diff options
| author | Mel <mel@rnrd.eu> | 2025-07-01 03:04:07 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2025-07-01 03:04:07 +0200 |
| commit | 8e0beabeb4efa50a3072ef805682c0f42b6c16a8 (patch) | |
| tree | cd6b82d1741cdd52aadddae87c59e0617fb74ffd /boot/parse.c | |
| parent | e51799842aa367692152717a8db7c519dbc66c1f (diff) | |
| download | catskill-8e0beabeb4efa50a3072ef805682c0f42b6c16a8.tar.zst catskill-8e0beabeb4efa50a3072ef805682c0f42b6c16a8.zip | |
Parse pragmas as free-standing statements, without attachment
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/parse.c')
| -rw-r--r-- | boot/parse.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/boot/parse.c b/boot/parse.c index d410476..7b40fb1 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -31,6 +31,7 @@ struct Parser_Error PARSER_ERROR_EXPECTED_STATEMENT_END, PARSER_ERROR_EXPECTED_PRIMARY_EXPRESSION, PARSER_ERROR_EXPECTED_TYPE, + PARSER_ERROR_EXPECTED_PRAGMA, } kind; // TODO: add span to error }; @@ -69,6 +70,8 @@ parser_error_to_string(const struct Parser_Error* error) return "expected primary expression"; case PARSER_ERROR_EXPECTED_TYPE: return "expected type"; + case PARSER_ERROR_EXPECTED_PRAGMA: + return "expected pragma"; default: return "unknown error"; } @@ -596,6 +599,85 @@ parser_node_type(struct Parser* p, struct Parser_Error* error) return type; } +struct Pragma_Node* +parser_pragma_node(struct Parser* p, struct Parser_Error* error) +{ + // `| c_header "stdio.h"` + // `| clone always, printable + CHECK(parser_need(p, TOKEN_PIPE, error)); + + struct Pragma_Node *head = nil, *current = nil; + struct Token token = parser_peek(p); + while (!token_ends_statement(&token)) { + struct Token pragma_token = CHECK(parser_need(p, TOKEN_NAME, error)); + enum Pragma_Type pragma_type = pragma_type_from_string(pragma_token.value.name); + if (!pragma_type) { + *error = parser_error(PARSER_ERROR_EXPECTED_PRAGMA); + return nil; + } + + struct Span span = pragma_token.span; + + // parse the arguments until either statement end or comma + // arguments can either be numbers, names or strings. + uint argument_index = 0; + struct Pragma_Argument arguments[PRAGMA_ARGUMENT_MAX] = { 0 }; + + token = parser_peek(p); + while (!token_ends_statement(&token)) { + check(argument_index < PRAGMA_ARGUMENT_MAX, "too many pragma arguments"); + struct Pragma_Argument* argument = &arguments[argument_index]; + + union Token_Value* v = &token.value; + switch (token.kind) { + case TOKEN_LITERAL_INTEGER: + argument->type = PRAGMA_ARGUMENT_NUMBER; + argument->value.number = v->literal_integer; + break; + case TOKEN_LITERAL_FLOAT: + argument->type = PRAGMA_ARGUMENT_DECIMAL; + argument->value.decimal = v->literal_float; + break; + case TOKEN_LITERAL_STRING: + argument->type = PRAGMA_ARGUMENT_NAME_OR_STRING; + argument->value.name_or_string = v->literal_string; + break; + case TOKEN_NAME: + argument->type = PRAGMA_ARGUMENT_NAME_OR_STRING; + argument->value.name_or_string = v->name; + break; + default: + *error = parser_error(PARSER_ERROR_UNEXPECTED_TOKEN); + return nil; + } + argument_index++; + span = span_merge(span, token.span); + parser_next(p); + + // comma separates pragmas on a single line. + token = parser_peek(p); + if (token_is(&token, TOKEN_COMMA)) { + parser_next(p); + break; + } + if (token_ends_statement(&token)) { break; } + } + + struct Pragma_Node* pragma = pragma_node_new(pragma_type, span, pragma_token.location); + pragma->argument_count = argument_index; + memcpy(pragma->arguments, arguments, sizeof(arguments)); + + if (!head) { + head = pragma; + } else { + current->next = pragma; + } + current = pragma; + } + + return head; +} + struct Expression* parser_expression_primary_name(struct Parser* p, struct Parser_Error* error) { @@ -1152,6 +1234,26 @@ parser_statement_defer(struct Parser* p, struct Parser_Error* error) } struct Statement* +parser_statement_pragma(struct Parser* p, struct Parser_Error* error) +{ + struct Token pipe_token = parser_peek(p); + + struct Pragma_Node* pragma_node = parser_pragma_node(p, error); + if (!parser_error_is_none(error)) { + *error = parser_error(PARSER_ERROR_EXPECTED_PRAGMA); + return nil; + } + + struct Span span = {}; + FOR_EACH (struct Pragma_Node*, node, pragma_node) { + span = span_is_empty(span) ? node->span : span_merge(span, node->span); + } + + union Statement_Value value = { .pragma.inner = pragma_node }; + return statement_new(STATEMENT_PRAGMA, value, span, pipe_token.location); +} + +struct Statement* parser_statement(struct Parser* p, struct Parser_Error* error) { struct Token token = parser_peek(p); @@ -1182,6 +1284,8 @@ parser_statement(struct Parser* p, struct Parser_Error* error) return parser_statement_continue(p, error); case TOKEN_WORD_DEFER: return parser_statement_defer(p, error); + case TOKEN_PIPE: + return parser_statement_pragma(p, error); default: break; } |
