// 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))); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { if (_value != null) { return(Ast.Block( AstUtils.IfThen( _condition.TransformReadBoolean(gen, !_negateCondition), _jumpStatement.Transform(gen) ), _value.TransformRead(gen) )); } else { MSA.Expression tmpVariable = gen.CurrentScope.DefineHiddenVariable("#tmp_cond", typeof(object)); return(Ast.Block( Ast.Assign(tmpVariable, AstUtils.Box(_condition.TransformRead(gen))), AstUtils.IfThen( (_negateCondition ? Methods.IsFalse : Methods.IsTrue).OpCall(tmpVariable), _jumpStatement.Transform(gen) ), tmpVariable )); } }
// 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.CurrentScopeVariable, AstUtils.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), AstUtils.Empty() )); } // block: if (gen.CurrentBlock != null) { return(gen.Return(Methods.BlockBreak.OpCall(gen.CurrentBlock.BfcVariable, AstUtils.Box(transformedReturnValue)))); } // primary frame: return(Methods.MethodBreak.OpCall(AstUtils.Box(transformedReturnValue))); }
private MSA.Expression /*!*/ MakeExpressionQualifiedRead(AstGenerator /*!*/ gen, int opKind, string /*!*/[] /*!*/ names) { Debug.Assert(_qualifier != null && !(_qualifier is ConstantVariable)); object siteCache; MethodInfo op; if (opKind == OpIsDefined) { siteCache = new ExpressionQualifiedIsDefinedConstantSiteCache(); op = Methods.IsDefinedExpressionQualifiedConstant; } else { siteCache = new ExpressionQualifiedConstantSiteCache(); op = Methods.GetExpressionQualifiedConstant; } var result = op.OpCall( AstUtils.Box(_qualifier.TransformRead(gen)), gen.CurrentScopeVariable, Ast.Constant(siteCache), Ast.Constant(names) ); return(opKind == OpIsDefined?Ast.TryCatch(result, Ast.Catch(typeof(Exception), AstFactory.False)) : result); }
// when [<expr>, ...] *<array> private static MSA.Expression /*!*/ MakeArrayTest(AstGenerator /*!*/ gen, MSA.Expression /*!*/ array, MSA.Expression value) { return(Methods.ExistsUnsplat.OpCall( Ast.Constant(CallSite <Func <CallSite, object, object, object> > .Create( RubyCallAction.Make(gen.Context, "===", RubyCallSignature.WithImplicitSelf(2)) )), AstUtils.LightDynamic(ConvertToArraySplatAction.Make(gen.Context), array), AstUtils.Box(value) )); }
public static MSA.Expression /*!*/ IsFalse(MSA.Expression /*!*/ expression) { if (expression.Type == typeof(bool)) { return(Ast.Not(expression)); } else { return(Methods.IsFalse.OpCall(AstUtils.Box(expression))); } }
internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue) { if (_definitionLexicalDepth >= 0) { // static lookup: return(Ast.Assign(gen.CurrentScope.GetVariableAccessor(_definitionLexicalDepth, _closureIndex), AstUtils.Box(rightValue))); } else { // dynamic lookup: return(Methods.SetLocalVariable.OpCall(AstUtils.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name))); } }
internal static MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen, MSA.Expression /*!*/ left, MSA.Expression /*!*/ right) { MSA.ParameterExpression temp; MSA.Expression result = AstUtils.CoalesceTrue( AstUtils.Box(left), AstUtils.Box(right), Methods.IsTrue, out temp ); gen.CurrentScope.AddHidden(temp); return(result); }
private static RuleGenerator /*!*/ CreateSetter(int index) { return(delegate(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { var actualArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1); if (!metaBuilder.Error) { metaBuilder.Result = Methods.RubyStruct_SetValue.OpCall( Ast.Convert(args.TargetExpression, typeof(RubyStruct)), AstUtils.Constant(index), AstUtils.Box(actualArgs[0].Expression) ); } }); }
internal static void BuildConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { const string ToS = "to_s"; if (TryImplicitConversion(metaBuilder, args)) { metaBuilder.AddTypeRestriction(args.Target.GetType(), args.TargetExpression); return; } RubyMemberInfo conversionMethod, methodMissing = null; RubyClass targetClass = args.RubyContext.GetImmediateClassOf(args.Target); using (targetClass.Context.ClassHierarchyLocker()) { metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext, new[] { ToS, Symbols.MethodMissing } ); conversionMethod = targetClass.ResolveMethodForSiteNoLock(ToS, VisibilityContext.AllVisible).Info; // find method_missing - we need to add "to_s" method to the missing methods table: if (conversionMethod == null) { methodMissing = targetClass.ResolveMethodMissingForSite(ToS, RubyMethodVisibility.None); } } // invoke target.to_s and if successful convert the result to string unless it is already: if (conversionMethod != null) { conversionMethod.BuildCall(metaBuilder, args, ToS); } else { RubyCallAction.BuildMethodMissingCall(metaBuilder, args, ToS, methodMissing, RubyMethodVisibility.None, false, true); } if (metaBuilder.Error) { return; } metaBuilder.Result = Methods.ToSDefaultConversion.OpCall( AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), AstUtils.Box(args.TargetExpression), AstUtils.Box(metaBuilder.Result) ); }
internal static MSA.Expression /*!*/ YieldExpression( RubyContext /*!*/ context, ICollection <MSA.Expression> /*!*/ arguments, MSA.Expression splattedArgument, MSA.Expression rhsArgument, MSA.Expression blockArgument, MSA.Expression /*!*/ bfcVariable, MSA.Expression /*!*/ selfArgument) { Assert.NotNull(arguments, bfcVariable, selfArgument); bool hasArgumentArray; var opMethod = Methods.Yield(arguments.Count, splattedArgument != null, rhsArgument != null, out hasArgumentArray); var args = new AstExpressions(); foreach (var arg in arguments) { args.Add(AstUtils.Box(arg)); } if (hasArgumentArray) { args = new AstExpressions { Ast.NewArrayInit(typeof(object), args) }; } if (splattedArgument != null) { args.Add(AstUtils.LightDynamic(ExplicitSplatAction.Make(context), typeof(IList), splattedArgument)); } if (rhsArgument != null) { args.Add(AstUtils.Box(rhsArgument)); } args.Add(blockArgument != null ? AstUtils.Convert(blockArgument, typeof(Proc)) : AstFactory.NullOfProc); args.Add(AstUtils.Box(selfArgument)); args.Add(bfcVariable); return(Ast.Call(opMethod, args)); }
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; }
/// <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) )); } }
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 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; }
internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { Assert.NotNull(metaBuilder, args, name); // 2 implicit args: self, block var argsBuilder = new ArgsBuilder(2, Parameters.Mandatory.Length, Parameters.LeadingMandatoryCount, Parameters.Optional.Length, Parameters.Unsplat != null); argsBuilder.SetImplicit(0, AstUtils.Box(args.TargetExpression)); argsBuilder.SetImplicit(1, args.Signature.HasBlock ? AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)) : AstFactory.NullOfProc); argsBuilder.AddCallArguments(metaBuilder, args); if (metaBuilder.Error) { return; } // box explicit arguments: var boxedArguments = argsBuilder.GetArguments(); for (int i = 2; i < boxedArguments.Length; i++) { boxedArguments[i] = AstUtils.Box(boxedArguments[i]); } var method = GetDelegate(); if (method.GetType() == ParamsArrayDelegateType) { // Func<object, Proc, object[], object> metaBuilder.Result = AstFactory.CallDelegate(method, new[] { boxedArguments[0], boxedArguments[1], Ast.NewArrayInit(typeof(object), ArrayUtils.ShiftLeft(boxedArguments, 2)) }); } else { metaBuilder.Result = AstFactory.CallDelegate(method, boxedArguments); } }
// 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 MSA.Expression UnsplatArguments(AstGenerator /*!*/ gen, int start) { // [*array] == array, [*item] = [item] if (start == _expressions.Length - 1) { return(Methods.Unsplat.OpCall(AstUtils.Box(_expressions[start].TransformRead(gen)))); } MSA.Expression array = Methods.MakeArray0.OpCall(); for (int i = start; i < _expressions.Length; i++) { if (_expressions[i] is SplattedArgument) { array = Methods.AddRange.OpCall(array, _expressions[i].TransformRead(gen)); } else { array = Methods.AddItem.OpCall(array, AstUtils.Box(_expressions[i].TransformRead(gen))); } } return(array); }
public static MSA.Expression /*!*/ Condition(MSA.Expression /*!*/ test, MSA.Expression /*!*/ ifTrue, MSA.Expression /*!*/ ifFalse) { Assert.NotNull(test, ifTrue, ifFalse); Debug.Assert(test.Type == typeof(bool)); if (ifTrue.Type != ifFalse.Type) { if (ifTrue.Type.IsAssignableFrom(ifFalse.Type)) { ifFalse = Ast.Convert(ifFalse, ifTrue.Type); } else if (ifFalse.Type.IsAssignableFrom(ifTrue.Type)) { ifTrue = Ast.Convert(ifTrue, ifFalse.Type); } else { ifTrue = AstUtils.Box(ifTrue); ifFalse = AstUtils.Box(ifFalse); } } return(Ast.Condition(test, ifTrue, ifFalse)); }
private MSA.Expression /*!*/ MakeCompareException(AstGenerator /*!*/ gen, MSA.Expression /*!*/ comparisonSiteStorage, MSA.Expression /*!*/ expression, bool isSplatted) { if (isSplatted) { return(Methods.CompareSplattedExceptions.OpCall(comparisonSiteStorage, gen.CurrentScopeVariable, expression)); } else { return(Methods.CompareException.OpCall(comparisonSiteStorage, gen.CurrentScopeVariable, AstUtils.Box(expression))); } }
private MSA.Expression /*!*/ MakeCompareException(AstGenerator /*!*/ gen, MSA.Expression /*!*/ comparisonSiteStorage, MSA.Expression /*!*/ expression) { return(Methods.CompareException.OpCall(comparisonSiteStorage, gen.CurrentScopeVariable, AstUtils.Box(expression))); }
public void AddCallArguments(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { _callArguments = args; // calculate actual argument count: _actualArgumentCount = args.SimpleArgumentCount; if (args.Signature.HasSplattedArgument) { var splattedArg = args.GetSplattedMetaArgument(); metaBuilder.AddSplattedArgumentTest((IList)splattedArg.Value, splattedArg.Expression, out _listLength, out _listVariable); _actualArgumentCount += _listLength; } if (args.Signature.HasRhsArgument) { _actualArgumentCount++; } // check: if (HasTooFewArguments) { metaBuilder.SetWrongNumberOfArgumentsError(_actualArgumentCount, _mandatoryParamCount); return; } if (HasTooManyArguments) { metaBuilder.SetWrongNumberOfArgumentsError(_actualArgumentCount, _mandatoryParamCount); return; } bool isSplatted; // leading mandatory: for (int i = 0; i < _leadingMandatoryParamCount; i++) { _arguments[LeadingMandatoryIndex + i] = GetArgument(i, out isSplatted); } // trailing mandatory: for (int i = 0; i < TrailingMandatoryCount; i++) { _arguments[TrailingMandatoryIndex + i] = GetArgument(_actualArgumentCount - TrailingMandatoryCount + i, out isSplatted); } int start = _leadingMandatoryParamCount; int end = _actualArgumentCount - TrailingMandatoryCount; // optional: for (int i = 0; i < _optionalParamCount; i++) { _arguments[OptionalParameterIndex + i] = (start < end) ? GetArgument(start++, out isSplatted) : Ast.Field(null, Fields.DefaultArgument); } // unsplat: if (_hasUnsplatParameter) { Expression array; if (args.Signature.HasSplattedArgument) { // simple: var argsToUnsplat = new List <Expression>(); while (start < end) { var arg = GetArgument(start, out isSplatted); if (isSplatted) { break; } argsToUnsplat.Add(AstUtils.Box(arg)); start++; } array = Methods.MakeArrayOpCall(argsToUnsplat); int rangeStart = start - args.SimpleArgumentCount; int rangeLength = Math.Min(end - start, _listLength - rangeStart); // splatted: if (rangeLength > 0) { array = Methods.AddSubRange.OpCall(array, _listVariable, Ast.Constant(rangeStart), Ast.Constant(rangeLength)); start += rangeLength; } // rhs: while (start < end) { array = Methods.AddItem.OpCall(array, AstUtils.Box(GetArgument(start, out isSplatted))); start++; } } else { var argsToUnsplat = new List <Expression>(end - start); while (start < end) { argsToUnsplat.Add(AstUtils.Box(GetArgument(start++, out isSplatted))); } array = Methods.MakeArrayOpCall(argsToUnsplat); } _arguments[UnsplatParameterIndex] = array; } _callArguments = null; _listVariable = null; Debug.Assert(CollectionUtils.TrueForAll(_arguments, (e) => e != null)); }
/// <summary> /// Transform as expression whose value is read as Boolean. /// </summary> internal virtual MSA.Expression /*!*/ TransformReadBoolean(AstGenerator /*!*/ gen, bool positive) { return((positive ? Methods.IsTrue : Methods.IsFalse).OpCall(AstUtils.Box(TransformRead(gen)))); }
internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue) { return(Methods.SetInstanceVariable.OpCall(gen.CurrentSelfVariable, AstUtils.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name))); }