| while (!vm->halted) { | while (!vm->halted) { | ||||
| size_t iptr = vm->iptr; | size_t iptr = vm->iptr; | ||||
| printf("\n======\n\n(%d) Will run instr: ", vm->iptr); | printf("\n======\n\n(%d) Will run instr: ", vm->iptr); | ||||
| l2_vm_print_op(vm->ops, vm->opcount, &iptr); | |||||
| l2_vm_print_op(vm->ops, vm->opslen, &iptr); | |||||
| if (fgets(buf, sizeof(buf), stdin) == NULL) { | if (fgets(buf, sizeof(buf), stdin) == NULL) { | ||||
| break; | break; | ||||
| } | } | ||||
| l2_vm_init(&vm, NULL, 0); | l2_vm_init(&vm, NULL, 0); | ||||
| } else if (w.len > 0) { | } else if (w.len > 0) { | ||||
| vm.ops = w.mem; | vm.ops = w.mem; | ||||
| vm.opcount = w.len / sizeof(l2_word); | |||||
| vm.opslen = w.len; | |||||
| while (vm.iptr < vm.opcount) { | |||||
| while (vm.iptr < vm.opslen) { | |||||
| l2_vm_step(&vm); | l2_vm_step(&vm); | ||||
| } | } | ||||
| } | } | ||||
| if (do_serialize_bytecode) { | if (do_serialize_bytecode) { | ||||
| l2_bc_serialize( | |||||
| outbc, bytecode_writer.mem, | |||||
| bytecode_writer.len / sizeof(l2_word)); | |||||
| l2_bc_serialize(outbc, bytecode_writer.mem, bytecode_writer.len); | |||||
| } | } | ||||
| if (do_print_bytecode || do_print_tokens || do_serialize_bytecode) { | if (do_print_bytecode || do_print_tokens || do_serialize_bytecode) { | ||||
| } | } | ||||
| struct l2_vm vm; | struct l2_vm vm; | ||||
| l2_vm_init(&vm, bytecode_writer.mem, bytecode_writer.len / sizeof(l2_word)); | |||||
| l2_vm_init(&vm, bytecode_writer.mem, bytecode_writer.len); | |||||
| if (do_step) { | if (do_step) { | ||||
| step_through(&vm); | step_through(&vm); |
| typedef uint32_t l2_word; | typedef uint32_t l2_word; | ||||
| #define l2_bytecode_version 1 | |||||
| #define l2_bytecode_version 2 | |||||
| enum l2_opcode { | enum l2_opcode { | ||||
| /* | /* | ||||
| L2_OP_ADD, | L2_OP_ADD, | ||||
| /* | /* | ||||
| * Call a function; func_call <argc> | |||||
| * Call a function; func_call <argc:u4> | |||||
| * Pop <argc> times | * Pop <argc> times | ||||
| * Pop <func> | * Pop <func> | ||||
| * Push array with args | * Push array with args | ||||
| * Call <func> | * Call <func> | ||||
| * (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, | |||||
| L2_OP_FUNC_CALL_U4, | |||||
| /* | /* | ||||
| * Call an infix function | * Call an infix function | ||||
| L2_OP_FUNC_CALL_INFIX, | L2_OP_FUNC_CALL_INFIX, | ||||
| /* | /* | ||||
| * Jump relative; rjmp <count> | |||||
| * Jump relative; rjmp <count:u4> | |||||
| * Jump <count> words forwards | * Jump <count> words forwards | ||||
| */ | */ | ||||
| L2_OP_RJMP, | |||||
| L2_OP_RJMP_U4, | |||||
| /* | /* | ||||
| * Look up a value from the current stack frame; stack_frame_lookup <key> | |||||
| * Look up a value from the current stack frame; stack_frame_lookup <key:u4> | |||||
| * Find <val> in stack frame using <key> | * Find <val> in stack frame using <key> | ||||
| * Push <val> | * Push <val> | ||||
| */ | */ | ||||
| L2_OP_STACK_FRAME_LOOKUP, | |||||
| L2_OP_STACK_FRAME_LOOKUP_U4, | |||||
| /* | /* | ||||
| * Set a value in the current stack frame; stack_frame_set <key> | |||||
| * Set a value in the current stack frame; stack_frame_set <key:u4> | |||||
| * Read <val> | * Read <val> | ||||
| * Assign <val> to stack frame at <key> | * Assign <val> to stack frame at <key> | ||||
| */ | */ | ||||
| L2_OP_STACK_FRAME_SET, | |||||
| L2_OP_STACK_FRAME_SET_U4, | |||||
| /* | /* | ||||
| * Replace a value on the stack; stack_frame_replace <key> | |||||
| * Replace a value on the stack; stack_frame_replace <key:U4> | |||||
| * Read <val> | * Read <val> | ||||
| * Assign <val> to stack frame at <key> | * Assign <val> to stack frame at <key> | ||||
| */ | */ | ||||
| L2_OP_STACK_FRAME_REPLACE, | |||||
| L2_OP_STACK_FRAME_REPLACE_U4, | |||||
| /* | /* | ||||
| * 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> | |||||
| * Allocate an atom from one word; alloc_atom <word:u4> | |||||
| * Alloc atom <var> from <word> | * Alloc atom <var> from <word> | ||||
| * Push <var> | * Push <var> | ||||
| */ | */ | ||||
| L2_OP_ALLOC_ATOM, | |||||
| L2_OP_ALLOC_ATOM_U4, | |||||
| /* | /* | ||||
| * Allocate a real from two words; alloc_real <high> <low> | |||||
| * Alloc real <var> from <high> << 32 | <low> | |||||
| * Allocate a real from two words; alloc_real <double:u8> | |||||
| * Alloc real <var> from <double> | |||||
| * Push <var> | * Push <var> | ||||
| */ | */ | ||||
| L2_OP_ALLOC_REAL, | |||||
| L2_OP_ALLOC_REAL_D8, | |||||
| /* | /* | ||||
| * Allocate a buffer from static data; alloc_buffer_static <length> <offset> | |||||
| * Allocate a buffer from static data; alloc_buffer_static <length:u4> <offset:u4> | |||||
| * Alloc buffer <var> with <length> and <offset> | * Alloc buffer <var> with <length> and <offset> | ||||
| * Push <var> | * Push <var> | ||||
| */ | */ | ||||
| L2_OP_ALLOC_BUFFER_STATIC, | |||||
| L2_OP_ALLOC_BUFFER_STATIC_U4, | |||||
| /* | /* | ||||
| * Allocate an array; <count> | |||||
| * Allocate an array; <count:u4> | |||||
| * Pop <count> times | * Pop <count> times | ||||
| * Alloc array <var> | * Alloc array <var> | ||||
| * Push <var> | * Push <var> | ||||
| */ | */ | ||||
| L2_OP_ALLOC_ARRAY, | |||||
| L2_OP_ALLOC_ARRAY_U4, | |||||
| /* | /* | ||||
| * Allocate an integer->value map. | * Allocate an integer->value map. | ||||
| L2_OP_ALLOC_NAMESPACE, | L2_OP_ALLOC_NAMESPACE, | ||||
| /* | /* | ||||
| * Allocate a function; alloc_function <pos> | |||||
| * Allocate a function; alloc_function <pos:u4> | |||||
| * Alloc function <var> pointing to location <word> | * Alloc function <var> pointing to location <word> | ||||
| * Push <var> | * Push <var> | ||||
| */ | */ | ||||
| L2_OP_ALLOC_FUNCTION, | |||||
| L2_OP_ALLOC_FUNCTION_U4, | |||||
| /* | /* | ||||
| * Set a namespace's name to a value; namespace_set <key> | |||||
| * Set a namespace's name to a value; namespace_set <key:u4> | |||||
| * Read <val> | * Read <val> | ||||
| * Read <ns> | * Read <ns> | ||||
| * Assign <val> to <ns[<key>]> | * Assign <val> to <ns[<key>]> | ||||
| */ | */ | ||||
| L2_OP_NAMESPACE_SET, | |||||
| L2_OP_NAMESPACE_SET_U4, | |||||
| /* | /* | ||||
| * Lookup a value from a namespace; namespace_lookup <key> | |||||
| * Lookup a value from a namespace; namespace_lookup <key:u4> | |||||
| * Pop <ns> | * Pop <ns> | ||||
| * Push <ns[<key>]> | * Push <ns[<key>]> | ||||
| */ | */ | ||||
| L2_OP_NAMESPACE_LOOKUP, | |||||
| L2_OP_NAMESPACE_LOOKUP_U4, | |||||
| /* | /* | ||||
| * Look up a value from an array; array_lookup <key> | |||||
| * Look up a value from an array; array_lookup <key:u4> | |||||
| * Pop <arr> | * Pop <arr> | ||||
| * Push <arr[<key>]> | * Push <arr[<key>]> | ||||
| */ | */ | ||||
| L2_OP_ARRAY_LOOKUP, | |||||
| L2_OP_ARRAY_LOOKUP_U4, | |||||
| /* | /* | ||||
| * Set a value in an array; array_set <key> | * Set a value in an array; array_set <key> |
| #include <stdio.h> | #include <stdio.h> | ||||
| int l2_bc_serialize(FILE *outf, l2_word *data, size_t len); | |||||
| int l2_bc_serialize(FILE *outf, unsigned char *data, size_t len); | |||||
| int l2_bc_load(FILE *inf, struct l2_io_writer *w); | int l2_bc_load(FILE *inf, struct l2_io_writer *w); | ||||
| #endif | #endif |
| void l2_vm_print_stack(struct l2_vm *vm); | void l2_vm_print_stack(struct l2_vm *vm); | ||||
| void l2_vm_print_fstack(struct l2_vm *vm); | void l2_vm_print_fstack(struct l2_vm *vm); | ||||
| void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr); | |||||
| void l2_vm_print_bytecode(l2_word *ops, size_t opcount); | |||||
| void l2_vm_print_op(unsigned char *ops, size_t opcount, size_t *ptr); | |||||
| void l2_vm_print_bytecode(unsigned char *ops, size_t opcount); | |||||
| #endif | #endif |
| struct l2_vm { | struct l2_vm { | ||||
| int halted; | int halted; | ||||
| int gc_scheduled; | int gc_scheduled; | ||||
| l2_word *ops; | |||||
| size_t opcount; | |||||
| unsigned char *ops; | |||||
| size_t opslen; | |||||
| l2_word iptr; | l2_word iptr; | ||||
| struct l2_io_writer *std_output; | struct l2_io_writer *std_output; | ||||
| l2_word gc_start; | l2_word gc_start; | ||||
| }; | }; | ||||
| void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount); | |||||
| void l2_vm_init(struct l2_vm *vm, unsigned char *ops, size_t opslen); | |||||
| l2_word l2_vm_alloc(struct l2_vm *vm, enum l2_value_type typ, enum l2_value_flags flags); | l2_word l2_vm_alloc(struct l2_vm *vm, enum l2_value_type typ, enum l2_value_flags flags); | ||||
| l2_word l2_vm_error(struct l2_vm *vm, const char *fmt, ...); | l2_word l2_vm_error(struct l2_vm *vm, const char *fmt, ...); | ||||
| l2_word l2_vm_type_error(struct l2_vm *vm, struct l2_vm_value *val); | l2_word l2_vm_type_error(struct l2_vm *vm, struct l2_vm_value *val); |
| #include "gen/gen.h" | #include "gen/gen.h" | ||||
| #include <string.h> | |||||
| #include "bytecode.h" | #include "bytecode.h" | ||||
| static void put(struct l2_generator *gen, l2_word word) { | |||||
| l2_bufio_put_n(&gen->writer, &word, sizeof(word)); | |||||
| static void put(struct l2_generator *gen, unsigned char ch) { | |||||
| l2_bufio_put(&gen->writer, ch); | |||||
| gen->pos += 1; | gen->pos += 1; | ||||
| } | } | ||||
| static void put_u4le(struct l2_generator *gen, l2_word word) { | |||||
| char data[4] = { | |||||
| (word >> 0) & 0xff, | |||||
| (word >> 8) & 0xff, | |||||
| (word >> 16) & 0xff, | |||||
| (word >> 24) & 0xff, | |||||
| }; | |||||
| l2_bufio_put_n(&gen->writer, data, 4); | |||||
| gen->pos += 4; | |||||
| } | |||||
| static void put_d8le(struct l2_generator *gen, double num) { | |||||
| uint64_t integer; | |||||
| memcpy(&integer, &num, 8); | |||||
| char data[8] = { | |||||
| (integer >> 0) & 0xff, | |||||
| (integer >> 8) & 0xff, | |||||
| (integer >> 16) & 0xff, | |||||
| (integer >> 24) & 0xff, | |||||
| (integer >> 32) & 0xff, | |||||
| (integer >> 40) & 0xff, | |||||
| (integer >> 48) & 0xff, | |||||
| (integer >> 56) & 0xff, | |||||
| }; | |||||
| l2_bufio_put_n(&gen->writer, data, 8); | |||||
| gen->pos += 8; | |||||
| } | |||||
| void l2_gen_init(struct l2_generator *gen, struct l2_io_writer *w) { | void l2_gen_init(struct l2_generator *gen, struct l2_io_writer *w) { | ||||
| l2_strset_init(&gen->atomset); | l2_strset_init(&gen->atomset); | ||||
| l2_strset_init(&gen->stringset); | l2_strset_init(&gen->stringset); | ||||
| } | } | ||||
| void l2_gen_rjmp(struct l2_generator *gen, l2_word len) { | void l2_gen_rjmp(struct l2_generator *gen, l2_word len) { | ||||
| put(gen, L2_OP_RJMP); | |||||
| put(gen, len); | |||||
| put(gen, L2_OP_RJMP_U4); | |||||
| put_u4le(gen, len); | |||||
| } | } | ||||
| void l2_gen_discard(struct l2_generator *gen) { | void l2_gen_discard(struct l2_generator *gen) { | ||||
| void l2_gen_number(struct l2_generator *gen, double num) { | void l2_gen_number(struct l2_generator *gen, double num) { | ||||
| uint64_t n; | uint64_t n; | ||||
| memcpy(&n, &num, sizeof(num)); | memcpy(&n, &num, sizeof(num)); | ||||
| put(gen, L2_OP_ALLOC_REAL); | |||||
| put(gen, n >> 32); | |||||
| put(gen, n); | |||||
| put(gen, L2_OP_ALLOC_REAL_D8); | |||||
| put_d8le(gen, num); | |||||
| } | } | ||||
| 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); | |||||
| put(gen, id); | |||||
| 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); | |||||
| put(gen, id); | |||||
| 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) { | ||||
| aligned += sizeof(l2_word) - (aligned % sizeof(l2_word)); | aligned += sizeof(l2_word) - (aligned % sizeof(l2_word)); | ||||
| } | } | ||||
| put(gen, L2_OP_RJMP); | |||||
| put(gen, aligned / sizeof(l2_word)); | |||||
| put(gen, L2_OP_RJMP_U4); | |||||
| put_u4le(gen, aligned / sizeof(l2_word)); | |||||
| l2_word pos = gen->pos; | l2_word pos = gen->pos; | ||||
| gen->pos += aligned / sizeof(l2_word); | gen->pos += aligned / sizeof(l2_word); | ||||
| 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); | |||||
| put(gen, len); | |||||
| put(gen, pos); | |||||
| 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); | |||||
| put(gen, s->length); | |||||
| put(gen, s->pos); | |||||
| 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); | |||||
| put(gen, s->length); | |||||
| put(gen, s->pos); | |||||
| 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); | |||||
| put(gen, pos); | |||||
| 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); | |||||
| put(gen, count); | |||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, number); | |||||
| 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) { | ||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, atom_id); | |||||
| 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); | |||||
| put(gen, argc); | |||||
| 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) { |
| #include <stdint.h> | #include <stdint.h> | ||||
| int l2_bc_serialize(FILE *outf, l2_word *data, size_t len) { | |||||
| int l2_bc_serialize(FILE *outf, unsigned char *data, size_t len) { | |||||
| char header[4] = { 0x1b, 0x6c, 0x32, 0x63 }; | char header[4] = { 0x1b, 0x6c, 0x32, 0x63 }; | ||||
| if (fwrite(header, 1, 4, outf) < 4) { | if (fwrite(header, 1, 4, outf) < 4) { | ||||
| fprintf(stderr, "Write error\n"); | fprintf(stderr, "Write error\n"); | ||||
| uint32_t version = l2_bytecode_version; | uint32_t version = l2_bytecode_version; | ||||
| unsigned char version_buf[4] = { | unsigned char version_buf[4] = { | ||||
| (version & 0xff000000ull) >> 24, | |||||
| (version & 0x00ff0000ull) >> 16, | |||||
| (version & 0x0000ff00ull) >> 8, | |||||
| (version & 0x000000ffull) >> 0, | |||||
| (version >> 0) & 0xff, | |||||
| (version >> 8) & 0xff, | |||||
| (version >> 16) & 0xff, | |||||
| (version >> 24) & 0xff, | |||||
| }; | }; | ||||
| if (fwrite(version_buf, 1, 4, outf) < 4) { | if (fwrite(version_buf, 1, 4, outf) < 4) { | ||||
| fprintf(stderr, "Write error\n"); | fprintf(stderr, "Write error\n"); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| struct l2_io_file_writer w = { | |||||
| .w.write = l2_io_file_write, | |||||
| .f = outf, | |||||
| }; | |||||
| struct l2_bufio_writer writer; | |||||
| l2_bufio_writer_init(&writer, &w.w); | |||||
| unsigned char word_buf[4]; | |||||
| for (size_t i = 0; i < len; ++i) { | |||||
| uint32_t word = data[i]; | |||||
| word_buf[0] = (word & 0xff000000ull) >> 24; | |||||
| word_buf[1] = (word & 0x00ff0000ull) >> 16; | |||||
| word_buf[2] = (word & 0x0000ff00ull) >> 8; | |||||
| word_buf[3] = (word & 0x000000ffull) >> 0; | |||||
| l2_bufio_put_n(&writer, word_buf, 4); | |||||
| if (fwrite(data, 1, len, outf) < len) { | |||||
| fprintf(stderr, "Write error\n"); | |||||
| return -1; | |||||
| } | } | ||||
| l2_bufio_flush(&writer); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| uint32_t version = 0 | | uint32_t version = 0 | | ||||
| ((uint32_t)version_buf[0]) << 24 | | |||||
| ((uint32_t)version_buf[1]) << 16 | | |||||
| ((uint32_t)version_buf[2]) << 8 | | |||||
| ((uint32_t)version_buf[3]) << 0; | |||||
| ((uint32_t)version_buf[0]) << 0 | | |||||
| ((uint32_t)version_buf[1]) << 8 | | |||||
| ((uint32_t)version_buf[2]) << 16 | | |||||
| ((uint32_t)version_buf[3]) << 24; | |||||
| if (version != l2_bytecode_version) { | if (version != l2_bytecode_version) { | ||||
| fprintf( | fprintf( | ||||
| stderr, "Version mismatch! Bytecode file uses bytecode version %i" | stderr, "Version mismatch! Bytecode file uses bytecode version %i" | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| struct l2_bufio_writer writer; | |||||
| l2_bufio_writer_init(&writer, w); | |||||
| // Must be divisible by 4 | // Must be divisible by 4 | ||||
| unsigned char buffer[4096]; | unsigned char buffer[4096]; | ||||
| while (1) { | while (1) { | ||||
| size_t n = fread(buffer, 1, sizeof(buffer), inf); | size_t n = fread(buffer, 1, sizeof(buffer), inf); | ||||
| if (n < 4) { | |||||
| l2_bufio_flush(&writer); | |||||
| if (n == 0) { | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| for (size_t i = 0; i < n; i += 4) { | |||||
| l2_word word = 0 | | |||||
| ((uint32_t)buffer[i + 0]) << 24 | | |||||
| ((uint32_t)buffer[i + 1]) << 16 | | |||||
| ((uint32_t)buffer[i + 2]) << 8 | | |||||
| ((uint32_t)buffer[i + 3]) << 0; | |||||
| l2_bufio_put_n(&writer, &word, 4); | |||||
| } | |||||
| w->write(w, buffer, n); | |||||
| } | } | ||||
| } | } |
| #include <string.h> | #include <string.h> | ||||
| #include <stdint.h> | #include <stdint.h> | ||||
| void l2_vm_print_val(struct l2_vm_value *val) { | |||||
| static l2_word read_u4le(unsigned char *ops, size_t *ptr) { | |||||
| unsigned char *data = &ops[*ptr]; | |||||
| l2_word ret = | |||||
| (l2_word)data[0] | | |||||
| (l2_word)data[1] << 8 | | |||||
| (l2_word)data[2] << 16 | | |||||
| (l2_word)data[3] << 24; | |||||
| *ptr += 4; | |||||
| return ret; | |||||
| } | |||||
| static double read_d8le(unsigned char *ops, size_t *ptr) { | |||||
| unsigned char *data = &ops[*ptr]; | |||||
| uint64_t integer = 0 | | |||||
| (uint64_t)data[0] | | |||||
| (uint64_t)data[1] << 8 | | |||||
| (uint64_t)data[2] << 16 | | |||||
| (uint64_t)data[3] << 24 | | |||||
| (uint64_t)data[4] << 32 | | |||||
| (uint64_t)data[5] << 40 | | |||||
| (uint64_t)data[6] << 48 | | |||||
| (uint64_t)data[7] << 56; | |||||
| double num; | |||||
| memcpy(&num, &integer, 8); | |||||
| *ptr += 8; | |||||
| return num; | |||||
| } | |||||
| void l2_vm_print_val(struct l2_vm_value *val) { | |||||
| switch (l2_vm_value_type(val)) { | switch (l2_vm_value_type(val)) { | ||||
| case L2_VAL_TYPE_NONE: | case L2_VAL_TYPE_NONE: | ||||
| printf("NONE\n"); | printf("NONE\n"); | ||||
| } | } | ||||
| } | } | ||||
| void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) { | |||||
| void l2_vm_print_op(unsigned char *ops, size_t opcount, size_t *ptr) { | |||||
| enum l2_opcode opcode = (enum l2_opcode)ops[(*ptr)++]; | enum l2_opcode opcode = (enum l2_opcode)ops[(*ptr)++]; | ||||
| switch (opcode) { | switch (opcode) { | ||||
| printf("ADD\n"); | printf("ADD\n"); | ||||
| return; | return; | ||||
| case L2_OP_FUNC_CALL: | |||||
| printf("FUNC_CALL %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_FUNC_CALL_U4: | |||||
| printf("FUNC_CALL %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_FUNC_CALL_INFIX: | case L2_OP_FUNC_CALL_INFIX: | ||||
| printf("FUNC_CALL_INFIX\n"); | printf("FUNC_CALL_INFIX\n"); | ||||
| return; | return; | ||||
| case L2_OP_RJMP: | |||||
| printf("RJMP %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_RJMP_U4: | |||||
| printf("RJMP %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_STACK_FRAME_LOOKUP: | |||||
| printf("STACK_FRAME_LOOKUP %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_STACK_FRAME_LOOKUP_U4: | |||||
| printf("STACK_FRAME_LOOKUP %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_STACK_FRAME_SET: | |||||
| printf("STACK_FRAME_SET %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_STACK_FRAME_SET_U4: | |||||
| printf("STACK_FRAME_SET %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_STACK_FRAME_REPLACE: | |||||
| printf("STACK_FRAME_REPLACE %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_STACK_FRAME_REPLACE_U4: | |||||
| printf("STACK_FRAME_REPLACE %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_RET: | case L2_OP_RET: | ||||
| printf("ALLOC_NONE\n"); | printf("ALLOC_NONE\n"); | ||||
| return; | return; | ||||
| case L2_OP_ALLOC_ATOM: | |||||
| printf("ALLOC_ATOM %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_ALLOC_ATOM_U4: | |||||
| printf("ALLOC_ATOM %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_ALLOC_REAL: | |||||
| { | |||||
| l2_word w1 = ops[(*ptr)++]; | |||||
| l2_word w2 = ops[(*ptr)++]; | |||||
| printf("ALLOC_REAL %08x %08x\n", w1, w2); | |||||
| } | |||||
| case L2_OP_ALLOC_REAL_D8: | |||||
| printf("ALLOC_REAL %f\n", read_d8le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_ALLOC_BUFFER_STATIC: | |||||
| case L2_OP_ALLOC_BUFFER_STATIC_U4: | |||||
| { | { | ||||
| l2_word w1 = ops[(*ptr)++]; | |||||
| l2_word w2 = ops[(*ptr)++]; | |||||
| l2_word w1 = read_u4le(ops, ptr); | |||||
| l2_word w2 = read_u4le(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_ARRAY: | |||||
| printf("ALLOC_ARRAY %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_ALLOC_ARRAY_U4: | |||||
| printf("ALLOC_ARRAY_U4 %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_ALLOC_NAMESPACE: | case L2_OP_ALLOC_NAMESPACE: | ||||
| printf("ALLOC_NAMESPACE\n"); | printf("ALLOC_NAMESPACE\n"); | ||||
| return; | return; | ||||
| case L2_OP_ALLOC_FUNCTION: | |||||
| printf("ALLOC_FUNCTION %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_ALLOC_FUNCTION_U4: | |||||
| printf("ALLOC_FUNCTION_U4 %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_NAMESPACE_SET: | |||||
| printf("NAMESPACE_SET %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_NAMESPACE_SET_U4: | |||||
| printf("NAMESPACE_SET_U4 %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_NAMESPACE_LOOKUP: | |||||
| printf("NAMESPACE_LOOKUP %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_NAMESPACE_LOOKUP_U4: | |||||
| printf("NAMESPACE_LOOKUP_U4 %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_ARRAY_LOOKUP: | |||||
| printf("ARRAY_LOOKUP %08x\n", ops[(*ptr)++]); | |||||
| case L2_OP_ARRAY_LOOKUP_U4: | |||||
| printf("ARRAY_LOOKUP_U4 %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_ARRAY_SET: | case L2_OP_ARRAY_SET: | ||||
| printf("ARRAY_SET %08x\n", ops[(*ptr)++]); | |||||
| printf("ARRAY_SET %08x\n", read_u4le(ops, ptr)); | |||||
| return; | return; | ||||
| case L2_OP_DYNAMIC_LOOKUP: | case L2_OP_DYNAMIC_LOOKUP: | ||||
| printf("\n"); | printf("\n"); | ||||
| } | } | ||||
| void l2_vm_print_bytecode(l2_word *ops, size_t opcount) { | |||||
| void l2_vm_print_bytecode(unsigned char *ops, size_t opcount) { | |||||
| size_t ptr = 0; | size_t ptr = 0; | ||||
| while (ptr < opcount) { | while (ptr < opcount) { | ||||
| printf("%04zu ", ptr); | printf("%04zu ", ptr); |
| return (l2_word)id; | return (l2_word)id; | ||||
| } | } | ||||
| static double u32s_to_double(uint32_t high, uint32_t low) { | |||||
| double d; | |||||
| uint64_t num = (uint64_t)high << 32 | (uint64_t)low; | |||||
| memcpy(&d, &num, sizeof(num)); | |||||
| return d; | |||||
| } | |||||
| static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val); | static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val); | ||||
| static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val); | static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val); | ||||
| return "(unknown)"; | return "(unknown)"; | ||||
| } | } | ||||
| void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) { | |||||
| void l2_vm_init(struct l2_vm *vm, unsigned char *ops, size_t opslen) { | |||||
| if (!stdio_inited) { | if (!stdio_inited) { | ||||
| std_output.w.write = l2_io_file_write; | std_output.w.write = l2_io_file_write; | ||||
| std_output.f = stdout; | std_output.f = stdout; | ||||
| vm->halted = 0; | vm->halted = 0; | ||||
| vm->gc_scheduled = 0; | vm->gc_scheduled = 0; | ||||
| vm->ops = ops; | vm->ops = ops; | ||||
| vm->opcount = opcount; | |||||
| vm->opslen = opslen; | |||||
| vm->iptr = 0; | vm->iptr = 0; | ||||
| vm->sptr = 0; | vm->sptr = 0; | ||||
| vm->fsptr = 0; | vm->fsptr = 0; | ||||
| vm->iptr = func->func.pos; | vm->iptr = func->func.pos; | ||||
| } | } | ||||
| static l2_word read_u4le(struct l2_vm *vm) { | |||||
| unsigned char *data = &vm->ops[vm->iptr]; | |||||
| l2_word ret = | |||||
| (l2_word)data[0] | | |||||
| (l2_word)data[1] << 8 | | |||||
| (l2_word)data[2] << 16 | | |||||
| (l2_word)data[3] << 24; | |||||
| vm->iptr += 4; | |||||
| return ret; | |||||
| } | |||||
| static double read_d8le(struct l2_vm *vm) { | |||||
| unsigned char *data = &vm->ops[vm->iptr]; | |||||
| uint64_t integer = 0 | | |||||
| (uint64_t)data[0] | | |||||
| (uint64_t)data[1] << 8 | | |||||
| (uint64_t)data[2] << 16 | | |||||
| (uint64_t)data[3] << 24 | | |||||
| (uint64_t)data[4] << 32 | | |||||
| (uint64_t)data[5] << 40 | | |||||
| (uint64_t)data[6] << 48 | | |||||
| (uint64_t)data[7] << 56; | |||||
| double num; | |||||
| memcpy(&num, &integer, 8); | |||||
| vm->iptr += 8; | |||||
| return num; | |||||
| } | |||||
| void l2_vm_step(struct l2_vm *vm) { | void l2_vm_step(struct l2_vm *vm) { | ||||
| enum l2_opcode opcode = (enum l2_opcode)vm->ops[vm->iptr++]; | enum l2_opcode opcode = (enum l2_opcode)vm->ops[vm->iptr++]; | ||||
| vm->sptr -= 1; | vm->sptr -= 1; | ||||
| break; | break; | ||||
| case L2_OP_FUNC_CALL: | |||||
| case L2_OP_FUNC_CALL_U4: | |||||
| { | { | ||||
| l2_word argc = vm->ops[vm->iptr++]; | |||||
| l2_word argc = read_u4le(vm); | |||||
| vm->sptr -= argc; | vm->sptr -= argc; | ||||
| l2_word *argv = vm->stack + vm->sptr; | l2_word *argv = vm->stack + vm->sptr; | ||||
| } | } | ||||
| break; | break; | ||||
| case L2_OP_RJMP: | |||||
| vm->iptr += vm->ops[vm->iptr] + 1; | |||||
| case L2_OP_RJMP_U4: | |||||
| vm->iptr += read_u4le(vm) + 1; | |||||
| break; | break; | ||||
| case L2_OP_STACK_FRAME_LOOKUP: | |||||
| case L2_OP_STACK_FRAME_LOOKUP_U4: | |||||
| { | { | ||||
| l2_word key = vm->ops[vm->iptr++]; | |||||
| l2_word key = read_u4le(vm); | |||||
| struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; | struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; | ||||
| vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, ns, key); | vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, ns, key); | ||||
| } | } | ||||
| break; | break; | ||||
| case L2_OP_STACK_FRAME_SET: | |||||
| case L2_OP_STACK_FRAME_SET_U4: | |||||
| { | { | ||||
| l2_word key = vm->ops[vm->iptr++]; | |||||
| l2_word key = read_u4le(vm); | |||||
| l2_word val = vm->stack[vm->sptr - 1]; | l2_word val = vm->stack[vm->sptr - 1]; | ||||
| struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; | struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; | ||||
| l2_vm_namespace_set(ns, key, val); | l2_vm_namespace_set(ns, key, val); | ||||
| } | } | ||||
| break; | break; | ||||
| case L2_OP_STACK_FRAME_REPLACE: | |||||
| case L2_OP_STACK_FRAME_REPLACE_U4: | |||||
| { | { | ||||
| l2_word key = vm->ops[vm->iptr++]; | |||||
| l2_word key = read_u4le(vm); | |||||
| l2_word val = vm->stack[vm->sptr - 1]; | l2_word val = vm->stack[vm->sptr - 1]; | ||||
| struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; | 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 | l2_vm_namespace_replace(vm, ns, key, val); // TODO: error if returns -1 | ||||
| vm->stack[vm->sptr++] = 0; | vm->stack[vm->sptr++] = 0; | ||||
| break; | break; | ||||
| case L2_OP_ALLOC_ATOM: | |||||
| case L2_OP_ALLOC_ATOM_U4: | |||||
| word = alloc_val(vm); | word = alloc_val(vm); | ||||
| vm->values[word].flags = L2_VAL_TYPE_ATOM; | vm->values[word].flags = L2_VAL_TYPE_ATOM; | ||||
| vm->values[word].atom = vm->ops[vm->iptr++]; | |||||
| vm->values[word].atom = read_u4le(vm); | |||||
| vm->stack[vm->sptr++] = word; | vm->stack[vm->sptr++] = word; | ||||
| break; | break; | ||||
| case L2_OP_ALLOC_REAL: | |||||
| case L2_OP_ALLOC_REAL_D8: | |||||
| { | { | ||||
| word = alloc_val(vm); | word = alloc_val(vm); | ||||
| l2_word high = vm->ops[vm->iptr++]; | |||||
| l2_word low = vm->ops[vm->iptr++]; | |||||
| vm->values[word].flags = L2_VAL_TYPE_REAL; | vm->values[word].flags = L2_VAL_TYPE_REAL; | ||||
| vm->values[word].real = u32s_to_double(high, low); | |||||
| vm->values[word].real = read_d8le(vm); | |||||
| vm->stack[vm->sptr++] = word; | vm->stack[vm->sptr++] = word; | ||||
| } | } | ||||
| break; | break; | ||||
| case L2_OP_ALLOC_BUFFER_STATIC: | |||||
| case L2_OP_ALLOC_BUFFER_STATIC_U4: | |||||
| { | { | ||||
| word = alloc_val(vm); | word = alloc_val(vm); | ||||
| l2_word length = vm->ops[vm->iptr++]; | |||||
| l2_word offset = vm->ops[vm->iptr++]; | |||||
| l2_word length = read_u4le(vm); | |||||
| l2_word offset = read_u4le(vm); | |||||
| vm->values[word].flags = L2_VAL_TYPE_BUFFER; | vm->values[word].flags = L2_VAL_TYPE_BUFFER; | ||||
| vm->values[word].buffer = malloc(sizeof(struct l2_vm_buffer) + length); | vm->values[word].buffer = malloc(sizeof(struct l2_vm_buffer) + length); | ||||
| vm->values[word].buffer->len = length; | vm->values[word].buffer->len = length; | ||||
| } | } | ||||
| break; | break; | ||||
| case L2_OP_ALLOC_ARRAY: | |||||
| case L2_OP_ALLOC_ARRAY_U4: | |||||
| { | { | ||||
| l2_word count = vm->ops[vm->iptr++]; | |||||
| l2_word count = read_u4le(vm); | |||||
| l2_word arr_id = alloc_val(vm); | l2_word arr_id = alloc_val(vm); | ||||
| struct l2_vm_value *arr = &vm->values[arr_id]; | struct l2_vm_value *arr = &vm->values[arr_id]; | ||||
| arr->flags = L2_VAL_TYPE_ARRAY; | arr->flags = L2_VAL_TYPE_ARRAY; | ||||
| vm->sptr += 1; | vm->sptr += 1; | ||||
| break; | break; | ||||
| case L2_OP_ALLOC_FUNCTION: | |||||
| case L2_OP_ALLOC_FUNCTION_U4: | |||||
| word = alloc_val(vm); | word = alloc_val(vm); | ||||
| vm->values[word].flags = L2_VAL_TYPE_FUNCTION; | vm->values[word].flags = L2_VAL_TYPE_FUNCTION; | ||||
| vm->values[word].func.pos = vm->ops[vm->iptr++]; | |||||
| vm->values[word].func.pos = read_u4le(vm); | |||||
| vm->values[word].func.ns = vm->fstack[vm->fsptr - 1].ns; | vm->values[word].func.ns = vm->fstack[vm->fsptr - 1].ns; | ||||
| vm->stack[vm->sptr] = word; | vm->stack[vm->sptr] = word; | ||||
| vm->sptr += 1; | vm->sptr += 1; | ||||
| break; | break; | ||||
| case L2_OP_NAMESPACE_SET: | |||||
| case L2_OP_NAMESPACE_SET_U4: | |||||
| { | { | ||||
| l2_word key = vm->ops[vm->iptr++]; | |||||
| l2_word key = read_u4le(vm); | |||||
| l2_word val = vm->stack[vm->sptr - 1]; | l2_word val = vm->stack[vm->sptr - 1]; | ||||
| l2_word ns = vm->stack[vm->sptr - 2]; | l2_word ns = vm->stack[vm->sptr - 2]; | ||||
| l2_vm_namespace_set(&vm->values[ns], key, val); | l2_vm_namespace_set(&vm->values[ns], key, val); | ||||
| } | } | ||||
| break; | break; | ||||
| case L2_OP_NAMESPACE_LOOKUP: | |||||
| case L2_OP_NAMESPACE_LOOKUP_U4: | |||||
| { | { | ||||
| l2_word key = vm->ops[vm->iptr++]; | |||||
| l2_word key = read_u4le(vm); | |||||
| l2_word ns = vm->stack[--vm->sptr]; | l2_word ns = vm->stack[--vm->sptr]; | ||||
| vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, &vm->values[ns], key); | vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, &vm->values[ns], key); | ||||
| } | } | ||||
| break; | break; | ||||
| case L2_OP_ARRAY_LOOKUP: | |||||
| case L2_OP_ARRAY_LOOKUP_U4: | |||||
| { | { | ||||
| l2_word key = vm->ops[vm->iptr++]; | |||||
| l2_word key = read_u4le(vm); | |||||
| l2_word arr = vm->stack[--vm->sptr]; | l2_word arr = vm->stack[--vm->sptr]; | ||||
| // TODO: Error if out of bounds or incorrect type | // TODO: Error if out of bounds or incorrect type | ||||
| vm->stack[vm->sptr++] = vm->values[arr].array->data[key]; | vm->stack[vm->sptr++] = vm->values[arr].array->data[key]; |