예제 #1
0
        public static MSA.Expression /*!*/ MakeArrayOpCall(IList <MSA.Expression> /*!*/ args)
        {
            Assert.NotNull(args);

            switch (args.Count)
            {
            case 0: return(Methods.MakeArray0.OpCall());

            case 1: return(Methods.MakeArray1.OpCall(AstUtils.Box(args[0])));

            case 2: return(Methods.MakeArray2.OpCall(AstUtils.Box(args[0]), AstUtils.Box(args[1])));

            case 3: return(Methods.MakeArray3.OpCall(AstUtils.Box(args[0]), AstUtils.Box(args[1]), AstUtils.Box(args[2])));

            case 4: return(Methods.MakeArray4.OpCall(AstUtils.Box(args[0]), AstUtils.Box(args[1]), AstUtils.Box(args[2]), AstUtils.Box(args[3])));

            case 5:
                return(Methods.MakeArray5.OpCall(new AstExpressions {
                    AstUtils.Box(args[0]), AstUtils.Box(args[1]), AstUtils.Box(args[2]), AstUtils.Box(args[3]), AstUtils.Box(args[4])
                }));

            default:
                Debug.Assert(args.Count > Runtime.RubyOps.OptimizedOpCallParamCount);
                return(Methods.MakeArrayN.OpCall(AstUtils.NewArrayHelper(typeof(object), args)));
            }
        }
예제 #2
0
 internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen)
 {
     return(Methods.DefineMethod.OpCall(
                (_target != null) ? AstUtils.Box(_target.TransformRead(gen)) : AstUtils.Constant(null),
                gen.CurrentScopeVariable,
                Ast.Constant(new RubyMethodBody(this, gen.Document, gen.Encoding))
                ));
 }
 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)
                ));
 }
예제 #4
0
        internal LoopFunc CreateDelegate()
        {
            var loop          = Visit(_loop);
            var body          = new List <Expression>();
            var finallyClause = new List <Expression>();

            foreach (var variable in _loopVariables)
            {
                LocalVariable local;
                if (!_outerVariables.TryGetValue(variable.Key, out local))
                {
                    local = _closureVariables[variable.Key];
                }

                Expression elemRef = local.LoadFromArray(_frameDataVar, _frameClosureVar);

                if (local.InClosureOrBoxed)
                {
                    var box = variable.Value.BoxStorage;
                    Debug.Assert(box != null);
                    body.Add(Expression.Assign(box, elemRef));
                    AddTemp(box);
                }
                else
                {
                    // Always initialize the variable even if it is only written to.
                    // If a write-only variable is actually not assigned during execution of the loop we will still write some value back.
                    // This value must be the original value, which we assign at entry.
                    body.Add(Expression.Assign(variable.Key, AstUtils.Convert(elemRef, variable.Key.Type)));

                    if ((variable.Value.Access & ExpressionAccess.Write) != 0)
                    {
                        finallyClause.Add(Expression.Assign(elemRef, AstUtils.Box(variable.Key)));
                    }

                    AddTemp(variable.Key);
                }
            }

            if (finallyClause.Count > 0)
            {
                body.Add(Expression.TryFinally(loop, Expression.Block(finallyClause)));
            }
            else
            {
                body.Add(loop);
            }

            body.Add(Expression.Label(_returnLabel, Expression.Constant(_loopEndInstructionIndex - _loopStartInstructionIndex)));

            var lambda = Expression.Lambda <LoopFunc>(
                _temps != null ? Expression.Block(_temps, body) : Expression.Block(body),
                new[] { _frameDataVar, _frameClosureVar, _frameVar }
                );

            return(lambda.Compile());
        }
예제 #5
0
        internal override MSA.Expression TransformDefinedCondition(AstGenerator /*!*/ gen)
        {
            // MRI doesn't evaluate the arguments
            MSA.Expression result = AstUtils.LightDynamic(
                RubyCallAction.Make(gen.Context, _methodName, RubyCallSignature.IsDefined(_target == null)),
                typeof(bool),
                gen.CurrentScopeVariable,
                (_target != null) ? AstUtils.Box(_target.TransformRead(gen)) : gen.CurrentSelfVariable
                );

            return((_target != null) ? gen.TryCatchAny(result, AstFactory.False) : result);
        }
예제 #6
0
        internal static MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen, MSA.Expression /*!*/ left, MSA.Expression /*!*/ right)
        {
            MSA.ParameterExpression temp;

            MSA.Expression result = AstUtils.CoalesceFalse(
                AstUtils.Box(left),
                AstUtils.Box(right),
                Methods.IsTrue,
                out temp
                );

            gen.CurrentScope.AddHidden(temp);
            return(result);
        }
