/// <summary>
        /// Generates CIL for the typeof 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>
        private void GenerateTypeof(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            if (this.Operand is NameExpression)
            {
                // Unresolvable references must return "undefined" rather than throw an error.
                ((NameExpression)this.Operand).GenerateGet(generator, optimizationInfo, false);
            }
            else
            {
                // Emit code for resolving the value of the operand.
                this.Operand.GenerateCode(generator, optimizationInfo);
            }

            if (optimizationInfo.RootExpression == this)
            {
                // Pop it and quit.
                generator.Pop();
                return;
            }

            // Convert to System.Object.
            EmitConversion.ToAny(generator, this.Operand.GetResultType(optimizationInfo));

            // Call TypeUtilities.TypeOf(operand).
            generator.Call(ReflectionHelpers.TypeUtilities_TypeOf);
        }
Beispiel #2
0
        /// <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)
        {
            // Setup the method info.
            // this.context.SetupMethod(optimizationInfo);

            // Add the generated method to the nested function list.
            if (optimizationInfo.NestedFunctions == null)
            {
                optimizationInfo.NestedFunctions = new List <FunctionMethodGenerator>();
            }
            optimizationInfo.NestedFunctions.Add(context);

            // Add all the nested methods to the parent list.
            // Note: it's used to compute which variables are being hoisted.
            if (this.context.Dependencies != null)
            {
                foreach (var nestedFunctionExpression in this.context.Dependencies)
                {
                    optimizationInfo.NestedFunctions.Add(nestedFunctionExpression);
                }
            }

            if (HoistValues != null)
            {
                // Script engine:
                EmitHelpers.LoadEngine(generator);

                // Method ID:
                generator.LoadInt64(context.MethodID);

                generator.LoadInt32(HoistValues.Count);

                // Hoist vars array:
                generator.NewArray(typeof(object));

                // Load each one:
                for (int i = 0; i < HoistValues.Count; i++)
                {
                    generator.Duplicate();
                    generator.LoadInt32(i);

                    // Load the variable value:
                    Type type = HoistValues[i].Get(generator);

                    // Box if necessary:
                    EmitConversion.ToAny(generator, type);

                    generator.StoreArrayElement(typeof(object));
                }

                generator.NewObject(ReflectionHelpers.HoistFunctionReference_Constructor);
            }
            else
            {
                // body
                generator.LoadInt64(context.MethodID);
                generator.Call(ReflectionHelpers.MethodLookup_Load);
            }
        }
 /// <summary>
 /// Generates CIL for the statement.
 /// </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)
 {
     // Emit code to throw the given value.
     EmitHelpers.LoadEngine(generator);
     this.Value.GenerateCode(generator, optimizationInfo);
     EmitConversion.ToAny(generator, this.Value.GetResultType(optimizationInfo));
     generator.LoadInt32(1);
     generator.LoadStringOrNull(optimizationInfo.Source.Path);
     generator.LoadStringOrNull(optimizationInfo.FunctionName);
     generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Object);
     generator.Throw();
 }
Beispiel #4
0
        /// <summary>
        /// Generates an array containing the argument values for a tagged template literal.
        /// </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="templateLiteral"> The template literal expression containing the parameter
        /// values. </param>
        internal void GenerateTemplateArgumentsArray(ILGenerator generator, OptimizationInfo optimizationInfo, TemplateLiteralExpression templateLiteral)
        {
                        #warning change this.

            // Generate an array containing the value of each argument.
            generator.LoadInt32(templateLiteral.Values.Count + 1);
            generator.NewArray(typeof(object));

            // Load the first parameter.
            generator.Duplicate();
            generator.LoadInt32(0);

            // The first parameter to the tag function is an array of strings.
            var stringsExpression = new List <Expression>(templateLiteral.Strings.Count);
            foreach (var templateString in templateLiteral.Strings)
            {
                stringsExpression.Add(new LiteralExpression(templateString));
            }
            new LiteralExpression(stringsExpression).GenerateCode(generator, optimizationInfo);
            generator.Duplicate();

            // Now we need the name of the property.
            generator.LoadString("raw");

            // Now generate an array of raw strings.
            var rawStringsExpression = new List <Expression>(templateLiteral.RawStrings.Count);
            foreach (var rawString in templateLiteral.RawStrings)
            {
                rawStringsExpression.Add(new LiteralExpression(rawString));
            }
            new LiteralExpression(rawStringsExpression).GenerateCode(generator, optimizationInfo);

            // Freeze array by calling ObjectInstance Freeze(ObjectInstance).
            // generator.CallStatic(ReflectionHelpers.ObjectConstructor_Freeze);

            // Now store the raw strings as a property of the base strings array.
            // generator.LoadBoolean(optimizationInfo.StrictMode);
            // generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Object);

            // Store in the array.
            generator.StoreArrayElement(typeof(object));

            // Values are passed as subsequent parameters.
            for (int i = 0; i < templateLiteral.Values.Count; i++)
            {
                generator.Duplicate();
                generator.LoadInt32(i + 1);
                templateLiteral.Values[i].GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, templateLiteral.Values[i].GetResultType(optimizationInfo));
                generator.StoreArrayElement(typeof(object));
            }
        }
