1 // Parsing logic for type definitions
7 #include "../stdlib/util.h"
11 #include "functions.h"
12 #include "statements.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;
23 const char *next = pos;
24 whitespace(ctx, &next);
25 if (get_indent(ctx, next) != indent) break;
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);
33 whitespace(ctx, &pos); // TODO: check for newline
34 // if (!(space_types & WHITESPACE_NEWLINES)) {
39 if (get_indent(ctx, next) > indent && next < eol(next))
40 parser_err(ctx, next, eol(next), "I couldn't parse this namespace declaration");
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);
56 const char *name = get_id(&pos);
57 if (!name) parser_err(ctx, start, pos, "I expected a name for this struct");
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);
69 if (match_word(&pos, "secret")) {
71 } else if (match_word(&pos, "external")) {
73 } else if (match_word(&pos, "opaque")) {
75 parser_err(ctx, pos - strlen("opaque"), pos, "A struct can't be opaque if it has fields defined");
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) {
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);
106 const char *name = get_id(&pos);
107 if (!name) parser_err(ctx, start, pos, "I expected a name for this enum");
109 if (!match(&pos, "(")) return NULL;
111 tag_ast_t *tags = NULL;
112 whitespace(ctx, &pos);
115 const char *tag_start = pos;
116 const char *tag_name = get_id(&pos);
117 if (!tag_name) break;
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");
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");
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) {
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);
168 const char *name = get_id(&pos);
169 if (!name) parser_err(ctx, start, pos, "I expected a name for this lang");
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) {
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);