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> 93static __declspec(thread)
VM *g_active_vm = NULL;
95static __thread
VM *g_active_vm = NULL;
111static int fun_vm_vfprintf(FILE *stream,
const char *fmt, va_list ap) {
112 int written = vfprintf(stream, fmt, ap);
113 if (stream == stderr && g_active_vm) {
115 const char *opname =
"unknown";
116 const char *fname = NULL;
117 const char *sfile = NULL;
120 if (g_active_vm->fp >= 0) {
121 Frame *
f = &g_active_vm->frames[g_active_vm->fp];
125 sfile =
f->fn->source_file;
127 if (ip >= 0 && ip < f->fn->instr_count) {
128 int op =
f->fn->instructions[ip].op;
129 if (op >= 0 && op < (
int)(
sizeof(opcode_names) /
sizeof(opcode_names[0]))) {
130 opname = opcode_names[op];
134 for (
int i = ip; i >= 0; --i) {
142 if (line <= 0) line = g_active_vm->current_line > 0 ? g_active_vm->current_line : 1;
151 const char *top_path = NULL;
152 if (g_active_vm->fp >= 0) {
153 Frame *entry = &g_active_vm->frames[0];
157 if (!top_path) top_path = sfile;
159 char mapped_path[1024];
160 int mapped_line = line;
162 sfile = strdup(mapped_path);
169 fprintf(stream == stderr ? stderr : stream,
170 " (at %s:%d in %s, op %s @ip %d)\n",
171 sfile ? sfile :
"<unknown>",
173 fname ? fname :
"<entry>",
190static int fun_vm_fprintf(FILE *stream,
const char *fmt, ...) {
193 int r = fun_vm_vfprintf(stream, fmt, ap);
200#define fprintf fun_vm_fprintf 205static __thread jmp_buf g_vm_err_jmp;
216static void fun_vm_exit(
int code) {
217 if (g_active_vm && g_active_vm->repl_on_error) {
219 longjmp(g_vm_err_jmp,
code ?
code : 1);
230#define exit(code) fun_vm_exit(code) 233static void push_value(
VM *vm,
Value v);
249 if (!vm || vm->
fp < 0) {
250 fprintf(stderr,
"Runtime error: %s\n", msg ? msg :
"<error>");
254 if (
f->try_sp >= 0) {
257 snprintf(
buf,
sizeof(
buf),
"Runtime error: %s", msg);
259 snprintf(
buf,
sizeof(
buf),
"Runtime error");
264 int try_idx =
f->try_stack[
f->try_sp--];
265 int target =
f->fn->instructions[try_idx].operand;
270 fprintf(stderr,
"Runtime error: %s\n", msg ? msg :
"<error>");
318static const char *value_type_name(
ValueType t) {
372static void vm_pop_frame(
VM *vm);
384 while (vm->
fp >= 0) {
409 printf(
"=== globals ===\n");
417 printf(
"===============\n");
454 if (!file || line <= 0)
return -1;
503 printf(
"(no breakpoints)\n");
564static void push_value(
VM *vm,
Value v) {
566 fprintf(stderr,
"Runtime error: stack overflow\n");
580static Value pop_value(
VM *vm) {
582 fprintf(stderr,
"Runtime error: stack underflow\n");
606 fprintf(stderr,
"Runtime type error: expected int/float on stack, got %s\n", value_type_name(
v.type));
641 return sizeof(
Value);
669 return offsetof(
VM, sp);
698static void frame_init(
Frame *
f) {
756 fprintf(stderr,
"Runtime error: too many frames\n");
765 f->locals[i] =
args[i];
777static void vm_pop_frame(
VM *vm) {
779 fprintf(stderr,
"Runtime error: pop frame with empty frame stack\n");
824 int jcode = setjmp(g_vm_err_jmp);
827 fprintf(stderr,
"Entering REPL due to runtime error (code %d)\n", jcode);
837 vm_push_frame(vm, entry, 0, NULL);
839 while (vm->
fp >= 0) {
859 fprintf(stderr,
"Paused (debug)\n");
862 if (vm->
fp < 0)
break;
867 if (
f->ip < 0 ||
f->ip >=
f->fn->instr_count) {
871 push_value(vm, nilv);
879 const char *opname = (inst.
op >= 0 && inst.
op < (int)(
sizeof(opcode_names) /
sizeof(opcode_names[0])))
880 ? opcode_names[inst.
op]
882 const char *fname =
f->fn &&
f->fn->name ?
f->fn->name :
"<entry>";
883 const char *sfile =
f->fn &&
f->fn->source_file ?
f->fn->source_file :
"<unknown>";
891 if (!sv) sv = strdup(
"<oom>");
892 fprintf(stdout,
"%s%s", sv, (i ==
count - 1 ?
"" :
", "));
900 const char *sfile = (
f->fn &&
f->fn->source_file) ?
f->fn->source_file : NULL;
907 fprintf(stderr,
"Breakpoint %d hit at %s:%d\n", bi, sfile, line);
910 if (vm->
fp < 0)
break;
1101#ifdef FUN_WITH_OPENSSL 1114#ifdef FUN_WITH_SQLITE 1122#if defined(FUN_WITH_CPP) 1132 vm_raise_error(vm,
"CPP support is not enabled (build with -DFUN_WITH_CPP=ON)");
1140#ifdef FUN_WITH_PCRE2 1166 if (!opcode_is_valid(inst.
op)) {
1167 fprintf(stderr,
"Runtime error: unknown opcode %d (%s) at instruction %d\n",
1169 (inst.
op >= 0 && inst.
op <
sizeof(opcode_names) /
sizeof(opcode_names[0]))
1170 ? opcode_names[inst.
op]
Implements the OP_ABS opcode for absolute value in the VM.
Execute a bytecode program starting from the given entry point.
Implements the OP_AND opcode for logical AND in the VM.
Implements the OP_APOP opcode for removing elements from arrays in the VM.
Implements the OP_SET opcode for setting elements in arrays in the VM.
Implements the OP_BAND opcode bitwise AND (uint32).
Implements the OP_BNOT opcode bitwise NOT (uint32).
Implements the OP_BOR opcode bitwise OR (uint32).
Implements the OP_BXOR opcode bitwise XOR (uint32).
Implements the OP_CALL opcode for function calls in the VM.
Implements the OP_CAST opcode for converting a value to a target type.
Implements the OP_CEIL opcode using C99 math.h ceil().
Implements the OP_CLAMP opcode for value clamping in the VM.
Implements the OP_CLEAR opcode for clearing arrays in the VM.
Implements OP_CLOCK_MONO_MS to push monotonic clock in ms.
Implements the OP_SQLITE_CLOSE opcode (conditional build).
Implements the OP_PCSC_CONNECT opcode (conditional build).
Implements the OP_CONTAINS opcode for checking array membership in the VM.
Implements the OP_COS opcode using C99 math.h cos().
libcurl helpers and buffers used by HTTP-related VM opcodes.
Implements the OP_PCSC_DISCONNECT opcode (conditional build).
Implements the OP_DIV opcode (numeric division) in the VM.
Fun VM opcode snippet: HTTP download to file via libcurl (OP_CURL_DOWNLOAD).
Implements the OP_DUP opcode for duplicating the top stack value in the VM.
Implements the OP_ECHO opcode for printing without a trailing newline.
Implements the OP_ENUMERATE opcode for enumerating arrays in the VM.
Implements OP_ENV to read an environment variable by name.
Implements OP_ENV_ALL to read the full environment into a map.
Implements the OP_EQ opcode for equality comparison in the VM.
Implements the OP_PCSC_ESTABLISH opcode (conditional build).
Implements the OP_SQLITE_EXEC opcode (conditional build).
Implements the OP_EXIT opcode to terminate the script with an exit code.
Implements the OP_EXP opcode using C99 math.h exp().
Implements OP_FD_POLL_READ to check if a file descriptor is readable.
Implements OP_FD_POLL_WRITE to check if a file descriptor is writable.
Implements OP_FD_SET_NONBLOCK to toggle O_NONBLOCK on a file descriptor.
Implements the OP_FIND opcode for finding substrings in the VM.
Implements the OP_PCRE2_FINDALL opcode (conditional build).
Implements the OP_FLOOR opcode using C99 math.h floor().
Implements the OP_FMAX opcode using C99 math.h fmax(). Accepts int or float; follows IEEE-754 NaN han...
Implements the OP_FMIN opcode using C99 math.h fmin(). Accepts int or float; follows IEEE-754 NaN han...
VM opcode snippet for releasing an INI handle (OP_INI_FREE).
VM opcode snippet for loading a JSON document from a file.
VM opcode snippet: push the current Fun version string (OP_FUN_VERSION).
Implements the OP_GCD opcode for greatest common divisor.
Fun VM opcode snippet: HTTP GET via libcurl (OP_CURL_GET).
VM opcode snippet for reading a boolean from an INI dictionary (OP_INI_GET_BOOL).
VM opcode snippet for reading a floating-point value from INI (OP_INI_GET_DOUBLE).
VM opcode snippet for reading an integer from INI (OP_INI_GET_INT).
Implements the OP_RUST_GET_SP opcode (conditional build).
VM opcode snippet for reading a string from INI (OP_INI_GET_STRING).
Implements the OP_GTE opcode for greater-than-or-equal comparison in the VM.
Implements the OP_HALT opcode for stopping VM execution.
INI handle registry implementation used by VM INI opcodes.
Implements the OP_HAS_KEY opcode for map key checking in the VM.
Implements the OP_RUST_HELLO opcode (conditional build).
Implements the OP_RUST_HELLO_ARGS opcode (conditional build).
Implements the OP_RUST_HELLO_ARGS_RETURN opcode (conditional build).
Implements the OP_INDEX_GET opcode for array and map indexing in the VM.
Implements the OP_INDEX_OF opcode for finding the index of a value in an array in the VM.
Implements the OP_INDEX_SET opcode for array and map assignment in the VM.
VM opcode snippet for setting an INI value (OP_INI_SET).
INI parsing helpers and VM opcode support via iniparser.
Implements the OP_INSERT opcode for inserting elements into arrays in the VM.
Implements the OP_ISQRT opcode for integer square root (floor).
Iterator-style helpers exposed as built-ins (enumerate, zip).
Implements the OP_JOIN opcode for joining array elements into a string in the VM.
VM opcode snippet for parsing a JSON string into a Fun Value.
JSON extension helpers and VM opcode cases (conditional build).
Implements the OP_JUMP opcode for unconditional jumps in the VM.
Implements the OP_JUMP_IF_FALSE opcode for conditional jumps in the VM.
Implements the OP_KEYS opcode for retrieving map keys in the VM.
Implements the OP_LCM opcode for least common multiple.
Implements the OP_LEN opcode for getting the length of arrays or strings in the VM.
Implements the OP_LINE pseudo-opcode to update the current source line.
Implements OP_OS_LIST_DIR to list entries in a directory.
Implements the OP_PCSC_LIST_READERS opcode (conditional build).
VM opcode snippet for loading an INI file (OP_INI_LOAD).
Implements the OP_LOAD_CONST opcode for loading constants in the VM.
Implements the OP_LOAD_GLOBAL opcode for loading global variables in the VM.
Implements the OP_LOAD_LOCAL opcode for loading local variables in the VM.
Implements the OP_LOG10 opcode using C99 math.h log10().
Implements the OP_LOG opcode using C99 math.h log() (natural logarithm).
Implements the OP_LT opcode for less-than comparison in the VM.
Implements the OP_LTE opcode for less-than-or-equal comparison in the VM.
Implements the OP_MAKE_ARRAY opcode for creating arrays in the VM.
Implements the OP_MAKE_MAP opcode for creating maps in the VM.
Simple string-keyed map implementation backing VAL_MAP Values.
Implements the OP_PCRE2_MATCH opcode (conditional build).
Implements the OP_MAX opcode for finding the maximum of two values in the VM.
Implements OP_OPENSSL_MD5 to compute an MD5 hash in hexadecimal.
Implements the OP_MIN opcode for finding the minimum of two values in the VM.
Implements the OP_MOD opcode for modulo operation in the VM.
Implements the OP_MUL opcode (numeric multiplication) in the VM.
VM opcode snippet for XML node name retrieval.
Implements the OP_NEQ opcode for inequality comparison in the VM.
Implements the OP_NOP opcode for no operation in the VM.
Implements the OP_NOT opcode for logical NOT in the VM.
Implements the OP_SQLITE_OPEN opcode (conditional build).
OpenSSL-based hashing helpers used by crypto-related opcodes.
Implements the OP_OR opcode for logical OR in the VM.
PCRE2 configuration header and includes for regex-related opcodes.
PC/SC smartcard helper registries and lookup utilities.
Implements the OP_POP opcode for removing the top stack value in the VM.
Fun VM opcode snippet: HTTP POST via libcurl (OP_CURL_POST).
Implements the OP_POW opcode for exponentiation in the VM.
Implements the OP_PRINT opcode for printing values in the VM.
Implements OP_PROC_RUN to execute a shell command and capture stdout.
Implements OP_PROC_SYSTEM to execute a shell command and return exit code.
Implements the OP_PUSH opcode for appending elements to arrays in the VM.
Implements the OP_SQLITE_QUERY opcode (conditional build).
Implements the OP_RANDOM_INT opcode for generating random integers in the VM.
Implements OP_RANDOM_NUMBER to generate cryptographically secure random bytes.
Implements the OP_RANDOM_SEED opcode for seeding the random number generator in the VM.
Implements the OP_READ_FILE opcode for reading file contents in the VM.
VM opcode snippet for OP_REGEX_MATCH (POSIX full-match).
VM opcode snippet for OP_REGEX_REPLACE (POSIX global replace).
VM opcode snippet for OP_REGEX_SEARCH (POSIX first-match search).
Implements the OP_PCSC_RELEASE opcode (conditional build).
Implements the OP_REMOVE opcode for removing elements from arrays in the VM.
Implements the OP_RETURN opcode for returning from a function in the VM.
Implements OP_OPENSSL_RIPEMD160 to compute a RIPEMD-160 hash in hex.
Implements the OP_ROTL opcode rotate-left (uint32).
VM opcode snippet for retrieving the root node of an XML document.
Implements the OP_ROTR opcode rotate-right (uint32).
Implements the OP_ROUND opcode using C99 math.h round(). C99 round() rounds half away from zero.
VM opcode snippet for saving an INI dictionary to a file (OP_INI_SAVE).
Implements the OP_SCLAMP opcode for signed N-bit two's-complement wrapping.
Implements OP_SERIAL_CLOSE to close an open serial port.
Implements OP_SERIAL_CONFIG to change serial port parameters.
Implements OP_SERIAL_OPEN to open and configure a serial port.
Implements OP_SERIAL_RECV to read bytes from a serial port.
Implements OP_SERIAL_SEND to write bytes to a serial port.
Implements the OP_RUST_SET_EXIT opcode (conditional build).
Implements OP_OPENSSL_SHA256 to compute a SHA-256 hash in hex.
Implements OP_OPENSSL_SHA512 to compute a SHA-512 hash in hex.
Implements the OP_SHL opcode logical left shift (uint32).
Implements the OP_SHR opcode logical right shift (uint32).
Implements the OP_SIGN opcode returning -1, 0, or 1.
Implements the OP_SIN opcode using C99 math.h sin().
Implements OP_SLEEP_MS to suspend execution for a number of milliseconds.
Implements the OP_SLICE opcode for array slicing in the VM.
Implements OP_SOCK_CLOSE to close a socket file descriptor.
Implements OP_SOCK_RECV to receive data from a socket into a string.
Implements OP_SOCK_SEND to transmit data over a connected socket.
Implements OP_SOCK_TCP_ACCEPT to accept an incoming TCP connection.
Implements OP_SOCK_TCP_CONNECT to open a TCP connection.
Implements OP_SOCK_TCP_LISTEN to create a TCP listening socket.
Implements OP_SOCK_UNIX_CONNECT to connect to a UNIX domain socket path.
Implements OP_SOCK_UNIX_LISTEN to create a UNIX domain listening socket.
Implements the OP_SPLIT opcode for splitting strings in the VM.
SQLite handle registry and helper utilities for the Fun VM extension.
Implements the OP_SQRT opcode using C99 math.h sqrt().
Implements the OP_STORE_GLOBAL opcode for storing global variables in the VM.
Implements the OP_STORE_LOCAL opcode for storing local variables in the VM.
String built-ins wrappers used by VM opcodes.
VM opcode snippet for converting a Fun Value to a JSON string.
Call frame representing one active function invocation.
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.
Stub opcode implementations for INI support when FUN_WITH_INI is disabled.
Implements the OP_SUB opcode (numeric subtraction) in the VM.
Implements the OP_SUBSTR opcode for extracting substrings in the VM.
Implements the OP_SWAP opcode for stack manipulation in the VM.
Implements the OP_TAN opcode using C99 math.h tan().
Implements the OP_PCRE2_TEST opcode (conditional build).
VM opcode snippet for retrieving the concatenated text of an XML node.
Cross-platform thread helpers and registry used by OP_THREAD_SPAWN/OP_THREAD_JOIN.
Implements OP_THREAD_JOIN to wait for a spawned thread and get its result.
Implements OP_THREAD_SPAWN to run a function in a background thread.
Implements the OP_THROW opcode for raising exceptions in the VM.
Implements OP_TIME_NOW_MS to push current wall-clock time in ms since Unix epoch.
VM opcode snippet for writing a Fun Value as JSON to a file.
Implements the OP_TO_NUMBER opcode for converting values to integers in the VM.
Implements the OP_TO_STRING opcode for converting values to strings in the VM.
Implements the OP_PCSC_TRANSMIT opcode (conditional build).
Implements the OP_TRUNC opcode using C99 math.h trunc().
Implements the OP_TRY_POP opcode to end a try/catch region.
Implements the OP_TRY_PUSH opcode to begin a try/catch region.
Implements the OP_TYPEOF opcode for obtaining a human-readable type name.
Implements the OP_UCLAMP opcode for unsigned N-bit wrapping.
VM opcode snippet for removing an INI entry (OP_INI_UNSET).
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.
Implements the OP_VALUES opcode for retrieving map values in the VM.
size_t vm_offset_of_exit_code(void)
Obtain offsetof(VM, exit_code) for FFI struct field access.
size_t vm_offset_of_globals(void)
Obtain offsetof(VM, globals) for FFI struct field access.
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.
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).
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).
void vm_init(VM *vm)
Initialize a VM instance to its default state.
void vm_debug_reset(VM *vm)
Reset debugger state: breakpoints and stepping controls.
void vm_debug_request_next(VM *vm)
Request step-over (stop after next instruction in current frame).
size_t vm_offset_of_stack(void)
Obtain offsetof(VM, stack) for FFI struct field access.
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.
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)
Add two 64-bit integers from the VM stack and push the sum.
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...
Implements the OP_WRITE_FILE opcode for writing to a file in the VM.
Lightweight libxml2 handle registry for Fun VM extension helpers.
VM opcode snippet for parsing XML text into a document handle.
Implements the OP_ZIP opcode for array zipping in the VM.