private MSA.Expression /*!*/ MakeParametersInitialization(AstGenerator /*!*/ gen, MSA.Expression[] /*!*/ parameters) { Assert.NotNull(gen); Assert.NotNullItems(parameters); var result = AstFactory.CreateExpressionArray( _parameters.LeftValues.Count + (_parameters.UnsplattedValue != null ? 1 : 0) + 1 ); int resultIndex = 0; bool paramsInArray = HasFormalParametersInArray; for (int i = 0; i < _parameters.LeftValues.Count; i++) { var parameter = paramsInArray ? Ast.ArrayAccess(parameters[HiddenParameterCount], Ast.Constant(i)) : parameters[HiddenParameterCount + i]; result[resultIndex++] = _parameters.LeftValues[i].TransformWrite(gen, parameter); } if (_parameters.UnsplattedValue != null) { // the last parameter is unsplat: var parameter = parameters[parameters.Length - 1]; result[resultIndex++] = _parameters.UnsplattedValue.TransformWrite(gen, parameter); } result[resultIndex++] = Ast.Empty(); Debug.Assert(resultIndex == result.Length); return(AstFactory.Block(result)); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Break internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression transformedReturnValue = TransformReturnValue(gen); // eval: if (gen.CompilerOptions.IsEval) { return(Methods.EvalBreak.OpCall(gen.CurrentRfcVariable, AstFactory.Box(transformedReturnValue))); } // loop: if (gen.CurrentLoop != null) { return(Ast.Block( Ast.Assign( gen.CurrentLoop.ResultVariable, Ast.Convert(transformedReturnValue, gen.CurrentLoop.ResultVariable.Type) ), Ast.Break(gen.CurrentLoop.BreakLabel), Ast.Empty() )); } // block: if (gen.CurrentBlock != null) { return(gen.Return(Methods.BlockBreak.OpCall(gen.CurrentBlock.BfcVariable, AstFactory.Box(transformedReturnValue)))); } // primary frame: return(Methods.MethodBreak.OpCall(AstFactory.Box(transformedReturnValue))); }
internal MSA.Expression /*!*/ TransformOptionalsInitialization(AstGenerator /*!*/ gen) { Assert.NotNull(gen); if (_optional == null) { return(Ast.Empty()); } MSA.Expression singleton = gen.CurrentScope.DefineHiddenVariable("#default", typeof(object)); MSA.Expression result = Ast.Empty(); for (int i = 0; i < _optional.Count; i++) { result = AstUtils.IfThen(Ast.Equal(_optional[i].Left.TransformRead(gen), singleton), result, _optional[i].TransformRead(gen) ); } return(Ast.Block( Ast.Assign(singleton, Ast.Field(null, Fields.RubyOps_DefaultArgumentField)), result, Ast.Empty() )); }
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()))); }
// when [<expr>, ...] *<array> // // generates this code: // // IEnumerator<object>/*!*/ enumVar = RubyOps.Unsplat(<array>).GetEnumerator(); // bool result = false; // while (enumVar.MoveNext()) { // if (<MakeTest>(enumVar.Current)) { // result = true; // break; // } // } private static MSA.Expression /*!*/ MakeArrayTest(AstGenerator /*!*/ gen, MSA.Expression /*!*/ array, MSA.Expression value) { MSA.Expression enumVariable = gen.CurrentScope.DefineHiddenVariable("#case-enumerator", typeof(IEnumerator <object>)); MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#case-compare-result", typeof(bool)); MSA.LabelTarget label = Ast.Label(); return(AstFactory.Block( Ast.Assign(enumVariable, Ast.Call( Methods.Unsplat.OpCall(AstFactory.Box(array)), Methods.IEnumerable_Of_Object_GetEnumerator )), Ast.Assign(resultVariable, Ast.Constant(false)), AstUtils.While( Ast.Call(enumVariable, Methods.IEnumerator_MoveNext), AstUtils.If( MakeTest(gen, Ast.Call(enumVariable, Methods.IEnumerator_get_Current), value), Ast.Block( Ast.Assign(resultVariable, Ast.Constant(true)), Ast.Break(label), Ast.Empty() ) ), null, label, null ), resultVariable )); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Redo internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { // eval: if (gen.CompilerOptions.IsEval) { return(Methods.EvalRedo.OpCall(gen.CurrentRfcVariable)); } // loop: if (gen.CurrentLoop != null) { return(Ast.Block( Ast.Assign(gen.CurrentLoop.RedoVariable, Ast.Constant(true)), Ast.Continue(gen.CurrentLoop.ContinueLabel), Ast.Empty() )); } // block: if (gen.CurrentBlock != null) { return(Ast.Continue(gen.CurrentBlock.RedoLabel)); } // method: return(Methods.MethodRedo.OpCall(gen.CurrentRfcVariable)); }
public Expression CreateRule() { if (_binding == null) { if (_test == null) { throw Error.MissingTest(); } if (_target == null) { throw Error.MissingTarget(); } _binding = Expression.Block( _temps != null ? _temps.ToArray() : new ParameterExpression[0], Expression.Condition( _test, AstUtils.Convert(_target, typeof(void)), Ast.Empty() ) ); } return(_binding); }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Next internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression transformedReturnValue = TransformReturnValue(gen); // eval: if (gen.CompilerOptions.IsEval) { return(Methods.EvalNext.OpCall(gen.CurrentRfcVariable, AstFactory.Box(transformedReturnValue))); } // loop: if (gen.CurrentLoop != null) { return(Ast.Block( transformedReturnValue, // evaluate for side-effects Ast.Continue(gen.CurrentLoop.ContinueLabel), Ast.Empty() )); } // block: if (gen.CurrentBlock != null) { return(gen.Return(transformedReturnValue)); } // method: return(Methods.MethodNext.OpCall(gen.CurrentRfcVariable, AstFactory.Box(transformedReturnValue))); }
internal sealed override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { string debugString = (IsSingletonDeclaration) ? "SINGLETON" : ((this is ClassDeclaration) ? "CLASS" : "MODULE") + " " + QualifiedName.Name; ScopeBuilder outerLocals = gen.CurrentScope; // definition needs to take place outside the defined lexical scope: MSA.Expression definition = MakeDefinitionExpression(gen); MSA.Expression selfVariable = outerLocals.DefineHiddenVariable("#module", typeof(RubyModule)); MSA.Expression rfcVariable = gen.CurrentRfcVariable; MSA.Expression parentScope = gen.CurrentScopeVariable; // inner locals: ScopeBuilder scope = new ScopeBuilder(); MSA.Expression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyScope)); gen.EnterModuleDefinition( scope, selfVariable, scopeVariable, IsSingletonDeclaration ); // first, transform locals defined within the module body: DefinedScope.TransformLocals(scope); // second, transform body: MSA.Expression transformedBody = Body.TransformRead(gen); // outer local: MSA.Expression resultVariable = outerLocals.DefineHiddenVariable("#result", transformedBody.Type); // begin with new scope // self = DefineModule/Class(... parent scope here ...) // <body> // end MSA.Expression result = AstFactory.Block( gen.DebugMarker(debugString), Ast.Assign(selfVariable, definition), scope.CreateScope( Ast.Block( Ast.Assign(scopeVariable, Methods.CreateModuleScope.OpCall(scope.VisibleVariables(), parentScope, rfcVariable, selfVariable)), Ast.Assign(resultVariable, transformedBody), Ast.Empty() ) ), gen.DebugMarker("END OF " + debugString), resultVariable ); gen.LeaveModuleDefinition(); return(result); }
internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression[] result = new MSA.Expression[_items.Count + 1]; for (int i = 0; i < _items.Count; i++) { result[i] = Methods.UndefineMethod.OpCall(gen.CurrentScopeVariable, AstUtils.Constant(_items[i].Name)); } result[_items.Count] = Ast.Empty(); return(Ast.Block(result)); }
public static MSA.Expression /*!*/ Block(List <MSA.Expression /*!*/> /*!*/ expressions) { switch (expressions.Count) { case 0: return(Ast.Empty()); case 1: return(expressions[0]); default: return(Ast.Block(new ReadOnlyCollection <MSA.Expression>(expressions.ToArray()))); } }
public static MSA.Expression /*!*/ Block(params MSA.Expression /*!*/[] /*!*/ expressions) { switch (expressions.Length) { case 0: return(Ast.Empty()); case 1: return(expressions[0]); default: return(Ast.Block(new ReadOnlyCollection <MSA.Expression>(expressions))); } }
internal static MSA.Expression /*!*/ MakeUserMethodBody(AstGenerator gen, int lastLine, MSA.Expression /*!*/ blockParameter, MSA.Expression /*!*/ rfcVariable, MSA.ParameterExpression /*!*/ methodUnwinder, MSA.Expression /*!*/ bodyStatement, ResultOperation resultOperation, int profileTickIndex, MSA.ParameterExpression stampVariable, MSA.LabelTarget returnLabel) { Assert.NotNull(blockParameter, rfcVariable, bodyStatement, methodUnwinder); Debug.Assert(!resultOperation.IsIgnore, "return value should not be ignored"); Debug.Assert(returnLabel != null || resultOperation.Variable != null, "return label needed"); MSA.Expression resultExpression = Ast.Field(methodUnwinder, MethodUnwinder.ReturnValueField); if (resultOperation.Variable != null) { resultExpression = Ast.Assign(resultOperation.Variable, resultExpression); } else { resultExpression = Ast.Return(returnLabel, resultExpression); } // TODO: move this to the caller: MSA.Expression profileStart, profileEnd; if (stampVariable != null) { profileStart = Ast.Assign(stampVariable, Methods.Stopwatch_GetTimestamp.OpCall()); profileEnd = Methods.UpdateProfileTicks.OpCall(Ast.Constant(profileTickIndex), stampVariable); } else { profileStart = profileEnd = Ast.Empty(); } return(AstUtils.Try( // initialize frame (RFC): profileStart, Ast.Assign(rfcVariable, Methods.CreateRfcForMethod.OpCall(AstUtils.Convert(blockParameter, typeof(Proc)))), bodyStatement ).Filter(methodUnwinder, Ast.Equal(Ast.Field(methodUnwinder, MethodUnwinder.TargetFrameField), rfcVariable), // return unwinder.ReturnValue; resultExpression ).Finally( Ast.Assign(Ast.Field(rfcVariable, RuntimeFlowControl.IsActiveMethodField), Ast.Constant(false)), profileEnd, gen != null && gen.TraceEnabled ? Methods.TraceMethodReturn.OpCall( gen.CurrentScopeVariable, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(lastLine) ) : Ast.Empty() )); }
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 )); }
protected override Expression VisitTry(TryExpression node) { MSAst.Expression b = Visit(node.Body); ReadOnlyCollection <CatchBlock> h = Visit(node.Handlers, VisitCatchBlock); MSAst.Expression y = Visit(node.Finally); MSAst.Expression f; _insideConditionalBlock = true; try { f = Visit(node.Fault); } finally { _insideConditionalBlock = false; } node = Ast.MakeTry(node.Type, b, y, f, h); List <MSAst.CatchBlock> newHandlers = null; MSAst.Expression newFinally = null; // If the TryStatement has any Catch blocks we need to insert the exception // event as a first statement so that we can be notified of first-chance exceptions. if (node.Handlers != null && node.Handlers.Count > 0) { newHandlers = new List <CatchBlock>(); foreach (var catchBlock in node.Handlers) { ParameterExpression exceptionVar = catchBlock.Variable ?? Ast.Parameter(catchBlock.Test, null); Expression debugMarker, thread; if (_transformToGenerator) { debugMarker = Ast.Call( typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.GetCurrentSequencePointForGeneratorFrame)), _frame ); thread = Ast.Call(typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.GetThread)), _frame); } else { debugMarker = _debugMarker; thread = _thread; } MSAst.Expression exceptionEvent = Ast.Block( // Rethrow ForceToGeneratorLoopException AstUtils.If( Ast.TypeIs( exceptionVar, typeof(ForceToGeneratorLoopException) ), Ast.Throw(exceptionVar) ), AstUtils.If( Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled)), _pushFrame ?? Ast.Empty(), Ast.Call( typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.OnTraceEvent)), thread, debugMarker, exceptionVar ) ) ); newHandlers.Add(Ast.MakeCatchBlock( catchBlock.Test, exceptionVar, Ast.Block( exceptionEvent, catchBlock.Body ), catchBlock.Filter )); } } if (!_transformToGenerator && node.Finally != null) { // Prevent the user finally block from running if the frame is currently remapping to generator newFinally = AstUtils.If( Ast.Not( Ast.Call( typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.IsCurrentLeafFrameRemappingToGenerator)), _thread ) ), node.Finally ); } if (newHandlers != null || newFinally != null) { node = Ast.MakeTry( node.Type, node.Body, newFinally ?? node.Finally, node.Fault, newHandlers != null ? (IEnumerable <CatchBlock>)newHandlers : node.Handlers ); } return(node); }
internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression parentScope = gen.CurrentScopeVariable; ScopeBuilder scope = new ScopeBuilder(); // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment): MSA.Expression blockParameter, selfParameter; MSA.ParameterExpression[] parameters = DefineParameters(out selfParameter, out blockParameter); MSA.Expression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope)); MSA.LabelTarget redoLabel = Ast.Label(); gen.EnterBlockDefinition( scope, blockParameter, selfParameter, scopeVariable, redoLabel ); if (_definedScope != null) { _definedScope.TransformLocals(scope); } MSA.Expression paramInit = MakeParametersInitialization(gen, parameters); MSA.ParameterExpression blockUnwinder = scope.DefineHiddenVariable("#unwinder", typeof(BlockUnwinder)); MSA.Expression loop = AstFactory.Infinite(null, redoLabel, AstUtils.Try( gen.TransformStatements(_body, ResultOperation.Return) ).Catch(blockUnwinder, // redo: AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Continue(redoLabel)), // next: gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField)) ) ); if (gen.TraceEnabled) { int firstStatementLine = _body.Count > 0 ? _body[0].Location.Start.Line : Location.End.Line; int lastStatementLine = _body.Count > 0 ? _body[_body.Count - 1].Location.End.Line : Location.End.Line; loop = Ast.TryFinally( Ast.Block( Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(firstStatementLine)), loop ), Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(lastStatementLine)) ); } MSA.Expression body = Ast.Block( Ast.Assign(scopeVariable, Methods.CreateBlockScope.OpCall(scope.VisibleVariables(), parentScope, blockParameter, selfParameter) ), paramInit, loop, Ast.Empty() ); body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveBlockDefinition(); int parameterCount = _parameters.LeftValues.Count; var attributes = _parameters.GetBlockSignatureAttributes(); return(Methods.DefineBlock.OpCall( gen.CurrentScopeVariable, gen.CurrentRfcVariable, gen.CurrentSelfVariable, Ast.Lambda( BlockDispatcher.GetDelegateType(parameterCount, attributes), body, gen.EncodeMethodName(gen.CurrentMethod.MethodName, Location), new ReadOnlyCollection <MSA.ParameterExpression>(parameters) ), Ast.Constant(parameterCount), Ast.Constant(attributes) )); }
private MSAst.LambdaExpression CreateOuterLambda(Type lambdaType, MSAst.Expression debuggableBody) { List <MSAst.Expression> bodyExpressions = new List <MSAst.Expression>(); List <MSAst.Expression> tryExpressions = new List <MSAst.Expression>(); List <MSAst.Expression> finallyExpressions = new List <MSAst.Expression>(); Type returnType = lambdaType.GetMethod("Invoke").ReturnType; MSAst.LabelTarget returnLabelTarget = Ast.Label(returnType); // Init $funcInfo tryExpressions.Add( Ast.Assign( _funcInfo, Ast.Convert(_functionInfo, typeof(FunctionInfo)) ) ); // Init $traceLocations // $TODO: only do this if we're in TracePoints mode tryExpressions.Add( Ast.Assign( _traceLocations, Ast.Call(typeof(RuntimeOps).GetMethod("GetTraceLocations"), _funcInfo) ) ); // Init sourceFile locals foreach (var entry in _sourceFilesMap) { tryExpressions.Add( Ast.Assign( entry.Value, Ast.Constant(entry.Key, typeof(DebugSourceFile)) ) ); } if (_noPushFrameOptimization) { tryExpressions.Add(_pushFrame); } tryExpressions.Add(Ast.Call( typeof(RuntimeOps).GetMethod("OnFrameEnterTraceEvent"), _thread )); var frameExit = AstUtils.If( Ast.Equal( _debugMarkerLocationMap.Length > 0 ? Ast.Property(_sourceFilesMap[_debugMarkerLocationMap[0].SourceFile], "Mode") : _globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled) ), Ast.Call( typeof(RuntimeOps).GetMethod("OnFrameExitTraceEvent"), _thread, _debugMarker, _retVal != null ? (MSAst.Expression)Ast.Convert(_retVal, typeof(object)) : Ast.Constant(null) ) ); // normal exit tryExpressions.Add( Ast.Block( _retVal != null ? Ast.Assign(_retVal, debuggableBody) : debuggableBody, Ast.Assign(_frameExitException, Ast.Constant(true)), frameExit) ); tryExpressions.Add( _retVal != null ? (MSAst.Expression)Ast.Return(returnLabelTarget, _retVal) : Ast.Empty() ); MSAst.Expression[] popFrame = new MSAst.Expression[] { AstUtils.If( // Fire thead-exit event if PopFrame returns true Ast.AndAlso( Ast.Equal(Ast.Call(typeof(RuntimeOps).GetMethod("PopFrame"), _thread), Ast.Constant(true)), Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled)) ), Ast.Call( typeof(RuntimeOps).GetMethod("OnThreadExitEvent"), _thread ) ) }; if (_noPushFrameOptimization) { finallyExpressions.AddRange(popFrame); } else { finallyExpressions.Add( AstUtils.If( Ast.Equal(_framePushed, Ast.Constant(true)), popFrame ) ); } MSAst.ParameterExpression caughtException; // Run the function body bodyExpressions.Add(Ast.TryCatchFinally( Ast.TryCatch( Ast.Block( ArrayUtils.Append(tryExpressions.ToArray(), Ast.Default(returnType)) ), Ast.Catch( caughtException = Ast.Variable(typeof(Exception), "$caughtException"), Ast.Block( // The expressions below will always throw. // If the exception needs to be cancelled then OnTraceEvent will throw ForceToGeneratorLoopException. // If the exception is not being cancelled then we'll just rethrow at the end of the catch block. AstUtils.If( Ast.Not( Ast.TypeIs( caughtException, typeof(ForceToGeneratorLoopException) ) ), AstUtils.If( Ast.NotEqual(_globalDebugMode, AstUtils.Constant((int)DebugMode.Disabled)), _noPushFrameOptimization ? Ast.Empty() : _conditionalPushFrame, Ast.Call( typeof(RuntimeOps).GetMethod("OnTraceEventUnwind"), _thread, _debugMarker, caughtException ) ), // exception exit AstUtils.If( Ast.Not(_frameExitException), frameExit ) ), Ast.Rethrow(), // Ensuring that the catch block is of the same type as the try block Ast.Default(returnType) ) ) ), Ast.Block(finallyExpressions), Ast.Catch( typeof(ForceToGeneratorLoopException), Ast.TryFinally( // Handle ForceToGeneratorLoopException Ast.Block( returnType != typeof(void) ? Ast.Block( Ast.Assign( _retValFromGeneratorLoop, Ast.Call( typeof(RuntimeOps).GetMethod("GeneratorLoopProc"), _thread ) ), AstUtils.If( Ast.NotEqual( _retValFromGeneratorLoop, Ast.Constant(null) ), Ast.Assign(_retVal, Ast.Convert(_retValFromGeneratorLoop, returnType)), Ast.Return( returnLabelTarget, Ast.Convert(_retValFromGeneratorLoop, returnType) ) ).Else( Ast.Assign(_retVal, Ast.Default(returnType)), Ast.Return( returnLabelTarget, Ast.Default(returnType) ) ) ) : Ast.Block( Ast.Call( typeof(RuntimeOps).GetMethod("GeneratorLoopProc"), _thread ), Ast.Return(returnLabelTarget) ) , // Ensuring that the catch block is of the same type as the try block Ast.Default(returnType) ), // Make sure that the debugMarker is up-to-date after the generator loop Ast.Assign( _debugMarker, Ast.Call( typeof(RuntimeOps).GetMethod("GetCurrentSequencePointForLeafGeneratorFrame"), _thread ) ) ) ) )); MSAst.Expression body = Ast.Block(bodyExpressions); if (body.Type == typeof(void) && returnType != typeof(void)) { body = Ast.Block(body, Ast.Default(returnType)); } return(Ast.Lambda( lambdaType, Ast.Block( _lambdaVars, Ast.Label(returnLabelTarget, body) ), _alias, _lambdaParams)); }
internal MSA.Expression /*!*/ TransformStatements(MSA.Expression prologue, List <Expression> /*!*/ statements, MSA.Expression epilogue, ResultOperation resultOperation) { Assert.NotNullItems(statements); int count = statements.Count + (prologue != null ? 1 : 0) + (epilogue != null ? 1 : 0); if (count == 0) { if (resultOperation.IsIgnore) { return(Ast.Empty()); } else if (resultOperation.Variable != null) { return(Ast.Assign(resultOperation.Variable, Ast.Constant(null, resultOperation.Variable.Type))); } else { return(Ast.Return(CurrentFrame.ReturnLabel, Ast.Constant(null))); } } else if (count == 1) { if (prologue != null) { return(prologue); } if (epilogue != null) { return(epilogue); } if (resultOperation.IsIgnore) { return(statements[0].Transform(this)); } else { return(statements[0].TransformResult(this, resultOperation)); } } else { var result = new MSA.Expression[count + 1]; int resultIndex = 0; if (prologue != null) { result[resultIndex++] = prologue; } // transform all but the last statement if it is an expression stmt: for (int i = 0; i < statements.Count - 1; i++) { result[resultIndex++] = statements[i].Transform(this); } if (statements.Count > 0) { if (resultOperation.IsIgnore) { result[resultIndex++] = statements[statements.Count - 1].Transform(this); } else { result[resultIndex++] = statements[statements.Count - 1].TransformResult(this, resultOperation); } } if (epilogue != null) { result[resultIndex++] = epilogue; } result[resultIndex++] = MSA.Expression.Empty(); Debug.Assert(resultIndex == result.Length); return(Ast.Block(new ReadOnlyCollection <MSA.Expression>(result))); } }
internal MSA.Expression /*!*/ DebugMarker(string /*!*/ marker) { return(_debugCompiler ? Methods.X.OpCall(Ast.Constant(marker)) : (MSA.Expression)Ast.Empty()); }
public override MSA.Expression /*!*/ Reduce() { return(Ast.Empty()); }
internal MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen, bool isLambda) { ScopeBuilder scope = DefineLocals(gen.CurrentScope); // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment): MSA.ParameterExpression blockParameter, selfParameter; var parameters = DefineParameters(out selfParameter, out blockParameter); MSA.ParameterExpression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope)); MSA.LabelTarget redoLabel = Ast.Label(); gen.EnterBlockDefinition( scope, blockParameter, selfParameter, scopeVariable, redoLabel ); MSA.Expression paramInit = MakeParametersInitialization(gen, parameters); MSA.ParameterExpression blockUnwinder, filterVariable; MSA.Expression traceCall, traceReturn; if (gen.TraceEnabled) { int firstStatementLine = _body.Count > 0 ? _body.First.Location.Start.Line : Location.End.Line; int lastStatementLine = _body.Count > 0 ? _body.Last.Location.End.Line : Location.End.Line; traceCall = Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(firstStatementLine)); traceReturn = Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(lastStatementLine)); } else { traceCall = traceReturn = Ast.Empty(); } MSA.Expression body = AstUtils.Try( paramInit, traceCall, Ast.Label(redoLabel), AstUtils.Try( gen.TransformStatements(_body, ResultOperation.Return) ).Catch(blockUnwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"), // redo: AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Goto(redoLabel)), // next: gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField)) ) ).Filter(filterVariable = Ast.Parameter(typeof(Exception), "#e"), Methods.FilterBlockException.OpCall(scopeVariable, filterVariable) ).Finally( traceReturn, Ast.Empty() ); body = gen.AddReturnTarget( scope.CreateScope( scopeVariable, Methods.CreateBlockScope.OpCall(new AstExpressions { scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), blockParameter, selfParameter, EnterInterpretedFrameExpression.Instance }), body ) ); gen.LeaveBlockDefinition(); int parameterCount = ParameterCount; var attributes = _parameters.GetBlockSignatureAttributes(); var dispatcher = Ast.Constant( BlockDispatcher.Create(parameterCount, attributes, gen.SourcePath, Location.Start.Line), typeof(BlockDispatcher) ); return(Ast.Coalesce( (isLambda ? Methods.InstantiateLambda : Methods.InstantiateBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher), (isLambda ? Methods.DefineLambda : Methods.DefineBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher, BlockDispatcher.CreateLambda( body, RubyStackTraceBuilder.EncodeMethodName(gen.CurrentMethod.MethodName, gen.SourcePath, Location, gen.DebugMode), parameters, parameterCount, attributes ) ) )); }
internal MSA.LambdaExpression /*!*/ TransformBody(AstGenerator /*!*/ gen, RubyScope /*!*/ declaringScope, RubyModule /*!*/ declaringModule) { string encodedName = RubyStackTraceBuilder.EncodeMethodName(_name, gen.SourcePath, Location, gen.DebugMode); AstParameters parameters; ScopeBuilder scope = DefineLocals(out parameters); var scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyMethodScope)); var selfParameter = parameters[0]; var blockParameter = parameters[1]; // exclude block parameter even if it is explicitly specified: int visiblePrameterCountAndSignatureFlags = (parameters.Count - 2) << 2; if (_parameters.Block != null) { visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasBlockFlag; } if (_parameters.Unsplat != null) { visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasUnsplatFlag; } gen.EnterMethodDefinition( scope, selfParameter, scopeVariable, blockParameter, _name, _parameters ); // profiling: MSA.Expression profileStart, profileEnd; if (gen.Profiler != null) { int profileTickIndex = gen.Profiler.GetTickIndex(encodedName); var stampVariable = scope.DefineHiddenVariable("#stamp", typeof(long)); profileStart = Ast.Assign(stampVariable, Methods.Stopwatch_GetTimestamp.OpCall()); profileEnd = Methods.UpdateProfileTicks.OpCall(AstUtils.Constant(profileTickIndex), stampVariable); } else { profileStart = profileEnd = AstUtils.Empty(); } // tracing: MSA.Expression traceCall, traceReturn; if (gen.TraceEnabled) { traceCall = Methods.TraceMethodCall.OpCall( scopeVariable, gen.SourcePathConstant, AstUtils.Constant(Location.Start.Line) ); traceReturn = Methods.TraceMethodReturn.OpCall( gen.CurrentScopeVariable, gen.SourcePathConstant, AstUtils.Constant(Location.End.Line) ); } else { traceCall = traceReturn = AstUtils.Empty(); } MSA.ParameterExpression unwinder; MSA.Expression body = AstUtils.Try( profileStart, _parameters.TransformOptionalsInitialization(gen), traceCall, Body.TransformResult(gen, ResultOperation.Return) ).Filter(unwinder = Ast.Parameter(typeof(Exception), "#u"), Methods.IsMethodUnwinderTargetFrame.OpCall(scopeVariable, unwinder), Ast.Return(gen.ReturnLabel, Methods.GetMethodUnwinderReturnValue.OpCall(unwinder)) ).Finally( // leave frame: Methods.LeaveMethodFrame.OpCall(scopeVariable), Ast.Empty(), profileEnd, traceReturn ); body = gen.AddReturnTarget( scope.CreateScope( scopeVariable, Methods.CreateMethodScope.OpCall(new AstExpressions { scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), Ast.Constant(visiblePrameterCountAndSignatureFlags), Ast.Constant(declaringScope, typeof(RubyScope)), Ast.Constant(declaringModule, typeof(RubyModule)), Ast.Constant(_name), selfParameter, blockParameter, EnterInterpretedFrameExpression.Instance }), body ) ); gen.LeaveMethodDefinition(); return(CreateLambda(encodedName, parameters, body)); }
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)); }
static Statement Rewrite(Statement body) { if (body is LabeledStatement) { var ls = (LabeledStatement)body; return(ls.Mark(Rewrite(ls.Statement))); } if (body is BlockStatement) { var node = body as BlockStatement; var newbody = new List <Statement>(); foreach (var stmt in node.Statements) { var ns = Rewrite(stmt); if (ns is BlockStatement) { newbody.AddRange(((BlockStatement)ns).Statements); } else { newbody.Add(ns); } } return(Ast.Block(newbody)); } if (body is WriteStatement) { var ws = (WriteStatement)body; if (ws.Value is CommaExpression) { var ce = ws.Value as CommaExpression; var block = RewriteExpressions(ce.Expressions, x => Ast.Write(ws.Variable, x)); return(Rewrite(Ast.Block(block))); } else if (ws.Value == null) { var cb = ws.Variable.Block; if (cb != null) { cb.RemoveVariables(new List <Variable>(new[] { ws.Variable })); cb.Bind(); } return(Ast.Empty()); } else if (ws.Variable.Block == null) { //var cb = ws.Variable.Block; //cb.RemoveVariables(new List<Variable>(new[] { ws.Variable })); //cb.Bind(); return(Ast.Empty()); } else if (ws.HasNoRef) { //var cb = ws.Variable.Block; //cb.RemoveVariables(new List<Variable>(new[] { ws.Variable })); //cb.Bind(); //return Ast.Empty(); } } if (body is ReturnStatement) { var rs = body as ReturnStatement; if (rs.Expression is UnaryExpression && rs.Expression.NodeType == AstNodeType.Convert) { var ux = (UnaryExpression)rs.Expression; var op = ux.Operand; if (op is VoidExpression) { return(Rewrite(op as VoidExpression)); } if (op is CommaExpression) { var ce = op as CommaExpression; var block = RewriteExpressions(ce.Expressions, x => Ast.Return(Ast.ConvertHelper(x, ux.Type))); return(Rewrite(Ast.Block(block))); } } if (rs.Expression is CommaExpression) { var ce = rs.Expression as CommaExpression; var le = ce.Expressions[ce.Expressions.Count - 1]; if (le is VoidExpression && ((VoidExpression)le).Statement is ContinueStatement) { var block = RewriteExpressions(ce.Expressions, x => Ast.Continue()); return(Rewrite(Ast.Block(block))); } else { var block = RewriteExpressions(ce.Expressions, Ast.Return); return(Rewrite(Ast.Block(block))); } } if (rs.Expression is VoidExpression) { var ve = rs.Expression as VoidExpression; return(Rewrite(ve)); } if (rs.Expression is MethodCallExpression) { var mce = rs.Expression as MethodCallExpression; var uce = Unwrap(mce.Instance); if (uce is CommaExpression) { var ce = uce as CommaExpression; var block = RewriteExpressions(ce.Expressions, x => { if (mce.Arguments.Count == 1 && mce.Arguments[0].Type == typeof(object[])) { var mc = Ast.SimpleCallHelper(x, mce.Method, mce.Arguments.ToArray()); mc.TailCall = mce.TailCall; return(Ast.Return(mc)); } else { //var args = Array.ConvertAll(mce.Arguments.ToArray(), y => Ast.ConvertHelper(y, typeof(object))); var mc = Ast.SimpleCallHelper(x, mce.Method, mce.Arguments.ToArray()); mc.TailCall = mce.TailCall; return(Ast.Return(mc)); } }); return(Rewrite(Ast.Block(block))); } } } if (body is ExpressionStatement) { var es = (ExpressionStatement)body; var trs = TryRewriteExpression(es.Expression); if (trs != null) { return(trs); } } if (body is IfStatement) { var ifs = (IfStatement)body; if (ifs.ElseStatement == null) { return(Ast.If(ifs.Tests[0].Test, Rewrite(ifs.Tests[0].Body)).ToStatement()); } else { return(Ast.If(ifs.Tests[0].Test, Rewrite(ifs.Tests[0].Body)).Else(Rewrite(ifs.ElseStatement))); } } return(body); }
internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { TransformBody(gen); return(Ast.Empty()); }
private MSA.Expression /*!*/ TransformExceptionHandling(AstGenerator /*!*/ gen, ResultOperation resultOperation) { Assert.NotNull(gen); MSA.Expression exceptionThrownVariable = gen.CurrentScope.DefineHiddenVariable("#exception-thrown", typeof(bool)); MSA.ParameterExpression exceptionVariable = gen.CurrentScope.DefineHiddenVariable("#exception", typeof(Exception)); MSA.Expression exceptionRethrowVariable = gen.CurrentScope.DefineHiddenVariable("#exception-rethrow", typeof(bool)); MSA.Expression retryingVariable = gen.CurrentScope.DefineHiddenVariable("#retrying", typeof(bool)); MSA.ParameterExpression evalUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder)); MSA.Expression oldExceptionVariable = gen.CurrentScope.DefineHiddenVariable("#old-exception", typeof(Exception)); MSA.Expression transformedBody; MSA.Expression transformedEnsure; MSA.Expression transformedElse; if (_ensureStatements != null) { transformedEnsure = Ast.Block( // ensure: Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)), gen.TransformStatements(_ensureStatements, ResultOperation.Ignore), Methods.SetCurrentException.OpCall(gen.CurrentScopeVariable, oldExceptionVariable), // rethrow: AstUtils.IfThen( Ast.AndAlso( exceptionRethrowVariable, Ast.NotEqual(oldExceptionVariable, Ast.Constant(null)) ), Ast.Throw(oldExceptionVariable) ), Ast.Empty() ); } else { // rethrow: transformedEnsure = AstUtils.IfThen( Ast.AndAlso( exceptionRethrowVariable, Ast.NotEqual( Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)), Ast.Constant(null, typeof(Exception))) ), Ast.Throw(oldExceptionVariable) ); } if (_elseStatements != null) { transformedElse = gen.TransformStatements(_elseStatements, resultOperation); } else { transformedElse = Ast.Empty(); } // body should do return, but else-clause is present => we cannot do return from the guarded statements: // (the value of the last expression in the body cannot be the last executed expression statement => we can ignore it): transformedBody = gen.TransformStatements(_statements, (_elseStatements != null) ? ResultOperation.Ignore : resultOperation); MSA.Expression setInRescueFlag = null, clearInRescueFlag = null; var breakLabel = Ast.Label(); var continueLabel = Ast.Label(); // make rescue clause: MSA.Expression transformedRescue; if (_rescueClauses != null) { // outer-most EH blocks sets and clears runtime flag RuntimeFlowControl.InTryRescue: if (gen.CurrentRescue == null) { setInRescueFlag = Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InRescueField), Ast.Constant(true)); clearInRescueFlag = Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InRescueField), Ast.Constant(false)); } else { setInRescueFlag = clearInRescueFlag = Ast.Empty(); } gen.EnterRescueClause(retryingVariable, breakLabel, continueLabel); var handlers = new IfStatementTest[_rescueClauses.Count]; for (int i = 0; i < handlers.Length; i++) { handlers[i] = _rescueClauses[i].Transform(gen, resultOperation); } transformedRescue = Ast.Block( setInRescueFlag, AstUtils.Try( AstUtils.If(handlers, Ast.Assign(exceptionRethrowVariable, Ast.Constant(true))) ).Filter(evalUnwinder, Ast.Equal(Ast.Field(evalUnwinder, EvalUnwinder.ReasonField), Ast.Constant(BlockReturnReason.Retry)), Ast.Block( Ast.Assign(retryingVariable, Ast.Constant(true)), Ast.Continue(continueLabel), Ast.Empty() ) ) ); gen.LeaveRescueClause(); } else { transformedRescue = Ast.Assign(exceptionRethrowVariable, Ast.Constant(true)); } if (_elseStatements != null) { transformedElse = AstUtils.Unless(exceptionThrownVariable, transformedElse); } var result = AstFactory.Infinite(breakLabel, continueLabel, Ast.Assign(exceptionThrownVariable, Ast.Constant(false)), Ast.Assign(exceptionRethrowVariable, Ast.Constant(false)), Ast.Assign(retryingVariable, Ast.Constant(false)), AstUtils.Try( // save exception (old_$! is not used unless there is a rescue clause): Ast.Block( (_rescueClauses == null) ? (MSA.Expression)Ast.Empty() : Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)), AstUtils.Try( transformedBody ).Filter(exceptionVariable, Methods.CanRescue.OpCall(gen.CurrentRfcVariable, exceptionVariable), Ast.Assign(exceptionThrownVariable, Ast.Constant(true)), Methods.SetCurrentExceptionAndStackTrace.OpCall(gen.CurrentScopeVariable, exceptionVariable), transformedRescue ).FinallyIf((_rescueClauses != null), // restore previous exception if the current one has been handled: AstUtils.Unless(exceptionRethrowVariable, Methods.SetCurrentException.OpCall(gen.CurrentScopeVariable, oldExceptionVariable) ), clearInRescueFlag ), // unless (exception_thrown) do <else-statements> end transformedElse, Ast.Empty() ) ).FilterIf((_rescueClauses != null || _elseStatements != null), exceptionVariable, Methods.CanRescue.OpCall(gen.CurrentRfcVariable, exceptionVariable), Ast.Block( Methods.SetCurrentExceptionAndStackTrace.OpCall(gen.CurrentScopeVariable, exceptionVariable), Ast.Assign(exceptionRethrowVariable, Ast.Constant(true)), Ast.Empty() ) ).Finally( AstUtils.Unless(retryingVariable, transformedEnsure) ), Ast.Break(breakLabel) ); return(result); }
internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { return(AstUtils.IfThenElse(TransformCondition(gen), _body.Transform(gen), _elseStatement != null ? _elseStatement.Transform(gen) : Ast.Empty() )); }
protected override MSAst.Expression VisitDebugInfo(MSAst.DebugInfoExpression node) { if (!node.IsClear) { MSAst.Expression transformedExpression; // Verify that DebugInfoExpression has valid SymbolDocumentInfo if (node.Document == null) { throw new InvalidOperationException( string.Format( CultureInfo.CurrentCulture, ErrorStrings.DebugInfoWithoutSymbolDocumentInfo, _locationCookie)); } DebugSourceFile sourceFile = _debugContext.GetDebugSourceFile( String.IsNullOrEmpty(node.Document.FileName) ? "<compile>" : node.Document.FileName); // Update the location cookie int locationCookie = _locationCookie++; if (!_transformToGenerator) { MSAst.Expression tracebackCall = null; if (locationCookie == 0) { tracebackCall = Ast.Empty(); } else { tracebackCall = Ast.Call( typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.OnTraceEvent)), _thread, AstUtils.Constant(locationCookie), Ast.Convert(Ast.Constant(null), typeof(Exception)) ); } transformedExpression = Ast.Block( Ast.Assign( _debugMarker, AstUtils.Constant(locationCookie) ), Ast.IfThen( Ast.GreaterThan( Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"), Ast.Constant((int)DebugMode.ExceptionsOnly) ), Ast.IfThen( Ast.OrElse( Ast.Equal( Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"), Ast.Constant((int)DebugMode.FullyEnabled) ), Ast.ArrayIndex( _traceLocations, AstUtils.Constant(locationCookie) ) ), Ast.Block( _pushFrame ?? Ast.Empty(), tracebackCall ) ) ) ); } else { Debug.Assert(_generatorLabelTarget != null); transformedExpression = Ast.Block( AstUtils.YieldReturn( _generatorLabelTarget, _debugYieldValue, locationCookie ) ); // Update the variable scope map if (_currentLocals.Count > 0) { BlockExpression curentBlock = _currentLocals.Peek(); if (!_variableScopeMapCache.TryGetValue(curentBlock, out IList <VariableInfo> scopedVaribles)) { scopedVaribles = new List <VariableInfo>(); BlockExpression[] blocks = _currentLocals.ToArray(); for (int i = blocks.Length - 1; i >= 0; i--) { foreach (var variable in blocks[i].Variables) { scopedVaribles.Add(_localsToVarInfos[variable]); } } _variableScopeMapCache.Add(curentBlock, scopedVaribles); } _variableScopeMap.Add(locationCookie, scopedVaribles); } DebugSourceSpan span = new DebugSourceSpan( sourceFile, node.StartLine, node.StartColumn, node.EndLine, node.EndColumn); // Update the location-span map _markerLocationMap.Add(locationCookie, span); } return(transformedExpression); } return(Ast.Empty()); }
/// <summary> /// WithStatement is translated to the DLR AST equivalent to /// the following Python code snippet (from with statement spec): /// /// mgr = (EXPR) /// exit = mgr.__exit__ # Not calling it yet /// value = mgr.__enter__() /// exc = True /// try: /// VAR = value # Only if "as VAR" is present /// BLOCK /// except: /// # The exceptional case is handled here /// exc = False /// if not exit(*sys.exc_info()): /// raise /// # The exception is swallowed if exit() returns true /// finally: /// # The normal and non-local-goto cases are handled here /// if exc: /// exit(None, None, None) /// /// </summary> public override MSAst.Expression Reduce() { // Five statements in the result... ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(6); ReadOnlyCollectionBuilder <MSAst.ParameterExpression> variables = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(6); MSAst.ParameterExpression lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_with"); variables.Add(lineUpdated); //****************************************************************** // 1. mgr = (EXPR) //****************************************************************** MSAst.ParameterExpression manager = Ast.Variable(typeof(object), "with_manager"); variables.Add(manager); statements.Add( GlobalParent.AddDebugInfo( Ast.Assign( manager, _contextManager ), new SourceSpan(Start, _header) ) ); //****************************************************************** // 2. exit = mgr.__exit__ # Not calling it yet //****************************************************************** MSAst.ParameterExpression exit = Ast.Variable(typeof(object), "with_exit"); variables.Add(exit); statements.Add( MakeAssignment( exit, GlobalParent.Get( "__exit__", manager ) ) ); //****************************************************************** // 3. value = mgr.__enter__() //****************************************************************** MSAst.ParameterExpression value = Ast.Variable(typeof(object), "with_value"); variables.Add(value); statements.Add( GlobalParent.AddDebugInfoAndVoid( MakeAssignment( value, Parent.Invoke( new CallSignature(0), Parent.LocalContext, GlobalParent.Get( "__enter__", manager ) ) ), new SourceSpan(Start, _header) ) ); //****************************************************************** // 4. exc = True //****************************************************************** MSAst.ParameterExpression exc = Ast.Variable(typeof(bool), "with_exc"); variables.Add(exc); statements.Add( MakeAssignment( exc, AstUtils.Constant(true) ) ); //****************************************************************** // 5. The final try statement: // // try: // VAR = value # Only if "as VAR" is present // BLOCK // except: // # The exceptional case is handled here // exc = False // if not exit(*sys.exc_info()): // raise // # The exception is swallowed if exit() returns true // finally: // # The normal and non-local-goto cases are handled here // if exc: // exit(None, None, None) //****************************************************************** MSAst.ParameterExpression exception; MSAst.ParameterExpression nestedFrames = Ast.Variable(typeof(List <DynamicStackFrame>), "$nestedFrames"); variables.Add(nestedFrames); statements.Add( // try: AstUtils.Try( AstUtils.Try(// try statement body PushLineUpdated(false, lineUpdated), _var != null ? (MSAst.Expression)Ast.Block( // VAR = value _var.TransformSet(SourceSpan.None, value, PythonOperationKind.None), // BLOCK _body, AstUtils.Empty() ) : // BLOCK (MSAst.Expression)_body // except:, // try statement location ).Catch(exception = Ast.Variable(typeof(Exception), "exception"), // Python specific exception handling code TryStatement.GetTracebackHeader( this, exception, GlobalParent.AddDebugInfoAndVoid( Ast.Block( // exc = False MakeAssignment( exc, AstUtils.Constant(false) ), Ast.Assign( nestedFrames, Ast.Call(AstMethods.GetAndClearDynamicStackFrames) ), // if not exit(*sys.exc_info()): // raise AstUtils.IfThen( GlobalParent.Convert( typeof(bool), ConversionResultKind.ExplicitCast, GlobalParent.Operation( typeof(bool), PythonOperationKind.IsFalse, MakeExitCall(exit, exception) ) ), UpdateLineUpdated(true), Ast.Call( AstMethods.SetDynamicStackFrames, nestedFrames ), Ast.Throw( Ast.Call( AstMethods.MakeRethrowExceptionWorker, exception ) ) ) ), _body.Span ) ), Ast.Call( AstMethods.SetDynamicStackFrames, nestedFrames ), PopLineUpdated(lineUpdated), Ast.Empty() ) // finally: ).Finally( // if exc: // exit(None, None, None) AstUtils.IfThen( exc, GlobalParent.AddDebugInfoAndVoid( Ast.Block( Ast.Dynamic( GlobalParent.PyContext.Invoke( new CallSignature(3) // signature doesn't include function ), typeof(object), new MSAst.Expression[] { Parent.LocalContext, exit, AstUtils.Constant(null), AstUtils.Constant(null), AstUtils.Constant(null) } ), Ast.Empty() ), _contextManager.Span ) ) ) ); statements.Add(AstUtils.Empty()); return(Ast.Block(variables.ToReadOnlyCollection(), statements.ToReadOnlyCollection())); }
// 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 blockUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(BlockUnwinder)); MSA.ParameterExpression evalUnwinder = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder)); 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 = AstFactory.IsTrue(_condition.TransformRead(gen)); gen.LeaveLoop(); MSA.Expression conditionPositiveStmt, conditionNegativeStmt; if (_isWhileLoop) { conditionPositiveStmt = Ast.Empty(); conditionNegativeStmt = Ast.Break(breakLabel); } else { conditionPositiveStmt = Ast.Break(breakLabel); conditionNegativeStmt = Ast.Empty(); } // make the loop first: MSA.Expression loop = Ast.Block( Ast.Assign(redoVariable, Ast.Constant(_isPostTest)), AstFactory.Infinite(breakLabel, continueLabel, AstUtils.Try( AstUtils.If(redoVariable, Ast.Assign(redoVariable, Ast.Constant(false)) ).ElseIf(transformedCondition, conditionPositiveStmt ).Else( conditionNegativeStmt ), transformedBody ).Catch(blockUnwinder, // redo = u.IsRedo Ast.Assign(redoVariable, Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField)) ).Filter(evalUnwinder, Ast.Equal(Ast.Field(evalUnwinder, EvalUnwinder.ReasonField), AstFactory.BlockReturnReasonBreak), // result = unwinder.ReturnValue Ast.Assign(resultVariable, Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField)), Ast.Break(breakLabel) ) ), Ast.Empty() ); // wrap it to try finally that updates RFC state: if (!isInnerLoop) { loop = AstUtils.Try( Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InLoopField), Ast.Constant(true)), loop ).Finally( Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InLoopField), Ast.Constant(false)) ); } return(AstFactory.Block(loop, resultVariable)); }