From 462959e6ab15a7dfdfa6f97ec775e30d795f073b Mon Sep 17 00:00:00 2001 From: bog Date: Wed, 20 Mar 2024 16:26:59 +0100 Subject: [PATCH] :sparkles: array arithmetic. --- doc/grammar.bnf | 10 +- lib/bytecode.h | 2 +- lib/ccm.c | 311 +++++++++++++++++++++++++++++++++++++++--------- lib/ccm.h | 23 +++- lib/compiler.c | 9 ++ lib/exec.c | 81 +++++++++++-- lib/node.h | 2 +- lib/parser.c | 126 ++++++++++++++------ lib/parser.h | 3 +- lib/type.h | 4 +- lib/value.c | 87 ++++++++++++++ lib/value.h | 5 + lib/vec.c | 16 +++ lib/vec.h | 1 + tests/array.ccm | 31 +++++ 15 files changed, 594 insertions(+), 117 deletions(-) create mode 100644 tests/array.ccm diff --git a/doc/grammar.bnf b/doc/grammar.bnf index c08e7bf..182ac89 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -1,9 +1,8 @@ MODULE ::= EXPR* EXPR ::= -| IN +| OR | ASSERT ASSERT ::= (assert_eq|assert_ne) tuple -IN ::= OR (in OR)? OR ::= AND (or AND)* AND ::= EQNE (and EQNE)* EQNE ::= CMP ((eq|ne) CMP)? @@ -12,14 +11,17 @@ TERM ::= FACTOR ((add|sub) FACTOR)* FACTOR ::= USUB ((mul|div|mod) USUB)* USUB ::= sub* NOT NOT ::= not* POW -POW ::= LITERAL (pow LITERAL)? +POW ::= IN (pow IN)? +IN ::= LITERAL (in LITERAL)? LITERAL ::= | BUILTIN | TUPLE | INDEX +| ARRAY | opar EXPR cpar +ARRAY ::= osquare (EXPR (comma EXPR)*)? csquare INDEX ::= -| (TUPLE|str) osquare (EXPR (comma EXPR)*)? csquare +| (TUPLE|str|ARRAY) osquare (EXPR (comma EXPR)*)? csquare TUPLE ::= | opar EXPR+ cpar BUILTIN ::= num | bool | str diff --git a/lib/bytecode.h b/lib/bytecode.h index 77f7a0d..fc3904d 100644 --- a/lib/bytecode.h +++ b/lib/bytecode.h @@ -9,7 +9,7 @@ G(OP_ADD), G(OP_SUB), G(OP_USUB), G(OP_MUL), \ G(OP_DIV), G(OP_POW), G(OP_MOD), G(OP_MK_TUPLE), \ G(OP_ASSERT_EQ), G(OP_ASSERT_NE), G(OP_BRF), G(OP_BR), \ G(OP_NOT), G(OP_IN), G(OP_INDEX), G(OP_EQ), G(OP_LT), \ -G(OP_GT) +G(OP_GT), G(OP_MK_ARRAY) CCM_ENUM_H(Opcode, OPCODES); diff --git a/lib/ccm.c b/lib/ccm.c index 11c20ff..0b05175 100644 --- a/lib/ccm.c +++ b/lib/ccm.c @@ -6,16 +6,25 @@ void ccm_init(ccm_t* self) assert(self); vec_init(&self->values); vec_init(&self->stack); + vec_init(&self->globals); err_init(&self->err); + self->id_counter = 0; +} + +void ccm_entry_free(ccm_entry_t* self) +{ + value_free(self->value); + free(self->value); } void ccm_free(ccm_t* self) { assert(self); err_free(&self->err); - vec_free_elements(&self->values, (void*) value_free); + vec_free_elements(&self->values, (void*) ccm_entry_free); vec_free(&self->values); vec_free(&self->stack); + vec_free(&self->globals); } size_t ccm_str(ccm_t* self, char* buffer, size_t size) @@ -27,7 +36,7 @@ size_t ccm_str(ccm_t* self, char* buffer, size_t size) for (size_t i=0; istack.size; i++) { - value_t* val = self->values.data[(CCM) self->stack.data[i]]; + value_t* val = ccm_to_value(self, (CCM) self->stack.data[i]); sz += value_str(val, buffer + sz, size - sz); sz += snprintf(buffer + sz, size - sz, "\n"); } @@ -35,6 +44,48 @@ size_t ccm_str(ccm_t* self, char* buffer, size_t size) return sz; } +value_t* ccm_find_value(ccm_t* self, size_t addr) +{ + for (size_t i=0; ivalues.size; i++) + { + if (((ccm_entry_t*) self->values.data[i])->id == (int) addr) + { + return ((ccm_entry_t*)self->values.data[i])->value; + } + } + assert(0); +} + +size_t ccm_add_value(ccm_t* self, value_t* value) +{ + assert(self); + assert(value); + + ccm_entry_t* entry = malloc(sizeof(ccm_entry_t)); + entry->value = value; + entry->id = self->id_counter; + self->id_counter++; + + vec_push(&self->values, entry); + return self->id_counter - 1; +} + +size_t ccm_store_global(ccm_t* self, CCM value) +{ + assert(self); + + vec_push(&self->globals, (void*) value); + return self->globals.size - 1; +} + +CCM ccm_load_global(ccm_t* self, size_t addr) +{ + assert(self); + assert(addr < self->globals.size); + + return (CCM) self->globals.data[addr]; +} + CCM ccm_from_value(ccm_t* self, value_t* value) { assert(self); @@ -58,6 +109,22 @@ CCM ccm_from_value(ccm_t* self, value_t* value) ); } break; + case TYPE_ARRAY: { + vec_t * vec = malloc(sizeof(vec_t)); + vec_init(vec); + for (size_t i=0; idata.array->size; i++) + { + vec_push(vec, + value->data.array->data[i] + ); + } + + return ccm_to_array( + self, + vec, + value->line + ); + } break; case TYPE_TUPLE: { vec_t * vec = malloc(sizeof(vec_t)); vec_init(vec); @@ -87,13 +154,19 @@ CCM ccm_from_value(ccm_t* self, value_t* value) value_t* ccm_to_value(ccm_t* self, CCM value) { assert(self); - assert(value < self->values.size); - return (value_t*) self->values.data[value]; + value_t* val = ccm_find_value(self, value); + + if (val->type == TYPE_REF) + { + CCM addr = (CCM) self->globals.data[val->data.ref]; + return ccm_to_value(self, addr); + } + return val; } int ccm_is_num(ccm_t* self, CCM value) { - value_t const* val = self->values.data[value]; + value_t const* val = ccm_find_value(self, value); return val->type == TYPE_NUM; } @@ -102,16 +175,14 @@ double ccm_from_num(ccm_t* self, CCM value) assert(self); assert(value < self->values.size); + value_t* val = ccm_find_value(self, value); + if (!ccm_is_num(self, value)) { - err_push(&self->err, - ((value_t*) self->values.data[value])->line, - "not a num"); + err_push(&self->err, val->line, "not a num"); return 0.0; } - value_t* val = self->values.data[value]; - return val->data.num; } @@ -120,15 +191,14 @@ CCM ccm_to_num(ccm_t* self, double value, int line) assert(self); value_t* val = malloc(sizeof(value_t)); value_init_num(val, value, line); - vec_push(&self->values, val); - return self->values.size - 1; + return ccm_add_value(self, val); } int ccm_is_tuple(ccm_t* self, CCM value) { assert(self); - value_t* val = self->values.data[value]; + value_t* val = ccm_find_value(self, value); assert(val); return val->type == TYPE_TUPLE; } @@ -136,7 +206,8 @@ int ccm_is_tuple(ccm_t* self, CCM value) vec_t* ccm_from_tuple(ccm_t* self, CCM value) { assert(self); - value_t* val = self->values.data[value]; + value_t* val = ccm_find_value(self, value); + if (!ccm_is_tuple(self, value)) { err_push(&self->err, val->line, "not a tuple"); @@ -152,41 +223,38 @@ CCM ccm_to_tuple(ccm_t* self, vec_t* values, int line) value_t* value = malloc(sizeof(value_t)); value_init_new_tuple(value, values, line); - vec_push(&self->values, value); - return self->values.size - 1; + return ccm_add_value(self, value); } int ccm_is_boolean(ccm_t* self, CCM value) { assert(self); - return ((value_t*) self->values.data[value])->type - == TYPE_BOOLEAN; + return ccm_find_value(self, value)->type == TYPE_BOOLEAN; } int ccm_from_boolean(ccm_t* self, CCM value) { assert(self); - return ((value_t*) self->values.data[value])->data.boolean; + return ccm_find_value(self, value)->data.boolean; } CCM ccm_to_boolean(ccm_t* self, int value, int line) { value_t* boolean = malloc(sizeof(value_t)); value_init_boolean(boolean, value, line); - vec_push(&self->values, boolean); - return self->values.size - 1; + return ccm_add_value(self, boolean); } int ccm_is_str(ccm_t* self, CCM value) { assert(self); - return ((value_t*) self->values.data[value])->type == TYPE_STR; + return ccm_find_value(self, value)->type == TYPE_STR; } char* ccm_from_str(ccm_t* self, CCM value) { assert(self); - return ((value_t*) self->values.data[value])->data.str; + return ccm_find_value(self, value)->data.str; } CCM ccm_to_str(ccm_t* self, char* value, int line) @@ -197,9 +265,50 @@ CCM ccm_to_str(ccm_t* self, char* value, int line) value_t* val = malloc(sizeof(value_t)); value_init_str(val, value, line); - vec_push(&self->values, val); + return ccm_add_value(self, val); +} - return self->values.size - 1; +int ccm_is_array(ccm_t* self, CCM value) +{ + assert(self); + value_t const* val = ccm_find_value(self, value); + return val->type == TYPE_ARRAY; +} + +vec_t* ccm_from_array(ccm_t* self, CCM value) +{ + assert(self); + value_t* val = ccm_find_value(self, value); + return val->data.array; +} + +CCM ccm_to_array(ccm_t* self, vec_t* value, int line) +{ + assert(self); + value_t* val = malloc(sizeof(value_t)); + value_init_new_array(val, value, line); + return ccm_add_value(self, val); +} + +int ccm_is_ref(ccm_t* self, CCM value) +{ + assert(self); + return ccm_find_value(self, value)->type == TYPE_REF; +} + +size_t ccm_from_ref(ccm_t* self, CCM value) +{ + assert(self); + return ccm_find_value(self, value)->data.ref; +} + +CCM ccm_to_ref(ccm_t* self, size_t value, int line) +{ + assert(self); + + value_t* val = malloc(sizeof(value_t)); + value_init_ref(val, value, line); + return ccm_add_value(self, val); } void ccm_push(ccm_t* self, CCM value) @@ -229,28 +338,44 @@ void ccm_in(ccm_t* self) CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); - int line = ((value_t*) self->values.data[ccm_lhs])->line; + int line = ccm_find_value(self, ccm_lhs)->line; - if (!ccm_is_tuple(self, ccm_rhs)) - { - err_push(&self->err, line, "cannot test membership"); + if (ccm_is_ref(self, ccm_rhs)) { + value_t* rhs_val = ccm_to_value(self, ccm_rhs); + value_t* val = ccm_to_value(self, ccm_lhs); + assert(rhs_val->type == TYPE_ARRAY); + vec_t* rhs = rhs_val->data.array; + + for (size_t i=0; isize; i++) + { + if (value_equals(val, rhs->data[i])) + { + ccm_push(self, ccm_to_boolean(self, 1, line)); + return; + } + } + + ccm_push(self, ccm_to_boolean(self, 0, line)); return; } + if (ccm_is_tuple(self, ccm_rhs)) { + vec_t* rhs = ccm_from_tuple(self, ccm_rhs); + value_t* val = ccm_find_value(self, ccm_lhs); - - vec_t* rhs = ccm_from_tuple(self, ccm_rhs); - value_t* val = ((value_t*)self->values.data[ccm_lhs]); - - for (size_t i=0; isize; i++) - { - if (value_equals(val, rhs->data[i])) + for (size_t i=0; isize; i++) { - ccm_push(self, ccm_to_boolean(self, 1, line)); - return; + if (value_equals(val, rhs->data[i])) + { + ccm_push(self, ccm_to_boolean(self, 1, line)); + return; + } } - } - ccm_push(self, ccm_to_boolean(self, 0, line)); + ccm_push(self, ccm_to_boolean(self, 0, line)); + return; + } + err_push(&self->err, line, "cannot test membership"); + return; } void ccm_add(ccm_t* self) @@ -258,8 +383,44 @@ void ccm_add(ccm_t* self) assert(self); CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); - int line = ((value_t*) self->values.data[ccm_lhs])->line; + int line = ccm_find_value(self, ccm_lhs)->line; + if (ccm_is_ref(self, ccm_rhs) + && ccm_is_ref(self, ccm_lhs)) + { + value_t* lhs = ccm_to_value(self, ccm_lhs); + value_t* rhs = ccm_to_value(self, ccm_rhs); + + vec_t* data = malloc(sizeof(vec_t)); + vec_init(data); + + for (size_t i=0; idata.array->size; i++) + { + vec_push(data, + lhs->data.array->data[i]); + } + + for (size_t i=0; idata.array->size; i++) + { + vec_push(data, + rhs->data.array->data[i]); + } + + value_t* res = malloc(sizeof(value_t)); + value_init_new_array(res, data, lhs->line); + + CCM res_id = ccm_store_global( + self, + ccm_add_value(self, res) + ); + + value_t* ref = malloc(sizeof(value_t)); + value_init_ref(ref, res_id, lhs->line); + + ccm_push(self, ccm_add_value(self, ref)); + + return; + } if (ccm_is_str(self, ccm_rhs) && ccm_is_str(self, ccm_lhs)) { @@ -286,8 +447,7 @@ void ccm_sub(ccm_t* self) assert(self); CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); - int line = ((value_t*) self->values.data[ccm_lhs])->line; - + int line = ccm_find_value(self, ccm_lhs)->line; double rhs = ccm_from_num(self, ccm_rhs); double lhs = ccm_from_num(self, ccm_lhs); @@ -298,7 +458,7 @@ void ccm_usub(ccm_t* self) { assert(self); CCM ccm_lhs = ccm_pop(self); - int line = ((value_t*) self->values.data[ccm_lhs])->line; + int line = ccm_find_value(self, ccm_lhs)->line; double lhs = ccm_from_num(self, ccm_lhs); @@ -310,8 +470,48 @@ void ccm_mul(ccm_t* self) assert(self); CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); - int line = ((value_t*) self->values.data[ccm_lhs])->line; + int line = ccm_find_value(self, ccm_lhs)->line; + + if (ccm_is_ref(self, ccm_rhs) + && ccm_is_num(self, ccm_lhs)) + { + CCM tmp = ccm_lhs; + ccm_lhs = ccm_rhs; + ccm_rhs = tmp; + } + + if (ccm_is_ref(self, ccm_lhs) + && ccm_is_num(self, ccm_rhs)) + { + int count = ccm_from_num(self, ccm_rhs); + value_t* val = ccm_to_value(self, ccm_lhs); + vec_t* vec = malloc(sizeof(vec_t)); + vec_init(vec); + + for (int i=0; idata.array->size; j++) + { + vec_push( + vec, + val->data.array->data[j] + ); + } + } + + value_t* result = malloc(sizeof(value_t)); + value_init_new_array(result, vec, val->line); + + int id = ccm_store_global( + self, + ccm_add_value(self, result) + ); + CCM res = ccm_to_ref(self, id, val->line); + ccm_push(self, res); + + return; + } if (ccm_is_str(self, ccm_rhs) && ccm_is_num(self, ccm_lhs)) { @@ -349,8 +549,7 @@ void ccm_div(ccm_t* self) assert(self); CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); - int line = ((value_t*) self->values.data[ccm_lhs])->line; - + int line = ccm_find_value(self, ccm_lhs)->line; double rhs = ccm_from_num(self, ccm_rhs); double lhs = ccm_from_num(self, ccm_lhs); @@ -362,7 +561,7 @@ void ccm_mod(ccm_t* self) assert(self); CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); - int line = ((value_t*) self->values.data[ccm_lhs])->line; + int line = ccm_find_value(self, ccm_lhs)->line; double rhs = ccm_from_num(self, ccm_rhs); double lhs = ccm_from_num(self, ccm_lhs); @@ -375,7 +574,7 @@ void ccm_pow(ccm_t* self) assert(self); CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); - int line = ((value_t*) self->values.data[ccm_lhs])->line; + int line = ccm_find_value(self, ccm_lhs)->line; double rhs = ccm_from_num(self, ccm_rhs); double lhs = ccm_from_num(self, ccm_lhs); @@ -387,8 +586,8 @@ void ccm_not(ccm_t* self) { assert(self); CCM ccm_lhs = ccm_pop(self); - int line = ((value_t*) self->values.data[ccm_lhs])->line; + int line = ccm_find_value(self, ccm_lhs)->line; int lhs = ccm_from_boolean(self, ccm_lhs); ccm_push(self, ccm_to_boolean(self, !lhs, line)); @@ -398,11 +597,9 @@ void ccm_eq(ccm_t* self) { CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); - value_t* lhs = ccm_to_value(self, ccm_lhs); value_t* rhs = ccm_to_value(self, ccm_rhs); - int line = ((value_t*) self->values.data[ccm_lhs])->line; - + int line = ccm_find_value(self, ccm_lhs)->line; int eq = value_equals(lhs, rhs); ccm_push(self, ccm_to_boolean(self, eq, line)); } @@ -414,8 +611,7 @@ void ccm_ne(ccm_t* self) value_t* lhs = ccm_to_value(self, ccm_lhs); value_t* rhs = ccm_to_value(self, ccm_rhs); - int line = ((value_t*) self->values.data[ccm_lhs])->line; - + int line = ccm_find_value(self, ccm_lhs)->line; int eq = value_equals(lhs, rhs); ccm_push(self, ccm_to_boolean(self, !eq, line)); } @@ -427,8 +623,8 @@ void ccm_lt(ccm_t* self) double lhs = ccm_from_num(self, ccm_lhs); double rhs = ccm_from_num(self, ccm_rhs); - int line = ((value_t*) self->values.data[ccm_lhs])->line; + int line = ccm_find_value(self, ccm_lhs)->line; ccm_push(self, ccm_to_boolean(self, lhs < rhs, line)); } @@ -445,8 +641,7 @@ void ccm_gt(ccm_t* self) double lhs = ccm_from_num(self, ccm_lhs); double rhs = ccm_from_num(self, ccm_rhs); - int line = ((value_t*) self->values.data[ccm_lhs])->line; - + int line = ccm_find_value(self, ccm_lhs)->line; ccm_push(self, ccm_to_boolean(self, lhs > rhs, line)); } diff --git a/lib/ccm.h b/lib/ccm.h index a665ee6..f28c778 100644 --- a/lib/ccm.h +++ b/lib/ccm.h @@ -6,18 +6,31 @@ #include "value.h" #include "err.h" -typedef unsigned long long CCM; +typedef size_t CCM; + +typedef struct { + int id; + value_t* value; +} ccm_entry_t; typedef struct { err_t err; vec_t values; vec_t stack; + vec_t globals; + int id_counter; } ccm_t; void ccm_init(ccm_t* self); +void ccm_entry_free(ccm_entry_t* self); void ccm_free(ccm_t* self); size_t ccm_str(ccm_t* self, char* buffer, size_t size); +value_t* ccm_find_value(ccm_t* self, size_t addr); +size_t ccm_add_value(ccm_t* self, value_t* value); + +size_t ccm_store_global(ccm_t* self, CCM value); +CCM ccm_load_global(ccm_t* self, size_t addr); CCM ccm_from_value(ccm_t* self, value_t* value); value_t* ccm_to_value(ccm_t* self, CCM value); @@ -38,6 +51,14 @@ int ccm_is_str(ccm_t* self, CCM value); char* ccm_from_str(ccm_t* self, CCM value); CCM ccm_to_str(ccm_t* self, char* value, int line); +int ccm_is_array(ccm_t* self, CCM value); +vec_t* ccm_from_array(ccm_t* self, CCM value); +CCM ccm_to_array(ccm_t* self, vec_t* value, int line); + +int ccm_is_ref(ccm_t* self, CCM value); +size_t ccm_from_ref(ccm_t* self, CCM value); +CCM ccm_to_ref(ccm_t* self, size_t value, int line); + void ccm_push(ccm_t* self, CCM value); CCM ccm_pop(ccm_t* self); CCM ccm_top(ccm_t* self, int depth); diff --git a/lib/compiler.c b/lib/compiler.c index 48fad60..208bb2c 100644 --- a/lib/compiler.c +++ b/lib/compiler.c @@ -30,6 +30,15 @@ void compiler_compile(compiler_t* self, switch (node->kind) { + case NODE_ARRAY: { + for (size_t i=0; ichildren.size; i++) + { + size_t k = node->children.size - 1 - i; + compiler_compile(self, node->children.data[k], prog); + } + prog_add_instr(prog, OP_MK_ARRAY, node->children.size); + } break; + case NODE_LT: { compiler_compile(self, node->children.data[0], prog); compiler_compile(self, node->children.data[1], prog); diff --git a/lib/exec.c b/lib/exec.c index 83d9961..5ba24d4 100644 --- a/lib/exec.c +++ b/lib/exec.c @@ -44,6 +44,27 @@ void exec_instr(exec_t* self, switch (op) { + case OP_MK_ARRAY: { + vec_t* vec = malloc(sizeof(vec_t)); + vec_init(vec); + + for (int i=0; idata[0])->line; + + size_t addr = ccm_store_global( + ccm, + ccm_to_array(ccm, vec, line) + ); + + ccm_push(ccm, ccm_to_ref(ccm, addr, line)); + self->pc++; + } break; + case OP_EQ: { ccm_eq(ccm); self->pc++; @@ -101,9 +122,16 @@ void exec_instr(exec_t* self, char buf[2] = {target[idx], '\0'}; ccm_push(ccm, ccm_to_str(ccm, buf, line)); } - else if (ccm_is_tuple(ccm, ccm_target)) + else if (ccm_is_tuple(ccm, ccm_target) + || ccm_is_ref(ccm, ccm_target)) { - vec_t* target = ccm_from_tuple(ccm, ccm_target); + vec_t* target; + + if (ccm_is_tuple(ccm, ccm_target)) { + target = ccm_from_tuple(ccm, ccm_target); + } else { + target = ccm_to_value(ccm, ccm_target)->data.array; + } for (int i=0; idata.tuple; - } + } else if (ccm_is_ref(ccm, ccm_target)) { + target = val->data.array; + } else { assert(0); } } - ccm_push(ccm, ccm_from_value(ccm, result)); + + CCM ccm_result = ccm_from_value(ccm, result); + + if (ccm_is_array(ccm, ccm_result)) { + CCM ref = ccm_to_ref(ccm, + ccm_store_global(ccm, ccm_result), + result->line); + ccm_push(ccm, ref); + } else { + ccm_push(ccm, ccm_result); + } + } else { assert(0); } @@ -169,6 +210,9 @@ void exec_instr(exec_t* self, case OP_ASSERT_NE: case OP_ASSERT_EQ: { + // TODO: bug here + // [1] == [1] -> OK + // assert_eq ([1], [1]) -> Failed CCM val = ccm_pop(ccm); vec_t* values = ccm_from_tuple(ccm, val); assert(values->size == 2); @@ -179,14 +223,30 @@ void exec_instr(exec_t* self, oracle = 0; } - if (value_equals(values->data[0], - values->data[1]) == !oracle) + value_t* val_lhs = values->data[0]; + value_t* val_rhs = values->data[1]; + + if (val_lhs->type == TYPE_REF) + { + CCM c = ccm_add_value(ccm, val_lhs); + value_t* myval = ccm_to_value(ccm, c); + val_lhs = myval; + } + + if (val_rhs->type == TYPE_REF) + { + CCM c = ccm_add_value(ccm, val_rhs); + value_t* myval = ccm_to_value(ccm, c); + val_rhs = myval; + } + + if (value_equals(val_lhs, val_rhs) == !oracle) { char lhs[CCM_STRLEN]; - value_str(values->data[0], lhs, CCM_STRLEN); + value_str(val_lhs, lhs, CCM_STRLEN); char rhs[CCM_STRLEN]; - value_str(values->data[1], rhs, CCM_STRLEN); + value_str(val_rhs, rhs, CCM_STRLEN); char const* operator = oracle ? "==" : "!="; err_push( @@ -198,7 +258,6 @@ void exec_instr(exec_t* self, } self->pc++; - } break; case OP_PUSH: { @@ -228,7 +287,7 @@ void exec_instr(exec_t* self, for (int i=0; ivalues.data[val]); + value_t* v = value_new_clone(ccm_to_value(ccm, val)); vec_push(values, v); if (line == -1) diff --git a/lib/node.h b/lib/node.h index 5896388..88e8655 100644 --- a/lib/node.h +++ b/lib/node.h @@ -13,7 +13,7 @@ G(NODE_ASSERT_EQ), G(NODE_ASSERT_NE), G(NODE_BOOL), \ G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IN), \ G(NODE_OSQUARE), G(NODE_CSQUARE), G(NODE_INDEX), \ G(NODE_STR), G(NODE_LT), G(NODE_LE), G(NODE_GT), \ -G(NODE_GE), G(NODE_EQ), G(NODE_NE) +G(NODE_GE), G(NODE_EQ), G(NODE_NE), G(NODE_ARRAY) CCM_ENUM_H(NodeKind, NODE_KIND); diff --git a/lib/parser.c b/lib/parser.c index 808fbf0..95a3152 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -127,7 +127,7 @@ node_t* parser_try_new_expr(parser_t* self) return CCM_TRY(parser_try_new_assert); } - return CCM_TRY(parser_try_new_in); + return CCM_TRY(parser_try_new_or); } node_t* parser_try_new_assert(parser_t* self) @@ -166,36 +166,6 @@ node_t* parser_try_new_assert(parser_t* self) return node; } -node_t* parser_try_new_in(parser_t* self) -{ - assert(self); - node_t* lhs = CCM_TRY(parser_try_new_or); - if (!lhs) { return NULL; } - - if (lexer_peek_kind(self->lexer, NODE_IN, 0)) - { - lexer_consume_next(self->lexer, NODE_IN); - node_t* node = malloc(sizeof(node_t)); - node_init(node, NODE_IN, "", lhs->line); - - node_t* rhs = CCM_TRY(parser_try_new_or); - - if (!rhs) - { - node_free(lhs); free(lhs); - node_free(node); free(node); - - return NULL; - } - - node_push_new_child(node, lhs); - node_push_new_child(node, rhs); - lhs = node; - } - - return lhs; -} - node_t* parser_try_new_or(parser_t* self) { assert(self); @@ -269,11 +239,11 @@ node_t* parser_try_new_eqne(parser_t* self) node_t* rhs = CCM_TRY(parser_try_new_cmp); - if (!rhs) - { + if (!rhs) + { node_free(node); free(node); node_free(lhs); free(lhs); - return NULL; + return NULL; } node_push_new_child(node, lhs); @@ -299,11 +269,11 @@ node_t* parser_try_new_cmp(parser_t* self) node_t* rhs = CCM_TRY(parser_try_new_term); - if (!rhs) - { + if (!rhs) + { node_free(node); free(node); node_free(lhs); free(lhs); - return NULL; + return NULL; } node_push_new_child(node, lhs); @@ -441,7 +411,7 @@ node_t* parser_try_new_not(parser_t* self) node_t* parser_try_new_pow(parser_t* self) { assert(self); - node_t* lhs = CCM_TRY(parser_try_new_literal); + node_t* lhs = CCM_TRY(parser_try_new_in); if (!lhs) { return NULL; } if (lexer_peek_kind(self->lexer, NODE_POW, 0)) @@ -453,7 +423,7 @@ node_t* parser_try_new_pow(parser_t* self) return NULL; } - node_t* rhs = CCM_TRY(parser_try_new_literal); + node_t* rhs = CCM_TRY(parser_try_new_in); if (!rhs) { @@ -474,10 +444,52 @@ node_t* parser_try_new_pow(parser_t* self) return lhs; } +node_t* parser_try_new_in(parser_t* self) +{ + assert(self); + node_t* lhs = CCM_TRY(parser_try_new_literal); + if (!lhs) { return NULL; } + + if (lexer_peek_kind(self->lexer, NODE_IN, 0)) + { + lexer_consume_next(self->lexer, NODE_IN); + node_t* node = malloc(sizeof(node_t)); + node_init(node, NODE_IN, "", lhs->line); + + node_t* rhs = CCM_TRY(parser_try_new_literal); + + if (!rhs) + { + node_free(lhs); free(lhs); + node_free(node); free(node); + + return NULL; + } + + node_push_new_child(node, lhs); + node_push_new_child(node, rhs); + lhs = node; + } + + return lhs; +} + node_t* parser_try_new_literal(parser_t* self) { assert(self); + if (lexer_peek_kind(self->lexer, NODE_OSQUARE, 0)) + { + node_t* array = CCM_TRY(parser_try_new_array); + + if (lexer_peek_kind(self->lexer, NODE_OSQUARE, 0)) + { + return CCM_TRY_LL1(parser_try_new_index, array); + } + + return array; + } + if (lexer_peek_kind(self->lexer, NODE_OPAR, 0)) { node_t* tuple = CCM_TRY(parser_try_new_tuple); @@ -524,6 +536,42 @@ node_t* parser_try_new_literal(parser_t* self) return CCM_TRY(parser_try_new_builtin); } +node_t* parser_try_new_array(parser_t* self) +{ + assert(self); + + node_t* node = malloc(sizeof(node_t)); + node_init(node, NODE_ARRAY, "", self->lexer->line); + + lexer_consume_next(self->lexer, NODE_OSQUARE); + + int first = 1; + + while (!lexer_peek_kind(self->lexer, NODE_CSQUARE, 0)) + { + if (!first) + { + lexer_consume_next(self->lexer, NODE_COMMA); + } + + node_t* expr = CCM_TRY(parser_try_new_expr); + + if (!expr) + { + node_free(node); free(node); + return NULL; + } + + node_push_new_child(node, expr); + + first = 0; + } + + lexer_consume_next(self->lexer, NODE_CSQUARE); + + return node; +} + node_t* parser_try_new_index(parser_t* self, node_t* target) { assert(self); diff --git a/lib/parser.h b/lib/parser.h index f7407d9..f6a156e 100644 --- a/lib/parser.h +++ b/lib/parser.h @@ -26,7 +26,6 @@ int parser_ensure(parser_t* self, node_t* node, NodeKind kind); node_t* parser_try_new_module(parser_t* self); node_t* parser_try_new_expr(parser_t* self); node_t* parser_try_new_assert(parser_t* self); -node_t* parser_try_new_in(parser_t* self); node_t* parser_try_new_or(parser_t* self); node_t* parser_try_new_and(parser_t* self); node_t* parser_try_new_eqne(parser_t* self); @@ -36,7 +35,9 @@ node_t* parser_try_new_factor(parser_t* self); node_t* parser_try_new_usub(parser_t* self); node_t* parser_try_new_not(parser_t* self); node_t* parser_try_new_pow(parser_t* self); +node_t* parser_try_new_in(parser_t* self); node_t* parser_try_new_literal(parser_t* self); +node_t* parser_try_new_array(parser_t* self); node_t* parser_try_new_index(parser_t* self, node_t* target); node_t* parser_try_new_tuple(parser_t* self); node_t* parser_try_new_builtin(parser_t* self); diff --git a/lib/type.h b/lib/type.h index 9f1a0eb..909d626 100644 --- a/lib/type.h +++ b/lib/type.h @@ -7,7 +7,9 @@ G(TYPE_NUM), \ G(TYPE_TUPLE), \ G(TYPE_BOOLEAN), \ -G(TYPE_STR) +G(TYPE_STR), \ +G(TYPE_ARRAY), \ +G(TYPE_REF) CCM_ENUM_H(Type, TYPES); diff --git a/lib/value.c b/lib/value.c index 480007c..588ffc3 100644 --- a/lib/value.c +++ b/lib/value.c @@ -35,6 +35,25 @@ void value_init_str(value_t* self, char const* value, int line) self->line = line; } +void value_init_new_array(value_t* self, vec_t* value, int line) +{ + assert(self); + assert(value); + + self->data.array = value; + self->type = TYPE_ARRAY; + self->line = line; +} + +void value_init_ref(value_t* self, size_t value, int line) +{ + assert(self); + + self->data.ref = value; + self->type = TYPE_REF; + self->line = line; +} + value_t* value_new_clone(value_t* self) { assert(self); @@ -43,6 +62,21 @@ value_t* value_new_clone(value_t* self) switch (self->type) { + case TYPE_REF: { + value_init_ref(value, self->data.ref, self->line); + } break; + case TYPE_ARRAY: { + vec_t* array = malloc(sizeof(vec_t)); + vec_init(array); + for (size_t i=0; idata.array->size; i++) + { + vec_push(array, + self->data.array->data[i] + ); + } + value_init_new_array(value, array, self->line); + } break; + case TYPE_STR: { value_init_str(value, self->data.str, self->line); } break; @@ -79,6 +113,13 @@ value_t* value_new_clone(value_t* self) void value_free(value_t* self) { + if (self->type == TYPE_ARRAY) + { + //vec_free_elements(self->data.array, (void*) value_free); + vec_free(self->data.array); + free(self->data.array); + } + if (self->type == TYPE_TUPLE) { vec_free_elements(self->data.tuple, (void*) value_free); @@ -100,6 +141,29 @@ size_t value_str(value_t* self, char* buffer, size_t size) switch (self->type) { + case TYPE_ARRAY: { + sz += snprintf(buffer + sz, size - sz, "["); + + for (size_t i=0; idata.array->size; i++) + { + if (i > 0) + { + sz += snprintf(buffer + sz, size - sz, ", "); + } + + sz += value_str( + self->data.array->data[i], + buffer + sz, + size - sz + ); + } + + sz += snprintf(buffer + sz, size - sz, "]"); + } break; + case TYPE_REF: { + sz += snprintf(buffer + sz, size - sz, "", + self->data.ref); + } break; case TYPE_STR: { sz += snprintf(buffer + sz, size - sz, "%s", self->data.str); @@ -152,6 +216,29 @@ int value_equals(value_t* self, value_t* rhs) switch (self->type) { + case TYPE_ARRAY: { + if (self->data.array->size != rhs->data.array->size) { + return 0; + } + + for (size_t i=0; idata.array->size; i++) + { + value_t* a = self->data.array->data[i]; + value_t* b = rhs->data.array->data[i]; + + if (!value_equals(a, b)) + { + return 0; + } + } + + return 1; + } break; + + case TYPE_REF: { + return self->data.ref == rhs->data.ref; + } break; + case TYPE_STR: { return strcmp(self->data.str, rhs->data.str) == 0; } break; diff --git a/lib/value.h b/lib/value.h index 931d117..1fa6a19 100644 --- a/lib/value.h +++ b/lib/value.h @@ -11,6 +11,8 @@ typedef struct { vec_t* tuple; int boolean; char* str; + vec_t* array; + size_t ref; } data; Type type; @@ -21,6 +23,9 @@ void value_init_num(value_t* self, double num, int line); void value_init_new_tuple(value_t* self, vec_t* values, int line); void value_init_boolean(value_t* self, int boolean, int line); void value_init_str(value_t* self, char const* value, int line); +void value_init_new_array(value_t* self, vec_t* value, int line); +void value_init_ref(value_t* self, size_t value, int line); + value_t* value_new_clone(value_t* self); void value_free(value_t* self); diff --git a/lib/vec.c b/lib/vec.c index 99e07b1..0b6cd31 100644 --- a/lib/vec.c +++ b/lib/vec.c @@ -70,3 +70,19 @@ void* vec_pop(vec_t* self) return value; } +void vec_remove(vec_t* self, size_t idx, void (*free_fun)(void*)) +{ + if (free_fun) + { + free_fun(self->data[idx]); + } + + free(self->data[idx]); + + for (ssize_t i=idx; i<((ssize_t)self->size) - 1; i++) + { + self->data[i] = self->data[i + 1]; + } + + vec_pop(self); +} diff --git a/lib/vec.h b/lib/vec.h index 2005227..cce057a 100644 --- a/lib/vec.h +++ b/lib/vec.h @@ -18,5 +18,6 @@ void vec_free(vec_t* self); void vec_push(vec_t* self, void* value); void* vec_pop(vec_t* self); +void vec_remove(vec_t* self, size_t idx, void (*free_fun)(void*)); #endif diff --git a/tests/array.ccm b/tests/array.ccm new file mode 100644 index 0000000..03d7458 --- /dev/null +++ b/tests/array.ccm @@ -0,0 +1,31 @@ +# EQUALITY +assert_eq (true, [1, 2] == [1, 2]) +assert_eq (true, [1, 2] <> [1, 3]) +assert_eq (false, [1, 2] == [7, 2]) +assert_eq (false, [1, 2] <> [1, 2]) + +# INDEX +assert_eq (1, [1, 2, 3][0]) +assert_eq (2, [1, 2, 3][1]) +assert_eq (3, [1, 2, 3][2]) +assert_eq (1, [1, 2, 3][-3]) +assert_eq (2, [1, 2, 3][-2]) +assert_eq (3, [1, 2, 3][-1]) +assert_eq (2, [1, [2, 3]][-1, 0]) +assert_eq (4, [[1, 2], [3, 4]][-1, -1]) +assert_eq ([3, 4], [[1, 2], [3, 4]][-1]) + +# ARITHMETIC +assert_eq ([1, 2, 3], [1, 2, 3]) +assert_eq ([1, 2, 3], [1, 2] + [3]) +assert_eq ([2, 2, 2], [2] * 3) +assert_eq ([2, 2, 2], 3 * [2]) +assert_eq ([2, 6, 2, 6], 2*([2] + [6])) + +# MEMBERSHIP +assert_eq (true, 2 in [1, 2, 3]) +assert_eq (false, 4 in [1, 2, 3]) +assert_eq (true, [2, 3] in [1, [2, 3]]) +assert_eq (false, [2, 4] in [1, [2, 3]]) + +