internal MSA.Expression /*!*/ TransformOptionalsInitialization(AstGenerator /*!*/ gen) { Assert.NotNull(gen); if (_optional.Length == 0) { return(AstUtils.Empty()); } MSA.Expression singleton = gen.CurrentScope.DefineHiddenVariable("#default", typeof(object)); MSA.Expression result = AstUtils.Empty(); for (int i = 0; i < _optional.Length; i++) { result = AstUtils.IfThen( Ast.Equal(_optional[i].Left.TransformRead(gen), singleton), Ast.Block( result, _optional[i].TransformRead(gen) // assignment ) ); } return(Ast.Block( Ast.Assign(singleton, Ast.Field(null, Fields.DefaultArgument)), result, AstUtils.Empty() )); }
/// <summary> /// Gets the expression for the actual updating of the line number for stack traces to be available /// </summary> internal MSAst.Expression GetSaveLineNumberExpression(MSAst.ParameterExpression exception, bool preventAdditionalAdds) { Debug.Assert(exception.Type == typeof(Exception)); return(Ast.Block( AstUtils.If( Ast.Not( LineNumberUpdated ), Ast.Call( AstMethods.UpdateStackTrace, exception, LocalContext, _funcCodeExpr, _GetCurrentMethod, AstUtils.Constant(Name), AstUtils.Constant(GlobalParent.SourceUnit.Path ?? "<string>"), new LastFaultingLineExpression(LineNumberExpression) ) ), Ast.Assign( LineNumberUpdated, AstUtils.Constant(preventAdditionalAdds) ), AstUtils.Empty() )); }
private MSA.Expression /*!*/ MakeParametersInitialization(AstGenerator /*!*/ gen, AstParameters /*!*/ parameters) { var result = new AstExpressions( _parameters.LeftValues.Count + (_parameters.UnsplattedValue != null ? 1 : 0) + 1 ); bool paramsInArray = HasFormalParametersInArray; for (int i = 0; i < _parameters.LeftValues.Count; i++) { var parameter = paramsInArray ? (MSA.Expression) Ast.ArrayAccess(parameters[HiddenParameterCount], AstUtils.Constant(i)) : parameters[HiddenParameterCount + i]; result.Add(_parameters.LeftValues[i].TransformWrite(gen, parameter)); } if (_parameters.UnsplattedValue != null) { // the last parameter is unsplat: var parameter = parameters[parameters.Count - 1]; result.Add(_parameters.UnsplattedValue.TransformWrite(gen, parameter)); } result.Add(AstUtils.Empty()); return(Ast.Block(result)); }
internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { return(AstUtils.IfThenElse( _condition.TransformCondition(gen, !_negateCondition), _body.Transform(gen), _elseStatement != null ? _elseStatement.Transform(gen) : AstUtils.Empty() )); }
internal sealed override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { string debugString = (IsSingletonDeclaration) ? "SINGLETON" : ((this is ClassDefinition) ? "CLASS" : "MODULE") + " " + QualifiedName.Name; ScopeBuilder outerLocals = gen.CurrentScope; // definition needs to take place outside the defined lexical scope: var definition = MakeDefinitionExpression(gen); var selfVariable = outerLocals.DefineHiddenVariable("#module", typeof(RubyModule)); var parentScope = gen.CurrentScopeVariable; // inner locals: ScopeBuilder scope = DefineLocals(); var scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyScope)); gen.EnterModuleDefinition( scope, selfVariable, scopeVariable, IsSingletonDeclaration ); // 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 = new AstBlock { gen.DebugMarker(debugString), Ast.Assign(selfVariable, definition), scope.CreateScope( scopeVariable, Methods.CreateModuleScope.OpCall( scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), parentScope, selfVariable ), Ast.Block( Ast.Assign(resultVariable, transformedBody), AstUtils.Empty() ) ), gen.DebugMarker("END OF " + debugString), resultVariable }; gen.LeaveModuleDefinition(); return(result); }
/// <summary> /// Gets the expression for the actual updating of the line number for stack traces to be available /// </summary> internal MSAst.Expression GetSaveLineNumberExpression(bool preventAdditionalAdds) { MSAst.Expression res; if (preventAdditionalAdds) { res = _saveLineNumberNoAdds; } else { res = _saveLineNumberAdds; } if (res == null) { res = Ast.Block( AstUtils.If( Ast.Not( LineNumberUpdated ), Ast.Call( AstMethods.UpdateStackTrace, LocalContext, _funcCodeExpr, _GetCurrentMethod, AstUtils.Constant(Name), AstUtils.Constant(GlobalParent.SourceUnit.Path ?? "<string>"), new LastFaultingLineExpression(LineNumberExpression) ) ), Ast.Assign( LineNumberUpdated, AstUtils.Constant(preventAdditionalAdds) ), AstUtils.Empty() ); if (preventAdditionalAdds) { _saveLineNumberNoAdds = res; } else { _saveLineNumberAdds = res; } } return(res); }
/// <summary> /// Gets the expression for the actual updating of the line number for stack traces to be available /// </summary> internal MSAst.Expression GetSaveLineNumberExpression(MSAst.ParameterExpression exception, bool preventAdditionalAdds) { Debug.Assert(exception.Type == typeof(Exception)); return Ast.Block( AstUtils.If( Ast.Not( LineNumberUpdated ), UpdateStackTrace(exception) ), Ast.Assign( LineNumberUpdated, AstUtils.Constant(preventAdditionalAdds) ), AstUtils.Empty() ); }
private MSA.Expression /*!*/ MakeParametersInitialization(AstGenerator /*!*/ gen, AstParameters /*!*/ parameters) { var result = new AstExpressions( ParameterCount + (_parameters.Optional.Length > 0 ? 1 : 0) + (_parameters.Unsplat != null ? 1 : 0) + (_parameters.Block != null ? 1 : 0) + 1 ); // TODO: we can skip parameters that are locals (need to be defined as parameters, not as #n): var paramsArray = HasFormalParametersInArray ? parameters[HiddenParameterCount] : null; int parameterIndex = 0; for (int i = 0; i < _parameters.Mandatory.Length; i++) { result.Add(_parameters.Mandatory[i].TransformWrite(gen, GetParameterAccess(parameters, paramsArray, parameterIndex))); parameterIndex++; } if (_parameters.Optional.Length > 0) { for (int i = 0; i < _parameters.Optional.Length; i++) { result.Add(_parameters.Optional[i].Left.TransformWrite(gen, GetParameterAccess(parameters, paramsArray, parameterIndex))); parameterIndex++; } result.Add(_parameters.TransformOptionalsInitialization(gen)); } if (_parameters.Unsplat != null) { // the last parameter is unsplat: result.Add(_parameters.Unsplat.TransformWrite(gen, parameters[parameters.Count - (_parameters.Block != null ? 2 : 1)])); } if (_parameters.Block != null) { result.Add(_parameters.Block.TransformWrite(gen, parameters[parameters.Count - 1])); parameterIndex++; } result.Add(AstUtils.Empty()); return(Ast.Block(result)); }
public override MSAst.Expression Reduce() { MSAst.Expression destination = _dest; if (_expressions.Length == 0) { MSAst.Expression result; if (destination != null) { result = Ast.Call( AstMethods.PrintNewlineWithDest, Parent.LocalContext, destination ); } else { result = Ast.Call( AstMethods.PrintNewline, Parent.LocalContext ); } return(GlobalParent.AddDebugInfo(result, Span)); } else { // Create list for the individual statements ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(); // Store destination in a temp, if we have one MSAst.ParameterExpression temp = null; if (destination != null) { temp = Ast.Variable(typeof(object), "destination"); statements.Add(MakeAssignment(temp, destination)); destination = temp; } for (int i = 0; i < _expressions.Length; i++) { bool withComma = (i < _expressions.Length - 1 || _trailingComma);// ? "PrintComma" : "Print"; Expression current = _expressions[i]; MSAst.MethodCallExpression mce; if (destination != null) { mce = Ast.Call( withComma ? AstMethods.PrintCommaWithDest : AstMethods.PrintWithDest, Parent.LocalContext, destination, AstUtils.Convert(current, typeof(object)) ); } else { mce = Ast.Call( withComma ? AstMethods.PrintComma : AstMethods.Print, Parent.LocalContext, AstUtils.Convert(current, typeof(object)) ); } statements.Add(mce); } statements.Add(AstUtils.Empty()); MSAst.Expression res; if (temp != null) { res = Ast.Block(new[] { temp }, statements.ToReadOnlyCollection()); } else { res = Ast.Block(statements.ToReadOnlyCollection()); } return(GlobalParent.AddDebugInfo(res, Span)); } }
internal MSA.Expression /*!*/ TransformStatements(MSA.Expression prologue, Statements /*!*/ statements, MSA.Expression epilogue, ResultOperation resultOperation) { Assert.NotNull(statements); int count = statements.Count + (prologue != null ? 1 : 0) + (epilogue != null ? 1 : 0); if (count == 0) { if (resultOperation.IsIgnore) { return(AstUtils.Empty()); } else if (resultOperation.Variable != null) { return(Ast.Assign(resultOperation.Variable, AstUtils.Constant(null, resultOperation.Variable.Type))); } else { return(Ast.Return(CurrentFrame.ReturnLabel, AstUtils.Constant(null))); } } else if (count == 1) { if (prologue != null) { return(prologue); } if (epilogue != null) { return(epilogue); } if (resultOperation.IsIgnore) { return(statements.First.Transform(this)); } else { return(statements.First.TransformResult(this, resultOperation)); } } else { var result = new AstBlock(); if (prologue != null) { result.Add(prologue); } // transform all but the last statement if it is an expression stmt: foreach (var statement in statements.AllButLast) { result.Add(statement.Transform(this)); } if (statements.Count > 0) { if (resultOperation.IsIgnore) { result.Add(statements.Last.Transform(this)); } else { result.Add(statements.Last.TransformResult(this, resultOperation)); } } if (epilogue != null) { result.Add(epilogue); } result.Add(AstUtils.Empty()); return(result); } }
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)); }
// 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)); }