diff --git a/Example.txt b/Example.txt index 963eecb..2dfad8b 100644 --- a/Example.txt +++ b/Example.txt @@ -1 +1 @@ -say my name (1gm+2gm); \ No newline at end of file +say my name (1gm+"Heisenberg"); \ No newline at end of file diff --git a/Interpreter.py b/Interpreter.py index 78fcd16..6836214 100644 --- a/Interpreter.py +++ b/Interpreter.py @@ -1,12 +1,12 @@ from Stmt import * from Expr import * -from typing import Any +from typing import Tuple,Any from TokenType import TokenType class JesseRuntimeError(RuntimeError): - def __init__(self, line: int, message: str) -> None: + def __init__(self, pos: Tuple[int], message: str) -> None: super().__init__(message) - self.line = line + self.pos = pos class Interpreter: ''' @@ -14,15 +14,20 @@ class Interpreter: It implements all the visitor methods for the AST nodes. ''' - def __init__(self, jesse) -> None: + def __init__(self, jesse:object,source:str) -> None: self.jesse = jesse + self.source = source + self.lines = source.splitlines() + def interpret(self, statements: List[Stmt]) -> None: try: for statement in statements: self.execute(statement) except JesseRuntimeError as error: - self.jesse.runtime_error(error) + pos = error.pos + code = self.lines[pos[0] - 1] + self.jesse.runtime_error(code,pos,error) def visit_literal_expr(self, expr: Literal) -> Any: return expr.value @@ -42,12 +47,12 @@ def visit_unary_expr(self, expr: Unary) -> Any: def check_number_operand(self, operator: Token, operand: Any) -> None: if isinstance(operand, float): return - raise JesseRuntimeError(operator.pos[0], "Operand must be a number.") + raise JesseRuntimeError(operator.pos, "operands must be a numbers, its basic math yo") def check_number_operands(self, operator: Token, left: Any, right: Any) -> None: if isinstance(left, float) and isinstance(right, float): return - raise JesseRuntimeError(operator.pos[0], "Operands must be numbers.") + raise JesseRuntimeError(operator.pos, "operands must be numbers, its basic math yo") def is_truthy(self, obj: Any) -> bool: if obj is None: @@ -111,7 +116,7 @@ def visit_binary_expr(self, expr: Binary) -> Any: return left + right if isinstance(left, str) and isinstance(right, str): return left + right - raise JesseRuntimeError(expr.operator.pos[0], "Operands must be two numbers or two strings.") + raise JesseRuntimeError(expr.operator.pos, "operands must be two numbers or two strings yo") elif expr.operator.token_type == TokenType.GREATER: self.check_number_operands(expr.operator, left, right) return left > right diff --git a/Jesse.py b/Jesse.py index 3d6a1b0..ad740b4 100644 --- a/Jesse.py +++ b/Jesse.py @@ -23,7 +23,7 @@ def run(self, source: str) -> None: return parser = Parser(self,source,tokens) statements = parser.parse() - interpreter = Interpreter(self) + interpreter = Interpreter(self,source) interpreter.interpret(statements) def run_file(self, path: str) -> None: @@ -49,8 +49,10 @@ def run_prompt(self) -> None: def error(self, code:str, pos: Tuple[int,int], message: str) -> None: self.report_error(code,pos, message) - def runtime_error(self, error: RuntimeError) -> None: - print(f'[Runtime Error] {error}') + def runtime_error(self, code:str, pos: Tuple[int,int], error: RuntimeError) -> None: + print(code) + print(" " * pos[1] + '^' + '-'*(len(code) - pos[1] - 1)) + print(f'[Runtime Error {pos[0]}] mr white {error}') self.had_runtime_error = True def report_error(self, code:str, pos: Tuple[int,int], message: str) -> None: diff --git a/Scanner.py b/Scanner.py index 4836db9..ea2b2c8 100644 --- a/Scanner.py +++ b/Scanner.py @@ -130,13 +130,12 @@ def scan_tokens(self) -> List[Token]: did_match = True continue # Match meth (numbers) - match = re.match(r'\d+(.\d+)?', self.source) + match = re.match(r'\d+(\.\d+)?', self.source) if match: # Try to match gm after the number # Otherwise raise an error - match_unit = re.match(r'gm', self.source[match.end():]) - if match_unit: - final_match = match.group()+match_unit.group() + if self.source[match.end():match.end()+2] == 'gm': + final_match = match.group()+"gm" pos = (self.line, self.column) self.column += match.end() + 2 self.add_token(TokenType.METH, final_match, float(match.group()), pos)