added map expressions
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
stack = {count: 0, head: none};
|
||||||
|
|
||||||
|
fun push(stack, value)
|
||||||
|
{
|
||||||
|
node = {prev: none, item: value};
|
||||||
|
|
||||||
|
node.prev = stack.head;
|
||||||
|
stack.head = node;
|
||||||
|
stack.count = stack.count + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pop(stack)
|
||||||
|
{
|
||||||
|
if stack.head == none:
|
||||||
|
return none; # return it; ?
|
||||||
|
|
||||||
|
value = stack.head.item;
|
||||||
|
stack.head = stack.head.prev;
|
||||||
|
stack.count = stack.count - 1;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
push(stack, 1);
|
||||||
|
push(stack, 2);
|
||||||
|
push(stack, 3);
|
||||||
|
x = pop(stack);
|
||||||
|
y = pop(stack);
|
||||||
|
z = pop(stack);
|
||||||
|
w = pop(stack);
|
||||||
|
|
||||||
|
assert(x == 3);
|
||||||
|
assert(y == 2);
|
||||||
|
assert(z == 1);
|
||||||
|
assert(w == none);
|
||||||
@@ -58,8 +58,9 @@ static const InstrInfo instr_table[] = {
|
|||||||
[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}},
|
||||||
[OPCODE_INSERT] = {"INSERT", 0, NULL},
|
|
||||||
[OPCODE_SELECT] = {"SELECT", 0, NULL},
|
[OPCODE_SELECT] = {"SELECT", 0, NULL},
|
||||||
|
[OPCODE_INSERT] = {"INSERT", 0, NULL},
|
||||||
|
[OPCODE_INSERT2] = {"INSERT2", 0, NULL},
|
||||||
[OPCODE_PUSHINT] = {"PUSHINT", 1, (OperandType[]) {OPTP_INT}},
|
[OPCODE_PUSHINT] = {"PUSHINT", 1, (OperandType[]) {OPTP_INT}},
|
||||||
[OPCODE_PUSHFLT] = {"PUSHFLT", 1, (OperandType[]) {OPTP_FLOAT}},
|
[OPCODE_PUSHFLT] = {"PUSHFLT", 1, (OperandType[]) {OPTP_FLOAT}},
|
||||||
[OPCODE_PUSHSTR] = {"PUSHSTR", 1, (OperandType[]) {OPTP_STRING}},
|
[OPCODE_PUSHSTR] = {"PUSHSTR", 1, (OperandType[]) {OPTP_STRING}},
|
||||||
|
|||||||
@@ -37,8 +37,9 @@ typedef enum {
|
|||||||
OPCODE_ASS,
|
OPCODE_ASS,
|
||||||
OPCODE_POP,
|
OPCODE_POP,
|
||||||
OPCODE_CALL,
|
OPCODE_CALL,
|
||||||
OPCODE_INSERT,
|
|
||||||
OPCODE_SELECT,
|
OPCODE_SELECT,
|
||||||
|
OPCODE_INSERT,
|
||||||
|
OPCODE_INSERT2,
|
||||||
OPCODE_PUSHINT,
|
OPCODE_PUSHINT,
|
||||||
OPCODE_PUSHFLT,
|
OPCODE_PUSHFLT,
|
||||||
OPCODE_PUSHSTR,
|
OPCODE_PUSHSTR,
|
||||||
|
|||||||
+28
-9
@@ -88,19 +88,38 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
|
|||||||
lop = oper->head;
|
lop = oper->head;
|
||||||
rop = lop->next;
|
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))
|
if(!emit_instr_for_node(exeb, rop, error))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const char *name = ((IdentExprNode*) lop)->val;
|
if(((ExprNode*) lop)->kind == EXPR_IDENT)
|
||||||
|
{
|
||||||
|
const char *name = ((IdentExprNode*) lop)->val;
|
||||||
|
|
||||||
Operand op = { .type = OPTP_STRING, .as_string = name };
|
Operand op = { .type = OPTP_STRING, .as_string = name };
|
||||||
return ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, node->offset, node->length);
|
if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, node->offset, node->length))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if(((ExprNode*) lop)->kind == EXPR_SELECT)
|
||||||
|
{
|
||||||
|
Node *idx = ((IndexSelectionExprNode*) lop)->idx;
|
||||||
|
Node *set = ((IndexSelectionExprNode*) lop)->set;
|
||||||
|
|
||||||
|
if(!emit_instr_for_node(exeb, set, error))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!emit_instr_for_node(exeb, idx, error))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, node->offset, node->length))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Assignment left operand can't be assigned to");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EXPR_INT:
|
case EXPR_INT:
|
||||||
|
|||||||
+170
-79
@@ -631,6 +631,52 @@ static Node *parse_expression_statement(Context *ctx)
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Node *makeStringExprNode(Context *ctx, const char *str, int len)
|
||||||
|
{
|
||||||
|
if(str == NULL)
|
||||||
|
str = "";
|
||||||
|
|
||||||
|
if(len < 0)
|
||||||
|
len = strlen(str);
|
||||||
|
|
||||||
|
char *copy;
|
||||||
|
int copyl;
|
||||||
|
{
|
||||||
|
copy = BPAlloc_Malloc(ctx->alloc, len + 1);
|
||||||
|
|
||||||
|
if(copy == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(copy, str, len);
|
||||||
|
copy[len] = '\0';
|
||||||
|
copyl = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringExprNode *node;
|
||||||
|
{
|
||||||
|
node = BPAlloc_Malloc(ctx->alloc, sizeof(StringExprNode));
|
||||||
|
|
||||||
|
if(node == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->base.base.kind = NODE_EXPR;
|
||||||
|
node->base.base.next = NULL;
|
||||||
|
node->base.base.offset = ctx->token->offset;
|
||||||
|
node->base.base.length = ctx->token->length;
|
||||||
|
node->base.kind = EXPR_STRING;
|
||||||
|
node->val = copy;
|
||||||
|
node->len = copyl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Node*) node;
|
||||||
|
}
|
||||||
|
|
||||||
static Node *parse_string_primary_expression(Context *ctx)
|
static Node *parse_string_primary_expression(Context *ctx)
|
||||||
{
|
{
|
||||||
assert(ctx != NULL);
|
assert(ctx != NULL);
|
||||||
@@ -719,43 +765,9 @@ static Node *parse_string_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
temp[temp_used] = '\0';
|
temp[temp_used] = '\0';
|
||||||
|
|
||||||
char *copy;
|
|
||||||
int copyl;
|
|
||||||
|
|
||||||
{
|
|
||||||
copy = BPAlloc_Malloc(ctx->alloc, temp_used + 1);
|
|
||||||
|
|
||||||
if(copy == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(ctx->error, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(copy, temp);
|
|
||||||
copyl = temp_used;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringExprNode *node;
|
|
||||||
{
|
|
||||||
node = BPAlloc_Malloc(ctx->alloc, sizeof(StringExprNode));
|
|
||||||
|
|
||||||
if(node == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(ctx->error, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->base.base.kind = NODE_EXPR;
|
|
||||||
node->base.base.next = NULL;
|
|
||||||
node->base.base.offset = ctx->token->offset;
|
|
||||||
node->base.base.length = ctx->token->length;
|
|
||||||
node->base.kind = EXPR_STRING;
|
|
||||||
node->val = copy;
|
|
||||||
node->len = copyl;
|
|
||||||
}
|
|
||||||
|
|
||||||
next(ctx);
|
next(ctx);
|
||||||
return (Node*) node;
|
|
||||||
|
return makeStringExprNode(ctx, temp, temp_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Node *parse_list_primary_expression(Context *ctx)
|
static Node *parse_list_primary_expression(Context *ctx)
|
||||||
@@ -879,7 +891,30 @@ static Node *parse_map_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
Node *key = parse_expression(ctx);
|
Node *key;
|
||||||
|
|
||||||
|
_Bool key_is_a_single_ident;
|
||||||
|
{
|
||||||
|
_Bool key_starts_with_an_ident = current(ctx) == TIDENT;
|
||||||
|
|
||||||
|
next(ctx);
|
||||||
|
|
||||||
|
key_is_a_single_ident = key_starts_with_an_ident && (current(ctx) == TDONE || current(ctx) == ':');
|
||||||
|
|
||||||
|
prev(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(key_is_a_single_ident)
|
||||||
|
{
|
||||||
|
assert(current(ctx) == TIDENT);
|
||||||
|
key = makeStringExprNode(ctx, ctx->src + ctx->token->offset, ctx->token->length);
|
||||||
|
|
||||||
|
next(ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key = parse_expression(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
if(key == NULL)
|
if(key == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -982,6 +1017,39 @@ static char *copy_token_text(Context *ctx)
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Node *makeIdentExprNode(Context *ctx)
|
||||||
|
{
|
||||||
|
char *copy = copy_token_text(ctx);
|
||||||
|
int copyl = ctx->token->length;
|
||||||
|
|
||||||
|
if(copy == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentExprNode *node;
|
||||||
|
{
|
||||||
|
node = BPAlloc_Malloc(ctx->alloc, sizeof(IdentExprNode));
|
||||||
|
|
||||||
|
if(node == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->base.base.kind = NODE_EXPR;
|
||||||
|
node->base.base.next = NULL;
|
||||||
|
node->base.base.offset = ctx->token->offset;
|
||||||
|
node->base.base.length = ctx->token->length;
|
||||||
|
node->base.kind = EXPR_IDENT;
|
||||||
|
node->val = copy;
|
||||||
|
node->len = copyl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Node*) node;
|
||||||
|
}
|
||||||
|
|
||||||
static Node *parse_primary_expresion(Context *ctx)
|
static Node *parse_primary_expresion(Context *ctx)
|
||||||
{
|
{
|
||||||
assert(ctx != NULL);
|
assert(ctx != NULL);
|
||||||
@@ -1224,33 +1292,10 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
case TIDENT:
|
case TIDENT:
|
||||||
{
|
{
|
||||||
char *copy = copy_token_text(ctx);
|
Node *node = makeIdentExprNode(ctx);
|
||||||
int copyl = ctx->token->length;
|
|
||||||
|
|
||||||
if(copy == NULL)
|
if(node == NULL)
|
||||||
{
|
return NULL;
|
||||||
Error_Report(ctx->error, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
IdentExprNode *node;
|
|
||||||
{
|
|
||||||
node = BPAlloc_Malloc(ctx->alloc, sizeof(IdentExprNode));
|
|
||||||
|
|
||||||
if(node == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(ctx->error, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->base.base.kind = NODE_EXPR;
|
|
||||||
node->base.base.next = NULL;
|
|
||||||
node->base.base.offset = ctx->token->offset;
|
|
||||||
node->base.base.length = ctx->token->length;
|
|
||||||
node->base.kind = EXPR_IDENT;
|
|
||||||
node->val = copy;
|
|
||||||
node->len = copyl;
|
|
||||||
}
|
|
||||||
|
|
||||||
next(ctx);
|
next(ctx);
|
||||||
|
|
||||||
@@ -1270,6 +1315,26 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Node *makeIndexSelectionExprNode(Context *ctx, Node *set, Node *idx)
|
||||||
|
{
|
||||||
|
IndexSelectionExprNode *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 = -1;
|
||||||
|
sel->base.base.length = -1;
|
||||||
|
sel->base.kind = EXPR_SELECT;
|
||||||
|
sel->set = set;
|
||||||
|
sel->idx = idx;
|
||||||
|
return (Node*) sel;
|
||||||
|
}
|
||||||
|
|
||||||
static Node *parse_postfix_expression(Context *ctx)
|
static Node *parse_postfix_expression(Context *ctx)
|
||||||
{
|
{
|
||||||
assert(ctx != NULL);
|
assert(ctx != NULL);
|
||||||
@@ -1283,6 +1348,43 @@ static Node *parse_postfix_expression(Context *ctx)
|
|||||||
{
|
{
|
||||||
switch(current(ctx))
|
switch(current(ctx))
|
||||||
{
|
{
|
||||||
|
case '.':
|
||||||
|
{
|
||||||
|
next(ctx);
|
||||||
|
|
||||||
|
// We expect an identifier after the dot.
|
||||||
|
|
||||||
|
if(done(ctx))
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 0, "Source ended after dot of dot selection expression");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current(ctx) != TIDENT)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after fot of dot selection expression where an identifier was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *idx = makeStringExprNode(ctx, ctx->src + ctx->token->offset, ctx->token->length);
|
||||||
|
|
||||||
|
if(idx == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Node *sel = makeIndexSelectionExprNode(ctx, node, idx);
|
||||||
|
|
||||||
|
if(sel == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sel->offset = node->offset;
|
||||||
|
sel->length = idx->offset + idx->length - node->offset;
|
||||||
|
|
||||||
|
next(ctx); // Get to the token after the identifier.
|
||||||
|
|
||||||
|
node = (Node*) sel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case '[':
|
case '[':
|
||||||
{
|
{
|
||||||
Node *idx = parse_list_primary_expression(ctx);
|
Node *idx = parse_list_primary_expression(ctx);
|
||||||
@@ -1298,24 +1400,13 @@ static Node *parse_postfix_expression(Context *ctx)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexSelectionExprNode *sel;
|
Node *sel = makeIndexSelectionExprNode(ctx, node, ls->itemc == 1 ? ls->items : (Node*) ls);
|
||||||
{
|
|
||||||
sel = BPAlloc_Malloc(ctx->alloc, sizeof(IndexSelectionExprNode));
|
|
||||||
|
|
||||||
if(sel == NULL)
|
if(sel == NULL)
|
||||||
{
|
return NULL;
|
||||||
Error_Report(ctx->error, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sel->base.base.kind = NODE_EXPR;
|
sel->offset = node->offset;
|
||||||
sel->base.base.next = NULL;
|
sel->length = idx->offset + idx->length - node->offset;
|
||||||
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;
|
node = (Node*) sel;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
|
|
||||||
|
static _Bool op_eql(Object *self, Object *other);
|
||||||
static void print(Object *obj, FILE *fp);
|
static void print(Object *obj, FILE *fp);
|
||||||
|
|
||||||
static const Type t_none = {
|
static const Type t_none = {
|
||||||
@@ -9,6 +10,7 @@ static const Type t_none = {
|
|||||||
.name = "none",
|
.name = "none",
|
||||||
.size = sizeof (Object),
|
.size = sizeof (Object),
|
||||||
.print = print,
|
.print = print,
|
||||||
|
.op_eql = op_eql,
|
||||||
};
|
};
|
||||||
|
|
||||||
static Object the_none_object = {
|
static Object the_none_object = {
|
||||||
@@ -32,3 +34,11 @@ static void print(Object *obj, FILE *fp)
|
|||||||
|
|
||||||
fprintf(fp, "none");
|
fprintf(fp, "none");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _Bool op_eql(Object *self, Object *other)
|
||||||
|
{
|
||||||
|
(void) self;
|
||||||
|
|
||||||
|
assert(other->type == &t_none);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
+19
-2
@@ -21,6 +21,22 @@ static Object *bin_count(Runtime *runtime, Object **argv, unsigned int argc, Err
|
|||||||
return Object_FromInt(n, Runtime_GetHeap(runtime), error);
|
return Object_FromInt(n, Runtime_GetHeap(runtime), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Object *bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||||
|
{
|
||||||
|
assert(argc == 1);
|
||||||
|
|
||||||
|
if(Object_ToBool(argv[0], error))
|
||||||
|
{
|
||||||
|
return Object_NewNone(Runtime_GetHeap(runtime), error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!error->occurred)
|
||||||
|
Error_Report(error, 0, "Assertion failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
int argc;
|
int argc;
|
||||||
@@ -28,8 +44,9 @@ typedef struct {
|
|||||||
} BuiltinNativeFunctions;
|
} BuiltinNativeFunctions;
|
||||||
|
|
||||||
BuiltinNativeFunctions builtins[] = {
|
BuiltinNativeFunctions builtins[] = {
|
||||||
{"print", -1, bin_print},
|
{"print", -1, bin_print},
|
||||||
{"count", 1, bin_count},
|
{"count", 1, bin_count},
|
||||||
|
{"assert", 1, bin_assert},
|
||||||
};
|
};
|
||||||
|
|
||||||
_Bool add_builtins(Runtime *runtime, Error *error)
|
_Bool add_builtins(Runtime *runtime, Error *error)
|
||||||
|
|||||||
+60
-24
@@ -456,7 +456,19 @@ static _Bool step(Runtime *runtime, Error *error)
|
|||||||
Error_Report(error, 1, "Invalid instruction index");
|
Error_Report(error, 1, "Invalid instruction index");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
#warning "TEMPORARY"
|
||||||
|
{
|
||||||
|
int index = runtime->frame->index;
|
||||||
|
Executable *exe = runtime->frame->exe;
|
||||||
|
Source *src = Executable_GetSource(exe);
|
||||||
|
int offset = Executable_GetInstrOffset(exe, index);
|
||||||
|
int length = Executable_GetInstrLength(exe, index);
|
||||||
|
const char *str = Source_GetBody(src);
|
||||||
|
|
||||||
|
printf("Executing [%.*s]\n", length, str + offset);
|
||||||
|
}
|
||||||
|
*/
|
||||||
runtime->frame->index += 1;
|
runtime->frame->index += 1;
|
||||||
|
|
||||||
switch(opcode)
|
switch(opcode)
|
||||||
@@ -641,30 +653,6 @@ static _Bool step(Runtime *runtime, Error *error)
|
|||||||
return 1;
|
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_SELECT:
|
case OPCODE_SELECT:
|
||||||
{
|
{
|
||||||
assert(opc == 0);
|
assert(opc == 0);
|
||||||
@@ -693,6 +681,54 @@ static _Bool step(Runtime *runtime, Error *error)
|
|||||||
return 1;
|
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_INSERT2:
|
||||||
|
{
|
||||||
|
assert(opc == 0);
|
||||||
|
|
||||||
|
if(runtime->frame->used < 3)
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "Frame has not enough values on the stack to run INSERT2 instruction");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object *val = Stack_Top(runtime->stack, -2);
|
||||||
|
Object *col = Stack_Top(runtime->stack, -1);
|
||||||
|
Object *key = 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:
|
case OPCODE_PUSHINT:
|
||||||
{
|
{
|
||||||
assert(opc == 1);
|
assert(opc == 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user