code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(98 lines)
1 // Logic for parsing container types (lists, sets, tables)
3 #include <stdarg.h>
4 #include <stdbool.h>
6 #include "../ast.h"
7 #include "../stdlib/util.h"
8 #include "context.h"
9 #include "errors.h"
10 #include "expressions.h"
11 #include "suffixes.h"
12 #include "utils.h"
14 ast_t *parse_list(parse_ctx_t *ctx, const char *pos) {
15 const char *start = pos;
16 if (!match(&pos, "[")) return NULL;
18 whitespace(ctx, &pos);
20 ast_list_t *items = NULL;
21 for (;;) {
22 ast_t *item = optional(ctx, &pos, parse_extended_expr);
23 if (!item) break;
24 ast_t *suffixed = parse_comprehension_suffix(ctx, item);
25 while (suffixed) {
26 item = suffixed;
27 pos = suffixed->end;
28 suffixed = parse_comprehension_suffix(ctx, item);
30 items = new (ast_list_t, .ast = item, .next = items);
31 if (!match_separator(ctx, &pos)) break;
33 whitespace(ctx, &pos);
34 expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this list");
36 REVERSE_LIST(items);
37 return NewAST(ctx->file, start, pos, List, .items = items);
40 ast_t *parse_table(parse_ctx_t *ctx, const char *pos) {
41 const char *start = pos;
42 if (!match(&pos, "{")) return NULL;
44 whitespace(ctx, &pos);
46 ast_list_t *entries = NULL;
47 for (;;) {
48 const char *entry_start = pos;
49 ast_t *key = optional(ctx, &pos, parse_extended_expr);
50 if (!key) break;
51 whitespace(ctx, &pos);
52 ast_t *value = NULL;
53 if (match(&pos, ":"))
54 value = expect(ctx, pos - 1, &pos, parse_expr, "I couldn't parse the value for this table entry");
55 ast_t *entry = NewAST(ctx->file, entry_start, pos, TableEntry, .key = key, .value = value);
56 ast_t *suffixed = parse_comprehension_suffix(ctx, entry);
57 while (suffixed) {
58 entry = suffixed;
59 pos = suffixed->end;
60 suffixed = parse_comprehension_suffix(ctx, entry);
62 entries = new (ast_list_t, .ast = entry, .next = entries);
63 if (!match_separator(ctx, &pos)) break;
66 REVERSE_LIST(entries);
68 whitespace(ctx, &pos);
70 ast_t *fallback = NULL, *default_value = NULL;
71 if (match(&pos, ";")) {
72 for (;;) {
73 whitespace(ctx, &pos);
74 const char *attr_start = pos;
75 if (match_word(&pos, "fallback")) {
76 whitespace(ctx, &pos);
77 if (!match(&pos, "=")) parser_err(ctx, attr_start, pos, "I expected an '=' after 'fallback'");
78 if (fallback) parser_err(ctx, attr_start, pos, "This table already has a fallback");
79 fallback = expect(ctx, attr_start, &pos, parse_expr, "I expected a fallback table");
80 } else if (match_word(&pos, "default")) {
81 whitespace(ctx, &pos);
82 if (!match(&pos, "=")) parser_err(ctx, attr_start, pos, "I expected an '=' after 'default'");
83 if (default_value) parser_err(ctx, attr_start, pos, "This table already has a default");
84 default_value = expect(ctx, attr_start, &pos, parse_expr, "I expected a default value");
85 } else {
86 break;
88 whitespace(ctx, &pos);
89 if (!match(&pos, ",")) break;
93 whitespace(ctx, &pos);
94 expect_closing(ctx, &pos, "}", "I wasn't able to parse the rest of this table");
96 return NewAST(ctx->file, start, pos, Table, .default_value = default_value, .entries = entries,
97 .fallback = fallback);