Beispiel #5
0
        /// <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)
        {
            // Note: we use GetRawOperand() so that grouping operators are not ignored.
            var operand = this.GetRawOperand(0);

            // There is only one operand, and it can be either a reference or a function call.
            // We need to split the operand into a function and some arguments.
            // If the operand is a reference, it is equivalent to a function call with no arguments.

            // Get as a call expr:
            FunctionCallExpression function = operand as FunctionCallExpression;

            System.Reflection.MethodBase resolvedMethod = null;

            if (function != null)
            {
                // Did it resolve?
                resolvedMethod = function.ResolvedMethod;
            }

            if (resolvedMethod != null)
            {
                // Awesome, we can pre-emit the construct call!

                // Set is constructor (immediately cleared by CallExpr's GenerateCode method):
                optimizationInfo.IsConstructCall = true;

                // Emit an ordinary call:
                function.GenerateCode(generator, optimizationInfo);
                return;
            }

                        #warning incorrect.
            // Emit the function instance first.
            function.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, function.GetResultType(optimizationInfo));
        }
Beispiel #6
0
        /// <summary>
        /// Generates CIL for the statement.
        /// </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)
        {
            // Get the previous root - we'll be changing it:
            Expression prevRoot = optimizationInfo.RootExpression;

            List <string> labels = optimizationInfo.Labels;

            optimizationInfo.Labels = null;

            // Construct a loop expression.
            // var enumerator = TypeUtilities.EnumeratePropertyNames(rhs).GetEnumerator();
            // while (true) {
            //   continue-target:
            //   if (enumerator.MoveNext() == false)
            //	 goto break-target;
            //   lhs = enumerator.Current;
            //
            //   <body statements>
            // }
            // break-target:

            // Call IEnumerable<string> EnumeratePropertyNames(ScriptEngine engine, object obj)
            // optimizationInfo.MarkSequencePoint(generator, this.TargetObjectSourceSpan);
            EmitHelpers.LoadEngine(generator);
            this.TargetObject.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.TargetObject.GetResultType(optimizationInfo));
            generator.Call(ReflectionHelpers.TypeUtilities_EnumeratePropertyNames);

            // Store the enumerator in a temporary variable.
            var enumerator = generator.CreateTemporaryVariable(typeof(IEnumerator <string>));

            generator.StoreVariable(enumerator);

            var breakTarget    = generator.CreateLabel();
            var continueTarget = generator.DefineLabelPosition();

            // Emit debugging information.
            // if (optimizationInfo.DebugDocument != null)
            //  generator.MarkSequencePoint(optimizationInfo.DebugDocument, this.VariableSourceSpan);

            //   if (enumerator.MoveNext() == false)
            //	 goto break-target;
            generator.LoadVariable(enumerator);
            generator.Call(ReflectionHelpers.IEnumerator_MoveNext);
            generator.BranchIfFalse(breakTarget);

            // lhs = enumerator.Current;
            this.Variable.GenerateSet(generator, optimizationInfo, false, typeof(string), delegate(bool two){
                generator.LoadVariable(enumerator);
                generator.Call(ReflectionHelpers.IEnumerator_Current);

                if (two)
                {
                    generator.Duplicate();
                }
            }, false);



            // Emit the body statement(s).
            optimizationInfo.PushBreakOrContinueInfo(labels, breakTarget, continueTarget, false);

            // Mark the body as root:
            Body.SetRoot(optimizationInfo);

            Body.GenerateCode(generator, optimizationInfo);
            optimizationInfo.PopBreakOrContinueInfo();

            generator.Branch(continueTarget);
            generator.DefineLabelPosition(breakTarget);

            // Restore root:
            optimizationInfo.RootExpression = prevRoot;
        }
        /// <summary>
        /// Generates IL for the script.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        protected override void GenerateCode(ArgVariable[] arguments, ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Method signature: object FunctionDelegate(object thisObj, object[] arguments)

            // Transfer the function name into the scope.
            if (!string.IsNullOrEmpty(Name) &&
                IncludeNameInScope &&
                !HasArgument(Name) &&
                optimizationInfo.MethodOptimizationHints.HasVariable(Name))
            {
                var functionName = new NameExpression(InitialScope, Name);

                functionName.ApplyType(optimizationInfo, typeof(object));

                functionName.GenerateSet(generator, optimizationInfo, false, typeof(object), delegate(bool two)
                {
                    generator.LoadInt64(MethodID);
                    generator.Call(ReflectionHelpers.MethodLookup_Load);

                    if (two)
                    {
                        // Duplicate it:
                        generator.Duplicate();
                    }
                }, false);
            }

            // Transfer the arguments object into the scope.
            if (MethodOptimizationHints.HasArguments && !HasArgument("arguments"))
            {
                var argsSet = new NameExpression(this.InitialScope, "arguments");

                argsSet.ApplyType(optimizationInfo, typeof(object));

                argsSet.GenerateSet(generator, optimizationInfo, false, typeof(object), delegate(bool two)
                {
                    // argumentValues

                    // Build an object[] from the arg values.

                    // Define an array:
                    int argCount = (arguments == null)?0 : arguments.Length;

                    generator.LoadInt32(argCount);
                    generator.NewArray(typeof(object));

                    for (int a = 0; a < argCount; a++)
                    {
                        // One of many args:
                        ArgVariable currentArg = arguments[a];

                        generator.Duplicate();
                        generator.LoadInt32(a);
                        currentArg.Get(generator);
                        EmitConversion.ToAny(generator, currentArg.Type);
                        generator.StoreArrayElement(typeof(object));
                    }


                    generator.NewObject(ReflectionHelpers.Arguments_Constructor);

                    if (two)
                    {
                        generator.Duplicate();
                    }
                }, false);
            }

            // Temp cache return var/target:
            var retVar  = optimizationInfo.ReturnVariable;
            var retTarg = optimizationInfo.ReturnTarget;

            optimizationInfo.ReturnVariable = null;
            optimizationInfo.ReturnTarget   = null;

            // Initialize any declarations.
            (this.InitialScope as DeclarativeScope).GenerateDeclarations(generator, optimizationInfo);

            // Generate code for the body of the function.
            this.AbstractSyntaxTree.GenerateCode(generator, optimizationInfo);

            // Define the return target - this is where the return statement jumps to.
            // ReturnTarget can be null if there were no return statements.
            if (optimizationInfo.ReturnTarget != null)
            {
                generator.DefineLabelPosition(optimizationInfo.ReturnTarget);
            }

            // Load the return value.  If the variable is null, there were no return statements.
            if (optimizationInfo.ReturnVariable != null)
            {
                // Return the value stored in the variable.  Will be null if execution hits the end
                // of the function without encountering any return statements.
                generator.LoadVariable(optimizationInfo.ReturnVariable);
            }

            // Restore:
            optimizationInfo.ReturnVariable = retVar;
            optimizationInfo.ReturnTarget   = retTarg;
        }
        /// <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);
        }
