mirror of
https://github.com/Alvin-Zilverstand/femcode.git
synced 2026-03-06 13:23:39 +01:00
feat: Implement try-except error handling
This commit is contained in:
8
examples/error_handling.fem
Normal file
8
examples/error_handling.fem
Normal file
@@ -0,0 +1,8 @@
|
||||
Twink Femboycore
|
||||
# This will cause a division by zero error
|
||||
result is 10 / 0
|
||||
UwU Boy result
|
||||
Periodt
|
||||
Bimboy Femboycore
|
||||
UwU Boy "An error occurred!"
|
||||
Periodt
|
||||
@@ -135,6 +135,14 @@ class Interpreter:
|
||||
def visit_ContinueStatement(self, node):
|
||||
raise ContinueLoop()
|
||||
|
||||
def visit_TryExceptStatement(self, node):
|
||||
try:
|
||||
self.visit(node.try_block)
|
||||
except Exception as e:
|
||||
# For now, catch all Python exceptions and execute the except block
|
||||
# In a more advanced interpreter, you might map specific Femcode errors
|
||||
self.visit(node.except_block)
|
||||
|
||||
def visit_List(self, node):
|
||||
elements = [self.visit(element) for element in node.elements]
|
||||
return elements
|
||||
|
||||
18
src/lexer.py
18
src/lexer.py
@@ -164,6 +164,24 @@ class Lexer:
|
||||
if re.match(r'\bContinue\b', self.text[self.pos:]):
|
||||
self.pos += len('Continue')
|
||||
return Token('CONTINUE', 'Continue')
|
||||
if re.match(r'\bTwink\b', self.text[self.pos:]):
|
||||
self.pos += len('Twink')
|
||||
return Token('TRY', 'Twink')
|
||||
if re.match(r'\bBimboy\b', self.text[self.pos:]):
|
||||
self.pos += len('Bimboy')
|
||||
return Token('EXCEPT', 'Bimboy')
|
||||
if re.match(r'\band\b', self.text[self.pos:]):
|
||||
self.pos += len('and')
|
||||
return Token('AND', 'and')
|
||||
if re.match(r'\bor\b', self.text[self.pos:]):
|
||||
self.pos += len('or')
|
||||
return Token('OR', 'or')
|
||||
if re.match(r'\bTwink\b', self.text[self.pos:]):
|
||||
self.pos += len('Twink')
|
||||
return Token('TRY', 'Twink')
|
||||
if re.match(r'\bBimboy\b', self.text[self.pos:]):
|
||||
self.pos += len('Bimboy')
|
||||
return Token('EXCEPT', 'Bimboy')
|
||||
if re.match(r'\band\b', self.text[self.pos:]):
|
||||
self.pos += len('and')
|
||||
return Token('AND', 'and')
|
||||
|
||||
@@ -81,17 +81,10 @@ class BreakStatement(AST):
|
||||
class ContinueStatement(AST):
|
||||
pass
|
||||
|
||||
class ForStatement(AST):
|
||||
def __init__(self, var_name, iterable, body):
|
||||
self.var_name = var_name
|
||||
self.iterable = iterable
|
||||
self.body = body
|
||||
|
||||
class BreakStatement(AST):
|
||||
pass
|
||||
|
||||
class ContinueStatement(AST):
|
||||
pass
|
||||
class TryExceptStatement(AST):
|
||||
def __init__(self, try_block, except_block):
|
||||
self.try_block = try_block
|
||||
self.except_block = except_block
|
||||
|
||||
class FunctionDefinition(AST):
|
||||
def __init__(self, name, parameters, body):
|
||||
@@ -192,6 +185,9 @@ class Parser:
|
||||
self.consume('CONTINUE')
|
||||
return ContinueStatement()
|
||||
|
||||
if token.type == 'TRY':
|
||||
return self.parse_try_except_statement()
|
||||
|
||||
raise Exception(f"Invalid statement starting with token {token.type}")
|
||||
|
||||
def parse_print_statement(self):
|
||||
@@ -316,12 +312,18 @@ class Parser:
|
||||
if token.type == 'INTEGER':
|
||||
self.consume('INTEGER')
|
||||
return Number(token)
|
||||
elif token.type == 'FLOAT':
|
||||
self.consume('FLOAT')
|
||||
return Number(token) # Using Number AST for both int and float for now
|
||||
elif token.type == 'STRING':
|
||||
self.consume('STRING')
|
||||
return String(token)
|
||||
elif token.type == 'KAWAII' or token.type == 'CRINGE':
|
||||
self.consume(token.type)
|
||||
return Boolean(token)
|
||||
elif token.type == 'NULL':
|
||||
self.consume('NULL')
|
||||
return Null()
|
||||
elif token.type == 'ID':
|
||||
# Consume the ID token first
|
||||
self.consume('ID')
|
||||
@@ -332,7 +334,7 @@ class Parser:
|
||||
return self.parse_function_call(token)
|
||||
elif next_token.type == 'DOT':
|
||||
# It's a property access
|
||||
return self.parse_property_access(Variable(token))
|
||||
return self.parse_property_access(Variable(token)) # Pass Variable node as target
|
||||
elif next_token.type == 'LBRACKET':
|
||||
# It's an index access
|
||||
return self.parse_index_access(Variable(token))
|
||||
@@ -465,3 +467,26 @@ class Parser:
|
||||
property_name_token = self.get_current_token()
|
||||
self.consume('ID')
|
||||
return PropertyAccess(target_node, property_name_token.value)
|
||||
|
||||
def parse_try_except_statement(self):
|
||||
self.consume('TRY')
|
||||
self.consume('FEMBOYCORE')
|
||||
try_block_statements = []
|
||||
while self.get_current_token().type != 'PERIODT':
|
||||
if self.get_current_token().type == 'EOF':
|
||||
raise Exception("Unterminated try block: Expected 'Periodt'")
|
||||
try_block_statements.append(self.parse_statement())
|
||||
self.consume('PERIODT')
|
||||
try_block = Block(try_block_statements)
|
||||
|
||||
self.consume('EXCEPT')
|
||||
self.consume('FEMBOYCORE')
|
||||
except_block_statements = []
|
||||
while self.get_current_token().type != 'PERIODT':
|
||||
if self.get_current_token().type == 'EOF':
|
||||
raise Exception("Unterminated except block: Expected 'Periodt'")
|
||||
except_block_statements.append(self.parse_statement())
|
||||
self.consume('PERIODT')
|
||||
except_block = Block(except_block_statements)
|
||||
|
||||
return TryExceptStatement(try_block, except_block)
|
||||
Reference in New Issue
Block a user