diff --git a/build.sh b/build.sh index a02769e..1df1dd2 100755 --- a/build.sh +++ b/build.sh @@ -75,6 +75,7 @@ gcc src/main.c src/debug.c \ temp/utils/bucketlist.o \ temp/objects/o_map.o \ temp/objects/o_none.o \ + temp/objects/o_list.o \ temp/objects/o_bool.o \ temp/objects/o_string.o \ temp/runtime/runtime.o \ diff --git a/samples/list.noja b/samples/list.noja new file mode 100644 index 0000000..7277e92 --- /dev/null +++ b/samples/list.noja @@ -0,0 +1,7 @@ + + +l = [1, 2, 3]; + +print(count); +print(count(l)); +print(l, '\n'); \ No newline at end of file diff --git a/src/common/executable.c b/src/common/executable.c index 8897bbc..015f2ba 100644 --- a/src/common/executable.c +++ b/src/common/executable.c @@ -58,6 +58,7 @@ static const InstrInfo instr_table[] = { [OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}}, [OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_CALL] = {"CALL", 1, (OperandType[]) {OPTP_INT}}, + [OPCODE_INSERT] = {"INSERT", 0, NULL}, [OPCODE_PUSHINT] = {"PUSHINT", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_PUSHFLT] = {"PUSHFLT", 1, (OperandType[]) {OPTP_FLOAT}}, [OPCODE_PUSHSTR] = {"PUSHSTR", 1, (OperandType[]) {OPTP_STRING}}, @@ -66,6 +67,7 @@ static const InstrInfo instr_table[] = { [OPCODE_PUSHFLS] = {"PUSHFLS", 0, NULL}, [OPCODE_PUSHNNE] = {"PUSHNNE", 0, NULL}, [OPCODE_PUSHFUN] = {"PUSHFUN", 2, (OperandType[]) {OPTP_INT, OPTP_INT}}, + [OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_RETURN] = {"RETURN", 0, NULL}, diff --git a/src/common/executable.h b/src/common/executable.h index 41d7e99..48ba952 100644 --- a/src/common/executable.h +++ b/src/common/executable.h @@ -37,6 +37,7 @@ typedef enum { OPCODE_ASS, OPCODE_POP, OPCODE_CALL, + OPCODE_INSERT, OPCODE_PUSHINT, OPCODE_PUSHFLT, OPCODE_PUSHSTR, @@ -45,6 +46,7 @@ typedef enum { OPCODE_PUSHFLS, OPCODE_PUSHNNE, OPCODE_PUSHFUN, + OPCODE_PUSHLST, OPCODE_RETURN, OPCODE_JUMPIFANDPOP, OPCODE_JUMPIFNOTANDPOP, diff --git a/src/compiler/ASTi.h b/src/compiler/ASTi.h index 46c75b2..4ed7654 100644 --- a/src/compiler/ASTi.h +++ b/src/compiler/ASTi.h @@ -33,6 +33,7 @@ typedef enum { EXPR_ASS, EXPR_INT, EXPR_CALL, + EXPR_LIST, EXPR_NONE, EXPR_TRUE, EXPR_FALSE, @@ -78,6 +79,12 @@ typedef struct { int len; } StringExprNode; +typedef struct { + ExprNode base; + Node *items; + int itemc; +} ListExprNode; + typedef struct { ExprNode base; char *val; diff --git a/src/compiler/compile.c b/src/compiler/compile.c index 82c5fc2..1581a4e 100644 --- a/src/compiler/compile.c +++ b/src/compiler/compile.c @@ -113,6 +113,42 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) return ExeBuilder_Append(exeb, error, OPCODE_PUSHVAR, &op, 1, node->offset, node->length); } + case EXPR_LIST: + { + // PUSHLST + // PUSHINT + // + // INSERT + + ListExprNode *l = (ListExprNode*) node; + + Operand op; + + op = (Operand) { .type = OPTP_INT, .as_int = l->itemc }; + if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHLST, &op, 1, node->offset, node->length)) + return 0; + + Node *item = l->items; + int i = 0; + + while(item) + { + op = (Operand) { .type = OPTP_INT, .as_int = i }; + if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHINT, &op, 1, item->offset, item->length)) + return 0; + + if(!emit_instr_for_node(exeb, item, error)) + return 0; + + if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT, NULL, 0, item->offset, item->length)) + return 0; + + i += 1; + item = item->next; + } + return 1; + } + case EXPR_CALL: { CallExprNode *p = (CallExprNode*) expr; diff --git a/src/compiler/parse.c b/src/compiler/parse.c index 0d60e3e..cb6c50c 100644 --- a/src/compiler/parse.c +++ b/src/compiler/parse.c @@ -651,6 +651,96 @@ static Node *parse_string_primary_expression(Context *ctx) return (Node*) node; } +static Node *parse_list_primary_expression(Context *ctx) +{ + assert(ctx != NULL); + + if(done(ctx)) + { + Error_Report(ctx->error, 0, "Source ended where a list literal was expected"); + return NULL; + } + + if(current(ctx) != '[') + { + Error_Report(ctx->error, 0, "Got token \"%.*s\" where a list literal was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } + + int offset = current_token(ctx)->offset; + + Node *items = NULL; + int itemc = 0; + + next(ctx); // Skip the '['. + + if(current(ctx) != ']') + { + Node *tail = NULL; + + while(1) + { + // Parse. + Node *item = parse_expression(ctx); + + if(item == NULL) + return NULL; + + // Append. + if(tail) + tail->next = item; + else + items = item; + tail = item; + itemc += 1; + + // Get ',' or ']'. + + if(current(ctx) == ']') + break; + + if(current(ctx) != ',') + { + if(current(ctx) == TDONE) + Error_Report(ctx->error, 0, "Source ended inside a list literal"); + else + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" inside list literal, where ',' or ']' were expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } + + next(ctx); // Skip the ','. + } + } + + int length = current_token(ctx)->offset + + current_token(ctx)->length + - offset; + + next(ctx); // Skip the ']'. + + ListExprNode *list; + { + list = BPAlloc_Malloc(ctx->alloc, sizeof(ListExprNode)); + + if(list == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + list->base.base.kind = NODE_EXPR; + list->base.base.next = NULL; + list->base.base.offset = offset; + list->base.base.length = length; + list->base.kind = EXPR_LIST; + list->items = items; + list->itemc = itemc; + } + + return (Node*) list; + +} + static char *copy_token_text(Context *ctx) { char *copy = BPAlloc_Malloc(ctx->alloc, ctx->token->length + 1); @@ -705,6 +795,9 @@ static Node *parse_primary_expresion(Context *ctx) return (Node*) temp; } + case '[': + return parse_list_primary_expression(ctx); + case '(': { next(ctx); // Consume the '('. diff --git a/src/debug.c b/src/debug.c index 0dee9cf..8239246 100644 --- a/src/debug.c +++ b/src/debug.c @@ -452,10 +452,7 @@ _Bool Debug_Callback(Runtime *runtime, void *userp) { Stack *stack = Runtime_GetStack(runtime); assert(stack != NULL); - - Error error; - Error_Init(&error); - + if(Stack_Size(stack) == 0) fprintf(stderr, "The stack is empty.\n"); @@ -465,15 +462,7 @@ _Bool Debug_Callback(Runtime *runtime, void *userp) assert(obj != NULL); fprintf(stderr, " %d | ", i); - Object_Print(obj, stderr, &error); - - if(error.occurred) - { - Error_Free(&error); - Error_Init(&error); - fprintf(stderr, "(unprintable)"); - } - + Object_Print(obj, stderr); fprintf(stderr, "\n"); } } diff --git a/src/main.c b/src/main.c index d293088..c6f5056 100644 --- a/src/main.c +++ b/src/main.c @@ -227,7 +227,7 @@ int main(int argc, char **argv) RuntimeError_Free(&error); return 1; } - + Object *result = run(runtime, (Error*) &error, exe, 0, NULL, 0); if(result == NULL) diff --git a/src/objects/o_list.c b/src/objects/o_list.c index cb55cb7..6d1c97c 100644 --- a/src/objects/o_list.c +++ b/src/objects/o_list.c @@ -11,6 +11,7 @@ typedef struct { static Object *select(Object *self, Object *key, Heap *heap, Error *err); static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err); static int count(Object *self); +static void print(Object *obj, FILE *fp); static const Type t_list = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, @@ -19,6 +20,7 @@ static const Type t_list = { .select = select, .insert = insert, .count = count, + .print = print, }; static inline int calc_capacity(int mapper_size) @@ -151,4 +153,17 @@ static int count(Object *self) ListObject *list = (ListObject*) self; return list->count; +} + +static void print(Object *self, FILE *fp) +{ + ListObject *list = (ListObject*) self; + + for(int i = 0; i < list->count; i += 1) + { + Object_Print(list->vals[i], fp); + + if(i+1 < list->count) + fprintf(fp, ", "); + } } \ No newline at end of file diff --git a/src/objects/o_map.c b/src/objects/o_map.c index f6db6ca..95a1124 100644 --- a/src/objects/o_map.c +++ b/src/objects/o_map.c @@ -13,6 +13,7 @@ typedef struct { static Object *select(Object *self, Object *key, Heap *heap, Error *err); static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err); static int count(Object *self); +static void print(Object *self, FILE *fp); static const Type t_map = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, @@ -21,6 +22,7 @@ static const Type t_map = { .select = select, .insert = insert, .count = count, + .print = print, }; static inline int calc_capacity(int mapper_size) @@ -74,6 +76,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error) assert(heap != NULL); assert(error != NULL); + fprintf(stderr, "Selecting from:\n\t"); + Object_Print(self, stderr); + fprintf(stderr, "\n"); + MapObject *map = (MapObject*) self; int mask = map->mapper_size - 1; @@ -86,10 +92,15 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error) int i = hash & mask; +#warning "TEMP" + fprintf(stderr, "-----------------\n"); + while(1) { int k = map->mapper[i]; + fprintf(stderr, "map->mapper[%d] = %d\n", i, k); + if(k == -1) { // Empty slot. @@ -102,6 +113,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error) // Is it the right one? assert(k >= 0); +#warning "TEMP" + fprintf(stderr, "map->keys[%d] = ", k); + Object_Print(map->keys[k], stderr); + fprintf(stderr, " (of type %s)\n", Object_GetName(map->keys[k])); if(Object_Compare(key, map->keys[k], error)) // Found it! @@ -114,8 +129,12 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error) // Not the one we wanted. } + int old_i = i; + pert >>= 5; i = (i * 5 + pert + 1) & mask; + + fprintf(stderr, "%d -> %d\n", old_i, i); } UNREACHABLE; @@ -258,4 +277,19 @@ static int count(Object *self) MapObject *map = (MapObject*) self; return map->count; +} + +static void print(Object *self, FILE *fp) +{ + MapObject *map = (MapObject*) self; + + for(int i = 0; i < map->count; i += 1) + { + Object_Print(map->keys[i], fp); + fprintf(fp, ": "); + Object_Print(map->vals[i], fp); + + if(i+1 < map->count) + fprintf(fp, ", "); + } } \ No newline at end of file diff --git a/src/objects/o_string.c b/src/objects/o_string.c index 075c41b..dfe4b3f 100644 --- a/src/objects/o_string.c +++ b/src/objects/o_string.c @@ -94,7 +94,12 @@ static _Bool op_eql(Object *self, Object *other) StringObject *s1 = (StringObject*) self; StringObject *s2 = (StringObject*) other; - return s1->size == s2->size && !strncmp(s1->body, s2->body, s1->size); + _Bool match = s1->size == s2->size && !strncmp(s1->body, s2->body, s1->size); + +#warning "TEMP" + fprintf(stderr, "%s == %s ? %s\n", s1->body, s2->body, match ? "yes" : "no"); + + return match; } static void print(Object *obj, FILE *fp) diff --git a/src/objects/objects.c b/src/objects/objects.c index e7d9d27..a65082b 100644 --- a/src/objects/objects.c +++ b/src/objects/objects.c @@ -106,22 +106,17 @@ Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, E return type->call(obj, argv, argc, heap, err); } -_Bool Object_Print(Object *obj, FILE *fp, Error *error) +void Object_Print(Object *obj, FILE *fp) { - assert(error != NULL); assert(obj != NULL); const Type *type = Object_GetType(obj); assert(type); if(type->print == NULL) - { - Error_Report(error, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); - return 0; - } - - type->print(obj, fp); - return 1; + fprintf(fp, "<%s is unprintable>", Object_GetName(obj)); + else + type->print(obj, fp); } Object *Object_Select(Object *coll, Object *key, Heap *heap, Error *err) diff --git a/src/objects/objects.h b/src/objects/objects.h index b4beceb..e946905 100644 --- a/src/objects/objects.h +++ b/src/objects/objects.h @@ -74,7 +74,7 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err); int Object_Hash (Object *obj, Error *err); Object* Object_Copy (Object *obj, Heap *heap, Error *err); Object* Object_Call (Object *obj, Object **argv, unsigned int argc, Heap *heap, Error *err); -_Bool Object_Print (Object *obj, FILE *fp, Error *error); +void Object_Print (Object *obj, FILE *fp); Object* Object_Select(Object *coll, Object *key, Heap *heap, Error *err); Object* Object_Delete(Object *coll, Object *key, Heap *heap, Error *err); _Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *err); diff --git a/src/runtime/builtins.c b/src/runtime/builtins.c index 88bede3..30a3fb0 100644 --- a/src/runtime/builtins.c +++ b/src/runtime/builtins.c @@ -4,11 +4,21 @@ static Object *bin_print(Runtime *runtime, Object **argv, unsigned int argc, Error *error) { for(int i = 0; i < (int) argc; i += 1) - Object_Print(argv[i], stdout, error); + Object_Print(argv[i], stdout); return Object_NewNone(Runtime_GetHeap(runtime), error); } +static Object *bin_count(Runtime *runtime, Object **argv, unsigned int argc, Error *error) +{ + int n = Object_Count(argv[0], error); + + if(error->occurred) + return NULL; + + return Object_FromInt(n, Runtime_GetHeap(runtime), error); +} + typedef struct { const char *name; int argc; @@ -17,6 +27,7 @@ typedef struct { BuiltinNativeFunctions builtins[] = { {"print", -1, bin_print}, + {"count", 1, bin_count}, }; _Bool add_builtins(Runtime *runtime, Error *error) @@ -29,7 +40,7 @@ _Bool add_builtins(Runtime *runtime, Error *error) if(dest == NULL) return 0; - for(int i = 0; i < (int) (sizeof(builtins) / sizeof(builtins[0])); i += 1) + for(int i = 0; (unsigned int) i < sizeof(builtins) / sizeof(builtins[0]); i += 1) { Object *name = Object_FromString(builtins[i].name, -1, heap, error); diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index d11c182..73cec22 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -641,6 +641,30 @@ static _Bool step(Runtime *runtime, Error *error) return 1; } + case OPCODE_INSERT: + { + assert(opc == 0); + + if(runtime->frame->used < 3) + { + Error_Report(error, 1, "Frame has not enough values on the stack to run INSERT instruction"); + return NULL; + } + + Object *col = Stack_Top(runtime->stack, -2); + Object *key = Stack_Top(runtime->stack, -1); + Object *val = Stack_Top(runtime->stack, 0); + + assert(col != NULL && key != NULL && val != NULL); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + if(!Object_Insert(col, key, val, runtime->heap, error)) + return 0; + return 1; + } + case OPCODE_PUSHINT: { assert(opc == 1); @@ -713,8 +737,9 @@ static _Bool step(Runtime *runtime, Error *error) return 0; } } - else if(obj == NULL) - return 0; + else + if(obj == NULL) + return 0; if(!Runtime_Push(runtime, error, obj)) return 0; @@ -780,6 +805,21 @@ static _Bool step(Runtime *runtime, Error *error) return 1; } + case OPCODE_PUSHLST: + { + assert(opc == 1); + assert(ops[0].type == OPTP_INT); + + Object *obj = Object_NewList(ops[0].as_int, runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + case OPCODE_RETURN: return 0;