added equality and relational operators

This commit is contained in:
cozis
2021-11-03 02:04:38 +00:00
parent c0d788656e
commit 9d600b66be
9 changed files with 285 additions and 6 deletions
+6
View File
@@ -7,5 +7,11 @@ if p:
else else
a = 2; a = 2;
if 'hello2' == 'hello': print('Yup!'); else print('Nop!');
print('\n');
print(a); print(a);
print(1 < 1 < 1);
return a; return a;
+13 -4
View File
@@ -7,10 +7,19 @@ while p:
p = false; p = false;
} }
# ------------------------------------- #
do
{
print('Hello 2!\n');
}
while false;
do { # ------------------------------------- #
print('Hello 2!\n'); i = 0;
while i < 10:
} while true; {
print('i = ', i+1, '\n');
i = i + 1;
}
+8
View File
@@ -47,6 +47,14 @@ static const InstrInfo instr_table[] = {
[OPCODE_SUB] = {"SUB", 0, NULL}, [OPCODE_SUB] = {"SUB", 0, NULL},
[OPCODE_MUL] = {"MUL", 0, NULL}, [OPCODE_MUL] = {"MUL", 0, NULL},
[OPCODE_DIV] = {"DIV", 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_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}},
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}},
[OPCODE_CALL] = {"CALL", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_CALL] = {"CALL", 1, (OperandType[]) {OPTP_INT}},
+6
View File
@@ -28,6 +28,12 @@ typedef enum {
OPCODE_SUB, OPCODE_SUB,
OPCODE_MUL, OPCODE_MUL,
OPCODE_DIV, OPCODE_DIV,
OPCODE_EQL,
OPCODE_NQL,
OPCODE_LSS,
OPCODE_GRT,
OPCODE_LEQ,
OPCODE_GEQ,
OPCODE_ASS, OPCODE_ASS,
OPCODE_POP, OPCODE_POP,
OPCODE_CALL, OPCODE_CALL,
+8
View File
@@ -22,6 +22,14 @@ typedef enum {
EXPR_SUB, EXPR_SUB,
EXPR_MUL, EXPR_MUL,
EXPR_DIV, EXPR_DIV,
EXPR_EQL,
EXPR_NQL,
EXPR_LSS,
EXPR_LEQ,
EXPR_GRT,
EXPR_GEQ,
EXPR_ASS, EXPR_ASS,
EXPR_INT, EXPR_INT,
EXPR_CALL, EXPR_CALL,
+12
View File
@@ -15,6 +15,12 @@ static Opcode exprkind_to_opcode(ExprKind kind)
case EXPR_SUB: return OPCODE_SUB; case EXPR_SUB: return OPCODE_SUB;
case EXPR_MUL: return OPCODE_MUL; case EXPR_MUL: return OPCODE_MUL;
case EXPR_DIV: return OPCODE_DIV; 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: default:
UNREACHABLE; UNREACHABLE;
break; break;
@@ -38,6 +44,12 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
case EXPR_SUB: case EXPR_SUB:
case EXPR_MUL: case EXPR_MUL:
case EXPR_DIV: 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; OperExprNode *oper = (OperExprNode*) expr;
+59 -2
View File
@@ -16,6 +16,10 @@ typedef enum {
TSUB = '-', TSUB = '-',
TMUL = '*', TMUL = '*',
TDIV = '/', TDIV = '/',
TLSS = '<',
TGRT = '>',
TASS = '=', TASS = '=',
TDONE = 256, TDONE = 256,
@@ -33,6 +37,12 @@ typedef enum {
TKWRETURN, TKWRETURN,
TKWWHILE, TKWWHILE,
TKWDO, TKWDO,
TEQL,
TNQL,
TLEQ,
TGEQ,
} TokenKind; } TokenKind;
typedef struct Token Token; typedef struct Token Token;
@@ -65,6 +75,9 @@ static inline _Bool isoper(char c)
c == '-' || c == '-' ||
c == '*' || c == '*' ||
c == '/' || c == '/' ||
c == '<' ||
c == '>' ||
c == '!' ||
c == '='; c == '=';
} }
@@ -239,6 +252,30 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error)
{ {
tok->kind = TDIV; 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, "=")) else if(matchop(str + tok->offset, tok->length, "="))
{ {
tok->kind = TASS; 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 == '/' ||
tok->kind == '<' ||
tok->kind == '>' ||
tok->kind == TLEQ ||
tok->kind == TGEQ ||
tok->kind == TEQL ||
tok->kind == TNQL ||
tok->kind == '='; tok->kind == '=';
} }
@@ -1029,13 +1072,21 @@ static inline int precedenceof(Token *tok)
case '=': case '=':
return 0; return 0;
case '<':
case '>':
case TLEQ:
case TGEQ:
case TEQL:
case TNQL:
return 1;
case '+': case '+':
case '-': case '-':
return 1; return 2;
case '*': case '*':
case '/': case '/':
return 2; return 3;
default: default:
return -100000000; 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_SUB; break;
case '*': temp->base.kind = EXPR_MUL; break; case '*': temp->base.kind = EXPR_MUL; break;
case '/': temp->base.kind = EXPR_DIV; 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; case '=': temp->base.kind = EXPR_ASS; break;
default: default:
+17
View File
@@ -4,6 +4,7 @@
static long long int to_int(Object *obj, Error *err); static long long int to_int(Object *obj, Error *err);
static void print(Object *obj, FILE *fp); static void print(Object *obj, FILE *fp);
static _Bool op_eql(Object *self, Object *other);
typedef struct { typedef struct {
Object base; Object base;
@@ -17,6 +18,7 @@ static const Type t_int = {
.atomic = ATMTP_INT, .atomic = ATMTP_INT,
.to_int = to_int, .to_int = to_int,
.print = print, .print = print,
.op_eql = op_eql,
}; };
static long long int to_int(Object *obj, Error *err) 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); 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;
}
+156
View File
@@ -349,6 +349,100 @@ static Object *do_math_op(Object *lop, Object *rop, Opcode opcode, Heap *heap, E
return res; 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) static _Bool step(Runtime *runtime, Error *error)
{ {
assert(runtime != NULL); assert(runtime != NULL);
@@ -407,6 +501,68 @@ static _Bool step(Runtime *runtime, Error *error)
break; 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: case OPCODE_ASS:
{ {
assert(opc == 1); assert(opc == 1);