diff options
| author | Mel <mel@rnrd.eu> | 2026-05-28 04:24:51 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2026-05-28 04:24:51 +0200 |
| commit | 4ec376b67d605910cb7757dc2e15a28a942f59ca (patch) | |
| tree | 4e98614792e5a00175fa29e705142850993d68f6 | |
| parent | a5b24e3eedc8bd48de99cfb90abb3bececa5d29f (diff) | |
| download | catskill-4ec376b67d605910cb7757dc2e15a28a942f59ca.tar.zst catskill-4ec376b67d605910cb7757dc2e15a28a942f59ca.zip | |
Correct type modifier combinations and grouping
Signed-off-by: Mel <mel@rnrd.eu>
| -rw-r--r-- | boot/lex.c | 5 | ||||
| -rw-r--r-- | boot/parse.c | 34 | ||||
| -rw-r--r-- | boot/tests/parse/type_modifiers.cskt | 22 | ||||
| -rw-r--r-- | docs/grammar.md | 4 |
4 files changed, 55 insertions, 10 deletions
diff --git a/boot/lex.c b/boot/lex.c index 6c3e86f..29b5294 100644 --- a/boot/lex.c +++ b/boot/lex.c @@ -335,7 +335,7 @@ bool token_ends_statement(const struct Token* t) { return token_is(t, TOKEN_END_OF_FILE) || token_is(t, TOKEN_NEWLINE) - || token_is(t, TOKEN_SEMICOLON); + || token_is(t, TOKEN_SEMICOLON); } bool @@ -358,6 +358,7 @@ token_can_begin_type(const struct Token* t) // references case TOKEN_AMPERSAND: + case TOKEN_AND: // `&&` counts as a double-reference! return true; default: return false; @@ -877,4 +878,4 @@ lexer_next(struct Lexer* l) union Token_Value value = (union Token_Value){ .unknown_character = c.character }; return token_new(TOKEN_SOMETHING, span_width(position, 1), cursor, value); -} \ No newline at end of file +} diff --git a/boot/parse.c b/boot/parse.c index 56d767a..ef71540 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -381,6 +381,8 @@ parser_block_node(struct Parser* p, struct Parser_Error* error) if (!parser_probe(p, TOKEN_CURLY_CLOSE)) CHECK_RETURN(parser_end_statement(p, error), struct Tree_Block); + parser_unglue(p); + if (!head) { head = statement; } else { @@ -401,6 +403,7 @@ parser_block_node(struct Parser* p, struct Parser_Error* error) } struct Tree_Type* parser_node_type(struct Parser* p, struct Parser_Error* error); +struct Tree_Type* parser_node_type_inner(struct Parser* p, struct Parser_Error* error); struct Tree_Function_Header parser_function_header_node(struct Parser* p, struct Parser_Error* error) @@ -710,6 +713,11 @@ parser_node_type_tuple(struct Parser* p, struct Parser_Error* error) } struct Token close_token = CHECK(parser_need(p, TOKEN_ROUND_CLOSE, error)); + + // single-element tuples are equivalent to their inner type, + // which allows us to use them for grouping. + if (head && !head->next) return head; + struct Span span = span_merge(open_token.span, close_token.span); return tree_type_new( TREE_TYPE_TUPLE, (union Tree_Type_Value){ .tuple = { head } }, span, open_token.location); @@ -759,18 +767,31 @@ parser_node_type_array_or_map(struct Parser* p, struct Parser_Error* error) struct Tree_Type* parser_node_type_reference(struct Parser* p, struct Parser_Error* error) { - struct Token ampersand_token = CHECK(parser_need(p, TOKEN_AMPERSAND, error)); + // we accept a fused `&&` token as two references + struct Token sigil = parser_next(p); + bool double_ref = token_is(&sigil, TOKEN_AND); + if (!double_ref && !token_is(&sigil, TOKEN_AMPERSAND)) { + parser_error(error, PARSER_ERROR_UNEXPECTED_TOKEN, sigil); + return nil; + } - struct Tree_Type* referenced_type = CHECK(parser_node_type(p, error)); + struct Tree_Type* referenced_type = CHECK(parser_node_type_inner(p, error)); if (!referenced_type) { - parser_error(error, PARSER_ERROR_EXPECTED_TYPE, ampersand_token); + parser_error(error, PARSER_ERROR_EXPECTED_TYPE, sigil); return nil; } - struct Span span = span_merge(ampersand_token.span, referenced_type->span); - return tree_type_new( + struct Span span = span_merge(sigil.span, referenced_type->span); + struct Tree_Type* ref = tree_type_new( TREE_TYPE_REFERENCE, (union Tree_Type_Value){ .reference = { referenced_type } }, span, - ampersand_token.location); + sigil.location); + + if (double_ref) { + ref = tree_type_new( + TREE_TYPE_REFERENCE, (union Tree_Type_Value){ .reference = { ref } }, span, + sigil.location); + } + return ref; } struct Tree_Type* @@ -793,6 +814,7 @@ parser_node_type_inner(struct Parser* p, struct Parser_Error* error) case TOKEN_SQUARE_OPEN: return parser_node_type_array_or_map(p, error); case TOKEN_AMPERSAND: + case TOKEN_AND: return parser_node_type_reference(p, error); default: parser_error(error, PARSER_ERROR_UNEXPECTED_TOKEN, token); diff --git a/boot/tests/parse/type_modifiers.cskt b/boot/tests/parse/type_modifiers.cskt new file mode 100644 index 0000000..3c639b3 --- /dev/null +++ b/boot/tests/parse/type_modifiers.cskt @@ -0,0 +1,22 @@ +checks for various type modifier combinations. +&...? should always combine into an optional reference to a type. +1-tuples should always decay into their inner element type, +allowing for usage as a group. + +<<< + +var a &int? = nil +var b &(int?) = nil +var c (int) = 0 +var d (int, bool) = nil +var e &&int = nil +var f &&int? = nil + +>>> + +(variable (declaration a (type maybe (type reference to (type name int))) (initializer (expr (name nil))))) +(variable (declaration b (type reference to (type maybe (type name int))) (initializer (expr (name nil))))) +(variable (declaration c (type name int) (initializer (expr 0)))) +(variable (declaration d (type tuple (type name int) (type name bool)) (initializer (expr (name nil))))) +(variable (declaration e (type reference to (type reference to (type name int))) (initializer (expr (name nil))))) +(variable (declaration f (type maybe (type reference to (type reference to (type name int)))) (initializer (expr (name nil))))) diff --git a/docs/grammar.md b/docs/grammar.md index 18a8550..fd47c47 100644 --- a/docs/grammar.md +++ b/docs/grammar.md @@ -236,10 +236,10 @@ type_variant = "variant" "{" variant_cases "}" type_class = "class" "{" class_methods "}" type_function = "fun" function_header type_structure = "{" struct_fields "}" -type_tuple = "(" [ type { "," type } ] ")" +type_tuple = "(" [ type { "," type } ] ")" # 1-tuple is equivalent to a simple group type_array = "[" type "]" type_map = "[" type "=" type "]" -type_reference = "&" type +type_reference = "&" type_inner # common shapes |
