added equality and relational operators
This commit is contained in:
@@ -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
@@ -7,10 +7,19 @@ while p:
|
|||||||
p = false;
|
p = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------- #
|
||||||
|
|
||||||
|
do
|
||||||
do {
|
{
|
||||||
|
|
||||||
print('Hello 2!\n');
|
print('Hello 2!\n');
|
||||||
|
}
|
||||||
|
while false;
|
||||||
|
|
||||||
} 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_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}},
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
@@ -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:
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user