Moved local identifiers to resolver and AST

Now the local identifier is associated with each node so symbols in
function bodies (which are compiled long after the associated
sunScriptFile instances are closed) can be mangled correctly.
This commit is contained in:
arookas 2016-02-01 19:17:56 -05:00
parent 04aba6938b
commit 675f2ab4a7
6 changed files with 161 additions and 85 deletions

View file

@ -31,7 +31,7 @@ namespace arookas
else {
if (results.Error is sunSourceException) {
var error = results.Error as sunSourceException;
Error(" in file \"{0}\"\n at line {1}, col {2}\n\n{3}{4}", error.Location.File, error.Location.Line, error.Location.Column, GetErrorPreview(error.Location), error.Message);
Error(" in file \"{0}\"\n at line {1}, col {2}\n\n{3}{4}", error.Location.ScriptName, error.Location.Line, error.Location.Column, GetErrorPreview(error.Location), error.Message);
exitCode = 1;
}
else {
@ -107,7 +107,7 @@ namespace arookas
static string GetErrorPreview(sunSourceLocation location) {
Stream file;
try {
file = File.OpenRead(location.File);
file = File.OpenRead(location.ScriptName);
}
catch {
// simply don't do a preview if opening a file fails

View file

@ -4,20 +4,36 @@ using System.Collections.Generic;
namespace arookas {
public class sunSourceLocation {
public string File { get; private set; }
public int Line { get; private set; }
public int Column { get; private set; }
string mScriptName;
ulong mScriptId;
int mLine, mColumn;
public sunSourceLocation(string file, int line, int column) {
public string ScriptName {
get { return mScriptName; }
}
public ulong ScriptId {
get { return mScriptId; }
}
public int Line {
get { return mLine; }
}
public int Column {
get { return mColumn; }
}
public sunSourceLocation(string file, ulong id, int line, int column) {
if (file == null) {
throw new ArgumentNullException("file");
}
File = file;
Line = line;
Column = column;
mScriptName = file;
mScriptId = id;
mLine = line;
mColumn = column;
}
public override string ToString() { return String.Format("\"{0}\", ({1},{2})", File, Line, Column); }
public override string ToString() {
return String.Format("\"{0}\", ({1},{2})", mScriptName, mLine, mColumn);
}
}
class sunNode : IEnumerable<sunNode> {

View file

@ -53,7 +53,8 @@ namespace arookas {
return symbol;
}
public sunFunctionSymbol DefineFunction(sunFunctionDefinition node) {
var name = MangleSymbolName(node.Name.Value, false, (node.Modifiers & sunSymbolModifiers.Local) != 0);
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);
}
@ -64,9 +65,10 @@ namespace arookas {
SymbolTable.Add(symbol);
return symbol;
}
public sunCallableSymbol ResolveCallable(sunFunctionCall node) {
var global = node.Name.Value;
var local = MangleSymbolName(global, false, true);
var local = MangleSymbolName(global, node.Location.ScriptId, false, true);
var symbol = SymbolTable.Callables.FirstOrDefault(i => i.Name == local);
if (symbol != null) {
return symbol;
@ -77,6 +79,7 @@ namespace arookas {
}
return null;
}
public sunCallableSymbol MustResolveCallable(sunFunctionCall node) {
var symbol = ResolveCallable(node);
if (symbol == null) {
@ -94,7 +97,7 @@ namespace arookas {
}
sunVariableSymbol DeclareVariable(sunIdentifier node, sunSymbolModifiers modifiers) {
var local = (modifiers & sunSymbolModifiers.Local) != 0;
var name = MangleSymbolName(node.Value, false, local);
var name = MangleSymbolName(node.Value, node.Location.ScriptId, false, local);
if (Scopes.Any(i => i.GetIsDeclared(name))) {
throw new sunRedeclaredVariableException(node);
}
@ -109,15 +112,16 @@ namespace arookas {
}
sunConstantSymbol DeclareConstant(sunIdentifier node, sunExpression expression, sunSymbolModifiers modifiers) {
var local = (modifiers & sunSymbolModifiers.Local) != 0;
var name = MangleSymbolName(node.Value, false, local);
var name = MangleSymbolName(node.Value, node.Location.ScriptId, false, local);
if (Scopes.Any(i => i.GetIsDeclared(name))) {
throw new sunRedeclaredVariableException(node);
}
return Scopes.DeclareConstant(name, expression);
}
public sunStorableSymbol ResolveStorable(sunIdentifier node) {
var global = node.Value;
var local = MangleSymbolName(global, false, true);
var local = MangleSymbolName(global, node.Location.ScriptId, false, true);
var symbol = ResolveStorable(local);
if (symbol != null) {
return symbol;
@ -143,6 +147,7 @@ namespace arookas {
public sunConstantSymbol ResolveConstant(sunIdentifier node) {
return ResolveStorable(node) as sunConstantSymbol;
}
public sunStorableSymbol MustResolveStorable(sunIdentifier node) {
var symbol = ResolveStorable(node);
if (symbol == null) {
@ -196,7 +201,7 @@ namespace arookas {
return symbol;
}
sunStorableSymbol AddSystemVariable(string name) {
var symbol = Scopes.DeclareVariable(MangleSymbolName(name, true, false));
var symbol = Scopes.DeclareVariable(MangleSystemSymbol(name));
SymbolTable.Add(symbol);
return symbol;
}

View file

@ -4,36 +4,29 @@ using System;
namespace arookas {
// base exception type
public class sunCompilerException : Exception {
public sunCompilerException() {
}
public sunCompilerException() { }
public sunCompilerException(string format, params object[] args)
: base(String.Format(format, args)) { }
}
// exceptions that have a location in the source
public abstract class sunSourceException : sunCompilerException {
public abstract sunSourceLocation Location { get; }
public sunSourceException() {
}
public sunSourceException(string format, params object[] args)
: base(format, args) { }
}
public class sunImportException : sunCompilerException {
public string Name { get; private set; }
public sunImportResult Result { get; private set; }
string mName;
sunImportResult mResult;
public string Name {
get { return mName; }
}
public sunImportResult Result {
get { return mResult; }
}
public override string Message {
get {
string format;
var format = "Name: {0}, Result: {1}";
switch (Result) {
case sunImportResult.Loaded: format = "Script '{0}' loaded successfully."; break; // Error: Success!
case sunImportResult.Skipped: format = "Script '{0}' was skipped."; break;
case sunImportResult.Missing: format = "Script '{0}' could not be found."; break;
case sunImportResult.FailedToLoad: format = "Script '{0}' failed to load."; break;
default: format = "Name: {0}, Result: {1}"; break;
case sunImportResult.Loaded: format = "Script '{0}' loaded successfully."; break; // Error: Success!
case sunImportResult.Skipped: format = "Script '{0}' was skipped."; break;
case sunImportResult.Missing: format = "Script '{0}' could not be found."; break;
case sunImportResult.FailedToLoad: format = "Script '{0}' failed to load."; break;
}
return String.Format(format, Name, Result);
}
@ -46,106 +39,152 @@ namespace arookas {
if (!result.IsDefined()) {
throw new ArgumentOutOfRangeException("name");
}
Name = name;
Result = result;
mName = name;
mResult = result;
}
}
// exceptions that have a location in the source
public abstract class sunSourceException : sunCompilerException {
public abstract sunSourceLocation Location { get; }
public sunSourceException() { }
public sunSourceException(string format, params object[] args)
: base(format, args) { }
}
// wrapper around Grammatica exceptions
class sunParserException : sunSourceException {
string file;
string mFile;
ulong mId;
ParseException mInfo;
public ParseException Info { get; private set; }
public override string Message { get { return Info.ErrorMessage; } }
public override sunSourceLocation Location { get { return new sunSourceLocation(file, Info.Line, Info.Column); } }
public ParseException Info {
get { return mInfo; }
}
public override string Message {
get { return Info.ErrorMessage; }
}
public override sunSourceLocation Location {
get { return new sunSourceLocation(mFile, mId, Info.Line, Info.Column); }
}
public sunParserException(string file, ParseException info) {
public sunParserException(string file, ulong id, ParseException info) {
if (file == null) {
throw new ArgumentNullException("file");
}
if (info == null) {
throw new ArgumentNullException("info");
}
this.file = file;
Info = info;
mFile = file;
mId = id;
mInfo = info;
}
}
// node exceptions
abstract class sunNodeException<TNode> : sunSourceException where TNode : sunNode {
public TNode Node { get; private set; }
public override sunSourceLocation Location { get { return Node.Location; } }
TNode mNode;
public TNode Node {
get { return mNode; }
}
public override sunSourceLocation Location {
get { return mNode.Location; }
}
protected sunNodeException(TNode node) {
if (node == null) {
throw new ArgumentNullException("node");
}
Node = node;
mNode = node;
}
}
class sunRedeclaredBuiltinException : sunNodeException<sunBuiltinDeclaration> {
public override string Message { get { return String.Format("Redeclared builtin '{0}'.", Node.Name.Value); } }
public override string Message {
get { return String.Format("Redeclared builtin '{0}'.", Node.Name.Value); }
}
public sunRedeclaredBuiltinException(sunBuiltinDeclaration node)
: base(node) { }
}
class sunUndefinedFunctionException : sunNodeException<sunFunctionCall> {
public override string Message { get { return String.Format("Undefined function or builtin '{0}'.", Node.Name.Value); } }
public override string Message {
get { return String.Format("Undefined function or builtin '{0}'.", Node.Name.Value); }
}
public sunUndefinedFunctionException(sunFunctionCall node)
: base(node) { }
}
class sunRedefinedFunctionException : sunNodeException<sunFunctionDefinition> {
public override string Message { get { return String.Format("Redefined function '{0}'.", Node.Name.Value); } }
public override string Message {
get { return String.Format("Redefined function '{0}'.", Node.Name.Value); }
}
public sunRedefinedFunctionException(sunFunctionDefinition node)
: base(node) { }
}
class sunUndeclaredVariableException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Undeclared variable '{0}'.", Node.Value); } }
public override string Message {
get { return String.Format("Undeclared variable '{0}'.", Node.Value); }
}
public sunUndeclaredVariableException(sunIdentifier node)
: base(node) { }
}
class sunRedeclaredVariableException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Redeclared variable '{0}'.", Node.Value); } }
public override string Message {
get { return String.Format("Redeclared variable '{0}'.", Node.Value); }
}
public sunRedeclaredVariableException(sunIdentifier node)
: base(node) { }
}
class sunAssignConstantException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Constant '{0}' is read-only.", Node.Value); } }
public override string Message {
get { return String.Format("Constant '{0}' is read-only.", Node.Value); }
}
public sunAssignConstantException(sunIdentifier node)
: base(node) { }
}
class sunConstantExpressionException : sunNodeException<sunNode> {
public override string Message { get { return "Expression must be constant."; } }
public override string Message {
get { return "Expression must be constant."; }
}
public sunConstantExpressionException(sunNode node)
: base(node) { }
}
class sunRedeclaredParameterException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Redeclared parameter '{0}'.", Node.Value); } }
public override string Message {
get { return String.Format("Redeclared parameter '{0}'.", Node.Value); }
}
public sunRedeclaredParameterException(sunIdentifier node)
: base(node) { }
}
class sunVariadicFunctionException : sunNodeException<sunFunctionDefinition> {
public override string Message { get { return String.Format("Function '{0}' is defined as a variadic function (only builtins may be variadic).", Node.Name.Value); } }
public override string Message {
get { return String.Format("Function '{0}' is defined as a variadic function (only builtins may be variadic).", Node.Name.Value); }
}
public sunVariadicFunctionException(sunFunctionDefinition node)
: base(node) { }
}
class sunEscapeSequenceException : sunNodeException<sunStringLiteral> {
public override string Message { get { return String.Format("Bad escape sequence in string."); } }
public override string Message {
get { return String.Format("Bad escape sequence in string."); }
}
public sunEscapeSequenceException(sunStringLiteral node)
: base(node) { }
}
class sunVariadicParameterListException : sunNodeException<sunParameterList> {
public override string Message { get { return String.Format("Bad variadic parameter list."); } }
public override string Message {
get { return String.Format("Bad variadic parameter list."); }
}
public sunVariadicParameterListException(sunParameterList node)
: base(node) { }
@ -181,25 +220,33 @@ namespace arookas {
}
}
class sunIdentifierException : sunNodeException<sunIdentifier> {
public override string Message { get { return String.Format("Invalid identifier '{0}'.", Node.Value); } }
public override string Message {
get { return String.Format("Invalid identifier '{0}'.", Node.Value); }
}
public sunIdentifierException(sunIdentifier node)
: base(node) { }
}
class sunMissingImportException : sunNodeException<sunImport> {
public override string Message { get { return String.Format("Could not find import file '{0}'.", Node.ImportFile.Value); } }
public override string Message {
get { return String.Format("Could not find import file '{0}'.", Node.ImportFile.Value); }
}
public sunMissingImportException(sunImport node)
: base(node) { }
}
class sunBreakException : sunNodeException<sunBreak> {
public override string Message { get { return "Misplaced break statement."; } }
public override string Message {
get { return "Misplaced break statement."; }
}
public sunBreakException(sunBreak node)
: base(node) { }
}
class sunContinueException : sunNodeException<sunContinue> {
public override string Message { get { return "Misplaced continue statement."; } }
public override string Message {
get { return "Misplaced continue statement."; }
}
public sunContinueException(sunContinue node)
: base(node) { }

View file

@ -18,6 +18,7 @@ namespace arookas {
List<sunScriptFile> mImports;
Stack<sunScriptFile> mFiles;
string mRootDirectory, mCurrentDirectory;
ulong mFileId;
string CurrentDirectory {
get {
@ -64,7 +65,7 @@ namespace arookas {
return sunImportResult.Skipped;
}
try {
file = new sunScriptFile(path, File.OpenRead(path));
file = new sunScriptFile(path, File.OpenRead(path), mFileId++);
}
catch {
return sunImportResult.FailedToLoad;
@ -85,6 +86,7 @@ namespace arookas {
public class sunScriptFile : IDisposable {
string mName;
Stream mStream;
ulong mId;
public string Name {
get { return mName; }
@ -92,8 +94,11 @@ namespace arookas {
public Stream Stream {
get { return mStream; }
}
public ulong Id {
get { return mId; }
}
public sunScriptFile(string name, Stream stream) {
public sunScriptFile(string name, Stream stream, ulong id) {
if (name == null) {
throw new ArgumentNullException("name");
}
@ -105,6 +110,7 @@ namespace arookas {
}
mName = name;
mStream = stream;
mId = id;
}
public void Dispose() {

View file

@ -12,35 +12,37 @@ namespace arookas {
"true", "false",
};
__sunParser mParser;
sunScriptFile mFile;
public sunNode Parse(sunScriptFile file) {
using (var input = file.CreateReader()) {
mFile = file;
using (var input = mFile.CreateReader()) {
try {
var parser = new __sunParser(input);
var node = parser.Parse();
return CreateAst(file.Name, node);
mParser = new __sunParser(input);
var node = mParser.Parse();
return CreateAst(node);
}
catch (ParserLogException ex) {
throw new sunParserException(file.Name, ex[0]);
throw new sunParserException(file.Name, mFile.Id, ex[0]);
}
}
}
static sunNode CreateAst(string file, Node node) {
var ast = ConvertNode(file, node);
sunNode CreateAst(Node node) {
var ast = ConvertNode(node);
if (ast == null) {
return null;
}
// children
if (node is Production) {
var production = node as Production;
for (int i = 0; i < production.Count; ++i) {
var child = CreateAst(file, production[i]);
var child = CreateAst(production[i]);
if (child != null) {
ast.Add(child);
}
}
}
// transcience
if (ast.Count == 1) {
switch (GetId(node)) {
case __sunConstants.ROOT_STATEMENT:
@ -59,10 +61,10 @@ namespace arookas {
}
return ast;
}
static sunNode ConvertNode(string file, Node node) {
sunNode ConvertNode(Node node) {
var id = GetId(node);
var parent = GetId(node.Parent);
var location = new sunSourceLocation(file, node.StartLine, node.StartColumn);
var location = new sunSourceLocation(mFile.Name, mFile.Id, node.StartLine, node.StartColumn);
var token = "";
if (node is Token) {
token = (node as Token).Image;
@ -102,11 +104,11 @@ namespace arookas {
switch (id) {
case __sunConstants.ADD: return new sunAdd(location);
case __sunConstants.SUB: {
if (parent == __sunConstants.UNARY_OPERATOR) {
return new sunNeg(location);
if (parent == __sunConstants.UNARY_OPERATOR) {
return new sunNeg(location);
}
return new sunSub(location);
}
return new sunSub(location);
}
case __sunConstants.MUL: return new sunMul(location);
case __sunConstants.DIV: return new sunDiv(location);
case __sunConstants.MOD: return new sunMod(location);
@ -213,8 +215,8 @@ namespace arookas {
switch (parent) {
case __sunConstants.FUNCTION_MODIFIERS:
case __sunConstants.BUILTIN_MODIFIERS: {
return new sunConstKeyword(location);
}
return new sunConstKeyword(location);
}
}
}
if (id == __sunConstants.LOCAL) {