Complete rewrite of the symbol resolution API.

- Constants are now symbols alongside variables in the "storable" symbol
class.
- Added Resolve* and MustResolve* versions in the new symbol-resolution
API.
- Moved storable-symbol compilation code out of the AST classes and into
the respective symbol classes. Storable symbols have extra compile
methods for get, set, increment, and decrement operations.
- Adapted the scope class accordingly.
- Added checks against assignment to constant symbols (which all throw
sunAssignConstantException).
This commit is contained in:
arookas 2015-12-27 22:39:55 -05:00
parent 664d1e227e
commit 0840a33f9b
7 changed files with 224 additions and 125 deletions

View file

@ -124,7 +124,7 @@ namespace arookas
class sunPostfixAugment : sunOperand
{
public sunIdentifier Variable { get { return this[0] as sunIdentifier; } }
public sunAugment Operator { get { return this[1] as sunAugment; } }
public sunAugment Augment { get { return this[1] as sunAugment; } }
public sunPostfixAugment(sunSourceLocation location)
: base(location)
@ -134,19 +134,22 @@ namespace arookas
public override void Compile(sunContext context)
{
var variableInfo = context.ResolveVariable(Variable);
var symbol = context.MustResolveStorable(Variable);
if (symbol is sunConstantSymbol)
{
throw new sunAssignConstantException(Variable);
}
if (Parent is sunOperand)
{
context.Text.PushVariable(variableInfo);
symbol.CompileGet(context);
}
Operator.Compile(context, variableInfo);
context.Text.StoreVariable(variableInfo);
Augment.Compile(context, symbol);
}
}
class sunPrefixAugment : sunOperand
{
public sunAugment Operator { get { return this[0] as sunAugment; } }
public sunAugment Augment { get { return this[0] as sunAugment; } }
public sunIdentifier Variable { get { return this[1] as sunIdentifier; } }
public sunPrefixAugment(sunSourceLocation location)
@ -157,12 +160,15 @@ namespace arookas
public override void Compile(sunContext context)
{
var variableInfo = context.ResolveVariable(Variable);
Operator.Compile(context, variableInfo);
context.Text.StoreVariable(variableInfo);
var symbol = context.MustResolveStorable(Variable);
if (symbol is sunConstantSymbol)
{
throw new sunAssignConstantException(Variable);
}
Augment.Compile(context, symbol);
if (Parent is sunOperand)
{
context.Text.PushVariable(variableInfo);
symbol.CompileGet(context);
}
}
}
@ -175,7 +181,7 @@ namespace arookas
}
public abstract void Compile(sunContext context, sunVariableSymbol variable);
public abstract void Compile(sunContext context, sunStorableSymbol symbol);
}
class sunIncrement : sunAugment
@ -186,9 +192,10 @@ namespace arookas
}
public override void Compile(sunContext context, sunVariableSymbol variable)
public override void Compile(sunContext context, sunStorableSymbol symbol)
{
context.Text.IncVariable(variable);
symbol.CompileInc(context);
symbol.CompileSet(context);
}
}
@ -200,9 +207,10 @@ namespace arookas
}
public override void Compile(sunContext context, sunVariableSymbol variable)
public override void Compile(sunContext context, sunStorableSymbol symbol)
{
context.Text.DecVariable(variable);
symbol.CompileDec(context);
symbol.CompileSet(context);
}
}
}

View file

@ -53,7 +53,7 @@ namespace arookas
public override void Compile(sunContext context)
{
var callableInfo = context.ResolveCallable(this);
var callableInfo = context.MustResolveCallable(this);
if (!callableInfo.Parameters.ValidateArgumentCount(Arguments.Count))
{
throw new sunArgumentCountException(this, callableInfo);

View file

@ -1,10 +1,10 @@
namespace arookas
{
class sunVariableReference : sunNode
class sunStorableReference : sunNode
{
public sunIdentifier Variable { get { return this[0] as sunIdentifier; } }
public sunIdentifier Storable { get { return this[0] as sunIdentifier; } }
public sunVariableReference(sunSourceLocation location)
public sunStorableReference(sunSourceLocation location)
: base(location)
{
@ -12,23 +12,13 @@
public override void Compile(sunContext context)
{
sunVariableSymbol variableInfo;
sunConstInfo constInfo;
context.ResolveVariableOrConstant(Variable, out variableInfo, out constInfo);
if (variableInfo != null)
{
context.Text.PushVariable(variableInfo);
}
if (constInfo != null)
{
constInfo.Expression.Compile(context);
}
context.MustResolveStorable(Storable).Compile(context);
}
}
class sunVariableDeclaration : sunNode
{
public sunIdentifier Variable { get { return this[0] as sunIdentifier; } }
public sunIdentifier Storable { get { return this[0] as sunIdentifier; } }
public sunVariableDeclaration(sunSourceLocation location)
: base(location)
@ -38,7 +28,7 @@
public override void Compile(sunContext context)
{
var variableInfo = context.DeclareVariable(Variable);
context.DeclareVariable(Storable);
}
}
@ -52,7 +42,7 @@
public override void Compile(sunContext context)
{
var variableInfo = context.DeclareVariable(Variable);
context.DeclareVariable(Storable);
base.Compile(context);
}
}
@ -70,8 +60,12 @@
public override void Compile(sunContext context)
{
var variableInfo = context.ResolveVariable(Variable);
Operator.Compile(context, variableInfo, Expression);
var symbol = context.MustResolveStorable(Storable);
if (symbol is sunConstantSymbol)
{
throw new sunAssignConstantException(Storable);
}
Operator.Compile(context, symbol as sunVariableSymbol, Expression);
}
}
@ -88,7 +82,7 @@
public override void Compile(sunContext context)
{
var constInfo = context.DeclareConstant(Constant, Expression);
context.DeclareConstant(Constant, Expression);
}
}
}

