From 65e53daa6662df2e85a67c35e2b25fa78f40d455 Mon Sep 17 00:00:00 2001 From: Alvin <524715@vistacollege.nl> Date: Tue, 22 Jul 2025 16:22:49 +0200 Subject: [PATCH] feat: Implement while loops --- examples/loops.fem | 5 +++++ src/interpreter.py | 4 ++++ src/lexer.py | 3 +++ src/parser.py | 29 ++++++++++++++++++++++++++++- 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 examples/loops.fem diff --git a/examples/loops.fem b/examples/loops.fem new file mode 100644 index 0000000..33effca --- /dev/null +++ b/examples/loops.fem @@ -0,0 +1,5 @@ +counter is 0 +Otokonoko counter < 5 Femboycore + UwU Boy counter + counter is counter + 1 +Periodt \ No newline at end of file diff --git a/src/interpreter.py b/src/interpreter.py index dc547c0..af4b3fa 100644 --- a/src/interpreter.py +++ b/src/interpreter.py @@ -75,3 +75,7 @@ class Interpreter: self.visit(node.if_block) elif node.else_block: self.visit(node.else_block) + + def visit_WhileStatement(self, node): + while self.visit(node.condition): + self.visit(node.body) diff --git a/src/lexer.py b/src/lexer.py index adc9886..8c8ccc0 100644 --- a/src/lexer.py +++ b/src/lexer.py @@ -90,6 +90,9 @@ class Lexer: if re.match(r'\bAndrogyny\b', self.text[self.pos:]): self.pos += len('Androgyny') return Token('ANDROGYNY', 'Androgyny') + if re.match(r'\bOtokonoko\b', self.text[self.pos:]): + self.pos += len('Otokonoko') + return Token('OTOKONOKO', 'Otokonoko') if re.match(r'\bis\b', self.text[self.pos:]): self.pos += 2 return Token('ASSIGN', 'is') diff --git a/src/parser.py b/src/parser.py index e1b1473..5588931 100644 --- a/src/parser.py +++ b/src/parser.py @@ -48,6 +48,11 @@ class IfStatement(AST): self.if_block = if_block self.else_block = else_block +class WhileStatement(AST): + def __init__(self, condition, body): + self.condition = condition + self.body = body + class Parser: def __init__(self, tokens): self.tokens = tokens @@ -83,6 +88,9 @@ class Parser: if token.type == 'FEMBOY_FEMININE': return self.parse_if_statement() + if token.type == 'OTOKONOKO': + return self.parse_while_statement() + raise Exception(f"Invalid statement starting with token {token.type}") def parse_print_statement(self): @@ -135,6 +143,25 @@ class Parser: return IfStatement(condition, if_block, else_block) + def parse_while_statement(self): + self.get_next_token() # Consume OTOKONOKO + + condition = self.expression() + + if self.peek_next_token().type != 'FEMBOYCORE': + raise Exception("Expected 'Femboycore' to start while loop body") + self.get_next_token() # Consume FEMBOYCORE + + body_statements = [] + while self.peek_next_token().type != 'PERIODT': + if self.peek_next_token().type == 'EOF': + raise Exception("Unterminated while loop: Expected 'Periodt'") + body_statements.append(self.parse_statement()) + self.get_next_token() # Consume PERIODT + body = Block(body_statements) + + return WhileStatement(condition, body) + def factor(self): token = self.get_next_token() if token.type == 'INTEGER': @@ -167,4 +194,4 @@ class Parser: right_node = self.expression() # Recursively parse right side of comparison node = Comparison(left=node, op=op_token, right=right_node) - return node + return node \ No newline at end of file