Fix operator precedence and boolification
This commit is contained in:
parent
7d6af5f4c7
commit
ddd9f6e5d5
2
ast.c
2
ast.c
@ -125,7 +125,7 @@ CORD ast_to_cord(ast_t *ast)
|
||||
T(EnumDef, "(%s, tags=%r, namespace=%r)", data.name, tags_to_cord(data.tags), ast_to_cord(data.namespace))
|
||||
T(Index, "(indexed=%r, index=%r)", ast_to_cord(data.indexed), ast_to_cord(data.index))
|
||||
T(FieldAccess, "(fielded=%r, field=%s)", ast_to_cord(data.fielded), data.field)
|
||||
T(DocTest, "(expr=%r, output=%s)", ast_to_cord(data.expr), data.output)
|
||||
T(DocTest, "(expr=%r, output=%s)", ast_to_cord(data.expr), data.output ? data.output : "")
|
||||
T(Use, "(%s)", data.path)
|
||||
T(LinkerDirective, "(%s)", data.directive)
|
||||
#undef T
|
||||
|
23
compile.c
23
compile.c
@ -20,7 +20,7 @@ CORD compile_statement(ast_t *ast)
|
||||
{
|
||||
switch (ast->tag) {
|
||||
case If: case For: case While: case FunctionDef: case Return: case StructDef: case EnumDef:
|
||||
case Declare: case Assign: case UpdateAssign:
|
||||
case Declare: case Assign: case UpdateAssign: case DocTest:
|
||||
return compile(ast);
|
||||
default:
|
||||
return CORD_asprintf("(void)%r;", compile(ast));
|
||||
@ -61,12 +61,12 @@ CORD compile(ast_t *ast)
|
||||
case BINOP_MINUS: return CORD_asprintf("(%r - %r)", lhs, rhs);
|
||||
case BINOP_LSHIFT: return CORD_asprintf("(%r << %r)", lhs, rhs);
|
||||
case BINOP_RSHIFT: return CORD_asprintf("(%r >> %r)", lhs, rhs);
|
||||
case BINOP_EQ: return CORD_asprintf("(%r == %r)", lhs, rhs);
|
||||
case BINOP_NE: return CORD_asprintf("(%r != %r)", lhs, rhs);
|
||||
case BINOP_LT: return CORD_asprintf("(%r < %r)", lhs, rhs);
|
||||
case BINOP_LE: return CORD_asprintf("(%r <= %r)", lhs, rhs);
|
||||
case BINOP_GT: return CORD_asprintf("(%r > %r)", lhs, rhs);
|
||||
case BINOP_GE: return CORD_asprintf("(%r >= %r)", lhs, rhs);
|
||||
case BINOP_EQ: return CORD_asprintf("__eq(%r, %r)", lhs, rhs);
|
||||
case BINOP_NE: return CORD_asprintf("__ne(%r, %r)", lhs, rhs);
|
||||
case BINOP_LT: return CORD_asprintf("__lt(%r, %r)", lhs, rhs);
|
||||
case BINOP_LE: return CORD_asprintf("__le(%r, %r)", lhs, rhs);
|
||||
case BINOP_GT: return CORD_asprintf("__gt(%r, %r)", lhs, rhs);
|
||||
case BINOP_GE: return CORD_asprintf("__ge(%r, %r)", lhs, rhs);
|
||||
case BINOP_AND: return CORD_asprintf("and(%r, %r)", lhs, rhs);
|
||||
case BINOP_OR: return CORD_asprintf("or(%r, %r)", lhs, rhs);
|
||||
case BINOP_XOR: return CORD_asprintf("xor(%r, %r)", lhs, rhs);
|
||||
@ -285,6 +285,15 @@ CORD compile(ast_t *ast)
|
||||
code = CORD_cat(code, "} __data;\n};\n");
|
||||
return code;
|
||||
}
|
||||
case DocTest: {
|
||||
auto test = Match(ast, DocTest);
|
||||
CORD src = heap_strn(test->expr->start, (size_t)(test->expr->end - test->expr->start));
|
||||
return CORD_asprintf(
|
||||
"__test(%r, %r, %r);\n",
|
||||
compile(WrapAST(test->expr, StringLiteral, .cord=src)),
|
||||
compile(test->expr),
|
||||
compile(WrapAST(test->expr, StringLiteral, .cord=test->output)));
|
||||
}
|
||||
// Index, FieldAccess,
|
||||
// DocTest,
|
||||
// Use,
|
||||
|
28
nextlang.h
28
nextlang.h
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <err.h>
|
||||
#include <gc.h>
|
||||
#include <gc/cord.h>
|
||||
#include <stdbool.h>
|
||||
@ -52,28 +53,35 @@
|
||||
.data=memcpy(GC_MALLOC(sizeof(__items)), __items, sizeof(__items)), \
|
||||
.copy_on_write=1}; })
|
||||
|
||||
#define not(x) _Generic(x, bool: !(x), default: ~(x))
|
||||
#define and(x, y) _Generic(x, bool: (x) && (y), default: (x) & (y))
|
||||
#define or(x, y) _Generic(x, bool: (x) || (y), default: (x) | (y))
|
||||
#define xor(x, y) ((x) ^ (y))
|
||||
#define not(x) _Generic(x, bool: (bool)!(x), default: ~(x))
|
||||
#define and(x, y) _Generic(x, bool: (bool)((x) && (y)), default: ((x) & (y)))
|
||||
#define or(x, y) _Generic(x, bool: (bool)((x) || (y)), default: ((x) | (y)))
|
||||
#define xor(x, y) _Generic(x, bool: (bool)((x) ^ (y)), default: ((x) ^ (y)))
|
||||
#define mod(x, n) ((x) % (n))
|
||||
#define mod1(x, n) (((x) % (n)) + (__typeof(x))1)
|
||||
#define __cmp(x, y) (_Generic(x, CORD: CORD_cmp(x, y), char*: strcmp(x, y), const char*: strcmp(x, y), default: (x > 0) - (y > 0)))
|
||||
#define __lt(x, y) (_Generic(x, int8_t: x < y, int16_t: x < y, int32_t: x < y, int64_t: x < y, float: x < y, double: x < y, char: x < y, bool: x < y, \
|
||||
#define __lt(x, y) (bool)(_Generic(x, int8_t: x < y, int16_t: x < y, int32_t: x < y, int64_t: x < y, float: x < y, double: x < y, char: x < y, bool: x < y, \
|
||||
default: __cmp(x, y) < 0))
|
||||
#define __le(x, y) (_Generic(x, int8_t: x <= y, int16_t: x <= y, int32_t: x <= y, int64_t: x <= y, float: x <= y, double: x <= y, char: x <= y, bool: x <= y, \
|
||||
#define __le(x, y) (bool)(_Generic(x, int8_t: x <= y, int16_t: x <= y, int32_t: x <= y, int64_t: x <= y, float: x <= y, double: x <= y, char: x <= y, bool: x <= y, \
|
||||
default: __cmp(x, y) <= 0))
|
||||
#define __ge(x, y) (_Generic(x, int8_t: x >= y, int16_t: x >= y, int32_t: x >= y, int64_t: x >= y, float: x >= y, double: x >= y, char: x >= y, bool: x >= y, \
|
||||
#define __ge(x, y) (bool)(_Generic(x, int8_t: x >= y, int16_t: x >= y, int32_t: x >= y, int64_t: x >= y, float: x >= y, double: x >= y, char: x >= y, bool: x >= y, \
|
||||
default: __cmp(x, y) >= 0))
|
||||
#define __gt(x, y) (_Generic(x, int8_t: x > y, int16_t: x > y, int32_t: x > y, int64_t: x > y, float: x > y, double: x > y, char: x > y, bool: x > y, \
|
||||
#define __gt(x, y) (bool)(_Generic(x, int8_t: x > y, int16_t: x > y, int32_t: x > y, int64_t: x > y, float: x > y, double: x > y, char: x > y, bool: x > y, \
|
||||
default: __cmp(x, y) > 0))
|
||||
#define __eq(x, y) (_Generic(x, int8_t: x == y, int16_t: x == y, int32_t: x == y, int64_t: x == y, float: x == y, double: x == y, char: x == y, bool: x == y, \
|
||||
#define __eq(x, y) (bool)(_Generic(x, int8_t: x == y, int16_t: x == y, int32_t: x == y, int64_t: x == y, float: x == y, double: x == y, char: x == y, bool: x == y, \
|
||||
default: __cmp(x, y) == 0))
|
||||
#define __ne(x, y) (_Generic(x, int8_t: x != y, int16_t: x != y, int32_t: x != y, int64_t: x != y, float: x != y, double: x != y, char: x != y, bool: x != y, \
|
||||
#define __ne(x, y) (bool)(_Generic(x, int8_t: x != y, int16_t: x != y, int32_t: x != y, int64_t: x != y, float: x != y, double: x != y, char: x != y, bool: x != y, \
|
||||
default: __cmp(x, y) != 0))
|
||||
#define min(x, y) ({ __declare(__min_lhs, x); __declare(__min_rhs, y); __le(__min_lhs, __min_rhs) ? __min_lhs : __min_rhs; })
|
||||
#define max(x, y) ({ __declare(__min_lhs, x); __declare(__min_rhs, y); __ge(__min_lhs, __min_rhs) ? __min_lhs : __min_rhs; })
|
||||
|
||||
#define say(str) puts(CORD_to_const_char_star(__cord(str)))
|
||||
#define __test(src, expr, expected) do { \
|
||||
CORD __result = __cord(expr); \
|
||||
say(CORD_catn(5, USE_COLOR ? "\x1b[33m>>>\x1b[0;1m " : ">>> ", src, USE_COLOR ? "\n\x1b[0;33m===\x1b[0;35m " : "\n=== ", __result, "\x1b[m")); \
|
||||
if (expected && CORD_cmp(__result, expected)) { \
|
||||
errx(1, "I expected:\n%s but got:\n%s", CORD_to_const_char_star(expected), CORD_to_const_char_star(__result)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
74
parse.c
74
parse.c
@ -30,16 +30,17 @@ extern void builtin_fail(const char *fmt, ...);
|
||||
#define STUB_PARSER(name) PARSER(name) { (void)ctx; (void)pos; return NULL; }
|
||||
|
||||
int op_tightness[] = {
|
||||
[BINOP_POWER]=1,
|
||||
[BINOP_MULT]=2, [BINOP_DIVIDE]=2, [BINOP_MOD]=2, [BINOP_MOD1]=2,
|
||||
[BINOP_PLUS]=3, [BINOP_MINUS]=3,
|
||||
[BINOP_CONCAT]=4,
|
||||
[BINOP_POWER]=9,
|
||||
[BINOP_MULT]=8, [BINOP_DIVIDE]=8, [BINOP_MOD]=8, [BINOP_MOD1]=8,
|
||||
[BINOP_PLUS]=7, [BINOP_MINUS]=7,
|
||||
[BINOP_CONCAT]=6,
|
||||
[BINOP_LSHIFT]=5, [BINOP_RSHIFT]=5,
|
||||
[BINOP_MIN]=6, [BINOP_MAX]=6,
|
||||
[BINOP_EQ]=7, [BINOP_NE]=7,
|
||||
[BINOP_LT]=8, [BINOP_LE]=8, [BINOP_GT]=8, [BINOP_GE]=8,
|
||||
[BINOP_AND]=9, [BINOP_OR]=9, [BINOP_XOR]=9,
|
||||
[BINOP_MIN]=4, [BINOP_MAX]=4,
|
||||
[BINOP_EQ]=3, [BINOP_NE]=3,
|
||||
[BINOP_LT]=2, [BINOP_LE]=2, [BINOP_GT]=2, [BINOP_GE]=2,
|
||||
[BINOP_AND]=1, [BINOP_OR]=1, [BINOP_XOR]=1,
|
||||
};
|
||||
#define MAX_TIGHTNESS 9
|
||||
|
||||
static const char *keywords[] = {
|
||||
"yes", "xor", "while", "use", "then", "struct", "stop", "skip", "return",
|
||||
@ -1172,39 +1173,38 @@ static ast_t *parse_infix_expr(parse_ctx_t *ctx, const char *pos, int min_tightn
|
||||
if (!lhs) return NULL;
|
||||
|
||||
spaces(&pos);
|
||||
binop_e op = match_binary_operator(&pos);
|
||||
if (op == BINOP_UNKNOWN || op_tightness[op] < min_tightness)
|
||||
return lhs;
|
||||
for (binop_e op; (op=match_binary_operator(&pos)) != BINOP_UNKNOWN && op_tightness[op] >= min_tightness; spaces(&pos)) {
|
||||
ast_t *key = NULL;
|
||||
if (op == BINOP_MIN || op == BINOP_MAX) {
|
||||
key = NewAST(ctx->file, pos, pos, Var, .name=op == BINOP_MIN ? "_min_" : "_max_");
|
||||
for (bool progress = true; progress; ) {
|
||||
ast_t *new_term;
|
||||
progress = (false
|
||||
|| (new_term=parse_index_suffix(ctx, key))
|
||||
|| (new_term=parse_field_suffix(ctx, key))
|
||||
|| (new_term=parse_fncall_suffix(ctx, key, NORMAL_FUNCTION))
|
||||
);
|
||||
if (progress) key = new_term;
|
||||
}
|
||||
if (key->tag == Var) key = NULL;
|
||||
else pos = key->end;
|
||||
|
||||
ast_t *key = NULL;
|
||||
if (op == BINOP_MIN || op == BINOP_MAX) {
|
||||
key = NewAST(ctx->file, pos, pos, Var, .name=op == BINOP_MIN ? "_min_" : "_max_");
|
||||
for (bool progress = true; progress; ) {
|
||||
ast_t *new_term;
|
||||
progress = (false
|
||||
|| (new_term=parse_index_suffix(ctx, key))
|
||||
|| (new_term=parse_field_suffix(ctx, key))
|
||||
|| (new_term=parse_fncall_suffix(ctx, key, NORMAL_FUNCTION))
|
||||
);
|
||||
if (progress) key = new_term;
|
||||
}
|
||||
if (key->tag == Var) key = NULL;
|
||||
else pos = key->end;
|
||||
|
||||
spaces(&pos);
|
||||
ast_t *rhs = parse_infix_expr(ctx, pos, op_tightness[op] + 1);
|
||||
if (!rhs) break;
|
||||
pos = rhs->end;
|
||||
|
||||
if (op == BINOP_MIN) {
|
||||
return NewAST(ctx->file, lhs->start, rhs->end, Min, .lhs=lhs, .rhs=rhs, .key=key);
|
||||
} else if (op == BINOP_MAX) {
|
||||
return NewAST(ctx->file, lhs->start, rhs->end, Max, .lhs=lhs, .rhs=rhs, .key=key);
|
||||
} else {
|
||||
lhs = NewAST(ctx->file, lhs->start, rhs->end, BinaryOp, .lhs=lhs, .op=op, .rhs=rhs);
|
||||
}
|
||||
}
|
||||
spaces(&pos);
|
||||
ast_t *rhs = parse_infix_expr(ctx, pos, op_tightness[op]);
|
||||
if (!rhs) return lhs;
|
||||
pos = rhs->end;
|
||||
|
||||
switch (op) {
|
||||
case BINOP_MIN:
|
||||
return NewAST(ctx->file, lhs->start, rhs->end, Min, .lhs=lhs, .rhs=rhs, .key=key);
|
||||
case BINOP_MAX:
|
||||
return NewAST(ctx->file, lhs->start, rhs->end, Max, .lhs=lhs, .rhs=rhs, .key=key);
|
||||
default:
|
||||
return NewAST(ctx->file, lhs->start, rhs->end, BinaryOp, .lhs=lhs, .rhs=rhs, .op=op);
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
ast_t *parse_expr(parse_ctx_t *ctx, const char *pos) {
|
||||
|
Loading…
Reference in New Issue
Block a user