added assignment operator
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
USING_VALGRIND=0
|
USING_VALGRIND=1
|
||||||
|
|
||||||
FLAGS="-L3p/libs/ -I3p/include/ -Wall -Wextra -g -DUSING_VALGRIND=$USING_VALGRIND -DTRACE_SOURCE_COPIES=$TRACE_SOURCE_COPIES"
|
FLAGS="-L3p/libs/ -I3p/include/ -Wall -Wextra -g -DUSING_VALGRIND=$USING_VALGRIND -DTRACE_SOURCE_COPIES=$TRACE_SOURCE_COPIES"
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
|
||||||
|
p = 1;
|
||||||
|
return p;
|
||||||
|
|
||||||
if true
|
if true
|
||||||
{
|
{
|
||||||
return 3;
|
x = 7;
|
||||||
2;
|
2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
4;
|
4;
|
||||||
return 99;
|
return x;
|
||||||
@@ -47,7 +47,7 @@ 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_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}},
|
||||||
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}},
|
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}},
|
||||||
|
|
||||||
[OPCODE_PUSHINT] = {"PUSHINT", 1, (OperandType[]) {OPTP_INT}},
|
[OPCODE_PUSHINT] = {"PUSHINT", 1, (OperandType[]) {OPTP_INT}},
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ typedef enum {
|
|||||||
OPCODE_SUB,
|
OPCODE_SUB,
|
||||||
OPCODE_MUL,
|
OPCODE_MUL,
|
||||||
OPCODE_DIV,
|
OPCODE_DIV,
|
||||||
|
OPCODE_ASS,
|
||||||
OPCODE_POP,
|
OPCODE_POP,
|
||||||
OPCODE_PUSHINT,
|
OPCODE_PUSHINT,
|
||||||
OPCODE_PUSHFLT,
|
OPCODE_PUSHFLT,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ typedef enum {
|
|||||||
EXPR_SUB,
|
EXPR_SUB,
|
||||||
EXPR_MUL,
|
EXPR_MUL,
|
||||||
EXPR_DIV,
|
EXPR_DIV,
|
||||||
|
EXPR_ASS,
|
||||||
EXPR_INT,
|
EXPR_INT,
|
||||||
EXPR_NONE,
|
EXPR_NONE,
|
||||||
EXPR_TRUE,
|
EXPR_TRUE,
|
||||||
|
|||||||
@@ -50,6 +50,29 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
|
|||||||
NULL, 0, node->offset, node->length);
|
NULL, 0, node->offset, node->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case EXPR_ASS:
|
||||||
|
{
|
||||||
|
OperExprNode *oper = (OperExprNode*) expr;
|
||||||
|
|
||||||
|
Node *lop, *rop;
|
||||||
|
lop = oper->head;
|
||||||
|
rop = lop->next;
|
||||||
|
|
||||||
|
if(((ExprNode*) lop)->kind != EXPR_IDENT)
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Assignment left operand must be an identifier");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!emit_instr_for_node(exeb, rop, error))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const char *name = ((IdentExprNode*) lop)->val;
|
||||||
|
|
||||||
|
Operand op = { .type = OPTP_STRING, .as_string = name };
|
||||||
|
return ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, node->offset, node->length);
|
||||||
|
}
|
||||||
|
|
||||||
case EXPR_INT:
|
case EXPR_INT:
|
||||||
{
|
{
|
||||||
IntExprNode *p = (IntExprNode*) expr;
|
IntExprNode *p = (IntExprNode*) expr;
|
||||||
|
|||||||
@@ -852,15 +852,15 @@ static inline _Bool isbinop(Token *tok)
|
|||||||
return tok->kind == '+' ||
|
return tok->kind == '+' ||
|
||||||
tok->kind == '-' ||
|
tok->kind == '-' ||
|
||||||
tok->kind == '*' ||
|
tok->kind == '*' ||
|
||||||
tok->kind == '/';
|
tok->kind == '/' ||
|
||||||
|
tok->kind == '=';
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline _Bool isrightassoc(Token *tok)
|
static inline _Bool isrightassoc(Token *tok)
|
||||||
{
|
{
|
||||||
assert(tok != NULL);
|
assert(tok != NULL);
|
||||||
|
|
||||||
(void) tok;
|
return tok->kind == '=';
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int precedenceof(Token *tok)
|
static inline int precedenceof(Token *tok)
|
||||||
@@ -869,6 +869,9 @@ static inline int precedenceof(Token *tok)
|
|||||||
|
|
||||||
switch(tok->kind)
|
switch(tok->kind)
|
||||||
{
|
{
|
||||||
|
case '=':
|
||||||
|
return 0;
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
return 1;
|
return 1;
|
||||||
@@ -928,6 +931,7 @@ 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_ASS; break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
|
|
||||||
|
#if USING_VALGRIND
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct OflowAlloc OflowAlloc;
|
typedef struct OflowAlloc OflowAlloc;
|
||||||
struct OflowAlloc {
|
struct OflowAlloc {
|
||||||
OflowAlloc *prev;
|
OflowAlloc *prev;
|
||||||
@@ -38,11 +42,20 @@ Heap *Heap_New(int size)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USING_VALGRIND
|
||||||
|
VALGRIND_CREATE_MEMPOOL(heap, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
return heap;
|
return heap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Heap_Free(Heap *heap)
|
void Heap_Free(Heap *heap)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if USING_VALGRIND
|
||||||
|
VALGRIND_DESTROY_MEMPOOL(heap);
|
||||||
|
#endif
|
||||||
|
|
||||||
while(heap->oflow)
|
while(heap->oflow)
|
||||||
{
|
{
|
||||||
OflowAlloc *prev = heap->oflow->prev;
|
OflowAlloc *prev = heap->oflow->prev;
|
||||||
@@ -106,5 +119,9 @@ void *Heap_RawMalloc(Heap *heap, int size, Error *err)
|
|||||||
|
|
||||||
assert(((intptr_t) addr) % 8 == 0);
|
assert(((intptr_t) addr) % 8 == 0);
|
||||||
|
|
||||||
|
#if USING_VALGRIND
|
||||||
|
VALGRIND_MEMPOOL_ALLOC(heap, addr, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
+4
-4
@@ -103,9 +103,9 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
|
|
||||||
assert(k >= 0);
|
assert(k >= 0);
|
||||||
|
|
||||||
if(Object_Compare(key, map->keys[i], error))
|
if(Object_Compare(key, map->keys[k], error))
|
||||||
// Found it!
|
// Found it!
|
||||||
return map->vals[i];
|
return map->vals[k];
|
||||||
|
|
||||||
if(error->occurred)
|
if(error->occurred)
|
||||||
// Key doesn't implement compare.
|
// Key doesn't implement compare.
|
||||||
@@ -230,11 +230,11 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *e
|
|||||||
{
|
{
|
||||||
assert(k >= 0);
|
assert(k >= 0);
|
||||||
|
|
||||||
if(Object_Compare(key, map->keys[i], error))
|
if(Object_Compare(key, map->keys[k], error))
|
||||||
{
|
{
|
||||||
// Already inserted.
|
// Already inserted.
|
||||||
// Overwrite the value.
|
// Overwrite the value.
|
||||||
map->vals[i] = val;
|
map->vals[k] = val;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ typedef struct {
|
|||||||
|
|
||||||
static int hash(Object *self);
|
static int hash(Object *self);
|
||||||
static int count(Object *self);
|
static int count(Object *self);
|
||||||
|
static Object *copy(Object *self, Heap *heap, Error *err);
|
||||||
|
static _Bool op_eql(Object *self, Object *other);
|
||||||
|
|
||||||
static const Type t_string = {
|
static const Type t_string = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
@@ -19,6 +21,8 @@ static const Type t_string = {
|
|||||||
.size = sizeof (StringObject),
|
.size = sizeof (StringObject),
|
||||||
.hash = hash,
|
.hash = hash,
|
||||||
.count = count,
|
.count = count,
|
||||||
|
.copy = copy,
|
||||||
|
.op_eql = op_eql,
|
||||||
};
|
};
|
||||||
|
|
||||||
Object *Object_FromString(const char *str, int len, Heap *heap, Error *error)
|
Object *Object_FromString(const char *str, int len, Heap *heap, Error *error)
|
||||||
@@ -66,4 +70,27 @@ static int hash(Object *self)
|
|||||||
StringObject *strobj = (StringObject*) self;
|
StringObject *strobj = (StringObject*) self;
|
||||||
|
|
||||||
return hashbytes((unsigned char*) strobj->body, strobj->size);
|
return hashbytes((unsigned char*) strobj->body, strobj->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object *copy(Object *self, Heap *heap, Error *err)
|
||||||
|
{
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(self->type == &t_string);
|
||||||
|
assert(heap != NULL);
|
||||||
|
assert(err != NULL);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Bool op_eql(Object *self, Object *other)
|
||||||
|
{
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(self->type == &t_string);
|
||||||
|
assert(other != NULL);
|
||||||
|
assert(other->type == &t_string);
|
||||||
|
|
||||||
|
StringObject *s1 = (StringObject*) self;
|
||||||
|
StringObject *s2 = (StringObject*) other;
|
||||||
|
|
||||||
|
return s1->size == s2->size && !strncmp(s1->body, s2->body, s1->size);
|
||||||
}
|
}
|
||||||
+19
-15
@@ -49,7 +49,7 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err)
|
|||||||
|
|
||||||
if(type->deepsize == NULL)
|
if(type->deepsize == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ int Object_Hash(Object *obj, Error *err)
|
|||||||
|
|
||||||
if(type->hash == NULL)
|
if(type->hash == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ Object *Object_Copy(Object *obj, Heap *heap, Error *err)
|
|||||||
|
|
||||||
if(type->copy == NULL)
|
if(type->copy == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, E
|
|||||||
|
|
||||||
if(type->call == NULL)
|
if(type->call == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,11 +117,11 @@ Object *Object_Select(Object *coll, Object *key, Heap *heap, Error *err)
|
|||||||
|
|
||||||
if(type->select == NULL)
|
if(type->select == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->select(coll, key, heap, err);
|
return type->select(coll, key, heap, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *Object_Delete(Object *coll, Object *key, Heap *heap, Error *err)
|
Object *Object_Delete(Object *coll, Object *key, Heap *heap, Error *err)
|
||||||
@@ -135,7 +135,7 @@ Object *Object_Delete(Object *coll, Object *key, Heap *heap, Error *err)
|
|||||||
|
|
||||||
if(type->delete == NULL)
|
if(type->delete == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ _Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *e
|
|||||||
|
|
||||||
if(type->insert == NULL)
|
if(type->insert == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ int Object_Count(Object *coll, Error *err)
|
|||||||
|
|
||||||
if(type->count == NULL)
|
if(type->count == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ Object *Object_Next(Object *iter, Heap *heap, Error *err)
|
|||||||
|
|
||||||
if(type->next == NULL)
|
if(type->next == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ Object *Object_Prev(Object *iter, Heap *heap, Error *err)
|
|||||||
|
|
||||||
if(type->prev == NULL)
|
if(type->prev == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +248,7 @@ long long int Object_ToInt(Object *obj, Error *err)
|
|||||||
|
|
||||||
if(type->to_int == NULL)
|
if(type->to_int == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +271,7 @@ _Bool Object_ToBool(Object *obj, Error *err)
|
|||||||
|
|
||||||
if(type->to_bool == NULL)
|
if(type->to_bool == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ double Object_ToFloat(Object *obj, Error *err)
|
|||||||
|
|
||||||
if(type->to_float == NULL)
|
if(type->to_float == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,12 +303,16 @@ double Object_ToFloat(Object *obj, Error *err)
|
|||||||
|
|
||||||
_Bool Object_Compare(Object *obj1, Object *obj2, Error *error)
|
_Bool Object_Compare(Object *obj1, Object *obj2, Error *error)
|
||||||
{
|
{
|
||||||
|
assert(obj1 != NULL);
|
||||||
|
assert(obj2 != NULL);
|
||||||
|
assert(error != NULL);
|
||||||
|
|
||||||
if(obj1->type != obj2->type)
|
if(obj1->type != obj2->type)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(obj1->type->op_eql == NULL)
|
if(obj1->type->op_eql == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, "Object %s doesn't implement %s", Object_GetName(obj1), __func__);
|
Error_Report(error, 0, "Object %s doesn't implement %s", Object_GetName(obj1), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-2
@@ -83,7 +83,7 @@ _Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj)
|
|||||||
|
|
||||||
if(runtime->frame->used == MAX_FRAME_STACK)
|
if(runtime->frame->used == MAX_FRAME_STACK)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Frames stack limit of %d reached", MAX_FRAME_STACK);
|
Error_Report(error, 0, "Frame stack limit of %d reached", MAX_FRAME_STACK);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ _Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n)
|
|||||||
|
|
||||||
if((unsigned int) runtime->frame->used < n)
|
if((unsigned int) runtime->frame->used < n)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Frames has not enough values on the stack");
|
Error_Report(error, 0, "Frame has not enough values on the stack");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,6 +365,30 @@ static _Bool step(Runtime *runtime, Error *error)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OPCODE_ASS:
|
||||||
|
{
|
||||||
|
assert(opc == 1);
|
||||||
|
assert(ops[0].type == OPTP_STRING);
|
||||||
|
|
||||||
|
if(runtime->frame->used == 0)
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Frame has not enough values on the stack");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object *val = Stack_Top(runtime->stack, 0);
|
||||||
|
assert(val != NULL);
|
||||||
|
|
||||||
|
Object *key = Object_FromString(ops[0].as_string, -1, runtime->heap, error);
|
||||||
|
|
||||||
|
if(key == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!Object_Insert(runtime->frame->vars, key, val, runtime->heap, error))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
case OPCODE_POP:
|
case OPCODE_POP:
|
||||||
{
|
{
|
||||||
assert(opc == 1);
|
assert(opc == 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user