diff options
| author | Mel <mel@rnrd.eu> | 2025-07-06 03:32:07 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2025-07-06 03:32:07 +0200 |
| commit | ebd176b8e7eb14060375a28d6ac50500d9d2c808 (patch) | |
| tree | 6c79ac631b5b8a4c025c09940a4a0fb1c71dd129 | |
| parent | 620d82a5e314a82784e02b4af387a67d53242149 (diff) | |
| download | catskill-ebd176b8e7eb14060375a28d6ac50500d9d2c808.tar.zst catskill-ebd176b8e7eb14060375a28d6ac50500d9d2c808.zip | |
Parse variadic parameters in function definitions
Signed-off-by: Mel <mel@rnrd.eu>
| -rw-r--r-- | boot/lex.c | 9 | ||||
| -rw-r--r-- | boot/parse.c | 9 | ||||
| -rw-r--r-- | boot/tests/parse/variadic_parameters.cskt | 13 | ||||
| -rw-r--r-- | boot/tree.c | 3 | ||||
| -rw-r--r-- | boot/visit.c | 5 |
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); |