예제 #7
0
        public static RuleGenerator /*!*/ GetException()
        {
            return(new RuleGenerator((metaBuilder, args, name) => {
                Debug.Assert(args.Target is Exception);

                // 1 optional parameter (exceptionArg):
                var argsBuilder = new ArgsBuilder(0, 0, 1, false);
                argsBuilder.AddCallArguments(metaBuilder, args);

                if (!metaBuilder.Error)
                {
                    if (argsBuilder.ExplicitArgumentCount == 0)
                    {
                        metaBuilder.Result = args.TargetExpression;
                    }
                    else
                    {
                        RubyClass cls = args.RubyContext.GetClassOf(args.Target);
                        var classExpression = AstUtils.Constant(cls);
                        args.SetTarget(classExpression, cls);

                        ParameterExpression messageVariable = null;

                        // RubyOps.MarkException(new <exception-type>(GetClrMessage(<class>, #message = <message>)))
                        if (cls.BuildAllocatorCall(metaBuilder, args, () =>
                                                   Ast.Call(null, new Func <RubyClass, object, string>(GetClrMessage).Method,
                                                            classExpression,
                                                            Ast.Assign(messageVariable = metaBuilder.GetTemporary(typeof(object), "#message"), AstUtils.Box(argsBuilder[0]))
                                                            )
                                                   ))
                        {
                            // ReinitializeException(<result>, #message)
                            metaBuilder.Result = Ast.Call(null, new Func <RubyContext, Exception, object, Exception>(ReinitializeException).Method,
                                                          AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)),
                                                          metaBuilder.Result,
                                                          messageVariable ?? AstUtils.Box(argsBuilder[0])
                                                          );
                        }
                        else
                        {
                            metaBuilder.SetError(Methods.MakeAllocatorUndefinedError.OpCall(Ast.Convert(args.TargetExpression, typeof(RubyClass))));
                        }
                    }
                }
            }));
        }
예제 #8
0
        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;
        }
예제 #9
0
        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;
        }
예제 #10
0
 // return the target object on error:
 protected override void SetError(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     metaBuilder.Result = Ast.Convert(Methods.MakeArray1.OpCall(AstUtils.Box(args.TargetExpression)), typeof(IList));
 }
예제 #11
0
 // return the target object on error:
 protected override Expression /*!*/ MakeErrorExpression(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     return(Ast.Convert(Methods.MakeArray1.OpCall(AstUtils.Box(args.TargetExpression)), typeof(IList)));
 }
예제 #12
0
 // return the target object on error:
 protected override void SetError(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     metaBuilder.Result = AstUtils.Box(args.TargetExpression);
 }
예제 #13
0
 // return the target object on error:
 protected override Expression /*!*/ MakeErrorExpression(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Type /*!*/ resultType)
 {
     return(AstUtils.Box(args.TargetExpression));
 }
예제 #14
0
 protected override Expression /*!*/ MakeValidatorCall(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Expression /*!*/ result)
 {
     return(AstUtils.LightDynamic(ConvertToStrAction.Make(args.RubyContext), AstUtils.Box(result)));
 }
예제 #15
0
        protected virtual Expression /*!*/ MakeValidatorCall(CallArguments /*!*/ args, Expression /*!*/ targetClassNameConstant, Expression /*!*/ result)
        {
            var validator = ConversionResultValidator;

            return((validator != null) ? validator.OpCall(targetClassNameConstant, AstUtils.Box(result)) : result);
        }
