1
0
Fork 0
forked from fun/fun

Refactored all OP_ functions to vm/CATEGORY/ and renamed the files.

This commit is contained in:
Johannes Findeisen 2025-09-15 23:26:42 +02:00
commit 50a91d0b6f
67 changed files with 91 additions and 92 deletions

View file

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(fun VERSION 0.2.1 LANGUAGES C) project(fun VERSION 0.2.2 LANGUAGES C)
set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)

0
examples/objects_more.fun Normal file → Executable file
View file

135
src/vm.c
View file

@ -193,69 +193,78 @@ void vm_run(VM *vm, Bytecode *entry) {
switch (inst.op) { switch (inst.op) {
/* All opcode handlers as .c includes */ /* All opcode handlers as .c includes */
#include "vm_cases/core/vm_case_nop.c" #include "vm/arithmetic/add.c"
#include "vm_cases/core/vm_case_load_const.c" #include "vm/arithmetic/div.c"
#include "vm_cases/core/vm_case_load_local.c" #include "vm/arithmetic/mul.c"
#include "vm_cases/core/vm_case_store_local.c" #include "vm/arithmetic/sub.c"
#include "vm_cases/arithmetic/vm_case_add.c"
#include "vm_cases/arithmetic/vm_case_sub.c" #include "vm/arrays/arr_insert.c"
#include "vm_case_mul.c" #include "vm/arrays/arr_pop.c"
#include "vm_case_div.c" #include "vm/arrays/arr_push.c"
#include "vm_case_lt.c" #include "vm/arrays/arr_remove.c"
#include "vm_case_lte.c" #include "vm/arrays/arr_set.c"
#include "vm_cases/core/vm_case_jump.c" #include "vm/arrays/clear.c"
#include "vm_case_gt.c" #include "vm/arrays/contains.c"
#include "vm_case_gte.c" #include "vm/arrays/enumerate.c"
#include "vm_cases/logic/vm_case_eq.c" #include "vm/arrays/index_get.c"
#include "vm_case_neq.c" #include "vm/arrays/index_of.c"
#include "vm_cases/core/vm_case_jump_if_false.c" #include "vm/arrays/index_set.c"
#include "vm_case_call.c" #include "vm/arrays/join.c"
#include "vm_case_return.c" #include "vm/arrays/make_array.c"
#include "vm_case_print.c" #include "vm/arrays/slice.c"
#include "vm_cases/core/vm_case_halt.c" #include "vm/arrays/zip.c"
#include "vm_case_pop.c"
#include "vm_case_dup.c" #include "vm/core/call.c"
#include "vm_case_swap.c" #include "vm/core/dup.c"
#include "vm_case_make_array.c" #include "vm/core/halt.c"
#include "vm_case_index_get.c" #include "vm/core/jump.c"
#include "vm_case_index_set.c" #include "vm/core/jump_if_false.c"
#include "vm_case_len.c" #include "vm/core/load_const.c"
#include "vm_case_arr_push.c" #include "vm/core/load_global.c"
#include "vm_case_arr_pop.c" #include "vm/core/load_local.c"
#include "vm_case_arr_set.c" #include "vm/core/nop.c"
#include "vm_case_arr_insert.c" #include "vm/core/pop.c"
#include "vm_case_arr_remove.c" #include "vm/core/return.c"
#include "vm_case_slice.c" #include "vm/core/store_global.c"
#include "vm_case_to_number.c" #include "vm/core/store_local.c"
#include "vm_case_to_string.c" #include "vm/core/swap.c"
#include "vm_case_split.c"
#include "vm_case_join.c" #include "vm/io/read_file.c"
#include "vm_case_substr.c" #include "vm/io/write_file.c"
#include "vm_case_find.c"
#include "vm_case_contains.c" #include "vm/logic/and.c"
#include "vm_case_index_of.c" #include "vm/logic/eq.c"
#include "vm_case_clear.c" #include "vm/logic/gt.c"
#include "vm_case_enumerate.c" #include "vm/logic/gte.c"
#include "vm_case_zip.c" #include "vm/logic/lt.c"
#include "vm_case_min.c" #include "vm/logic/lte.c"
#include "vm_case_max.c" #include "vm/logic/neq.c"
#include "vm_case_clamp.c" #include "vm/logic/not.c"
#include "vm_case_abs.c" #include "vm/logic/or.c"
#include "vm_case_pow.c"
#include "vm_case_random_seed.c" #include "vm/maps/has_key.c"
#include "vm_case_random_int.c" #include "vm/maps/keys.c"
#include "vm_case_make_map.c" #include "vm/maps/make_map.c"
#include "vm_case_keys.c" #include "vm/maps/values.c"
#include "vm_case_values.c"
#include "vm_case_has_key.c" #include "vm/math/abs.c"
#include "vm_case_read_file.c" #include "vm/math/clamp.c"
#include "vm_case_write_file.c" #include "vm/math/max.c"
#include "vm_case_load_global.c" #include "vm/math/min.c"
#include "vm_case_store_global.c" #include "vm/math/mod.c"
#include "vm_case_mod.c" #include "vm/math/pow.c"
#include "vm_case_and.c" #include "vm/math/random_int.c"
#include "vm_case_or.c" #include "vm/math/random_seed.c"
#include "vm_case_not.c"
#include "vm/strings/find.c"
#include "vm/strings/split.c"
#include "vm/strings/substr.c"
#include "vm/len.c"
#include "vm/print.c"
#include "vm/to_number.c"
#include "vm/to_string.c"
default: default:
if (!opcode_is_valid(inst.op)) { if (!opcode_is_valid(inst.op)) {
fprintf(stderr, "Runtime error: unknown opcode %d (%s) at instruction %d\n", fprintf(stderr, "Runtime error: unknown opcode %d (%s) at instruction %d\n",

View file

@ -18,7 +18,6 @@ case OP_INDEX_GET: {
if (idx.type != VAL_STRING) { fprintf(stderr, "INDEX_GET key must be string for map\n"); exit(1); } if (idx.type != VAL_STRING) { fprintf(stderr, "INDEX_GET key must be string for map\n"); exit(1); }
Value out; Value out;
if (!map_get_copy(&container, idx.s ? idx.s : "", &out)) { if (!map_get_copy(&container, idx.s ? idx.s : "", &out)) {
/* missing -> nil */
out = make_nil(); out = make_nil();
} }
free_value(container); free_value(container);

View file

@ -11,7 +11,6 @@ case OP_INDEX_SET: {
if (!array_set(&container, (int)idx.i, v)) { if (!array_set(&container, (int)idx.i, v)) {
fprintf(stderr, "Runtime error: index out of range\n"); exit(1); fprintf(stderr, "Runtime error: index out of range\n"); exit(1);
} }
/* v moved into array */
free_value(container); free_value(container);
free_value(idx); free_value(idx);
} else if (container.type == VAL_MAP) { } else if (container.type == VAL_MAP) {

View file

@ -4,6 +4,6 @@ case OP_POP: {
exit(1); exit(1);
} }
Value v = pop_value(vm); Value v = pop_value(vm);
free_value(v); // free the popped value free_value(v);
break; break;
} }

8
src/vm/core/return.c Normal file
View file

@ -0,0 +1,8 @@
case OP_RETURN: {
Value retv;
if (vm->sp >= 0) retv = pop_value(vm);
else retv = make_nil();
vm_pop_frame(vm);
push_value(vm, retv);
break;
}

View file

@ -10,7 +10,6 @@ case OP_MAKE_MAP: {
fprintf(stderr, "Map literal set failed\n"); exit(1); fprintf(stderr, "Map literal set failed\n"); exit(1);
} }
free_value(key); free_value(key);
/* val ownership moved */
} }
push_value(vm, m); push_value(vm, m);
break; break;

View file

@ -2,11 +2,16 @@ case OP_CLAMP: {
Value hi = pop_value(vm); Value hi = pop_value(vm);
Value lo = pop_value(vm); Value lo = pop_value(vm);
Value x = pop_value(vm); Value x = pop_value(vm);
if (x.type != VAL_INT || lo.type != VAL_INT || hi.type != VAL_INT) { fprintf(stderr, "CLAMP expects ints\n"); exit(1); } if (x.type != VAL_INT || lo.type != VAL_INT || hi.type != VAL_INT) {
fprintf(stderr, "CLAMP expects ints\n");
exit(1);
}
int64_t v = x.i; int64_t v = x.i;
if (v < lo.i) v = lo.i; if (v < lo.i) v = lo.i;
if (v > hi.i) v = hi.i; if (v > hi.i) v = hi.i;
push_value(vm, make_int(v)); push_value(vm, make_int(v));
free_value(x); free_value(lo); free_value(hi); free_value(x);
free_value(lo);
free_value(hi);
break; break;
} }

View file

@ -2,7 +2,6 @@ case OP_POW: {
Value b = pop_value(vm); Value b = pop_value(vm);
Value a = pop_value(vm); Value a = pop_value(vm);
if (a.type != VAL_INT || b.type != VAL_INT) { fprintf(stderr, "POW expects ints\n"); exit(1); } if (a.type != VAL_INT || b.type != VAL_INT) { fprintf(stderr, "POW expects ints\n"); exit(1); }
/* simple integer pow */
int64_t base = a.i; int64_t base = a.i;
int64_t exp = b.i; int64_t exp = b.i;
int64_t res = 1; int64_t res = 1;

View file

@ -1,12 +1,11 @@
case OP_PRINT: { case OP_PRINT: {
Value v = pop_value(vm); Value v = pop_value(vm);
/* snapshot value at print time (deep copy arrays) */
Value snap = deep_copy_value(&v); Value snap = deep_copy_value(&v);
free_value(v); free_value(v);
if (vm->output_count < VM_OUTPUT_SIZE) { if (vm->output_count < VM_OUTPUT_SIZE) {
vm->output[vm->output_count++] = snap; // store snapshot vm->output[vm->output_count++] = snap;
} else { } else {
free_value(snap); // prevent leak free_value(snap);
fprintf(stderr, "Runtime error: output buffer overflow\n"); fprintf(stderr, "Runtime error: output buffer overflow\n");
exit(1); exit(1);
} }

View file

@ -1,28 +1,23 @@
case OP_TO_NUMBER: { case OP_TO_NUMBER: {
Value v = pop_value(vm); Value v = pop_value(vm);
if (v.type == VAL_INT) { if (v.type == VAL_INT) {
/* pass-through */
Value out = make_int(v.i); Value out = make_int(v.i);
free_value(v); free_value(v);
push_value(vm, out); push_value(vm, out);
} else if (v.type == VAL_STRING) { } else if (v.type == VAL_STRING) {
const char *s = v.s ? v.s : ""; const char *s = v.s ? v.s : "";
/* trim spaces */
const char *p = s; const char *p = s;
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p++; while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p++;
char *endp = NULL; char *endp = NULL;
long long parsed = strtoll(p, &endp, 10); long long parsed = strtoll(p, &endp, 10);
/* skip trailing spaces */
while (endp && (*endp == ' ' || *endp == '\t' || *endp == '\r' || *endp == '\n')) endp++; while (endp && (*endp == ' ' || *endp == '\t' || *endp == '\r' || *endp == '\n')) endp++;
if (endp && *endp != '\0') { if (endp && *endp != '\0') {
/* non-numeric suffix -> 0 */
push_value(vm, make_int(0)); push_value(vm, make_int(0));
} else { } else {
push_value(vm, make_int((int64_t)parsed)); push_value(vm, make_int((int64_t)parsed));
} }
free_value(v); free_value(v);
} else { } else {
/* nil, array, function -> 0 */
free_value(v); free_value(v);
push_value(vm, make_int(0)); push_value(vm, make_int(0));
} }

View file

@ -1,13 +0,0 @@
case OP_RETURN: {
Value retv;
/* if there's something on the stack -> return it, else nil */
if (vm->sp >= 0) retv = pop_value(vm);
else retv = make_nil();
/* pop frame (free locals) */
vm_pop_frame(vm);
/* push return value into caller frame (or onto stack if no caller) */
push_value(vm, retv);
break;
}