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 { else {
if (results.Error is sunSourceException) { if (results.Error is sunSourceException) {
var error = results.Error as 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; exitCode = 1;
} }
else { else {
@ -107,7 +107,7 @@ namespace arookas
static string GetErrorPreview(sunSourceLocation location) { static string GetErrorPreview(sunSourceLocation location) {
Stream file; Stream file;
try { try {
file = File.OpenRead(location.File); file = File.OpenRead(location.ScriptName);
} }
catch { catch {
// simply don't do a preview if opening a file fails // simply don't do a preview if opening a file fails

View file

@ -4,20 +4,36 @@ using System.Collections.Generic;
namespace arookas { namespace arookas {
public class sunSourceLocation { public class sunSourceLocation {
public string File { get; private set; } string mScriptName;
public int Line { get; private set; } ulong mScriptId;
public int Column { get; private set; } 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) { if (file == null) {
throw new ArgumentNullException("file"); throw new ArgumentNullException("file");
} }
File = file; mScriptName = file;
Line = line; mScriptId = id;
Column = column; 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> { class sunNode : IEnumerable<sunNode> {

View file

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

View file

@ -4,36 +4,29 @@ using System;
namespace arookas { namespace arookas {
// base exception type // base exception type
public class sunCompilerException : Exception { public class sunCompilerException : Exception {
public sunCompilerException() { public sunCompilerException() { }
}
public sunCompilerException(string format, params object[] args) public sunCompilerException(string format, params object[] args)
: base(String.Format(format, 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 class sunImportException : sunCompilerException {
public string Name { get; private set; } string mName;
public sunImportResult Result { get; private set; } sunImportResult mResult;
public string Name {
get { return mName; }
}
public sunImportResult Result {
get { return mResult; }
}
public override string Message { public override string Message {
get { get {
string format; var format = "Name: {0}, Result: {1}";
switch (Result) { switch (Result) {
case sunImportResult.Loaded: format = "Script '{0}' loaded successfully."; break; // Error: Success! case sunImportResult.Loaded: format = "Script '{0}' loaded successfully."; break; // Error: Success!
case sunImportResult.Skipped: format = "Script '{0}' was skipped."; break; case sunImportResult.Skipped: format = "Script '{0}' was skipped."; break;
case sunImportResult.Missing: format = "Script '{0}' could not be found."; break; case sunImportResult.Missing: format = "Script '{0}' could not be found."; break;
case sunImportResult.FailedToLoad: format = "Script '{0}' failed to load."; break; case sunImportResult.FailedToLoad: format = "Script '{0}' failed to load."; break;
default: format = "Name: {0}, Result: {1}"; break;
} }
return String.Format(format, Name, Result); return String.Format(format, Name, Result);
} }
@ -46,106 +39,152 @@ namespace arookas {
if (!result.IsDefined()) { if (!result.IsDefined()) {
throw new ArgumentOutOfRangeException("name"); throw new ArgumentOutOfRangeException("name");
} }
Name = name; mName = name;
Result = result; 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 // wrapper around Grammatica exceptions
class sunParserException : sunSourceException { class sunParserException : sunSourceException {
string file; string mFile;
ulong mId;
ParseException mInfo;
public ParseException Info { get; private set; } public ParseException Info {
public override string Message { get { return Info.ErrorMessage; } } get { return mInfo; }
public override sunSourceLocation Location { get { return new sunSourceLocation(file, Info.Line, Info.Column); } } }
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) { if (file == null) {
throw new ArgumentNullException("file"); throw new ArgumentNullException("file");
} }
if (info == null) { if (info == null) {
throw new ArgumentNullException("info"); throw new ArgumentNullException("info");
} }
this.file = file; mFile = file;
Info = info; mId = id;
mInfo = info;
} }
} }
// node exceptions // node exceptions
abstract class sunNodeException<TNode> : sunSourceException where TNode : sunNode { abstract class sunNodeException<TNode> : sunSourceException where TNode : sunNode {
public TNode Node { get; private set; } TNode mNode;
public override sunSourceLocation Location { get { return Node.Location; } }
public TNode Node {
get { return mNode; }
}
public override sunSourceLocation Location {
get { return mNode.Location; }
}
protected sunNodeException(TNode node) { protected sunNodeException(TNode node) {
if (node == null) { if (node == null) {
throw new ArgumentNullException("node"); throw new ArgumentNullException("node");
} }
Node = node; mNode = node;
} }
} }
class sunRedeclaredBuiltinException : sunNodeException<sunBuiltinDeclaration> { 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) public sunRedeclaredBuiltinException(sunBuiltinDeclaration node)
: base(node) { } : base(node) { }
} }
class sunUndefinedFunctionException : sunNodeException<sunFunctionCall> { 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) public sunUndefinedFunctionException(sunFunctionCall node)
: base(node) { } : base(node) { }
} }
class sunRedefinedFunctionException : sunNodeException<sunFunctionDefinition> { 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) public sunRedefinedFunctionException(sunFunctionDefinition node)
: base(node) { } : base(node) { }
} }
class sunUndeclaredVariableException : sunNodeException<sunIdentifier> { 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) public sunUndeclaredVariableException(sunIdentifier node)
: base(node) { } : base(node) { }
} }
class sunRedeclaredVariableException : sunNodeException<sunIdentifier> { 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) public sunRedeclaredVariableException(sunIdentifier node)
: base(node) { } : base(node) { }
} }
class sunAssignConstantException : sunNodeException<sunIdentifier> { 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) public sunAssignConstantException(sunIdentifier node)
: base(node) { } : base(node) { }
} }
class sunConstantExpressionException : sunNodeException<sunNode> { 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) public sunConstantExpressionException(sunNode node)
: base(node) { } : base(node) { }
} }
class sunRedeclaredParameterException : sunNodeException<sunIdentifier> { 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) public sunRedeclaredParameterException(sunIdentifier node)
: base(node) { } : base(node) { }
} }
class sunVariadicFunctionException : sunNodeException<sunFunctionDefinition> { 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) public sunVariadicFunctionException(sunFunctionDefinition node)
: base(node) { } : base(node) { }
} }
class sunEscapeSequenceException : sunNodeException<sunStringLiteral> { 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) public sunEscapeSequenceException(sunStringLiteral node)
: base(node) { } : base(node) { }
} }
class sunVariadicParameterListException : sunNodeException<sunParameterList> { 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) public sunVariadicParameterListException(sunParameterList node)
: base(node) { } : base(node) { }
@ -181,25 +220,33 @@ namespace arookas {
} }
} }
class sunIdentifierException : sunNodeException<sunIdentifier> { 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) public sunIdentifierException(sunIdentifier node)
: base(node) { } : base(node) { }
} }
class sunMissingImportException : sunNodeException<sunImport> { 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) public sunMissingImportException(sunImport node)
: base(node) { } : base(node) { }
} }
class sunBreakException : sunNodeException<sunBreak> { 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) public sunBreakException(sunBreak node)
: base(node) { } : base(node) { }
} }
class sunContinueException : sunNodeException<sunContinue> { 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) public sunContinueException(sunContinue node)
: base(node) { } : base(node) { }

View file

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

View file

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