diff --git a/smnp/environment/environment.py b/smnp/environment/environment.py index 0433056..fff3799 100644 --- a/smnp/environment/environment.py +++ b/smnp/environment/environment.py @@ -6,13 +6,14 @@ from smnp.type.model import Type class Environment(): - def __init__(self, scopes, functions, methods): + def __init__(self, scopes, functions, methods, source): self.scopes = scopes self.functions = functions self.methods = methods self.customFunctions = [] self.customMethods = [] self.callStack = [] + self.source = source def invokeMethod(self, object, name, args): builtinMethodResult = self._invokeBuiltinMethod(object, name, args) diff --git a/smnp/environment/factory.py b/smnp/environment/factory.py index ede8e66..32ae6ce 100644 --- a/smnp/environment/factory.py +++ b/smnp/environment/factory.py @@ -1,7 +1,3 @@ -from smnp.environment.environment import Environment -from smnp.module import functions, methods - - def createEnvironment(): - return Environment([{}], functions, methods) + return diff --git a/smnp/error/base.py b/smnp/error/base.py index f5413ef..cf593b4 100644 --- a/smnp/error/base.py +++ b/smnp/error/base.py @@ -2,6 +2,7 @@ class SmnpException(Exception): def __init__(self, msg, pos): self.msg = msg self.pos = pos + self.file = None def _title(self): pass @@ -10,7 +11,10 @@ class SmnpException(Exception): return "" def _position(self): - return "" if self.pos is None else f" [line {self.pos[0]+1}, col {self.pos[1]+1}]" + return "" if self.pos is None else f"[line {self.pos[0]+1}, col {self.pos[1]+1}]" + + def _file(self): + return "" if self.file is None else f"File: {self.file}" def message(self): - return f"{self._title()}{self._position()}:\n{self.msg}\n{self._postMessage()}" + return f"{self._title()}\n{self._file()} {self._position()}\n\n{self.msg}\n{self._postMessage()}" diff --git a/smnp/error/custom.py b/smnp/error/custom.py index d9f6def..0b35f50 100644 --- a/smnp/error/custom.py +++ b/smnp/error/custom.py @@ -1,9 +1,12 @@ -from smnp.error.base import SmnpException +from smnp.error.runtime import RuntimeException -class CustomException(SmnpException): +class CustomException(RuntimeException): def __init__(self, message, pos): super().__init__(message, pos) def _title(self): return "Execution Error" + + def _postMessage(self): + return "\n" + self.environment.callStackToString() if len(self.environment.callStack) > 0 else "" \ No newline at end of file diff --git a/smnp/library/loader.py b/smnp/library/loader.py index c40f6f4..bb4e377 100644 --- a/smnp/library/loader.py +++ b/smnp/library/loader.py @@ -5,5 +5,5 @@ from smnp.program.interpreter import Interpreter def loadStandardLibrary(): mainSource = resource_string('smnp.library.code', 'main.mus').decode("utf-8") - env = Interpreter.interpretString(mainSource) + env = Interpreter.interpretString(mainSource, "") return env diff --git a/smnp/program/interpreter.py b/smnp/program/interpreter.py index 7bbe79e..2a6dcc9 100644 --- a/smnp/program/interpreter.py +++ b/smnp/program/interpreter.py @@ -1,6 +1,7 @@ from smnp.ast.parser import parse -from smnp.environment.factory import createEnvironment +from smnp.environment.environment import Environment from smnp.error.runtime import RuntimeException +from smnp.module import functions, methods from smnp.program.FileReader import readLines from smnp.runtime.evaluator import evaluate from smnp.token.tokenizer import tokenize @@ -9,16 +10,31 @@ from smnp.token.tokenizer import tokenize class Interpreter: @staticmethod - def interpretString(string, printTokens=False, printAst=False, execute=True, baseEnvironment=None): - return Interpreter._interpret(string.splitlines(), printTokens, printAst, execute, baseEnvironment) + def interpretString(string, source, printTokens=False, printAst=False, execute=True, baseEnvironment=None): + return Interpreter._interpret( + string.splitlines(), + source, + printTokens, + printAst, + execute, + baseEnvironment, + ) @staticmethod - def interpretFile(file, printTokens=False, printAst=False, execute=True, baseEnvironment=None): - return Interpreter._interpret(readLines(file), printTokens, printAst, execute, baseEnvironment) + def interpretFile(file, printTokens=False, printAst=False, execute=True, baseEnvironment=None, source=None): + return Interpreter._interpret( + readLines(file), + source if source is not None else file, + printTokens, + printAst, + execute, + baseEnvironment, + ) @staticmethod - def _interpret(lines, printTokens=False, printAst=False, execute=True, baseEnvironment=None): - environment = createEnvironment() + def _interpret(lines, source, printTokens=False, printAst=False, execute=True, baseEnvironment=None): + environment = Environment([{}], functions, methods, source=source) + if baseEnvironment is not None: environment.extend(baseEnvironment) @@ -37,4 +53,5 @@ class Interpreter: return environment except RuntimeException as e: e.environment = environment + e.file = environment.source raise e \ No newline at end of file