📄 expast.cs
字号:
//-----------------------------------------------------------------------------
// File: ExpAST.cs
//
// Description: All Expression nodes in the AST
// See AST.cs for details
//-----------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Xml;
using SymbolEngine;
using Blue.Public;
using CodeGen = Blue.CodeGen;
namespace AST
{
#region Exp base class
//-----------------------------------------------------------------------------
// General expression
//-----------------------------------------------------------------------------
/// <summary>
/// Abstract base class for all expressions.
/// </summary>
/// <remarks>
/// <para>Provides virtual functions for Resolving as a left or right hand side expressions.
/// All expressions have an associated System.Type (the <see cref="Exp.CLRType"/> property).</para>
/// <para>When an expression is resolved, it can mutate itself into a new expression.The
/// <see cref="Exp.ResolveExpAsLeft"/> and <see cref="Exp.ResolveExpAsRight"/> instance members
/// return a exp. If the expression was not mutated, they return the 'this' pointer. If a mutation
/// does occur, they could return a totally new, resolved, exp node. This is useful for code
/// transforms. (ex: constant-folding).</para>
/// </remarks>
public abstract class Exp : Node
{
//.........................................................................
// Semantic resolution. Resolve the exp as either a LHS or RHS value.
//.........................................................................
// Resolve the expression as a LHS value
public static void ResolveExpAsLeft(ref Exp e, ISemanticResolver s)
{
e = e.ResolveExpAsLeft(s);
Debug.Assert(e != null);
}
protected virtual Exp ResolveExpAsLeft(ISemanticResolver s)
{
// Default impl - most expressions aren't valid on the LHS.
//s.ThrowError_NotValidLHS(this.Location);
ThrowError(SymbolError.NotValidLHS(this.Location));
return null;
}
// Resolve expression as a RHS value. The exp node can totally change on us
// (operator overloading, constant folding, etc), so we must pass as a ref
public static void ResolveExpAsRight(ref Exp e, ISemanticResolver s)
{
// Debugging helper. Useful when we want to break when resolving
// a particular symbol.
#if false
// Set lTarget to a symbol that we want to see resolved.
FileRange lTarget = new FileRange("SemanticChecker.cs", 143, 39, 143, 43);
if (lTarget.Equals(e.Location))
{
System.Diagnostics.Debugger.Break();
}
#endif
e = e.ResolveExpAsRight(s);
Debug.Assert(e != null);
}
// Helper to resolve the expression as RHS value.
// Return the newly-resolved exp node. In most cases, that will just be
// the old node, but in a resolved state. For things like operator overloading,
// it will be a totally different node.
// Note that we must expose this version because 'ref Exp' is not assignable
// with any derived expression.
protected abstract Exp ResolveExpAsRight(ISemanticResolver s);
//.........................................................................
// Code generation
// To codegen something like: 'a=b', we need to be able to do:
// [a]lhs_pre // emit code to load context for the assignment
// [b]rhs // emit code to load value to be assigned
// [a]lhs_post // emit code to actually store the results
//
// Most expressions will only need a rhs.
//.........................................................................
public virtual void GenerateAsLeftPre(CodeGen.EmitCodeGen gen)
{
Debug.Assert(false, "Didn't implement GenerateAsLeftPre");
}
public virtual void GenerateAsRight(CodeGen.EmitCodeGen gen)
{
Debug.Assert(false, "Didn't implement GenerateAsRight");
}
public virtual void GenerateAsLeftPost(CodeGen.EmitCodeGen gen)
{
Debug.Assert(false, "Didn't implement GenerateAsLeftPost");
}
//.........................................................................
// Code Generation - Generate the address of this expression
//.........................................................................
public virtual void GenerateAddrOf(CodeGen.EmitCodeGen gen)
{
// Can't get the addr of most expressions
//Debug.Assert(false, "Didn't implemented GenerateAddrOf");
// Default impl, evaluate as RHS, store in temp, gen addr of that.
gen.GenerateAddrOf(this);
}
// @todo - not really working yet. We don't do constant folding.
//.........................................................................
// Simplifying an expression that we pass in. Pass out the simplified
// expression (or the same thing we passed in if we can't simplify)
//.........................................................................
public static void TrySimplify(ref Exp e)
{
e = e.TrySimplify();
}
// @todo - not really working yet.
// Actual workhorse, Default behavior, can't simplify, so return the original
protected virtual Exp TrySimplify()
{
return this;
}
// Return true iff the given expression is allowed to have a null type
public static bool CanBeNullType(Exp e)
{
return (e is NullExp) || (e is IfExp) || (e is ArgExp) || (e is NamespaceExp);
}
// Determine the CLR Type of this expression
// As a convenience, return the clr type to saves us from having to
// call CLRType
public System.Type CalcCLRType(ISemanticResolver s)
{
Type tOld = m_clrType;
m_clrType = CalcCLRTypeHelper(s);
Debug.Assert(m_clrType != null || Exp.CanBeNullType(this));
// Assert that if we called this multiple times, the value hasn't changed on us
Debug.Assert(((tOld == null)) || (tOld == m_clrType));
// @todo - we don't resolve pointers yet....
// The only place we can use them is in evaluating a MethodPtr for a delegate ctor.
if (m_clrType == Type.GetType("System.IntPtr"))
{
Debug.Assert(this is MethodPtrExp);
return m_clrType;
}
// @todo - move this into a place w/ better perf...
// EnsureResolved
if (m_clrType != null)
{
TypeEntry t = s.ResolveCLRTypeToBlueType(m_clrType);
t.EnsureResolved(s);
}
return m_clrType;
}
// This gets called by CalcCLRType()
// Derived classes override this and return the clr type
protected virtual Type CalcCLRTypeHelper(ISemanticResolver s)
{
// This should be implemented
Debug.Assert(false, "@todo - impl");
return null;
}
public System.Type CLRType
{
get { return m_clrType; }
}
private System.Type m_clrType;
}
#endregion
//-----------------------------------------------------------------------------
// Expression to represent an argument to a method call
//-----------------------------------------------------------------------------
/// <summary>
/// Node for an argument in a method call
/// </summary>
/// <remarks>
/// An ArgExp represents each argument in a <see cref="MethodCallExp"/>.
/// <para><children>Children:<list type="bullet">
/// <item><see cref="EArgFlow"/> - specify if this is an 'in', 'out', or 'ref' parameter.</item>
/// <item><see cref="Exp"/> - specify the expression for this parameter</item>
/// </list></children></para>
/// </remarks>
public class ArgExp : Exp
{
public ArgExp(AST.EArgFlow eFlow, Exp exp)
{
Debug.Assert(exp != null);
Debug.Assert(!(exp is ArgExp), "ArgExp should never wrap an ArgExp");
m_exp = exp;
m_eFlow = eFlow;
}
#region Checks
public override void DebugCheck(ISemanticResolver s)
{
m_exp.DebugCheck(s);
}
// Dump as XML
public override void Dump(XmlWriter o)
{
o.WriteStartElement("ArgExp");
o.WriteAttributeString("flow", m_eFlow.ToString());
m_exp.Dump(o);
o.WriteEndElement();
}
public override void ToSource(System.CodeDom.Compiler.IndentedTextWriter sb)
{
sb.Write("<{0}>", this.m_eFlow.ToString());
this.m_exp.ToSource(sb);
}
#endregion
#region Properties & Data
EArgFlow m_eFlow;
public EArgFlow Flow
{
get { return m_eFlow; }
}
Exp m_exp;
public Exp InnerExp
{
get { return m_exp; }
}
#endregion
#region Resolution
protected override Type CalcCLRTypeHelper(ISemanticResolver s)
{
// Get the type of our inner
Type t = m_exp.CalcCLRType(s);
// If we've already got a reference, then we're ok.
// Also ok if we're null (since literals can't be passed as a ref/out)
if ((t == null) || (t.IsByRef))
return t;
// Ref & Out params are actually type 'T&', not 'T'
if (Flow == EArgFlow.cRef || Flow == EArgFlow.cOut)
{
t = s.GetRefToType(t);
}
return t;
}
// Resolve the expression as a LHS value
protected override Exp ResolveExpAsLeft(ISemanticResolver s)
{
Debug.Assert(m_eFlow == EArgFlow.cOut | m_eFlow == EArgFlow.cRef);
ResolveExpAsLeft(ref m_exp, s);
CalcCLRType(s);
return this;
}
// Resolve the expression as RHS value.
protected override Exp ResolveExpAsRight(ISemanticResolver s)
{
//Debug.Assert(m_eFlow == EArgFlow.cIn | m_eFlow == EArgFlow.cRef);
Exp.ResolveExpAsRight(ref m_exp, s);
CalcCLRType(s);
return this;
}
#endregion
public override void GenerateAsRight(CodeGen.EmitCodeGen gen)
{
/*
if (Flow == EArgFlow.cIn)
m_exp.GenerateAsRight(gen);
else
m_exp.GenerateAddrOf(gen);
*/
gen.GenerateArg(this);
}
}
//-----------------------------------------------------------------------------
// Expression that represents a type
// Should only be used as an intermediate node.
//-----------------------------------------------------------------------------
public class TempTypeExp : Exp
{
public TempTypeExp(TypeSig t)
{
m_tSig = t;
}
TypeSig m_tSig;
public TypeSig TypeSigRec
{
get { return m_tSig; }
}
#region Checks
public override void DebugCheck(ISemanticResolver s)
{
Debug.Assert(false);
}
// Dump as XML
public override void Dump(XmlWriter o)
{
Debug.Assert(false);
}
public override void ToSource(System.CodeDom.Compiler.IndentedTextWriter sb)
{
sb.Write("<T>{0}", this.m_tSig.ToString());
}
#endregion
#region Resolution
// Semantic resolution
protected override Exp ResolveExpAsRight(ISemanticResolver s)
{
Debug.Assert(false);
return null;
}
// Code generation
public override void GenerateAsRight(CodeGen.EmitCodeGen gen)
{
Debug.Assert(false);
}
protected override Type CalcCLRTypeHelper(ISemanticResolver s)
{
Debug.Assert(false);
return null;
}
#endregion
} // end TypeExp
#region Statement Expressions
/// <summary>
/// Abstract base class for expression that have sideeffects and can be used as statements.
/// </summary>
/// <remarks>
/// <para>Some expressions, like assignment, methodcalls, and the ++,-- operators
/// have sideeffects and so they can be used as a statement.</para>
/// <para>A StatementExp can be used directly as an expression, or it can be held in a
/// <see cref="ExpStatement"/> to be used as a statement.</para>
/// </remarks>
public abstract class StatementExp : Exp
{
// Statement expressions can be generated as a statement or expression.
// As an expression, they must leave a value on the top of the stack
// As a statement, they don't leave a value on top (and hence may
// be able to have a more efficient impl).
// Normal Generate() will generate as a RHS expression.
public virtual void GenerateAsStatement(CodeGen.EmitCodeGen gen)
{
// Default impl generates as a RHS exp and just pops the value off
gen.GenerateAsStatement(this);
}
// Allow safe resolving on Statement Exp. Allowed to change to another StmtExp
public static void ResolveExpAsRight(ref StatementExp se, ISemanticResolver s)
{
Exp e = se;
Exp.ResolveExpAsRight(ref e, s);
if (e is StatementExp)
se = (StatementExp) e;
else
Debug.Assert(false, "Shouldn't have resolved to a non-stmtexp");
Debug.Assert(se != null);
}
}
#if true
//-----------------------------------------------------------------------------
// Declares a temporary local var
// We must execute this as a statement to actually create the local,
// And then we can use the GetLocal() to get a LocalExp to refer to the temp.
//-----------------------------------------------------------------------------
public class DeclareLocalStmtExp : StatementExp
{
public DeclareLocalStmtExp(System.Type t, ISemanticResolver s)
: this(s.ResolveCLRTypeToBlueType(t))
{
}
public DeclareLocalStmtExp(TypeEntry t)
{
LocalVarExpEntry l = new LocalVarExpEntry();
l.m_strName = ".temp_local_" + m_count;
m_count++;
l.m_type = t;
m_exp = new LocalExp(l);
}
#region Properties & Data
LocalExp m_exp;
public LocalExp GetLocal()
{
return m_exp;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -