Skip to content

Commit

Permalink
Better runtime errors
Browse files Browse the repository at this point in the history
  • Loading branch information
AkshayWarrier committed Apr 27, 2023
1 parent 84d6172 commit 7d4e47e
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Example.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
say my name (1gm+2gm);
say my name (1gm+"Heisenberg");
21 changes: 13 additions & 8 deletions Interpreter.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
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:
'''
The interpreter class for the Jesse programming language.
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
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions Jesse.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
7 changes: 3 additions & 4 deletions Scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 7d4e47e

Please sign in to comment.