|
@@ -309,6 +309,11 @@ typedef struct {
|
|
|
T_EQUALS,
|
|
|
T_NOTEQUALS,
|
|
|
T_PLUSASSIGN,
|
|
|
+ T_MINUSASSIGN,
|
|
|
+ T_SLASHASSIGN,
|
|
|
+ T_STARASSIGN,
|
|
|
+ T_SLASHSLASHASSIGN,
|
|
|
+ T_PERCENTASSIGN,
|
|
|
T_BARBAR,
|
|
|
T_ANDAND,
|
|
|
T_STARSTAR,
|
|
@@ -322,17 +327,20 @@ typedef struct {
|
|
|
T_COLON,
|
|
|
T_BAR,
|
|
|
T_AND,
|
|
|
- T_RAISE,
|
|
|
T_LT,
|
|
|
T_LTLT,
|
|
|
T_GT,
|
|
|
T_GTGT,
|
|
|
+ T_LE,
|
|
|
+ T_GE,
|
|
|
T_STAR,
|
|
|
T_SLASH,
|
|
|
T_PERCENT,
|
|
|
T_COMMA,
|
|
|
T_DOT,
|
|
|
T_BANG,
|
|
|
+ T_RAISE,
|
|
|
+ T_TILDE,
|
|
|
|
|
|
T_INLINE,
|
|
|
|
|
@@ -577,6 +585,16 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
return TK(NOTEQUALS);
|
|
|
else if (strncmp(&source[*pos], "+=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
return TK(PLUSASSIGN);
|
|
|
+ else if (strncmp(&source[*pos], "-=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
+ return TK(MINUSASSIGN);
|
|
|
+ else if (strncmp(&source[*pos], "*=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
+ return TK(STARASSIGN);
|
|
|
+ else if (strncmp(&source[*pos], "/=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
+ return TK(SLASHASSIGN);
|
|
|
+ else if (strncmp(&source[*pos], "//=", 3) == 0 && ++(*pos) && ++(*pos) && ++(*pos))
|
|
|
+ return TK(SLASHSLASHASSIGN);
|
|
|
+ else if (strncmp(&source[*pos], "%=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
+ return TK(PERCENTASSIGN);
|
|
|
else if (strncmp(&source[*pos], "||", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
return TK(BARBAR);
|
|
|
else if (strncmp(&source[*pos], "&&", 2) == 0 && ++(*pos) && ++(*pos))
|
|
@@ -593,6 +611,10 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
return TK(LTLT);
|
|
|
else if (strncmp(&source[*pos], ">>", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
return TK(GTGT);
|
|
|
+ else if (strncmp(&source[*pos], "<=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
+ return TK(LE);
|
|
|
+ else if (strncmp(&source[*pos], ">=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
+ return TK(GE);
|
|
|
else if (source[*pos] == '(' && ++(*pos))
|
|
|
return TK(LPAR);
|
|
|
else if (source[*pos] == ')' && ++(*pos))
|
|
@@ -633,6 +655,14 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
return TK(GT);
|
|
|
else if (source[*pos] == '!' && ++(*pos))
|
|
|
return TK(BANG);
|
|
|
+ else if (source[*pos] == '|' && ++(*pos))
|
|
|
+ return TK(BAR);
|
|
|
+ else if (source[*pos] == '&' && ++(*pos))
|
|
|
+ return TK(AND);
|
|
|
+ else if (source[*pos] == '^' && ++(*pos))
|
|
|
+ return TK(RAISE);
|
|
|
+ else if (source[*pos] == '~' && ++(*pos))
|
|
|
+ return TK(TILDE);
|
|
|
|
|
|
LEX_ERROR("unexpected input")
|
|
|
}
|
|
@@ -668,6 +698,7 @@ struct _node_t {
|
|
|
|
|
|
N_NOT,
|
|
|
N_NEGATE,
|
|
|
+ N_BNOT,
|
|
|
|
|
|
N_LITERAL,
|
|
|
N_LIST,
|
|
@@ -688,9 +719,18 @@ struct _node_t {
|
|
|
N_POW,
|
|
|
N_SHL,
|
|
|
N_SHR,
|
|
|
+ N_XOR,
|
|
|
+ N_BOR,
|
|
|
+ N_BAND,
|
|
|
|
|
|
N_ASSIGN,
|
|
|
N_ASSIGN_ADD,
|
|
|
+ N_ASSIGN_SUB,
|
|
|
+ N_ASSIGN_MUL,
|
|
|
+ N_ASSIGN_DIV,
|
|
|
+ N_ASSIGN_IDIV,
|
|
|
+ N_ASSIGN_MOD,
|
|
|
+ N_ASSIGN_POW,
|
|
|
|
|
|
N_EQUALS,
|
|
|
N_NOTEQUALS,
|
|
@@ -701,6 +741,8 @@ struct _node_t {
|
|
|
|
|
|
N_LT,
|
|
|
N_GT,
|
|
|
+ N_LE,
|
|
|
+ N_GE,
|
|
|
|
|
|
N_INC,
|
|
|
N_DEC,
|
|
@@ -1054,6 +1096,10 @@ node_t *parse_unary(list_t *tokens, size_t *pos) {
|
|
|
node_t *a = parse_unary(tokens, pos);
|
|
|
|
|
|
return NODE1(NOT, a);
|
|
|
+ } else if (MATCH(TILDE)) {
|
|
|
+ node_t *a = parse_unary(tokens, pos);
|
|
|
+
|
|
|
+ return NODE1(BNOT, a);
|
|
|
}
|
|
|
|
|
|
return parse_postfix(tokens, pos);
|
|
@@ -1175,6 +1221,18 @@ node_t *parse_relation(list_t *tokens, size_t *pos) {
|
|
|
|
|
|
a = NODE2(GT, a, b);
|
|
|
|
|
|
+ continue;
|
|
|
+ } else if (MATCH(LE)) {
|
|
|
+ node_t *b = parse_shift(tokens, pos);
|
|
|
+
|
|
|
+ a = NODE2(LE, a, b);
|
|
|
+
|
|
|
+ continue;
|
|
|
+ } else if (MATCH(GE)) {
|
|
|
+ node_t *b = parse_shift(tokens, pos);
|
|
|
+
|
|
|
+ a = NODE2(GE, a, b);
|
|
|
+
|
|
|
continue;
|
|
|
}
|
|
|
|
|
@@ -1241,18 +1299,36 @@ node_t *parse_equality(list_t *tokens, size_t *pos) {
|
|
|
node_t *parse_bitand(list_t *tokens, size_t *pos) {
|
|
|
node_t *a = parse_equality(tokens, pos);
|
|
|
|
|
|
+ while (MATCH(AND)) {
|
|
|
+ node_t *b = parse_equality(tokens, pos);
|
|
|
+
|
|
|
+ a = NODE2(BAND, a, b);
|
|
|
+ }
|
|
|
+
|
|
|
return a;
|
|
|
}
|
|
|
|
|
|
node_t *parse_bitxor(list_t *tokens, size_t *pos) {
|
|
|
node_t *a = parse_bitand(tokens, pos);
|
|
|
|
|
|
+ while (MATCH(RAISE)) {
|
|
|
+ node_t *b = parse_bitand(tokens, pos);
|
|
|
+
|
|
|
+ a = NODE2(XOR, a, b);
|
|
|
+ }
|
|
|
+
|
|
|
return a;
|
|
|
}
|
|
|
|
|
|
node_t *parse_bitor(list_t *tokens, size_t *pos) {
|
|
|
node_t *a = parse_bitxor(tokens, pos);
|
|
|
|
|
|
+ while (MATCH(BAR)) {
|
|
|
+ node_t *b = parse_bitxor(tokens, pos);
|
|
|
+
|
|
|
+ a = NODE2(BOR, a, b);
|
|
|
+ }
|
|
|
+
|
|
|
return a;
|
|
|
}
|
|
|
|
|
@@ -1309,6 +1385,26 @@ node_t *parse_assignment(list_t *tokens, size_t *pos) {
|
|
|
node_t *b = parse_assignment(tokens, pos);
|
|
|
|
|
|
return NODE2(ASSIGN_ADD, a, b);
|
|
|
+ } else if (MATCH(MINUSASSIGN)) {
|
|
|
+ node_t *b = parse_assignment(tokens, pos);
|
|
|
+
|
|
|
+ return NODE2(ASSIGN_SUB, a, b);
|
|
|
+ } else if (MATCH(STARASSIGN)) {
|
|
|
+ node_t *b = parse_assignment(tokens, pos);
|
|
|
+
|
|
|
+ return NODE2(ASSIGN_MUL, a, b);
|
|
|
+ } else if (MATCH(SLASHASSIGN)) {
|
|
|
+ node_t *b = parse_assignment(tokens, pos);
|
|
|
+
|
|
|
+ return NODE2(ASSIGN_DIV, a, b);
|
|
|
+ } else if (MATCH(SLASHSLASHASSIGN)) {
|
|
|
+ node_t *b = parse_assignment(tokens, pos);
|
|
|
+
|
|
|
+ return NODE2(ASSIGN_IDIV, a, b);
|
|
|
+ } else if (MATCH(PERCENTASSIGN)) {
|
|
|
+ node_t *b = parse_assignment(tokens, pos);
|
|
|
+
|
|
|
+ return NODE2(ASSIGN_MOD, a, b);
|
|
|
}
|
|
|
|
|
|
return a;
|
|
@@ -1332,7 +1428,7 @@ node_t *parse_block(list_t *tokens, size_t *pos) {
|
|
|
return NODEL(PROGRAM, stmts);
|
|
|
}
|
|
|
|
|
|
-#define BLOCK() (MATCH(COLON)?parse_stmt(tokens, pos):parse_block(tokens, pos))
|
|
|
+#define BLOCK() (CLIFF||MATCH(COLON)?parse_stmt(tokens, pos):parse_block(tokens, pos))
|
|
|
|
|
|
node_t *parse_if(list_t *tokens, size_t *pos) {
|
|
|
node_t *a = parse_expr(tokens, pos);
|
|
@@ -1479,7 +1575,7 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
node_t *b = NULL;
|
|
|
node_t *c = NULL;
|
|
|
|
|
|
- if (!AT(LCB) && !AT(COLON)) {
|
|
|
+ if (!AT(LCB) && !AT(COLON) && !CLIFF) {
|
|
|
if (MATCH(VAR)) {
|
|
|
if (AT(NAME) && ATP(OF, 1)) {
|
|
|
token_t *t = tokens->data[(*pos)++];
|
|
@@ -1517,7 +1613,7 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
} else if (MATCH(DEFER)) {
|
|
|
node_t *a;
|
|
|
|
|
|
- if (AT(LCB) || AT(COLON))
|
|
|
+ if (AT(LCB))
|
|
|
a = BLOCK();
|
|
|
else a = parse_stmt(tokens, pos);
|
|
|
|
|
@@ -1529,7 +1625,7 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
|
|
|
EXPECT(CATCH, "catch");
|
|
|
|
|
|
- if (!AT(COLON) && !AT(LCB)) {
|
|
|
+ if (!AT(COLON) && !AT(LCB) && !CLIFF) {
|
|
|
if (!AT(NAME))
|
|
|
PARSE_ERROR("expected identifier");
|
|
|
|
|
@@ -1862,7 +1958,18 @@ const char *STD[][2] = {
|
|
|
"func die(msg, c=1) {\n"
|
|
|
" println(msg)\n"
|
|
|
" exit(c)\n"
|
|
|
- "}"
|
|
|
+ "}\n"
|
|
|
+ "let SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2\n"
|
|
|
+ "func frewind(file)\n"
|
|
|
+ " fseek(file, 0, SEEK_SET)\n"
|
|
|
+ "func file_read(filename) {\n"
|
|
|
+ " var file = fopen(filename, \"r\")\n"
|
|
|
+ " defer fclose(file)\n"
|
|
|
+ " fseek(file, 0, SEEK_END)\n"
|
|
|
+ " let size = ftell(file)\n"
|
|
|
+ " frewind(file)\n"
|
|
|
+ " return str(fread(file, size))\n"
|
|
|
+ "}\n"
|
|
|
},
|
|
|
|
|
|
{NULL, NULL}
|
|
@@ -1988,6 +2095,12 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
case N_ASSIGN: ASSIGN(node->a, compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
|
|
|
case N_ASSIGN_ADD: COMPASSIGN(node->a, "add", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_SUB: COMPASSIGN(node->a, "sub", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_MUL: COMPASSIGN(node->a, "mul", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_DIV: COMPASSIGN(node->a, "div", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_IDIV: COMPASSIGN(node->a, "idiv", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_MOD: COMPASSIGN(node->a, "mod", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_POW: COMPASSIGN(node->a, "pow", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
|
|
|
case N_INC:
|
|
|
COMPASSIGN(node->a, "add", EMIT("state->one"));
|
|
@@ -1998,6 +2111,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
break;
|
|
|
|
|
|
case N_VAR: break;
|
|
|
+ case N_LET: break;
|
|
|
|
|
|
case N_IF:
|
|
|
EMIT("if (_qi_truthy(state, ");
|
|
@@ -2300,6 +2414,14 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
BINOP("gt");
|
|
|
break;
|
|
|
|
|
|
+ case N_LE:
|
|
|
+ BINOP("le");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case N_GE:
|
|
|
+ BINOP("ge");
|
|
|
+ break;
|
|
|
+
|
|
|
case N_ADD:
|
|
|
BINOP("add");
|
|
|
break;
|
|
@@ -2336,6 +2458,18 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
BINOP("shr");
|
|
|
break;
|
|
|
|
|
|
+ case N_XOR:
|
|
|
+ BINOP("xor");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case N_BOR:
|
|
|
+ BINOP("bor");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case N_BAND:
|
|
|
+ BINOP("band");
|
|
|
+ break;
|
|
|
+
|
|
|
case N_NEGATE:
|
|
|
UNOP("negate");
|
|
|
break;
|
|
@@ -2344,6 +2478,10 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
UNOP("not");
|
|
|
break;
|
|
|
|
|
|
+ case N_BNOT:
|
|
|
+ UNOP("bnot");
|
|
|
+ break;
|
|
|
+
|
|
|
case N_INLINE: EMIT("%s;", unescape(node->t->text)); break;
|
|
|
|
|
|
default:
|