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

132 lines
5.8 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;
public abstract class BinaryOp : AST{
protected AST operand1;
protected AST operand2;
protected JSToken operatorTok;
protected Type type1;
protected Type type2;
protected MethodInfo operatorMeth;
internal BinaryOp(Context context, AST operand1, AST operand2)
: this(context, operand1, operand2, (JSToken)0){
}
internal BinaryOp(Context context, AST operand1, AST operand2, JSToken operatorTok)
: base(context) {
this.operand1 = operand1;
this.operand2 = operand2;
this.operatorTok = operatorTok;
this.type1 = null;
this.type2 = null;
this.operatorMeth = null;
}
internal override void CheckIfOKToUseInSuperConstructorCall(){
this.operand1.CheckIfOKToUseInSuperConstructorCall();
this.operand2.CheckIfOKToUseInSuperConstructorCall();
}
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 AST PartiallyEvaluate(){
this.operand1 = this.operand1.PartiallyEvaluate();
this.operand2 = this.operand2.PartiallyEvaluate();
try{
if (this.operand1 is ConstantWrapper){
if (this.operand2 is ConstantWrapper)
return new ConstantWrapper(this.Evaluate(), this.context);
else{
Object val = ((ConstantWrapper)this.operand1).value;
if (val is String && ((String)val).Length == 1 && this.operand2.InferType(null) == Typeob.Char)
((ConstantWrapper)this.operand1).value = (Char)((String)val)[0];
}
}else if (this.operand2 is ConstantWrapper){
Object val = ((ConstantWrapper)this.operand2).value;
if (val is String && ((String)val).Length == 1 && this.operand1.InferType(null) == Typeob.Char)
((ConstantWrapper)this.operand2).value = (Char)((String)val)[0];
}
}catch(JScriptException e){
this.context.HandleError((JSError)(e.ErrorNumber & 0xFFFF));
}catch{
this.context.HandleError(JSError.TypeMismatch);
}
return this;
}
internal override void TranslateToILInitializer(ILGenerator il){
this.operand1.TranslateToILInitializer(il);
this.operand2.TranslateToILInitializer(il);
}
}
}