📄 expast.cs
字号:
protected override Type CalcCLRTypeHelper(ISemanticResolver s)
{
return typeof(bool);
}
#endregion
// Code generation
public override void GenerateAsRight(CodeGen.EmitCodeGen gen)
{
gen.Generate(this);
}
}
//-----------------------------------------------------------------------------
// Binary operations
//-----------------------------------------------------------------------------
public class BinaryExp : Exp
{
// @dogfood - 'new String[]' not needed when we have an array of literals,
private static string [] m_ops = new String[] {
"+", "-", "*", "/", "%",
"&&", "||",
"==", "!=", "<", ">", "<=", ">=",
"&", "|", "^",
"<<", ">>"
};
public static string OpName(BinaryOp op)
{
return m_ops[(int) op];
}
public enum BinaryOp
{
cAdd,
cSub,
cMul,
cDiv,
cMod,
cAnd,
cOr,
cEqu,
cNeq,
cLT,
cGT,
cLE,
cGE,
cBitwiseAnd,
cBitwiseOr,
cBitwiseXor,
cShiftLeft,
cShiftRight,
cInvalid,
}
public BinaryExp(Exp left, Exp right, BinaryOp op)
{
Debug.Assert(left != null);
Debug.Assert(right != null);
//m_filerange = FileRange.Merge(left.Location, right.Location);
m_left = left;
m_right = right;
m_op = op;
}
#region Properties & Data
protected Exp m_left;
protected Exp m_right;
protected BinaryOp m_op;
public Exp Left
{
get { return m_left; }
}
public Exp Right
{
get { return m_right; }
}
public BinaryOp Op
{
get { return m_op; }
}
#endregion
#region Resolution
// Try and simplify
protected override Exp TrySimplify()
{
TrySimplify(ref m_left);
TrySimplify(ref m_right);
IntExp i1 = Left as IntExp;
IntExp i2 = Right as IntExp;
if (i1 != null && i2 != null)
{
int n1 = i1.Value;
int n2 = i2.Value;
switch(Op)
{
case BinaryOp.cAdd:
return new IntExp(n1 + n2, Location);
}
}
// Can't simplify
return this;
}
// Nothing to resolve for literal expressions
protected override Exp ResolveExpAsRight(ISemanticResolver s)
{
// Always resolve our children
ResolveExpAsRight(ref m_left, s);
ResolveExpAsRight(ref m_right, s);
// If we don't match a predefined operator, then check for overloads
if (!MatchesPredefinedOp(Op, this.Left.CLRType, this.Right.CLRType))
{
// Packagage Left & Right into parameters for a method call
ArgExp [] args = new ArgExp [2] {
new ArgExp(EArgFlow.cIn, m_left),
new ArgExp(EArgFlow.cIn, m_right)
};
// Check for delegate combination
// D operator+(D, D)
// D operator-(D, D)
if (AST.DelegateDecl.IsDelegate(m_left.CLRType))
{
if (m_left.CLRType == m_right.CLRType)
{
if (Op == BinaryOp.cAdd || Op == BinaryOp.cSub)
{
System.Type d = m_left.CLRType;
// Translates to:
// op+ --> (D) System.Delegate.Combine(left, right)
// op- --> (D) System.Delegate.Remove(left, right)
TypeEntry tDelegate = s.LookupSystemType("MulticastDelegate");
string stName = (Op == BinaryOp.cAdd) ? "Combine" : "Remove";
bool dummy;
MethodExpEntry sym = tDelegate.LookupMethod(s, new Identifier(stName),
new Type[] { d, d}, out dummy);
Exp call2 = new CastObjExp(
new ResolvedTypeSig(d, s),
new MethodCallExp(
null,sym, args, s)
);
Exp.ResolveExpAsRight(ref call2, s);
return call2;
}
}
} // end delgate op+ check
// Check for System.String.Concat().
// @todo - this should be able to compress an entire subtree, not just 2 args.
// (ie, a+b+c -> String.Concat(a,b,c);
// So we can't merge this into the SearchForOverload.
// But for now we'll be lazy...
if ((Op == BinaryOp.cAdd) && (Left.CLRType == typeof(string) || Right.CLRType == typeof(string)))
{
Exp call2 = new MethodCallExp(
new DotObjExp(
new SimpleObjExp(
new Identifier("System", this.m_filerange)
),
new Identifier("String", this.m_filerange)),
new Identifier("Concat", m_filerange),
args);
call2.SetLocation(this.Location);
Exp.ResolveExpAsRight(ref call2, s);
return call2;
}
MethodExpEntry m = SearchForOverloadedOp(s);
if (m == null && (Op == BinaryOp.cEqu || Op == BinaryOp.cNeq))
{
// If it's '==' or '!=', then it's ok if we didn't find
// an overload.
} else
{
// Couldn't find an overload, throw error
if (m == null)
{
//ThrowError_NoAcceptableOperator(s, this.Location, m_left.CLRType, m_right.CLRType, Op);
ThrowError(SymbolError.NoAcceptableOperator(this.Location, m_left.CLRType, m_right.CLRType, Op));
}
// Replace this node w/ the method call
MethodCallExp call = new MethodCallExp(null, m, args, s);
call.SetLocation(this.Location);
return call;
}
}
CalcCLRType(s);
return this;
}
// Search for an overloaded operator. Return the symbol for the method if found.
// Return null if not found.
MethodExpEntry SearchForOverloadedOp(ISemanticResolver s)
{
Type [] alParams = new Type[2];
alParams[0] = m_left.CLRType;
alParams[1] = m_right.CLRType;
string stName = MethodDecl.GetOpOverloadedName(this.Op);
MethodExpEntry sym;
if (m_left.CLRType != null)
{
TypeEntry t1 = s.ResolveCLRTypeToBlueType(m_left.CLRType);
sym = t1.LookupOverloadedOperator(s, stName, alParams);
if (sym != null)
return sym;
}
if (m_right.CLRType != null)
{
TypeEntry t2 = s.ResolveCLRTypeToBlueType(m_right.CLRType);
sym = t2.LookupOverloadedOperator(s, stName, alParams);
if (sym != null)
return sym;
}
return null;
}
// Helpers for detecting if we match predefined ops
// Return true if we're any integral type, else false.
static public bool IsNumber(System.Type t)
{
return t == typeof(int) || t == typeof(char);
}
static public bool IsBool(System.Type t)
{
return t == typeof(bool);
}
static public bool IsInteger(System.Type t)
{
return t == typeof(int) || t == typeof(char);
}
static public bool IsEnum(System.Type t)
{
return (t != null) && t.IsEnum;
}
// Return true if our param types let us match a predefined operator.
// Else return false (which implies that we must match against an
// overloaded operator)
// @todo - combine w/ CalcCLRTypeHelper()
static public bool MatchesPredefinedOp(BinaryOp op, Type clrLeft, Type clrRight)
{
// For arithmetic ops, only predefined if both args are numbers
if (op == BinaryOp.cAdd || op == BinaryOp.cMul || op == BinaryOp.cSub ||
op == BinaryOp.cDiv || op == BinaryOp.cMod ||
op == BinaryOp.cShiftLeft || op == BinaryOp.cShiftRight)
{
return IsNumber(clrLeft) && IsNumber(clrRight);
}
if (op == BinaryOp.cEqu || op == BinaryOp.cNeq)
{
if (IsNumber(clrLeft) && IsNumber(clrRight))
return true;
if (IsBool(clrLeft) && IsBool(clrRight))
return true;
if (IsEnum(clrLeft) && IsEnum(clrRight))
return true;
return false;
}
// Bitwise operators work on either bool or integers
if (op == BinaryOp.cBitwiseAnd || op == BinaryOp.cBitwiseOr || op == BinaryOp.cBitwiseXor)
{
if (IsInteger(clrLeft) && IsInteger(clrRight))
return true;
if (IsBool(clrLeft) && IsBool(clrRight))
return true;
if (IsEnum(clrLeft) && IsEnum(clrRight)) // @todo -only if flags attribute specified
return true;
return false;
}
// Relational ops only work on ints
if (op == BinaryOp.cLT || op == BinaryOp.cGT ||
op == BinaryOp.cLE || op == BinaryOp.cGE)
{
if (IsNumber(clrLeft) && IsNumber(clrRight))
return true;
if (IsEnum(clrLeft) && IsEnum(clrRight))
return true;
}
// These ops can't be overloaded, so they had better
// match a default type
if (op == BinaryOp.cAnd || op == BinaryOp.cOr)
{
return true;
}
return false;
}
// Determine the CLR type of this expression
// If we're a predefined op, then this is given by the C# spec.
// If we're an overloaded op, then this is the return type of the method
// that we resolve to.
protected override Type CalcCLRTypeHelper(ISemanticResolver s)
{
switch(this.Op)
{
// Special case for string.concat
case BinaryOp.cAdd:
if (Left.CLRType == typeof(string) || Right.CLRType == typeof(string))
return typeof(string);
return typeof(int);
case BinaryOp.cSub: return typeof(int);
case BinaryOp.cMul: return typeof(int);
case BinaryOp.cDiv: return typeof(int);
case BinaryOp.cMod: return typeof(int);
case BinaryOp.cAnd: return typeof(bool);
case BinaryOp.cOr: return typeof(bool);
case BinaryOp.cEqu: return typeof(bool);
case BinaryOp.cNeq: return typeof(bool);
case BinaryOp.cLT: return typeof(bool);
case BinaryOp.cGT: return typeof(bool);
case BinaryOp.cLE: return typeof(bool);
case BinaryOp.cGE: return typeof(bool);
case BinaryOp.cBitwiseAnd: return Left.CLRType;
case BinaryOp.cBitwiseOr: return Left.CLRType;
case BinaryOp.cBitwiseXor: return Left.CLRType;
case BinaryOp.cShiftLeft: return Left.CLRType;
case BinaryOp.cShiftRight: return Left.CLRType;
}
Debug.Assert(false, "Unknown binary op:"+this.Op.ToString());
return null;
}
#endregion
// Code generation
public override void GenerateAsRight(CodeGen.EmitCodeGen gen)
{
gen.Generate(this);
}
#region Checks
//-----------------------------------------------------------------------------
// Debugging check
//-----------------------------------------------------------------------------
public override void DebugCheck(ISemanticResolver s)
{
Debug.Assert(m_left != null);
Debug.Assert(m_right != null);
CalcCLRType(s);
m_left.DebugCheck(s);
m_right.DebugCheck(s);
}
// Dump as XML
public override void Dump(XmlWriter o)
{
o.WriteStartElement("BinaryExp");
o.WriteAttributeString("op", m_op.ToString());
m_left.Dump(o);
m_right.Dump(o);
o.WriteEndElement();
}
public override void ToSource(System.CodeDom.Compiler.IndentedTextWriter sb)
{
sb.Write('(');
m_left.ToSource(sb);
sb.Write(OpName(this.m_op));
m_right.ToSource(sb);
sb.Write(')');
}
#endregion
}
//-----------------------------------------------------------------------------
// Unary operations
//-----------------------------------------------------------------------------
public class UnaryExp : Exp
{
public enum UnaryOp
{
cNegate,
cNot,
cPreInc,
cPostInc,
cPreDec,
cPostDec
}
public UnaryExp(Exp left, UnaryOp op)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -