Files
yallie 9fa3874800 Added the contents of the archive.
Moved the original file to the archive subfolder.
2017-11-20 16:11:42 +03:00

300 lines
12 KiB
C#

// ==++==
//
//
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
// ==--==
namespace Microsoft.JScript
{
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
public sealed class NumericUnary : UnaryOp{
private Object metaData = null;
private JSToken operatorTok;
private MethodInfo operatorMeth;
private Type type;
internal NumericUnary(Context context, AST operand, JSToken operatorTok)
: base(context, operand){
this.operatorTok = operatorTok;
this.operatorMeth = null;
this.type = null;
}
public NumericUnary(int operatorTok)
: this(null, null, (JSToken)operatorTok){
}
internal override Object Evaluate(){
return this.EvaluateUnary(this.operand.Evaluate());
}
#if !DEBUG
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
#endif
public Object EvaluateUnary(Object v){
IConvertible ic = Convert.GetIConvertible(v);
switch(Convert.GetTypeCode(v, ic)){
case TypeCode.Empty: return this.EvaluateUnary(Double.NaN);
case TypeCode.DBNull: return this.EvaluateUnary(0);
case TypeCode.Boolean: return this.EvaluateUnary(ic.ToBoolean(null) ? 1 : 0);
case TypeCode.Char: return this.EvaluateUnary((int)ic.ToChar(null));
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
int i = ic.ToInt32(null);
switch (this.operatorTok){
case JSToken.BitwiseNot:
return ~i;
case JSToken.LogicalNot:
return i == 0;
case JSToken.Minus:
if (i == 0) return -(double)i;
return -i;
case JSToken.Plus:
return i;
default:
throw new JScriptException(JSError.InternalError, this.context);
}
case TypeCode.UInt32:
uint ui = ic.ToUInt32(null);
switch (this.operatorTok){
case JSToken.BitwiseNot:
return ~ui;
case JSToken.LogicalNot:
return ui == 0;
case JSToken.Minus:
if (ui != 0 && ui <= Int32.MaxValue)
return -(int)ui;
else
return -(double)ui;
case JSToken.Plus:
return ui;
default:
throw new JScriptException(JSError.InternalError, this.context);
}
case TypeCode.Int64:
long l = ic.ToInt64(null);
switch (this.operatorTok){
case JSToken.BitwiseNot:
return ~l;
case JSToken.LogicalNot:
return l == 0;
case JSToken.Minus:
if (l == 0) return -(double)l;
return -l;
case JSToken.Plus:
return l;
default:
throw new JScriptException(JSError.InternalError, this.context);
}
case TypeCode.UInt64:
ulong ul = ic.ToUInt64(null);
switch (this.operatorTok){
case JSToken.BitwiseNot:
return ~ul;
case JSToken.LogicalNot:
return ul == 0;
case JSToken.Minus:
if (ul != -0 && ul < Int64.MaxValue)
return -(long)ul;
else
return -(double)ul;
case JSToken.Plus:
return ul;
default:
throw new JScriptException(JSError.InternalError, this.context);
}
case TypeCode.Single:
case TypeCode.Double:
double d = ic.ToDouble(null);
switch (this.operatorTok){
case JSToken.BitwiseNot:
return ~(int)d;
case JSToken.LogicalNot:
return !Convert.ToBoolean(d);
case JSToken.Minus:
return -d;
case JSToken.Plus:
return d;
default:
throw new JScriptException(JSError.InternalError, this.context);
}
case TypeCode.String:
goto no_overload_case;
}
MethodInfo oper = this.GetOperator(v.GetType());
if (oper != null)
return oper.Invoke(null, (BindingFlags)0, JSBinder.ob, new Object[]{v}, null);
no_overload_case:
switch (this.operatorTok){
case JSToken.BitwiseNot:
return ~Convert.ToInt32(v, ic);
case JSToken.LogicalNot:
return !Convert.ToBoolean(v, ic);
case JSToken.Minus:
return -Convert.ToNumber(v, ic);
case JSToken.Plus:
return Convert.ToNumber(v, ic);
default:
throw new JScriptException(JSError.InternalError, this.context);
}
}
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;
}
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 (this.operatorTok == JSToken.LogicalNot) return Typeob.Boolean;
switch (Type.GetTypeCode(this.type)){
case TypeCode.Empty: return this.operatorTok == JSToken.BitwiseNot ? Typeob.Int32 : Typeob.Double;
case TypeCode.Object: return Typeob.Object;
case TypeCode.DBNull: return Typeob.Int32;
case TypeCode.Boolean: return Typeob.Int32;
case TypeCode.SByte: return (this.operatorTok == JSToken.BitwiseNot) ? Typeob.SByte : Typeob.Int32;
case TypeCode.Char: return Typeob.Int32;
case TypeCode.Byte: return (this.operatorTok == JSToken.BitwiseNot) ? Typeob.Byte : Typeob.Int32;
case TypeCode.Int16: return (this.operatorTok == JSToken.BitwiseNot) ? Typeob.Int16 : Typeob.Int32;
case TypeCode.UInt16: return (this.operatorTok == JSToken.BitwiseNot) ? Typeob.UInt16 : Typeob.Int32;
case TypeCode.Int32: return Typeob.Int32;
case TypeCode.UInt32: return this.operatorTok == JSToken.Minus ? Typeob.Double : Typeob.UInt32;
case TypeCode.Int64: return Typeob.Int64;
case TypeCode.UInt64: return this.operatorTok == JSToken.Minus ? Typeob.Double : Typeob.UInt64;
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.String: return this.operatorTok == JSToken.BitwiseNot ? Typeob.Int32 : Typeob.Double;
}
if (Typeob.JSObject.IsAssignableFrom(this.type))
return Typeob.Double;
else
return Typeob.Object;
}
internal override void TranslateToConditionalBranch(ILGenerator il, bool branchIfTrue, Label label, bool shortForm){
if (this.operatorTok == JSToken.LogicalNot)
this.operand.TranslateToConditionalBranch(il, !branchIfTrue, label, shortForm);
else
base.TranslateToConditionalBranch(il, branchIfTrue, label, shortForm);
}
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);
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 TranslateToILInitializer(ILGenerator il){
IReflect rtype = this.InferType(null);
this.operand.TranslateToILInitializer(il);
if (rtype != Typeob.Object)
return;
this.metaData = il.DeclareLocal(typeof(NumericUnary));
ConstantWrapper.TranslateToILInt(il, (int)this.operatorTok);
il.Emit(OpCodes.Newobj, CompilerGlobals.numericUnaryConstructor);
il.Emit(OpCodes.Stloc, (LocalBuilder)this.metaData);
}
}
}