about summary refs log tree commit diff
path: root/boot
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2025-07-06 03:32:07 +0200
committerMel <mel@rnrd.eu>2025-07-06 03:32:07 +0200
commitebd176b8e7eb14060375a28d6ac50500d9d2c808 (patch)
tree6c79ac631b5b8a4c025c09940a4a0fb1c71dd129 /boot
parent620d82a5e314a82784e02b4af387a67d53242149 (diff)
downloadcatskill-ebd176b8e7eb14060375a28d6ac50500d9d2c808.tar.zst
catskill-ebd176b8e7eb14060375a28d6ac50500d9d2c808.zip
Parse variadic parameters in function definitions
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot')
-rw-r--r--boot/lex.c9
-rw-r--r--boot/parse.c9
-rw-r--r--boot/tests/parse/variadic_parameters.cskt13
-rw-r--r--boot/tree.c3
-rw-r--r--boot/visit.c5
5 files changed, 36 insertions, 3 deletions
diff --git a/boot/lex.c b/boot/lex.c
index f450798..82d3567 100644
--- a/boot/lex.c
+++ b/boot/lex.c
@@ -123,6 +123,7 @@ enum Token_Kind
     TOKEN_AMPERSAND,
     TOKEN_DOT,
     TOKEN_DOT_DOT,
+    TOKEN_DOT_DOT_DOT,
     TOKEN_BANG,
     TOKEN_QUESTION,
     TOKEN_PERCENT,
@@ -244,6 +245,8 @@ token_kind_to_string(enum Token_Kind kind)
         return "DOT";
     case TOKEN_DOT_DOT:
         return "DOT_DOT";
+    case TOKEN_DOT_DOT_DOT:
+        return "DOT_DOT_DOT";
     case TOKEN_BANG:
         return "BANG";
     case TOKEN_QUESTION:
@@ -618,10 +621,12 @@ lexer_symbol_token(struct Lexer* l, struct Lexer_Char current)
         if (a.got_match) RET{ TOKEN_ASSIGN_AMPERSAND, 2 };
         RET{ TOKEN_AMPERSAND, 1 };
     }
-    case '.':
-        a = lexer_match_char(l, '.');
+    case '.': {
+        lexer_match_chars(l, '.', '.', &a, &b);
+        if (a.got_match && b.got_match) RET{ TOKEN_DOT_DOT_DOT, 3 };
         if (a.got_match) RET{ TOKEN_DOT_DOT, 2 };
         RET{ TOKEN_DOT, 1 };
+    }
     case '!': {
         a = lexer_match_char(l, '=');
         if (a.got_match) RET{ TOKEN_NOT_EQUAL, 2 };
diff --git a/boot/parse.c b/boot/parse.c
index 5d839a8..cd5f019 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -254,6 +254,13 @@ parser_function_header_node(struct Parser* p, struct Parser_Error* error)
 
     struct Function_Header_Node header = { 0 };
     while (!parser_probe(p, TOKEN_ROUND_CLOSE)) {
+        // TODO: correctly output parameter spans
+        bool variadic = false;
+        if (parser_probe(p, TOKEN_DOT_DOT_DOT)) {
+            variadic = true;
+            parser_next(p);
+        }
+
         struct Token name_token =
             CHECK_RETURN(parser_need(p, TOKEN_NAME, error), struct Function_Header_Node);
         struct String name = name_token.value.name;
@@ -266,6 +273,8 @@ parser_function_header_node(struct Parser* p, struct Parser_Error* error)
         }
 
         type->value_name = name;
+        type->variadic = variadic;
+
         if (!header.parameters_type_and_name)
             header.parameters_type_and_name = type;
         else
diff --git a/boot/tests/parse/variadic_parameters.cskt b/boot/tests/parse/variadic_parameters.cskt
new file mode 100644
index 0000000..3b718a1
--- /dev/null
+++ b/boot/tests/parse/variadic_parameters.cskt
@@ -0,0 +1,13 @@
+correct parsing of variadic parameters in function
+definitions
+
+<<<
+
+printf = fun (format string, ...args any) {
+    # some implementation here
+}
+
+>>>
+
+(expr (binary = (expr (name printf)) (expr (function (param format) (type name string) (param args) (type variadic name any) (block
+)))))
\ No newline at end of file
diff --git a/boot/tree.c b/boot/tree.c
index 3c808f8..9ea9e6f 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -530,6 +530,9 @@ struct Type_Node
     // it is assigned to, e.g. `x int`, `string y`, etc.
     // this is the name of that binding, for ease of listing.
     struct String value_name;
+    // true if the type is used as a variadic parameter.
+    // e.g. `fun (format string, ...args string)`.
+    bool variadic;
 
     // if type is within a group of multiple types,
     // points to the next type within the group.
diff --git a/boot/visit.c b/boot/visit.c
index c1dd797..781c227 100644
--- a/boot/visit.c
+++ b/boot/visit.c
@@ -864,6 +864,8 @@ printer_visit_type_node(struct Visit* visit, struct Type_Node* node)
 {
     TREE_PRINTER_PREAMBLE
     PRINT("(type ");
+    if (node->variadic)
+        PRINT("variadic ");
     walk_type_node(visit, node);
     PRINT(")");
 }
@@ -1020,7 +1022,8 @@ printer_visit_function_header(struct Visit* visit, struct Function_Header_Node*
     TREE_PRINTER_PREAMBLE
 
     FOR_EACH (struct Type_Node*, current, header->parameters_type_and_name) {
-        if (current != header->parameters_type_and_name) PRINT(" ");
+        // if (current != header->parameters_type_and_name) PRINT(" ");
+        PRINT_WHITESPACE_IF_NEEDED(" ");
 
         if (current->value_name.data && current->value_name.data[0] != '\0')
             PRINT("(param %s) ", current->value_name.data);