private MakeMethodBlockParameterRead ( ) : |
||
Результат |
// see Ruby Language.doc/Runtime/Control Flow Implementation/Yield internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { MSA.Expression bfcVariable = gen.CurrentScope.DefineHiddenVariable("#yielded-bfc", typeof(BlockParam)); MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#result", typeof(object)); MSA.Expression evalUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder)); MSA.Expression postYield; if (gen.CompilerOptions.IsEval) { // eval: postYield = Methods.EvalYield.OpCall(gen.CurrentRfcVariable, bfcVariable, resultVariable); } else if (gen.CurrentBlock != null) { // block: postYield = Methods.BlockYield.OpCall(gen.CurrentRfcVariable, gen.CurrentBlock.BfcVariable, bfcVariable, resultVariable); } else { // method: postYield = Methods.MethodYield.OpCall(gen.CurrentRfcVariable, bfcVariable, resultVariable); } return AstFactory.Block( gen.DebugMarker("#RB: yield begin"), Ast.Assign(bfcVariable, Methods.CreateBfcForYield.OpCall(gen.MakeMethodBlockParameterRead())), Ast.Assign(resultVariable, (Arguments ?? Arguments.Empty).TransformToYield(gen, bfcVariable, Ast.Property(AstUtils.Convert(gen.MakeMethodBlockParameterRead(), typeof(Proc)), Proc.SelfProperty) )), AstUtils.IfThen(postYield, gen.Return(resultVariable)), gen.DebugMarker("#RB: yield end"), resultVariable ); }
internal static MSA.Expression /*!*/ TransformRetry(AstGenerator /*!*/ gen) { // eval: if (gen.CompilerOptions.IsEval) { return(Methods.EvalRetry.OpCall(gen.CurrentRfcVariable)); } // rescue clause: if (gen.CurrentRescue != null) { return(Ast.Block( Ast.Assign(gen.CurrentRescue.RetryingVariable, Ast.Constant(true)), Ast.Continue(gen.CurrentRescue.ContinueLabel), Ast.Empty() )); } // block: if (gen.CurrentBlock != null) { return(gen.Return(Methods.BlockRetry.OpCall(gen.CurrentBlock.BfcVariable))); } // primary frame: return(gen.Return(Methods.MethodRetry.OpCall(gen.CurrentRfcVariable, gen.MakeMethodBlockParameterRead()))); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { if (gen.CurrentMethod.IsTopLevelCode && gen.CurrentBlock == null && !gen.CompilerOptions.IsEval) { return(Ast.Throw(Methods.MakeTopLevelSuperException.OpCall())); } // invoke super member action: CallBuilder callBuilder = new CallBuilder(gen); // self: callBuilder.Instance = gen.CurrentSelfVariable; // arguments: if (Arguments != null) { Arguments.TransformToCall(gen, callBuilder); } else { // copy parameters from the method: // TODO: parameters in top-level eval LexicalScope.TransformParametersToSuperCall(gen, callBuilder, gen.CurrentMethod.Parameters); } // block: MSA.Expression transformedBlock; if (Block != null) { transformedBlock = Block.Transform(gen); } else { transformedBlock = gen.MakeMethodBlockParameterRead(); } // variable assigned to the transformed block in MakeCallWithBlockRetryable: MSA.Expression blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#super-call-block", typeof(Proc)); callBuilder.Block = blockArgVariable; // TODO: this could be improved, currently the right method name and declaring module is always searched for at run-time (at the site): return(gen.DebugMark( MethodCall.MakeCallWithBlockRetryable(gen, callBuilder.MakeSuperCallAction(gen.CurrentFrame.UniqueId), blockArgVariable, transformedBlock, Block != null && Block.IsDefinition ), "#RB: super call ('" + gen.CurrentMethod.MethodName + "')" )); }
internal static MSA.Expression /*!*/ MakeCallWithBlockRetryable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ invoke, MSA.Expression blockArgVariable, MSA.Expression transformedBlock, bool isBlockDefinition) { Assert.NotNull(invoke); Debug.Assert((blockArgVariable == null) == (transformedBlock == null)); // see Ruby Language.doc/Control Flow Implementation/Method Call With a Block MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#method-result", typeof(object)); MSA.ParameterExpression evalUnwinder; MSA.LabelTarget retryLabel = Ast.Label("retry"); var result = new AstBlock { Ast.Assign(blockArgVariable, Ast.Convert(transformedBlock, blockArgVariable.Type)), Ast.Label(retryLabel), (isBlockDefinition) ? Methods.InitializeBlock.OpCall(blockArgVariable) : null, AstUtils.Try( Ast.Assign(resultVariable, invoke) ).Catch(evalUnwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"), Ast.Assign( resultVariable, Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField) ) ), Ast.IfThen(Ast.TypeEqual(resultVariable, typeof(BlockReturnResult)), Ast.IfThenElse(Methods.IsRetrySingleton.OpCall(resultVariable), // retry: AstUtils.IfThenElse(Ast.Equal(gen.MakeMethodBlockParameterRead(), blockArgVariable), RetryStatement.TransformRetry(gen), Ast.Goto(retryLabel) ), // return: gen.Return(ReturnStatement.Propagate(gen, resultVariable)) ) ), resultVariable }; return(result); }
internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { if (gen.CurrentMethod.IsTopLevelCode && gen.CurrentBlock == null && !gen.CompilerOptions.IsEval) { return Ast.Throw(Methods.MakeTopLevelSuperException.OpCall()); } // invoke super member action: CallBuilder callBuilder = new CallBuilder(gen); // self: callBuilder.Instance = gen.CurrentSelfVariable; // arguments: if (Arguments != null) { Arguments.TransformToCall(gen, callBuilder); } else { // copy parameters from the method: // TODO: parameters in top-level eval LexicalScope.TransformParametersToSuperCall(gen, callBuilder, gen.CurrentMethod.Parameters); } // block: MSA.Expression transformedBlock; if (Block != null) { transformedBlock = Block.Transform(gen); } else { transformedBlock = gen.MakeMethodBlockParameterRead(); } // variable assigned to the transformed block in MakeCallWithBlockRetryable: MSA.Expression blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#super-call-block", typeof(Proc)); callBuilder.Block = blockArgVariable; // TODO: this could be improved, currently the right method name and declaring module is always searched for at run-time (at the site): return gen.DebugMark( MethodCall.MakeCallWithBlockRetryable(gen, callBuilder.MakeSuperCallAction(gen.CurrentFrame.UniqueId), blockArgVariable, transformedBlock, Block != null && Block.IsDefinition ), "#RB: super call ('" + gen.CurrentMethod.MethodName + "')" ); }
internal static MSA.Expression/*!*/ Propagate(AstGenerator/*!*/ gen, MSA.Expression/*!*/ resultVariable) { // eval: if (gen.CompilerOptions.IsEval) { return Methods.EvalPropagateReturn.OpCall(resultVariable); } // block: if (gen.CurrentBlock != null) { return Methods.BlockPropagateReturn.OpCall( gen.CurrentBlock.BfcVariable, resultVariable ); } // method: return Methods.MethodPropagateReturn.OpCall( gen.CurrentScopeVariable, gen.MakeMethodBlockParameterRead(), Ast.Convert(resultVariable, typeof(BlockReturnResult)) ); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Yield internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { MSA.Expression bfcVariable = gen.CurrentScope.DefineHiddenVariable("#yielded-bfc", typeof(BlockParam)); MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#result", typeof(object)); MSA.Expression evalUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder)); MSA.Expression postYield; if (gen.CompilerOptions.IsEval) { // eval: postYield = Methods.EvalYield.OpCall(gen.CurrentRfcVariable, bfcVariable, resultVariable); } else if (gen.CurrentBlock != null) { // block: postYield = Methods.BlockYield.OpCall(gen.CurrentRfcVariable, gen.CurrentBlock.BfcVariable, bfcVariable, resultVariable); } else { // method: postYield = Methods.MethodYield.OpCall(gen.CurrentRfcVariable, bfcVariable, resultVariable); } return(AstFactory.Block( gen.DebugMarker("#RB: yield begin"), Ast.Assign(bfcVariable, Methods.CreateBfcForYield.OpCall(gen.MakeMethodBlockParameterRead())), Ast.Assign(resultVariable, (Arguments ?? Arguments.Empty).TransformToYield(gen, bfcVariable, Ast.Property(AstUtils.Convert(gen.MakeMethodBlockParameterRead(), typeof(Proc)), Proc.SelfProperty) )), AstUtils.IfThen(postYield, gen.Return(resultVariable)), gen.DebugMarker("#RB: yield end"), resultVariable )); }
internal static MSA.Expression/*!*/ TransformRetry(AstGenerator/*!*/ gen) { // eval: if (gen.CompilerOptions.IsEval) { return Methods.EvalRetry.OpCall(gen.CurrentScopeVariable); } // rescue clause: if (gen.CurrentRescue != null) { return Ast.Block( Ast.Assign(gen.CurrentRescue.RetryingVariable, AstUtils.Constant(true)), Ast.Goto(gen.CurrentRescue.RetryLabel, typeof(void)) ); } // block: if (gen.CurrentBlock != null) { return gen.Return(Methods.BlockRetry.OpCall(gen.CurrentBlock.BfcVariable)); } // primary frame: return gen.Return(Methods.MethodRetry.OpCall(gen.CurrentScopeVariable, gen.MakeMethodBlockParameterRead())); }
internal static MSA.Expression /*!*/ MakeCallWithBlockRetryable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ invoke, MSA.Expression blockArgVariable, MSA.Expression transformedBlock, bool isBlockDefinition) { Assert.NotNull(invoke); Debug.Assert((blockArgVariable == null) == (transformedBlock == null)); // see Ruby Language.doc/Control Flow Implementation/Method Call With a Block MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#method-result", typeof(object)); MSA.ParameterExpression evalUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder)); MSA.LabelTarget label = Ast.Label(); return(AstFactory.Block( Ast.Assign(blockArgVariable, Ast.Convert(transformedBlock, blockArgVariable.Type)), AstFactory.Infinite(label, null, (!isBlockDefinition) ? (MSA.Expression)Ast.Empty() : (MSA.Expression)Methods.InitializeBlock.OpCall(blockArgVariable), AstUtils.Try( Ast.Assign(resultVariable, invoke) ).Catch(evalUnwinder, Ast.Assign( resultVariable, Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField) ) ), // if result != RetrySingleton then break end AstUtils.Unless(Methods.IsRetrySingleton.OpCall(AstFactory.Box(resultVariable)), Ast.Break(label)), // if blockParam == #block then retry end (gen.CurrentMethod.IsTopLevelCode) ? Ast.Empty() : AstUtils.IfThen(Ast.Equal(gen.MakeMethodBlockParameterRead(), blockArgVariable), RetryStatement.TransformRetry(gen)) ), resultVariable )); }
internal static MSA.Expression /*!*/ Propagate(AstGenerator /*!*/ gen, MSA.Expression /*!*/ resultVariable) { // eval: if (gen.CompilerOptions.IsEval) { return(Methods.EvalPropagateReturn.OpCall(resultVariable)); } // block: if (gen.CurrentBlock != null) { return(Methods.BlockPropagateReturn.OpCall( gen.CurrentBlock.BfcVariable, resultVariable )); } // method: return(Methods.MethodPropagateReturn.OpCall( gen.CurrentScopeVariable, gen.MakeMethodBlockParameterRead(), Ast.Convert(resultVariable, typeof(BlockReturnResult)) )); }
internal static MSA.Expression/*!*/ MakeCallWithBlockRetryable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ invoke, MSA.Expression blockArgVariable, MSA.Expression transformedBlock, bool isBlockDefinition) { Assert.NotNull(invoke); Debug.Assert((blockArgVariable == null) == (transformedBlock == null)); // see Ruby Language.doc/Control Flow Implementation/Method Call With a Block MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#method-result", typeof(object)); MSA.ParameterExpression evalUnwinder; MSA.LabelTarget retryLabel = Ast.Label("retry"); var result = new AstBlock { Ast.Assign(blockArgVariable, Ast.Convert(transformedBlock, blockArgVariable.Type)), Ast.Label(retryLabel), (isBlockDefinition) ? Methods.InitializeBlock.OpCall(blockArgVariable) : null, AstUtils.Try( Ast.Assign(resultVariable, invoke) ).Catch(evalUnwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"), Ast.Assign( resultVariable, Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField) ) ), Ast.IfThen(Ast.TypeEqual(resultVariable, typeof(BlockReturnResult)), Ast.IfThenElse(Methods.IsRetrySingleton.OpCall(resultVariable), // retry: AstUtils.IfThenElse(Ast.Equal(gen.MakeMethodBlockParameterRead(), blockArgVariable), RetryStatement.TransformRetry(gen), Ast.Goto(retryLabel) ), // return: gen.Return(ReturnStatement.Propagate(gen, resultVariable)) ) ), resultVariable }; return result; }
internal override MSA.Expression TransformDefinedCondition(AstGenerator /*!*/ gen) { // block_given semantics: return(Ast.NotEqual(gen.MakeMethodBlockParameterRead(), Ast.Constant(null))); }
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 override MSA.Expression TransformDefinedCondition(AstGenerator/*!*/ gen) { // block_given semantics: return Ast.NotEqual(gen.MakeMethodBlockParameterRead(), AstUtils.Constant(null)); }
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 static MSA.Expression/*!*/ MakeCallWithBlockRetryable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ invoke, MSA.Expression blockArgVariable, MSA.Expression transformedBlock, bool isBlockDefinition) { Assert.NotNull(invoke); Debug.Assert((blockArgVariable == null) == (transformedBlock == null)); // see Ruby Language.doc/Control Flow Implementation/Method Call With a Block MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#method-result", typeof(object)); MSA.ParameterExpression evalUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder)); MSA.LabelTarget label = Ast.Label(); return AstFactory.Block( Ast.Assign(blockArgVariable, Ast.Convert(transformedBlock, blockArgVariable.Type)), AstFactory.Infinite(label, null, (!isBlockDefinition) ? (MSA.Expression)Ast.Empty() : (MSA.Expression)Methods.InitializeBlock.OpCall(blockArgVariable), AstUtils.Try( Ast.Assign(resultVariable, invoke) ).Catch(evalUnwinder, Ast.Assign( resultVariable, Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField) ) ), // if result != RetrySingleton then break end AstUtils.Unless(Methods.IsRetrySingleton.OpCall(AstFactory.Box(resultVariable)), Ast.Break(label)), // if blockParam == #block then retry end (gen.CurrentMethod.IsTopLevelCode) ? Ast.Empty() : AstUtils.IfThen(Ast.Equal(gen.MakeMethodBlockParameterRead(), blockArgVariable), RetryStatement.TransformRetry(gen)) ), resultVariable ); }