ssc/ssc/context.cs

246 lines
7.5 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 {
bool mOpen;
aBinaryWriter mWriter;
uint mTextOffset, mDataOffset, mSymbolOffset;
Stack<sunNameLabel> mNameStack;
public sunWriter Text { get; private set; }
public sunDataTable DataTable { get; private set; }
public sunSymbolTable SymbolTable { get; private set; }
public sunScopeStack Scopes { get; private set; }
public sunLoopStack Loops { get; private set; }
public sunImportResolver ImportResolver { 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; }
public sunCallableSymbol Int { get; private set; }
public sunCallableSymbol Float { get; private set; }
public sunCallableSymbol Typeof { get; private set; }
public sunContext() {
DataTable = new sunDataTable();
SymbolTable = new sunSymbolTable();
Scopes = new sunScopeStack();
Loops = new sunLoopStack();
mNameStack = new Stack<sunNameLabel>(5);
}
// open/close
public void Open(Stream output) { Open(output, sunImportResolver.Default); }
public void Open(Stream output, sunImportResolver importResolver) {
if (mOpen) {
throw new InvalidOperationException();
}
if (output == null) {
throw new ArgumentNullException("output");
}
if (importResolver == null) {
throw new ArgumentNullException("importResolver");
}
mOpen = true;
DataTable.Clear();
SymbolTable.Clear();
Scopes.Clear();
Loops.Clear();
mNameStack.Clear();
ImportResolver = importResolver;
mWriter = new aBinaryWriter(output, Endianness.Big, Encoding.GetEncoding(932));
Text = new sunWriter(mWriter);
mWriter.PushAnchor();
WriteHeader(); // dummy header
// begin text block
mTextOffset = (uint)mWriter.Position;
mWriter.PushAnchor(); // match code offsets and writer offsets
// add system builtins
Yield = AddSystemBuiltin("yield");
Exit = AddSystemBuiltin("exit");
Lock = AddSystemBuiltin("lock");
Unlock = AddSystemBuiltin("unlock");
Int = AddSystemBuiltin("int");
Float = AddSystemBuiltin("float");
Typeof = AddSystemBuiltin("typeof");
}
public void Close() {
if (!mOpen) {
throw new InvalidOperationException();
}
mWriter.PopAnchor();
mDataOffset = (uint)mWriter.Position;
DataTable.Write(mWriter);
mSymbolOffset = (uint)mWriter.Position;
SymbolTable.Write(mWriter);
mWriter.Goto(0);
WriteHeader();
mOpen = false;
}
// imports/compilation
public sunImportResult Import(string name) {
if (name == null) {
throw new ArgumentNullException("name");
}
sunScriptFile file;
var result = ImportResolver.ResolveImport(name, out file);
if (result == sunImportResult.Loaded) {
try {
ImportResolver.EnterFile(file);
var parser = new sunParser();
var tree = parser.Parse(file);
tree.Compile(this);
ImportResolver.ExitFile(file);
}
finally {
file.Dispose();
}
}
return result;
}
// callables
public sunBuiltinSymbol DeclareBuiltin(sunBuiltinDeclaration node) {
if (SymbolTable.Callables.Any(i => i.Name == node.Builtin.Value)) {
throw new sunRedeclaredBuiltinException(node);
}
var symbol = new sunBuiltinSymbol(node.Builtin.Value, node.Parameters.ParameterInfo, SymbolTable.Count);
SymbolTable.Add(symbol);
return symbol;
}
public sunFunctionSymbol DefineFunction(sunFunctionDefinition node) {
if (node.Parameters.IsVariadic) {
throw new sunVariadicFunctionException(node);
}
if (SymbolTable.Callables.Any(i => i.Name == node.Function.Value)) {
throw new sunRedefinedFunctionException(node);
}
var symbol = new sunFunctionSymbol(node.Function.Value, node.Parameters.ParameterInfo, node.Body);
SymbolTable.Add(symbol);
return symbol;
}
public sunCallableSymbol ResolveCallable(sunFunctionCall node) {
var symbol = SymbolTable.Callables.FirstOrDefault(i => i.Name == node.Function.Value);
if (symbol == null) {
throw new sunUndefinedFunctionException(node);
}
return symbol;
}
public sunCallableSymbol MustResolveCallable(sunFunctionCall node) {
var symbol = ResolveCallable(node);
if (symbol == null) {
throw new sunUndefinedFunctionException(node);
}
return symbol;
}
// storables
public sunVariableSymbol DeclareVariable(sunIdentifier node) {
#if SSC_PACK_VARS
if (Scopes.Top.GetIsDeclared(node.Value)) {
throw new sunRedeclaredVariableException(node);
}
#else
if (Scopes.Any(i => i.GetIsDeclared(node.Value))) {
throw new sunRedeclaredVariableException(node);
}
#endif
var symbol = Scopes.DeclareVariable(node.Value);
if (Scopes.Top.Type == sunScopeType.Script) { // global-scope variables are added to the symbol table
#if SSC_PACK_VARS
// only add the variable symbol if there isn't one with this index already
if (!SymbolTable.Variables.Any(i => i.Index == symbol.Index)) {
SymbolTable.Add(new sunVariableSymbol(String.Format("global{0}", symbol.Index), symbol.Display, symbol.Index));
}
#else
SymbolTable.Add(symbol);
#endif
}
return symbol;
}
public sunConstantSymbol DeclareConstant(sunIdentifier node, sunExpression expression) {
#if SSC_PACK_VARS
if (Scopes.Top.GetIsDeclared(node.Value)) {
throw new sunRedeclaredVariableException(node);
}
#else
if (Scopes.Any(i => i.GetIsDeclared(node.Value))) {
throw new sunRedeclaredVariableException(node);
}
#endif
return Scopes.DeclareConstant(node.Value, expression);
}
public sunStorableSymbol ResolveStorable(sunIdentifier node) {
for (int i = Scopes.Count - 1; i >= 0; --i) {
var symbol = Scopes[i].ResolveStorable(node.Value);
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;
}
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;
}
sunCallableSymbol AddSystemBuiltin(string name) {
var symbol = new sunBuiltinSymbol(name, SymbolTable.Count);
SymbolTable.Add(symbol);
return symbol;
}
void WriteHeader() {
mWriter.WriteString("SPCB");
mWriter.Write32(mTextOffset);
mWriter.Write32(mDataOffset);
mWriter.WriteS32(DataTable.Count);
mWriter.Write32(mSymbolOffset);
mWriter.WriteS32(SymbolTable.Count);
mWriter.WriteS32(SymbolTable.VariableCount);
}
}
}