L2_OP_ADD, | L2_OP_ADD, | ||||
/* | /* | ||||
* Call a function; func_call <argc:u4> | |||||
* Call a function; func_call <argc> | |||||
* Pop <argc> times | * Pop <argc> times | ||||
* Pop <func> | * Pop <func> | ||||
* Push array with args | * Push array with args | ||||
* (Before returning, the function will push a return value onto the stack) | * (Before returning, the function will push a return value onto the stack) | ||||
*/ | */ | ||||
L2_OP_FUNC_CALL_U4, | L2_OP_FUNC_CALL_U4, | ||||
L2_OP_FUNC_CALL_U1, | |||||
/* | /* | ||||
* Call an infix function | * Call an infix function | ||||
L2_OP_FUNC_CALL_INFIX, | L2_OP_FUNC_CALL_INFIX, | ||||
/* | /* | ||||
* Jump relative; rjmp <count:u4> | |||||
* Jump relative; rjmp <count> | |||||
* Jump <count> words forwards | * Jump <count> words forwards | ||||
*/ | */ | ||||
L2_OP_RJMP_U4, | L2_OP_RJMP_U4, | ||||
L2_OP_RJMP_U1, | |||||
/* | /* | ||||
* Look up a value from the current stack frame; stack_frame_lookup <key:u4> | |||||
* Look up a value from the current stack frame; stack_frame_lookup <key> | |||||
* Find <val> in stack frame using <key> | * Find <val> in stack frame using <key> | ||||
* Push <val> | * Push <val> | ||||
*/ | */ | ||||
L2_OP_STACK_FRAME_LOOKUP_U4, | L2_OP_STACK_FRAME_LOOKUP_U4, | ||||
L2_OP_STACK_FRAME_LOOKUP_U1, | |||||
/* | /* | ||||
* Set a value in the current stack frame; stack_frame_set <key:u4> | |||||
* Set a value in the current stack frame; stack_frame_set <key> | |||||
* Read <val> | * Read <val> | ||||
* Assign <val> to stack frame at <key> | * Assign <val> to stack frame at <key> | ||||
*/ | */ | ||||
L2_OP_STACK_FRAME_SET_U4, | L2_OP_STACK_FRAME_SET_U4, | ||||
L2_OP_STACK_FRAME_SET_U1, | |||||
/* | /* | ||||
* Replace a value on the stack; stack_frame_replace <key:U4> | |||||
* Replace a value on the stack; stack_frame_replace <key> | |||||
* Read <val> | * Read <val> | ||||
* Assign <val> to stack frame at <key> | * Assign <val> to stack frame at <key> | ||||
*/ | */ | ||||
L2_OP_STACK_FRAME_REPLACE_U4, | L2_OP_STACK_FRAME_REPLACE_U4, | ||||
L2_OP_STACK_FRAME_REPLACE_U1, | |||||
/* | /* | ||||
* Return from a function. | * Return from a function. | ||||
L2_OP_ALLOC_NONE, | L2_OP_ALLOC_NONE, | ||||
/* | /* | ||||
* Allocate an atom from one word; alloc_atom <word:u4> | |||||
* Allocate an atom from one word; alloc_atom <word> | |||||
* Alloc atom <var> from <word> | * Alloc atom <var> from <word> | ||||
* Push <var> | * Push <var> | ||||
*/ | */ | ||||
L2_OP_ALLOC_ATOM_U4, | L2_OP_ALLOC_ATOM_U4, | ||||
L2_OP_ALLOC_ATOM_U1, | |||||
/* | /* | ||||
* Allocate a real from two words; alloc_real <double:u8> | * Allocate a real from two words; alloc_real <double:u8> | ||||
L2_OP_ALLOC_REAL_D8, | L2_OP_ALLOC_REAL_D8, | ||||
/* | /* | ||||
* Allocate a buffer from static data; alloc_buffer_static <length:u4> <offset:u4> | |||||
* Allocate a buffer from static data; alloc_buffer_static <length> <offset> | |||||
* Alloc buffer <var> with <length> and <offset> | * Alloc buffer <var> with <length> and <offset> | ||||
* Push <var> | * Push <var> | ||||
*/ | */ | ||||
L2_OP_ALLOC_BUFFER_STATIC_U4, | L2_OP_ALLOC_BUFFER_STATIC_U4, | ||||
L2_OP_ALLOC_BUFFER_STATIC_U1, | |||||
/* | /* | ||||
* Allocate an array; <count:u4> | * Allocate an array; <count:u4> | ||||
* Push <var> | * Push <var> | ||||
*/ | */ | ||||
L2_OP_ALLOC_ARRAY_U4, | L2_OP_ALLOC_ARRAY_U4, | ||||
L2_OP_ALLOC_ARRAY_U1, | |||||
/* | /* | ||||
* Allocate an integer->value map. | * Allocate an integer->value map. | ||||
L2_OP_ALLOC_NAMESPACE, | L2_OP_ALLOC_NAMESPACE, | ||||
/* | /* | ||||
* Allocate a function; alloc_function <pos:u4> | |||||
* Allocate a function; alloc_function <pos> | |||||
* Alloc function <var> pointing to location <word> | * Alloc function <var> pointing to location <word> | ||||
* Push <var> | * Push <var> | ||||
*/ | */ | ||||
L2_OP_ALLOC_FUNCTION_U4, | L2_OP_ALLOC_FUNCTION_U4, | ||||
L2_OP_ALLOC_FUNCTION_U1, | |||||
/* | /* | ||||
* Set a namespace's name to a value; namespace_set <key:u4> | * Set a namespace's name to a value; namespace_set <key:u4> | ||||
* Assign <val> to <ns[<key>]> | * Assign <val> to <ns[<key>]> | ||||
*/ | */ | ||||
L2_OP_NAMESPACE_SET_U4, | L2_OP_NAMESPACE_SET_U4, | ||||
L2_OP_NAMESPACE_SET_U1, | |||||
/* | /* | ||||
* Lookup a value from a namespace; namespace_lookup <key:u4> | * Lookup a value from a namespace; namespace_lookup <key:u4> | ||||
* Push <ns[<key>]> | * Push <ns[<key>]> | ||||
*/ | */ | ||||
L2_OP_NAMESPACE_LOOKUP_U4, | L2_OP_NAMESPACE_LOOKUP_U4, | ||||
L2_OP_NAMESPACE_LOOKUP_U1, | |||||
/* | /* | ||||
* Look up a value from an array; array_lookup <key:u4> | * Look up a value from an array; array_lookup <key:u4> | ||||
* Push <arr[<key>]> | * Push <arr[<key>]> | ||||
*/ | */ | ||||
L2_OP_ARRAY_LOOKUP_U4, | L2_OP_ARRAY_LOOKUP_U4, | ||||
L2_OP_ARRAY_LOOKUP_U1, | |||||
/* | /* | ||||
* Set a value in an array; array_set <key> | * Set a value in an array; array_set <key> | ||||
* Read <arr> | * Read <arr> | ||||
* Assign <val> to <arr[<key>]> | * Assign <val> to <arr[<key>]> | ||||
*/ | */ | ||||
L2_OP_ARRAY_SET, | |||||
L2_OP_ARRAY_SET_U4, | |||||
L2_OP_ARRAY_SET_U1, | |||||
/* | /* | ||||
* Look up a runtime value in an array or object. | * Look up a runtime value in an array or object. |
void l2_gen_halt(struct l2_generator *gen); | void l2_gen_halt(struct l2_generator *gen); | ||||
void l2_gen_rjmp(struct l2_generator *gen, l2_word len); | void l2_gen_rjmp(struct l2_generator *gen, l2_word len); | ||||
void l2_gen_rjmp_placeholder(struct l2_generator *gen); | |||||
void l2_gen_discard(struct l2_generator *gen); | void l2_gen_discard(struct l2_generator *gen); | ||||
void l2_gen_swap_discard(struct l2_generator *gen); | void l2_gen_swap_discard(struct l2_generator *gen); | ||||
void l2_gen_ret(struct l2_generator *gen); | void l2_gen_ret(struct l2_generator *gen); |
} | } | ||||
void l2_gen_rjmp(struct l2_generator *gen, l2_word len) { | void l2_gen_rjmp(struct l2_generator *gen, l2_word len) { | ||||
if (len <= 0xff) { | |||||
put(gen, L2_OP_RJMP_U1); | |||||
put(gen, len); | |||||
} else { | |||||
put(gen, L2_OP_RJMP_U4); | |||||
put_u4le(gen, len); | |||||
} | |||||
} | |||||
void l2_gen_rjmp_placeholder(struct l2_generator *gen) { | |||||
put(gen, L2_OP_RJMP_U4); | put(gen, L2_OP_RJMP_U4); | ||||
put_u4le(gen, len); | |||||
put_u4le(gen, 0); | |||||
} | } | ||||
void l2_gen_discard(struct l2_generator *gen) { | void l2_gen_discard(struct l2_generator *gen) { | ||||
void l2_gen_atom(struct l2_generator *gen, char **str) { | void l2_gen_atom(struct l2_generator *gen, char **str) { | ||||
size_t id = l2_strset_put(&gen->atomset, str); | size_t id = l2_strset_put(&gen->atomset, str); | ||||
put(gen, L2_OP_ALLOC_ATOM_U4); | |||||
put_u4le(gen, id); | |||||
if (id <= 0xff) { | |||||
put(gen, L2_OP_ALLOC_ATOM_U1); | |||||
put(gen, id); | |||||
} else { | |||||
put(gen, L2_OP_ALLOC_ATOM_U4); | |||||
put_u4le(gen, id); | |||||
} | |||||
} | } | ||||
void l2_gen_atom_copy(struct l2_generator *gen, char *str) { | void l2_gen_atom_copy(struct l2_generator *gen, char *str) { | ||||
size_t id = l2_strset_put_copy(&gen->atomset, str); | size_t id = l2_strset_put_copy(&gen->atomset, str); | ||||
put(gen, L2_OP_ALLOC_ATOM_U4); | |||||
put_u4le(gen, id); | |||||
if (id <= 0xff) { | |||||
put(gen, L2_OP_ALLOC_ATOM_U1); | |||||
put(gen, id); | |||||
} else { | |||||
put(gen, L2_OP_ALLOC_ATOM_U4); | |||||
put_u4le(gen, id); | |||||
} | |||||
} | } | ||||
void l2_gen_string(struct l2_generator *gen, char **str) { | void l2_gen_string(struct l2_generator *gen, char **str) { | ||||
size_t id = l2_strset_get(&gen->stringset, *str); | size_t id = l2_strset_get(&gen->stringset, *str); | ||||
if (id == 0) { | if (id == 0) { | ||||
size_t len = strlen(*str); | size_t len = strlen(*str); | ||||
size_t aligned = len; | |||||
if (aligned % sizeof(l2_word) != 0) { | |||||
aligned += sizeof(l2_word) - (aligned % sizeof(l2_word)); | |||||
} | |||||
put(gen, L2_OP_RJMP_U4); | |||||
put_u4le(gen, aligned / sizeof(l2_word)); | |||||
l2_gen_rjmp(gen, len); | |||||
l2_word pos = gen->pos; | l2_word pos = gen->pos; | ||||
gen->pos += aligned / sizeof(l2_word); | |||||
gen->pos += len; | |||||
l2_bufio_put_n(&gen->writer, *str, len); | l2_bufio_put_n(&gen->writer, *str, len); | ||||
for (size_t i = len; i < aligned; ++i) { | |||||
l2_bufio_put(&gen->writer, '\0'); | |||||
} | |||||
id = l2_strset_put(&gen->stringset, str); | id = l2_strset_put(&gen->stringset, str); | ||||
gen->strings = realloc(gen->strings, id * sizeof(*gen->strings)); | gen->strings = realloc(gen->strings, id * sizeof(*gen->strings)); | ||||
gen->strings[id - 1].length = len; | gen->strings[id - 1].length = len; | ||||
gen->strings[id - 1].pos = pos; | gen->strings[id - 1].pos = pos; | ||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U4); | |||||
put_u4le(gen, len); | |||||
put_u4le(gen, pos); | |||||
if (len <= 0xff && pos <= 0xff) { | |||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U1); | |||||
put(gen, len); | |||||
put(gen, pos); | |||||
} else { | |||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U4); | |||||
put_u4le(gen, len); | |||||
put_u4le(gen, pos); | |||||
} | |||||
} else { | } else { | ||||
free(*str); | free(*str); | ||||
struct l2_generator_string *s = &gen->strings[id - 1]; | struct l2_generator_string *s = &gen->strings[id - 1]; | ||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U4); | |||||
put_u4le(gen, s->length); | |||||
put_u4le(gen, s->pos); | |||||
if (s->length <= 0xff && s->pos <= 0xff) { | |||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U1); | |||||
put(gen, s->length); | |||||
put(gen, s->pos); | |||||
} else { | |||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U4); | |||||
put_u4le(gen, s->length); | |||||
put_u4le(gen, s->pos); | |||||
} | |||||
} | } | ||||
} | } | ||||
l2_gen_string(gen, &s); | l2_gen_string(gen, &s); | ||||
} else { | } else { | ||||
struct l2_generator_string *s = &gen->strings[id - 1]; | struct l2_generator_string *s = &gen->strings[id - 1]; | ||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U4); | |||||
put_u4le(gen, s->length); | |||||
put_u4le(gen, s->pos); | |||||
if (s->length <= 0xff && s->pos <= 0xff) { | |||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U1); | |||||
put(gen, s->length); | |||||
put(gen, s->pos); | |||||
} else { | |||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U4); | |||||
put_u4le(gen, s->length); | |||||
put_u4le(gen, s->pos); | |||||
} | |||||
} | } | ||||
} | } | ||||
void l2_gen_function(struct l2_generator *gen, l2_word pos) { | void l2_gen_function(struct l2_generator *gen, l2_word pos) { | ||||
put(gen, L2_OP_ALLOC_FUNCTION_U4); | |||||
put_u4le(gen, pos); | |||||
if (pos <= 0xff) { | |||||
put(gen, L2_OP_ALLOC_FUNCTION_U1); | |||||
put(gen, pos); | |||||
} else { | |||||
put(gen, L2_OP_ALLOC_FUNCTION_U4); | |||||
put_u4le(gen, pos); | |||||
} | |||||
} | } | ||||
void l2_gen_array(struct l2_generator *gen, l2_word count) { | void l2_gen_array(struct l2_generator *gen, l2_word count) { | ||||
put(gen, L2_OP_ALLOC_ARRAY_U4); | |||||
put_u4le(gen, count); | |||||
if (count <= 0xff) { | |||||
put(gen, L2_OP_ALLOC_ARRAY_U1); | |||||
put(gen, count); | |||||
} else { | |||||
put(gen, L2_OP_ALLOC_ARRAY_U4); | |||||
put_u4le(gen, count); | |||||
} | |||||
} | } | ||||
void l2_gen_namespace(struct l2_generator *gen) { | void l2_gen_namespace(struct l2_generator *gen) { | ||||
void l2_gen_namespace_set(struct l2_generator *gen, char **ident) { | void l2_gen_namespace_set(struct l2_generator *gen, char **ident) { | ||||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
put(gen, L2_OP_NAMESPACE_SET_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_NAMESPACE_SET_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_NAMESPACE_SET_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_namespace_set_copy(struct l2_generator *gen, char *ident) { | void l2_gen_namespace_set_copy(struct l2_generator *gen, char *ident) { | ||||
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | ||||
put(gen, L2_OP_NAMESPACE_SET_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_NAMESPACE_SET_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_NAMESPACE_SET_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident) { | void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident) { | ||||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
put(gen, L2_OP_NAMESPACE_LOOKUP_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_NAMESPACE_LOOKUP_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_NAMESPACE_LOOKUP_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_namespace_lookup_copy(struct l2_generator *gen, char *ident) { | void l2_gen_namespace_lookup_copy(struct l2_generator *gen, char *ident) { | ||||
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | ||||
put(gen, L2_OP_NAMESPACE_LOOKUP_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_NAMESPACE_LOOKUP_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_NAMESPACE_LOOKUP_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_array_lookup(struct l2_generator *gen, int number) { | void l2_gen_array_lookup(struct l2_generator *gen, int number) { | ||||
put(gen, L2_OP_ARRAY_LOOKUP_U4); | |||||
put_u4le(gen, number); | |||||
if (number <= 0xff) { | |||||
put(gen, L2_OP_ARRAY_LOOKUP_U1); | |||||
put(gen, number); | |||||
} else { | |||||
put(gen, L2_OP_ARRAY_LOOKUP_U4); | |||||
put_u4le(gen, number); | |||||
} | |||||
} | } | ||||
void l2_gen_array_set(struct l2_generator *gen, int number) { | void l2_gen_array_set(struct l2_generator *gen, int number) { | ||||
put(gen, L2_OP_ARRAY_SET); | |||||
put(gen, number); | |||||
if (number <= 0xff) { | |||||
put(gen, L2_OP_ARRAY_SET_U1); | |||||
put(gen, number); | |||||
} else { | |||||
put(gen, L2_OP_ARRAY_SET_U4); | |||||
put_u4le(gen, number); | |||||
} | |||||
} | } | ||||
void l2_gen_dynamic_lookup(struct l2_generator *gen) { | void l2_gen_dynamic_lookup(struct l2_generator *gen) { | ||||
void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | ||||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
put(gen, L2_OP_STACK_FRAME_LOOKUP_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_STACK_FRAME_LOOKUP_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_STACK_FRAME_LOOKUP_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_stack_frame_lookup_copy(struct l2_generator *gen, char *ident) { | void l2_gen_stack_frame_lookup_copy(struct l2_generator *gen, char *ident) { | ||||
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | ||||
put(gen, L2_OP_STACK_FRAME_LOOKUP_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_STACK_FRAME_LOOKUP_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_STACK_FRAME_LOOKUP_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_stack_frame_set(struct l2_generator *gen, char **ident) { | void l2_gen_stack_frame_set(struct l2_generator *gen, char **ident) { | ||||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
put(gen, L2_OP_STACK_FRAME_SET_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_STACK_FRAME_SET_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_STACK_FRAME_SET_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_stack_frame_set_copy(struct l2_generator *gen, char *ident) { | void l2_gen_stack_frame_set_copy(struct l2_generator *gen, char *ident) { | ||||
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | ||||
put(gen, L2_OP_STACK_FRAME_SET_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_STACK_FRAME_SET_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_STACK_FRAME_SET_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident) { | void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident) { | ||||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
put(gen, L2_OP_STACK_FRAME_REPLACE_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_STACK_FRAME_REPLACE_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_STACK_FRAME_REPLACE_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_stack_frame_replace_copy(struct l2_generator *gen, char *ident) { | void l2_gen_stack_frame_replace_copy(struct l2_generator *gen, char *ident) { | ||||
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | size_t atom_id = l2_strset_put_copy(&gen->atomset, ident); | ||||
put(gen, L2_OP_STACK_FRAME_REPLACE_U4); | |||||
put_u4le(gen, atom_id); | |||||
if (atom_id <= 0xff) { | |||||
put(gen, L2_OP_STACK_FRAME_REPLACE_U1); | |||||
put(gen, atom_id); | |||||
} else { | |||||
put(gen, L2_OP_STACK_FRAME_REPLACE_U4); | |||||
put_u4le(gen, atom_id); | |||||
} | |||||
} | } | ||||
void l2_gen_func_call(struct l2_generator *gen, l2_word argc) { | void l2_gen_func_call(struct l2_generator *gen, l2_word argc) { | ||||
put(gen, L2_OP_FUNC_CALL_U4); | |||||
put_u4le(gen, argc); | |||||
if (argc <= 0xff) { | |||||
put(gen, L2_OP_FUNC_CALL_U1); | |||||
put(gen, argc); | |||||
} else { | |||||
put(gen, L2_OP_FUNC_CALL_U4); | |||||
put_u4le(gen, argc); | |||||
} | |||||
} | } | ||||
void l2_gen_func_call_infix(struct l2_generator *gen) { | void l2_gen_func_call_infix(struct l2_generator *gen) { |
((uint32_t)version_buf[2]) << 16 | | ((uint32_t)version_buf[2]) << 16 | | ||||
((uint32_t)version_buf[3]) << 24; | ((uint32_t)version_buf[3]) << 24; | ||||
if (version != l2_bytecode_version) { | if (version != l2_bytecode_version) { | ||||
fprintf( | |||||
stderr, "Version mismatch! Bytecode file uses bytecode version %i" | |||||
fprintf(stderr, | |||||
"Version mismatch! Bytecode file uses bytecode version %i" | |||||
", but your build of lang2 uses bytecode version %i\n", | ", but your build of lang2 uses bytecode version %i\n", | ||||
version, l2_bytecode_version); | version, l2_bytecode_version); | ||||
return -1; | return -1; |
w.w.write = l2_io_mem_write; | w.w.write = l2_io_mem_write; | ||||
gen->writer.w = &w.w; | gen->writer.w = &w.w; | ||||
// Generates two words; RJMP, 0 | |||||
l2_gen_rjmp(gen, 0); | |||||
// Generates five bytes; RJMP, then 4 byte counter | |||||
l2_gen_rjmp_placeholder(gen); | |||||
l2_word pos = gen->pos; | l2_word pos = gen->pos; | ||||
return -1; | return -1; | ||||
} | } | ||||
l2_word *ops = w.mem; | |||||
l2_word opcount = w.len / sizeof(l2_word); | |||||
unsigned char *ops = w.mem; | |||||
l2_word opcount = w.len - 5; | |||||
// Due to the earlier gen_rjmp, the second word will be the argument to RJMP. | |||||
// Need to set it properly to skip the function body. | |||||
// The '- 2' is because we don't skip the RJMP, <count> sequence. | |||||
ops[1] = opcount - 2; | |||||
// Write the jump distance (little endian) | |||||
ops[1] = (opcount >> 0) & 0xff; | |||||
ops[2] = (opcount >> 8) & 0xff; | |||||
ops[3] = (opcount >> 16) & 0xff; | |||||
ops[4] = (opcount >> 24) & 0xff; | |||||
l2_bufio_put_n(&gen->writer, ops, opcount * sizeof(l2_word)); | |||||
l2_bufio_put_n(&gen->writer, ops, w.len); | |||||
free(w.mem); | free(w.mem); | ||||
l2_gen_function(gen, pos); | l2_gen_function(gen, pos); |
return ret; | return ret; | ||||
} | } | ||||
static l2_word read_u1le(unsigned char *ops, size_t *ptr) { | |||||
return ops[(*ptr)++]; | |||||
} | |||||
static double read_d8le(unsigned char *ops, size_t *ptr) { | static double read_d8le(unsigned char *ops, size_t *ptr) { | ||||
unsigned char *data = &ops[*ptr]; | unsigned char *data = &ops[*ptr]; | ||||
uint64_t integer = 0 | | uint64_t integer = 0 | | ||||
case L2_OP_FUNC_CALL_U4: | case L2_OP_FUNC_CALL_U4: | ||||
printf("FUNC_CALL %08x\n", read_u4le(ops, ptr)); | printf("FUNC_CALL %08x\n", read_u4le(ops, ptr)); | ||||
return; | return; | ||||
case L2_OP_FUNC_CALL_U1: | |||||
printf("FUNC_CALL %02x\n", read_u1le(ops, ptr)); | |||||
return; | |||||
case L2_OP_FUNC_CALL_INFIX: | case L2_OP_FUNC_CALL_INFIX: | ||||
printf("FUNC_CALL_INFIX\n"); | printf("FUNC_CALL_INFIX\n"); | ||||
case L2_OP_RJMP_U4: | case L2_OP_RJMP_U4: | ||||
printf("RJMP %08x\n", read_u4le(ops, ptr)); | printf("RJMP %08x\n", read_u4le(ops, ptr)); | ||||
return; | return; | ||||
case L2_OP_RJMP_U1: | |||||
printf("RJMP %02x\n", read_u1le(ops, ptr)); | |||||
return; | |||||
case L2_OP_STACK_FRAME_LOOKUP_U4: | case L2_OP_STACK_FRAME_LOOKUP_U4: | ||||
printf("STACK_FRAME_LOOKUP %08x\n", read_u4le(ops, ptr)); | printf("STACK_FRAME_LOOKUP %08x\n", read_u4le(ops, ptr)); | ||||
return; | return; | ||||
case L2_OP_STACK_FRAME_LOOKUP_U1: | |||||
printf("STACK_FRAME_LOOKUP %02x\n", read_u1le(ops, ptr)); | |||||
return; | |||||
case L2_OP_STACK_FRAME_SET_U4: | case L2_OP_STACK_FRAME_SET_U4: | ||||
printf("STACK_FRAME_SET %08x\n", read_u4le(ops, ptr)); | printf("STACK_FRAME_SET %08x\n", read_u4le(ops, ptr)); | ||||
return; | return; | ||||
case L2_OP_STACK_FRAME_SET_U1: | |||||
printf("STACK_FRAME_SET %02x\n", read_u1le(ops, ptr)); | |||||
return; | |||||
case L2_OP_STACK_FRAME_REPLACE_U4: | case L2_OP_STACK_FRAME_REPLACE_U4: | ||||
printf("STACK_FRAME_REPLACE %08x\n", read_u4le(ops, ptr)); | printf("STACK_FRAME_REPLACE %08x\n", read_u4le(ops, ptr)); | ||||
return; | return; | ||||
case L2_OP_STACK_FRAME_REPLACE_U1: | |||||
printf("STACK_FRAME_REPLACE %02x\n", read_u1le(ops, ptr)); | |||||
return; | |||||
case L2_OP_RET: | case L2_OP_RET: | ||||
printf("RET\n"); | printf("RET\n"); | ||||
case L2_OP_ALLOC_ATOM_U4: | case L2_OP_ALLOC_ATOM_U4: | ||||
printf("ALLOC_ATOM %08x\n", read_u4le(ops, ptr)); | printf("ALLOC_ATOM %08x\n", read_u4le(ops, ptr)); | ||||
return; | return; | ||||
case L2_OP_ALLOC_ATOM_U1: | |||||
printf("ALLOC_ATOM %02x\n", read_u1le(ops, ptr)); | |||||
return; | |||||
case L2_OP_ALLOC_REAL_D8: | case L2_OP_ALLOC_REAL_D8: | ||||
printf("ALLOC_REAL %f\n", read_d8le(ops, ptr)); | printf("ALLOC_REAL %f\n", read_d8le(ops, ptr)); | ||||
printf("ALLOC_BUFFER_STATIC %08x %08x\n", w1, w2); | printf("ALLOC_BUFFER_STATIC %08x %08x\n", w1, w2); | ||||
} | } | ||||
return; | return; | ||||
case L2_OP_ALLOC_BUFFER_STATIC_U1: | |||||
{ | |||||
l2_word w1 = read_u1le(ops, ptr); | |||||
l2_word w2 = read_u1le(ops, ptr);; | |||||
printf("ALLOC_BUFFER_STATIC %02x %02x\n", w1, w2); | |||||
} | |||||
return; | |||||
case L2_OP_ALLOC_ARRAY_U4: | case L2_OP_ALLOC_ARRAY_U4: | ||||
printf("ALLOC_ARRAY_U4 %08x\n", read_u4le(ops, ptr)); | |||||
printf("ALLOC_ARRAY %08x\n", read_u4le(ops, ptr)); | |||||
return; | |||||
case L2_OP_ALLOC_ARRAY_U1: | |||||
printf("ALLOC_ARRAY %02x\n", read_u1le(ops, ptr)); | |||||
return; | return; | ||||
case L2_OP_ALLOC_NAMESPACE: | case L2_OP_ALLOC_NAMESPACE: | ||||
return; | return; | ||||
case L2_OP_ALLOC_FUNCTION_U4: | case L2_OP_ALLOC_FUNCTION_U4: | ||||
printf("ALLOC_FUNCTION_U4 %08x\n", read_u4le(ops, ptr)); | |||||
printf("ALLOC_FUNCTION %08x\n", read_u4le(ops, ptr)); | |||||
return; | |||||
case L2_OP_ALLOC_FUNCTION_U1: | |||||
printf("ALLOC_FUNCTION %02x\n", read_u1le(ops, ptr)); | |||||
return; | return; | ||||
case L2_OP_NAMESPACE_SET_U4: | case L2_OP_NAMESPACE_SET_U4: | ||||
printf("NAMESPACE_SET_U4 %08x\n", read_u4le(ops, ptr)); | |||||
printf("NAMESPACE_SET %08x\n", read_u4le(ops, ptr)); | |||||
return; | |||||
case L2_OP_NAMESPACE_SET_U1: | |||||
printf("NAMESPACE_SET %02x\n", read_u1le(ops, ptr)); | |||||
return; | return; | ||||
case L2_OP_NAMESPACE_LOOKUP_U4: | case L2_OP_NAMESPACE_LOOKUP_U4: | ||||
printf("NAMESPACE_LOOKUP_U4 %08x\n", read_u4le(ops, ptr)); | |||||
printf("NAMESPACE_LOOKUP %08x\n", read_u4le(ops, ptr)); | |||||
return; | |||||
case L2_OP_NAMESPACE_LOOKUP_U1: | |||||
printf("NAMESPACE_LOOKUP %02x\n", read_u1le(ops, ptr)); | |||||
return; | return; | ||||
case L2_OP_ARRAY_LOOKUP_U4: | case L2_OP_ARRAY_LOOKUP_U4: | ||||
printf("ARRAY_LOOKUP_U4 %08x\n", read_u4le(ops, ptr)); | |||||
printf("ARRAY_LOOKUP %08x\n", read_u4le(ops, ptr)); | |||||
return; | |||||
case L2_OP_ARRAY_LOOKUP_U1: | |||||
printf("ARRAY_LOOKUP %02x\n", read_u1le(ops, ptr)); | |||||
return; | return; | ||||
case L2_OP_ARRAY_SET: | |||||
case L2_OP_ARRAY_SET_U4: | |||||
printf("ARRAY_SET %08x\n", read_u4le(ops, ptr)); | printf("ARRAY_SET %08x\n", read_u4le(ops, ptr)); | ||||
return; | return; | ||||
case L2_OP_ARRAY_SET_U1: | |||||
printf("ARRAY_SET %02x\n", read_u1le(ops, ptr)); | |||||
return; | |||||
case L2_OP_DYNAMIC_LOOKUP: | case L2_OP_DYNAMIC_LOOKUP: | ||||
printf("DYNAMIC_LOOKUP\n"); | printf("DYNAMIC_LOOKUP\n"); |
return ret; | return ret; | ||||
} | } | ||||
static l2_word read_u1le(struct l2_vm *vm) { | |||||
return vm->ops[vm->iptr++]; | |||||
} | |||||
static double read_d8le(struct l2_vm *vm) { | static double read_d8le(struct l2_vm *vm) { | ||||
unsigned char *data = &vm->ops[vm->iptr]; | unsigned char *data = &vm->ops[vm->iptr]; | ||||
uint64_t integer = 0 | | uint64_t integer = 0 | | ||||
vm->sptr -= 1; | vm->sptr -= 1; | ||||
break; | break; | ||||
case L2_OP_FUNC_CALL_U4: | |||||
{ | |||||
l2_word argc = read_u4le(vm); | |||||
vm->sptr -= argc; | |||||
l2_word *argv = vm->stack + vm->sptr; | |||||
l2_word func_id = vm->stack[--vm->sptr]; | |||||
call_func(vm, func_id, argc, argv); | |||||
} | |||||
break; | |||||
#define X(read) \ | |||||
l2_word argc = read(vm); \ | |||||
vm->sptr -= argc; \ | |||||
l2_word *argv = vm->stack + vm->sptr; \ | |||||
l2_word func_id = vm->stack[--vm->sptr]; \ | |||||
call_func(vm, func_id, argc, argv) | |||||
case L2_OP_FUNC_CALL_U4: { X(read_u4le); } break; | |||||
case L2_OP_FUNC_CALL_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_RJMP_U4: | |||||
vm->iptr += read_u4le(vm) + 1; | |||||
break; | |||||
#define X(read) word = read(vm); vm->iptr += word; | |||||
case L2_OP_RJMP_U4: { X(read_u4le); } break; | |||||
case L2_OP_RJMP_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_STACK_FRAME_LOOKUP_U4: | |||||
{ | |||||
l2_word key = read_u4le(vm); | |||||
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; | |||||
vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, ns, key); | |||||
} | |||||
break; | |||||
#define X(read) \ | |||||
l2_word key = read(vm); \ | |||||
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; \ | |||||
vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, ns, key); | |||||
case L2_OP_STACK_FRAME_LOOKUP_U4: { X(read_u4le); } break; | |||||
case L2_OP_STACK_FRAME_LOOKUP_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_STACK_FRAME_SET_U4: | |||||
{ | |||||
l2_word key = read_u4le(vm); | |||||
l2_word val = vm->stack[vm->sptr - 1]; | |||||
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; | |||||
l2_vm_namespace_set(ns, key, val); | |||||
} | |||||
break; | |||||
#define X(read) \ | |||||
l2_word key = read(vm); \ | |||||
l2_word val = vm->stack[vm->sptr - 1]; \ | |||||
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; \ | |||||
l2_vm_namespace_set(ns, key, val); | |||||
case L2_OP_STACK_FRAME_SET_U4: { X(read_u4le); } break; | |||||
case L2_OP_STACK_FRAME_SET_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_STACK_FRAME_REPLACE_U4: | |||||
{ | |||||
l2_word key = read_u4le(vm); | |||||
l2_word val = vm->stack[vm->sptr - 1]; | |||||
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; | |||||
l2_vm_namespace_replace(vm, ns, key, val); // TODO: error if returns -1 | |||||
} | |||||
break; | |||||
#define X(read) \ | |||||
l2_word key = read(vm); \ | |||||
l2_word val = vm->stack[vm->sptr - 1]; \ | |||||
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; \ | |||||
l2_vm_namespace_replace(vm, ns, key, val); // TODO: error if returns -1 | |||||
case L2_OP_STACK_FRAME_REPLACE_U4: { X(read_u4le); } break; | |||||
case L2_OP_STACK_FRAME_REPLACE_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_RET: | case L2_OP_RET: | ||||
{ | { | ||||
vm->stack[vm->sptr++] = 0; | vm->stack[vm->sptr++] = 0; | ||||
break; | break; | ||||
case L2_OP_ALLOC_ATOM_U4: | |||||
word = alloc_val(vm); | |||||
vm->values[word].flags = L2_VAL_TYPE_ATOM; | |||||
vm->values[word].atom = read_u4le(vm); | |||||
#define X(read) \ | |||||
word = alloc_val(vm); \ | |||||
vm->values[word].flags = L2_VAL_TYPE_ATOM; \ | |||||
vm->values[word].atom = read(vm); \ | |||||
vm->stack[vm->sptr++] = word; | vm->stack[vm->sptr++] = word; | ||||
break; | |||||
case L2_OP_ALLOC_ATOM_U4: { X(read_u4le); } break; | |||||
case L2_OP_ALLOC_ATOM_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_ALLOC_REAL_D8: | case L2_OP_ALLOC_REAL_D8: | ||||
{ | { | ||||
} | } | ||||
break; | break; | ||||
case L2_OP_ALLOC_BUFFER_STATIC_U4: | |||||
{ | |||||
word = alloc_val(vm); | |||||
l2_word length = read_u4le(vm); | |||||
l2_word offset = read_u4le(vm); | |||||
vm->values[word].flags = L2_VAL_TYPE_BUFFER; | |||||
vm->values[word].buffer = malloc(sizeof(struct l2_vm_buffer) + length); | |||||
vm->values[word].buffer->len = length; | |||||
memcpy( | |||||
(unsigned char *)vm->values[word].buffer + sizeof(struct l2_vm_buffer), | |||||
vm->ops + offset, length); | |||||
vm->stack[vm->sptr] = word; | |||||
vm->sptr += 1; | |||||
} | |||||
break; | |||||
case L2_OP_ALLOC_ARRAY_U4: | |||||
{ | |||||
l2_word count = read_u4le(vm); | |||||
l2_word arr_id = alloc_val(vm); | |||||
struct l2_vm_value *arr = &vm->values[arr_id]; | |||||
arr->flags = L2_VAL_TYPE_ARRAY; | |||||
if (count == 0) { | |||||
arr->array = NULL; | |||||
vm->stack[vm->sptr++] = arr_id; | |||||
break; | |||||
} | |||||
arr->array = malloc(sizeof(struct l2_vm_array) + count * sizeof(l2_word)); | |||||
arr->array->len = count; | |||||
arr->array->size = count; | |||||
for (l2_word i = 0; i < count; ++i) { | |||||
arr->array->data[count - 1 - i] = vm->stack[--vm->sptr]; | |||||
} | |||||
#define X(read) \ | |||||
word = alloc_val(vm); \ | |||||
l2_word length = read(vm); \ | |||||
l2_word offset = read(vm); \ | |||||
vm->values[word].flags = L2_VAL_TYPE_BUFFER; \ | |||||
vm->values[word].buffer = malloc(sizeof(struct l2_vm_buffer) + length); \ | |||||
vm->values[word].buffer->len = length; \ | |||||
memcpy( \ | |||||
(unsigned char *)vm->values[word].buffer + sizeof(struct l2_vm_buffer), \ | |||||
vm->ops + offset, length); \ | |||||
vm->stack[vm->sptr] = word; \ | |||||
vm->sptr += 1; | |||||
case L2_OP_ALLOC_BUFFER_STATIC_U4: { X(read_u4le); } break; | |||||
case L2_OP_ALLOC_BUFFER_STATIC_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
vm->stack[vm->sptr++] = arr_id; | |||||
} | |||||
break; | |||||
#define X(read) \ | |||||
l2_word count = read(vm); \ | |||||
l2_word arr_id = alloc_val(vm); \ | |||||
struct l2_vm_value *arr = &vm->values[arr_id]; \ | |||||
arr->flags = L2_VAL_TYPE_ARRAY; \ | |||||
if (count == 0) { \ | |||||
arr->array = NULL; \ | |||||
vm->stack[vm->sptr++] = arr_id; \ | |||||
break; \ | |||||
} \ | |||||
arr->array = malloc(sizeof(struct l2_vm_array) + count * sizeof(l2_word)); \ | |||||
arr->array->len = count; \ | |||||
arr->array->size = count; \ | |||||
for (l2_word i = 0; i < count; ++i) { \ | |||||
arr->array->data[count - 1 - i] = vm->stack[--vm->sptr]; \ | |||||
} \ | |||||
vm->stack[vm->sptr++] = arr_id; | |||||
case L2_OP_ALLOC_ARRAY_U4: { X(read_u4le); } break; | |||||
case L2_OP_ALLOC_ARRAY_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_ALLOC_NAMESPACE: | case L2_OP_ALLOC_NAMESPACE: | ||||
word = alloc_val(vm); | word = alloc_val(vm); | ||||
vm->sptr += 1; | vm->sptr += 1; | ||||
break; | break; | ||||
case L2_OP_ALLOC_FUNCTION_U4: | |||||
word = alloc_val(vm); | |||||
vm->values[word].flags = L2_VAL_TYPE_FUNCTION; | |||||
vm->values[word].func.pos = read_u4le(vm); | |||||
vm->values[word].func.ns = vm->fstack[vm->fsptr - 1].ns; | |||||
vm->stack[vm->sptr] = word; | |||||
#define X(read) \ | |||||
word = alloc_val(vm); \ | |||||
vm->values[word].flags = L2_VAL_TYPE_FUNCTION; \ | |||||
vm->values[word].func.pos = read(vm); \ | |||||
vm->values[word].func.ns = vm->fstack[vm->fsptr - 1].ns; \ | |||||
vm->stack[vm->sptr] = word; \ | |||||
vm->sptr += 1; | vm->sptr += 1; | ||||
break; | |||||
case L2_OP_ALLOC_FUNCTION_U4: { X(read_u4le); } break; | |||||
case L2_OP_ALLOC_FUNCTION_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_NAMESPACE_SET_U4: | |||||
{ | |||||
l2_word key = read_u4le(vm); | |||||
l2_word val = vm->stack[vm->sptr - 1]; | |||||
l2_word ns = vm->stack[vm->sptr - 2]; | |||||
l2_vm_namespace_set(&vm->values[ns], key, val); | |||||
} | |||||
break; | |||||
#define X(read) \ | |||||
l2_word key = read(vm); \ | |||||
l2_word val = vm->stack[vm->sptr - 1]; \ | |||||
l2_word ns = vm->stack[vm->sptr - 2]; \ | |||||
l2_vm_namespace_set(&vm->values[ns], key, val); | |||||
case L2_OP_NAMESPACE_SET_U4: { X(read_u4le); } break; | |||||
case L2_OP_NAMESPACE_SET_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_NAMESPACE_LOOKUP_U4: | |||||
{ | |||||
l2_word key = read_u4le(vm); | |||||
l2_word ns = vm->stack[--vm->sptr]; | |||||
vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, &vm->values[ns], key); | |||||
} | |||||
break; | |||||
#define X(read) \ | |||||
l2_word key = read(vm); \ | |||||
l2_word ns = vm->stack[--vm->sptr]; \ | |||||
vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, &vm->values[ns], key); | |||||
case L2_OP_NAMESPACE_LOOKUP_U4: { X(read_u4le); } break; | |||||
case L2_OP_NAMESPACE_LOOKUP_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_ARRAY_LOOKUP_U4: | |||||
{ | |||||
l2_word key = read_u4le(vm); | |||||
l2_word arr = vm->stack[--vm->sptr]; | |||||
// TODO: Error if out of bounds or incorrect type | |||||
vm->stack[vm->sptr++] = vm->values[arr].array->data[key]; | |||||
} | |||||
break; | |||||
#define X(read) \ | |||||
l2_word key = read(vm); \ | |||||
l2_word arr = vm->stack[--vm->sptr]; \ | |||||
/* TODO: Error if out of bounds or incorrect type */ \ | |||||
vm->stack[vm->sptr++] = vm->values[arr].array->data[key]; | |||||
case L2_OP_ARRAY_LOOKUP_U4: { X(read_u4le); } break; | |||||
case L2_OP_ARRAY_LOOKUP_U1: { X(read_u1le); } break; | |||||
#undef X | |||||
case L2_OP_ARRAY_SET: | |||||
{ | |||||
l2_word key = vm->ops[vm->iptr++]; | |||||
l2_word val = vm->stack[vm->sptr - 1]; | |||||
l2_word arr = vm->stack[vm->sptr - 2]; | |||||
// TODO: Error if out of bounds or incorrect type | |||||
vm->values[arr].array->data[key] = val; | |||||
} | |||||
break; | |||||
#define X(read) \ | |||||
l2_word key = read(vm); \ | |||||
l2_word val = vm->stack[vm->sptr - 1]; \ | |||||
l2_word arr = vm->stack[vm->sptr - 2]; \ | |||||
/* TODO: Error if out of bounds or incorrect type */ \ | |||||
vm->values[arr].array->data[key] = val; | |||||
case L2_OP_ARRAY_SET_U4: { X(read_u4le); } break; | |||||
case L2_OP_ARRAY_SET_U1: { X(read_u1le); } break; | |||||
case L2_OP_DYNAMIC_LOOKUP: | case L2_OP_DYNAMIC_LOOKUP: | ||||
{ | { |