added equality and relational operators
This commit is contained in:
@@ -7,5 +7,11 @@ if p:
|
||||
else
|
||||
a = 2;
|
||||
|
||||
if 'hello2' == 'hello': print('Yup!'); else print('Nop!');
|
||||
print('\n');
|
||||
print(a);
|
||||
|
||||
print(1 < 1 < 1);
|
||||
|
||||
|
||||
return a;
|
||||
+13
-4
@@ -7,10 +7,19 @@ while p:
|
||||
p = false;
|
||||
}
|
||||
|
||||
# ------------------------------------- #
|
||||
|
||||
do
|
||||
{
|
||||
print('Hello 2!\n');
|
||||
}
|
||||
while false;
|
||||
|
||||
do {
|
||||
# ------------------------------------- #
|
||||
|
||||
print('Hello 2!\n');
|
||||
|
||||
} while true;
|
||||
i = 0;
|
||||
while i < 10:
|
||||
{
|
||||
print('i = ', i+1, '\n');
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,14 @@ static const InstrInfo instr_table[] = {
|
||||
[OPCODE_SUB] = {"SUB", 0, NULL},
|
||||
[OPCODE_MUL] = {"MUL", 0, NULL},
|
||||
[OPCODE_DIV] = {"DIV", 0, NULL},
|
||||
|
||||
[OPCODE_EQL] = {"EQL", 0, NULL},
|
||||
[OPCODE_NQL] = {"NQL", 0, NULL},
|
||||
[OPCODE_LSS] = {"LSS", 0, NULL},
|
||||
[OPCODE_GRT] = {"GRT", 0, NULL},
|
||||
[OPCODE_LEQ] = {"LEQ", 0, NULL},
|
||||
[OPCODE_GEQ] = {"GEQ", 0, NULL},
|
||||
|
||||
[OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}},
|
||||
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_CALL] = {"CALL", 1, (OperandType[]) {OPTP_INT}},
|
||||
|
||||
@@ -28,6 +28,12 @@ typedef enum {
|
||||
OPCODE_SUB,
|
||||
OPCODE_MUL,
|
||||
OPCODE_DIV,
|
||||
OPCODE_EQL,
|
||||
OPCODE_NQL,
|
||||
OPCODE_LSS,
|
||||
OPCODE_GRT,
|
||||
OPCODE_LEQ,
|
||||
OPCODE_GEQ,
|
||||
OPCODE_ASS,
|
||||
OPCODE_POP,
|
||||
OPCODE_CALL,
|
||||
|
||||
@@ -22,6 +22,14 @@ typedef enum {
|
||||
EXPR_SUB,
|
||||
EXPR_MUL,
|
||||
EXPR_DIV,
|
||||
|
||||
EXPR_EQL,
|
||||
EXPR_NQL,
|
||||
EXPR_LSS,
|
||||
EXPR_LEQ,
|
||||
EXPR_GRT,
|
||||
EXPR_GEQ,
|
||||
|
||||
EXPR_ASS,
|
||||
EXPR_INT,
|
||||
EXPR_CALL,
|
||||
|
||||
@@ -15,6 +15,12 @@ static Opcode exprkind_to_opcode(ExprKind kind)
|
||||
case EXPR_SUB: return OPCODE_SUB;
|
||||
case EXPR_MUL: return OPCODE_MUL;
|
||||
case EXPR_DIV: return OPCODE_DIV;
|
||||
case EXPR_EQL: return OPCODE_EQL;
|
||||
case EXPR_NQL: return OPCODE_NQL;
|
||||
case EXPR_LSS: return OPCODE_LSS;
|
||||
case EXPR_LEQ: return OPCODE_LEQ;
|
||||
case EXPR_GRT: return OPCODE_GRT;
|
||||
case EXPR_GEQ: return OPCODE_GEQ;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
break;
|
||||
@@ -38,6 +44,12 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
|
||||
case EXPR_SUB:
|
||||
case EXPR_MUL:
|
||||
case EXPR_DIV:
|
||||
case EXPR_EQL:
|
||||
case EXPR_NQL:
|
||||
case EXPR_LSS:
|
||||
case EXPR_LEQ:
|
||||
case EXPR_GRT:
|
||||
case EXPR_GEQ:
|
||||
{
|
||||
OperExprNode *oper = (OperExprNode*) expr;
|
||||
|
||||
|
||||
+59
-2
@@ -16,6 +16,10 @@ typedef enum {
|
||||
TSUB = '-',
|
||||
TMUL = '*',
|
||||
TDIV = '/',
|
||||
|
||||
TLSS = '<',
|
||||
TGRT = '>',
|
||||
|
||||
TASS = '=',
|
||||
|
||||
TDONE = 256,
|
||||
@@ -33,6 +37,12 @@ typedef enum {
|
||||
TKWRETURN,
|
||||
TKWWHILE,
|
||||
TKWDO,
|
||||
|
||||
TEQL,
|
||||
TNQL,
|
||||
TLEQ,
|
||||
TGEQ,
|
||||
|
||||
} TokenKind;
|
||||
|
||||
typedef struct Token Token;
|
||||
@@ -65,6 +75,9 @@ static inline _Bool isoper(char c)
|
||||
c == '-' ||
|
||||
c == '*' ||
|
||||
c == '/' ||
|
||||
c == '<' ||
|
||||
c == '>' ||
|
||||
c == '!' ||
|
||||
c == '=';
|
||||
}
|
||||
|
||||
@@ -239,6 +252,30 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error)
|
||||
{
|
||||
tok->kind = TDIV;
|
||||
}
|
||||
else if(matchop(str + tok->offset, tok->length, "=="))
|
||||
{
|
||||
tok->kind = TEQL;
|
||||
}
|
||||
else if(matchop(str + tok->offset, tok->length, "!="))
|
||||
{
|
||||
tok->kind = TNQL;
|
||||
}
|
||||
else if(matchop(str + tok->offset, tok->length, "<"))
|
||||
{
|
||||
tok->kind = TLSS;
|
||||
}
|
||||
else if(matchop(str + tok->offset, tok->length, "<="))
|
||||
{
|
||||
tok->kind = TLEQ;
|
||||
}
|
||||
else if(matchop(str + tok->offset, tok->length, ">"))
|
||||
{
|
||||
tok->kind = TGRT;
|
||||
}
|
||||
else if(matchop(str + tok->offset, tok->length, ">="))
|
||||
{
|
||||
tok->kind = TGEQ;
|
||||
}
|
||||
else if(matchop(str + tok->offset, tok->length, "="))
|
||||
{
|
||||
tok->kind = TASS;
|
||||
@@ -1010,6 +1047,12 @@ static inline _Bool isbinop(Token *tok)
|
||||
tok->kind == '-' ||
|
||||
tok->kind == '*' ||
|
||||
tok->kind == '/' ||
|
||||
tok->kind == '<' ||
|
||||
tok->kind == '>' ||
|
||||
tok->kind == TLEQ ||
|
||||
tok->kind == TGEQ ||
|
||||
tok->kind == TEQL ||
|
||||
tok->kind == TNQL ||
|
||||
tok->kind == '=';
|
||||
}
|
||||
|
||||
@@ -1029,13 +1072,21 @@ static inline int precedenceof(Token *tok)
|
||||
case '=':
|
||||
return 0;
|
||||
|
||||
case '<':
|
||||
case '>':
|
||||
case TLEQ:
|
||||
case TGEQ:
|
||||
case TEQL:
|
||||
case TNQL:
|
||||
return 1;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
return 1;
|
||||
return 2;
|
||||
|
||||
case '*':
|
||||
case '/':
|
||||
return 2;
|
||||
return 3;
|
||||
|
||||
default:
|
||||
return -100000000;
|
||||
@@ -1087,6 +1138,12 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
|
||||
case '-': temp->base.kind = EXPR_SUB; break;
|
||||
case '*': temp->base.kind = EXPR_MUL; break;
|
||||
case '/': temp->base.kind = EXPR_DIV; break;
|
||||
case '<': temp->base.kind = EXPR_LSS; break;
|
||||
case '>': temp->base.kind = EXPR_GRT; break;
|
||||
case TLEQ: temp->base.kind = EXPR_LEQ; break;
|
||||
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 '=': temp->base.kind = EXPR_ASS; break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
static long long int to_int(Object *obj, Error *err);
|
||||
static void print(Object *obj, FILE *fp);
|
||||
static _Bool op_eql(Object *self, Object *other);
|
||||
|
||||
typedef struct {
|
||||
Object base;
|
||||
@@ -17,6 +18,7 @@ static const Type t_int = {
|
||||
.atomic = ATMTP_INT,
|
||||
.to_int = to_int,
|
||||
.print = print,
|
||||
.op_eql = op_eql,
|
||||
};
|
||||
|
||||
static long long int to_int(Object *obj, Error *err)
|
||||
@@ -53,3 +55,18 @@ static void print(Object *obj, FILE *fp)
|
||||
|
||||
fprintf(fp, "%lld", ((IntObject*) obj)->val);
|
||||
}
|
||||
|
||||
static _Bool op_eql(Object *self, Object *other)
|
||||
{
|
||||
assert(self != NULL);
|
||||
assert(self->type == &t_int);
|
||||
assert(other != NULL);
|
||||
assert(other->type == &t_int);
|
||||
|
||||
IntObject *i1, *i2;
|
||||
|
||||
i1 = (IntObject*) self;
|
||||
i2 = (IntObject*) other;
|
||||
|
||||
return i1->val == i2->val;
|
||||
}
|
||||
@@ -349,6 +349,100 @@ static Object *do_math_op(Object *lop, Object *rop, Opcode opcode, Heap *heap, E
|
||||
return res;
|
||||
}
|
||||
|
||||
static Object *do_relational_op(Object *lop, Object *rop, Opcode opcode, Heap *heap, Error *error)
|
||||
{
|
||||
assert(lop != NULL);
|
||||
assert(rop != NULL);
|
||||
|
||||
#define APPLY(x, y, z, id) \
|
||||
switch(opcode) \
|
||||
{ \
|
||||
case OPCODE_LSS: (z) = (x) < (y); break; \
|
||||
case OPCODE_GRT: (z) = (x) > (y); break; \
|
||||
case OPCODE_LEQ: (z) = (x) <= (y); break; \
|
||||
case OPCODE_GEQ: (z) = (x) >= (y); break; \
|
||||
default: assert(0); break; \
|
||||
}
|
||||
|
||||
_Bool res;
|
||||
|
||||
if(Object_IsInt(lop))
|
||||
{
|
||||
long long int raw_lop = Object_ToInt(lop, error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
|
||||
if(Object_IsInt(rop))
|
||||
{
|
||||
// int + int
|
||||
long long int raw_rop = Object_ToInt(rop, error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
|
||||
APPLY(raw_lop, raw_rop, res, id)
|
||||
}
|
||||
else if(Object_IsFloat(rop))
|
||||
{
|
||||
// int + float
|
||||
double raw_rop = Object_ToFloat(rop, error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
|
||||
APPLY((double) raw_lop, raw_rop, res, id)
|
||||
}
|
||||
else
|
||||
{
|
||||
Error_Report(error, 0, "Relational operation on a non-numeric object");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if(Object_IsFloat(lop))
|
||||
{
|
||||
double raw_lop = Object_ToFloat(lop, error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
|
||||
if(Object_IsInt(rop))
|
||||
{
|
||||
// float + int
|
||||
long long int raw_rop = Object_ToInt(rop, error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
|
||||
APPLY(raw_lop, (double) raw_rop, res, id)
|
||||
}
|
||||
else if(Object_IsFloat(rop))
|
||||
{
|
||||
// float + float
|
||||
double raw_rop = Object_ToFloat(rop, error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
|
||||
APPLY(raw_lop, raw_rop, res, id)
|
||||
}
|
||||
else
|
||||
{
|
||||
Error_Report(error, 0, "Relational operation on a non-numeric object");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error_Report(error, 0, "Relational operation on a non-numeric object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#undef APPLY
|
||||
|
||||
return Object_FromBool(res, heap, error);
|
||||
}
|
||||
|
||||
static _Bool step(Runtime *runtime, Error *error)
|
||||
{
|
||||
assert(runtime != NULL);
|
||||
@@ -407,6 +501,68 @@ static _Bool step(Runtime *runtime, Error *error)
|
||||
break;
|
||||
}
|
||||
|
||||
case OPCODE_EQL:
|
||||
case OPCODE_NQL:
|
||||
{
|
||||
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 rawres = Object_Compare(lop, rop, error);
|
||||
|
||||
if(error->occurred == 1)
|
||||
return 0;
|
||||
|
||||
if(opcode == OPCODE_NQL)
|
||||
rawres = !rawres;
|
||||
|
||||
Object *res = Object_FromBool(rawres, runtime->heap, error);
|
||||
|
||||
if(res == NULL)
|
||||
return 0;
|
||||
|
||||
if(!Runtime_Push(runtime, error, res))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case OPCODE_LSS:
|
||||
case OPCODE_GRT:
|
||||
case OPCODE_LEQ:
|
||||
case OPCODE_GEQ:
|
||||
{
|
||||
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);
|
||||
|
||||
Object *res = do_relational_op(lop, rop, opcode, runtime->heap, error);
|
||||
|
||||
if(res == NULL)
|
||||
return 0;
|
||||
|
||||
if(!Runtime_Push(runtime, error, res))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case OPCODE_ASS:
|
||||
{
|
||||
assert(opc == 1);
|
||||
|
||||
Reference in New Issue
Block a user