Exemple #1
0
        /// <summary>
        /// Generates CIL for an assignment expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        /// <param name="target"> The target to modify. </param>
        private void GenerateAssignment(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target)
        {
            // Load the value to assign.
            var rhs = GetOperand(1);

            // Potentially transferring a constant here.
            // Note that all of the others affect the source value in some way
            // so this is the only one which can potentially transfer a constant like this.
            object constValue = target.GetConstantValue();

            // Store the value.
            target.GenerateSet(generator, optimizationInfo, optimizationInfo.RootExpression != this, rhs.GetResultType(optimizationInfo), delegate(bool two)
            {
                // Generate the code:

                if (constValue != null)
                {
                    // Straight emit the constant value (Note that it could be a function - it handles that for us):
                    EmitHelpers.EmitValue(generator, constValue);
                }
                else
                {
                    rhs.GenerateCode(generator, optimizationInfo);
                }

                if (two)
                {
                    // Duplicate the value so it remains on the stack afterwards.
                    generator.Duplicate();
                }
            }, optimizationInfo.StrictMode);
        }
Exemple #2
0
        /// <summary>
        /// Emits the arguments set.
        /// </summary>
        private void EmitArguments(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Get the args:
            IList <Expression> arguments        = null;
            Expression         argumentsOperand = null;

            if (OperandCount > 1)
            {
                argumentsOperand = this.GetRawOperand(1);
                ListExpression argList = argumentsOperand as ListExpression;

                if (argList != null)
                {
                    // Multiple parameters were recieved.
                    arguments = argList.Items;

                    // Set the operand to null so it doesn't try to emit it as a single arg:
                    argumentsOperand = null;
                }
            }

            int  paraCount       = 0;
            int  parameterOffset = 0;
            bool staticMethod    = false;

            System.Reflection.ParameterInfo[] paraSet = null;
            IList <ArgVariable> argsSet = null;


            if (UserDefined == null)
            {
                // - Is the first arg ScriptEngine?
                // - Does it have thisObj / does it want an instance object?
                paraSet = ResolvedMethod.GetParameters();

                paraCount = paraSet.Length;

                staticMethod = ResolvedMethod.IsStatic || ResolvedMethod.IsConstructor;

                if (paraSet.Length > 0)
                {
                    if (paraSet[0].ParameterType == typeof(ScriptEngine))
                    {
                        // Emit an engine reference now:
                        EmitHelpers.LoadEngine(generator);

                        parameterOffset++;
                    }

                    if (paraSet.Length > parameterOffset && paraSet[parameterOffset].Name == "thisObj")
                    {
                        // It's acting like an instance method.
                        parameterOffset++;
                        staticMethod = false;
                    }
                }

                if (!staticMethod)
                {
                    // Generate the 'this' ref:
                    var baseExpression = ((MemberAccessExpression)this.Target).Base;
                    baseExpression.GenerateCode(generator, optimizationInfo);
                }
            }
            else
            {
                // These are always static.
                paraCount = UserDefined.Arguments.Count;

                argsSet = UserDefined.Arguments;

                // Skip 'this' - it's emitted separately:
                parameterOffset = 1;
            }

            // Next, we're matching params starting from parameterOffset with the args,
            // type casting if needed.
            for (int i = parameterOffset; i < paraCount; i++)
            {
                Expression expression   = null;
                object     defaultValue = null;
                Type       paramType    = null;

                if (paraSet == null)
                {
                    // Get the type:
                    paramType = argsSet[i].Type;
                }
                else
                {
                    // Get the parameter info:
                    var param = paraSet[i];

                    // Get the parameters type:
                    paramType = param.ParameterType;

                    // Get the default value:
                    defaultValue = param.RawDefaultValue;

                    // Is it a params array?
                    if (Attribute.IsDefined(param, typeof(ParamArrayAttribute)))
                    {
                        // It's always an array - get the element type:
                        paramType = paramType.GetElementType();

                        // For each of the remaining args..
                        int offset = i - parameterOffset;

                        int argCount = 0;

                        if (arguments != null)
                        {
                            // Get the full count:
                            argCount = arguments.Count;
                        }
                        else if (argumentsOperand != null)
                        {
                            // Just one arg and it's still hanging around.
                            argCount = offset + 1;
                        }

                        // Define an array:
                        generator.LoadInt32(argCount);
                        generator.NewArray(paramType);

                        for (int a = offset; a < argCount; a++)
                        {
                            if (arguments != null)
                            {
                                // One of many args:
                                expression = arguments[a];
                            }
                            else
                            {
                                // Just one arg:
                                expression = argumentsOperand;
                            }

                            generator.Duplicate();
                            generator.LoadInt32(a - offset);
                            expression.GenerateCode(generator, optimizationInfo);
                            Type res = expression.GetResultType(optimizationInfo);

                            EmitConversion.Convert(generator, res, paramType);
                            generator.StoreArrayElement(paramType);
                        }

                        // All done - can't be anymore.
                        break;
                    }
                }

                if (arguments != null && (i - parameterOffset) <= arguments.Count)
                {
                    // Get one of many args:
                    expression = arguments[i - parameterOffset];
                }
                else if (argumentsOperand != null)
                {
                    // Just the one argument.
                    expression = argumentsOperand;

                    // By setting it to null after, it can't get emitted again
                    // (in the event that this method actually accepts >1 args)
                    argumentsOperand = null;
                }

                if (expression == null)
                {
                    // Emit whatever the default is for the parameters type:
                    if (defaultValue != null)
                    {
                        // Emit the default value:
                        EmitHelpers.EmitValue(generator, defaultValue);
                    }
                    else if (paramType.IsValueType)
                    {
                        // E.g. an integer 0
                        EmitHelpers.EmitValue(generator, Activator.CreateInstance(paramType));
                    }
                    else
                    {
                        // Just a null (a real one):
                        generator.LoadNull();
                    }
                }
                else if (expression is TemplateLiteralExpression)
                {
                    // Tagged template literal.
                    TemplateLiteralExpression templateLiteral = (TemplateLiteralExpression)expression;
                    GenerateTemplateArgumentsArray(generator, optimizationInfo, templateLiteral);
                    return;
                }
                else
                {
                    // Output the arg:
                    expression.GenerateCode(generator, optimizationInfo);

                    // Convert:
                    EmitConversion.Convert(generator, expression.GetResultType(optimizationInfo), paramType);
                }
            }
        }
        /// <summary>
        /// Generates CIL for the logical operators.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        private void GenerateLogical(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // If either evaluates statically to 0 then we also know the correct return type.
            object leftEval = Left.Evaluate();

            if (leftEval != null)
            {
                // RHS only.

                bool leftTrue = TypeConverter.ToBoolean(leftEval);

                // a && b
                // If a is false, don't do anything with b.
                // If a is true, emit b.
                // a || b
                // If a is false, emit b. If it's true, emit a.

                if (OperatorType == OperatorType.LogicalAnd && !leftTrue)
                {
                    // Don't evaluate the RHS. Just emit a 'false' if one is needed.
                    if (optimizationInfo.RootExpression != this)
                    {
                        // Emit the false:
                        generator.LoadBoolean(false);
                    }
                }
                else if (OperatorType == OperatorType.LogicalOr && leftTrue)
                {
                    // Emit the left object only.
                    if (optimizationInfo.RootExpression != this)
                    {
                        // Load it:
                        EmitHelpers.EmitValue(generator, leftEval);
                    }
                }
                else if (optimizationInfo.RootExpression == this)
                {
                    // Emitting b (no return type required).

                    // Right will be the root instead.
                    optimizationInfo.RootExpression = Right;
                    Right.GenerateCode(generator, optimizationInfo);
                    optimizationInfo.RootExpression = this;
                }
                else
                {
                    // Emitting b (return type required).

                    // Output required.
                    Right.GenerateCode(generator, optimizationInfo);
                }

                return;
            }

            // Evaluate B, just in case we're doing RHS only:
            object rightEval = Right.Evaluate();

            // Get the statically-determined types of the left and right operands.
            Type leftType  = this.Left.GetResultType(optimizationInfo);
            Type rightType = rightEval == null?this.Right.GetResultType(optimizationInfo) : rightEval.GetType();

            // Load the left-hand side operand.
            this.Left.GenerateCode(generator, optimizationInfo);

            // Make sure the output type is consistant.
            if (leftType != rightType)
            {
                if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true)
                {
                    EmitConversion.ToNumber(generator, leftType);
                    leftType = typeof(double);
                }
                else
                {
                    EmitConversion.ToAny(generator, leftType);
                    leftType = typeof(object);
                }
            }

            // If this is an OR, we might be using the value currently on the stack if it's true.
            // So, duplicate:
            if (OperatorType == OperatorType.LogicalOr && optimizationInfo.RootExpression != this)
            {
                generator.Duplicate();
            }

            // Convert to a boolean:
            EmitConversion.ToBool(generator, leftType);

            // If this is an AND, we might be using the value currently on the stack if it's false.
            // So, duplicate:
            if (OperatorType == OperatorType.LogicalAnd && optimizationInfo.RootExpression != this)
            {
                generator.Duplicate();
            }

            // Stack contains:
            // OR: "left, (bool)left"
            // AND: "(bool)left, (bool)left"

            var endOfIf = generator.CreateLabel();

            if (this.OperatorType == OperatorType.LogicalAnd)
            {
                generator.BranchIfFalse(endOfIf);
            }
            else
            {
                generator.BranchIfTrue(endOfIf);
            }

            if (optimizationInfo.RootExpression == this)
            {
                // Right hand side will now be the root (output is not in use).
                optimizationInfo.RootExpression = Right;

                Right.GenerateCode(generator, optimizationInfo);

                // Restore:
                optimizationInfo.RootExpression = this;
            }
            else
            {
                // Stack contains "left" which we don't need if we fall through here. Pop it off:
                generator.Pop();

                // Output is in use.
                Right.GenerateCode(generator, optimizationInfo);

                // Make sure the output type is consistant.
                if (leftType != rightType)
                {
                    if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true)
                    {
                        EmitConversion.ToNumber(generator, rightType);
                    }
                    else
                    {
                        EmitConversion.ToAny(generator, rightType);
                    }
                }
            }

            // Define the label used above.
            generator.DefineLabelPosition(endOfIf);
        }
        /// <summary>
        /// Generates CIL for the expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Literals cannot have side-effects so if a return value is not expected then generate
            // nothing.
            if (optimizationInfo.RootExpression == this)
            {
                return;
            }

            if (this.Value is int)
            {
                generator.LoadInt32((int)this.Value);
            }
            else if (this.Value is double)
            {
                generator.LoadDouble((double)this.Value);
            }
            else if (this.Value is string)
            {
                generator.LoadString((string)this.Value);
            }
            else if (this.Value is bool)
            {
                generator.LoadBoolean((bool)this.Value);
            }
            else if (this.Value is RegularExpressionLiteral)
            {
                // RegExp
                var sharedRegExpVariable = optimizationInfo.GetRegExpVariable(generator, (RegularExpressionLiteral)this.Value);
                var label1 = generator.CreateLabel();
                var label2 = generator.CreateLabel();

                // if (sharedRegExp == null) {
                generator.LoadVariable(sharedRegExpVariable);
                generator.LoadNull();
                generator.BranchIfNotEqual(label1);

                // sharedRegExp = Global.RegExp.OnConstruct(source, flags)
                EmitHelpers.LoadPrototypes(generator);
                generator.LoadField(ReflectionHelpers.PrototypeLookup_RegExp);
                generator.LoadString(((RegularExpressionLiteral)this.Value).Pattern);
                generator.LoadString(((RegularExpressionLiteral)this.Value).Flags);
                generator.Call(ReflectionHelpers.RegExp_Construct);
                generator.Duplicate();
                generator.StoreVariable(sharedRegExpVariable);

                // } else {
                generator.Branch(label2);
                generator.DefineLabelPosition(label1);

                // Global.RegExp.OnConstruct(sharedRegExp, flags)
                EmitHelpers.LoadPrototypes(generator);
                generator.LoadField(ReflectionHelpers.PrototypeLookup_RegExp);
                generator.LoadVariable(sharedRegExpVariable);
                generator.LoadNull();
                generator.Call(ReflectionHelpers.RegExp_Construct);

                // }
                generator.DefineLabelPosition(label2);
            }
            else if (this.Value == Null.Value)
            {
                // Null.
                EmitHelpers.EmitNull(generator);
            }
            else if (this.Value == Undefined.Value)
            {
                // Undefined.
                EmitHelpers.EmitUndefined(generator);
            }
            else if (this.Value is List <Expression> )
            {
                // Construct an array literal.
                var arrayLiteral = (List <Expression>) this.Value;

                // Operands for ArrayConstructor.New() are: an ArrayConstructor instance (ArrayConstructor), an array (object[])
                // ArrayConstructor
                EmitHelpers.LoadEngine(generator);

                // object[]
                generator.LoadInt32(arrayLiteral.Count);
                generator.NewArray(typeof(object));

                for (int i = 0; i < arrayLiteral.Count; i++)
                {
                    // Operands for StoreArrayElement() are: an array (object[]), index (int), value (object).
                    // Array
                    generator.Duplicate();

                    // Index
                    generator.LoadInt32(i);

                    // Value
                    var elementExpression = arrayLiteral[i];
                    if (elementExpression == null)
                    {
                        generator.LoadNull();
                    }
                    else
                    {
                        elementExpression.GenerateCode(generator, optimizationInfo);
                        EmitConversion.ToAny(generator, elementExpression.GetResultType(optimizationInfo));
                    }

                    // Store the element value.
                    generator.StoreArrayElement(typeof(object));
                }

                // ArrayConstructor.New(object[])
                generator.Call(ReflectionHelpers.Array_New);
            }
            else if (this.Value is List <KeyValuePair <Expression, Expression> > )
            {
                // This is an object literal.
                var properties = (List <KeyValuePair <Expression, Expression> >) this.Value;

                // We'll generate a prototype and a custom object type for it:
                Library.Prototype proto = CreatedPrototype;

                // Create a new object.
                generator.NewObject(proto.TypeConstructor);

                foreach (var keyValuePair in properties)
                {
                    string     propertyName  = keyValuePair.Key.ToString();
                    Expression propertyValue = keyValuePair.Value;

                    // Duplicate the object ref:
                    generator.Duplicate();

                    // Add a new property to the object.

                    Type valueType = propertyValue.GetResultType(optimizationInfo);

                    // Get the property:
                    Library.PropertyVariable pv = proto.GetProperty(propertyName);

                    // Set it:
                    pv.Set(generator, optimizationInfo, false, valueType, delegate(bool two){
                        if (pv.IsConstant)
                        {
                            // Emit the constant:
                            EmitHelpers.EmitValue(generator, pv.ConstantValue);
                        }
                        else
                        {
                            // Write the value to set now:
                            propertyValue.GenerateCode(generator, optimizationInfo);
                        }

                        // Note: This one always ignores 'two'
                    });
                }
            }
            else
            {
                throw new NotImplementedException("Unknown literal type.");
            }
        }