// arguments: complex arguments (expressions, maplets, splat, block) // singleArgument: siple argument (complex are not used) // assignmentRhsArgument: rhs of the assignment: target.method=(rhs) /*!*/ internal static MSA.Expression TransformRead(Expression/*!*/ node, AstGenerator/*!*/ gen, bool hasImplicitSelf, string/*!*/ methodName, MSA.Expression/*!*/ transformedTarget, Arguments arguments, Block block, MSA.Expression singleArgument, MSA.Expression assignmentRhsArgument) { Debug.Assert(assignmentRhsArgument == null || block == null, "Block not allowed in assignment"); Debug.Assert(singleArgument == null || arguments == null && assignmentRhsArgument == null); Assert.NotNull(gen, transformedTarget); Assert.NotEmpty(methodName); // Pass args in this order: // 1. instance // 2. block (if present) // 3. passed args: normal args, maplets, array // 4. RHS of assignment (if present) MSA.Expression blockArgVariable; MSA.Expression transformedBlock; if (block != null) { blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#block-def", typeof(Proc)); transformedBlock = block.Transform(gen); } else { blockArgVariable = transformedBlock = null; } var siteBuilder = new CallSiteBuilder(gen, transformedTarget, blockArgVariable); if (arguments != null) { arguments.TransformToCall(gen, siteBuilder); } else if (singleArgument != null) { siteBuilder.Add(singleArgument); } MSA.Expression rhsVariable = null; if (assignmentRhsArgument != null) { rhsVariable = gen.CurrentScope.DefineHiddenVariable("#rhs", assignmentRhsArgument.Type); siteBuilder.RhsArgument = Ast.Assign(rhsVariable, assignmentRhsArgument); } var dynamicSite = siteBuilder.MakeCallAction(methodName, hasImplicitSelf); #if FEATURE_CALL_SITE_TRACER if (gen.Context.CallSiteCreated != null) { gen.Context.CallSiteCreated(node, dynamicSite); } #endif MSA.Expression result = gen.DebugMark(dynamicSite, methodName); if (block != null) { result = gen.DebugMark(MakeCallWithBlockRetryable(gen, result, blockArgVariable, transformedBlock, block.IsDefinition), "#RB: method call with a block ('" + methodName + "')"); } if (assignmentRhsArgument != null) { result = Ast.Block(result, rhsVariable); } return result; }
// when <expr> // generates into: // RubyOps.IsTrue(<expr>) if the case has no value, otherise: // RubyOps.IsTrue(Call("===", <expr>, <value>)) private static MSA.Expression /*!*/ MakeTest(AstGenerator /*!*/ gen, MSA.Expression /*!*/ expr, MSA.Expression value) { if (value != null) { expr = CallSiteBuilder.InvokeMethod(gen.Context, "===", RubyCallSignature.WithScope(1), gen.CurrentScopeVariable, expr, value ); } return(AstFactory.IsTrue(expr)); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { Assert.NotNull(gen); MSA.Expression transformedBlock = _block.Transform(gen); MSA.Expression blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#forloop-block", typeof(Proc)); MSA.Expression result = CallSiteBuilder.InvokeMethod(gen.Context, "each", RubyCallSignature.WithScopeAndBlock(0), gen.CurrentScopeVariable, _list.TransformRead(gen), blockArgVariable ); return(gen.DebugMark(MethodCall.MakeCallWithBlockRetryable(gen, result, blockArgVariable, transformedBlock, true), "#RB: method call with a block ('for-loop')")); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { switch (_kind) { case StringKind.Mutable: return(TransformConcatentation(gen, _parts, StringFactory.Instance)); case StringKind.Symbol: return(TransformConcatentation(gen, _parts, SymbolFactory.Instance)); case StringKind.Command: return(CallSiteBuilder.InvokeMethod(gen.Context, "`", new RubyCallSignature(1, RubyCallFlags.HasScope | RubyCallFlags.HasImplicitSelf), gen.CurrentScopeVariable, gen.CurrentSelfVariable, TransformConcatentation(gen, _parts, StringFactory.Instance) )); } throw Assert.Unreachable; }
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)); } }
// when <expr> // generates into: // RubyOps.IsTrue(<expr>) if the case has no value, otherise: // RubyOps.IsTrue(Call("===", <expr>, <value>)) private static MSA.Expression /*!*/ MakeTest(AstGenerator /*!*/ gen, Expression /*!*/ expr, MSA.Expression value) { MSA.Expression transformedExpr = expr.TransformRead(gen); if (expr is SplattedArgument) { if (value != null) { return(Methods.ExistsUnsplatCompare.OpCall( Ast.Constant(CallSite <Func <CallSite, object, object, object> > .Create( RubyCallAction.Make(gen.Context, "===", RubyCallSignature.WithImplicitSelf(2)) )), AstUtils.LightDynamic(ExplicitTrySplatAction.Make(gen.Context), transformedExpr), AstUtils.Box(value) )); } else { return(Methods.ExistsUnsplat.OpCall( AstUtils.LightDynamic(ExplicitTrySplatAction.Make(gen.Context), transformedExpr) )); } } else { if (value != null) { return(AstFactory.IsTrue( CallSiteBuilder.InvokeMethod(gen.Context, "===", RubyCallSignature.WithScope(1), gen.CurrentScopeVariable, transformedExpr, value ) )); } else { return(AstFactory.IsTrue(transformedExpr)); } } }
internal void TransformForSuperCall(AstGenerator /*!*/ gen, CallSiteBuilder /*!*/ siteBuilder) { for (int i = 0; i < _leadingMandatoryCount; i++) { siteBuilder.Add(_mandatory[i].TransformRead(gen)); } foreach (SimpleAssignmentExpression s in _optional) { siteBuilder.Add(s.Left.TransformRead(gen)); } for (int i = _leadingMandatoryCount; i < _mandatory.Length; i++) { siteBuilder.Add(_mandatory[i].TransformRead(gen)); } if (_unsplat != null) { siteBuilder.SplattedArgument = _unsplat.TransformRead(gen); } }
internal void TransformForSuperCall(AstGenerator /*!*/ gen, CallSiteBuilder /*!*/ siteBuilder) { if (_mandatory != null) { foreach (Variable v in _mandatory) { siteBuilder.Add(v.TransformRead(gen)); } } if (_optional != null) { foreach (SimpleAssignmentExpression s in _optional) { siteBuilder.Add(s.Left.TransformRead(gen)); } } if (_array != null) { siteBuilder.SplattedArgument = _array.TransformRead(gen); } }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { // variable assigned to the transformed block in MakeCallWithBlockRetryable: MSA.Expression blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#super-call-block", typeof(Proc)); // invoke super member action: var siteBuilder = new CallSiteBuilder(gen, gen.CurrentSelfVariable, blockArgVariable); // arguments: if (HasImplicitArguments) { // MRI 1.8: If a block is called via define_method stub its parameters are used here. // MRI 1.9: This scenario is not supported. // We don't support this either. Otherwise we would need to emit super call with dynamic parameters if gen.CurrentBlock != null. if (gen.CurrentMethod.Parameters != null) { gen.CurrentMethod.Parameters.TransformForSuperCall(gen, siteBuilder); } else if (gen.CompilerOptions.TopLevelParameterNames != null) { bool hasUnsplat = gen.CompilerOptions.TopLevelHasUnsplatParameter; string[] names = gen.CompilerOptions.TopLevelParameterNames; // dynamic lookup: for (int i = 0; i < names.Length - (hasUnsplat ? 1 : 0); i++) { siteBuilder.Add(Methods.GetLocalVariable.OpCall(gen.CurrentScopeVariable, AstUtils.Constant(names[i]))); } if (hasUnsplat) { siteBuilder.SplattedArgument = Methods.GetLocalVariable.OpCall(gen.CurrentScopeVariable, AstUtils.Constant(names[names.Length - 1])); } } else { // this means we are not inside any method scope -> an exception will be thrown at the call site } } else { Arguments.TransformToCall(gen, siteBuilder); } // block: MSA.Expression transformedBlock; if (Block != null) { transformedBlock = Block.Transform(gen); } else { transformedBlock = gen.MakeMethodBlockParameterRead(); } return(gen.DebugMark( MethodCall.MakeCallWithBlockRetryable(gen, siteBuilder.MakeSuperCallAction(gen.CurrentFrame.UniqueId, HasImplicitArguments), blockArgVariable, transformedBlock, Block != null && Block.IsDefinition ), "#RB: super call ('" + gen.CurrentMethod.MethodName + "')" )); }
internal MSA.Expression <T> /*!*/ Transform <T>(AstGenerator /*!*/ gen) { Debug.Assert(gen != null); ScopeBuilder scope = DefineLocals(); MSA.ParameterExpression[] parameters; MSA.ParameterExpression selfVariable; MSA.ParameterExpression runtimeScopeVariable; MSA.ParameterExpression blockParameter; if (gen.CompilerOptions.FactoryKind == TopScopeFactoryKind.None || gen.CompilerOptions.FactoryKind == TopScopeFactoryKind.ModuleEval) { parameters = new MSA.ParameterExpression[4]; runtimeScopeVariable = parameters[0] = Ast.Parameter(typeof(RubyScope), "#scope"); selfVariable = parameters[1] = Ast.Parameter(typeof(object), "#self"); parameters[2] = Ast.Parameter(typeof(RubyModule), "#module"); blockParameter = parameters[3] = Ast.Parameter(typeof(Proc), "#block"); } else { parameters = new MSA.ParameterExpression[2]; runtimeScopeVariable = parameters[0] = Ast.Parameter(typeof(RubyScope), "#scope"); selfVariable = parameters[1] = Ast.Parameter(typeof(object), "#self"); blockParameter = null; } gen.EnterSourceUnit( scope, selfVariable, runtimeScopeVariable, blockParameter, gen.CompilerOptions.TopLevelMethodName, // method name for blocks null // parameters for super calls ); MSA.Expression body; if (_statements.Count > 0) { if (gen.PrintInteractiveResult) { var resultVariable = scope.DefineHiddenVariable("#result", typeof(object)); var epilogue = Methods.PrintInteractiveResult.OpCall(runtimeScopeVariable, AstUtils.LightDynamic(ConvertToSAction.Make(gen.Context), typeof(MutableString), CallSiteBuilder.InvokeMethod(gen.Context, "inspect", RubyCallSignature.WithScope(0), gen.CurrentScopeVariable, resultVariable ) ) ); body = gen.TransformStatements(null, _statements, epilogue, ResultOperation.Store(resultVariable)); } else { body = gen.TransformStatements(_statements, ResultOperation.Return); } // TODO: var exceptionVariable = Ast.Parameter(typeof(Exception), "#exception"); body = AstUtils.Try( body ).Filter(exceptionVariable, Methods.TraceTopLevelCodeFrame.OpCall(runtimeScopeVariable, exceptionVariable), Ast.Empty() ); } else { body = AstUtils.Constant(null); } // scope initialization: MSA.Expression prologue; switch (gen.CompilerOptions.FactoryKind) { case TopScopeFactoryKind.None: case TopScopeFactoryKind.ModuleEval: prologue = Methods.InitializeScopeNoLocals.OpCall(runtimeScopeVariable, EnterInterpretedFrameExpression.Instance); break; case TopScopeFactoryKind.Hosted: case TopScopeFactoryKind.File: case TopScopeFactoryKind.WrappedFile: prologue = Methods.InitializeScope.OpCall( runtimeScopeVariable, scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), EnterInterpretedFrameExpression.Instance ); break; case TopScopeFactoryKind.Main: prologue = Methods.InitializeScope.OpCall( runtimeScopeVariable, scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), EnterInterpretedFrameExpression.Instance ); if (_dataOffset >= 0) { prologue = Ast.Block( prologue, Methods.SetDataConstant.OpCall( runtimeScopeVariable, gen.SourcePathConstant, AstUtils.Constant(_dataOffset) ) ); } break; default: throw Assert.Unreachable; } // BEGIN blocks: if (gen.FileInitializers != null) { var b = new AstBlock(); b.Add(prologue); b.Add(gen.FileInitializers); b.Add(body); body = b; } body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveSourceUnit(); return(Ast.Lambda <T>(body, GetEncodedName(gen), parameters)); }
internal void TransformToCall(AstGenerator /*!*/ gen, CallSiteBuilder /*!*/ siteBuilder) { siteBuilder.SplattedArgument = TransformToCallInternal(gen, siteBuilder); }