Beispiel #9
0
        /// <summary>
        /// Pushes the value of the reference onto the stack.
        /// </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="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if
        /// the name is unresolvable; <c>false</c> to output <c>null</c> instead. </param>
        public void GenerateGet(ILGenerator generator, OptimizationInfo optimizationInfo, bool throwIfUnresolvable)
        {
            if (ResolvedProperty == null)
            {
                // Dynamic access.

                // optimizationInfo.TypeError("Attempted to get a property dynamically. Currently unsupported.");

                // Load the left-hand side:
                var lhs = this.GetOperand(0);

                // -- Begin args for Prototype.GetPropertyValue --

                // Script engine (engine):
                EmitHelpers.LoadEngine(generator);

                // Emit LHS to the stack (thisObj):
                lhs.GenerateCode(generator, optimizationInfo);

                // What type have we now got on the stack? Expected to be just 'object'.
                Type lhsType = lhs.GetResultType(optimizationInfo);

                // Ensure it's boxed (still thisObj):
                EmitConversion.ToAny(generator, lhsType);

                // Load the property name and convert to a string (property).
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToString(generator, rhs.GetResultType(optimizationInfo));

                // Get the value:
                generator.Call(ReflectionHelpers.Object_GetPropertyValue);

                // Either it's now on the stack, or we threw a null ref.
            }
            else if (isArrayIndex)
            {
                // Array indexer
                // -------------
                // xxx = object[index]

                // Load the left-hand side
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);

                // Load the right-hand side and convert to [theTypeHere] (typically int32).
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);

                // Convert the index:
                EmitConversion.Convert(generator, rhs.GetResultType(optimizationInfo), ResolvedProperty.FirstIndexType);

                // Emit a get for the indexer:
                ResolvedProperty.Get(generator);
            }
            else
            {
                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);

                if (ResolvedProperty != null)
                {
                    if (ResolvedProperty.HasEngine)
                    {
                        // Emit the engine ref:
                        EmitHelpers.LoadEngine(generator);
                    }

                    if (ResolvedProperty.HasAccessor)
                    {
                        // Emit the 'this' obj:
                        lhs.GenerateCode(generator, optimizationInfo);
                    }

                    // Emit a get:
                    ResolvedProperty.Get(generator);
                }
            }
        }
        /// <summary>
        /// Generates CIL for the addition operation.
        /// </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 GenerateAdd(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Get the statically-determined types of the left and right operands.
            Type leftType  = this.Left.GetResultType(optimizationInfo);
            Type rightType = this.Right.GetResultType(optimizationInfo);

            // The add operator adds two strings together if at least one of the operands
            // is a string, otherwise it adds two numbers.
            if (PrimitiveTypeUtilities.IsString(leftType) || PrimitiveTypeUtilities.IsString(rightType))
            {
                // If at least one of the operands is a string, then the add operator concatenates.

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

                // Convert the operand to a concatenated string.
                EmitConversion.ToPrimitive(generator, leftType, PrimitiveTypeHint.None);
                EmitConversion.ToConcatenatedString(generator, leftType);

                // Load the right-hand side onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                if (rightType == typeof(string))
                {
                    // Concatenate the two strings.
                    generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_String);
                }
                else if (rightType == typeof(ConcatenatedString))
                {
                    // Concatenate the two strings.
                    generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_ConcatenatedString);
                }
                else
                {
                    // Convert the operand to an object.
                    EmitConversion.ToPrimitive(generator, rightType, PrimitiveTypeHint.None);
                    EmitConversion.ToAny(generator, rightType);

                    // Concatenate the two strings.
                    generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_Object);
                }
            }
            else if (leftType != typeof(object) && leftType != typeof(Library.ObjectInstance) &&
                     rightType != typeof(object) && rightType != typeof(Library.ObjectInstance))
            {
                // Neither of the operands are strings.

                // If the two types are numeric integers, retain the one with the most accuracy.
                Type numeric = TypeConverter.MostAccurateInteger(leftType, rightType);

                if (numeric == null)
                {
                    // Load the left hand side onto the stack.
                    this.Left.GenerateCode(generator, optimizationInfo);

                    // Convert the operand to a number.
                    EmitConversion.ToNumber(generator, leftType);

                    // Load the right hand side onto the stack.
                    this.Right.GenerateCode(generator, optimizationInfo);

                    // Convert the operand to a number.
                    EmitConversion.ToNumber(generator, rightType);

                    // Add the two numbers.
                    generator.Add();
                }
                else
                {
                    // Use them both converted to 'numeric'

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

                    // Convert the operand to a number.
                    EmitConversion.ToNumber(generator, leftType, numeric);

                    // Load the right hand side onto the stack.
                    this.Right.GenerateCode(generator, optimizationInfo);

                    // Convert the operand to a number.
                    EmitConversion.ToNumber(generator, rightType, numeric);

                    // Add the two numbers.
                    generator.Add();
                }
            }
            else
            {
                // It is unknown whether the operands are strings.

                // Load the left hand side onto the stack.
                this.Left.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, leftType);

                // Load the right hand side onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, rightType);

                // Add the two objects.
                generator.Call(ReflectionHelpers.TypeUtilities_Add);
            }
        }
        /// <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)
        {
            // If a return value is not expected, generate only the side-effects.

            /*if (optimizationInfo.SuppressReturnValue == true)
             * {
             *      this.GenerateSideEffects(generator, optimizationInfo);
             *      return;
             * }*/

            // Special case the addition operator.
            if (this.OperatorType == OperatorType.Add)
            {
                GenerateAdd(generator, optimizationInfo);
                return;
            }

            // Special case the instanceof operator.
            if (this.OperatorType == OperatorType.InstanceOf)
            {
                GenerateInstanceOf(generator, optimizationInfo);
                return;
            }

            // Special case the in operator.
            if (this.OperatorType == OperatorType.In)
            {
                GenerateIn(generator, optimizationInfo);
                return;
            }

            // Special case the relational operators.
            if (this.OperatorType == OperatorType.LessThan ||
                this.OperatorType == OperatorType.LessThanOrEqual ||
                this.OperatorType == OperatorType.GreaterThan ||
                this.OperatorType == OperatorType.GreaterThanOrEqual)
            {
                GenerateRelational(generator, optimizationInfo);
                return;
            }

            // Special case the logical operators.
            if (this.OperatorType == OperatorType.LogicalAnd ||
                this.OperatorType == OperatorType.LogicalOr)
            {
                GenerateLogical(generator, optimizationInfo);
                return;
            }

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

            // Convert the left argument.
            switch (this.OperatorType)
            {
            // Arithmetic operations.
            case OperatorType.Subtract:
            case OperatorType.Multiply:
            case OperatorType.Divide:
            case OperatorType.Modulo:
                EmitConversion.ToNumber(generator, this.Left.GetResultType(optimizationInfo));
                break;

            // Bitwise operations.
            case OperatorType.BitwiseAnd:
            case OperatorType.BitwiseOr:
            case OperatorType.BitwiseXor:
            case OperatorType.LeftShift:
            case OperatorType.SignedRightShift:
            case OperatorType.UnsignedRightShift:
                EmitConversion.ToInt32(generator, this.Left.GetResultType(optimizationInfo));
                break;

            // Equality operations.
            case OperatorType.Equal:
            case OperatorType.StrictlyEqual:
            case OperatorType.NotEqual:
            case OperatorType.StrictlyNotEqual:
                EmitConversion.ToAny(generator, this.Left.GetResultType(optimizationInfo));
                break;
            }

            // Load the right hand side onto the stack.
            this.Right.GenerateCode(generator, optimizationInfo);

            // If the return isn't in use, pop them both:
            if (optimizationInfo.RootExpression == this)
            {
                generator.Pop();
                generator.Pop();
                return;
            }

            // Convert the right argument.
            switch (this.OperatorType)
            {
            // Arithmetic operations.
            case OperatorType.Subtract:
            case OperatorType.Multiply:
            case OperatorType.Divide:
            case OperatorType.Modulo:
                EmitConversion.ToNumber(generator, this.Right.GetResultType(optimizationInfo));
                break;

            // Bitwise operations.
            case OperatorType.BitwiseAnd:
            case OperatorType.BitwiseOr:
            case OperatorType.BitwiseXor:
                EmitConversion.ToInt32(generator, this.Right.GetResultType(optimizationInfo));
                break;

            case OperatorType.LeftShift:
            case OperatorType.SignedRightShift:
            case OperatorType.UnsignedRightShift:
                EmitConversion.ToUInt32(generator, this.Right.GetResultType(optimizationInfo));
                generator.LoadInt32(0x1F);
                generator.BitwiseAnd();
                break;

            // Equality operations.
            case OperatorType.Equal:
            case OperatorType.StrictlyEqual:
            case OperatorType.NotEqual:
            case OperatorType.StrictlyNotEqual:
                EmitConversion.ToAny(generator, this.Right.GetResultType(optimizationInfo));
                break;
            }

            // Apply the operator.
            switch (this.OperatorType)
            {
            // Arithmetic operations.
            case OperatorType.Subtract:
                generator.Subtract();
                break;

            case OperatorType.Multiply:
                generator.Multiply();
                break;

            case OperatorType.Divide:
                generator.Divide();
                break;

            case OperatorType.Modulo:
                generator.Remainder();
                break;

            // Bitwise operations.
            case OperatorType.BitwiseAnd:
                generator.BitwiseAnd();
                break;

            case OperatorType.BitwiseOr:
                generator.BitwiseOr();
                break;

            case OperatorType.BitwiseXor:
                generator.BitwiseXor();
                break;

            // Shift operations.
            case OperatorType.LeftShift:
                generator.ShiftLeft();
                break;

            case OperatorType.SignedRightShift:
                generator.ShiftRight();
                break;

            case OperatorType.UnsignedRightShift:
                generator.ShiftRightUnsigned();
                EmitConversion.ToNumber(generator, typeof(uint));
                break;

            // Equality operations.
            case OperatorType.Equal:
                generator.Call(ReflectionHelpers.TypeComparer_Equals);
                break;

            case OperatorType.StrictlyEqual:
                generator.Call(ReflectionHelpers.TypeComparer_StrictEquals);
                break;

            case OperatorType.NotEqual:
                generator.Call(ReflectionHelpers.TypeComparer_Equals);
                generator.LoadBoolean(false);
                generator.CompareEqual();
                break;

            case OperatorType.StrictlyNotEqual:
                generator.Call(ReflectionHelpers.TypeComparer_StrictEquals);
                generator.LoadBoolean(false);
                generator.CompareEqual();
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported operator {0}", this.OperatorType));
            }
        }
        /// <summary>
        /// Generates CIL for the instanceof operator.
        /// </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 GenerateInstanceOf(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            if (optimizationInfo.RootExpression == this)
            {
                Left.GenerateCode(generator, optimizationInfo);
                Right.GenerateCode(generator, optimizationInfo);
                generator.Pop();
                generator.Pop();
                return;
            }

            // Emit the left-hand side expression and convert it to an object.
            this.Left.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.Left.GetResultType(optimizationInfo));

            // Store the left-hand side expression in a temporary variable.
            var temp = generator.CreateTemporaryVariable(typeof(object));

            generator.StoreVariable(temp);

            // Emit the right-hand side expression.
            this.Right.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.Right.GetResultType(optimizationInfo));

            // Check the right-hand side is a function - if not, throw an exception.
            generator.IsInstance(typeof(Library.FunctionInstance));
            generator.Duplicate();
            var endOfTypeCheck = generator.CreateLabel();

            generator.BranchIfNotNull(endOfTypeCheck);

            // Throw an nicely formatted exception.
            var rightValue = generator.CreateTemporaryVariable(typeof(object));

            generator.StoreVariable(rightValue);
            EmitHelpers.LoadEngine(generator);
            generator.LoadString("TypeError");
            generator.LoadString("The instanceof operator expected a function, but found '{0}' instead");
            generator.LoadInt32(1);
            generator.NewArray(typeof(object));
            generator.Duplicate();
            generator.LoadInt32(0);
            generator.LoadVariable(rightValue);
            generator.Call(ReflectionHelpers.TypeUtilities_TypeOf);
            generator.StoreArrayElement(typeof(object));
            generator.Call(ReflectionHelpers.String_Format);
            generator.LoadInt32(1);
            generator.LoadStringOrNull(optimizationInfo.Source.Path);
            generator.LoadStringOrNull(optimizationInfo.FunctionName);
            generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error);
            generator.Throw();
            generator.DefineLabelPosition(endOfTypeCheck);
            generator.ReleaseTemporaryVariable(rightValue);

            // Emit the engine for FunctionInstance_HasInstance:
            EmitHelpers.LoadEngine(generator);

            // Load the left-hand side expression from the temporary variable.
            generator.LoadVariable(temp);

            // Call FunctionInstance.HasInstance(object)
            generator.Call(ReflectionHelpers.FunctionInstance_HasInstance);

            // Allow the temporary variable to be reused.
            generator.ReleaseTemporaryVariable(temp);
        }
