ssc/ssc/context.cs
arookas a676f9e8e5 Merged sunConstDefinition and sunVariableDefinition
Now sunVariableDefinition declares either a constant symbol or a
variable symbol, depending on the appearance of the 'const' modifier.
2016-02-22 20:53:40 -05:00

236 lines
7.1 KiB
C#

using arookas.IO.Binary;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace arookas {
class sunContext {
Stack<sunNameLabel> mNameStack;
public sunDataTable DataTable { get; private set; }
public sunSymbolTable SymbolTable { get; private set; }
public sunScopeStack Scopes { get; private set; }
public sunLoopStack Loops { get; private set; }
// system builtins
public sunCallableSymbol Yield { get; private set; }
public sunCallableSymbol Exit { get; private set; }
public sunCallableSymbol Lock { get; private set; }
public sunCallableSymbol Unlock { get; private set; }
// system variables
public sunStorableSymbol Switch { get; private set; }
public sunContext() {
DataTable = new sunDataTable();
SymbolTable = new sunSymbolTable();
Scopes = new sunScopeStack();
Loops = new sunLoopStack();
mNameStack = new Stack<sunNameLabel>(10);
AddSystemSymbols();
}
public void Clear() {
DataTable.Clear();
SymbolTable.Clear();
Scopes.Clear();
Loops.Clear();
mNameStack.Clear();
// reinstall system symbols
AddSystemSymbols();
}
// callables
public sunBuiltinSymbol DeclareBuiltin(sunBuiltinDeclaration node) {
if (SymbolTable.Get<sunCallableSymbol>().Any(i => i.Name == node.Name.Value)) {
throw new sunRedeclaredBuiltinException(node);
}
var symbol = new sunBuiltinSymbol(node.Name.Value, node.Parameters.ParameterInfo, SymbolTable.Count);
SymbolTable.Add(symbol);
return symbol;
}
public sunFunctionSymbol DefineFunction(sunFunctionDefinition node) {
var local = (node.Modifiers & sunSymbolModifiers.Local) != 0;
var name = MangleSymbolName(node.Name.Value, node.Location.ScriptId, false, local);
if (node.Parameters.IsVariadic) {
throw new sunVariadicFunctionException(node);
}
if (SymbolTable.Get<sunCallableSymbol>().Any(i => i.Name == name)) {
throw new sunRedefinedFunctionException(node);
}
var symbol = new sunFunctionSymbol(name, node.Parameters.ParameterInfo, node.Body);
SymbolTable.Add(symbol);
return symbol;
}
public sunCallableSymbol ResolveCallable(sunFunctionCall node) {
var global = node.Name.Value;
var local = MangleSymbolName(global, node.Location.ScriptId, false, true);
var symbol = SymbolTable.Get<sunCallableSymbol>().FirstOrDefault(i => i.Name == local);
if (symbol != null) {
return symbol;
}
symbol = SymbolTable.Get<sunCallableSymbol>().FirstOrDefault(i => i.Name == global);
if (symbol != null) {
return symbol;
}
return null;
}
public sunCallableSymbol MustResolveCallable(sunFunctionCall node) {
var symbol = ResolveCallable(node);
if (symbol == null) {
throw new sunUndefinedFunctionException(node);
}
return symbol;
}
// storables
public sunVariableSymbol DeclareVariable(sunVariableDeclaration node) {
return DeclareVariable(node.Name, node.Modifiers);
}
public sunVariableSymbol DeclareVariable(sunVariableDefinition node) {
return DeclareVariable(node.Name, node.Modifiers);
}
sunVariableSymbol DeclareVariable(sunIdentifier node, sunSymbolModifiers modifiers) {
var local = (modifiers & sunSymbolModifiers.Local) != 0;
var name = MangleSymbolName(node.Value, node.Location.ScriptId, false, local);
var symbol = Scopes.DeclareVariable(name);
if (symbol == null) {
throw new sunRedeclaredVariableException(node);
}
#if SSC_SCOPES
if (Scopes.Top.Type == sunScopeType.Script) {
#else
if (Scopes.Count == 1) {
#endif
SymbolTable.Add(symbol);
}
return symbol;
}
public sunConstantSymbol DeclareConstant(sunVariableDefinition node) {
return DeclareConstant(node.Name, node.Expression, node.Modifiers);
}
sunConstantSymbol DeclareConstant(sunIdentifier node, sunExpression expression, sunSymbolModifiers modifiers) {
var local = (modifiers & sunSymbolModifiers.Local) != 0;
var name = MangleSymbolName(node.Value, node.Location.ScriptId, false, local);
var symbol = Scopes.DeclareConstant(name, expression);
if (symbol == null) {
throw new sunRedeclaredVariableException(node);
}
return symbol;
}
public sunStorableSymbol ResolveStorable(sunIdentifier node) {
var global = node.Value;
var local = MangleSymbolName(global, node.Location.ScriptId, false, true);
var symbol = ResolveStorable(local);
if (symbol != null) {
return symbol;
}
symbol = ResolveStorable(global);
if (symbol != null) {
return symbol;
}
return null;
}
sunStorableSymbol ResolveStorable(string name) {
for (int i = Scopes.Count - 1; i >= 0; --i) {
var symbol = Scopes[i].ResolveStorable(name);
if (symbol != null) {
return symbol;
}
}
return null;
}
public sunVariableSymbol ResolveVariable(sunIdentifier node) {
return ResolveStorable(node) as sunVariableSymbol;
}
public sunConstantSymbol ResolveConstant(sunIdentifier node) {
return ResolveStorable(node) as sunConstantSymbol;
}
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;
}
// name labels
public void PushNameLabel(sunNameLabel label) {
if (label == null) {
throw new ArgumentNullException("label");
}
mNameStack.Push(label);
}
public sunNameLabel PopNameLabel() {
if (mNameStack.Count > 0) {
return mNameStack.Pop();
}
return null;
}
// system symbols
void AddSystemSymbols() {
// add system builtins
Yield = AddSystemBuiltin("yield");
Exit = AddSystemBuiltin("exit");
Lock = AddSystemBuiltin("lock");
Unlock = AddSystemBuiltin("unlock");
// add system variables
Switch = AddSystemVariable("switch"); // storage for switch statements
}
sunCallableSymbol AddSystemBuiltin(string name) {
var symbol = new sunBuiltinSymbol(name, SymbolTable.Count);
SymbolTable.Add(symbol);
return symbol;
}
sunStorableSymbol AddSystemVariable(string name) {
var symbol = Scopes.DeclareVariable(MangleSystemSymbol(name));
SymbolTable.Add(symbol);
return symbol;
}
// static util
static string MangleSystemSymbol(string basename) {
return MangleSymbolName(basename, 0, true, false);
}
static string MangleLocalSymbol(string basename, ulong id) {
return MangleSymbolName(basename, id, false, true);
}
static string MangleSymbolName(string basename, ulong id, bool system, bool local) {
if (!system && !local) {
return basename;
}
var sb = new StringBuilder(basename.Length + 16);
if (system) {
sb.Append('$');
}
sb.Append(basename);
if (local) {
sb.AppendFormat("@{0}", id);
}
return sb.ToString();
}
}
}