internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { Assert.NotNull(metaBuilder, args, name); // 2 implicit args: self, block var argsBuilder = new ArgsBuilder(2, Parameters.Mandatory.Length, Parameters.LeadingMandatoryCount, Parameters.Optional.Length, Parameters.Unsplat != null); argsBuilder.SetImplicit(0, AstUtils.Box(args.TargetExpression)); argsBuilder.SetImplicit(1, args.Signature.HasBlock ? AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)) : AstFactory.NullOfProc); argsBuilder.AddCallArguments(metaBuilder, args); if (metaBuilder.Error) { return; } // box explicit arguments: var boxedArguments = argsBuilder.GetArguments(); for (int i = 2; i < boxedArguments.Length; i++) { boxedArguments[i] = AstUtils.Box(boxedArguments[i]); } var method = GetDelegate(); if (method.GetType() == ParamsArrayDelegateType) { // Func<object, Proc, object[], object> metaBuilder.Result = AstFactory.CallDelegate(method, new[] { boxedArguments[0], boxedArguments[1], Ast.NewArrayInit(typeof(object), ArrayUtils.ShiftLeft(boxedArguments, 2)) }); } else { metaBuilder.Result = AstFactory.CallDelegate(method, boxedArguments); } }
// see Ruby Language.doc/Runtime/Control Flow Implementation/While-Until internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#loop-result", typeof(object)); MSA.Expression redoVariable = gen.CurrentScope.DefineHiddenVariable("#skip-condition", typeof(bool)); MSA.ParameterExpression unwinder; bool isInnerLoop = gen.CurrentLoop != null; MSA.LabelTarget breakLabel = Ast.Label(); MSA.LabelTarget continueLabel = Ast.Label(); gen.EnterLoop(redoVariable, resultVariable, breakLabel, continueLabel); MSA.Expression transformedBody = gen.TransformStatements(_statements, ResultOperation.Ignore); MSA.Expression transformedCondition = _condition.TransformCondition(gen, true); gen.LeaveLoop(); MSA.Expression conditionPositiveStmt, conditionNegativeStmt; if (_isWhileLoop) { conditionPositiveStmt = AstUtils.Empty(); conditionNegativeStmt = Ast.Break(breakLabel); } else { conditionPositiveStmt = Ast.Break(breakLabel); conditionNegativeStmt = AstUtils.Empty(); } // make the loop first: MSA.Expression loop = new AstBlock { gen.ClearDebugInfo(), Ast.Assign(redoVariable, AstUtils.Constant(_isPostTest)), AstFactory.Infinite(breakLabel, continueLabel, AstUtils.Try( AstUtils.If(redoVariable, Ast.Assign(redoVariable, AstUtils.Constant(false)) ).ElseIf(transformedCondition, conditionPositiveStmt ).Else( conditionNegativeStmt ), transformedBody, AstUtils.Empty() ).Catch(unwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"), // redo = u.IsRedo Ast.Assign(redoVariable, Ast.Field(unwinder, BlockUnwinder.IsRedoField)), AstUtils.Empty() ).Filter(unwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"), Ast.Equal(Ast.Field(unwinder, EvalUnwinder.ReasonField), AstFactory.BlockReturnReasonBreak), // result = unwinder.ReturnValue Ast.Assign(resultVariable, Ast.Field(unwinder, EvalUnwinder.ReturnValueField)), Ast.Break(breakLabel) ) ), gen.ClearDebugInfo(), AstUtils.Empty(), }; // wrap it to try finally that updates RFC state: if (!isInnerLoop) { loop = AstUtils.Try( Methods.EnterLoop.OpCall(gen.CurrentScopeVariable), loop ).Finally( Methods.LeaveLoop.OpCall(gen.CurrentScopeVariable) ); } return(Ast.Block(loop, resultVariable)); }
private MSA.Expression /*!*/ TransformWrite(AstGenerator /*!*/ gen, List <MSA.Expression> /*!*/ 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(AstFactory.Box(rightValues[0]), AstFactory.Box(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(AstFactory.Box(rightValues[0])); optimizeReads = false; } else { // case 1: R(0,*) = L // case 2: otherwise resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, false /* Unsplat */); optimizeReads = !rightNoneSplat; } int writesCount = _leftValues.Count + (_unsplattedValue != null ? 1 : 0); if (writesCount == 0) { return(resultExpression); } var writes = new MSA.Expression[ 1 + // store result to a temp writesCount + 1 // load from the temp ]; int writeIndex = 0; MSA.Expression result = gen.CurrentScope.DefineHiddenVariable("#rhs", typeof(List <object>)); writes[writeIndex++] = Ast.Assign(result, resultExpression); MethodInfo itemGetter = typeof(List <object>).GetMethod("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, Ast.Constant(i)); } else if (splattedValue != null) { // checked get item: rvalue = Methods.GetArrayItem.OpCall(result, Ast.Constant(i)); } else { // missing item: rvalue = Ast.Constant(null); } } else { rvalue = Methods.GetArrayItem.OpCall(result, Ast.Constant(i)); } writes[writeIndex++] = _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, Ast.Constant(_leftValues.Count)); // assign the array (possibly empty) to *LHS: writes[writeIndex++] = _unsplattedValue.TransformWrite(gen, array); } writes[writeIndex++] = result; Debug.Assert(writes.Length == writeIndex); return(AstFactory.Block(writes)); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(AstFactory.Block(Transform(gen), Ast.Constant(null))); }
internal override MSA.Expression /*!*/ MakeDefinitionExpression(AstGenerator /*!*/ gen) { return(Methods.DefineSingletonClass.OpCall(gen.CurrentScopeVariable, AstFactory.Box(_singleton.TransformRead(gen)))); }
private MSA.Expression /*!*/ TransformBody(AstGenerator /*!*/ gen, MSA.Expression /*!*/ methodDefinitionVariable) { string encodedName = gen.EncodeMethodName(_name, Location); ScopeBuilder scope = new ScopeBuilder(); MSA.Expression parentScope = gen.CurrentScopeVariable; MSA.ParameterExpression[] parameters = DefineParameters(gen, scope); MSA.Expression currentMethodVariable = scope.DefineHiddenVariable("#method", typeof(RubyMethodInfo)); MSA.Expression rfcVariable = scope.DefineHiddenVariable("#rfc", typeof(RuntimeFlowControl)); MSA.Expression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyMethodScope)); MSA.Expression selfParameter = parameters[0]; MSA.Expression blockParameter = parameters[1]; gen.EnterMethodDefinition( scope, selfParameter, scopeVariable, blockParameter, rfcVariable, currentMethodVariable, _name, _parameters ); DefinedScope.TransformLocals(scope); MSA.ParameterExpression unwinder = scope.DefineHiddenVariable("#unwinder", typeof(MethodUnwinder)); MSA.Expression body = AstFactory.MakeUserMethodBody( gen, Location.End.Line, blockParameter, rfcVariable, unwinder, Ast.Block( Ast.Assign(currentMethodVariable, methodDefinitionVariable), Ast.Assign(scopeVariable, Methods.CreateMethodScope.OpCall( scope.VisibleVariables(), parentScope, currentMethodVariable, rfcVariable, selfParameter, blockParameter) ), _parameters.TransformOptionalsInitialization(gen), gen.TraceEnabled ? Methods.TraceMethodCall.OpCall(scopeVariable, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(Location.Start.Line)) : Ast.Empty(), Body.TransformResult(gen, ResultOperation.Return), Ast.Empty() ), ResultOperation.Return, (gen.Profiler != null) ? gen.Profiler.GetTickIndex(encodedName) : -1, (gen.Profiler != null) ? scope.DefineHiddenVariable("#stamp", typeof(long)) : null, gen.ReturnLabel ); body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveMethodDefinition(); return(CreateLambda( encodedName, parameters, body )); }