From 4ec376b67d605910cb7757dc2e15a28a942f59ca Mon Sep 17 00:00:00 2001 From: Mel Date: Thu, 28 May 2026 04:24:51 +0200 Subject: Correct type modifier combinations and grouping Signed-off-by: Mel --- boot/lex.c | 5 +++-- boot/parse.c | 34 ++++++++++++++++++++++++++++------ boot/tests/parse/type_modifiers.cskt | 22 ++++++++++++++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 boot/tests/parse/type_modifiers.cskt (limited to 'boot') 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))))) -- cgit 1.4.1