private void TransformBody(AstGenerator/*!*/ gen) { ScopeBuilder scope = DefineLocals(); var scopeVariable = gen.TopLevelScope.Builder.DefineHiddenVariable("#scope", typeof(RubyScope)); gen.EnterFileInitializer( scope, gen.TopLevelScope.SelfVariable, scopeVariable ); // visit nested initializers depth-first: var body = gen.TransformStatements(_statements, ResultOperation.Ignore); gen.LeaveFileInitializer(); gen.AddFileInitializer( scope.CreateScope( scopeVariable, Methods.CreateFileInitializerScope.OpCall( scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), gen.TopLevelScope.RuntimeScopeVariable ), body ) ); }
internal static MSA.Expression/*!*/ TransformConcatentation(AstGenerator/*!*/ gen, List<Expression>/*!*/ parts, Func<string, MethodInfo>/*!*/ opFactory, MSA.Expression additionalArg) { var opSuffix = new StringBuilder(Math.Min(parts.Count, 4)); List<MSA.Expression> merged = ConcatLiteralsAndTransform(gen, parts, opSuffix); if (merged.Count <= RubyOps.MakeStringParamCount) { if (merged.Count == 0) { merged.Add(Ast.Constant(String.Empty)); opSuffix.Append(RubyOps.SuffixBinary); } if (opSuffix.IndexOf(RubyOps.SuffixEncoded) != -1) { merged.Add(Ast.Constant(RubyEncoding.GetCodePage(gen.Encoding))); } if (additionalArg != null) { merged.Add(additionalArg); } return opFactory(opSuffix.ToString()).OpCall(merged); } else { var paramArray = Ast.NewArrayInit(typeof(object), merged); var codePage = Ast.Constant(RubyEncoding.GetCodePage(gen.Encoding)); return (additionalArg != null) ? opFactory("N").OpCall(paramArray, codePage, additionalArg) : opFactory("N").OpCall(paramArray, codePage); } }
internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { return Methods.MatchString.OpCall( Ast.Dynamic(ConvertToStrAction.Make(gen.Context), typeof(MutableString), _expression.Transform(gen)), _regex.Transform(gen), gen.CurrentScopeVariable ); }
internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { return AstFactory.Condition( Methods.IsFalse.OpCall(AstFactory.Box(_condition.TransformRead(gen))), gen.TransformStatementsToExpression(_statements), gen.TransformStatementsToExpression(_elseClause != null ? _elseClause.Statements : null) ); }
internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { string setterName = _memberName + "="; MSA.Expression transformedLeftTarget = _leftTarget.TransformRead(gen); MSA.Expression transformedRight = _right.TransformRead(gen); MSA.Expression leftTemp = gen.CurrentScope.DefineHiddenVariable(String.Empty, transformedLeftTarget.Type); bool leftIsSelf = _leftTarget.NodeType == NodeTypes.SelfReference; // lhs &&= rhs --> left.member && (left.member = rhs) // lhs ||= rhs --> left.member || (left.member = rhs) if (Operation == Symbols.And || Operation == Symbols.Or) { MSA.Expression leftMemberRead = MethodCall.TransformRead(this, gen, false, _memberName, Ast.Assign(leftTemp, transformedLeftTarget), null, null, null, null); MSA.Expression transformedWrite = MethodCall.TransformRead(this, gen, leftIsSelf, setterName, leftTemp, null, null, null, transformedRight); if (Operation == Symbols.And) { return AndExpression.TransformRead(gen, leftMemberRead, transformedWrite); } else { return OrExpression.TransformRead(gen, leftMemberRead, transformedWrite); } } else { // left.member= left.member().op(right) MSA.Expression leftMemberRead = MethodCall.TransformRead(this, gen, false, _memberName, leftTemp, null, null, null, null); MSA.Expression operationCall = MethodCall.TransformRead(this, gen, false, Operation, leftMemberRead, null, null, transformedRight, null); MSA.Expression transformedWrite = MethodCall.TransformRead(this, gen, leftIsSelf, setterName, Ast.Assign(leftTemp, transformedLeftTarget), null, null, null, operationCall); return transformedWrite; } }
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 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() ); }
internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { MSA.Expression result; int i = _elseIfClauses.Count - 1; if (i >= 0 && _elseIfClauses[i].Condition == null) { // ... else body end result = gen.TransformStatementsToExpression(_elseIfClauses[i].Statements); i--; } else { // no else clause => the result of the if-expression is nil: result = AstUtils.Constant(null); } while (i >= 0) { // emit: else (if (condition) body else result) result = AstFactory.Condition( _elseIfClauses[i].Condition.TransformCondition(gen, true), gen.TransformStatementsToExpression(_elseIfClauses[i].Statements), result ); i--; } // if (condition) body else result return AstFactory.Condition( _condition.TransformCondition(gen, true), gen.TransformStatementsToExpression(_body), result ); }
MSA.Expression/*!*/ StringConstructor.IFactory.CreateExpressionN(AstGenerator/*!*/ gen, IEnumerable<MSA.Expression>/*!*/ args) { return Methods.CreateRegex("N").OpCall( Ast.NewArrayInit(typeof(MutableString), args), AstUtils.Constant(_options), AstUtils.Constant(new StrongBox<RubyRegex>(null)) ); }
// 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 override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { return AstFactory.Condition( _condition.TransformReadBoolean(gen, true), _trueExpression.TransformRead(gen), _falseExpression.TransformRead(gen) ); }
// 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.CurrentScopeVariable, AstUtils.Box(transformedReturnValue)); } // loop: if (gen.CurrentLoop != null) { return Ast.Block( transformedReturnValue, // evaluate for side-effects Ast.Continue(gen.CurrentLoop.ContinueLabel), AstUtils.Empty() ); } // block: if (gen.CurrentBlock != null) { return gen.Return(transformedReturnValue); } // method: return Methods.MethodNext.OpCall(gen.CurrentScopeVariable, AstUtils.Box(transformedReturnValue)); }
// 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 postYield; if (gen.CompilerOptions.IsEval) { // eval: postYield = Methods.EvalYield.OpCall(gen.CurrentScopeVariable, bfcVariable, resultVariable); } else if (gen.CurrentBlock != null) { // block: postYield = Methods.BlockYield.OpCall(gen.CurrentScopeVariable, gen.CurrentBlock.BfcVariable, bfcVariable, resultVariable); } else { // method: postYield = Methods.MethodYield.OpCall(gen.CurrentScopeVariable, bfcVariable, resultVariable); } return new AstBlock { gen.DebugMarker("#RB: yield begin"), Ast.Assign(bfcVariable, Methods.CreateBfcForYield.OpCall(gen.MakeMethodBlockParameterRead())), Ast.Assign( resultVariable, (Arguments ?? Arguments.Empty).TransformToYield(gen, bfcVariable, gen.MakeMethodBlockParameterSelfRead()) ), AstUtils.IfThen(postYield, gen.Return(resultVariable)), gen.DebugMarker("#RB: yield end"), resultVariable }; }
private MSA.Expression/*!*/ TransformBody(AstGenerator/*!*/ gen, MSA.Expression/*!*/ methodDefinitionVariable) { string encodedName = RubyExceptionData.EncodeMethodName(gen.SourceUnit, _name, Location); ScopeBuilder scope = new ScopeBuilder(); MSA.Expression parentScope = gen.CurrentScopeVariable; MSA.ParameterExpression[] parameters = DefineParameters(gen, scope); MSA.Expression currentMethodVariable = scope.DefineHiddenVariable("#method", typeof(RubyMethodInfo)); MSA.Expression rfcVariable = scope.DefineHiddenVariable("#rfc", typeof(RuntimeFlowControl)); MSA.Expression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyMethodScope)); MSA.Expression selfParameter = parameters[0]; MSA.Expression blockParameter = parameters[1]; gen.EnterMethodDefinition( scope, selfParameter, scopeVariable, blockParameter, rfcVariable, currentMethodVariable, _name, _parameters ); DefinedScope.TransformLocals(scope); MSA.ParameterExpression unwinder = scope.DefineHiddenVariable("#unwinder", typeof(MethodUnwinder)); MSA.Expression body = AstFactory.MakeUserMethodBody( gen, Location.End.Line, blockParameter, rfcVariable, unwinder, Ast.Block( Ast.Assign(currentMethodVariable, methodDefinitionVariable), Ast.Assign(scopeVariable, Methods.CreateMethodScope.OpCall( scope.VisibleVariables(), parentScope, currentMethodVariable, rfcVariable, selfParameter, blockParameter) ), _parameters.TransformOptionalsInitialization(gen), gen.TraceEnabled ? Methods.TraceMethodCall.OpCall(scopeVariable, Ast.Convert(AstUtils.Constant(gen.SourceUnit.Path), typeof(string)), AstUtils.Constant(Location.Start.Line)) : AstUtils.Empty(), Body.TransformResult(gen, ResultOperation.Return), AstUtils.Empty() ), ResultOperation.Return, (gen.Profiler != null) ? gen.Profiler.GetTickIndex(encodedName) : -1, (gen.Profiler != null) ? scope.DefineHiddenVariable("#stamp", typeof(long)) : null, gen.ReturnLabel ); body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveMethodDefinition(); return CreateLambda( encodedName, parameters, body ); }
MSA.Expression/*!*/ StringConstructor.IFactory.CreateExpressionM(AstGenerator/*!*/ gen, MSAst.ExpressionCollectionBuilder/*!*/ args) { string suffix = new String('M', args.Count); args.Add(gen.Encoding.Expression); args.Add(AstUtils.Constant(_options)); args.Add(AstUtils.Constant(new StrongBox<RubyRegex>(null))); return Methods.CreateRegex(suffix).OpCall(args); }
/*!*/ internal override MSA.Expression TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { Assert.NotNull(gen, rightValue); // no-op return rightValue; }
internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { return AstFactory.Condition( _condition.TransformCondition(gen, false), gen.TransformStatementsToExpression(_statements), gen.TransformStatementsToExpression(_elseClause != null ? _elseClause.Statements : null) ); }
internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { return Ast.Condition( _condition.TransformReadBoolean(gen, !_negateCondition), AstUtils.Box(_body.TransformRead(gen)), (_elseStatement != null) ? AstUtils.Box(_elseStatement.TransformRead(gen)) : (MSA.Expression)AstUtils.Constant(null) ); }
internal override MSA.Expression/*!*/ TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { if (gen.CompilerOptions.IsEval || gen.GetCurrentNonSingletonModule() != null) { return Methods.SetClassVariable.OpCall(AstFactory.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name)); } else { return Methods.SetObjectClassVariable.OpCall(AstFactory.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name)); } }
// 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; }
private static MethodInfo/*!*/ GetOp(AstGenerator/*!*/ gen, int/*!*/ opKind) { switch (opKind) { case OpTryGet: return Methods.TryGetClassVariable; case OpGet: return Methods.GetClassVariable; case OpIsDefined: return Methods.IsDefinedClassVariable; default: throw Assert.Unreachable; } }
private MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, int/*!*/ opKind) { // eval or in a non-singleton module/class declaration // -> we find the right scope at runtime by walking the hierarchy // otherwise // -> variable is on Object return GetOp(gen, opKind).OpCall(gen.CurrentScopeVariable, AstUtils.Constant(Name)); }
internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { if (_isCondition) { return TransformReadCondition(gen); } else { return (_isExclusive ? Methods.CreateExclusiveRange : Methods.CreateInclusiveRange). OpCall(gen.CurrentScopeVariable, AstFactory.Box(_begin.TransformRead(gen)), AstFactory.Box(_end.TransformRead(gen))); } }
/*!*/ internal MSA.Expression Transform(AstGenerator/*!*/ gen) { if (_value is string) { return Ast.Constant(_value, typeof(string)); } else { return Methods.ConvertSymbolToClrString.OpCall(((StringConstructor)_value).TransformRead(gen)); } }
internal override MSA.Expression/*!*/ Transform(AstGenerator/*!*/ gen) { Assert.NotNull(gen); return Ast.Dynamic( ConvertToProcAction.Instance, typeof(Proc), gen.CurrentScopeVariable, _expression.TransformRead(gen) ); }
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] = AstUtils.Empty(); return Ast.Block(result); }
internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { var result = StringConstructor.TransformConcatentation(gen, _pattern, Methods.CreateRegex, Ast.Constant(_options)); if (_isCondition) { result = Methods.MatchLastInputLine.OpCall(result, gen.CurrentScopeVariable); } return result; }
internal override MSA.Expression/*!*/ TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { if (_transformed != null) { // static lookup: return Ast.Assign(_transformed, AstUtils.Convert(rightValue, _transformed.Type)); } else { // dynamic lookup: return Methods.SetLocalVariable.OpCall(AstFactory.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name)); } }
internal override string/*!*/ GetNodeName(AstGenerator/*!*/ gen) { if (_value == null) { return "nil"; } else if (_value is bool) { return (bool)_value ? "true" : "false"; } else { return base.GetNodeName(gen); } }
internal override MSA.Expression/*!*/ TransformReadVariable(AstGenerator/*!*/ gen, bool tryRead) { if (_transformed != null) { // static lookup: return _transformed; } else { // dynamic lookup: return Methods.GetLocalVariable.OpCall(gen.CurrentScopeVariable, AstUtils.Constant(Name)); } }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { Assert.NotNull(gen); if (_maplets != null) { return(gen.MakeHashOpCall(gen.TransformMapletsToExpressions(_maplets))); } else if (_expressions != null) { return(gen.MakeHashOpCall(gen.TranformExpressions(_expressions))); } else { return(Methods.MakeHash0.OpCall(gen.CurrentScopeVariable)); } }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { MSA.Expression transformedTarget; bool hasImplicitSelf; if (_target != null) { transformedTarget = _target.TransformRead(gen); hasImplicitSelf = false; } else { transformedTarget = gen.CurrentSelfVariable; hasImplicitSelf = true; } return(TransformRead(this, gen, hasImplicitSelf, _methodName, transformedTarget, Arguments, Block, null, null)); }
private MSA.Expression /*!*/ MakeParametersInitialization(AstGenerator /*!*/ gen, AstParameters /*!*/ parameters) { var result = new AstExpressions( ParameterCount + (_parameters.Optional.Length > 0 ? 1 : 0) + (_parameters.Unsplat != 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.Block != null) { result.Add(_parameters.Block.TransformWrite(gen, GetParameterAccess(parameters, paramsArray, parameterIndex))); parameterIndex++; } if (_parameters.Unsplat != null) { // the last parameter is unsplat: result.Add(_parameters.Unsplat.TransformWrite(gen, parameters[parameters.Count - 1])); } result.Add(AstUtils.Empty()); return(Ast.Block(result)); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { if (IsAscii || gen.Encoding == BinaryEncoding.Instance) { return(Methods.CreateMutableStringB.OpCall(Ast.Constant(_value))); } else if (IsUTF8 || gen.Encoding == BinaryEncoding.UTF8) { return(Methods.CreateMutableStringU.OpCall(Ast.Constant(_value))); } else { return(Methods.CreateMutableStringE.OpCall( Ast.Constant(_value), Ast.Constant(RubyEncoding.GetCodePage(gen.Encoding)) )); } }
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 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) { Assert.NotNull(gen); if (HasExceptionHandling) { MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#block-result", typeof(object)); return(Ast.Block( TransformExceptionHandling(gen, ResultOperation.Store(resultVariable)), resultVariable )); } else { return(gen.TransformStatementsToExpression(_statements)); } }
private static List <MSA.Expression> /*!*/ ConcatLiteralsAndTransform(AstGenerator /*!*/ gen, List <Expression> /*!*/ parts, StringBuilder /*!*/ opName) { var result = new List <MSA.Expression>(); var literals = new List <string>(); int concatLength = 0; var concatEncoding = StringLiteralEncoding.Ascii; ConcatLiteralsAndTransformRecursive(gen, parts, literals, ref concatLength, ref concatEncoding, result, opName); // finish trailing literals: if (literals.Count > 0) { result.Add(Ast.Constant(Concat(literals, concatLength))); opName.Append(OpSuffix(gen, concatEncoding)); } return(result); }
internal MSA.Expression /*!*/ TransformToYield(AstGenerator /*!*/ gen, MSA.Expression /*!*/ bfcVariable, MSA.Expression /*!*/ selfExpression) { var args = (_expressions != null) ? gen.TranformExpressions(_expressions) : new AstExpressions(); if (_maplets != null) { args.Add(gen.TransformToHashConstructor(_maplets)); } return(AstFactory.YieldExpression( gen.Context, args, (_array != null) ? _array.TransformRead(gen) : null, // splatted argument null, // rhs argument bfcVariable, selfExpression )); }
// when <expr0>, *<expr1>, ..., <exprN> // generates: // <MakeTest>(<expr0>) || <MakeArrayTest>(<expr1>) || ... [ || <MakeTest>(<exprN>) ] internal static MSA.Expression /*!*/ TransformWhenCondition(AstGenerator /*!*/ gen, Expression /*!*/[] /*!*/ comparisons, MSA.Expression value) { MSA.Expression result; if (comparisons.Length > 0) { result = MakeTest(gen, comparisons[comparisons.Length - 1], value); for (int i = comparisons.Length - 2; i >= 0; i--) { result = Ast.OrElse(MakeTest(gen, comparisons[i], value), result); } } else { result = Ast.Constant(false); } return(result); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { MSA.Expression result; if (_elseStatements != null) { // ... else body end result = gen.TransformStatementsToExpression(_elseStatements); } else { // no else clause => the result of the if-expression is nil: result = AstUtils.Constant(null); } MSA.Expression value; if (_value != null) { value = gen.CurrentScope.DefineHiddenVariable("#case-compare-value", typeof(object)); } else { value = null; } for (int i = _whenClauses.Length - 1; i >= 0; i--) { // emit: else (if (condition) body else result) result = AstFactory.Condition( TransformWhenCondition(gen, _whenClauses[i].Comparisons, value), gen.TransformStatementsToExpression(_whenClauses[i].Statements), result ); } if (_value != null) { result = Ast.Block( Ast.Assign(value, Ast.Convert(_value.TransformRead(gen), typeof(object))), result ); } return(result); }
private MSA.Expression /*!*/ TransformWrite(AstGenerator /*!*/ gen, MSA.Expression /*!*/ transformedRight, bool isSimpleRhs) { var writes = new AstBlock(); MSA.Expression rightList = gen.CurrentScope.DefineHiddenVariable("#rhs", typeof(IList)); MSA.Expression result; if (isSimpleRhs) { // 1.9 returns the RHS, not an unsplatted array, if there is just a single RHS: result = gen.CurrentScope.DefineHiddenVariable("#pr", transformedRight.Type); writes.Add(Ast.Assign(result, transformedRight)); transformedRight = AstUtils.LightDynamic(ImplicitSplatAction.Make(gen.Context), typeof(IList), result); } else { result = rightList; } writes.Add(Ast.Assign(rightList, transformedRight)); for (int i = 0; i < _unsplattedValueIndex; i++) { writes.Add(_leftValues[i].TransformWrite(gen, Methods.GetArrayItem.OpCall(rightList, AstUtils.Constant(i)))); } if (HasUnsplattedValue) { MSA.Expression explicitCount = AstUtils.Constant(_leftValues.Length - 1); // remaining RHS values: MSA.Expression array = Methods.GetArrayRange.OpCall(rightList, AstUtils.Constant(_unsplattedValueIndex), explicitCount); writes.Add(_leftValues[_unsplattedValueIndex].TransformWrite(gen, array)); for (int i = _unsplattedValueIndex + 1; i < _leftValues.Length; i++) { writes.Add(_leftValues[i].TransformWrite(gen, Methods.GetTrailingArrayItem.OpCall(rightList, AstUtils.Constant(_leftValues.Length - i), explicitCount))); } } writes.Add(result); return(writes); }
/// <code> /// End-exclusive range: /// if state /// state = IsFalse({end}) /// true /// else /// state = IsTrue({begin}) /// end /// /// End-inclusive range: /// if state || IsTrue({begin}) /// state = IsFalse({end}) /// true /// else /// false /// end /// </code> internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { var begin = AstUtils.Box(_range.Begin.TransformRead(gen)); var end = AstUtils.Box(_range.End.TransformRead(gen)); // state: // false <=> null // true <=> non-null if (_range.IsExclusive) { return(Ast.Condition( Ast.ReferenceNotEqual( _stateVariable.TransformReadVariable(gen, false), AstUtils.Constant(null) ), Ast.Block( _stateVariable.TransformWriteVariable(gen, Methods.NullIfTrue.OpCall(end)), AstUtils.Constant(true) ), Ast.ReferenceNotEqual( _stateVariable.TransformWriteVariable(gen, Methods.NullIfFalse.OpCall(begin)), AstUtils.Constant(null) ) )); } else { return(Ast.Condition( Ast.OrElse( Ast.ReferenceNotEqual( _stateVariable.TransformReadVariable(gen, false), AstUtils.Constant(null) ), Methods.IsTrue.OpCall(begin) ), Ast.Block( _stateVariable.TransformWriteVariable(gen, Methods.NullIfTrue.OpCall(end)), AstUtils.Constant(true) ), AstUtils.Constant(false) )); } }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Return internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression transformedReturnValue = TransformReturnValue(gen); // eval: if (gen.CompilerOptions.IsEval) { return(gen.Return(Methods.EvalReturn.OpCall(gen.CurrentScopeVariable, AstUtils.Box(transformedReturnValue)))); } // block: if (gen.CurrentBlock != null) { return(gen.Return(Methods.BlockReturn.OpCall(gen.CurrentBlock.BfcVariable, AstUtils.Box(transformedReturnValue)))); } // method: return(gen.Return(transformedReturnValue)); }
internal virtual MSA.Expression /*!*/ MakeDefinitionExpression(AstGenerator /*!*/ gen) { MSA.Expression transformedQualifier; MSA.Expression name = QualifiedName.TransformName(gen); switch (QualifiedName.TransformQualifier(gen, out transformedQualifier)) { case StaticScopeKind.Global: return(Methods.DefineGlobalModule.OpCall(gen.CurrentScopeVariable, name)); case StaticScopeKind.EnclosingModule: return(Methods.DefineNestedModule.OpCall(gen.CurrentScopeVariable, name)); case StaticScopeKind.Explicit: return(Methods.DefineModule.OpCall(gen.CurrentScopeVariable, AstUtils.Box(transformedQualifier), name)); } throw Assert.Unreachable; }
private static char OpSuffix(AstGenerator /*!*/ gen, StringLiteralEncoding encoding) { if (encoding == StringLiteralEncoding.Ascii) { return(RubyOps.SuffixBinary); } else if (encoding == StringLiteralEncoding.UTF8 || gen.Encoding == Encoding.UTF8) { return(RubyOps.SuffixUTF8); } else if (gen.Encoding == BinaryEncoding.Instance) { return(RubyOps.SuffixBinary); } else { return(RubyOps.SuffixEncoded); } }
internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue) { MSA.Expression transformedName = TransformName(gen); MSA.Expression transformedQualifier; switch (TransformQualifier(gen, out transformedQualifier)) { case StaticScopeKind.Global: return(Methods.SetGlobalConstant.OpCall(AstUtils.Box(rightValue), gen.CurrentScopeVariable, transformedName)); case StaticScopeKind.EnclosingModule: return(Methods.SetUnqualifiedConstant.OpCall(AstUtils.Box(rightValue), gen.CurrentScopeVariable, transformedName)); case StaticScopeKind.Explicit: return(Methods.SetQualifiedConstant.OpCall(AstUtils.Box(rightValue), transformedQualifier, gen.CurrentScopeVariable, transformedName)); } throw Assert.Unreachable; }
// // Traverses expressions in "parts" and concats all contiguous literal strings. // Notes: // - Instead of usign StringBuilder we place the string values that can be concatenated so far in to "literals" list and keep track // of their total length in "concatLength" and encoding in "concatEncoding". // If we reach a non-literal expression and we have some literals ready in "literals" array we do the concat and clear the list // and "concatLength" and "concatEncoding". // - "result" list contains argument expressions to the CreateMutableString* overloads. // - "opName" contains the name of the operation. This method appends suffix based on the argument types (see RubyOps.Suffix*). // private static void ConcatLiteralsAndTransformRecursive(AstGenerator /*!*/ gen, List <Expression> /*!*/ parts, List <string> /*!*/ literals, ref int concatLength, ref StringLiteralEncoding concatEncoding, List <MSA.Expression> /*!*/ result, StringBuilder /*!*/ opName) { for (int i = 0; i < parts.Count; i++) { Expression part = parts[i]; StringLiteral literal; StringConstructor ctor; if ((literal = part as StringLiteral) != null) { literals.Add(literal.Value); concatEncoding = CombineEncoding(concatEncoding, literal); concatLength += literal.Value.Length; } else if ((ctor = part as StringConstructor) != null) { ConcatLiteralsAndTransformRecursive(gen, ctor.Parts, literals, ref concatLength, ref concatEncoding, result, opName); } else { if (literals.Count > 0) { result.Add(Ast.Constant(Concat(literals, concatLength))); opName.Append(OpSuffix(gen, concatEncoding)); concatLength = 0; concatEncoding = StringLiteralEncoding.Ascii; literals.Clear(); } result.Add( Ast.Dynamic( ConvertToSAction.Instance, typeof(MutableString), gen.CurrentScopeVariable, part.TransformRead(gen) ) ); opName.Append(RubyOps.SuffixMutable); } } }
internal override MSA.Expression /*!*/ MakeDefinitionExpression(AstGenerator /*!*/ gen) { MSA.Expression transformedQualifier; MSA.Expression name = QualifiedName.TransformName(gen); MSA.Expression transformedSuper = (_superClass != null) ? AstUtils.Box(_superClass.TransformRead(gen)) : AstUtils.Constant(null); switch (QualifiedName.TransformQualifier(gen, out transformedQualifier)) { case StaticScopeKind.Global: return(Methods.DefineGlobalClass.OpCall(gen.CurrentScopeVariable, name, transformedSuper)); case StaticScopeKind.EnclosingModule: return(Methods.DefineNestedClass.OpCall(gen.CurrentScopeVariable, name, transformedSuper)); case StaticScopeKind.Explicit: return(Methods.DefineClass.OpCall(gen.CurrentScopeVariable, transformedQualifier, name, transformedSuper)); } throw Assert.Unreachable; }
private MSA.ParameterExpression[] /*!*/ DefineParameters(AstGenerator /*!*/ gen, ScopeBuilder /*!*/ scope) { // user defined locals/args: MSA.ParameterExpression[] parameters = DefinedScope.TransformParameters(_parameters, HiddenParameterCount); scope.AddVisibleParameters(parameters, HiddenParameterCount); parameters[0] = Ast.Parameter(typeof(object), "#self"); if (_parameters.Block != null) { // map user defined proc parameter to the special param #1: parameters[1] = _parameters.Block.TransformBlockParameterDefinition(); } else { parameters[1] = Ast.Parameter(typeof(Proc), "#block"); } return(parameters); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { switch (_index) { case MatchData: return(Methods.GetCurrentMatchData.OpCall(gen.CurrentScopeVariable)); case MatchLastGroup: return(Methods.GetCurrentMatchLastGroup.OpCall(gen.CurrentScopeVariable)); case PreMatch: return(Methods.GetCurrentPreMatch.OpCall(gen.CurrentScopeVariable)); case PostMatch: return(Methods.GetCurrentPostMatch.OpCall(gen.CurrentScopeVariable)); default: return(Methods.GetCurrentMatchGroup.OpCall(gen.CurrentScopeVariable, AstUtils.Constant(_index))); } }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { switch (_kind) { case StringKind.Mutable: return(TransformConcatentation(gen, _parts, Methods.CreateMutableString, null)); case StringKind.Immutable: return(TransformConcatentation(gen, _parts, Methods.CreateSymbol, null)); case StringKind.Command: return(Ast.Dynamic(RubyCallAction.Make("`", new RubyCallSignature(1, RubyCallFlags.HasScope | RubyCallFlags.HasImplicitSelf)), typeof(object), gen.CurrentScopeVariable, gen.CurrentSelfVariable, TransformConcatentation(gen, _parts, Methods.CreateMutableString, null) )); } throw Assert.Unreachable; }
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, CallBuilder callBuilder) { if (_expressions != null) { foreach (var arg in _expressions) { callBuilder.Add(arg.TransformRead(gen)); } } if (_maplets != null) { callBuilder.Add(gen.TransformToHashConstructor(_maplets)); } if (_array != null) { callBuilder.SplattedArgument = _array.TransformRead(gen); } }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { int intBegin, intEnd; if (IsIntegerRange(out intBegin, out intEnd)) { return((_isExclusive ? Methods.CreateExclusiveIntegerRange : Methods.CreateInclusiveIntegerRange).OpCall( AstUtils.Constant(intBegin), AstUtils.Constant(intEnd) )); } else { return((_isExclusive ? Methods.CreateExclusiveRange : Methods.CreateInclusiveRange).OpCall( AstUtils.Box(_begin.TransformRead(gen)), AstUtils.Box(_end.TransformRead(gen)), gen.CurrentScopeVariable, AstUtils.Constant(new BinaryOpStorage(gen.Context)) )); } }
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)); } }
// 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 )); }
// 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 static MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen, AstExpressions /*!*/ rightValues, MSA.Expression splattedValue, bool doSplat) { Assert.NotNull(gen, rightValues); MSA.Expression result; // We need to distinguish various special cases here. // For parallel assignment specification, see "Ruby Language.docx/Runtime/Parallel Assignment". // R(0,*)? bool rightNoneSplat = rightValues.Count == 0 && splattedValue != null; // R(1,-)? bool rightOneNone = rightValues.Count == 1 && splattedValue == null; if (rightNoneSplat) { result = AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), splattedValue); if (doSplat) { result = Methods.Splat.OpCall(result); } } else if (rightOneNone && doSplat) { result = rightValues[0]; } else { result = Methods.MakeArrayOpCall(rightValues); if (splattedValue != null) { result = Methods.SplatAppend.OpCall(result, AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), splattedValue)); } } return(result); }
private MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen, int opKind) { ConstantVariable constantQualifier = _qualifier as ConstantVariable; if (constantQualifier != null) { ConstantVariable constant; List <string> names = new List <string>(); names.Add(Name); do { names.Add(constantQualifier.Name); constant = constantQualifier; constantQualifier = constantQualifier.Qualifier as ConstantVariable; } while (constantQualifier != null); if (constant.Qualifier != null) { // {expr}::A::B return(constant.MakeExpressionQualifiedRead(gen, opKind, names.ToReverseArray())); } else { // A::B return(MakeCachedRead(gen, opKind, constant.IsGlobal, true, Ast.Constant(names.ToReverseArray()))); } } else if (_qualifier != null) { // {expr}::A return(MakeExpressionQualifiedRead(gen, opKind, new[] { Name })); } else { // A // ::A return(MakeCachedRead(gen, opKind, IsGlobal, false, Ast.Constant(Name))); } }