code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(101 lines)
1 // Parsing logic for binary operators
2 #include <stdbool.h>
4 #include "../ast.h"
5 #include "../stdlib/util.h"
6 #include "context.h"
7 #include "errors.h"
8 #include "expressions.h"
9 #include "suffixes.h"
10 #include "utils.h"
12 ast_e match_binary_operator(const char **pos) {
13 switch (**pos) {
14 case '+': {
15 *pos += 1;
16 return match(pos, "+") ? Concat : Plus;
18 case '-': {
19 *pos += 1;
20 if ((*pos)[0] != ' ' && (*pos)[-2] == ' ') // looks like `fn -5`
21 return Unknown;
22 return Minus;
24 case '*': *pos += 1; return Multiply;
25 case '/': *pos += 1; return Divide;
26 case '^': *pos += 1; return Power;
27 case '<': {
28 *pos += 1;
29 if (match(pos, "=")) return LessThanOrEquals; // "<="
30 else if (match(pos, ">")) return Compare; // "<>"
31 else if (match(pos, "<")) {
32 if (match(pos, "<")) return UnsignedLeftShift; // "<<<"
33 return LeftShift; // "<<"
34 } else return LessThan;
36 case '>': {
37 *pos += 1;
38 if (match(pos, "=")) return GreaterThanOrEquals; // ">="
39 if (match(pos, ">")) {
40 if (match(pos, ">")) return UnsignedRightShift; // ">>>"
41 return RightShift; // ">>"
43 return GreaterThan;
45 default: {
46 if (match(pos, "!=")) return NotEquals;
47 else if (match(pos, "==") && **pos != '=') return Equals;
48 else if (match_word(pos, "and")) return And;
49 else if (match_word(pos, "or")) return Or;
50 else if (match_word(pos, "xor")) return Xor;
51 else if (match_word(pos, "mod1")) return Mod1;
52 else if (match_word(pos, "mod")) return Mod;
53 else if (match_word(pos, "_min_")) return Min;
54 else if (match_word(pos, "_max_")) return Max;
55 else return Unknown;
60 ast_t *parse_infix_expr(parse_ctx_t *ctx, const char *pos, int min_tightness) {
61 ast_t *lhs = optional(ctx, &pos, parse_term);
62 if (!lhs) return NULL;
64 int64_t starting_line = get_line_number(ctx->file, pos);
65 int64_t starting_indent = get_indent(ctx, pos);
66 spaces(&pos);
67 for (ast_e op; (op = match_binary_operator(&pos)) != Unknown && op_tightness[op] >= min_tightness; spaces(&pos)) {
68 ast_t *key = NULL;
69 if (op == Min || op == Max) {
70 key = NewAST(ctx->file, pos, pos, Var, .name = (op == Min ? "_min_" : "_max_"));
71 for (bool progress = true; progress;) {
72 ast_t *new_term;
73 progress =
74 (false || (new_term = parse_index_suffix(ctx, key))
75 || (new_term = parse_method_call_suffix(ctx, key)) || (new_term = parse_field_suffix(ctx, key))
76 || (new_term = parse_fncall_suffix(ctx, key)) || (new_term = parse_non_optional_suffix(ctx, key)));
77 if (progress) key = new_term;
79 if (key && key->tag == Var) key = NULL;
80 else if (key) pos = key->end;
83 whitespace(ctx, &pos);
84 if (get_line_number(ctx->file, pos) != starting_line && get_indent(ctx, pos) < starting_indent)
85 parser_err(ctx, pos, eol(pos), "I expected this line to be at least as indented than the line above it");
87 ast_t *rhs = parse_infix_expr(ctx, pos, op_tightness[op] + 1);
88 if (!rhs) break;
89 pos = rhs->end;
91 if (op == Min) {
92 return NewAST(ctx->file, lhs->start, rhs->end, Min, .lhs = lhs, .rhs = rhs, .key = key);
93 } else if (op == Max) {
94 return NewAST(ctx->file, lhs->start, rhs->end, Max, .lhs = lhs, .rhs = rhs, .key = key);
95 } else {
96 lhs = new (ast_t, .file = ctx->file, .start = lhs->start, .end = rhs->end, .tag = op,
97 .__data.Plus.lhs = lhs, .__data.Plus.rhs = rhs);
100 return lhs;