From c859ed479227cee2cecedb83d74a40acf9758051 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 25 Aug 2025 00:55:29 -0400 Subject: Split out type parsing --- src/parse/functions.c | 1 + src/parse/parse.c | 142 +-------------------------------------------- src/parse/parse.h | 8 --- src/parse/types.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/parse/types.h | 10 ++++ 5 files changed, 168 insertions(+), 149 deletions(-) create mode 100644 src/parse/types.c (limited to 'src') diff --git a/src/parse/functions.c b/src/parse/functions.c index 69c695fd..7786da7a 100644 --- a/src/parse/functions.c +++ b/src/parse/functions.c @@ -14,6 +14,7 @@ #include "errors.h" #include "functions.h" #include "parse.h" +#include "types.h" #include "utils.h" public diff --git a/src/parse/parse.c b/src/parse/parse.c index df3694cf..52399e93 100644 --- a/src/parse/parse.c +++ b/src/parse/parse.c @@ -20,6 +20,7 @@ #include "functions.h" #include "numbers.h" #include "parse.h" +#include "types.h" #include "utils.h" static const char closing[128] = {['('] = ')', ['['] = ']', ['<'] = '>', ['{'] = '}'}; @@ -73,128 +74,6 @@ ast_t *parse_parens(parse_ctx_t *ctx, const char *pos) { return new (ast_t, .file = (ctx)->file, .start = start, .end = pos, .tag = expr->tag, .__data = expr->__data); } -type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - if (!match(&pos, "{")) return NULL; - whitespace(&pos); - type_ast_t *key_type = parse_type(ctx, pos); - if (!key_type) return NULL; - pos = key_type->end; - whitespace(&pos); - type_ast_t *value_type = NULL; - if (match(&pos, "=")) { - value_type = expect(ctx, start, &pos, parse_type, "I couldn't parse the rest of this table type"); - } else { - return NULL; - } - spaces(&pos); - ast_t *default_value = NULL; - if (match(&pos, ";") && match_word(&pos, "default")) { - expect_str(ctx, pos, &pos, "=", "I expected an '=' here"); - default_value = - expect(ctx, start, &pos, parse_extended_expr, "I couldn't parse the default value for this table"); - } - whitespace(&pos); - expect_closing(ctx, &pos, "}", "I wasn't able to parse the rest of this table type"); - return NewTypeAST(ctx->file, start, pos, TableTypeAST, .key = key_type, .value = value_type, - .default_value = default_value); -} - -type_ast_t *parse_set_type(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - if (!match(&pos, "|")) return NULL; - whitespace(&pos); - type_ast_t *item_type = parse_type(ctx, pos); - if (!item_type) return NULL; - pos = item_type->end; - whitespace(&pos); - expect_closing(ctx, &pos, "|", "I wasn't able to parse the rest of this set type"); - return NewTypeAST(ctx->file, start, pos, SetTypeAST, .item = item_type); -} - -type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - if (!match_word(&pos, "func")) return NULL; - spaces(&pos); - expect_str(ctx, start, &pos, "(", "I expected a parenthesis here"); - arg_ast_t *args = parse_args(ctx, &pos); - spaces(&pos); - type_ast_t *ret = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL; - expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function type"); - return NewTypeAST(ctx->file, start, pos, FunctionTypeAST, .args = args, .ret = ret); -} - -type_ast_t *parse_list_type(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - if (!match(&pos, "[")) return NULL; - type_ast_t *type = expect(ctx, start, &pos, parse_type, "I couldn't parse a list item type after this point"); - expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this list type"); - return NewTypeAST(ctx->file, start, pos, ListTypeAST, .item = type); -} - -type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - bool is_stack; - if (match(&pos, "@")) is_stack = false; - else if (match(&pos, "&")) is_stack = true; - else return NULL; - - spaces(&pos); - type_ast_t *type = - expect(ctx, start, &pos, parse_non_optional_type, "I couldn't parse a pointer type after this point"); - type_ast_t *ptr_type = NewTypeAST(ctx->file, start, pos, PointerTypeAST, .pointed = type, .is_stack = is_stack); - spaces(&pos); - while (match(&pos, "?")) - ptr_type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type = ptr_type); - return ptr_type; -} - -type_ast_t *parse_type_name(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - const char *id = get_id(&pos); - if (!id) return NULL; - for (;;) { - const char *next = pos; - spaces(&next); - if (!match(&next, ".")) break; - const char *next_id = get_id(&next); - if (!next_id) break; - id = String(id, ".", next_id); - pos = next; - } - return NewTypeAST(ctx->file, start, pos, VarTypeAST, .name = id); -} - -type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - type_ast_t *type = NULL; - bool success = (false || (type = parse_pointer_type(ctx, pos)) || (type = parse_list_type(ctx, pos)) - || (type = parse_table_type(ctx, pos)) || (type = parse_set_type(ctx, pos)) - || (type = parse_type_name(ctx, pos)) || (type = parse_func_type(ctx, pos))); - if (!success && match(&pos, "(")) { - whitespace(&pos); - type = optional(ctx, &pos, parse_type); - if (!type) return NULL; - whitespace(&pos); - expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this type"); - type->start = start; - type->end = pos; - } - - return type; -} - -type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos) { - const char *start = pos; - type_ast_t *type = parse_non_optional_type(ctx, pos); - if (!type) return NULL; - pos = type->end; - spaces(&pos); - while (match(&pos, "?")) - type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type = type); - return type; -} - ast_t *parse_field_suffix(parse_ctx_t *ctx, ast_t *lhs) { if (!lhs) return NULL; const char *pos = lhs->end; @@ -1476,25 +1355,6 @@ ast_t *parse_use(parse_ctx_t *ctx, const char *pos) { return NewAST(ctx->file, start, pos, Use, .var = var, .path = name, .what = what); } -type_ast_t *parse_type_str(const char *str) { - file_t *file = spoof_file("", str); - parse_ctx_t ctx = { - .file = file, - .on_err = NULL, - }; - - const char *pos = file->text; - whitespace(&pos); - type_ast_t *ast = parse_type(&ctx, pos); - if (!ast) return ast; - pos = ast->end; - whitespace(&pos); - if (strlen(pos) > 0) { - parser_err(&ctx, pos, pos + strlen(pos), "I couldn't parse this part of the type"); - } - return ast; -} - ast_t *parse(const char *str) { file_t *file = spoof_file("", str); parse_ctx_t ctx = { diff --git a/src/parse/parse.h b/src/parse/parse.h index c0eff43c..83f824db 100644 --- a/src/parse/parse.h +++ b/src/parse/parse.h @@ -17,14 +17,6 @@ ast_t *parse_method_call_suffix(parse_ctx_t *ctx, ast_t *self); ast_t *parse_non_optional_suffix(parse_ctx_t *ctx, ast_t *lhs); ast_t *parse_optional_conditional_suffix(parse_ctx_t *ctx, ast_t *stmt); ast_t *parse_optional_suffix(parse_ctx_t *ctx, ast_t *lhs); -type_ast_t *parse_list_type(parse_ctx_t *ctx, const char *pos); -type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos); -type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos); -type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos); -type_ast_t *parse_set_type(parse_ctx_t *ctx, const char *pos); -type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos); -type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos); -type_ast_t *parse_type_name(parse_ctx_t *ctx, const char *pos); ast_t *parse_assignment(parse_ctx_t *ctx, const char *pos); ast_t *parse_block(parse_ctx_t *ctx, const char *pos); ast_t *parse_bool(parse_ctx_t *ctx, const char *pos); diff --git a/src/parse/types.c b/src/parse/types.c new file mode 100644 index 00000000..36ddde45 --- /dev/null +++ b/src/parse/types.c @@ -0,0 +1,156 @@ +#include +#include +#include + +#include +#include + +#include "../ast.h" +#include "../stdlib/print.h" +#include "context.h" +#include "errors.h" +#include "functions.h" +#include "parse.h" +#include "types.h" +#include "utils.h" + +type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + if (!match(&pos, "{")) return NULL; + whitespace(&pos); + type_ast_t *key_type = parse_type(ctx, pos); + if (!key_type) return NULL; + pos = key_type->end; + whitespace(&pos); + type_ast_t *value_type = NULL; + if (match(&pos, "=")) { + value_type = expect(ctx, start, &pos, parse_type, "I couldn't parse the rest of this table type"); + } else { + return NULL; + } + spaces(&pos); + ast_t *default_value = NULL; + if (match(&pos, ";") && match_word(&pos, "default")) { + expect_str(ctx, pos, &pos, "=", "I expected an '=' here"); + default_value = + expect(ctx, start, &pos, parse_extended_expr, "I couldn't parse the default value for this table"); + } + whitespace(&pos); + expect_closing(ctx, &pos, "}", "I wasn't able to parse the rest of this table type"); + return NewTypeAST(ctx->file, start, pos, TableTypeAST, .key = key_type, .value = value_type, + .default_value = default_value); +} + +type_ast_t *parse_set_type(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + if (!match(&pos, "|")) return NULL; + whitespace(&pos); + type_ast_t *item_type = parse_type(ctx, pos); + if (!item_type) return NULL; + pos = item_type->end; + whitespace(&pos); + expect_closing(ctx, &pos, "|", "I wasn't able to parse the rest of this set type"); + return NewTypeAST(ctx->file, start, pos, SetTypeAST, .item = item_type); +} + +type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + if (!match_word(&pos, "func")) return NULL; + spaces(&pos); + expect_str(ctx, start, &pos, "(", "I expected a parenthesis here"); + arg_ast_t *args = parse_args(ctx, &pos); + spaces(&pos); + type_ast_t *ret = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL; + expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function type"); + return NewTypeAST(ctx->file, start, pos, FunctionTypeAST, .args = args, .ret = ret); +} + +type_ast_t *parse_list_type(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + if (!match(&pos, "[")) return NULL; + type_ast_t *type = expect(ctx, start, &pos, parse_type, "I couldn't parse a list item type after this point"); + expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this list type"); + return NewTypeAST(ctx->file, start, pos, ListTypeAST, .item = type); +} + +type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + bool is_stack; + if (match(&pos, "@")) is_stack = false; + else if (match(&pos, "&")) is_stack = true; + else return NULL; + + spaces(&pos); + type_ast_t *type = + expect(ctx, start, &pos, parse_non_optional_type, "I couldn't parse a pointer type after this point"); + type_ast_t *ptr_type = NewTypeAST(ctx->file, start, pos, PointerTypeAST, .pointed = type, .is_stack = is_stack); + spaces(&pos); + while (match(&pos, "?")) + ptr_type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type = ptr_type); + return ptr_type; +} + +type_ast_t *parse_type_name(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + const char *id = get_id(&pos); + if (!id) return NULL; + for (;;) { + const char *next = pos; + spaces(&next); + if (!match(&next, ".")) break; + const char *next_id = get_id(&next); + if (!next_id) break; + id = String(id, ".", next_id); + pos = next; + } + return NewTypeAST(ctx->file, start, pos, VarTypeAST, .name = id); +} + +type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + type_ast_t *type = NULL; + bool success = (false || (type = parse_pointer_type(ctx, pos)) || (type = parse_list_type(ctx, pos)) + || (type = parse_table_type(ctx, pos)) || (type = parse_set_type(ctx, pos)) + || (type = parse_type_name(ctx, pos)) || (type = parse_func_type(ctx, pos))); + if (!success && match(&pos, "(")) { + whitespace(&pos); + type = optional(ctx, &pos, parse_type); + if (!type) return NULL; + whitespace(&pos); + expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this type"); + type->start = start; + type->end = pos; + } + + return type; +} + +type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos) { + const char *start = pos; + type_ast_t *type = parse_non_optional_type(ctx, pos); + if (!type) return NULL; + pos = type->end; + spaces(&pos); + while (match(&pos, "?")) + type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type = type); + return type; +} + +type_ast_t *parse_type_str(const char *str) { + file_t *file = spoof_file("", str); + parse_ctx_t ctx = { + .file = file, + .on_err = NULL, + }; + + const char *pos = file->text; + whitespace(&pos); + type_ast_t *ast = parse_type(&ctx, pos); + if (!ast) return ast; + pos = ast->end; + whitespace(&pos); + if (strlen(pos) > 0) { + parser_err(&ctx, pos, pos + strlen(pos), "I couldn't parse this part of the type"); + } + return ast; +} diff --git a/src/parse/types.h b/src/parse/types.h index 1231f5ed..186d5322 100644 --- a/src/parse/types.h +++ b/src/parse/types.h @@ -2,5 +2,15 @@ #pragma once #include "../ast.h" +#include "context.h" type_ast_t *parse_type_str(const char *str); + +type_ast_t *parse_list_type(parse_ctx_t *ctx, const char *pos); +type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos); +type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos); +type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos); +type_ast_t *parse_set_type(parse_ctx_t *ctx, const char *pos); +type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos); +type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos); +type_ast_t *parse_type_name(parse_ctx_t *ctx, const char *pos); -- cgit v1.2.3