/// <summary> /// Evaluates the expression, if possible. /// </summary> /// <returns> The result of evaluating the expression, or <c>null</c> if the expression can /// not be evaluated. </returns> public override object Evaluate() { // Evaluate the operands. object left = this.Left.Evaluate(); if (left == null) { return(null); } object right; if (OperatorType == OperatorType.In) { right = null; if (ResolvedPrototype == null) { return(null); } } else { right = this.Right.Evaluate(); if (right == null) { return(null); } } // Apply the binary operator logic. switch (this.OperatorType) { case OperatorType.Add: { var leftPrimitive = TypeConverter.ToPrimitive(left, PrimitiveTypeHint.None); var rightPrimitive = TypeConverter.ToPrimitive(right, PrimitiveTypeHint.None); if (TypeUtilities.IsString(leftPrimitive) == true || TypeUtilities.IsString(rightPrimitive) == true) { return(TypeConverter.ToString(leftPrimitive) + TypeConverter.ToString(rightPrimitive)); } return(TypeConverter.ToNumber(leftPrimitive) + TypeConverter.ToNumber(rightPrimitive)); } // Arithmetic operations. case OperatorType.Subtract: return(TypeConverter.ToNumber(left) - TypeConverter.ToNumber(right)); case OperatorType.Multiply: return(TypeConverter.ToNumber(left) * TypeConverter.ToNumber(right)); case OperatorType.Divide: return(TypeConverter.ToNumber(left) / TypeConverter.ToNumber(right)); case OperatorType.Modulo: return(TypeConverter.ToNumber(left) % TypeConverter.ToNumber(right)); // Bitwise operations. case OperatorType.BitwiseAnd: return(TypeConverter.ToInt32(left) & TypeConverter.ToInt32(right)); case OperatorType.BitwiseOr: return(TypeConverter.ToInt32(left) | TypeConverter.ToInt32(right)); case OperatorType.BitwiseXor: return(TypeConverter.ToInt32(left) ^ TypeConverter.ToInt32(right)); case OperatorType.LeftShift: return(TypeConverter.ToInt32(left) << (int)(TypeConverter.ToUint32(right) & 0x1F)); case OperatorType.SignedRightShift: return(TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F)); case OperatorType.UnsignedRightShift: return((uint)TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F)); // Relational operations. case OperatorType.LessThan: return(TypeComparer.LessThan(left, right)); case OperatorType.LessThanOrEqual: return(TypeComparer.LessThanOrEqual(left, right)); case OperatorType.GreaterThan: return(TypeComparer.GreaterThan(left, right)); case OperatorType.GreaterThanOrEqual: return(TypeComparer.GreaterThanOrEqual(left, right)); // Equality operations. case OperatorType.Equal: return(TypeComparer.Equals(left, right) == true); case OperatorType.StrictlyEqual: return(TypeComparer.StrictEquals(left, right) == true); case OperatorType.NotEqual: return(TypeComparer.Equals(left, right) == false); case OperatorType.StrictlyNotEqual: return(TypeComparer.StrictEquals(left, right) == false); // Logical operations. case OperatorType.LogicalAnd: if (TypeConverter.ToBoolean(left) == false) { return(left); } return(right); case OperatorType.LogicalOr: if (TypeConverter.ToBoolean(left) == true) { return(left); } return(right); // Misc case OperatorType.In: // Constant property! Convert it to a string: string propertyName = TypeConverter.ToString(left); // Exists? return(ResolvedPrototype.GetProperty(propertyName) != null); case OperatorType.InstanceOf: return(null); default: throw new NotImplementedException(string.Format("Unsupported operator {0}", this.OperatorType)); } }
/// <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."); } }