/// <summary>
        /// Gets the prototype of objects constructed using this function.  Equivalent to
        /// the Function.prototype property.
        /// </summary>
        public Library.Prototype GetInstancePrototype(ScriptEngine engine)
        {
            if (_RawInstancePrototype == null)
            {
                // Create one now!
                _RawInstancePrototype = engine.Prototypes.Create();
            }

            return(_RawInstancePrototype);
        }
        internal override void ResolveVariables(OptimizationInfo optimizationInfo)
        {
            base.ResolveVariables(optimizationInfo);

            // If this is an 'in' operator, resolve the prototype of the right property.

            if (OperatorType == OperatorType.In)
            {
                // Get the type of the RHS (the object being checked):
                Type rhsType = Right.GetResultType(optimizationInfo);

                // Get the proto for it:
                ResolvedPrototype = optimizationInfo.Engine.Prototypes.Get(rhsType);
            }
        }
        internal override void ResolveVariables(OptimizationInfo optimizationInfo)
        {
            // Resolve kids too:
            base.ResolveVariables(optimizationInfo);

            // Is it an object literal?
            var properties = this.Value as List <KeyValuePair <Expression, Expression> >;

            if (properties == null)
            {
                // Not an object literal! How about an array?

                // Get the expressions:
                List <Expression> exprs = this.Value as List <Expression>;

                if (exprs == null)
                {
                    // Not an array either! Quit there.
                    return;
                }

                // For each one..
                foreach (Expression expr in exprs)
                {
                    // Resolve it:
                    expr.ResolveVariables(optimizationInfo);
                }

                return;
            }

            if (CreatedPrototype != null)
            {
                // Already made it!
                return;
            }

            // We'll generate a prototype and a custom object type for it:
            CreatedPrototype = optimizationInfo.Engine.Prototypes.Create();

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

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

                if (propertyValue is Expression)
                {
                    // Add a new property to the object.

                    var dataPropertyValue = (Expression)propertyValue;

                    // Resolve it:
                    dataPropertyValue.ResolveVariables(optimizationInfo);

                    Type valueType = dataPropertyValue.GetResultType(optimizationInfo);

                    // Create the property now:
                    Library.PropertyVariable pv = proto.AddProperty(propertyName, Library.PropertyAttributes.FullAccess, valueType);

                    // If it's a function value then it might be constant.
                    // It might be a constant string/ number too, so track them as well.
                    pv.TryLoadConstant(dataPropertyValue);
                }
                else
                {
                    throw new InvalidOperationException("Invalid property value type in object literal.");
                }
            }
        }
Example #4
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() + ")");
            }
        }
        /// <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.");
            }
        }