📄 csharpast.cs
字号:
using System;
using System.IO;
using System.Text;
using System.Collections;
using System.CodeDom;
using System.Globalization;
using antlr;
using antlr.collections;
using Dom = DDW.CSharp.Dom;
using DDW.CSharp.SymbolTable;
namespace DDW.CSharp.Parse
{
#region CSharpAST
/// <summary>
/// The base class for all custom ASTs.
/// </summary>
public class CSharpAST : antlr.BaseAST // was abstract
{
private int ttype = Token.INVALID_TYPE;
protected string p_text;
protected bool isDirty = true;
protected Dom.TypeDecl curType;
//public static int CurLine = 0;
//public static int CurCol = 0;
#region Constructor
public CSharpAST()
{
//Console.WriteLine("tok: "+this.GetType()+" ln# " + LinePragma.Line);
}
/// <summary>
/// Construct blank AST node using a token
/// </summary>
public CSharpAST(Token tok)
{
Console.WriteLine("has tok: "+this.GetType());
initialize(tok);
}
#endregion
#region UserData
/// <summary>
/// Gets or sets the user-definable data for the current object.
/// </summary>
public virtual IDictionary UserData
{
get{ return null; }
set{ }
}
#endregion
#region FileName
private string p_filename = "";
public string FileName
{
get{return p_filename;}
set{p_filename = value;}
}
#endregion
#region Text
/// <summary>
/// Gets or sets the text of the node.
/// </summary>
// public override string Text
// {
// get{return p_text;}
// set{p_text = value;}
// }
#endregion
#region Type
/// <summary>
/// Gets or sets the Type of the node (TODO: make this enum)
/// </summary>
public override int Type
{
get{return ttype;}
set{ttype = value;}
}
#endregion
#region LinePragma
private Dom.LinePragma p_linePragma = new Dom.LinePragma();
public Dom.LinePragma LinePragma
{
get
{
return p_linePragma;
}
set
{
p_linePragma = value;
}
}
#endregion
// was abstract
public virtual Dom.IGraph GetGraph(){ return null;}
public virtual Dom.IGraph GetGraph(Dom.IGraph graph)
{
//graph.LinePragma = this.LinePragma;
return graph;
}
#region ToString
public override String ToString()
{
return p_text +" (" + this.GetType().Name+")";
}
#endregion
#region Various Java methods
public override void initialize(int t, String txt)
{
setType(t);
setText(txt);
//LinePragma.Line = CurLine;
//LinePragma.Column = CurCol;
}
public override void initialize(AST t)
{
p_text = t.getText();
Type = t.Type;
// if(t is CSharpAST)
// {
// LinePragma.Line = CurLine;
// LinePragma.Column = CurCol;
// }
}
public override void initialize(Token tok)
{
p_text = tok.getText();
Type = tok.Type;
// LinePragma.Line = tok.getLine();
// LinePragma.Column = CurCol;
}
public override String getText()
{
return p_text;
}
public int getType()
{
return ttype;
}
public override void setText(String text_)
{
p_text = text_;
}
public override void setType(int ttype_)
{
ttype = ttype_;
}
#endregion
#region ScopeTable
private static Dom.CompileUnit currentCompileUnit;
public static ScopeCollection ScopeTable
{
get
{
return currentCompileUnit.ScopeTable;
}
}
#endregion
#region CurrentScope
private static Scope p_currentScope;
public static Scope CurrentScope
{
get
{
return p_currentScope;
}
set
{
p_currentScope = value;
}
}
#endregion
#region GlobalScope
private static AssemblyScope p_globalScope;
public static AssemblyScope GlobalScope
{
get
{
return p_globalScope;
}
set
{
p_globalScope = value;
}
}
#endregion
#region SymbolTable
private static DefinitionCollection p_symtab = new DefinitionCollection();
/// <summary>
/// Stores un-attributed symbols until all types/vars are declared.
/// </summary>
public static DefinitionCollection SymbolTable
{
get
{
return p_symtab;
}
}
#endregion
#region AddSymbol(Dom.ISymbol)
/// <summary>
/// Symbols are variables that refer to types, or type refs themselves.
/// </summary>
public void AddSymbol(Dom.ISymbolRef sgraph, string name)
{
IDefinition d = sgraph.Definition;
if(d == null)
{
d = new Definition();
sgraph.Definition = d;
d.Id = defCount++;
}
if(d.Scope == null) d.Scope = CSharpAST.CurrentScope;
d.SourceGraph = sgraph;
d.Name = name;
CSharpAST.SymbolTable.Add(d);
}
#endregion
#region ResolveSymbols()
/// <summary>
/// Attributes all the stored symbols - only call once all definitions are parsed. This will clear the symbol table once its contents are attributed.
/// </summary>
public bool ResolveSymbols()
{
bool isValid = true;
foreach(Definition d in SymbolTable)
{
Scope defScope = d.Scope;
if(d.SourceGraph is Dom.IScope)
defScope = d.Scope.EnclosingScope;
if(d.SourceGraph is Dom.UnknownReference)
{
Definition resolved = defScope.Lookup(d.Name);
if(resolved != null)
{
//d.Scope = resolved.Scope;
Dom.UnknownReference ur = (Dom.UnknownReference)d.SourceGraph;
ur.Definition = resolved;
Console.WriteLine(resolved.FullName);
}
else
{
isValid = false;
Console.WriteLine(
d.SourceGraph.GraphType.ToString() +
" def **not** found: " + d.Name);
}
}
else if(d.SourceGraph is Dom.TypeRef)
{
Definition resolved = defScope.Lookup(d.Name);
if(resolved != null)
{
// rewrite the def to be the looked up def
Dom.TypeRef tr = (Dom.TypeRef)d.SourceGraph;
tr.Definition = resolved;
Console.WriteLine("TypeRef: " + resolved.FullName);
}
else
{
isValid = false;
Console.WriteLine(
d.SourceGraph.GraphType.ToString() +
" not found: " + d.Name);
}
}
else
{
isValid = false;
Console.WriteLine("*** " + d.Name +" - not resolved: " + d.SourceGraph.GraphType.ToString());
}
}
SymbolTable.Clear();
return isValid;
}
#endregion
#region AddRootExpression(Dom.Expression, Type, string)
private static ExpressionRootCollection rootExprs = new ExpressionRootCollection();
/// <summary>
/// Stores root expressions (right sides, args, etc) to make expr exprAttr quicker.
/// </summary>
public void AddRootExpression(Dom.Expression expr, Type t, string propName)
{
if(expr == null) return;
ExpressionRoot er = new ExpressionRoot();
er.Expression = expr;
er.Instance = t;
er.PropertyName = propName;
CSharpAST.rootExprs.Add(er);
}
#endregion
#region ResolveExpressions()
/// <summary>
/// Determines all the return types of expressions, needed for resolving overloads.
/// </summary>
public void ResolveExpressions()
{
Attribution.AttributeExpressions(CSharpAST.rootExprs);
}
#endregion
#region OpenBlockScope()
public Scope OpenBlockScope()
{
Scope sc = new BlockScope();
sc.EnclosingScope = CSharpAST.CurrentScope;
CSharpAST.ScopeTable.Add(sc);
CSharpAST.CurrentScope = sc;
return sc;
}
#endregion
#region OpenScope(IScope)
/// <summary>
/// Creates a new scope and sets it as the current scope. This will also add a definition to the parent scope if needed (in case of eg Class or Namespace, but not eg block or compile unit).
/// </summary>
/// <param name="graph">The current graph element.</param>
/// <returns>Returns a reference to the newly created scope.</returns>
public Scope OpenScope(Dom.IScope graph)
{
switch(graph.GraphType)
{
case Dom.GraphTypes.CompileUnit :
{
// set scope table to current assembly's scope
currentCompileUnit = (Dom.CompileUnit)graph;
// add a new Assembly scope to it
GlobalScope = new AssemblyScope();
graph.Scope = GlobalScope;
break;
}
case Dom.GraphTypes.NamespaceDecl :
{
graph.Scope = new NamespaceScope();
break;
}
case Dom.GraphTypes.ClassDecl :
case Dom.GraphTypes.InterfaceDecl :
case Dom.GraphTypes.StructDecl :
case Dom.GraphTypes.EnumDecl :
{
graph.Scope = new TypeScope();
break;
}
case Dom.GraphTypes.MethodDecl :
case Dom.GraphTypes.IndexerDecl :
case Dom.GraphTypes.OperatorDecl :
case Dom.GraphTypes.ConstructorDecl :
case Dom.GraphTypes.DestructorDecl :
case Dom.GraphTypes.AccessorDecl :
{
graph.Scope = new MemberScope();
break;
}
default :
{
throw(new Exception("uncaught scope type"));
break;
}
}
// set parent and (parent's) child refs
graph.Scope.EnclosingScope = CSharpAST.CurrentScope;
if(CSharpAST.CurrentScope != null)
{
CSharpAST.CurrentScope.ChildScopes.Add(graph.Scope);
}
// add defintion and link scope to its name, if needed
if(graph is Dom.IDeclaration)
{
((INamedScope)graph.Scope).Definition =
((Dom.IDeclaration)graph).Definition;
// only add def after name is known
// AddDefinition((Dom.IDeclaration)graph, );
}
// add to the main scope table storage area too
CSharpAST.ScopeTable.Add(graph.Scope);
// set this to be the current scope
CSharpAST.CurrentScope = graph.Scope;
return graph.Scope;
}
#endregion
public static int defCount = 1;
#region AddDefinition(IDeclaration)
public IDefinition AddDefinition(Dom.IDeclaration dgraph, string name, Dom.IDeclaration type)
{
dgraph.Definition.Scope = CSharpAST.CurrentScope;
dgraph.Definition.SourceGraph = dgraph;
dgraph.Definition.Name = name;
dgraph.Definition.Type = type;
dgraph.Definition.Id = defCount++;
// overloadable types are stored as a collection in one OverloadableDefinition
// that is always created here
if(dgraph is Dom.IOverloadable)
{
// enclosing scopes are never null for defs..
Definition d = CSharpAST.CurrentScope.Lookup(name);
// overloads are stored in a main 'overloadable' definition
// that contains a 'Definitions' collection of each overloaded def.
// FIX: it is possible that a variable and a method have the same name
// so we must make sure the looked up def is actaully for a variable
// * thank you Niklas Pettersson
bool dov = d is OverloadableDefinition;
if(d == null || !dov)
{
d = new OverloadableDefinition();
d.Name = name;
d.Scope = CSharpAST.CurrentScope;
d.SourceGraph = dgraph;
d.Id = defCount++;
d.Type = type;
CSharpAST.CurrentScope.EnclosingScope.Add(d, name);
}
// must always be overloadable def
((OverloadableDefinition)d).Definitions.Add(dgraph.Definition);
}
else if(dgraph is Dom.IScope)
{
// all other scopes should also be registered in the enclosing scope
CSharpAST.CurrentScope.EnclosingScope.Add(dgraph.Definition, name);
}
else
{
// and locals, agrs should be registered in the scope they are found in
CSharpAST.CurrentScope.Add(dgraph.Definition, name);
}
return dgraph.Definition;
}
#endregion
#region AddBuiltInDefinition(string)
public IDefinition AddBuiltInDefinition(string name)
{
BuiltInDefinition bid =
(BuiltInDefinition)GlobalScope.DefinitionTable[name];
if(bid == null)
{
// set the def now for built in types as it is a subclass of def
bid = new BuiltInDefinition();
bid.Name = name;
// set type now as that is what is different
// the rest will get attributed once added to symbol table
bid.Scope = GlobalScope;
bid.Id = CSharpAST.defCount++;
// must add this to defs if it isn't there already
// this allows us to keep track of which built in types were used
// always add built in to global scope
GlobalScope.DefinitionTable.Add(name, bid);
}
return bid;
}
#endregion
#region CloseScope()
public void CloseScope()
{
CSharpAST.CurrentScope = CSharpAST.CurrentScope.EnclosingScope;
}
#endregion
}
#endregion
#region CompileUnit
public class CompileUnit : CSharpAST
{
public override Dom.IGraph GetGraph()
{
Dom.CompileUnit graph =
new Dom.CompileUnit();
return this.GetGraph(graph);
}
public Dom.CompileUnit
GetGraph(Dom.CompileUnit graph)
{
base.GetGraph(graph);
this.OpenScope(graph);
Dom.NamespaceDecl dns = null;
graph.FileName = this.FileName;
AST tok = this.getFirstChild();
while(tok != null)
{
if(tok is NamespaceNode)
{
Dom.NamespaceDecl ns =
(Dom.NamespaceDecl)((NamespaceNode)tok).GetGraph();
graph.Namespaces.Add(ns);
}
else if(tok is CustomAttributes)
((CustomAttributes)tok).GetGraph(graph.AssemblyCustomAttributes);
else if(tok is UsingNode)
graph.Imports.Add( (Dom.Import)((UsingNode)tok).GetGraph() );
else //if(tok is Types || tok is QualIdent)
{
if(dns == null)
{
dns = new Dom.NamespaceDecl();
dns.Name = "DefaultNamespace";
graph.Namespaces.Add(dns);
}
Types.ParseTypesIntoNamespace(tok, dns);
}
tok = tok.getNextSibling();
}
this.CloseScope();
// do type attribution for declarations, localdecls and args
graph.IsAttributed = ResolveSymbols();
// do type attribution for expressions
if(graph.IsAttributed)
{
ResolveExpressions();
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -