internal static MSA.Expression /*!*/ YieldExpression( RubyContext /*!*/ context, AstExpressions /*!*/ arguments, MSA.Expression splattedArgument, MSA.Expression rhsArgument, MSA.Expression /*!*/ bfcVariable, MSA.Expression /*!*/ selfArgument) { Assert.NotNull(arguments, bfcVariable, selfArgument); bool hasArgumentArray; var opMethod = Methods.Yield(arguments.Count, splattedArgument != null, rhsArgument != null, out hasArgumentArray); var args = new AstExpressions(); foreach (var arg in arguments) { args.Add(AstUtils.Box(arg)); } if (hasArgumentArray) { args = new AstExpressions { Ast.NewArrayInit(typeof(object), args) }; } if (splattedArgument != null) { args.Add(AstUtils.LightDynamic(SplatAction.Make(context), typeof(IList), splattedArgument)); } if (rhsArgument != null) { args.Add(AstUtils.Box(rhsArgument)); } args.Add(AstUtils.Box(selfArgument)); args.Add(bfcVariable); return(Ast.Call(opMethod, args)); }
internal void TransformToCall(AstGenerator /*!*/ gen, CallSiteBuilder /*!*/ siteBuilder) { if (_expressions != null) { foreach (var arg in _expressions) { siteBuilder.Add(arg.TransformRead(gen)); } } if (_maplets != null) { siteBuilder.Add(gen.TransformToHashConstructor(_maplets)); } if (_array != null) { siteBuilder.SplattedArgument = AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), _array.TransformRead(gen)); } }
internal static MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen, AstExpressions /*!*/ rightValues, MSA.Expression splattedValue, bool doSplat) { Assert.NotNull(gen, rightValues); MSA.Expression result; // We need to distinguish various special cases here. // For parallel assignment specification, see "Ruby Language.docx/Runtime/Parallel Assignment". // R(0,*)? bool rightNoneSplat = rightValues.Count == 0 && splattedValue != null; // R(1,-)? bool rightOneNone = rightValues.Count == 1 && splattedValue == null; if (rightNoneSplat) { result = AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), splattedValue); if (doSplat) { result = Methods.Splat.OpCall(result); } } else if (rightOneNone && doSplat) { result = rightValues[0]; } else { result = Methods.MakeArrayOpCall(rightValues); if (splattedValue != null) { result = Methods.SplatAppend.OpCall(result, AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), splattedValue)); } } return(result); }
private MSA.Expression /*!*/ TransformWrite(AstGenerator /*!*/ gen, AstExpressions /*!*/ rightValues, MSA.Expression splattedValue) { // We need to distinguish various special cases here. // Each of the bool variables defined below is true iff the corresponding special form of LHS/RHS occurs. // These flags drive the DLR AST being produced by this method. // For parallel assignment specification, see "Ruby Language.docx/Runtime/Parallel Assignment". // L(0,-) not applicable Debug.Assert(!(_leftValues.Count == 0 && _unsplattedValue == null)); // L(1,-)? bool leftOneNone = _leftValues.Count == 1 && _unsplattedValue == null; // L(0,*)? bool leftNoneSplat = _leftValues.Count == 0 && _unsplattedValue != null; // R(0,*)? bool rightNoneSplat = rightValues.Count == 0 && splattedValue != null; // R(1,-)? bool rightOneNone = rightValues.Count == 1 && splattedValue == null; // R(1,*)? bool rightOneSplat = rightValues.Count == 1 && splattedValue != null; // R(0,-) not applicable Debug.Assert(!(rightValues.Count == 0 && splattedValue == null)); MSA.Expression resultExpression; if (leftOneNone) { // L(1,-): // recurse right away (X) = RHS is equivalent to X = RHS: CompoundLeftValue compound = _leftValues[0] as CompoundLeftValue; if (compound != null) { return(compound.TransformWrite(gen, rightValues, splattedValue)); } if (rightOneSplat) { // R(1,*) resultExpression = Methods.SplatPair.OpCall( AstUtils.Box(rightValues[0]), AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), splattedValue) ); } else { // case 1: R(1,-) // case 2: R(0,*) // case 3: otherwise resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, true /* Splat */); } return(_leftValues[0].TransformWrite(gen, resultExpression)); } bool optimizeReads = true; if (rightOneNone && !leftNoneSplat) { // R(1,-) && !L(0,*) resultExpression = Methods.Unsplat.OpCall( AstUtils.LightDynamic(ConvertToArraySplatAction.Make(gen.Context), rightValues[0]) ); optimizeReads = false; } else { // case 1: R(0,*) = L // case 2: otherwise resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, false /* Unsplat */); optimizeReads = !rightNoneSplat; } var writes = new AstBlock(); MSA.Expression result = gen.CurrentScope.DefineHiddenVariable("#rhs", typeof(IList)); writes.Add(Ast.Assign(result, resultExpression)); MethodInfo itemGetter = Methods.IList_get_Item; for (int i = 0; i < _leftValues.Count; i++) { MSA.Expression rvalue; if (optimizeReads) { if (i < rightValues.Count) { // unchecked get item: rvalue = Ast.Call(result, itemGetter, AstUtils.Constant(i)); } else if (splattedValue != null) { // checked get item: rvalue = Methods.GetArrayItem.OpCall(result, AstUtils.Constant(i)); } else { // missing item: rvalue = AstUtils.Constant(null); } } else { rvalue = Methods.GetArrayItem.OpCall(result, AstUtils.Constant(i)); } writes.Add(_leftValues[i].TransformWrite(gen, rvalue)); } // unsplatting the rest of rhs values into an array: if (_unsplattedValue != null) { // copies the rest of resulting array to the *LHS; // the resulting array contains splatted *RHS - no need for additional appending: MSA.Expression array = Methods.GetArraySuffix.OpCall(result, AstUtils.Constant(_leftValues.Count)); // assign the array (possibly empty) to *LHS: writes.Add(_unsplattedValue.TransformWrite(gen, array)); } writes.Add(result); return(writes); }
private MSA.Expression /*!*/ TransformSplatType(AstGenerator /*!*/ gen) { return(AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), _splatType.TransformRead(gen))); }