Beispiel #13
0
        /// <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)
        {
            // Get the target as a name expression:
            NameExpression nameExpr = Target as NameExpression;

            // Grab if this is a 'new' call:
            bool isConstructor = optimizationInfo.IsConstructCall;

            optimizationInfo.IsConstructCall = false;

            if (ResolvedMethod != null)
            {
                // We have a known method!

                if (UserDefined != null)
                {
                    if (isConstructor)
                    {
                        // Generate code to produce the "this" value.
                        Library.Prototype proto = UserDefined.GetInstancePrototype(optimizationInfo.Engine);

                        // Create the object now:
                        generator.NewObject(proto.TypeConstructor);

                        // Duplicate (which will act as our return value):
                        if (optimizationInfo.RootExpression != this)
                        {
                            generator.Duplicate();
                        }
                    }
                    else
                    {
                        // There are three cases for non-constructor calls.
                        if (this.Target is NameExpression)
                        {
                            // 1. The function is a name expression (e.g. "parseInt()").
                            //	In this case this = scope.ImplicitThisValue, if there is one, otherwise undefined.
                            ((NameExpression)this.Target).GenerateThis(generator);
                        }
                        else if (this.Target is MemberAccessExpression)
                        {
                            // 2. The function is a member access expression (e.g. "Math.cos()").
                            //	In this case this = Math.
                            var baseExpression = ((MemberAccessExpression)this.Target).Base;
                            baseExpression.GenerateCode(generator, optimizationInfo);
                            EmitConversion.ToAny(generator, baseExpression.GetResultType(optimizationInfo));
                        }
                        else
                        {
                            // 3. Neither of the above (e.g. "(function() { return 5 })()")
                            //	In this case this = undefined.
                            EmitHelpers.EmitUndefined(generator);
                        }
                    }
                }

                // Emit the rest of the args:
                EmitArguments(generator, optimizationInfo);

                // Got a return type?
                Type returnType = GetResultType(optimizationInfo);

                // Then the call!
                if (typeof(System.Reflection.ConstructorInfo).IsAssignableFrom(ResolvedMethod.GetType()))
                {
                    // Actual constructor call:
                    generator.NewObject(ResolvedMethod as System.Reflection.ConstructorInfo);
                }
                else
                {
                    // Ordinary method:
                    generator.Call(ResolvedMethod);
                }

                if (isConstructor)
                {
                    // Always a returned value here. Needed?
                    if (optimizationInfo.RootExpression == this)
                    {
                        // Remove the return value:
                        generator.Pop();
                    }
                }
                else
                {
                    if (returnType == typeof(Nitrassic.Undefined))
                    {
                        if (optimizationInfo.RootExpression != this)
                        {
                            // Put undef on the stack:
                            EmitHelpers.EmitUndefined(generator);
                        }
                    }
                    else if (optimizationInfo.RootExpression == this)
                    {
                        // Remove the return value:
                        generator.Pop();
                    }
                }
            }
            else
            {
                // Either runtime resolve it or it's not actually a callable function
                throw new NotImplementedException("A function was called which was not supported (" + ToString() + ")");
            }
        }
