📄 ast.cs
字号:
//-----------------------------------------------------------------------------
// File: AST.cs
// The abstract syntax tree
//
// All AST nodes derive from class Node for utility purposes (dumping,
// source file mapping, etc).
//-----------------------------------------------------------------------------
#region Comment on AST node hierarchy
//-----------------------------------------------------------------------------
// Nodes fall into 3 categories:
// 1) Decl - declare something
// 2) Statement - statements in program
// 3) Exp - part of an expression
//
// Each node may reference its corresponding derived class from SymEntry
// The AST is pure and does not contain any resolved information besides
// the symbol table entry. All resolved data is stored on the symbol entry.
// The parser creates the AST with strings for the identifiers.
// Then the semantic checking populates the SymbolTable and does a lookup
// on the string name and sets the SymEntry fields.
//
// The node organization is:
// + Node - root class
// + ProgramDecl - declare a program
// + NamespaceDecl - declare a namespace
// + ClassDecl - declare a class
// + MemberDecl - member within a class
// + MethodDecl
// + FieldDecl
// + VarDecl
// + LocalVarDecl - declare a local variable
// + ParamVarDecl - declare a parameter
// + PropertyDecl
//
// + Statement
// + ReturnStatement
// + AssignStatement
// + IfStatement
// + LoopStatement
// + WhileStatement
// + DoStatement
//
// + Exp - nodes that form expressions
// + LiteralExp
// + IntExp
// + BoolExp
// + StringExp
// + CharExp
// + DoubleExp
// + BinaryExp
// + UnaryExp
// + ObjExp
// + SimpleObjExp - apply single identifier to ObjExp
// + DotObjExp - single identifier
// + MethodCallExp - evaluates to a method call
// + NewObjExp - create new objects
// + CastObjExp - cast an expression into an object
//
// + TypeSig - store a type
//-----------------------------------------------------------------------------
#endregion
using System;
using System.Collections;
using System.Diagnostics;
using System.Xml;
using SymbolEngine;
using Blue.Public;
//-----------------------------------------------------------------------------
/// <summary>
/// <c>Identifier</c> is a helper class to associate a string with a <c>FileRange</c>.
/// All AST references to a string-data should refer to an Identifier.
/// </summary>
//-----------------------------------------------------------------------------
public class Identifier
{
public Identifier(string stText)
: this(stText, null)
{ }
public Identifier(string stText, FileRange location)
{
m_stText = stText;
m_filerange = location;
}
protected string m_stText;
protected FileRange m_filerange;
public string Text
{
get { return m_stText; }
}
public FileRange Location
{
get { return m_filerange; }
}
}
//-----------------------------------------------------------------------------
// The Abstract Syntax Tree
//-----------------------------------------------------------------------------
namespace AST
{
#region Node, the base class for all AST nodes
//-----------------------------------------------------------------------------
// Base AST node serves for utility purposes
//-----------------------------------------------------------------------------
/// <summary>
/// <c>Node</c> is the base class for all nodes in the Abstract Syntax tree.
/// </summary>
/// <remarks>
/// <list type="bullet">
/// <item>It is associated with a <c>FileRange</c> object to guarantee that all nodes
/// can provide line number information. </item>
/// <item>It also provides some standard utility functions to serialize a subtree to
/// XML or strings.</item>
/// </list>
/// Nodes are split into the following major categories:
/// Declarations, Members, Statements, Expressions
/// </remarks>
public abstract class Node
{
#region Checks
// Utility to Dump to XML file
public static void DumpTree(Node root, XmlWriter o)
{
o.WriteStartDocument();
o.WriteStartElement("AST");
root.Dump(o);
o.WriteEndElement(); // AST
o.WriteEndDocument();
o.Close();
}
// Dump as xml. XmlWriter must be opended & document must be started
// Will not close document.
public abstract void Dump(XmlWriter o);
// Debugging function only:
// Debugging check to be done _after_ symbol resolution
// That way, we have a symbol table that we can verify everything against.
// Assert everything that we can possibly think of so that CodeGen
// has a well-resolved tree.
// If any of the asserts do fire, that means symbolic resolution is
// making a mistake and should be fixed.
public abstract void DebugCheck(ISemanticResolver s);
// These flags are used during the DebugCheck() to allow features
// that haven't been implemented to pass.
// remove these flags (set to false) as more stuff gets resolved
public readonly static bool m_DbgAllowNoCLRType = false;
// Debugging facility. Dump() spits out XML which can be really tough to read,
// and it's not clear what it should include.
// So we have a facility to spit it out as a string.
static string GetAsSourceString(Node n)
{
//System.Text.StringBuilder sb = new System.Text.StringBuilder();
//n.ToSource(sb);
//return sb.ToString();
return "empty";
}
public static void DumpSourceToStream(Node n, System.IO.TextWriter t)
{
Console.WriteLine("*** Begin Source dump: [");
System.CodeDom.Compiler.IndentedTextWriter i = new
System.CodeDom.Compiler.IndentedTextWriter(t, " ");
n.ToSource(i);
Console.WriteLine("] *** End source dump");
i.Close();
i = null;
}
// Dump the string to the console.
public static void DumpSource(Node n)
{
DumpSourceToStream(n, Console.Out);
}
// This should look like source but inject a few extra characters
// to make it clear how it was resolved.
public virtual void ToSource(System.CodeDom.Compiler.IndentedTextWriter sb)
{
//sb.Append("['" + this.GetType().ToString() + "' not implemented]");
sb.Write("['{0}' not implemented]", this.GetType().ToString());
}
#endregion
#region Linenumber info
// Line information.
protected FileRange m_filerange;
public FileRange Location
{
get { return m_filerange; }
}
// Parser has to be able to set the line number information.
public void SetLocation(FileRange l)
{
m_filerange = l;
}
#endregion Linenumber info
// Shortcut helper functions.
static public void PrintError(SymbolError.SymbolErrorException e)
{
Blue.Driver.StdErrorLog.PrintError(e);
}
static public void ThrowError(SymbolError.SymbolErrorException e)
{
Blue.Driver.StdErrorLog.ThrowError(e);
}
}
#endregion
#region Node for a Compilation-Unit
//-----------------------------------------------------------------------------
// Top level program
//-----------------------------------------------------------------------------
/// <summary>
/// The root AST node for an entire multi-file program.
/// </summary>
/// <remarks>
/// A ProgramDecl node contains all global namespace decls.
/// </remarks>
public class ProgramDecl : Node
{
#region Construction
public ProgramDecl(NamespaceDecl [] nGlobal)
{
Debug.Assert(nGlobal != null);
m_nGlobal = nGlobal;
}
#endregion
#region Checks
public override void Dump(XmlWriter o)
{
o.WriteStartElement("Program");
foreach(NamespaceDecl n in m_nGlobal)
n.Dump(o);
o.WriteEndElement();
}
// Debugging check
public override void DebugCheck(ISemanticResolver s)
{
foreach(NamespaceDecl n in m_nGlobal)
n.DebugCheck(s);
}
#endregion
#region Properties & Data
// Source file has a single implicity global namespace
NamespaceDecl [] m_nGlobal;
public NamespaceDecl [] GlobalNamespaces
{
get { return m_nGlobal; }
}
// List of classes, created by flattening all classes in
// all the namespaces.
TypeDeclBase[] m_arClasses;
public TypeDeclBase[] Classes
{
get {
return m_arClasses;
}
}
#endregion
#region Other Functions
// Get a flat array of classes from the namespaces
// The array is topologically sorted such that:
// if (i < j) then T[i] does not depend on T[j]
protected void CreateClassListFromNamespaces()
{
Debug.Assert(m_arClasses == null);
ArrayList a = new ArrayList();
foreach(NamespaceDecl n in m_nGlobal)
n.ReportClasses(a);
m_arClasses = new TypeDeclBase[a.Count];
for(int i = 0; i < a.Count; i++)
m_arClasses[i] = (TypeDeclBase) a[i];
}
#endregion
#region Resolution
public void ResolveNamespace(ISemanticResolver s, Scope scopeGlobal)
{
// First must do namespaces so that type stubs even
// have a context.
foreach(NamespaceDecl n in m_nGlobal)
n.ResolveNamespace("", s, scopeGlobal);
// Next, resolve type stubs so that using alias at least
// has stub types to refer to
ResolveTypeStubs(s);
// Now resolve Using decls. Have to do this before we
// try and use any types (since using decls will affect resolution)
foreach(NamespaceDecl n in m_nGlobal)
n.ResolveUsingDecls(s);
}
public void NotifyResolutionDone()
{
// Can't create the single class list until after
// all symbols have been resolved
CreateClassListFromNamespaces();
}
// Add stubs for all user types.
public void ResolveTypeStubs(ISemanticResolver s)
{
foreach(NamespaceDecl n in m_nGlobal)
n.ResolveTypesAsBlueStub(s);
}
// Resolve the types
public void ResolveTypes(
ISemanticResolver s,
ICLRtypeProvider provider)
{
// Then go through and resolve them to CLR types.
foreach(NamespaceDecl n in m_nGlobal)
n.ResolveTypesAsCLR(s, provider);
}
// Resolve the member declarations within a class.
// Since these can refer to other classes, we must have
// resolved all types before resolving any members
public void ResolveMemberDecls(
ISemanticResolver s,
ICLRtypeProvider provider
)
{
foreach(NamespaceDecl n in m_nGlobal)
n.ResolveMemberDecls(s, provider);
}
// Resolve the bodies of methods
public void ResolveBodies(ISemanticResolver s)
{
foreach(NamespaceDecl n in m_nGlobal)
n.ResolveBodies(s);
}
#endregion
} // end class Program
#endregion
#region AST Nodes that go in a Namespace Decl
//-----------------------------------------------------------------------------
// Using directive
//-----------------------------------------------------------------------------
public class UsingDirective : Node
{
#region Construction
// For alias
public UsingDirective(string stAlias, Exp eNamespace)
{
Debug.Assert(stAlias != null);
Debug.Assert(eNamespace != null);
m_stAlias = stAlias;
m_eNamespace = eNamespace;
}
// For search path
public UsingDirective(Exp eNamespace)
{
Debug.Assert(eNamespace != null);
m_stAlias = null;
m_eNamespace = eNamespace;
}
#endregion
#region Properties & Data
// We have 2 types of using directives: Alias & Search.
public bool IsAliasType
{
get { return m_stAlias != null; }
}
string m_stAlias;
Exp m_eNamespace;
#endregion
#region Resolution
// Lookup the symbol in this Using Alias/Directive.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -