1 // Recursive descent parser for parsing code
7 #include "../stdlib/util.h"
9 #include "containers.h"
11 #include "controlflow.h"
13 #include "expressions.h"
14 #include "functions.h"
21 ast_t *parse_parens(parse_ctx_t *ctx, const char *pos) {
22 const char *start = pos;
24 if (!match(&pos, "(")) return NULL;
25 whitespace(ctx, &pos);
26 ast_t *expr = optional(ctx, &pos, parse_extended_expr);
27 if (!expr) return NULL;
29 ast_t *comprehension = parse_comprehension_suffix(ctx, expr);
30 while (comprehension) {
32 pos = comprehension->end;
33 comprehension = parse_comprehension_suffix(ctx, expr);
36 whitespace(ctx, &pos);
37 expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this expression");
39 // Update the span to include the parens:
40 return new (ast_t, .file = (ctx)->file, .start = start, .end = pos, .tag = expr->tag, .__data = expr->__data);
43 ast_t *parse_reduction(parse_ctx_t *ctx, const char *pos) {
44 const char *start = pos;
45 if (!match(&pos, "(")) return NULL;
47 whitespace(ctx, &pos);
48 ast_e op = match_binary_operator(&pos);
49 if (op == Unknown) return NULL;
51 const char *op_str = binop_info[op].operator;
53 ast_t *key = NewAST(ctx->file, pos, pos, Var, .name = op_str);
54 for (bool progress = true; progress;) {
56 progress = (false || (new_term = parse_index_suffix(ctx, key))
57 || (new_term = parse_method_call_suffix(ctx, key)) || (new_term = parse_field_suffix(ctx, key))
58 || (new_term = parse_fncall_suffix(ctx, key)) || (new_term = parse_non_optional_suffix(ctx, key)));
59 if (progress) key = new_term;
61 if (key && key->tag == Var) key = NULL;
62 else if (key) pos = key->end;
64 whitespace(ctx, &pos);
65 if (!match(&pos, ":")) return NULL;
67 ast_t *iter = optional(ctx, &pos, parse_extended_expr);
68 if (!iter) return NULL;
69 ast_t *suffixed = parse_comprehension_suffix(ctx, iter);
73 suffixed = parse_comprehension_suffix(ctx, iter);
76 whitespace(ctx, &pos);
77 expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this reduction");
79 return NewAST(ctx->file, start, pos, Reduction, .iter = iter, .op = op, .key = key);
82 ast_t *parse_heap_alloc(parse_ctx_t *ctx, const char *pos) {
83 const char *start = pos;
84 if (!match(&pos, "@")) return NULL;
86 ast_t *val = expect(ctx, start, &pos, parse_term_no_suffix, "I expected an expression for this '@'");
90 if ((new_term = parse_index_suffix(ctx, val)) || (new_term = parse_fncall_suffix(ctx, val))
91 || (new_term = parse_method_call_suffix(ctx, val)) || (new_term = parse_field_suffix(ctx, val))) {
97 ast_t *ast = NewAST(ctx->file, start, pos, HeapAllocate, .value = val);
99 ast_t *next = parse_non_optional_suffix(ctx, ast);
106 ast_t *parse_stack_reference(parse_ctx_t *ctx, const char *pos) {
107 const char *start = pos;
108 if (!match(&pos, "&")) return NULL;
110 ast_t *val = expect(ctx, start, &pos, parse_term_no_suffix, "I expected an expression for this '&'");
114 if ((new_term = parse_index_suffix(ctx, val)) || (new_term = parse_fncall_suffix(ctx, val))
115 || (new_term = parse_method_call_suffix(ctx, val)) || (new_term = parse_field_suffix(ctx, val))) {
121 ast_t *ast = NewAST(ctx->file, start, pos, StackReference, .value = val);
123 ast_t *next = parse_non_optional_suffix(ctx, ast);
130 ast_t *parse_not(parse_ctx_t *ctx, const char *pos) {
131 const char *start = pos;
132 if (!match_word(&pos, "not")) return NULL;
134 ast_t *val = expect(ctx, start, &pos, parse_term, "I expected an expression for this 'not'");
135 return NewAST(ctx->file, start, pos, Not, .value = val);
138 ast_t *parse_negative(parse_ctx_t *ctx, const char *pos) {
139 const char *start = pos;
140 if (!match(&pos, "-")) return NULL;
142 ast_t *val = expect(ctx, start, &pos, parse_term, "I expected an expression for this '-'");
143 return NewAST(ctx->file, start, pos, Negative, .value = val);
146 ast_t *parse_bool(parse_ctx_t *ctx, const char *pos) {
147 const char *start = pos;
148 if (match_word(&pos, "yes")) return NewAST(ctx->file, start, pos, Bool, .b = true);
149 else if (match_word(&pos, "no")) return NewAST(ctx->file, start, pos, Bool, .b = false);
153 ast_t *parse_none(parse_ctx_t *ctx, const char *pos) {
154 const char *start = pos;
155 if (!match_word(&pos, "none")) return NULL;
156 return NewAST(ctx->file, start, pos, None);
159 ast_t *parse_var(parse_ctx_t *ctx, const char *pos) {
160 const char *start = pos;
161 const char *name = get_id(&pos);
162 if (!name) return NULL;
163 return NewAST(ctx->file, start, pos, Var, .name = name);
166 ast_t *parse_term_no_suffix(parse_ctx_t *ctx, const char *pos) {
169 (void)(false || (term = parse_none(ctx, pos)) || (term = parse_num(ctx, pos)) // Must come before int
170 || (term = parse_int(ctx, pos)) || (term = parse_negative(ctx, pos)) // Must come after num/int
171 || (term = parse_heap_alloc(ctx, pos)) || (term = parse_stack_reference(ctx, pos))
172 || (term = parse_bool(ctx, pos)) || (term = parse_text(ctx, pos, true)) || (term = parse_path(ctx, pos))
173 || (term = parse_lambda(ctx, pos)) || (term = parse_parens(ctx, pos)) || (term = parse_table(ctx, pos))
174 || (term = parse_var(ctx, pos)) || (term = parse_list(ctx, pos)) || (term = parse_reduction(ctx, pos))
175 || (term = parse_pass(ctx, pos)) || (term = parse_defer(ctx, pos)) || (term = parse_skip(ctx, pos))
176 || (term = parse_stop(ctx, pos)) || (term = parse_return(ctx, pos)) || (term = parse_not(ctx, pos))
177 || (term = parse_inline_c(ctx, pos)));
181 ast_t *parse_term(parse_ctx_t *ctx, const char *pos) {
182 const char *start = pos;
183 if (match(&pos, "???")) parser_err(ctx, start, pos, "This value needs to be filled in!");
185 ast_t *term = parse_term_no_suffix(ctx, pos);
186 if (!term) return NULL;
188 for (bool progress = true; progress;) {
191 (false || (new_term = parse_index_suffix(ctx, term)) || (new_term = parse_method_call_suffix(ctx, term))
192 || (new_term = parse_field_suffix(ctx, term)) || (new_term = parse_fncall_suffix(ctx, term))
193 || (new_term = parse_non_optional_suffix(ctx, term)));
194 if (progress) term = new_term;
199 ast_t *parse_expr(parse_ctx_t *ctx, const char *pos) {
200 return parse_infix_expr(ctx, pos, 0);
203 ast_t *parse_extended_expr(parse_ctx_t *ctx, const char *pos) {
206 if (false || (expr = optional(ctx, &pos, parse_for)) || (expr = optional(ctx, &pos, parse_while))
207 || (expr = optional(ctx, &pos, parse_if)) || (expr = optional(ctx, &pos, parse_when))
208 || (expr = optional(ctx, &pos, parse_repeat)) || (expr = optional(ctx, &pos, parse_do)))
211 return parse_expr(ctx, pos);
214 ast_t *parse_expr_str(const char *str) {
215 file_t *file = spoof_file("<string>", str);
221 const char *pos = file->text;
222 whitespace(&ctx, &pos);
223 ast_t *ast = parse_extended_expr(&ctx, pos);
225 whitespace(&ctx, &pos);
226 if (pos < file->text + file->len && *pos != '\0')
227 parser_err(&ctx, pos, pos + strlen(pos), "I couldn't parse this part of the string");