internal EnumDeclaration(Context context, IdentifierLiteral id, TypeExpression baseType, Block body, FieldAttributes attributes, CustomAttributeList customAttributes) : base(context, id, new TypeExpression(new ConstantWrapper(Typeob.Enum, null)), new TypeExpression[0], body, attributes, false, false, true, false, customAttributes) { this.baseType = (baseType != null) ? baseType : new TypeExpression(new ConstantWrapper(Typeob.Int32, null)); base.needsEngine = false; base.attributes &= TypeAttributes.NestedFamORAssem; TypeExpression expression = new TypeExpression(new ConstantWrapper(base.classob, base.context)); AST ast = new ConstantWrapper(-1, null); AST ast2 = new ConstantWrapper(1, null); JSMemberField[] fields = base.fields; for (int i = 0; i < fields.Length; i++) { FieldInfo info = fields[i]; JSVariableField field = (JSVariableField) info; field.attributeFlags = FieldAttributes.Literal | FieldAttributes.Static | FieldAttributes.Public; field.type = expression; if (field.value == null) { field.value = ast = new Plus(ast.context, ast, ast2); } else { ast = (AST) field.value; } field.value = new DeclaredEnumValue(field.value, field.Name, base.classob); } }
internal override AST PartiallyEvaluate(){ this.operand1 = this.operand1.PartiallyEvaluateAsReference(); this.operand2 = this.operand2.PartiallyEvaluate(); this.binOp = new Plus(this.context, this.operand1, this.operand2); this.operand1.SetPartialValue(this.binOp); if (this.Engine.doFast){ Binding b = this.operand1 as Binding; if (b != null && b.member is JSVariableField){ TypeExpression te = ((JSVariableField)b.member).type; if (te != null && te.InferType(null) == Typeob.String) this.operand1.context.HandleError(JSError.StringConcatIsSlow); } } return this; }
internal EnumDeclaration(Context context, IdentifierLiteral id, TypeExpression baseType, Block body, FieldAttributes attributes, CustomAttributeList customAttributes) : base(context, id, new TypeExpression(new ConstantWrapper(typeof(Enum), null)), new TypeExpression[0], body, attributes, false, false, true, false, customAttributes){ this.baseType = baseType != null ? baseType : new TypeExpression(new ConstantWrapper(Typeob.Int32, null)); this.needsEngine = false; this.attributes &= TypeAttributes.VisibilityMask; TypeExpression thisType = new TypeExpression(new ConstantWrapper(this.classob, this.context)); AST currentValue = new ConstantWrapper(-1, null); AST one = new ConstantWrapper(1, null); foreach (FieldInfo f in this.fields){ JSVariableField field = (JSVariableField)f; field.attributeFlags = FieldAttributes.Public|FieldAttributes.Static|FieldAttributes.Literal; field.type = thisType; if (field.value == null) field.value = currentValue = new Plus(currentValue.context, currentValue, one); else currentValue = (AST)field.value; field.value = new EnumWrapper(field.value, field.Name, this.classob); } }
internal override AST PartiallyEvaluate() { base.operand1 = base.operand1.PartiallyEvaluateAsReference(); base.operand2 = base.operand2.PartiallyEvaluate(); this.binOp = new Plus(base.context, base.operand1, base.operand2); base.operand1.SetPartialValue(this.binOp); if (base.Engine.doFast) { Binding binding = base.operand1 as Binding; if ((binding != null) && (binding.member is JSVariableField)) { TypeExpression type = ((JSVariableField) binding.member).type; if ((type != null) && (type.InferType(null) == Typeob.String)) { base.operand1.context.HandleError(JSError.StringConcatIsSlow); } } } return this; }
internal PlusAssign(Context context, AST operand1, AST operand2) : base(context, operand1, operand2, JSToken.FirstBinaryOp) { this.binOp = new Plus(context, operand1, operand2); this.metaData = null; }
internal override void TranslateToIL(ILGenerator il, Type rtype) { Type type = Microsoft.JScript.Convert.ToType(this.InferType(null)); if (this.metaData == null) { Type type2 = Typeob.Object; if (rtype == Typeob.Double) { type2 = rtype; } else if ((base.type1 == Typeob.Char) && (base.type2 == Typeob.Char)) { type2 = Typeob.String; } else if ((Microsoft.JScript.Convert.IsPrimitiveNumericType(rtype) && Microsoft.JScript.Convert.IsPromotableTo((IReflect)base.type1, (IReflect)rtype)) && Microsoft.JScript.Convert.IsPromotableTo((IReflect)base.type2, (IReflect)rtype)) { type2 = rtype; } else if ((base.type1 != Typeob.String) && (base.type2 != Typeob.String)) { type2 = Typeob.Double; } else { type2 = Typeob.String; } if ((type2 == Typeob.SByte) || (type2 == Typeob.Int16)) { type2 = Typeob.Int32; } else if (((type2 == Typeob.Byte) || (type2 == Typeob.UInt16)) || (type2 == Typeob.Char)) { type2 = Typeob.UInt32; } if (type2 == Typeob.String) { if ((base.operand1 is Plus) && (base.type1 == type2)) { Plus plus = (Plus)base.operand1; if ((plus.operand1 is Plus) && (plus.type1 == type2)) { Plus plus2 = (Plus)plus.operand1; if ((plus2.operand1 is Plus) && (plus2.type1 == type2)) { int num = plus.TranslateToILArrayOfStrings(il, 1); il.Emit(OpCodes.Dup); ConstantWrapper.TranslateToILInt(il, num - 1); base.operand2.TranslateToIL(il, type2); il.Emit(OpCodes.Stelem_Ref); il.Emit(OpCodes.Call, CompilerGlobals.stringConcatArrMethod); Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } else { TranslateToStringWithSpecialCaseForNull(il, plus2.operand1); TranslateToStringWithSpecialCaseForNull(il, plus2.operand2); TranslateToStringWithSpecialCaseForNull(il, plus.operand2); TranslateToStringWithSpecialCaseForNull(il, base.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat4Method); Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } } else { TranslateToStringWithSpecialCaseForNull(il, plus.operand1); TranslateToStringWithSpecialCaseForNull(il, plus.operand2); TranslateToStringWithSpecialCaseForNull(il, base.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat3Method); Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } } else { TranslateToStringWithSpecialCaseForNull(il, base.operand1); TranslateToStringWithSpecialCaseForNull(il, base.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat2Method); Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } } else { base.operand1.TranslateToIL(il, type2); base.operand2.TranslateToIL(il, type2); if (type2 == Typeob.Object) { il.Emit(OpCodes.Call, CompilerGlobals.plusDoOpMethod); } else if ((type2 == Typeob.Double) || (type2 == Typeob.Single)) { il.Emit(OpCodes.Add); } else if ((type2 == Typeob.Int32) || (type2 == Typeob.Int64)) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } if (type == Typeob.Char) { Microsoft.JScript.Convert.Emit(this, il, type2, Typeob.Char); Microsoft.JScript.Convert.Emit(this, il, Typeob.Char, rtype); } else { Microsoft.JScript.Convert.Emit(this, il, type2, rtype); } } } else if (this.metaData is MethodInfo) { MethodInfo metaData = (MethodInfo)this.metaData; ParameterInfo[] parameters = metaData.GetParameters(); base.operand1.TranslateToIL(il, parameters[0].ParameterType); base.operand2.TranslateToIL(il, parameters[1].ParameterType); il.Emit(OpCodes.Call, metaData); Microsoft.JScript.Convert.Emit(this, il, metaData.ReturnType, rtype); } else { il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); base.operand1.TranslateToIL(il, Typeob.Object); base.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Callvirt, CompilerGlobals.evaluatePlusMethod); Microsoft.JScript.Convert.Emit(this, il, Typeob.Object, rtype); } }
private Object EvaluatePlus2(Object v1, Object v2) { IConvertible ic1 = Convert.GetIConvertible(v1); IConvertible ic2 = Convert.GetIConvertible(v2); TypeCode t1 = Convert.GetTypeCode(v1, ic1); TypeCode t2 = Convert.GetTypeCode(v2, ic2); switch (t1) { case TypeCode.Empty: return(Plus.DoOp(v1, v2)); case TypeCode.DBNull: switch (t2) { case TypeCode.Empty: return(Double.NaN); case TypeCode.DBNull: return(0); case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: return(ic2.ToInt32(null)); case TypeCode.UInt32: return(ic2.ToUInt32(null)); case TypeCode.Int64: return(ic2.ToInt64(null)); case TypeCode.UInt64: return(ic2.ToUInt64(null)); case TypeCode.Single: case TypeCode.Double: return(ic2.ToDouble(null)); case TypeCode.Object: case TypeCode.Decimal: case TypeCode.DateTime: break; case TypeCode.String: return("null" + ic2.ToString(null)); } break; case TypeCode.Char: { int val = ic1.ToInt32(null); switch (t2) { case TypeCode.Empty: return(Double.NaN); case TypeCode.DBNull: return(val); case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: return(((IConvertible)Plus.DoOp(val, ic2.ToInt32(null))).ToChar(null)); case TypeCode.UInt32: case TypeCode.Int64: return(((IConvertible)Plus.DoOp((long)val, ic2.ToInt64(null))).ToChar(null)); case TypeCode.UInt64: return(((IConvertible)Plus.DoOp((ulong)val, ic2.ToUInt64(null))).ToChar(null)); case TypeCode.Single: case TypeCode.Double: checked { return((char)(int)(Convert.CheckIfDoubleIsInteger((double)Plus.DoOp((double)val, ic2.ToDouble(null))))); } case TypeCode.Object: case TypeCode.Decimal: case TypeCode.DateTime: return(Plus.DoOp(v1, v2)); case TypeCode.Char: case TypeCode.String: return(ic1.ToString(null) + ic2.ToString(null)); } break; } case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: { int val = ic1.ToInt32(null); switch (t2) { case TypeCode.Empty: return(Double.NaN); case TypeCode.DBNull: return(val); case TypeCode.Char: return(((IConvertible)Plus.DoOp(val, ic2.ToInt32(null))).ToChar(null)); case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: return(Plus.DoOp(val, ic2.ToInt32(null))); case TypeCode.UInt32: case TypeCode.Int64: return(Plus.DoOp((long)val, ic2.ToInt64(null))); case TypeCode.UInt64: if (val >= 0) { return(Plus.DoOp((ulong)val, ic2.ToUInt64(null))); } else { return(Plus.DoOp((double)val, ic2.ToDouble(null))); } case TypeCode.Single: case TypeCode.Double: return(Plus.DoOp((double)val, ic2.ToDouble(null))); case TypeCode.Object: case TypeCode.Decimal: case TypeCode.DateTime: break; case TypeCode.String: return(Convert.ToString(v1) + ic2.ToString(null)); } break; } case TypeCode.UInt32: { uint val = ic1.ToUInt32(null); switch (t2) { case TypeCode.Empty: return(Double.NaN); case TypeCode.DBNull: return(val); case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.Int32: int val2 = ic2.ToInt32(null); if (val2 >= 0) { return(Plus.DoOp(val, (uint)val2)); } else { return(Plus.DoOp((long)val, (long)val2)); } case TypeCode.Int64: return(Plus.DoOp((long)val, ic2.ToInt64(null))); case TypeCode.Char: return(((IConvertible)Plus.DoOp(val, ic2.ToUInt32(null))).ToChar(null)); case TypeCode.Boolean: case TypeCode.UInt16: case TypeCode.UInt32: return(Plus.DoOp(val, ic2.ToUInt32(null))); case TypeCode.UInt64: return(Plus.DoOp((ulong)val, ic2.ToUInt64(null))); case TypeCode.Single: case TypeCode.Double: return(Plus.DoOp((double)val, ic2.ToDouble(null))); case TypeCode.Object: case TypeCode.Decimal: case TypeCode.DateTime: break; case TypeCode.String: return(Convert.ToString(v1) + ic2.ToString(null)); } break; } case TypeCode.Int64: { long val = ic1.ToInt64(null); switch (t2) { case TypeCode.Empty: return(Double.NaN); case TypeCode.DBNull: return(val); case TypeCode.Char: return(((IConvertible)Plus.DoOp(val, ic2.ToInt64(null))).ToChar(null)); case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: return(Plus.DoOp(val, ic2.ToInt64(null))); case TypeCode.UInt64: if (val >= 0) { return(Plus.DoOp((ulong)val, ic2.ToUInt64(null))); } else { return(Plus.DoOp((double)val, ic2.ToDouble(null))); } case TypeCode.Single: case TypeCode.Double: return(Plus.DoOp((double)val, ic2.ToDouble(null))); case TypeCode.Object: case TypeCode.Decimal: case TypeCode.DateTime: break; case TypeCode.String: return(Convert.ToString(v1) + ic2.ToString(null)); } break; } case TypeCode.UInt64: { ulong val = ic1.ToUInt64(null); switch (t2) { case TypeCode.Empty: return(Double.NaN); case TypeCode.DBNull: return(val); case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: long val2 = ic2.ToInt64(null); if (val2 >= 0) { return(Plus.DoOp(val, (ulong)val2)); } else { return(Plus.DoOp((double)val, (double)val2)); } case TypeCode.Char: return(((IConvertible)Plus.DoOp(val, ic2.ToUInt64(null))).ToChar(null)); case TypeCode.UInt16: case TypeCode.Boolean: case TypeCode.UInt32: case TypeCode.UInt64: return(Plus.DoOp(val, ic2.ToUInt64(null))); case TypeCode.Single: case TypeCode.Double: return(Plus.DoOp((double)val, ic2.ToDouble(null))); case TypeCode.Object: case TypeCode.Decimal: case TypeCode.DateTime: break; case TypeCode.String: return(Convert.ToString(v1) + ic2.ToString(null)); } break; } case TypeCode.Single: case TypeCode.Double: { double d = ic1.ToDouble(null); switch (t2) { case TypeCode.Empty: return(Double.NaN); case TypeCode.DBNull: return(ic1.ToDouble(null)); case TypeCode.Char: return(System.Convert.ToChar(System.Convert.ToInt32((d + (double)ic2.ToInt32(null))))); case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: return(d + (double)ic2.ToInt32(null)); case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: return(d + ic2.ToDouble(null)); case TypeCode.Object: case TypeCode.Decimal: case TypeCode.DateTime: break; case TypeCode.String: return(new ConcatString(Convert.ToString(d), ic2.ToString(null))); } break; } case TypeCode.Object: case TypeCode.Decimal: case TypeCode.DateTime: break; case TypeCode.String: switch (t2) { case TypeCode.Object: break; case TypeCode.String: if (v1 is ConcatString) { return(new ConcatString((ConcatString)v1, ic2.ToString(null))); } else { return(new ConcatString(ic1.ToString(null), ic2.ToString(null))); } default: if (v1 is ConcatString) { return(new ConcatString((ConcatString)v1, Convert.ToString(v2))); } else { return(new ConcatString(ic1.ToString(null), Convert.ToString(v2))); } } break; } MethodInfo oper = this.GetOperator(v1 == null ? Typeob.Empty : v1.GetType(), v2 == null ? Typeob.Empty : v2.GetType()); if (oper != null) { return(oper.Invoke(null, (BindingFlags)0, JSBinder.ob, new Object[] { v1, v2 }, null)); } else { return(Plus.DoOp(v1, v2)); } }
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); }