Fun API Documentation 0.42.1
The programming language that makes you have fun!
Loading...
Searching...
No Matches
vm.h
Go to the documentation of this file.
1/*
2 * This file is part of the Fun programming language.
3 * https://fun-lang.xyz/
4 *
5 * Copyright 2025 Johannes Findeisen <you@hanez.org>
6 * Licensed under the terms of the Apache-2.0 license.
7 * https://opensource.org/license/apache-2-0
8 */
9
10/**
11 * @file vm.h
12 * @brief Core virtual machine data structures and public VM API.
13 *
14 * Declares the execution stack/frame layout, global state of the Fun VM,
15 * human-readable opcode names for diagnostics, and the public functions for
16 * initializing, running, resetting, and debugging the VM. FFI helper
17 * declarations for Rust/C++ experiments are also exposed here.
18 */
19#ifndef FUN_VM_H
20#define FUN_VM_H
21
22#include "bytecode.h"
23#include <stddef.h>
24
25#ifndef MAX_FRAMES
26#define MAX_FRAMES 128
27#endif
28
29#ifndef MAX_FRAME_LOCALS
30#define MAX_FRAME_LOCALS 64
31#endif
32
33#ifndef MAX_GLOBALS
34#define MAX_GLOBALS 128
35#endif
36
37#ifndef OUTPUT_SIZE
38#define OUTPUT_SIZE 1024
39#endif
40
41#ifndef STACK_SIZE
42#define STACK_SIZE 1024
43#endif
44
45static const char *opcode_names[] = {
46 "NOP", "LOAD_CONST", "LOAD_LOCAL", "STORE_LOCAL",
47 "LOAD_GLOBAL", "STORE_GLOBAL", "ADD", "SUB", "MUL", "DIV",
48 "LT", "LTE", "GT", "GTE", "EQ", "NEQ", "POP", "JUMP",
49 "JUMP_IF_FALSE", "CALL", "RETURN", "PRINT", "ECHO", "HALT",
50 "LINE",
51 "MOD", "AND", "OR", "NOT", "DUP", "SWAP",
52 "MAKE_ARRAY", "INDEX_GET", "INDEX_SET",
53 "LEN", "PUSH", "APOP", "SET", "INSERT", "REMOVE", "SLICE",
54 "TO_NUMBER", "TO_STRING", "CAST", "TYPEOF",
55 "SPLIT", "JOIN", "SUBSTR", "FIND",
56 "REGEX_MATCH", "REGEX_SEARCH", "REGEX_REPLACE",
57 "CONTAINS", "INDEX_OF", "CLEAR",
58 "ENUMERATE", "ZIP",
59 "MIN", "MAX", "CLAMP", "ABS", "POW", "RANDOM_SEED", "RANDOM_INT",
60 "MAKE_MAP", "KEYS", "VALUES", "HAS_KEY",
61 "READ_FILE", "WRITE_FILE", "ENV", "INPUT_LINE", "PROC_RUN", "PROC_SYSTEM",
62 "TIME_NOW_MS", "CLOCK_MONO_MS", "DATE_FORMAT",
63 "THREAD_SPAWN", "THREAD_JOIN", "SLEEP_MS",
64 "RANDOM_NUMBER",
65 "BAND", "BOR", "BXOR", "BNOT", "SHL", "SHR", "ROTL", "ROTR",
66 "JSON_PARSE", "JSON_STRINGIFY", "JSON_FROM_FILE", "JSON_TO_FILE",
67 "CURL_GET", "CURL_POST", "CURL_DOWNLOAD",
68 "SQLITE_OPEN", "SQLITE_CLOSE", "SQLITE_EXEC", "SQLITE_QUERY",
69 /* Redis (hiredis) */
70 "REDIS_CONNECT", "REDIS_CMD", "REDIS_CLOSE",
71 "LIBSQL_OPEN", "LIBSQL_CLOSE", "LIBSQL_EXEC", "LIBSQL_QUERY",
72 "PCSC_ESTABLISH", "PCSC_RELEASE", "PCSC_LIST_READERS", "PCSC_CONNECT", "PCSC_DISCONNECT", "PCSC_TRANSMIT",
73 "PCRE2_TEST", "PCRE2_MATCH", "PCRE2_FINDALL",
74 "INI_LOAD", "INI_FREE", "INI_GET_STRING", "INI_GET_INT", "INI_GET_DOUBLE", "INI_GET_BOOL", "INI_SET", "INI_UNSET", "INI_SAVE",
75 "XML_PARSE", "XML_ROOT", "XML_NAME", "XML_TEXT",
76 "SOCK_TCP_LISTEN", "SOCK_TCP_ACCEPT", "SOCK_TCP_CONNECT", "SOCK_SEND", "SOCK_RECV", "SOCK_CLOSE", "SOCK_UNIX_LISTEN", "SOCK_UNIX_CONNECT",
77 "FD_SET_NONBLOCK", "FD_POLL_READ", "FD_POLL_WRITE",
78 "EXIT",
79 "OS_LIST_DIR",
80 "SERIAL_OPEN", "SERIAL_CONFIG", "SERIAL_SEND", "SERIAL_RECV", "SERIAL_CLOSE",
81 "TRY_PUSH", "TRY_POP", "THROW",
82 "FMIN", "FMAX",
83 /* Rust FFI demo */
84 "RUST_HELLO", "RUST_HELLO_ARGS", "RUST_HELLO_ARGS_RETURN", "RUST_GET_SP", "RUST_SET_EXIT",
85 /* C++ demo */
86 "CPP_ADD"};
87
88/**
89 * @brief Call frame representing one active function invocation.
90 *
91 * Each frame keeps a pointer to its function bytecode, the current
92 * instruction pointer within that bytecode, a fixed-size array of local
93 * variables, and a small try/catch stack for exception handling.
94 */
95typedef struct {
97 int ip;
99 /* exception handling (per-frame) */
100 int try_stack[16];
101 int try_sp; /* -1 when empty */
102} Frame;
103
104/**
105 * @brief The Fun virtual machine state.
106 *
107 * Holds the operand stack, call frames, globals, standard output capture,
108 * runtime counters, and debugger state. Functions in this header operate on
109 * this structure; callers must ensure proper initialization with vm_init()
110 * before use and call vm_free()/vm_reset() as appropriate.
111 */
112struct VM {
114 int sp;
115
117 int fp; // frame pointer, -1 when no frame
118
120
121 Value output[OUTPUT_SIZE]; // store printed values
123 int output_is_partial[OUTPUT_SIZE]; // 1 when the corresponding output entry should not end with newline (echo)
124
125 long long instr_count; // executed instructions in the last vm_run
126
127#ifdef FUN_TRACE
128 /* Per-opcode execution counters (enabled when FUN_TRACE=1) */
129 long long op_counts[OPCODE_COUNT];
130#endif
131
132 int current_line; // last executed source line (debug)
133
134 int exit_code; // process exit code set by OP_EXIT
135
136 int trace_enabled; // when non-zero, print executed ops and stack
137 int repl_on_error; // when non-zero, enter REPL on runtime error (preserve stack)
138 int (*on_error_repl)(struct VM *vm); // optional hook to run REPL on error
139
140 /* --- Debugger state --- */
141 int debug_step_mode; // 0 none, 1 step, 2 next, 3 finish
142 int debug_step_target_fp; // target frame pointer for next/finish
143 long long debug_step_start_ic; // instruction count snapshot when step/next requested
144 int debug_stop_requested; // force a pause at loop top
145
146 struct {
147 char *file; // strdup'ed file path
148 int line; // 1-based line
149 int active; // 1 if active
151 int break_count; // number of active breakpoints
152};
153
154/** @brief Opaque VM alias for external users. */
155typedef struct VM VM;
156
157/**
158 * @brief Initialize a VM instance to zero/initial state.
159 * @param vm Non-NULL pointer to VM storage to initialize.
160 */
161void vm_init(VM *vm);
162
163/**
164 * @brief Clear the buffered output captured by the VM.
165 * @param vm VM instance.
166 */
167void vm_clear_output(VM *vm);
168/**
169 * @brief Print buffered output entries to stdout (debug aid).
170 * @param vm VM instance.
171 */
172void vm_print_output(VM *vm);
173/** Dump per-opcode execution counters (when FUN_TRACE enabled). */
175/** Print a human-readable VM stack trace to stderr (top frame first). */
176void vm_print_stacktrace(VM *vm);
177/**
178 * @brief Free all resources owned by the VM (globals, frames, output buffers).
179 * The VM object itself is not freed when allocated on the stack.
180 * @param vm VM instance to dispose.
181 */
182void vm_free(VM *vm);
183
184/**
185 * @brief Reset VM to initial state, freeing globals/locals/output.
186 * The VM object remains valid for reuse after this call.
187 * @param vm VM instance to reset.
188 */
189void vm_reset(VM *vm);
190
191/**
192 * @brief Print non-nil globals (index and value) to stdout.
193 * @param vm VM instance.
194 */
195void vm_dump_globals(VM *vm);
196/**
197 * @brief Execute the provided entry bytecode in the VM.
198 * Pushes an initial frame and runs until HALT or an unrecoverable error.
199 * @param vm VM instance.
200 * @param entry Entry bytecode to execute; must outlive the call.
201 */
202void vm_run(VM *vm, Bytecode *entry);
203
204/**
205 * @brief Raise a runtime error honoring active try/catch/finally handlers.
206 * If a try handler is active in the current frame, control jumps to it with
207 * an error string pushed on the stack. Otherwise, prints the error (with
208 * location) and terminates execution.
209 * @param vm VM instance.
210 * @param msg Null-terminated error message.
211 */
212void vm_raise_error(VM *vm, const char *msg);
213
214/* --- Debugger API --- */
215/** Reset debugger state (clear step mode and breakpoints). */
216void vm_debug_reset(VM *vm);
217/** Add a breakpoint at file:line; returns non-negative id on success or -1. */
218int vm_debug_add_breakpoint(VM *vm, const char *file, int line);
219/** Delete a breakpoint by id; returns 1 on success, 0 on failure. */
220int vm_debug_delete_breakpoint(VM *vm, int id);
221/** Remove all breakpoints. */
223/** Print the current list of breakpoints to stdout. */
225/** Request single-step execution mode. */
226void vm_debug_request_step(VM *vm);
227/** Step over (next) within the current frame. */
228void vm_debug_request_next(VM *vm);
229/** Run until the current frame returns (finish). */
231/** Continue execution until next breakpoint/stop. */
233
234/**
235 * @brief Check whether an integer value corresponds to a defined opcode.
236 * @param op Numeric opcode to validate.
237 * @return 1 if valid, 0 otherwise.
238 */
239static inline int opcode_is_valid(int op) {
240 return op >= OP_NOP && op <= OP_CPP_ADD; // all current opcodes
241}
242
243/* --- Minimal C ABI helpers for FFI (Rust opcode experiments) --- */
244/** Pop an int64 from the VM stack; accepts int/float; returns truncated value. */
245int64_t vm_pop_i64(VM *vm);
246/** Push an int64 onto the VM stack. */
247void vm_push_i64(VM *vm, int64_t v);
248
249/** Example Rust-implemented opcode (adds top two ints on stack). */
251
252/** Return a demo null-terminated C string owned by Rust. */
253const char *fun_rust_get_string(void);
254/** Print a C string via Rust; returns 0 on success. */
255int fun_rust_print_string(const char *msg);
256/** Return a newly allocated duplicate of the input C string (caller frees). */
257char *fun_rust_echo_string(const char *input);
258/** Free a C string previously returned by fun_rust_echo_string(). */
259void fun_rust_string_free(char *ptr);
260
261/** C++ demo opcode entry point (C ABI). */
262int fun_op_cpp_add(struct VM *vm);
263
264/* --- Extended C ABI for Rust to access VM internals (unsafe) --- */
265/** Size of struct VM in bytes. */
266size_t vm_sizeof(void);
267/** Size of struct Value in bytes. */
268size_t vm_value_sizeof(void);
269
270/**
271 * @brief Get a mutable byte pointer to the VM object.
272 * Extremely unsafe; for low-level FFI use only.
273 */
274void *vm_as_mut_ptr(VM *vm);
275
276/** Offsets of commonly accessed VM fields (for Rust FFI). */
277size_t vm_offset_of_exit_code(void);
278size_t vm_offset_of_sp(void);
279size_t vm_offset_of_stack(void);
280size_t vm_offset_of_globals(void);
281
282/* Demo Rust ops using the extended ABI */
285
286#endif
Definitions for the Fun VM bytecode: opcodes, instruction format, and bytecode container API.
#define OPCODE_COUNT
Definition bytecode.h:300
@ OP_CPP_ADD
Definition bytecode.h:296
@ OP_NOP
Definition bytecode.h:36
Call frame representing one active function invocation.
Definition vm.h:95
int try_sp
Definition vm.h:101
Bytecode * fn
Definition vm.h:96
Value locals[MAX_FRAME_LOCALS]
Definition vm.h:98
int try_stack[16]
Definition vm.h:100
int ip
Definition vm.h:97
The Fun virtual machine state.
Definition vm.h:112
int sp
Definition vm.h:114
long long instr_count
Definition vm.h:125
int debug_step_target_fp
Definition vm.h:142
Value output[OUTPUT_SIZE]
Definition vm.h:121
int line
Definition vm.h:148
int current_line
Definition vm.h:132
int repl_on_error
Definition vm.h:137
int fp
Definition vm.h:117
int output_is_partial[OUTPUT_SIZE]
Definition vm.h:123
int(* on_error_repl)(struct VM *vm)
Definition vm.h:138
int debug_stop_requested
Definition vm.h:144
int break_count
Definition vm.h:151
int active
Definition vm.h:149
int trace_enabled
Definition vm.h:136
int exit_code
Definition vm.h:134
int output_count
Definition vm.h:122
struct VM::@204221333366357065317066305241116055104274166224 breakpoints[64]
char * file
Definition vm.h:147
Value globals[MAX_GLOBALS]
Definition vm.h:119
int debug_step_mode
Definition vm.h:141
long long debug_step_start_ic
Definition vm.h:143
Frame frames[MAX_FRAMES]
Definition vm.h:116
Value stack[STACK_SIZE]
Definition vm.h:113
Tagged union representing a Fun value.
Definition value.h:68
size_t vm_offset_of_exit_code(void)
Obtain offsetof(VM, exit_code) for FFI struct field access.
Definition vm.c:690
void fun_rust_string_free(char *ptr)
#define MAX_GLOBALS
Definition vm.h:34
void vm_print_stacktrace(VM *vm)
Definition vm.c:855
size_t vm_offset_of_globals(void)
Obtain offsetof(VM, globals) for FFI struct field access.
Definition vm.c:717
size_t vm_value_sizeof(void)
Return sizeof(Value) for external FFI consumers.
Definition vm.c:671
void vm_raise_error(VM *vm, const char *msg)
Raise a runtime error honoring active try/catch/finally handlers. If a try handler is active in the c...
Definition vm.c:244
char * fun_rust_echo_string(const char *input)
void vm_debug_request_finish(VM *vm)
Request finish (run until the current frame returns).
Definition vm.c:555
void vm_debug_clear_breakpoints(VM *vm)
Remove all breakpoints from the VM.
Definition vm.c:507
void vm_debug_request_continue(VM *vm)
Resume normal execution (clear stepping state and stop flag).
Definition vm.c:566
void vm_debug_request_step(VM *vm)
Request single-step execution (stop after next instruction).
Definition vm.c:532
int vm_debug_delete_breakpoint(VM *vm, int id)
Delete a breakpoint by id.
Definition vm.c:487
void vm_push_i64(VM *vm, int64_t v)
Push a 64-bit integer as a VM int Value (C ABI helper).
Definition vm.c:652
int fun_op_cpp_add(struct VM *vm)
#define MAX_FRAMES
Definition vm.h:26
#define STACK_SIZE
Definition vm.h:42
void vm_init(VM *vm)
Initialize a VM instance to zero/initial state.
Definition vm.c:745
const char * fun_rust_get_string(void)
int fun_rust_print_string(const char *msg)
void vm_debug_reset(VM *vm)
Reset debugger state: breakpoints and stepping controls.
Definition vm.c:444
#define OUTPUT_SIZE
Definition vm.h:38
int fun_op_rget_sp(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...
void vm_debug_request_next(VM *vm)
Request step-over (stop after next instruction in current frame).
Definition vm.c:543
static const char * opcode_names[]
Definition vm.h:45
size_t vm_offset_of_stack(void)
Obtain offsetof(VM, stack) for FFI struct field access.
Definition vm.c:708
size_t vm_offset_of_sp(void)
Obtain offsetof(VM, sp) for FFI struct field access.
Definition vm.c:699
int fun_op_radd(VM *vm)
void vm_free(VM *vm)
Free all resources owned by the VM (globals, frames, output buffers). The VM object itself is not fre...
Definition vm.c:377
size_t vm_sizeof(void)
Return sizeof(VM) for external FFI consumers.
Definition vm.c:662
int vm_debug_add_breakpoint(VM *vm, const char *file, int line)
Add a source breakpoint.
Definition vm.c:468
void vm_clear_output(VM *vm)
Clear the buffered output captured by the VM.
Definition vm.c:359
void vm_reset(VM *vm)
Reset VM to initial state, freeing globals/locals/output. The VM object remains valid for reuse after...
Definition vm.c:392
void * vm_as_mut_ptr(VM *vm)
Get a mutable byte pointer to the VM object. Extremely unsafe; for low-level FFI use only.
Definition vm.c:681
void vm_debug_list_breakpoints(VM *vm)
Print active breakpoints to stdout.
Definition vm.c:516
int fun_op_rset_exit(VM *vm)
void vm_print_output(VM *vm)
Print buffered output entries to stdout (debug aid).
Definition vm.c:832
void vm_dump_opcode_counters(VM *vm)
int64_t vm_pop_i64(VM *vm)
Pop a numeric Value and convert it to a 64-bit integer (C ABI helper).
Definition vm.c:629
static int opcode_is_valid(int op)
Check whether an integer value corresponds to a defined opcode.
Definition vm.h:239
void vm_dump_globals(VM *vm)
Print non-nil globals (index and value) to stdout.
Definition vm.c:423
#define MAX_FRAME_LOCALS
Definition vm.h:30