From 0840a33f9b675e91bacd2cf6117c4960d79640d1 Mon Sep 17 00:00:00 2001 From: arookas Date: Sun, 27 Dec 2015 22:39:55 -0500 Subject: [PATCH] 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). --- ssc/ast/nodes.expressions.cs | 38 +++++---- ssc/ast/nodes.functions.cs | 2 +- ssc/ast/nodes.variables.cs | 34 ++++---- ssc/context.cs | 156 ++++++++++++++++++++--------------- ssc/parser.cs | 2 +- ssc/scope stack.cs | 37 +++++---- ssc/symbol table.cs | 80 +++++++++++++++++- 7 files changed, 224 insertions(+), 125 deletions(-) diff --git a/ssc/ast/nodes.expressions.cs b/ssc/ast/nodes.expressions.cs index 45b9ce5..13e4263 100644 --- a/ssc/ast/nodes.expressions.cs +++ b/ssc/ast/nodes.expressions.cs @@ -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); } } } diff --git a/ssc/ast/nodes.functions.cs b/ssc/ast/nodes.functions.cs index 18b8bb0..3db33eb 100644 --- a/ssc/ast/nodes.functions.cs +++ b/ssc/ast/nodes.functions.cs @@ -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); diff --git a/ssc/ast/nodes.variables.cs b/ssc/ast/nodes.variables.cs index 630c0ff..39641ea 100644 --- a/ssc/ast/nodes.variables.cs +++ b/ssc/ast/nodes.variables.cs @@ -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); } } } diff --git a/ssc/context.cs b/ssc/context.cs index 16df948..79e876b 100644 --- a/ssc/context.cs +++ b/ssc/context.cs @@ -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() { diff --git a/ssc/parser.cs b/ssc/parser.cs index 2a30cae..d8cb6e5 100644 --- a/ssc/parser.cs +++ b/ssc/parser.cs @@ -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); diff --git a/ssc/scope stack.cs b/ssc/scope stack.cs index 774166a..7274ddb 100644 --- a/ssc/scope stack.cs +++ b/ssc/scope stack.cs @@ -7,8 +7,8 @@ namespace arookas class sunScopeStack : IEnumerable { List stack = new List(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 variables = new List(10); - List constants = new List(10); + List storables = new List(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().Count(); } } + public int ConstantCount { get { return storables.OfType().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().FirstOrDefault(i => i.Name == name); } + public sunConstantSymbol ResolveConstant(string name) { return storables.OfType().FirstOrDefault(i => i.Name == name); } } enum sunScopeType diff --git a/ssc/symbol table.cs b/ssc/symbol table.cs index c2c9c7b..bdd7ddc 100644 --- a/ssc/symbol table.cs +++ b/ssc/symbol table.cs @@ -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, } }