diff --git a/samples/loop.noja b/samples/loop.noja index ed84305..892d435 100644 --- a/samples/loop.noja +++ b/samples/loop.noja @@ -23,6 +23,4 @@ do while i < 3; # ------------------------------------- # -# ------------------------------------- # - -print(count(1, 2)); \ No newline at end of file +# ------------------------------------- # \ No newline at end of file diff --git a/src/common/executable.c b/src/common/executable.c index 015f2ba..7ac4749 100644 --- a/src/common/executable.c +++ b/src/common/executable.c @@ -59,6 +59,7 @@ static const InstrInfo instr_table[] = { [OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_CALL] = {"CALL", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_INSERT] = {"INSERT", 0, NULL}, + [OPCODE_SELECT] = {"SELECT", 0, NULL}, [OPCODE_PUSHINT] = {"PUSHINT", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_PUSHFLT] = {"PUSHFLT", 1, (OperandType[]) {OPTP_FLOAT}}, [OPCODE_PUSHSTR] = {"PUSHSTR", 1, (OperandType[]) {OPTP_STRING}}, diff --git a/src/common/executable.h b/src/common/executable.h index 48ba952..19581b5 100644 --- a/src/common/executable.h +++ b/src/common/executable.h @@ -38,6 +38,7 @@ typedef enum { OPCODE_POP, OPCODE_CALL, OPCODE_INSERT, + OPCODE_SELECT, OPCODE_PUSHINT, OPCODE_PUSHFLT, OPCODE_PUSHSTR, diff --git a/src/compiler/ASTi.h b/src/compiler/ASTi.h index 4ed7654..01dee4a 100644 --- a/src/compiler/ASTi.h +++ b/src/compiler/ASTi.h @@ -40,6 +40,7 @@ typedef enum { EXPR_FLOAT, EXPR_STRING, EXPR_IDENT, + EXPR_SELECT, } ExprKind; typedef struct Node Node; @@ -104,6 +105,12 @@ typedef struct { int argc; } CallExprNode; +typedef struct { + ExprNode base; + Node *idx; + Node *set; +} IndexSelectionExprNode; + typedef struct { Node base; Node *condition; diff --git a/src/compiler/compile.c b/src/compiler/compile.c index b28f23d..ecb2b2b 100644 --- a/src/compiler/compile.c +++ b/src/compiler/compile.c @@ -188,6 +188,19 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error) return ExeBuilder_Append(exeb, error, OPCODE_CALL, &op, 1, node->offset, node->length); } + case EXPR_SELECT: + { + IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr; + + if(!emit_instr_for_node(exeb, sel->set, error)) + return 0; + + if(!emit_instr_for_node(exeb, sel->idx, error)) + return 0; + + return ExeBuilder_Append(exeb, error, OPCODE_SELECT, NULL, 0, node->offset, node->length); + } + case EXPR_NONE: return ExeBuilder_Append(exeb, error, OPCODE_PUSHNNE, NULL, 0, node->offset, node->length); diff --git a/src/compiler/parse.c b/src/compiler/parse.c index a3cb1be..c9b7ac3 100644 --- a/src/compiler/parse.c +++ b/src/compiler/parse.c @@ -1160,6 +1160,44 @@ static Node *parse_postfix_expression(Context *ctx) { switch(current(ctx)) { + case '[': + { + Node *idx = parse_list_primary_expression(ctx); + + if(idx == NULL) + return NULL; + + ListExprNode *ls = (ListExprNode*) idx; + + if(ls->itemc == 0) + { + Error_Report(ctx->error, 0, "Missing index in index selection expression"); + return NULL; + } + + IndexSelectionExprNode *sel; + { + sel = BPAlloc_Malloc(ctx->alloc, sizeof(IndexSelectionExprNode)); + + if(sel == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + sel->base.base.kind = NODE_EXPR; + sel->base.base.next = NULL; + sel->base.base.offset = node->offset; + sel->base.base.length = idx->offset + idx->length - node->offset; + sel->base.kind = EXPR_SELECT; + sel->set = node; + sel->idx = ls->itemc == 1 ? ls->items : (Node*) ls; + } + + node = (Node*) sel; + break; + } + case '(': { int offset = current_token(ctx)->offset; diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 73cec22..ca1c6a1 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -665,6 +665,34 @@ static _Bool step(Runtime *runtime, Error *error) return 1; } + case OPCODE_SELECT: + { + assert(opc == 0); + + if(runtime->frame->used < 2) + { + Error_Report(error, 1, "Frame has not enough values on the stack to run SELECT instruction"); + return NULL; + } + + Object *col = Stack_Top(runtime->stack, -1); + Object *key = Stack_Top(runtime->stack, 0); + + assert(col != NULL && key != NULL); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + Object *val = Object_Select(col, key, runtime->heap, error); + + if(val == NULL) + return 0; + + if(!Runtime_Push(runtime, error, val)) + return 0; + return 1; + } + case OPCODE_PUSHINT: { assert(opc == 1);