1 // Parsing logic for binary operators
5 #include "../stdlib/util.h"
8 #include "expressions.h"
12 ast_e match_binary_operator(const char **pos) {
16 return match(pos, "+") ? Concat : Plus;
20 if ((*pos)[0] != ' ' && (*pos)[-2] == ' ') // looks like `fn -5`
24 case '*': *pos += 1; return Multiply;
25 case '/': *pos += 1; return Divide;
26 case '^': *pos += 1; return Power;
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;
38 if (match(pos, "=")) return GreaterThanOrEquals; // ">="
39 if (match(pos, ">")) {
40 if (match(pos, ">")) return UnsignedRightShift; // ">>>"
41 return RightShift; // ">>"
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;
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);
67 for (ast_e op; (op = match_binary_operator(&pos)) != Unknown && op_tightness[op] >= min_tightness; spaces(&pos)) {
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;) {
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);
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);
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);