about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <[email protected]>2025-01-23 22:55:57 +0100
committerBaitinq <[email protected]>2025-01-23 22:55:57 +0100
commit84d70492d13a23d9ad5e409cdff2a6860b9c0adb (patch)
treec72b8cb9a0906d037343a05ce6a1a944c670d33e
parentSync grammar (diff)
downloadpry-lang-84d70492d13a23d9ad5e409cdff2a6860b9c0adb.tar.gz
pry-lang-84d70492d13a23d9ad5e409cdff2a6860b9c0adb.tar.bz2
pry-lang-84d70492d13a23d9ad5e409cdff2a6860b9c0adb.zip
Feature: Support calling funtion definitions
-rw-r--r--grammar.ebnf2
-rw-r--r--src/evaluator.zig27
-rw-r--r--src/parser.zig26
3 files changed, 40 insertions, 15 deletions
diff --git a/grammar.ebnf b/grammar.ebnf
index 5aa9b54..7175f6a 100644
--- a/grammar.ebnf
+++ b/grammar.ebnf
@@ -4,7 +4,7 @@ Statement    ::= (AssignmentStatement | FunctionCallStatement | IfStatement | Wh
 
 AssignmentStatement ::= "let" IDENTIFIER EQUALS Expression
 
-FunctionCallStatement ::= IDENTIFIER LPAREN FunctionArguments? RPAREN
+FunctionCallStatement ::= (IDENTIFIER | FunctionDefinition) LPAREN FunctionArguments? RPAREN
 
 IfStatement ::= "if" Expression LBRACE Statement* RBRACE -- TODO: Should function definitions be allowed?
 
diff --git a/src/evaluator.zig b/src/evaluator.zig
index ec6a698..3a145f8 100644
--- a/src/evaluator.zig
+++ b/src/evaluator.zig
@@ -97,16 +97,25 @@ pub const Evaluator = struct {
 
         const function_call_statement = node.FUNCTION_CALL_STATEMENT;
 
-        // Print function implementation
-        if (std.mem.eql(u8, function_call_statement.name, "print")) {
-            std.debug.assert(function_call_statement.arguments.len == 1);
-            std.debug.print("PRINT: {any}\n", .{try self.get_expression_value(function_call_statement.arguments[0])});
-            return null;
-        }
-
-        const function_definition = self.environment.get_variable(function_call_statement.name) orelse return EvaluatorError.EvaluationError;
+        switch (function_call_statement.expression.*) {
+            .FUNCTION_DEFINITION => |*function_definition| {
+                return try self.evaluate_function_definition(@ptrCast(function_definition), function_call_statement.arguments);
+            },
+            .PRIMARY_EXPRESSION => |*primary_expression| {
+                std.debug.assert(primary_expression.* == .IDENTIFIER);
+
+                // Print function implementation
+                if (std.mem.eql(u8, function_call_statement.expression.PRIMARY_EXPRESSION.IDENTIFIER.name, "print")) {
+                    std.debug.assert(function_call_statement.arguments.len == 1);
+                    std.debug.print("PRINT: {any}\n", .{try self.get_expression_value(function_call_statement.arguments[0])});
+                    return null;
+                }
 
-        return self.evaluate_function_definition(function_definition.FUNCTION_DEFINITION, function_call_statement.arguments);
+                const function_definition = self.environment.get_variable(primary_expression.IDENTIFIER.name) orelse return EvaluatorError.EvaluationError;
+                return self.evaluate_function_definition(function_definition.FUNCTION_DEFINITION, function_call_statement.arguments);
+            },
+            else => unreachable,
+        }
     }
 
     fn evaluate_if_statement(self: *Evaluator, node: *parser.Node) !?*Variable {
diff --git a/src/parser.zig b/src/parser.zig
index 94f5cb7..3f77b19 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -19,7 +19,7 @@ pub const Node = union(enum) {
         expression: *Node,
     },
     FUNCTION_CALL_STATEMENT: struct {
-        name: []const u8,
+        expression: *Node,
         arguments: []*Node,
     },
     IF_STATEMENT: struct {
@@ -149,11 +149,14 @@ pub const Parser = struct {
         });
     }
 
-    // FunctionCallStatement ::= IDENTIFIER LPAREN FunctionArguments? RPAREN
+    // FunctionCallStatement ::= (IDENTIFIER | FunctionDefinition) LPAREN FunctionArguments? RPAREN
     fn parse_function_call_statement(self: *Parser) ParserError!*Node {
         errdefer if (!self.try_context) std.debug.print("Error parsing function call statement {any}\n", .{self.peek_token()});
 
-        const identifier = try self.parse_token(tokenizer.TokenType.IDENTIFIER);
+        const identifier = self.accept_token(tokenizer.TokenType.IDENTIFIER);
+        const fn_def = self.accept_parse(parse_function_definition);
+
+        if (identifier == null and fn_def == null) return ParserError.ParsingError;
 
         _ = try self.parse_token(tokenizer.TokenType.LPAREN);
 
@@ -161,8 +164,21 @@ pub const Parser = struct {
 
         _ = try self.parse_token(tokenizer.TokenType.RPAREN);
 
+        if (fn_def != null) {
+            return self.create_node(.{ .FUNCTION_CALL_STATEMENT = .{
+                .expression = fn_def.?,
+                .arguments = arguments,
+            } });
+        }
+
         return self.create_node(.{ .FUNCTION_CALL_STATEMENT = .{
-            .name = try self.arena.dupe(u8, identifier.type.IDENTIFIER),
+            .expression = try self.create_node(.{
+                .PRIMARY_EXPRESSION = .{
+                    .IDENTIFIER = .{
+                        .name = try self.arena.dupe(u8, identifier.?.type.IDENTIFIER),
+                    },
+                },
+            }),
             .arguments = arguments,
         } });
     }
@@ -327,8 +343,8 @@ pub const Parser = struct {
     fn parse_primary_expression(self: *Parser) ParserError!*Node {
         errdefer if (!self.try_context) std.debug.print("Error parsing primary expression {any}\n", .{self.peek_token()});
 
-        if (self.accept_parse(parse_function_definition)) |stmt| return stmt;
         if (self.accept_parse(parse_function_call_statement)) |stmt| return stmt;
+        if (self.accept_parse(parse_function_definition)) |stmt| return stmt;
 
         // LPAREN (Expression) RPAREN
         if (self.accept_token(tokenizer.TokenType.LPAREN)) |_| {