View file

@ -118,7 +118,7 @@ namespace arookas
return result;
}
// builtins
// callables
public sunBuiltinSymbol DeclareBuiltin(sunBuiltinDeclaration node)
{
var symbolInfo = SymbolTable.Callables.FirstOrDefault(f => f.Name == node.Builtin.Value);
@ -130,22 +130,6 @@ namespace arookas
SymbolTable.Add(builtinInfo);
return builtinInfo;
}
public sunBuiltinSymbol DeclareSystemBuiltin(string name, bool variadic, params string[] parameters)
{
var builtinInfo = SymbolTable.Builtins.FirstOrDefault(f => f.Name == name);
if (builtinInfo == null)
{
builtinInfo = new sunBuiltinSymbol(name, new sunParameterInfo(parameters, variadic), SymbolTable.Count);
SymbolTable.Add(builtinInfo);
}
return builtinInfo;
}
public sunBuiltinSymbol ResolveSystemBuiltin(string name)
{
return SymbolTable.Builtins.FirstOrDefault(f => f.Name == name);
}
// functions
public sunFunctionSymbol DefineFunction(sunFunctionDefinition node)
{
if (node.Parameters.IsVariadic)
@ -163,85 +147,123 @@ namespace arookas
}
public sunCallableSymbol ResolveCallable(sunFunctionCall node)
{
var symbolInfo = SymbolTable.Callables.FirstOrDefault(f => f.Name == node.Function.Value);
if (symbolInfo == null)
var symbol = SymbolTable.Callables.FirstOrDefault(f => f.Name == node.Function.Value);
if (symbol == null)
{
throw new sunUndefinedFunctionException(node);
}
return symbolInfo;
return symbol;
}
public sunCallableSymbol MustResolveCallable(sunFunctionCall node)
{
var symbol = ResolveCallable(node);
if (symbol == null)
{
throw new sunUndefinedFunctionException(node);
}
return symbol;
}
// variables
public sunBuiltinSymbol DeclareSystemBuiltin(string name, bool variadic, params string[] parameters)
{
var builtinInfo = SymbolTable.Builtins.FirstOrDefault(f => f.Name == name);
if (builtinInfo == null)
{
builtinInfo = new sunBuiltinSymbol(name, new sunParameterInfo(parameters, variadic), SymbolTable.Count);
SymbolTable.Add(builtinInfo);
}
return builtinInfo;
}
public sunBuiltinSymbol ResolveSystemBuiltin(string name)
{
return SymbolTable.Builtins.FirstOrDefault(f => f.Name == name);
}
// storables
public sunVariableSymbol DeclareVariable(sunIdentifier node)
{
// assert variable is not already declared in current scope
if (Scopes.Top.GetIsVariableDeclared(node.Value))
if (Scopes.Top.GetIsDeclared(node.Value))
{
throw new sunRedeclaredVariableException(node);
}
var variableInfo = Scopes.DeclareVariable(node.Value);
return variableInfo;
}
public sunVariableSymbol ResolveVariable(sunIdentifier node)
public sunConstantSymbol DeclareConstant(sunIdentifier node, sunExpression expression)
{
// walk the stack backwards to resolve to the variable's latest declaration
for (int i = Scopes.Count - 1; i >= 0; --i)
{
var variableInfo = Scopes[i].ResolveVariable(node.Value);
if (variableInfo != null)
{
return variableInfo;
}
}
throw new sunUndeclaredVariableException(node);
}
public sunVariableSymbol DeclareParameter(string name) { return Scopes.DeclareVariable(name); }
// constants
public sunConstInfo DeclareConstant(sunIdentifier node, sunExpression expression)
{
if (Scopes.Top.GetIsConstantDeclared(node.Value))
if (Scopes.Top.GetIsDeclared(node.Value))
{
throw new sunRedeclaredVariableException(node);
}
var constInfo = Scopes.Top.DeclareConstant(node.Value, expression);
return constInfo;
}
public sunConstInfo ResolveConstant(sunIdentifier node)
public sunStorableSymbol ResolveStorable(sunIdentifier node)
{
// walk the stack backwards to resolve to the constant's latest declaration
for (int i = Scopes.Count - 1; i >= 0; --i)
{
var constInfo = Scopes[i].ResolveConstant(node.Value);
if (constInfo != null)
var symbol = Scopes[i].ResolveStorable(node.Value);
if (symbol != null)
{
return constInfo;
return symbol;
}
}
throw new sunUndeclaredVariableException(node);
return null;
}
public sunVariableSymbol ResolveVariable(sunIdentifier node)
{
for (int i = Scopes.Count - 1; i >= 0; --i)
{
var symbol = Scopes[i].ResolveVariable(node.Value);
if (symbol != null)
{
return symbol;
}
}
return null;
}
public sunConstantSymbol ResolveConstant(sunIdentifier node)
{
for (int i = Scopes.Count - 1; i >= 0; --i)
{
var symbol = Scopes[i].ResolveConstant(node.Value);
if (symbol != null)
{
return symbol;
}
}
return null;
}
public sunStorableSymbol MustResolveStorable(sunIdentifier node)
{
var symbol = ResolveStorable(node);
if (symbol == null)
{
throw new sunUndeclaredVariableException(node);
}
return symbol;
}
public sunVariableSymbol MustResolveVariable(sunIdentifier node)
{
var symbol = ResolveVariable(node);
if (symbol == null)
{
throw new sunUndeclaredVariableException(node);
}
return symbol;
}
public sunConstantSymbol MustResolveConstant(sunIdentifier node)
{
var symbol = ResolveConstant(node);
if (symbol == null)
{
throw new sunUndeclaredVariableException(node);
}
return symbol;
}
public void ResolveVariableOrConstant(sunIdentifier node, out sunVariableSymbol variableInfo, out sunConstInfo constInfo)
{
variableInfo = null;
constInfo = null;
// walk the stack backwards to resolve to the latest declaration
for (int i = Scopes.Count - 1; i >= 0; --i)
{
var variable = Scopes[i].ResolveVariable(node.Value);
if (variable != null)
{
variableInfo = variable;
}
var constant = Scopes[i].ResolveConstant(node.Value);
if (constant != null)
{
constInfo = constant;
}
}
throw new sunUndeclaredVariableException(node);
}
public sunVariableSymbol DeclareParameter(string name) { return Scopes.DeclareVariable(name); }
void WriteHeader()
{

View file

@ -212,7 +212,7 @@ namespace arookas
// variables
switch (GetId(node))
{
case __sunConstants.VARIABLE_REFERENCE: return new sunVariableReference(location);
case __sunConstants.VARIABLE_REFERENCE: return new sunStorableReference(location);
case __sunConstants.VARIABLE_DECLARATION: return new sunVariableDeclaration(location);
case __sunConstants.VARIABLE_DEFINITION: return new sunVariableDefinition(location);
case __sunConstants.VARIABLE_ASSIGNMENT: return new sunVariableAssignment(location);

View file

@ -7,8 +7,8 @@ namespace arookas
class sunScopeStack : IEnumerable<sunScope>
{
List<sunScope> stack = new List<sunScope>(8);
int GlobalCount { get { return stack.Where(i => i.Type == sunScopeType.Script).Sum(i => i.VariableCount); } }
int LocalCount { get { return stack.Where(i => i.Type == sunScopeType.Function).Sum(i => i.VariableCount); } }
int GlobalCount { get { return stack.Where(i => i.Type == sunScopeType.Script).Sum(i => i.StorableCount); } }
int LocalCount { get { return stack.Where(i => i.Type == sunScopeType.Function).Sum(i => i.StorableCount); } }
public int Count { get { return stack.Count; } }
@ -73,8 +73,7 @@ namespace arookas
class sunScope
{
List<sunVariableSymbol> variables = new List<sunVariableSymbol>(10);
List<sunConstInfo> constants = new List<sunConstInfo>(10);
List<sunStorableSymbol> storables = new List<sunStorableSymbol>(10);
public sunScopeType Type { get; private set; }
public sunScope(sunScopeType type)
@ -82,34 +81,36 @@ namespace arookas
Type = type;
}
public int VariableCount { get { return variables.Count; } }
public int ConstantCount { get { return constants.Count; } }
public int StorableCount { get { return storables.Count; } }
public int VariableCount { get { return storables.OfType<sunVariableSymbol>().Count(); } }
public int ConstantCount { get { return storables.OfType<sunConstantSymbol>().Count(); } }
public bool GetIsDeclared(string name) { return storables.Any(v => v.Name == name); }
public bool GetIsVariableDeclared(string name) { return variables.Any(v => v.Name == name); }
public sunVariableSymbol DeclareVariable(string name, int display, int index)
{
if (GetIsVariableDeclared(name) || GetIsConstantDeclared(name))
if (GetIsDeclared(name))
{
return null;
}
var variableInfo = new sunVariableSymbol(name, display, index);
variables.Add(variableInfo);
storables.Add(variableInfo);
return variableInfo;
}
public sunVariableSymbol ResolveVariable(string name) { return variables.FirstOrDefault(v => v.Name == name); }
public bool GetIsConstantDeclared(string name) { return constants.Any(c => c.Name == name); }
public sunConstInfo DeclareConstant(string name, sunExpression expression)
public sunConstantSymbol DeclareConstant(string name, sunExpression expression)
{
if (GetIsVariableDeclared(name) || GetIsConstantDeclared(name))
if (GetIsDeclared(name))
{
return null;
}
var constInfo = new sunConstInfo(name, expression);
constants.Add(constInfo);
return constInfo;
var constantSymbol = new sunConstantSymbol(name, expression);
storables.Add(constantSymbol);
return constantSymbol;
}
public sunConstInfo ResolveConstant(string name) { return constants.FirstOrDefault(c => c.Name == name); }
public sunStorableSymbol ResolveStorable(string name) { return storables.FirstOrDefault(i => i.Name == name); }
public sunVariableSymbol ResolveVariable(string name) { return storables.OfType<sunVariableSymbol>().FirstOrDefault(i => i.Name == name); }
public sunConstantSymbol ResolveConstant(string name) { return storables.OfType<sunConstantSymbol>().FirstOrDefault(i => i.Name == name); }
}
enum sunScopeType

View file

@ -54,6 +54,8 @@ namespace arookas
Name = name;
}
public abstract void Compile(sunContext context);
public virtual int WriteSymbolTable(aBinaryWriter writer, int ofs)
{
writer.WriteS32((int)Type);
@ -88,8 +90,6 @@ namespace arookas
public abstract void OpenCallSite(sunContext context, int argumentCount);
public abstract void CloseCallSites(sunContext context);
public abstract void Compile(sunContext context);
}
class sunBuiltinSymbol : sunCallableSymbol
@ -196,7 +196,35 @@ namespace arookas
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
class sunVariableSymbol : sunSymbol
abstract class sunStorableSymbol : sunSymbol
{
protected sunStorableSymbol(string name)
: base(name)
{
}
public override void Compile(sunContext context)
{
CompileGet(context); // compile get by default
}
public abstract void CompileGet(sunContext context);
public abstract void CompileSet(sunContext context);
public virtual void CompileInc(sunContext context)
{
CompileGet(context);
context.Text.PushInt(1);
context.Text.Add();
}
public virtual void CompileDec(sunContext context)
{
CompileGet(context);
context.Text.PushInt(1);
context.Text.Sub();
}
}
class sunVariableSymbol : sunStorableSymbol
{
public int Display { get; private set; }
public int Index { get; private set; }
@ -214,6 +242,22 @@ namespace arookas
Index = index;
}
public override void CompileGet(sunContext context)
{
context.Text.PushVariable(Display, Index);
}
public override void CompileSet(sunContext context)
{
context.Text.StoreVariable(Display, Index);
}
public override void CompileInc(sunContext context)
{
context.Text.IncVariable(Display, Index);
}
public override void CompileDec(sunContext context)
{
context.Text.DecVariable(Display, Index);
}
public override int WriteSymbolTable(aBinaryWriter writer, int ofs)
{
base.WriteSymbolTable(writer, ofs);
@ -225,10 +269,40 @@ namespace arookas
}
}
class sunConstantSymbol : sunStorableSymbol
{
sunExpression Expression { get; set; }
// symbol table
public override sunSymbolType Type { get { return sunSymbolType.Constant; } }
public override uint Data { get { return 0; } }
public sunConstantSymbol(string name, sunExpression expression)
: base(name)
{
if (expression == null)
{
throw new ArgumentNullException("expression");
}
Expression = expression;
}
public override void CompileGet(sunContext context)
{
Expression.Compile(context);
}
public override void CompileSet(sunContext context)
{
// checks against this have to be implemented at a higher level
throw new InvalidOperationException();
}
}
enum sunSymbolType
{
Builtin,
Function,
Variable,
Constant,
}
}