code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(183 lines)
1 // Parsing logic for type definitions
3 #include <stdbool.h>
4 #include <string.h>
6 #include "../ast.h"
7 #include "../stdlib/util.h"
8 #include "context.h"
9 #include "errors.h"
10 #include "files.h"
11 #include "functions.h"
12 #include "statements.h"
13 #include "text.h"
14 #include "typedefs.h"
15 #include "utils.h"
17 ast_t *parse_namespace(parse_ctx_t *ctx, const char *pos) {
18 const char *start = pos;
19 whitespace(ctx, &pos);
20 int64_t indent = get_indent(ctx, pos);
21 ast_list_t *statements = NULL;
22 for (;;) {
23 const char *next = pos;
24 whitespace(ctx, &next);
25 if (get_indent(ctx, next) != indent) break;
26 ast_t *stmt;
27 if ((stmt = optional(ctx, &pos, parse_struct_def)) || (stmt = optional(ctx, &pos, parse_func_def))
28 || (stmt = optional(ctx, &pos, parse_enum_def)) || (stmt = optional(ctx, &pos, parse_lang_def))
29 || (stmt = optional(ctx, &pos, parse_convert_def)) || (stmt = optional(ctx, &pos, parse_use))
30 || (stmt = optional(ctx, &pos, parse_inline_c)) || (stmt = optional(ctx, &pos, parse_declaration))) {
31 statements = new (ast_list_t, .ast = stmt, .next = statements);
32 pos = stmt->end;
33 whitespace(ctx, &pos); // TODO: check for newline
34 // if (!(space_types & WHITESPACE_NEWLINES)) {
35 // pos = stmt->end;
36 // break;
37 // }
38 } else {
39 if (get_indent(ctx, next) > indent && next < eol(next))
40 parser_err(ctx, next, eol(next), "I couldn't parse this namespace declaration");
41 break;
44 REVERSE_LIST(statements);
45 return NewAST(ctx->file, start, pos, Block, .statements = statements);
48 ast_t *parse_struct_def(parse_ctx_t *ctx, const char *pos) {
49 // struct Foo(...) [: \n body]
50 const char *start = pos;
51 if (!match_word(&pos, "struct")) return NULL;
53 int64_t starting_indent = get_indent(ctx, pos);
55 spaces(&pos);
56 const char *name = get_id(&pos);
57 if (!name) parser_err(ctx, start, pos, "I expected a name for this struct");
58 spaces(&pos);
60 if (!match(&pos, "(")) parser_err(ctx, pos, pos, "I expected a '(' and a list of fields here");
62 arg_ast_t *fields = parse_args(ctx, &pos);
64 whitespace(ctx, &pos);
65 bool secret = false, external = false, opaque = false;
66 if (match(&pos, ";")) { // Extra flags
67 whitespace(ctx, &pos);
68 for (;;) {
69 if (match_word(&pos, "secret")) {
70 secret = true;
71 } else if (match_word(&pos, "external")) {
72 external = true;
73 } else if (match_word(&pos, "opaque")) {
74 if (fields)
75 parser_err(ctx, pos - strlen("opaque"), pos, "A struct can't be opaque if it has fields defined");
76 opaque = true;
77 } else {
78 break;
81 if (!match_separator(ctx, &pos)) break;
85 expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this struct");
87 ast_t *namespace = NULL;
88 const char *ns_pos = pos;
89 whitespace(ctx, &ns_pos);
90 int64_t ns_indent = get_indent(ctx, ns_pos);
91 if (ns_indent > starting_indent) {
92 pos = ns_pos;
93 namespace = optional(ctx, &pos, parse_namespace);
95 if (!namespace) namespace = NewAST(ctx->file, pos, pos, Block, .statements = NULL);
96 return NewAST(ctx->file, start, pos, StructDef, .name = name, .fields = fields, .namespace = namespace,
97 .secret = secret, .external = external, .opaque = opaque);
100 ast_t *parse_enum_def(parse_ctx_t *ctx, const char *pos) {
101 // tagged union: enum Foo(a, b(x:Int,y:Int)=5, ...) [: \n namespace]
102 const char *start = pos;
103 if (!match_word(&pos, "enum")) return NULL;
104 int64_t starting_indent = get_indent(ctx, pos);
105 spaces(&pos);
106 const char *name = get_id(&pos);
107 if (!name) parser_err(ctx, start, pos, "I expected a name for this enum");
108 spaces(&pos);
109 if (!match(&pos, "(")) return NULL;
111 tag_ast_t *tags = NULL;
112 whitespace(ctx, &pos);
113 for (;;) {
114 spaces(&pos);
115 const char *tag_start = pos;
116 const char *tag_name = get_id(&pos);
117 if (!tag_name) break;
119 spaces(&pos);
120 arg_ast_t *fields;
121 bool secret = false;
122 if (match(&pos, "(")) {
123 whitespace(ctx, &pos);
124 fields = parse_args(ctx, &pos);
125 whitespace(ctx, &pos);
126 if (match(&pos, ";")) { // Extra flags
127 whitespace(ctx, &pos);
128 secret = match_word(&pos, "secret");
129 whitespace(ctx, &pos);
131 expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this tagged union member");
132 } else {
133 fields = NULL;
136 tags = new (tag_ast_t, .file = ctx->file, .start = tag_start, .end = pos, .name = tag_name, .fields = fields,
137 .secret = secret, .next = tags);
139 if (!match_separator(ctx, &pos)) break;
142 whitespace(ctx, &pos);
143 expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this enum definition");
145 REVERSE_LIST(tags);
147 if (tags == NULL) parser_err(ctx, start, pos, "This enum does not have any tags!");
149 ast_t *namespace = NULL;
150 const char *ns_pos = pos;
151 whitespace(ctx, &ns_pos);
152 int64_t ns_indent = get_indent(ctx, ns_pos);
153 if (ns_indent > starting_indent) {
154 pos = ns_pos;
155 namespace = optional(ctx, &pos, parse_namespace);
157 if (!namespace) namespace = NewAST(ctx->file, pos, pos, Block, .statements = NULL);
159 return NewAST(ctx->file, start, pos, EnumDef, .name = name, .tags = tags, .namespace = namespace);
162 ast_t *parse_lang_def(parse_ctx_t *ctx, const char *pos) {
163 const char *start = pos;
164 // lang Name: [namespace...]
165 if (!match_word(&pos, "lang")) return NULL;
166 int64_t starting_indent = get_indent(ctx, pos);
167 spaces(&pos);
168 const char *name = get_id(&pos);
169 if (!name) parser_err(ctx, start, pos, "I expected a name for this lang");
170 spaces(&pos);
172 ast_t *namespace = NULL;
173 const char *ns_pos = pos;
174 whitespace(ctx, &ns_pos);
175 int64_t ns_indent = get_indent(ctx, ns_pos);
176 if (ns_indent > starting_indent) {
177 pos = ns_pos;
178 namespace = optional(ctx, &pos, parse_namespace);
180 if (!namespace) namespace = NewAST(ctx->file, pos, pos, Block, .statements = NULL);
182 return NewAST(ctx->file, start, pos, LangDef, .name = name, .namespace = namespace);