예제 #16
0
        private MSA.Expression /*!*/ TransformWrite(AstGenerator /*!*/ gen, AstExpressions /*!*/ rightValues, MSA.Expression splattedValue)
        {
            // We need to distinguish various special cases here.
            // Each of the bool variables defined below is true iff the corresponding special form of LHS/RHS occurs.
            // These flags drive the DLR AST being produced by this method.
            // For parallel assignment specification, see "Ruby Language.docx/Runtime/Parallel Assignment".

            // L(0,-) not applicable
            Debug.Assert(!(_leftValues.Count == 0 && _unsplattedValue == null));

            // L(1,-)?
            bool leftOneNone = _leftValues.Count == 1 && _unsplattedValue == null;

            // L(0,*)?
            bool leftNoneSplat = _leftValues.Count == 0 && _unsplattedValue != null;

            // R(0,*)?
            bool rightNoneSplat = rightValues.Count == 0 && splattedValue != null;

            // R(1,-)?
            bool rightOneNone = rightValues.Count == 1 && splattedValue == null;

            // R(1,*)?
            bool rightOneSplat = rightValues.Count == 1 && splattedValue != null;

            // R(0,-) not applicable
            Debug.Assert(!(rightValues.Count == 0 && splattedValue == null));

            MSA.Expression resultExpression;

            if (leftOneNone)
            {
                // L(1,-):

                // recurse right away (X) = RHS is equivalent to X = RHS:
                CompoundLeftValue compound = _leftValues[0] as CompoundLeftValue;
                if (compound != null)
                {
                    return(compound.TransformWrite(gen, rightValues, splattedValue));
                }

                if (rightOneSplat)
                {
                    // R(1,*)
                    resultExpression = Methods.SplatPair.OpCall(
                        AstUtils.Box(rightValues[0]),
                        AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), splattedValue)
                        );
                }
                else
                {
                    // case 1: R(1,-)
                    // case 2: R(0,*)
                    // case 3: otherwise
                    resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, true /* Splat */);
                }

                return(_leftValues[0].TransformWrite(gen, resultExpression));
            }

            bool optimizeReads = true;

            if (rightOneNone && !leftNoneSplat)
            {
                // R(1,-) && !L(0,*)
                resultExpression = Methods.Unsplat.OpCall(
                    AstUtils.LightDynamic(ConvertToArraySplatAction.Make(gen.Context), rightValues[0])
                    );
                optimizeReads = false;
            }
            else
            {
                // case 1: R(0,*) = L
                // case 2: otherwise
                resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, false /* Unsplat */);
                optimizeReads    = !rightNoneSplat;
            }

            var writes = new AstBlock();

            MSA.Expression result = gen.CurrentScope.DefineHiddenVariable("#rhs", typeof(IList));
            writes.Add(Ast.Assign(result, resultExpression));

            MethodInfo itemGetter = Methods.IList_get_Item;

            for (int i = 0; i < _leftValues.Count; i++)
            {
                MSA.Expression rvalue;

                if (optimizeReads)
                {
                    if (i < rightValues.Count)
                    {
                        // unchecked get item:
                        rvalue = Ast.Call(result, itemGetter, AstUtils.Constant(i));
                    }
                    else if (splattedValue != null)
                    {
                        // checked get item:
                        rvalue = Methods.GetArrayItem.OpCall(result, AstUtils.Constant(i));
                    }
                    else
                    {
                        // missing item:
                        rvalue = AstUtils.Constant(null);
                    }
                }
                else
                {
                    rvalue = Methods.GetArrayItem.OpCall(result, AstUtils.Constant(i));
                }

                writes.Add(_leftValues[i].TransformWrite(gen, rvalue));
            }

            // unsplatting the rest of rhs values into an array:
            if (_unsplattedValue != null)
            {
                // copies the rest of resulting array to the *LHS;
                // the resulting array contains splatted *RHS - no need for additional appending:
                MSA.Expression array = Methods.GetArraySuffix.OpCall(result, AstUtils.Constant(_leftValues.Count));

                // assign the array (possibly empty) to *LHS:
                writes.Add(_unsplattedValue.TransformWrite(gen, array));
            }

            writes.Add(result);
            return(writes);
        }
예제 #17
0
 internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue)
 {
     return(Methods.SetGlobalVariable.OpCall(AstUtils.Box(rightValue), gen.CurrentScopeVariable, TransformName(gen)));
 }
예제 #18
0
        // 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));
        }
예제 #19
0
        protected override Expression VisitGoto(GotoExpression node)
        {
            BranchLabel label;

            var target = node.Target;
            var value  = Visit(node.Value);

            // TODO: Is it possible for an inner reducible node of the loop to rely on nodes produced by reducing outer reducible nodes?

            // Unknown label => must be within the loop:
            if (!_labelMapping.TryGetValue(target, out label))
            {
                return(node.Update(target, value));
            }

            // Known label within the loop:
            if (label.TargetIndex >= _loopStartInstructionIndex && label.TargetIndex < _loopEndInstructionIndex)
            {
                return(node.Update(target, value));
            }

            return(Expression.Return(_returnLabel,
                                     (value != null) ?
                                     Expression.Call(_frameVar, InterpretedFrame.GotoMethod, Expression.Constant(label.LabelIndex), AstUtils.Box(value)) :
                                     Expression.Call(_frameVar, InterpretedFrame.VoidGotoMethod, Expression.Constant(label.LabelIndex)),
                                     node.Type
                                     ));
        }
예제 #20
0
 internal override MSA.Expression /*!*/ MakeDefinitionExpression(AstGenerator /*!*/ gen)
 {
     return(Methods.DefineSingletonClass.OpCall(gen.CurrentScopeVariable, AstUtils.Box(_singleton.TransformRead(gen))));
 }