code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(191 lines)
1 // Parsing logic for parsing type annotations
3 #include <stdarg.h>
4 #include <stdbool.h>
5 #include <string.h>
7 #include <unictype.h>
8 #include <uniname.h>
10 #include "../ast.h"
11 #include "../stdlib/datatypes.h"
12 #include "../stdlib/print.h"
13 #include "../stdlib/text.h"
14 #include "context.h"
15 #include "errors.h"
16 #include "expressions.h"
17 #include "functions.h"
18 #include "types.h"
19 #include "utils.h"
21 type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos) {
22 const char *start = pos;
23 if (!match(&pos, "{")) return NULL;
24 whitespace(ctx, &pos);
25 type_ast_t *key_type = parse_type(ctx, pos);
26 if (!key_type) return NULL;
27 pos = key_type->end;
28 whitespace(ctx, &pos);
29 type_ast_t *value_type = NULL;
30 if (match(&pos, ":")) {
31 value_type = expect(ctx, start, &pos, parse_type, "I couldn't parse the rest of this table type");
33 spaces(&pos);
34 ast_t *default_value = NULL;
35 if (match(&pos, "=")) {
36 default_value =
37 expect(ctx, start, &pos, parse_extended_expr, "I couldn't parse the default value for this table");
39 whitespace(ctx, &pos);
40 expect_closing(ctx, &pos, "}", "I wasn't able to parse the rest of this table type");
41 return NewTypeAST(ctx->file, start, pos, TableTypeAST, .key = key_type, .value = value_type,
42 .default_value = default_value);
45 type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos) {
46 const char *start = pos;
47 if (!match_word(&pos, "func")) return NULL;
48 spaces(&pos);
49 expect_str(ctx, start, &pos, "(", "I expected a parenthesis here");
50 arg_ast_t *args = parse_args(ctx, &pos);
51 spaces(&pos);
52 type_ast_t *ret = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL;
53 expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function type");
54 return NewTypeAST(ctx->file, start, pos, FunctionTypeAST, .args = args, .ret = ret);
57 type_ast_t *parse_list_type(parse_ctx_t *ctx, const char *pos) {
58 const char *start = pos;
59 if (!match(&pos, "[")) return NULL;
60 type_ast_t *type = expect(ctx, start, &pos, parse_type, "I couldn't parse a list item type after this point");
61 expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this list type");
62 return NewTypeAST(ctx->file, start, pos, ListTypeAST, .item = type);
65 type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos) {
66 const char *start = pos;
67 bool is_stack;
68 if (match(&pos, "@")) is_stack = false;
69 else if (match(&pos, "&")) is_stack = true;
70 else return NULL;
72 spaces(&pos);
73 type_ast_t *type =
74 expect(ctx, start, &pos, parse_non_optional_type, "I couldn't parse a pointer type after this point");
75 type_ast_t *ptr_type = NewTypeAST(ctx->file, start, pos, PointerTypeAST, .pointed = type, .is_stack = is_stack);
76 spaces(&pos);
77 while (match(&pos, "?"))
78 ptr_type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type = ptr_type);
79 return ptr_type;
82 type_ast_t *parse_enum_type(parse_ctx_t *ctx, const char *pos) {
83 // tagged union: enum(A, B(x:Int,y:Int)=5, ...)
84 const char *start = pos;
85 if (!match_word(&pos, "enum")) return NULL;
86 spaces(&pos);
87 if (!match(&pos, "(")) return NULL;
89 tag_ast_t *tags = NULL;
90 whitespace(ctx, &pos);
91 for (;;) {
92 spaces(&pos);
93 const char *tag_start = pos;
94 const char *tag_name = get_id(&pos);
95 if (!tag_name) break;
97 spaces(&pos);
98 arg_ast_t *fields;
99 bool secret = false;
100 if (match(&pos, "(")) {
101 whitespace(ctx, &pos);
102 fields = parse_args(ctx, &pos);
103 whitespace(ctx, &pos);
104 if (match(&pos, ";")) { // Extra flags
105 whitespace(ctx, &pos);
106 secret = match_word(&pos, "secret");
107 whitespace(ctx, &pos);
109 expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this tagged union member");
110 } else {
111 fields = NULL;
114 tags = new (tag_ast_t, .file = ctx->file, .start = tag_start, .end = pos, .name = tag_name, .fields = fields,
115 .secret = secret, .next = tags);
117 if (!match_separator(ctx, &pos)) break;
120 whitespace(ctx, &pos);
121 expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this enum definition");
123 REVERSE_LIST(tags);
124 Text_t name = Texts("enum$", (int64_t)(start - ctx->file->text));
125 return NewTypeAST(ctx->file, start, pos, EnumTypeAST, .name = name, .tags = tags);
128 type_ast_t *parse_type_name(parse_ctx_t *ctx, const char *pos) {
129 const char *start = pos;
130 const char *id = get_id(&pos);
131 if (!id) return NULL;
132 for (;;) {
133 const char *next = pos;
134 spaces(&next);
135 if (!match(&next, ".")) break;
136 const char *next_id = get_id(&next);
137 if (!next_id) break;
138 id = String(id, ".", next_id);
139 pos = next;
141 return NewTypeAST(ctx->file, start, pos, VarTypeAST, .name = id);
144 type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos) {
145 const char *start = pos;
146 type_ast_t *type = NULL;
147 bool success = (false || (type = parse_pointer_type(ctx, pos)) || (type = parse_list_type(ctx, pos))
148 || (type = parse_table_type(ctx, pos)) || (type = parse_enum_type(ctx, pos))
149 || (type = parse_type_name(ctx, pos)) || (type = parse_func_type(ctx, pos)));
150 if (!success && match(&pos, "(")) {
151 whitespace(ctx, &pos);
152 type = optional(ctx, &pos, parse_type);
153 if (!type) return NULL;
154 whitespace(ctx, &pos);
155 expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this type");
156 type->start = start;
157 type->end = pos;
160 return type;
163 type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos) {
164 const char *start = pos;
165 type_ast_t *type = parse_non_optional_type(ctx, pos);
166 if (!type) return NULL;
167 pos = type->end;
168 spaces(&pos);
169 while (match(&pos, "?"))
170 type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type = type);
171 return type;
174 type_ast_t *parse_type_str(const char *str) {
175 file_t *file = spoof_file("<type>", str);
176 parse_ctx_t ctx = {
177 .file = file,
178 .on_err = NULL,
181 const char *pos = file->text;
182 whitespace(&ctx, &pos);
183 type_ast_t *ast = parse_type(&ctx, pos);
184 if (!ast) return ast;
185 pos = ast->end;
186 whitespace(&ctx, &pos);
187 if (strlen(pos) > 0) {
188 parser_err(&ctx, pos, pos + strlen(pos), "I couldn't parse this part of the type");
190 return ast;