📄 statementast.cs
字号:
//-----------------------------------------------------------------------------
// File: StatementAST.cs
//
// Description: All Statement nodes in the AST
// See AST.cs for details
//-----------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Xml;
using CodeGen = Blue.CodeGen;
using Utilities = Blue.Utilities;
using Blue.Public;
using SymbolEngine;
namespace AST
{
//-----------------------------------------------------------------------------
// Statement base class
//-----------------------------------------------------------------------------
/// <summary>
/// Abstract base class for all statements.
/// </summary>
public abstract class Statement : Node
{
// Semantic resolution
public abstract void ResolveStatement(ISemanticResolver s);
public virtual void ResolveStatement2(ISemanticResolver s) { }
// Code generation
public abstract void Generate(CodeGen.EmitCodeGen gen);
}
#region Empty Statement
//-----------------------------------------------------------------------------
// Empty statement
//-----------------------------------------------------------------------------
public class EmptyStatement : Statement
{
public EmptyStatement()
{
}
public override void ResolveStatement(ISemanticResolver s)
{
}
public override void Generate(CodeGen.EmitCodeGen gen)
{
// @todo - should we emit a nop?
}
#region Checks
public override void ToSource(System.CodeDom.Compiler.IndentedTextWriter sb)
{
sb.WriteLine("; // empty");
}
public override void Dump(XmlWriter o)
{
}
public override void DebugCheck(ISemanticResolver s)
{
}
#endregion
}
#endregion
#region BlockStatement
//-----------------------------------------------------------------------------
// Block statement
// Statements inside '{' .... '}'
// Can have their own statements & optionally their own little scope
//-----------------------------------------------------------------------------
public class BlockStatement : Statement
{
#region Construction
public BlockStatement(
LocalVarDecl[] arLocals, // can be null if we have no locals
Statement[] arStatements // never null
)
{
// If we have any locals in this block statement, then we
// also need to have a scope to hold them.
if (arLocals == null)
{
m_arLocals = new LocalVarDecl[0];
} else {
m_arLocals = arLocals;
// @todo - decorate name w/ filerange?
//m_scopeLocals = new Scope("block_scope", null);
}
// May have an empty statement block, so arStatements.Length could be 0
// but at least expect an array.
Debug.Assert(arStatements != null);
m_arStatements = arStatements;
// @todo - fix this
if (arStatements.Length == 0)
this.m_filerange = new FileRange();
else
this.m_filerange = arStatements[0].Location;
}
#endregion
// Inject a statement at the beginning
// Must resolve after doing this.
public void InjectStatementAtHead(Statement sNew)
{
Statement[] ar2 = new Statement[this.Statements.Length + 1];
ar2[0] = sNew;
for(int i = 0; i < Statements.Length; i++)
ar2[i + 1] = Statements[i];
this.m_arStatements = ar2;
}
public void InjectLocalVar(LocalVarDecl l)
{
//m_scopeLocals = new Scope("block_scope", null);
LocalVarDecl[] ar2 = new LocalVarDecl[Locals.Length + 1];
ar2[0] = l;
for(int i = 0; i < Locals.Length; i++)
ar2[i + 1] = Locals[i];
m_arLocals = ar2;
}
#region Checks
//-----------------------------------------------------------------------------
// Debugging check
//-----------------------------------------------------------------------------
public override void DebugCheck(ISemanticResolver s)
{
Debug.Assert(m_arLocals != null);
Debug.Assert(m_arStatements != null);
foreach(LocalVarDecl v in m_arLocals)
{
v.DebugCheck(s);
}
foreach(Statement st in m_arStatements)
{
st.DebugCheck(s);
}
}
public override void ToSource(System.CodeDom.Compiler.IndentedTextWriter sb)
{
sb.WriteLine('{');
sb.Indent++;
foreach(LocalVarDecl v in Locals)
{
v.ToSource(sb);
sb.WriteLine();
}
foreach(Statement s in Statements)
{
s.ToSource(sb); // these should already add '\n'
}
sb.Indent--;
sb.WriteLine('}');
}
// Dump as XML
public override void Dump(XmlWriter o)
{
o.WriteStartElement("BlockStatement");
foreach(LocalVarDecl v in Locals)
{
v.Dump(o);
}
foreach(Statement s in Statements)
{
s.Dump(o);
}
o.WriteEndElement();
}
#endregion
#region Properties & Data
Scope m_scopeLocals;
protected LocalVarDecl [] m_arLocals;
protected Statement[] m_arStatements;
public LocalVarDecl [] Locals
{
get { return m_arLocals; }
}
public Statement[] Statements
{
get { return m_arStatements; }
}
#endregion
#region Resolution
// Semantic resolution
public override void ResolveStatement(ISemanticResolver s)
{
Scope prev = null;
if (this.m_arLocals.Length != 0)
{
//s.PushScope(m_scopeLocals);
m_scopeLocals = new Scope("block_scope", null, s.GetCurrentContext());
prev = s.SetCurrentContext(m_scopeLocals);
}
foreach(LocalVarDecl v in Locals)
{
v.ResolveVarDecl(s);
}
foreach(Statement stmt in Statements)
{
stmt.ResolveStatement(s);
}
if (m_scopeLocals != null)
//s.PopScope(m_scopeLocals);
s.RestoreContext(prev);
}
public override void ResolveStatement2(ISemanticResolver s)
{
Scope prev = null;
if (m_scopeLocals != null)
//s.PushScope(m_scopeLocals);
prev = s.SetCurrentContext(m_scopeLocals);
foreach(Statement stmt in Statements)
{
stmt.ResolveStatement2(s);
}
if (m_scopeLocals != null)
//s.PopScope(m_scopeLocals);
s.RestoreContext(prev);
}
#endregion
// Code generation
public override void Generate(CodeGen.EmitCodeGen gen)
{
foreach(Statement stmt in Statements)
{
stmt.Generate(gen);
}
}
}
#endregion
#region EH statements
//-----------------------------------------------------------------------------
// Catch-handler, used in try block
//-----------------------------------------------------------------------------
public class CatchHandler
{
public CatchHandler(
TypeSig type, // type we're catching (must derived from System.Exception)
Identifier idName, // optional (can be null) name for local var to store exception
BlockStatement stmtBody // handler body (non-null)
)
{
Debug.Assert(stmtBody != null);
// General catch blocks just becomes a System.Exception
if (type == null)
{
m_type = new SimpleTypeSig(new DotObjExp(
new SimpleObjExp(new Identifier("System", null)),
new Identifier("Exception", null)
));
} else {
m_type = type;
}
m_idVarName = idName;
m_body = stmtBody;
}
#region Properties & Data
TypeSig m_type;
public TypeEntry CatchType
{
get { return m_type.BlueType; }
}
Identifier m_idVarName;
public Identifier IdVarName
{
get { return m_idVarName; }
}
LocalVarDecl m_var;
public LocalVarDecl CatchVarDecl
{
get {return m_var; }
}
BlockStatement m_body;
public BlockStatement Body
{
get { return m_body; }
}
#endregion
#region Checks
public void Dump(XmlWriter o)
{
o.WriteStartElement("Catch");
if (IdVarName != null)
o.WriteAttributeString("varname", IdVarName.Text);
if (m_type != null)
this.m_type.Dump(o);
Body.Dump(o);
o.WriteEndElement();
}
public void DebugCheck(ISemanticResolver s)
{
CatchType.DebugCheck(s);
Body.DebugCheck(s);
}
#endregion
#region Resolution
public void ResolveHandler2(ISemanticResolver s)
{
m_body.ResolveStatement2(s);
}
public void ResolveHandler(ISemanticResolver s)
{
// Catch blocks can declare an identifier
if (IdVarName != null)
{
m_var = new LocalVarDecl(IdVarName, m_type);
Body.InjectLocalVar(m_var);
}
this.m_type.ResolveType(s);
Body.ResolveStatement(s);
// Catch type must be of type System.Exception
if (m_var != null)
{
s.EnsureAssignable(m_var.Symbol.m_type.CLRType, typeof(System.Exception), IdVarName.Location);
}
// Catch type must be of type System.Exception
//TypeEntry tSystem_Exception =s.ResolveCLRTypeToBlueType(typeof(System.Exception));
//s.EnsureDerivedType(tSystem_Exception, m_type.TypeRec, new FileRange());
}
#endregion
}
//-----------------------------------------------------------------------------
// Try-Catch-Finally
// -> 'try' block 'finally' block
// -> 'try' block <'catch' '(' TypeSig id ')' block>+ ['finally' block]?
//-----------------------------------------------------------------------------
public class TryStatement : Statement
{
// Must have a finally or at least one Catch (or both)
public TryStatement(
BlockStatement stmtTry, // never null
CatchHandler [] arCatch, // can be null
BlockStatement stmtFinally // can be null
)
{
Debug.Assert(stmtTry != null); // always have a try block
Debug.Assert((arCatch != null && arCatch.Length > 0) || stmtFinally != null);
m_stmtTry = stmtTry;
m_arCatchHandlers = (arCatch == null) ? new CatchHandler[0] : arCatch;
m_stmtFinally = stmtFinally;
// @todo - this is wrong
m_filerange = stmtTry.Location;
}
#region Properties & Data
protected BlockStatement m_stmtTry;
public BlockStatement TryStmt
{
get { return m_stmtTry; }
}
protected CatchHandler [] m_arCatchHandlers;
public CatchHandler [] CatchHandlers
{
get { return m_arCatchHandlers; }
}
protected BlockStatement m_stmtFinally;
public BlockStatement FinallyStmt
{
get { return m_stmtFinally; }
}
#endregion
#region Checks
// Dump as XML
public override void Dump(XmlWriter o)
{
o.WriteStartElement("TryStatement");
o.WriteStartElement("try_block");
m_stmtTry.Dump(o);
o.WriteEndElement();
o.WriteStartElement("catch_handlers");
foreach(CatchHandler c in m_arCatchHandlers)
{
c.Dump(o);
}
o.WriteEndElement();
if (m_stmtFinally != null)
{
o.WriteStartElement("finally_block");
m_stmtFinally.Dump(o);
o.WriteEndElement();
}
o.WriteEndElement();
}
//-----------------------------------------------------------------------------
// Debugging check
//-----------------------------------------------------------------------------
public override void DebugCheck(ISemanticResolver s)
{
m_stmtTry.DebugCheck(s);
if (m_stmtFinally != null)
m_stmtFinally.DebugCheck(s);
foreach(CatchHandler c in CatchHandlers)
{
c.DebugCheck(s);
}
}
#endregion
#region Resolution
// Semantic resolution
public override void ResolveStatement(ISemanticResolver s)
{
m_stmtTry.ResolveStatement(s);
for(int i = 0; i < CatchHandlers.Length; i++)
{
CatchHandler c = CatchHandlers[i];
c.ResolveHandler(s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -