ssc/ssc/context.cs
2015-12-27 22:48:44 -05:00

278 lines
7.1 KiB
C#

using arookas.IO.Binary;
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace arookas
{
class sunContext
{
bool mOpen;
aBinaryWriter mWriter;
uint mTextOffset, mDataOffset, mSymbolOffset;
int mVarCount;
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; }
public sunContext()
{
DataTable = new sunDataTable();
SymbolTable = new sunSymbolTable();
Scopes = new sunScopeStack();
Loops = new sunLoopStack();
}
// 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();
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
DeclareSystemBuiltin("yield", false);
DeclareSystemBuiltin("exit", false);
DeclareSystemBuiltin("dump", false);
DeclareSystemBuiltin("lock", false);
DeclareSystemBuiltin("unlock", false);
DeclareSystemBuiltin("int", false, "x");
DeclareSystemBuiltin("float", false, "x");
DeclareSystemBuiltin("typeof", false, "x");
DeclareSystemBuiltin("print", true);
}
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);
mVarCount += tree.MaxLocalCount;
tree.Compile(this);
ImportResolver.ExitFile(file);
}
finally
{
file.Dispose();
}
}
return result;
}
// callables
public sunBuiltinSymbol DeclareBuiltin(sunBuiltinDeclaration node)
{
var symbolInfo = SymbolTable.Callables.FirstOrDefault(f => f.Name == node.Builtin.Value);
if (symbolInfo != null)
{
throw new sunRedeclaredBuiltinException(node);
}
var builtinInfo = new sunBuiltinSymbol(node.Builtin.Value, node.Parameters.ParameterInfo, SymbolTable.Count);
SymbolTable.Add(builtinInfo);
return builtinInfo;
}
public sunFunctionSymbol DefineFunction(sunFunctionDefinition node)
{
if (node.Parameters.IsVariadic)
{
throw new sunVariadicFunctionException(node);
}
var symbolInfo = SymbolTable.Callables.FirstOrDefault(f => f.Name == node.Function.Value);
if (symbolInfo != null)
{
throw new sunRedefinedFunctionException(node);
}
var functionInfo = new sunFunctionSymbol(node.Function.Value, node.Parameters.ParameterInfo, node.Body);
SymbolTable.Add(functionInfo);
return functionInfo;
}
public sunCallableSymbol ResolveCallable(sunFunctionCall node)
{
var symbol = SymbolTable.Callables.FirstOrDefault(f => f.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;
}
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.GetIsDeclared(node.Value))
{
throw new sunRedeclaredVariableException(node);
}
var variableInfo = Scopes.DeclareVariable(node.Value);
return variableInfo;
}
public sunConstantSymbol DeclareConstant(sunIdentifier node, sunExpression expression)
{
if (Scopes.Top.GetIsDeclared(node.Value))
{
throw new sunRedeclaredVariableException(node);
}
var constInfo = Scopes.Top.DeclareConstant(node.Value, expression);
return constInfo;
}
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)
{
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;
}
void WriteHeader()
{
mWriter.WriteString("SPCB");
mWriter.Write32(mTextOffset);
mWriter.Write32(mDataOffset);
mWriter.WriteS32(DataTable.Count);
mWriter.Write32(mSymbolOffset);
mWriter.WriteS32(SymbolTable.Count);
mWriter.WriteS32(mVarCount);
}
}
}