feat: Implement function parameters and return values

This commit is contained in:
Alvin
2025-07-22 16:46:57 +02:00
parent 08e2ea17dd
commit b6a3b3041d
4 changed files with 75 additions and 20 deletions

View File

@@ -0,0 +1,12 @@
Femboy add_numbers(a, b) Femboycore
Femme a + b
Periodt
result is add_numbers(10, 5)
UwU Boy result
Femboy greet(name) Femboycore
UwU Boy "Hello, " + name
Periodt
greet("World")

View File

@@ -1,9 +1,13 @@
class Interpreter:
def __init__(self, ast):
self.ast = ast
self.variables = {}
self.scope_stack = [{}]
self.functions = {}
@property
def current_scope(self):
return self.scope_stack[-1]
def interpret(self):
for node in self.ast:
self.visit(node)
@@ -57,13 +61,14 @@ class Interpreter:
def visit_Assign(self, node):
var_name = node.left.value
value = self.visit(node.right)
self.variables[var_name] = value
self.current_scope[var_name] = value
def visit_Variable(self, node):
var_name = node.value
if var_name in self.variables:
return self.variables[var_name]
else:
# Search up the scope stack for the variable
for scope in reversed(self.scope_stack):
if var_name in scope:
return scope[var_name]
raise NameError(f"name '{var_name}' is not defined")
def visit_Block(self, node):
@@ -93,14 +98,27 @@ class Interpreter:
raise NameError(f"Function '{func_name}' is not defined")
func_info = self.functions[func_name]
# For simplicity, no arguments are passed for now
# In a real interpreter, you'd push a new scope and bind arguments to parameters
# Evaluate arguments
evaluated_arguments = [self.visit(arg) for arg in node.arguments]
# Create a new scope for the function call
new_scope = {}
for i, param_name in enumerate(func_info['parameters']):
new_scope[param_name] = evaluated_arguments[i]
self.scope_stack.append(new_scope)
# Execute function body
try:
self.visit(func_info['body'])
except ReturnValue as e:
self.scope_stack.pop() # Pop the function scope
return e.value
finally:
# Ensure scope is popped even if no return or an error occurs
if len(self.scope_stack) > 1: # Don't pop global scope
self.scope_stack.pop()
def visit_ReturnStatement(self, node):
raise ReturnValue(self.visit(node.value))

View File

@@ -31,11 +31,13 @@ class Lexer:
if current_char == '"':
self.pos += 1
string_end = self.text.find('"', self.pos)
if string_end == -1:
self.error()
string = self.text[self.pos:string_end]
self.pos = string_end + 1
start_string = self.pos
while self.pos < len(self.text) and self.text[self.pos] != '"':
self.pos += 1
if self.pos == len(self.text):
self.error() # Unterminated string
string = self.text[start_string:self.pos]
self.pos += 1 # Consume closing quote
return Token('STRING', string)
if current_char.isdigit():
@@ -65,6 +67,9 @@ class Lexer:
if current_char == '/':
self.pos += 1
return Token('DIV', '/')
if current_char == ',':
self.pos += 1
return Token('COMMA', ',')
if current_char == '=':
if self.pos + 1 < len(self.text) and self.text[self.pos + 1] == '=':
self.pos += 2

View File

@@ -196,8 +196,25 @@ class Parser:
if name_token.type != 'ID':
raise Exception("Expected function name (ID)")
# For simplicity, assume no parameters for now
print(f"After function name: {self.peek_next_token()}")
# Parse parameters
parameters = []
if self.peek_next_token().type == 'LPAREN':
self.get_next_token() # Consume '('
print(f"After LPAREN: {self.peek_next_token()}")
while self.peek_next_token().type != 'RPAREN':
param_token = self.get_next_token()
if param_token.type != 'ID':
raise Exception("Expected parameter name (ID)")
parameters.append(param_token.value)
print(f"After parameter {param_token.value}: {self.peek_next_token()}")
if self.peek_next_token().type == 'COMMA':
self.get_next_token() # Consume ','
print(f"After COMMA: {self.peek_next_token()}")
# No 'elif' here, the loop condition handles the RPAREN
self.get_next_token() # Consume ')'
print(f"After RPAREN: {self.peek_next_token()}")
if self.peek_next_token().type != 'FEMBOYCORE':
raise Exception("Expected 'Femboycore' to start function body")
@@ -258,9 +275,12 @@ class Parser:
def parse_function_call(self, name_token):
self.get_next_token() # Consume '('
arguments = []
# For simplicity, assume no arguments for now
if self.peek_next_token().value == ')':
self.get_next_token() # Consume ')'
if self.peek_next_token().type != 'RPAREN':
while True:
arguments.append(self.expression())
if self.peek_next_token().type == 'COMMA':
self.get_next_token() # Consume ','
else:
raise Exception("Expected ')' after function call")
break # Exit loop if not COMMA (implies RPAREN or EOF)
self.get_next_token() # Consume ')'
return FunctionCall(name_token.value, arguments)