diff --git a/src/common/executable.c b/src/common/executable.c index 7c54343..f053cff 100644 --- a/src/common/executable.c +++ b/src/common/executable.c @@ -55,6 +55,8 @@ static const InstrInfo instr_table[] = { [OPCODE_GRT] = {"GRT", 0, NULL}, [OPCODE_LEQ] = {"LEQ", 0, NULL}, [OPCODE_GEQ] = {"GEQ", 0, NULL}, + [OPCODE_AND] = {"AND", 0, NULL}, + [OPCODE_OR] = {"AND", 0, NULL}, [OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}}, [OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}}, diff --git a/src/common/executable.h b/src/common/executable.h index 37b9478..82c5ff5 100644 --- a/src/common/executable.h +++ b/src/common/executable.h @@ -35,6 +35,8 @@ typedef enum { OPCODE_GRT, OPCODE_LEQ, OPCODE_GEQ, + OPCODE_AND, + OPCODE_OR, OPCODE_ASS, OPCODE_POP, OPCODE_CALL, diff --git a/src/compiler/ASTi.h b/src/compiler/ASTi.h index 9ee0ffd..2f3e931 100644 --- a/src/compiler/ASTi.h +++ b/src/compiler/ASTi.h @@ -30,6 +30,8 @@ typedef enum { EXPR_GRT, EXPR_GEQ, + EXPR_AND, + EXPR_OR, EXPR_NOT, EXPR_ASS, diff --git a/src/compiler/compile.c b/src/compiler/compile.c index 1fd4fb1..fea0296 100644 --- a/src/compiler/compile.c +++ b/src/compiler/compile.c @@ -40,6 +40,8 @@ static Opcode exprkind_to_opcode(ExprKind kind) case EXPR_LEQ: return OPCODE_LEQ; case EXPR_GRT: return OPCODE_GRT; case EXPR_GEQ: return OPCODE_GEQ; + case EXPR_AND: return OPCODE_AND; + case EXPR_OR: return OPCODE_OR; default: UNREACHABLE; break; @@ -70,6 +72,8 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) case EXPR_LEQ: case EXPR_GRT: case EXPR_GEQ: + case EXPR_AND: + case EXPR_OR: { OperExprNode *oper = (OperExprNode*) expr; diff --git a/src/compiler/parse.c b/src/compiler/parse.c index a6fc7b5..20c3b34 100644 --- a/src/compiler/parse.c +++ b/src/compiler/parse.c @@ -59,6 +59,8 @@ typedef enum { TKWIF, TKWFUN, TKWNOT, + TKWAND, + TKWOR, TKWELSE, TKWNONE, TKWTRUE, @@ -197,6 +199,14 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error) { tok->kind = TKWNOT; } + else if(matchstr(str + tok->offset, tok->length, "and")) + { + tok->kind = TKWAND; + } + else if(matchstr(str + tok->offset, tok->length, "or")) + { + tok->kind = TKWOR; + } else if(matchstr(str + tok->offset, tok->length, "else")) { tok->kind = TKWELSE; @@ -1519,6 +1529,8 @@ static inline _Bool isbinop(Token *tok) tok->kind == TGEQ || tok->kind == TEQL || tok->kind == TNQL || + tok->kind == TKWAND || + tok->kind == TKWOR || tok->kind == '='; } @@ -1538,21 +1550,27 @@ static inline int precedenceof(Token *tok) case '=': return 0; + case TKWOR: + return 1; + + case TKWAND: + return 2; + case '<': case '>': case TLEQ: case TGEQ: case TEQL: case TNQL: - return 1; + return 3; case '+': case '-': - return 2; + return 4; case '*': case '/': - return 3; + return 5; default: return -100000000; @@ -1610,8 +1628,10 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec) case TGEQ: temp->base.kind = EXPR_GEQ; break; case TEQL: temp->base.kind = EXPR_EQL; break; case TNQL: temp->base.kind = EXPR_NQL; break; + case TKWAND: temp->base.kind = EXPR_AND; break; + case TKWOR: temp->base.kind = EXPR_OR; break; case '=': temp->base.kind = EXPR_ASS; break; - + default: UNREACHABLE; break; diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 09e30fc..45efa0d 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -679,6 +679,44 @@ static _Bool step(Runtime *runtime, Error *error) return 1; } + case OPCODE_AND: + case OPCODE_OR: + { + assert(opc == 0); + + Object *rop = Stack_Top(runtime->stack, 0); + Object *lop = Stack_Top(runtime->stack, -1); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + // We managed to pop rop and lop, + // so we know they're not NULL. + assert(rop != NULL); + assert(lop != NULL); + + _Bool raw_rop, raw_lop, raw_res; + raw_lop = Object_ToBool(lop, error); + raw_rop = Object_ToBool(rop, error); + if(error->occurred) return 0; + + switch(opcode) + { + case OPCODE_AND: raw_res = raw_lop && raw_rop; break; + case OPCODE_OR: raw_res = raw_lop || raw_rop; break; + default: assert(0); break; + } + + Object *res = Object_FromBool(raw_res, runtime->heap, error); + + if(res == NULL) + return 0; + + if(!Runtime_Push(runtime, error, res)) + return 0; + return 1; + } + case OPCODE_ASS: { assert(opc == 1); diff --git a/tests/test.noja b/tests/test.noja index 24b8ad8..a26c848 100644 --- a/tests/test.noja +++ b/tests/test.noja @@ -59,6 +59,14 @@ assert(false != true); assert(true == not false); assert(false == not true); + assert((true and true ) == true); + assert((true and false) == false); + assert((false and true ) == false); + assert((false and false) == false); + assert((true or true ) == true); + assert((true or false) == true); + assert((false or true ) == true); + assert((false or false) == false); } # Test if-else statements.