Beispiel #14
0
        /// <summary>
        /// Stores the value on the top of the stack in the reference.
        /// </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="valueType"> The primitive type of the value that is on the top of the stack. </param>
        /// <param name="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if
        /// the name is unresolvable; <c>false</c> to create a new property instead. </param>
        public void GenerateSet(ILGenerator generator, OptimizationInfo optimizationInfo, bool rIU, Type valueType, SetValueMethod value, bool throwIfUnresolvable)
        {
            if (ResolvedProperty == null)
            {
                // Dynamic property access
                // -----------------------
                // xxx = object.Set(x)

                // Load the left-hand side:
                var lhs = this.GetOperand(0);

                // -- Begin args for Prototype.SetPropertyValue --

                // Script engine (engine):
                EmitHelpers.LoadEngine(generator);

                // Put LHS object onto stack now (thisObj):
                lhs.GenerateCode(generator, optimizationInfo);

                // What type have we now got on the stack? Typically expected to be 'object'.
                Type lhsType = lhs.GetResultType(optimizationInfo);

                // Ensure it's boxed (still thisObj):
                EmitConversion.ToAny(generator, lhsType);

                // Load the property name and convert to a string.
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToString(generator, rhs.GetResultType(optimizationInfo));

                if (rIU)
                {
                    // Output the value now (twice):
                    value(true);

                    // We now have [obj][value][value] on the stack.
                    // Calling the set method would fail (as it'll operate on the duplicated value).
                    // So, we have to pop one off and re-add it after.

                    // In order for SetValue to work, we need to shove the 2nd copy into a temp variable.
                    ILLocalVariable localVar = generator.DeclareVariable(valueType);

                    // Store into the local:
                    generator.StoreVariable(localVar);

                    // Set the value:
                    generator.Call(ReflectionHelpers.Object_SetPropertyValue);

                    // Load from the local:
                    generator.LoadVariable(localVar);
                }
                else
                {
                    // Output the value now:
                    value(false);

                    // Set the value:
                    generator.Call(ReflectionHelpers.Object_SetPropertyValue);
                }
            }
            else if (isArrayIndex)
            {
                // Array indexer
                // -------------
                // object[index] = x

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);

                // Load the right-hand side and convert to int32/uint32/whatever the indexer function wants.
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);

                // Convert the index:
                EmitConversion.Convert(generator, rhs.GetResultType(optimizationInfo), ResolvedProperty.FirstIndexType);

                // Call set:
                ResolvedProperty.Set(generator, optimizationInfo, rIU, valueType, value);
            }
            else
            {
                // Named property modification (e.g. x.property = y)
                // -------------------------------------------------

                if (ResolvedProperty.HasEngine)
                {
                    // Emit the engine ref:
                    EmitHelpers.LoadEngine(generator);
                }

                if (ResolvedProperty.HasAccessor)
                {
                    // Load the left-hand side:
                    var lhs = GetOperand(0);
                    lhs.GenerateCode(generator, optimizationInfo);
                }

                // Target object is now on the stack.

                // Set it:
                ResolvedProperty.Set(generator, optimizationInfo, rIU, valueType, value);
            }
        }
        /// <summary>
        /// Generates CIL for the statement.
        /// </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)
        {
            List <string> labels = optimizationInfo.Labels;

            optimizationInfo.Labels = null;

            // We need a label for each case clause and one for the default case.
            var     jumpTargets  = new ILLabel[this.CaseClauses.Count];
            int     defaultIndex = -1;
            ILLabel endOfSwitch  = generator.CreateLabel();

            // Generate code for the switch value.
            var startOfSwitch = generator.CreateLabel();

            this.Value.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.Value.GetResultType(optimizationInfo));

            // Save the switch value in a variable.
            var switchValue = generator.CreateTemporaryVariable(typeof(object));

            generator.StoreVariable(switchValue);

            for (int i = 0; i < this.CaseClauses.Count; i++)
            {
                var caseClause = this.CaseClauses[i];

                // Create a label for each clause.
                jumpTargets[i] = generator.CreateLabel();

                if (caseClause.Value == null)
                {
                    // This is a default clause.
                    defaultIndex = i;
                    continue;
                }

                // TypeComparer.StrictEquals(switchValue, caseValue)
                generator.LoadVariable(switchValue);
                caseClause.Value.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, caseClause.Value.GetResultType(optimizationInfo));
                generator.Call(ReflectionHelpers.TypeComparer_StrictEquals);

                // if (TypeComparer.StrictEquals(switchValue, caseValue) == true)
                //	 goto case i
                generator.BranchIfTrue(jumpTargets[i]);
            }

            // None of the cases matched, jump to the default clause or the end of the switch.
            if (defaultIndex >= 0)
            {
                generator.Branch(jumpTargets[defaultIndex]);
            }
            else
            {
                generator.Branch(endOfSwitch);
            }

            // Get the previous root - we'll be changing it:
            Expression prevRoot = optimizationInfo.RootExpression;

            for (int i = 0; i < this.CaseClauses.Count; i++)
            {
                // Define a label at the start of the case clause.
                generator.DefineLabelPosition(jumpTargets[i]);

                // Set up the information needed by the break statement.
                optimizationInfo.PushBreakOrContinueInfo(labels, endOfSwitch, null, false);

                // Emit the case clause statements.
                foreach (var statement in this.CaseClauses[i].BodyStatements)
                {
                    // Mark as root:
                    statement.SetRoot(optimizationInfo);

                    // Emit:
                    statement.GenerateCode(generator, optimizationInfo);
                }

                // Revert the information needed by the break statement.
                optimizationInfo.PopBreakOrContinueInfo();
            }

            // Define a label for the end of the switch statement.
            generator.DefineLabelPosition(endOfSwitch);

            // Release the switch value variable for use elsewhere.
            generator.ReleaseTemporaryVariable(switchValue);

            // Restore root:
            optimizationInfo.RootExpression = prevRoot;
        }
        /// <summary>
        /// Generates CIL for the relational 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 GenerateRelational(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Get the statically-determined types of the left and right operands.
            Type leftType  = this.Left.GetResultType(optimizationInfo);
            Type rightType = this.Right.GetResultType(optimizationInfo);

            // The relational operators compare strings if both of the operands are strings.
            if (leftType == typeof(string) && rightType == typeof(string))
            {
                // Both of the operands are strings.

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

                // Load the right hand side operand onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                if (optimizationInfo.RootExpression == this)
                {
                    generator.Pop();
                    generator.Pop();
                    return;
                }

                // Compare the two strings.
                generator.Call(ReflectionHelpers.String_CompareOrdinal);
                switch (this.OperatorType)
                {
                case OperatorType.LessThan:
                    generator.LoadInt32(0);
                    generator.CompareLessThan();
                    break;

                case OperatorType.LessThanOrEqual:
                    generator.LoadInt32(1);
                    generator.CompareLessThan();
                    break;

                case OperatorType.GreaterThan:
                    generator.LoadInt32(0);
                    generator.CompareGreaterThan();
                    break;

                case OperatorType.GreaterThanOrEqual:
                    generator.LoadInt32(-1);
                    generator.CompareGreaterThan();
                    break;
                }
            }
            else if (leftType == typeof(int) && rightType == typeof(int))
            {
                // Both of the operands are integers.

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

                // Load the right hand side operand onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                if (optimizationInfo.RootExpression == this)
                {
                    generator.Pop();
                    generator.Pop();
                    return;
                }

                // Compare the two numbers.
                switch (this.OperatorType)
                {
                case OperatorType.LessThan:
                    generator.CompareLessThan();
                    break;

                case OperatorType.GreaterThan:
                    generator.CompareGreaterThan();
                    break;

                case OperatorType.LessThanOrEqual:
                    // a <= b   <-->   (a > b) == false
                    generator.CompareGreaterThan();
                    generator.LoadBoolean(false);
                    generator.CompareEqual();
                    break;

                case OperatorType.GreaterThanOrEqual:
                    // a >= b   <-->   (a < b) == false
                    generator.CompareLessThan();
                    generator.LoadBoolean(false);
                    generator.CompareEqual();
                    break;
                }
            }
            else if (PrimitiveTypeUtilities.IsNumeric(leftType) || PrimitiveTypeUtilities.IsNumeric(rightType))
            {
                // At least one of the operands is a number.

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

                // Convert the operand to a number.
                EmitConversion.ToNumber(generator, leftType);

                // Load the right hand side operand onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                if (optimizationInfo.RootExpression == this)
                {
                    generator.Pop();
                    generator.Pop();
                    return;
                }

                // Convert the operand to a number.
                EmitConversion.ToNumber(generator, rightType);

                // Compare the two numbers.
                switch (this.OperatorType)
                {
                case OperatorType.LessThan:
                    generator.CompareLessThan();
                    break;

                case OperatorType.GreaterThan:
                    generator.CompareGreaterThan();
                    break;

                case OperatorType.LessThanOrEqual:
                    // a <= b   <-->   (a > b) == false
                    generator.CompareGreaterThanUnsigned();
                    generator.LoadBoolean(false);
                    generator.CompareEqual();
                    break;

                case OperatorType.GreaterThanOrEqual:
                    // a >= b   <-->   (a < b) == false
                    generator.CompareLessThanUnsigned();
                    generator.LoadBoolean(false);
                    generator.CompareEqual();
                    break;
                }
            }
            else
            {
                // It is unknown whether one of the operands is a string.

                // Load the left hand side operand onto the stack.
                this.Left.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, leftType);

                // Load the right hand side operand onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                if (optimizationInfo.RootExpression == this)
                {
                    generator.Pop();
                    generator.Pop();
                    return;
                }

                EmitConversion.ToAny(generator, rightType);

                switch (this.OperatorType)
                {
                case OperatorType.LessThan:
                    generator.Call(ReflectionHelpers.TypeComparer_LessThan);
                    break;

                case OperatorType.LessThanOrEqual:
                    generator.Call(ReflectionHelpers.TypeComparer_LessThanOrEqual);
                    break;

                case OperatorType.GreaterThan:
                    generator.Call(ReflectionHelpers.TypeComparer_GreaterThan);
                    break;

                case OperatorType.GreaterThanOrEqual:
                    generator.Call(ReflectionHelpers.TypeComparer_GreaterThanOrEqual);
                    break;
                }
            }
        }
        /// <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.");
            }
        }