about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2025-06-24 20:07:41 +0200
committerMel <mel@rnrd.eu>2025-06-24 20:07:41 +0200
commit47c5a0ecc6fccc3bfe0b5394d7297e635ab23184 (patch)
treebd99364fa76cfff6664b233a1e6682a63fdbd020
parenta63977f56a4c3dc4c53f0befe65c8252cc5c9b0b (diff)
downloadcatskill-47c5a0ecc6fccc3bfe0b5394d7297e635ab23184.tar.zst
catskill-47c5a0ecc6fccc3bfe0b5394d7297e635ab23184.zip
Parse named arguments, thus enabling type constructions
Signed-off-by: Mel <mel@rnrd.eu>
-rw-r--r--boot/parse.c36
-rw-r--r--boot/tree.c32
2 files changed, 52 insertions, 16 deletions
diff --git a/boot/parse.c b/boot/parse.c
index 3d2706f..ac324f9 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -705,7 +705,7 @@ parser_expression_member(struct Parser* p, struct Parser_Error* error)
 {
     struct Expression* left = CHECK(parser_expression_primary(p, error));
 
-    // NOTE: see `parser_expression_postfix_call`.
+    // NOTE: see `parser_expression_postfix_call_or_construct`.
     while (parser_probe(p, TOKEN_DOT)) {
         parser_next(p);
         struct Token name_token = CHECK(parser_need(p, TOKEN_NAME, error));
@@ -720,31 +720,53 @@ parser_expression_member(struct Parser* p, struct Parser_Error* error)
 }
 
 struct Expression*
-parser_expression_postfix_call(
+parser_expression_postfix_call_or_construct(
     struct Parser* p, struct Expression* subject, struct Parser_Error* error)
 {
     // NOTE: because of the way the parser works, we have to parse all subsequent
-    // call expressions in the same loop.
+    // call/construct expressions in the same loop.
     // this is the case with an expression like `meow_function()(123)`,
     // where the hypothetical `meow_function` returns a function pointer.
+
+    // calls and constructs look identical in the parser.
+    // * call: `meow_function(123, "hello")`
+    // * construct: `Meow(num = 123, str = "hello")`
     while (parser_probe(p, TOKEN_ROUND_OPEN)) {
         parser_next(p);
 
+        struct String_Array argument_names = string_array_new();
         struct Expression *arguments_head = nil, *arguments_current = nil;
         while (!parser_probe(p, TOKEN_ROUND_CLOSE)) {
+
+            // check if we have a named argument.
+            struct String name = string_empty();
+            struct Token name_token = parser_peek(p), next = parser_peek_further(p);
+            if (token_is(&name_token, TOKEN_NAME) && token_is(&next, TOKEN_ASSIGN)) {
+                parser_next(p);
+                parser_next(p);
+                name = name_token.value.name;
+            }
+
             struct Expression* argument = CHECK(parser_expression(p, error));
             if (!arguments_head)
                 arguments_head = argument;
             else
                 arguments_current->next = argument;
             arguments_current = argument;
+
+            // if we have a named argument, we need to add it to the names array,
+            // otherwise we just add an empty string.
+            string_array_add(&argument_names, name);
+
             if (parser_probe(p, TOKEN_COMMA)) parser_next(p);
         }
 
         struct Token token = CHECK(parser_need(p, TOKEN_ROUND_CLOSE, error));
         struct Span span = span_merge(subject->span, token.span);
-        union Expression_Value value = { .call = { subject, arguments_head } };
-        subject = expression_new(EXPRESSION_CALL, value, span, token.location);
+        union Expression_Value value = {
+            .call_or_construct = { subject, arguments_head, argument_names }
+        };
+        subject = expression_new(EXPRESSION_CALL_OR_CONSTRUCT, value, span, token.location);
     }
 
     return subject;
@@ -754,7 +776,7 @@ struct Expression*
 parser_expression_postfix_subscript(
     struct Parser* p, struct Expression* subject, struct Parser_Error* error)
 {
-    // NOTE: see `parser_expression_postfix_call`.
+    // NOTE: see `parser_expression_postfix_call_or_construct`.
     while (parser_probe(p, TOKEN_SQUARE_OPEN)) {
         parser_next(p);
 
@@ -776,7 +798,7 @@ parser_expression_postfix(struct Parser* p, struct Parser_Error* error)
     struct Token token = parser_peek(p);
     switch (token.kind) {
     case TOKEN_ROUND_OPEN:
-        return parser_expression_postfix_call(p, expression, error);
+        return parser_expression_postfix_call_or_construct(p, expression, error);
     case TOKEN_SQUARE_OPEN:
         return parser_expression_postfix_subscript(p, expression, error);
     default:;
diff --git a/boot/tree.c b/boot/tree.c
index e4d0272..2e046da 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -665,7 +665,7 @@ enum Expression_Kind
     EXPRESSION_BINARY_OPERATION,
 
     EXPRESSION_GROUP,
-    EXPRESSION_CALL,
+    EXPRESSION_CALL_OR_CONSTRUCT,
     EXPRESSION_SUBSCRIPT,
     EXPRESSION_MEMBER,
     EXPRESSION_INCREMENT_DECREMENT,
@@ -717,10 +717,14 @@ struct Expression_Group
     struct Expression* inner_expression;
 };
 
-struct Expression_Call
+struct Expression_Call_Or_Construct
 {
     struct Expression* subject;
-    struct Expression* arguments; // linked list of expressions.
+    // linked list of argument expressions.
+    struct Expression* arguments;
+    // names of the arguments, if given.
+    // an unnamed argument is represented as an empty string.
+    struct String_Array argument_names;
 };
 
 struct Expression_Subscript
@@ -764,7 +768,7 @@ union Expression_Value
     struct Expression_Unary_Operator unary_operator;
     struct Expression_Binary_Operator binary_operator;
     struct Expression_Group group;
-    struct Expression_Call call;
+    struct Expression_Call_Or_Construct call_or_construct;
     struct Expression_Subscript subscript;
     struct Expression_Member member;
     struct Expression_Increment_Decrement increment_decrement;
@@ -867,16 +871,26 @@ expression_print(const struct Expression* expression)
         expression_print(expression->value.group.inner_expression);
         printf(")");
         break;
-    case EXPRESSION_CALL:
-        printf("(call ");
-        expression_print(expression->value.call.subject);
-        FOR_EACH(struct Expression*, argument, expression->value.call.arguments)
+    case EXPRESSION_CALL_OR_CONSTRUCT: {
+        const struct Expression_Call_Or_Construct* coc =
+            &expression->value.call_or_construct;
+        printf("(call/construct ");
+        expression_print(coc->subject);
+        uint i = 0;
+        FOR_EACH(struct Expression*, argument, coc->arguments)
         {
-            printf(" ");
+            struct String name = string_array_at(&coc->argument_names, i++);
+            if (!string_is_empty(name)) {
+                printf(" (named arg '%s' ", name.data);
+            } else {
+                printf(" (arg ");
+            }
             expression_print(argument);
+            printf(")");
         }
         printf(")");
         break;
+    }
     case EXPRESSION_SUBSCRIPT:
         printf("(subscript ");
         expression_print(expression->value.subscript.subject);