diff --git a/examples/error_handling.fem b/examples/error_handling.fem new file mode 100644 index 0000000..82e4075 --- /dev/null +++ b/examples/error_handling.fem @@ -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 \ No newline at end of file diff --git a/src/interpreter.py b/src/interpreter.py index decbe0a..c7f31bd 100644 --- a/src/interpreter.py +++ b/src/interpreter.py @@ -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 diff --git a/src/lexer.py b/src/lexer.py index fa75d77..2319cd8 100644 --- a/src/lexer.py +++ b/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') diff --git a/src/parser.py b/src/parser.py index 075860b..c643c03 100644 --- a/src/parser.py +++ b/src/parser.py @@ -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) \ No newline at end of file