23#ifndef _POSIX_C_SOURCE
24#define _POSIX_C_SOURCE 200809L
27#define _XOPEN_SOURCE 700
41#include <netinet/in.h>
42#include <sys/socket.h>
83#include "vm/os/thread_common.c"
106 int written = vfprintf(stream, fmt, ap);
109 const char *opname =
"unknown";
110 const char *fname = NULL;
111 const char *sfile = NULL;
121 if (ip >= 0 && ip < f->fn->instr_count) {
128 for (
int i = ip; i >= 0; --i) {
145 const char *top_path = NULL;
151 if (!top_path) top_path = sfile;
153 char mapped_path[1024];
154 int mapped_line = line;
156 sfile = strdup(mapped_path);
163 fprintf(stream == stderr ? stderr : stream,
164 " (at %s:%d in %s, op %s @ip %d)\n",
165 sfile ? sfile :
"<unknown>",
167 fname ? fname :
"<entry>",
194#define fprintf fun_vm_fprintf
224#define exit(code) fun_vm_exit(code)
245 if (!vm || vm->
fp < 0) {
246 fprintf(stderr,
"Runtime error: %s\n", msg ? msg :
"<error>");
253 snprintf(buf,
sizeof(buf),
"Runtime error: %s", msg);
255 snprintf(buf,
sizeof(buf),
"Runtime error");
267 const char *fname = (bc && bc->
name) ? bc->
name :
"<anon>";
269 int last_ip = f->
ip - 1;
271 const char *opname =
"OP?";
272 if (bc && last_ip >= 0 && last_ip < bc->instr_count) {
278 fprintf(stderr,
"Runtime error at %s:%d in %s (ip=%d, %s): %s\n",
279 src, line > 0 ? line : 0, fname, last_ip, opname, msg ? msg :
"<error>");
394 while (vm->
fp >= 0) {
411 for (
int i = 0; i <
OPCODE_COUNT; ++i) vm->op_counts[i] = 0;
424 printf(
"=== globals ===\n");
432 printf(
"===============\n");
469 if (!file || line <= 0)
return -1;
518 printf(
"(no breakpoints)\n");
597 fprintf(stderr,
"Runtime error: stack overflow\n");
613 fprintf(stderr,
"Runtime error: stack underflow\n");
672 return sizeof(
Value);
691 return offsetof(
VM, exit_code);
700 return offsetof(
VM, sp);
709 return offsetof(
VM, stack);
718 return offsetof(
VM, globals);
758 for (
int i = 0; i <
OPCODE_COUNT; ++i) vm->op_counts[i] = 0;
791 fprintf(stderr,
"Runtime error: too many frames\n");
814 fprintf(stderr,
"Runtime error: pop frame with empty frame stack\n");
846 for (
int i = ip; i >= 0; --i) {
857 fprintf(stderr,
"Stack trace (most recent call first):\n");
858 for (
int fp = vm->
fp; fp >= 0; --fp) {
861 const char *fname = (bc && bc->
name) ? bc->
name :
"<anon>";
865 const char *opname =
"OP?";
866 if (bc && ip >= 0 && ip < bc->instr_count) {
872 fprintf(stderr,
" at %s:%d in %s (ip=%d, %s)\n", src, line > 0 ? line : 0, fname, ip, opname);
883 for (
int i = 0; i <
OPCODE_COUNT; ++i) total += vm->op_counts[i];
884 printf(
"=== opcode counters (total %lld) ===\n", total);
886 long long c = vm->op_counts[i];
889 printf(
"%3d %-16s %lld\n", i, name, c);
916 fprintf(stderr,
"Entering REPL due to runtime error (code %d)\n", jcode);
928 while (vm->
fp >= 0) {
948 fprintf(stderr,
"Paused (debug)\n");
951 if (vm->
fp < 0)
break;
971 const char *fname = (bc && bc->
name) ? bc->
name :
"<anon>";
976 snprintf(buf,
sizeof(buf),
"invalid opcode %d (%s) at %s:%d in %s (ip=%d)", inst.
op, opname, src, line > 0 ? line : 0, fname, ip);
984 vm->op_counts[inst.
op]++;
992 const char *fname = f->
fn && f->
fn->
name ? f->
fn->
name :
"<entry>";
996 int start =
count - 4;
997 if (start < 0) start = 0;
999 for (
int i = start; i <
count; ++i) {
1001 if (!sv) sv = strdup(
"<oom>");
1002 fprintf(stdout,
"%s%s", sv, (i ==
count - 1 ?
"" :
", "));
1017 fprintf(stderr,
"Breakpoint %d hit at %s:%d\n", bi, sfile, line);
1020 if (vm->
fp < 0)
break;
1028#include "vm/arithmetic/add.c"
1029#include "vm/arithmetic/div.c"
1030#include "vm/arithmetic/mul.c"
1031#include "vm/arithmetic/sub.c"
1033#include "vm/arrays/apop.c"
1034#include "vm/arrays/clear.c"
1035#include "vm/arrays/contains.c"
1036#include "vm/arrays/enumerate.c"
1037#include "vm/arrays/index_get.c"
1038#include "vm/arrays/index_of.c"
1039#include "vm/arrays/index_set.c"
1040#include "vm/arrays/insert.c"
1041#include "vm/arrays/join.c"
1042#include "vm/arrays/make_array.c"
1043#include "vm/arrays/push.c"
1044#include "vm/arrays/remove.c"
1045#include "vm/arrays/set.c"
1046#include "vm/arrays/slice.c"
1047#include "vm/arrays/zip.c"
1050#include "vm/bitwise/band.c"
1051#include "vm/bitwise/bnot.c"
1052#include "vm/bitwise/bor.c"
1053#include "vm/bitwise/bxor.c"
1054#include "vm/bitwise/rol.c"
1055#include "vm/bitwise/ror.c"
1056#include "vm/bitwise/shl.c"
1057#include "vm/bitwise/shr.c"
1059#include "vm/core/call.c"
1060#include "vm/core/dup.c"
1061#include "vm/core/exit.c"
1062#include "vm/core/halt.c"
1063#include "vm/core/jump.c"
1064#include "vm/core/jump_if_false.c"
1065#include "vm/core/load_const.c"
1066#include "vm/core/load_global.c"
1067#include "vm/core/load_local.c"
1068#include "vm/core/nop.c"
1069#include "vm/core/pop.c"
1070#include "vm/core/return.c"
1071#include "vm/core/store_global.c"
1072#include "vm/core/store_local.c"
1073#include "vm/core/swap.c"
1074#include "vm/core/throw.c"
1075#include "vm/core/try_pop.c"
1076#include "vm/core/try_push.c"
1078#include "vm/io/input_line.c"
1079#include "vm/io/read_file.c"
1080#include "vm/io/write_file.c"
1082#include "vm/logic/and.c"
1083#include "vm/logic/eq.c"
1084#include "vm/logic/gt.c"
1085#include "vm/logic/gte.c"
1086#include "vm/logic/lt.c"
1087#include "vm/logic/lte.c"
1088#include "vm/logic/neq.c"
1089#include "vm/logic/not.c"
1090#include "vm/logic/or.c"
1092#include "vm/maps/has_key.c"
1093#include "vm/maps/keys.c"
1094#include "vm/maps/make_map.c"
1095#include "vm/maps/values.c"
1097#include "vm/math/abs.c"
1098#include "vm/math/ceil.c"
1099#include "vm/math/clamp.c"
1100#include "vm/math/cos.c"
1101#include "vm/math/exp.c"
1102#include "vm/math/floor.c"
1103#include "vm/math/fmax.c"
1104#include "vm/math/fmin.c"
1105#include "vm/math/gcd.c"
1106#include "vm/math/isqrt.c"
1107#include "vm/math/lcm.c"
1108#include "vm/math/log.c"
1109#include "vm/math/log10.c"
1110#include "vm/math/max.c"
1111#include "vm/math/min.c"
1112#include "vm/math/mod.c"
1113#include "vm/math/pow.c"
1114#include "vm/math/random_int.c"
1115#include "vm/math/random_seed.c"
1116#include "vm/math/round.c"
1117#include "vm/math/sign.c"
1118#include "vm/math/sin.c"
1119#include "vm/math/sqrt.c"
1120#include "vm/math/tan.c"
1121#include "vm/math/trunc.c"
1124#include "vm/rust/get_sp.c"
1125#include "vm/rust/hello.c"
1126#include "vm/rust/hello_args.c"
1127#include "vm/rust/hello_args_return.c"
1128#include "vm/rust/set_exit.c"
1130#include "vm/os/clock_mono_ms.c"
1131#include "vm/os/date_format.c"
1132#include "vm/os/env.c"
1133#include "vm/os/env_all.c"
1134#include "vm/os/fun_version.c"
1135#include "vm/os/proc_run.c"
1136#include "vm/os/proc_system.c"
1137#include "vm/os/random_number.c"
1138#include "vm/os/serial_close.c"
1139#include "vm/os/serial_config.c"
1140#include "vm/os/serial_open.c"
1141#include "vm/os/serial_recv.c"
1142#include "vm/os/serial_send.c"
1143#include "vm/os/sleep_ms.c"
1144#include "vm/os/thread_join.c"
1145#include "vm/os/thread_spawn.c"
1146#include "vm/os/time_now_ms.c"
1149#include "vm/os/socket_close.c"
1150#include "vm/os/socket_recv.c"
1151#include "vm/os/socket_send.c"
1152#include "vm/os/socket_tcp_accept.c"
1153#include "vm/os/socket_tcp_connect.c"
1154#include "vm/os/socket_tcp_listen.c"
1155#include "vm/os/socket_unix_connect.c"
1156#include "vm/os/socket_unix_listen.c"
1159#include "vm/os/fd_set_nonblock.c"
1160#include "vm/os/fd_poll_read.c"
1161#include "vm/os/fd_poll_write.c"
1164#include "vm/pcsc/connect.c"
1165#include "vm/pcsc/disconnect.c"
1166#include "vm/pcsc/establish.c"
1167#include "vm/pcsc/list_readers.c"
1168#include "vm/pcsc/release.c"
1169#include "vm/pcsc/transmit.c"
1174#include "vm/json/from_file.c"
1175#include "vm/json/parse.c"
1176#include "vm/json/stringify.c"
1177#include "vm/json/to_file.c"
1182#include "vm/xml/name.c"
1183#include "vm/xml/parse.c"
1184#include "vm/xml/root.c"
1185#include "vm/xml/text.c"
1190#include "vm/ini/free.c"
1191#include "vm/ini/get_bool.c"
1192#include "vm/ini/get_double.c"
1193#include "vm/ini/get_int.c"
1194#include "vm/ini/get_string.c"
1195#include "vm/ini/load.c"
1196#include "vm/ini/save.c"
1197#include "vm/ini/set.c"
1198#include "vm/ini/unset.c"
1200#include "vm/ini/stubs.c"
1205#include "vm/curl/download.c"
1206#include "vm/curl/get.c"
1207#include "vm/curl/post.c"
1212#include "vm/kcgi/parse.c"
1213#include "vm/kcgi/reply_start.c"
1214#include "vm/kcgi/write.c"
1215#include "vm/kcgi/end.c"
1219#ifdef FUN_WITH_OPENSSL
1220#include "vm/openssl/md5.c"
1221#include "vm/openssl/ripemd160.c"
1222#include "vm/openssl/sha256.c"
1223#include "vm/openssl/sha512.c"
1227#ifdef FUN_WITH_SQLITE
1228#include "vm/sqlite/close.c"
1229#include "vm/sqlite/exec.c"
1230#include "vm/sqlite/open.c"
1231#include "vm/sqlite/query.c"
1235#ifdef FUN_WITH_REDIS
1236#include "vm/redis/connect.c"
1237#include "vm/redis/cmd.c"
1238#include "vm/redis/close.c"
1252 vm_raise_error(vm,
"CPP support is not enabled (build with -DFUN_WITH_CPP=ON)");
1258#ifdef FUN_WITH_PCRE2
1259#include "vm/pcre2/findall.c"
1260#include "vm/pcre2/match.c"
1261#include "vm/pcre2/test.c"
1264#include "vm/strings/find.c"
1265#include "vm/strings/regex_match.c"
1266#include "vm/strings/regex_replace.c"
1267#include "vm/strings/regex_search.c"
1268#include "vm/strings/split.c"
1269#include "vm/strings/substr.c"
1275#include "vm/os/list_dir.c"
1276#include "vm/print.c"
1277#include "vm/sclamp.c"
1278#include "vm/to_number.c"
1279#include "vm/to_string.c"
1280#include "vm/typeof.c"
1281#include "vm/uclamp.c"
1285 fprintf(stderr,
"Runtime error: unknown opcode %d (%s) at instruction %d\n",
libcurl helpers and buffers used by HTTP-related VM opcodes.
iniparser helpers for Fun VM INI-related opcodes (conditional build).
Iterator-style helpers exposed as built-ins (enumerate, zip).
json-c helpers for Fun VM JSON-related opcodes (conditional build).
Thin kcgi integration helpers used by VM opcodes under src/vm/kcgi/.
Simple string-keyed map implementation backing VAL_MAP Values.
OpenSSL-based hashing helpers used by crypto-related VM opcodes.
PCRE2 helpers for Fun VM extension opcodes (conditional build).
PC/SC smartcard helper registries and lookup utilities for VM opcodes.
Hiredis handle registry and reply mapping helpers for the Fun VM.
SQLite handle registry and helper utilities for the Fun VM extension.
String built-ins wrappers used by VM opcodes.
Instruction * instructions
Call frame representing one active function invocation.
Value locals[MAX_FRAME_LOCALS]
The Fun virtual machine state.
Value output[OUTPUT_SIZE]
int output_is_partial[OUTPUT_SIZE]
int(* on_error_repl)(struct VM *vm)
struct VM::@204221333366357065317066305241116055104274166224 breakpoints[64]
Value globals[MAX_GLOBALS]
long long debug_step_start_ic
Tagged union representing a Fun value.
void print_value(const Value *v)
Print a human-readable representation of a Value to stdout.
Value make_nil(void)
Construct a nil Value.
Value make_string(const char *s)
Construct a string Value by duplicating the given C string.
void free_value(Value v)
Free dynamic storage owned by a Value.
char * value_to_string_alloc(const Value *v)
Allocate a printable C string for a Value.
Value make_int(int64_t v)
Construct a Value representing a 64-bit integer.
Defines the Value type and associated functions for the Fun VM.
ValueType
Enumeration of all runtime value types supported by Fun.
size_t vm_offset_of_exit_code(void)
Obtain offsetof(VM, exit_code) for FFI struct field access.
static int fun_vm_fprintf(FILE *stream, const char *fmt,...)
fprintf wrapper forwarding to fun_vm_vfprintf.
void vm_print_stacktrace(VM *vm)
size_t vm_offset_of_globals(void)
Obtain offsetof(VM, globals) for FFI struct field access.
static Value pop_value(VM *vm)
Pop a Value from the VM operand stack.
size_t vm_value_sizeof(void)
Return sizeof(Value) for external FFI consumers.
void vm_raise_error(VM *vm, const char *msg)
Raise a runtime error inside the VM, honoring try/catch/finally.
static const char * value_type_name(ValueType t)
Get a human-readable name for a ValueType.
static void vm_pop_frame(VM *vm)
Pop the current call frame and free its local variables.
void vm_debug_request_finish(VM *vm)
Request finish (run until the current frame returns).
void vm_debug_clear_breakpoints(VM *vm)
Remove all breakpoints from the VM.
void vm_debug_request_continue(VM *vm)
Resume normal execution (clear stepping state and stop flag).
void vm_debug_request_step(VM *vm)
Request single-step execution (stop after next instruction).
static void frame_init(Frame *f)
Initialize a call frame to a clean state.
int vm_debug_delete_breakpoint(VM *vm, int id)
Delete a breakpoint by id.
void vm_push_i64(VM *vm, int64_t v)
Push a 64-bit integer as a VM int Value (C ABI helper).
static int vm_stack_space(const VM *vm)
static void push_value(VM *vm, Value v)
Push a Value onto the VM operand stack.
static void fun_vm_exit(int code)
Replacement for exit() used within this translation unit.
void vm_init(VM *vm)
Initialize a VM instance to its default state.
static int fun_vm_vfprintf(FILE *stream, const char *fmt, va_list ap)
fprintf-like wrapper that annotates stderr messages with VM source context.
static __thread jmp_buf g_vm_err_jmp
void vm_debug_reset(VM *vm)
Reset debugger state: breakpoints and stepping controls.
static void vm_push_frame(VM *vm, Bytecode *fn, int argc, Value *args)
Push a new call frame for a function and transfer arguments.
void vm_debug_request_next(VM *vm)
Request step-over (stop after next instruction in current frame).
static __thread VM * g_active_vm
size_t vm_offset_of_stack(void)
Obtain offsetof(VM, stack) for FFI struct field access.
static void vm_require_stack(VM *vm, int n)
static int vm_ip_to_line(const Bytecode *bc, int ip)
size_t vm_offset_of_sp(void)
Obtain offsetof(VM, sp) for FFI struct field access.
void vm_free(VM *vm)
Free resources owned directly by the VM structure.
size_t vm_sizeof(void)
Return sizeof(VM) for external FFI consumers.
int vm_debug_add_breakpoint(VM *vm, const char *file, int line)
Add a source breakpoint.
void vm_clear_output(VM *vm)
Clear the VM's buffered output values and partial flags.
int map_expanded_line_to_include_path(const char *path, int line, char *out_path, size_t out_path_cap, int *out_line)
Map a line number in expanded source back to original include path/line.
void vm_reset(VM *vm)
Reset the VM to a clean state.
void * vm_as_mut_ptr(VM *vm)
Cast the VM pointer to an opaque mutable void* (unsafe FFI helper).
void vm_debug_list_breakpoints(VM *vm)
Print active breakpoints to stdout.
char * preprocess_includes(const char *src)
Public wrapper to preprocess includes without a current path.
void vm_print_output(VM *vm)
Print the VM's buffered output values to stdout.
static int vm_stack_count(const VM *vm)
int64_t vm_pop_i64(VM *vm)
Pop a numeric Value and convert it to a 64-bit integer (C ABI helper).
void vm_dump_globals(VM *vm)
Print all non-nil global variables to stdout for debugging.
Core virtual machine data structures and public VM API.
int fun_op_cpp_add(struct VM *vm)
void vm_run(VM *vm, Bytecode *entry)
Execute the provided entry bytecode in the VM. Pushes an initial frame and runs until HALT or an unre...
static const char * opcode_names[]
void vm_dump_opcode_counters(VM *vm)
static int opcode_is_valid(int op)
Check whether an integer value corresponds to a defined opcode.
libxml2 handle registries and helper utilities for the Fun VM extension.