internal override IReflect InferType(JSField inference_target) { MethodInfo oper; if (this.type1 == null || inference_target != null) { oper = this.GetOperator(this.operand1.InferType(inference_target), this.operand2.InferType(inference_target)); } else { oper = this.GetOperator(this.type1, this.type2); } if (oper != null) { this.metaData = oper; return(oper.ReturnType); } if (this.type1 == Typeob.String || this.type2 == Typeob.String) { return(Typeob.String); } if (Convert.IsPrimitiveNumericType(this.type1)) { if (Convert.IsPromotableTo(this.type2, this.type1) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(this.type1))) { return(this.type1); } else if (Convert.IsPrimitiveNumericType(this.type1) && Convert.IsPrimitiveNumericTypeFitForDouble(this.type2)) { return(Typeob.Double); } } return(Typeob.Object); }
internal override IReflect InferType(JSField inference_target) { MethodInfo oper; if (this.type == null || inference_target != null) { oper = this.GetOperator(this.operand.InferType(inference_target)); } else { oper = this.GetOperator(this.type); } if (oper != null) { this.metaData = oper; return(oper.ReturnType); } if (Convert.IsPrimitiveNumericType(this.type)) { return(this.type); } else if (this.type == Typeob.Char) { return(this.type); } else if (Typeob.JSObject.IsAssignableFrom(this.type)) { return(Typeob.Double); } else { return(Typeob.Object); } }
private IReflect ProvideWrapperForPrototypeProperties(IReflect obType) { //Provide for early binding to prototype methods in fast mode, by fudging the type if (obType == Typeob.String) { obType = Globals.globalObject.originalString.Construct(); ((JSObject)obType).noExpando = this.fast; this.isImplicitWrapper = true; } else if ((obType is Type && Typeob.Array.IsAssignableFrom((Type)obType)) || obType is TypedArray) { obType = Globals.globalObject.originalArray.ConstructWrapper(); ((JSObject)obType).noExpando = this.fast; this.isImplicitWrapper = true; } else if (obType == Typeob.Boolean) { obType = Globals.globalObject.originalBoolean.Construct(); ((JSObject)obType).noExpando = this.fast; this.isImplicitWrapper = true; } else if (Convert.IsPrimitiveNumericType(obType)) { Type baseType = (Type)obType; obType = Globals.globalObject.originalNumber.Construct(); ((JSObject)obType).noExpando = this.fast; ((NumberObject)obType).baseType = baseType; this.isImplicitWrapper = true; } else if (obType is Type) { obType = Convert.ToIReflect((Type)obType, this.Engine); } return(obType); }
internal ErrorObject(ErrorPrototype parent, Object[] args) : base(parent) { this.exception = null; this.description = ""; this.number = 0; if (args.Length == 1) { if (args[0] == null || Convert.IsPrimitiveNumericType(args[0].GetType())) { this.number = Convert.ToNumber(args[0]); } else { this.description = Convert.ToString(args[0]); } } else if (args.Length > 1) { this.number = Convert.ToNumber(args[0]); this.description = Convert.ToString(args[1]); } this.message = this.description; this.noExpando = false; }
internal void SetInferredType(IReflect ir, AST expr) { this.isDefined = true; if (this.type != null) { return; //The local variable has a type annotation. } if (this.outerField != null) { this.outerField.SetInferredType(ir, expr); return; } if (Convert.IsPrimitiveNumericType(ir)) { ir = Typeob.Double; } else if (ir == Typeob.Void) { ir = Typeob.Object; } if (this.inferred_type == null) { this.inferred_type = ir; } else { //Check to see if ir is compatible with this.inferred_type. If not, generalize this.inferred_type to Object and invalidate dependants. if (ir == this.inferred_type) { return; } if (!Convert.IsPrimitiveNumericType(this.inferred_type) || !Convert.IsPrimitiveNumericType(ir) || !Convert.IsPromotableTo(ir, this.inferred_type)) { this.inferred_type = Typeob.Object; if (this.dependents != null) //Some other fields have had their inferred types set to something or other, based on this field's inferred type //Since the inference for this field proved wrong, the inferences for the other fields might be wrong as well. { for (int i = 0, n = this.dependents.Count; i < n; i++) { ((JSLocalField)this.dependents[i]).SetInferredType(Typeob.Object, null); } } } } }
internal void SetInferredType(IReflect ir, AST expr) { this.isDefined = true; if (this.type != null) { return; //The local variable has a type annotation. } if (this.outerField != null) { this.outerField.SetInferredType(ir, expr); return; } if (Convert.IsPrimitiveNumericTypeFitForDouble(ir)) { ir = Typeob.Double; } else if (ir == Typeob.Void) { ir = Typeob.Object; } if (this.inferred_type == null) { this.inferred_type = ir; } else { //Check to see if ir is compatible with this.inferred_type. If not, generalize this.inferred_type to Object and invalidate dependants. if (ir == this.inferred_type) { return; } if (!Convert.IsPrimitiveNumericType(this.inferred_type) || !Convert.IsPrimitiveNumericType(ir) || !Convert.IsPromotableTo(ir, this.inferred_type)) { this.inferred_type = Typeob.Object; if (this.dependents != null) { for (int i = 0, n = this.dependents.Count; i < n; i++) { ((JSLocalField)this.dependents[i]).SetInferredType(Typeob.Object, null); } } } } }
internal override IReflect InferType(JSField inference_target) { Debug.Assert(Globals.TypeRefs.InReferenceContext(this.type1)); Debug.Assert(Globals.TypeRefs.InReferenceContext(this.type2)); MethodInfo oper; if (this.type1 == null || inference_target != null) { oper = this.GetOperator(this.operand1.InferType(inference_target), this.operand2.InferType(inference_target)); } else { oper = this.GetOperator(this.type1, this.type2); } if (oper != null) { this.metaData = oper; return(oper.ReturnType); } if (this.type1 == Typeob.Char && this.operatorTok == JSToken.Minus) { TypeCode t2 = Type.GetTypeCode(this.type2); if (Convert.IsPrimitiveNumericTypeCode(t2) || t2 == TypeCode.Boolean) { return(Typeob.Char); } else if (t2 == TypeCode.Char) { return(Typeob.Int32); } } if (Convert.IsPrimitiveNumericType(this.type1)) { if (Convert.IsPromotableTo(this.type2, this.type1) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(this.type1))) { return(this.type1); } else if (Convert.IsPrimitiveNumericType(this.type1) && Convert.IsPrimitiveNumericTypeFitForDouble(this.type2)) { return(Typeob.Double); } } return(Typeob.Object); }
private MethodInfo GetOperator(IReflect ir) { Type t = ir is Type ? (Type)ir : Typeob.Object; if (this.type == t) { return(this.operatorMeth); } this.type = t; if (Convert.IsPrimitiveNumericType(t) || Typeob.JSObject.IsAssignableFrom(t)) { this.operatorMeth = null; return(null); } switch (this.operatorTok) { case JSToken.BitwiseNot: this.operatorMeth = t.GetMethod("op_OnesComplement", BindingFlags.Public | BindingFlags.Static, JSBinder.ob, new Type[] { t }, null); break; case JSToken.LogicalNot: this.operatorMeth = t.GetMethod("op_LogicalNot", BindingFlags.Public | BindingFlags.Static, JSBinder.ob, new Type[] { t }, null); break; case JSToken.Minus: this.operatorMeth = t.GetMethod("op_UnaryNegation", BindingFlags.Public | BindingFlags.Static, JSBinder.ob, new Type[] { t }, null); break; case JSToken.Plus: this.operatorMeth = t.GetMethod("op_UnaryPlus", BindingFlags.Public | BindingFlags.Static, JSBinder.ob, new Type[] { t }, null); break; default: throw new JScriptException(JSError.InternalError, this.context); } if (this.operatorMeth == null || (operatorMeth.Attributes & MethodAttributes.SpecialName) == 0 || operatorMeth.GetParameters().Length != 1) { this.operatorMeth = null; } if (this.operatorMeth != null) { this.operatorMeth = new JSMethodInfo(this.operatorMeth); } return(this.operatorMeth); }
private new MethodInfo GetOperator(IReflect ir1, IReflect ir2) { Type t1 = ir1 is Type ? (Type)ir1 : Typeob.Object; Type t2 = ir2 is Type ? (Type)ir2 : Typeob.Object; if (this.type1 == t1 && this.type2 == t2) { return(this.operatorMeth); } if (t1 == Typeob.String || t2 == Typeob.String || ((Convert.IsPrimitiveNumericType(t1) || Typeob.JSObject.IsAssignableFrom(t1)) && (Convert.IsPrimitiveNumericType(t2) || Typeob.JSObject.IsAssignableFrom(t2)))) { this.operatorMeth = null; this.type1 = t1; this.type2 = t2; return(null); } return(base.GetOperator(t1, t2)); }
private MethodInfo GetOperator(IReflect ir) { Type t = ir is Type ? (Type)ir : Typeob.Object; if (this.type == t) { return(this.operatorMeth); } this.type = t; if (Convert.IsPrimitiveNumericType(t) || Typeob.JSObject.IsAssignableFrom(t)) { this.operatorMeth = null; return(null); } switch (this.operatorTok) { case PostOrPrefix.PostfixDecrement: case PostOrPrefix.PrefixDecrement: this.operatorMeth = t.GetMethod("op_Decrement", BindingFlags.Public | BindingFlags.Static, JSBinder.ob, new Type[] { t }, null); break; case PostOrPrefix.PostfixIncrement: case PostOrPrefix.PrefixIncrement: this.operatorMeth = t.GetMethod("op_Increment", BindingFlags.Public | BindingFlags.Static, JSBinder.ob, new Type[] { t }, null); break; default: throw new JScriptException(JSError.InternalError, this.context); } if (this.operatorMeth != null && (!this.operatorMeth.IsStatic || (operatorMeth.Attributes & MethodAttributes.SpecialName) == (MethodAttributes)0 || operatorMeth.GetParameters().Length != 1)) { this.operatorMeth = null; } if (this.operatorMeth != null) { this.operatorMeth = new JSMethodInfo(this.operatorMeth); } return(this.operatorMeth); }
protected override void HandleNoSuchMemberError() { IReflect obType = this.rootObject.InferType(null); Object obVal = null; if (this.rootObject is ConstantWrapper) { obVal = this.rootObject.Evaluate(); } if ((obType == Typeob.Object && !this.isNonVirtual) || (obType is JSObject && !((JSObject)obType).noExpando) || (obType is GlobalScope && !((GlobalScope)obType).isKnownAtCompileTime)) { return; } if (obType is Type) { Type t = (Type)obType; if (Typeob.ScriptFunction.IsAssignableFrom(t) || t == Typeob.MathObject) { //dealing with an assigment to a member of a builtin constructor function. Debug.Assert(this.fast); this.memberNameContext.HandleError(JSError.OLENoPropOrMethod); return; } if (Typeob.IExpando.IsAssignableFrom(t)) { return; } if (!this.fast) { if (t == Typeob.Boolean || t == Typeob.String || Convert.IsPrimitiveNumericType(t)) { return; } } // Check to see if we couldn't get the member because it is non-static. if (obVal is ClassScope) { MemberInfo[] members = ((ClassScope)obVal).GetMember(this.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (members.Length > 0) { this.memberNameContext.HandleError(JSError.NonStaticWithTypeName); return; } } } if (obVal is FunctionObject) { this.rootObject = new ConstantWrapper(((FunctionObject)obVal).name, this.rootObject.context); this.memberNameContext.HandleError(JSError.OLENoPropOrMethod); return; } // Check to see if we couldn't get the member because it is static. if (obType is ClassScope) { MemberInfo[] members = ((ClassScope)obType).GetMember(this.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (members.Length > 0) { this.memberNameContext.HandleError(JSError.StaticRequiresTypeName); return; } } if (obVal is Type) { this.memberNameContext.HandleError(JSError.NoSuchStaticMember, Convert.ToTypeName((Type)obVal)); } else if (obVal is ClassScope) { this.memberNameContext.HandleError(JSError.NoSuchStaticMember, Convert.ToTypeName((ClassScope)obVal)); } else if (obVal is Namespace) { this.memberNameContext.HandleError(JSError.NoSuchType, ((Namespace)obVal).Name + "." + this.name); } else { if (obType == FunctionPrototype.ob && this.rootObject is Binding && ((Binding)this.rootObject).member is JSVariableField && ((JSVariableField)((Binding)this.rootObject).member).value is FunctionObject) { return; } this.memberNameContext.HandleError(JSError.NoSuchMember, Convert.ToTypeName(obType)); } }
internal override void TranslateToIL(ILGenerator il, Type rtype) { if (this.metaData == null) { Type bbrType = BitwiseBinary.ResultType(this.type1, this.type2, this.operatorTok); if (Convert.IsPrimitiveNumericType(this.type1)) { this.operand1.TranslateToIL(il, this.type1); Convert.Emit(this, il, this.type1, bbrType, true); } else { this.operand1.TranslateToIL(il, Typeob.Double); Convert.Emit(this, il, Typeob.Double, bbrType, true); } Type op2type = BitwiseBinary.Operand2Type(this.operatorTok, bbrType); if (Convert.IsPrimitiveNumericType(this.type2)) { this.operand2.TranslateToIL(il, this.type2); Convert.Emit(this, il, this.type2, op2type, true); } else { this.operand2.TranslateToIL(il, Typeob.Double); Convert.Emit(this, il, Typeob.Double, op2type, true); } switch (this.operatorTok) { case JSToken.BitwiseAnd: il.Emit(OpCodes.And); break; case JSToken.BitwiseOr: il.Emit(OpCodes.Or); break; case JSToken.BitwiseXor: il.Emit(OpCodes.Xor); break; case JSToken.LeftShift: BitwiseBinary.TranslateToBitCountMask(il, bbrType, this.operand2); il.Emit(OpCodes.Shl); break; case JSToken.RightShift: BitwiseBinary.TranslateToBitCountMask(il, bbrType, this.operand2); il.Emit(OpCodes.Shr); break; case JSToken.UnsignedRightShift: BitwiseBinary.TranslateToBitCountMask(il, bbrType, this.operand2); il.Emit(OpCodes.Shr_Un); break; default: throw new JScriptException(JSError.InternalError, this.context); } Convert.Emit(this, il, bbrType, rtype); return; } if (this.metaData is MethodInfo) { MethodInfo oper = (MethodInfo)this.metaData; ParameterInfo[] pars = oper.GetParameters(); this.operand1.TranslateToIL(il, pars[0].ParameterType); this.operand2.TranslateToIL(il, pars[1].ParameterType); il.Emit(OpCodes.Call, oper); Convert.Emit(this, il, oper.ReturnType, rtype); return; } //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method. //Compile operands to objects and devolve the decision making to run time thunks il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); this.operand1.TranslateToIL(il, Typeob.Object); this.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.evaluateBitwiseBinaryMethod); Convert.Emit(this, il, Typeob.Object, rtype); }
private void TranslateToILForNoOverloadCase(ILGenerator il, Type rtype) { Type lhtype = Convert.ToType(this.operand1.InferType(null)); Type rhtype = Convert.ToType(this.operand2.InferType(null)); Type rt = Typeob.Double; if (this.operatorTok != JSToken.Divide && (rtype == Typeob.Void || rtype == lhtype || Convert.IsPrimitiveNumericType(lhtype)) && (Convert.IsPromotableTo(rhtype, lhtype) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(lhtype)))) { rt = lhtype; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char) { rt = Typeob.UInt32; } // If we have "unsigned -= signed" or "signed -= unsigned" then generating the // correct code gets quite complicated. Just go late-bound for this edge case. if (this.operand2 is ConstantWrapper) { if (!((ConstantWrapper)this.operand2).IsAssignableTo(rt)) { // eg: "var u : byte = 123; u -= -100;" should go late bound because // of signed/unsigned mismatch but "u -= 1" should not. rt = Typeob.Object; } } else { if ((Convert.IsPrimitiveSignedNumericType(rhtype) && Convert.IsPrimitiveUnsignedIntegerType(lhtype)) || (Convert.IsPrimitiveUnsignedIntegerType(rhtype) && Convert.IsPrimitiveSignedIntegerType(lhtype))) { rt = Typeob.Object; } } this.operand1.TranslateToILPreSetPlusGet(il); Convert.Emit(this, il, lhtype, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Object) { il.Emit(OpCodes.Ldc_I4, (int)this.operatorTok); il.Emit(OpCodes.Call, CompilerGlobals.numericbinaryDoOpMethod); } else if (rt == Typeob.Double || rt == Typeob.Single) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else if (rt == Typeob.Int32 || rt == Typeob.Int64 || rt == Typeob.Int16 || rt == Typeob.SByte) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf_Un); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf_Un); break; default: throw new JScriptException(JSError.InternalError, this.context); } } if (rtype != Typeob.Void) { LocalBuilder result = il.DeclareLocal(rt); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc, result); Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); il.Emit(OpCodes.Ldloc, result); Convert.Emit(this, il, rt, rtype); } else { Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); } }
protected MethodInfo GetOperator(IReflect ir1, IReflect ir2) { if (ir1 is ClassScope) { ir1 = ((ClassScope)ir1).GetUnderlyingTypeIfEnum(); } if (ir2 is ClassScope) { ir2 = ((ClassScope)ir2).GetUnderlyingTypeIfEnum(); } Type t1 = ir1 is Type ? (Type)ir1 : Typeob.Object; Type t2 = ir2 is Type ? (Type)ir2 : Typeob.Object; if (this.type1 == t1 && this.type2 == t2) { return(this.operatorMeth); } this.type1 = t1; this.type2 = t2; this.operatorMeth = null; if (t1 == Typeob.String || Convert.IsPrimitiveNumericType(ir1) || Typeob.JSObject.IsAssignableFrom(t1)) { t1 = null; } if (t2 == Typeob.String || Convert.IsPrimitiveNumericType(ir2) || Typeob.JSObject.IsAssignableFrom(t2)) { t2 = null; } if (t1 == null && t2 == null) { return(null); } //One of the operands is an object of a type that might have a user defined operator. String name = "op_NoSuchOp"; switch (this.operatorTok) { case JSToken.BitwiseAnd: name = "op_BitwiseAnd"; break; case JSToken.BitwiseOr: name = "op_BitwiseOr"; break; case JSToken.BitwiseXor: name = "op_ExclusiveOr"; break; case JSToken.Divide: name = "op_Division"; break; case JSToken.Equal: name = "op_Equality"; break; case JSToken.GreaterThan: name = "op_GreaterThan"; break; case JSToken.GreaterThanEqual: name = "op_GreaterThanOrEqual"; break; case JSToken.LeftShift: name = "op_LeftShift"; break; case JSToken.LessThan: name = "op_LessThan"; break; case JSToken.LessThanEqual: name = "op_LessThanOrEqual"; break; case JSToken.Minus: name = "op_Subtraction"; break; case JSToken.Modulo: name = "op_Modulus"; break; case JSToken.Multiply: name = "op_Multiply"; break; case JSToken.NotEqual: name = "op_Inequality"; break; case JSToken.Plus: name = "op_Addition"; break; case JSToken.RightShift: name = "op_RightShift"; break; } Type[] types = new Type[] { this.type1, this.type2 }; if (t1 == t2) { MethodInfo op = t1.GetMethod(name, BindingFlags.Public | BindingFlags.Static, JSBinder.ob, types, null); if (op != null && (op.Attributes & MethodAttributes.SpecialName) != 0 && op.GetParameters().Length == 2) { this.operatorMeth = op; } } else { //Search both operand types, but only if there is a possibility that they might have operators defined on them MethodInfo op1 = t1 == null ? null : t1.GetMethod(name, BindingFlags.Public | BindingFlags.Static, JSBinder.ob, types, null); MethodInfo op2 = t2 == null ? null : t2.GetMethod(name, BindingFlags.Public | BindingFlags.Static, JSBinder.ob, types, null); this.operatorMeth = JSBinder.SelectOperator(op1, op2, this.type1, this.type2); //Choose the better of the two } if (this.operatorMeth != null) { this.operatorMeth = new JSMethodInfo(this.operatorMeth); } return(this.operatorMeth); }
internal override void TranslateToIL(ILGenerator il, Type rtype) { if (this.metaData == null) { Type rt = this.operatorTok == JSToken.LogicalNot ? Typeob.Boolean : Typeob.Double; if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(this.type, rtype)) { rt = rtype; } if (this.operatorTok == JSToken.BitwiseNot && !Convert.IsPrimitiveIntegerType(rt)) { rt = this.type; if (!Convert.IsPrimitiveIntegerType(rt)) { rt = Typeob.Int32; } } this.operand.TranslateToIL(il, this.type); Convert.Emit(this, il, this.type, rt, true); switch (this.operatorTok) { case JSToken.BitwiseNot: il.Emit(OpCodes.Not); break; case JSToken.LogicalNot: Convert.Emit(this, il, rt, Typeob.Boolean, true); rt = Typeob.Boolean; il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; case JSToken.Minus: il.Emit(OpCodes.Neg); break; case JSToken.Plus: break; default: throw new JScriptException(JSError.InternalError, this.context); } Convert.Emit(this, il, rt, rtype); return; } if (this.metaData is MethodInfo) { MethodInfo oper = (MethodInfo)this.metaData; ParameterInfo[] pars = oper.GetParameters(); this.operand.TranslateToIL(il, pars[0].ParameterType); il.Emit(OpCodes.Call, oper); Convert.Emit(this, il, oper.ReturnType, rtype); return; } //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method. //Compile operands to objects and devolve the decision making to run time thunks il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); this.operand.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.evaluateUnaryMethod); Convert.Emit(this, il, Typeob.Object, rtype); }
internal override void TranslateToIL(ILGenerator il, Type rtype) { Type type = Convert.ToType(this.InferType(null)); if (this.metaData == null) { Type rt = Typeob.Object; if (rtype == Typeob.Double) { rt = rtype; } else if (this.type1 == Typeob.Char && this.type2 == Typeob.Char) { rt = Typeob.String; } else if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(this.type1, rtype) && Convert.IsPromotableTo(this.type2, rtype)) { rt = rtype; } else if (this.type1 != Typeob.String && this.type2 != Typeob.String) //Both will be converted to numbers { rt = Typeob.Double; //Won't get here unless InferType returned Typeob.Double. } else { rt = Typeob.String; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char) { rt = Typeob.UInt32; } if (rt == Typeob.String) { if (this.operand1 is Plus && this.type1 == rt) { Plus op1 = (Plus)this.operand1; if (op1.operand1 is Plus && op1.type1 == rt) { Plus op11 = (Plus)op1.operand1; if (op11.operand1 is Plus && op11.type1 == rt) { int len = op1.TranslateToILArrayOfStrings(il, 1); il.Emit(OpCodes.Dup); ConstantWrapper.TranslateToILInt(il, len - 1); this.operand2.TranslateToIL(il, rt); il.Emit(OpCodes.Stelem_Ref); il.Emit(OpCodes.Call, CompilerGlobals.stringConcatArrMethod); Convert.Emit(this, il, rt, rtype); return; } Plus.TranslateToStringWithSpecialCaseForNull(il, op11.operand1); Plus.TranslateToStringWithSpecialCaseForNull(il, op11.operand2); Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand2); Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat4Method); Convert.Emit(this, il, rt, rtype); return; } Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand1); Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand2); Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat3Method); Convert.Emit(this, il, rt, rtype); return; } Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand1); Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat2Method); Convert.Emit(this, il, rt, rtype); return; } this.operand1.TranslateToIL(il, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Object) { il.Emit(OpCodes.Call, CompilerGlobals.plusDoOpMethod); } else if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Add); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } return; } if (this.metaData is MethodInfo) { MethodInfo oper = (MethodInfo)this.metaData; ParameterInfo[] pars = oper.GetParameters(); this.operand1.TranslateToIL(il, pars[0].ParameterType); this.operand2.TranslateToIL(il, pars[1].ParameterType); il.Emit(OpCodes.Call, oper); Convert.Emit(this, il, oper.ReturnType, rtype); return; } //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method. //Compile operands to objects and devolve the decision making to run time thunks //Also get here when dealing with Int64 and UInt64. These cannot always be converted to doubles. The late-bound code checks for this. il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); this.operand1.TranslateToIL(il, Typeob.Object); this.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Callvirt, CompilerGlobals.evaluatePlusMethod); Convert.Emit(this, il, Typeob.Object, rtype); }
private void TranslateToILForNoOverloadCase(ILGenerator il, Type rtype) { Type type = Convert.ToType(this.operand.InferType(null)); this.operand.TranslateToILPreSetPlusGet(il); if (rtype == Typeob.Void) { Type rt = Typeob.Double; if (Convert.IsPrimitiveNumericType(type)) { if (type == Typeob.SByte || type == Typeob.Int16) { rt = Typeob.Int32; } else if (type == Typeob.Byte || type == Typeob.UInt16 || type == Typeob.Char) { rt = Typeob.UInt32; } else { rt = type; } } Convert.Emit(this, il, type, rt); il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PrefixDecrement) { il.Emit(OpCodes.Sub); } else { il.Emit(OpCodes.Add); } } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PrefixDecrement) { il.Emit(OpCodes.Sub_Ovf); } else { il.Emit(OpCodes.Add_Ovf); } } else { if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PrefixDecrement) { il.Emit(OpCodes.Sub_Ovf_Un); } else { il.Emit(OpCodes.Add_Ovf_Un); } } Convert.Emit(this, il, rt, type); this.operand.TranslateToILSet(il); } else { //set rt to be the smallest type that is precise enough for the result and the variable Type rt = Typeob.Double; if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(type, rtype)) { rt = rtype; } else if (Convert.IsPrimitiveNumericType(type) && Convert.IsPromotableTo(rtype, type)) { rt = type; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char) { rt = Typeob.UInt32; } LocalBuilder result = il.DeclareLocal(rtype); Convert.Emit(this, il, type, rt); if (this.operatorTok == PostOrPrefix.PostfixDecrement) { il.Emit(OpCodes.Dup); if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } il.Emit(OpCodes.Stloc, result); il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Sub); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Sub_Ovf); } else { il.Emit(OpCodes.Sub_Ovf_Un); } } else if (this.operatorTok == PostOrPrefix.PostfixIncrement) { il.Emit(OpCodes.Dup); if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } il.Emit(OpCodes.Stloc, result); il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Add); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } } else if (this.operatorTok == PostOrPrefix.PrefixDecrement) { il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Sub); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Sub_Ovf); } else { il.Emit(OpCodes.Sub_Ovf_Un); } il.Emit(OpCodes.Dup); if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } il.Emit(OpCodes.Stloc, result); } else //if (this.operatorTok == PostOrPrefix.PrefixIncrement) { il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Add); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } il.Emit(OpCodes.Dup); if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } il.Emit(OpCodes.Stloc, result); } Convert.Emit(this, il, rt, type); this.operand.TranslateToILSet(il); il.Emit(OpCodes.Ldloc, result); } }
private void TranslateToILForNoOverloadCase(ILGenerator il, Type rtype) { Type lhtype = Convert.ToType(this.operand1.InferType(null)); Type rhtype = Convert.ToType(this.operand2.InferType(null)); Type rt = Typeob.Object; if (lhtype == Typeob.String || rhtype == Typeob.String) { rt = Typeob.String; } else if (rtype == Typeob.Void || rtype == lhtype || Convert.IsPrimitiveNumericType(lhtype) && (Convert.IsPromotableTo(rhtype, lhtype) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(lhtype)))) { rt = lhtype; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16) { rt = Typeob.UInt32; } // If we have "unsigned += signed" or "signed += unsigned" then generating the // correct code gets quite complicated. Just go late-bound for this edge case. if (this.operand2 is ConstantWrapper) { if (!((ConstantWrapper)this.operand2).IsAssignableTo(rt)) { // eg: "var u : byte = 123; u += -100;" should go late bound because // of signed/unsigned mismatch but "u += 1" should not. rt = Typeob.Object; } } else { if ((Convert.IsPrimitiveSignedNumericType(rhtype) && Convert.IsPrimitiveUnsignedIntegerType(lhtype)) || (Convert.IsPrimitiveUnsignedIntegerType(rhtype) && Convert.IsPrimitiveSignedIntegerType(lhtype))) { rt = Typeob.Object; } } this.operand1.TranslateToILPreSetPlusGet(il); Convert.Emit(this, il, lhtype, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Object || rt == Typeob.String) { il.Emit(OpCodes.Call, CompilerGlobals.plusDoOpMethod); rt = Typeob.Object; } else if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Add); } else if (rt == Typeob.Int32 || rt == Typeob.Int64 || rt == Typeob.Int16 || rt == Typeob.SByte) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } if (rtype != Typeob.Void) { LocalBuilder result = il.DeclareLocal(rt); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc, result); Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); il.Emit(OpCodes.Ldloc, result); Convert.Emit(this, il, rt, rtype); } else { Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); } }
internal override void TranslateToIL(ILGenerator il, Type rtype) { if (this.metaData == null) { Type rt = Typeob.Double; if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(this.type1, rtype) && Convert.IsPromotableTo(this.type2, rtype)) { rt = rtype; } if (this.operatorTok == JSToken.Divide) { rt = Typeob.Double; } else if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char) { rt = Typeob.UInt32; } this.operand1.TranslateToIL(il, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Double || rt == Typeob.Single) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf_Un); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf_Un); break; default: throw new JScriptException(JSError.InternalError, this.context); } } if (Convert.ToType(this.InferType(null)) == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } return; } if (this.metaData is MethodInfo) { MethodInfo oper = (MethodInfo)this.metaData; ParameterInfo[] pars = oper.GetParameters(); this.operand1.TranslateToIL(il, pars[0].ParameterType); this.operand2.TranslateToIL(il, pars[1].ParameterType); il.Emit(OpCodes.Call, oper); Convert.Emit(this, il, oper.ReturnType, rtype); return; } //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method. //Compile operands to objects and devolve the decision making to run time thunks il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); this.operand1.TranslateToIL(il, Typeob.Object); this.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.evaluateNumericBinaryMethod); Convert.Emit(this, il, Typeob.Object, rtype); }