Fun 0.41.5
The programming language that makes You have fun
Loading...
Searching...
No Matches
vm.c
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
19
20/* Ensure POSIX/XSI prototypes (nanosleep, wcwidth, etc.) are available
21 * before any system headers are included by amalgamated .c files. */
22#ifndef _WIN32
23#ifndef _POSIX_C_SOURCE
24#define _POSIX_C_SOURCE 200809L
25#endif
26#ifndef _XOPEN_SOURCE
27#define _XOPEN_SOURCE 700
28#endif
29#endif
30
31#include <math.h>
32#include <stdarg.h>
33#include <stddef.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <time.h>
38
39#ifdef __unix__
40#include <netdb.h>
41#include <netinet/in.h>
42#include <sys/socket.h>
43#include <sys/types.h>
44#include <sys/un.h>
45#include <sys/wait.h>
46#include <unistd.h>
47/* For hidden input (password) handling in OP_INPUT_LINE */
48#include <termios.h>
49/* For non-blocking sockets and polling */
50#include <fcntl.h>
51#include <poll.h>
52// #include <arpa/inet.h>
53#endif
54
55#ifdef _WIN32
56#include <windows.h>
57#endif
58
59/* Bring in split-out built-ins without changing the build system yet */
60#include "iter.c"
61#include "map.c"
62#include "string.c"
63#include "value.h"
64#include "vm.h"
65
66/* Notcurses support removed */
67
68// Optional by extensions commonly used code. #ifdef's are in each single file.
69#include "extensions/curl.c"
70#include "extensions/ini.c"
71#ifdef FUN_WITH_INI
72/* Central INI handle registry and helpers */
73#include "vm/ini/handles.c"
74#endif
75/* Note: INI opcode handlers are included below; changes in vm/ini/ .c files
76 * require vm.c to rebuild. */
77#include "extensions/json.c"
79#include "extensions/pcre2.c"
80#include "extensions/pcsc.c"
81#include "extensions/sqlite.c"
82#include "extensions/xml2.c"
83
84/* forward declarations for include mapping used in error reporting */
85extern char *preprocess_includes(const char *src);
86extern int map_expanded_line_to_include_path(const char *path, int line, char *out_path, size_t out_path_cap, int *out_line);
87
88/* Threading internals (registry and platform glue) */
90
91/* Track the currently running VM to annotate error messages */
92#ifdef _WIN32
93static __declspec(thread) VM *g_active_vm = NULL;
94#else
95static __thread VM *g_active_vm = NULL;
96#endif
97
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) {
114 /* Determine current frame and instruction pointer of the faulting op */
115 const char *opname = "unknown";
116 const char *fname = NULL;
117 const char *sfile = NULL;
118 int ip = -1;
119 int line = -1;
120 if (g_active_vm->fp >= 0) {
121 Frame *f = &g_active_vm->frames[g_active_vm->fp];
122 ip = f->ip - 1; /* last executed instruction */
123 if (f->fn) {
124 fname = f->fn->name;
125 sfile = f->fn->source_file;
126 /* derive opcode name */
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];
131 }
132 }
133 /* derive source line by scanning back to the most recent OP_LINE marker */
134 for (int i = ip; i >= 0; --i) {
135 Instruction prev = f->fn->instructions[i];
136 if (prev.op == OP_LINE) {
137 line = prev.operand;
138 break;
139 }
140 }
141 /* fallback to VM's last recorded line if no marker found */
142 if (line <= 0) line = g_active_vm->current_line > 0 ? g_active_vm->current_line : 1;
143
144 /* Map expanded line back to the real included file.
145 * Important: OP_LINE operands refer to the expanded, top-level source produced by
146 * the preprocessor. Therefore we must pass the TOP-LEVEL script path to the mapper,
147 * not the current function's own source_file (which may point at an included file).
148 */
149 if (line > 0) {
150 /* Attempt to retrieve the entry frame's source file as the true top-level path */
151 const char *top_path = NULL;
152 if (g_active_vm->fp >= 0) {
153 Frame *entry = &g_active_vm->frames[0];
154 if (entry && entry->fn && entry->fn->source_file) top_path = entry->fn->source_file;
155 }
156 /* Fallback: use current function's source when entry is unavailable */
157 if (!top_path) top_path = sfile;
158 if (top_path) {
159 char mapped_path[1024];
160 int mapped_line = line;
161 if (map_expanded_line_to_include_path(top_path, line, mapped_path, sizeof(mapped_path), &mapped_line)) {
162 sfile = strdup(mapped_path); /* leak acceptable on error paths */
163 line = mapped_line;
164 }
165 }
166 }
167 }
168 }
169 fprintf(stream == stderr ? stderr : stream,
170 " (at %s:%d in %s, op %s @ip %d)\n",
171 sfile ? sfile : "<unknown>",
172 line > 0 ? line : 1,
173 fname ? fname : "<entry>",
174 opname,
175 ip);
176 }
177 return written;
178}
179
190static int fun_vm_fprintf(FILE *stream, const char *fmt, ...) {
191 va_list ap;
192 va_start(ap, fmt);
193 int r = fun_vm_vfprintf(stream, fmt, ap);
194 va_end(ap);
195 return r;
196}
197
198
199/* Redirect fprintf within this translation unit so opcode handlers use our wrapper */
200#define fprintf fun_vm_fprintf
201
202/* Intercept exit() in this translation unit so VM errors don't terminate the process outright */
203#include <setjmp.h>
204
205static __thread jmp_buf g_vm_err_jmp;
206
216static void fun_vm_exit(int code) {
217 if (g_active_vm && g_active_vm->repl_on_error) {
218 /* Jump back to vm_run to allow dropping into the REPL with intact VM state */
219 longjmp(g_vm_err_jmp, code ? code : 1);
220 }
221 /* Fallback: terminate immediately if not in REPL-on-error mode */
222#ifdef _WIN32
223 _exit(code);
224#else
225 _Exit(code);
226#endif
227}
228
229/* Redirect exit inside this TU (affects included opcode handlers) */
230#define exit(code) fun_vm_exit(code)
231
232/* Forward decl for stack push used by vm_raise_error */
233static void push_value(VM *vm, Value v);
234
235/* Raise a runtime error that respects try/catch/finally semantics.
236 * If a handler is installed for the current frame, jump to it and push
237 * an error string for the catch clause. Otherwise, print and stop VM. */
248void vm_raise_error(VM *vm, const char *msg) {
249 if (!vm || vm->fp < 0) {
250 fprintf(stderr, "Runtime error: %s\n", msg ? msg : "<error>");
251 return;
252 }
253 Frame *f = &vm->frames[vm->fp];
254 if (f->try_sp >= 0) {
255 char buf[256];
256 if (msg) {
257 snprintf(buf, sizeof(buf), "Runtime error: %s", msg);
258 } else {
259 snprintf(buf, sizeof(buf), "Runtime error");
260 }
261 /* push error value and transfer control to handler target */
262 Value err = make_string(buf);
263 push_value(vm, err);
264 int try_idx = f->try_stack[f->try_sp--];
265 int target = f->fn->instructions[try_idx].operand;
266 f->ip = target;
267 return;
268 }
269 /* No handler: print annotated message and terminate VM */
270 fprintf(stderr, "Runtime error: %s\n", msg ? msg : "<error>");
271 vm->fp = -1; /* stop execution */
272}
273
274/*
275Opcode case include index (vm_case_*.inc):
276- Core/stack/frame:
277 vm_case_nop.inc, vm_case_halt.inc,
278 vm_case_load_const.inc, vm_case_load_local.inc, vm_case_store_local.inc,
279 vm_case_load_global.inc, vm_case_store_global.inc,
280 vm_case_pop.inc, vm_case_dup.inc, vm_case_swap.inc,
281 vm_case_call.inc, vm_case_return.inc, vm_case_print.inc, vm_case_jump.inc, vm_case_jump_if_false.inc
282- Arithmetic and logic:
283 vm_case_add.inc, vm_case_sub.inc, vm_case_mul.inc, vm_case_div.inc,
284 vm_case_mod.inc, vm_case_lt.inc, vm_case_lte.inc, vm_case_gt.inc, vm_case_gte.inc,
285 vm_case_eq.inc, vm_case_neq.inc, vm_case_and.inc, vm_case_or.inc, vm_case_not.inc
286- Conversions:
287 vm_case_to_number.inc, vm_case_to_string.inc
288- Arrays and slices:
289 vm_case_make_array.inc, vm_case_len.inc,
290 vm_case_index_get.inc, vm_case_index_set.inc,
291 vm_case_arr_push.inc, vm_case_arr_pop.inc, vm_case_arr_set.inc, vm_case_arr_insert.inc, vm_case_arr_remove.inc,
292 vm_case_slice.inc
293- Strings and iteration helpers:
294 vm_case_split.inc, vm_case_join.inc, vm_case_substr.inc, vm_case_find.inc,
295 vm_case_enumerate.inc, vm_case_zip.inc
296- Maps and I/O:
297 vm_case_make_map.inc, vm_case_keys.inc, vm_case_values.inc, vm_case_has_key.inc,
298 vm_case_read_file.inc, vm_case_write_file.inc
299- Math utils / RNG:
300 vm_case_min.inc, vm_case_max.inc, vm_case_clamp.inc, vm_case_abs.inc, vm_case_pow.inc,
301 vm_case_random_seed.inc, vm_case_random_int.inc
302
303Dev tips:
304- When adding a new opcode:
305 1) Define OP_<NAME> in bytecode.h and opcode_names[] in vm.h.
306 2) Implement its VM handler in src/vm_case_<lowercase>.inc.
307 3) Include it in the switch below.
308 4) Run scripts/check_op_includes.py to verify coverage.
309- You can run scripts/run_examples.sh to sanity-check examples quickly.
310*/
311
318static const char *value_type_name(ValueType t) {
319 switch (t) {
320 case VAL_FUNCTION:
321 return "function";
322 case VAL_INT:
323 return "int";
324 case VAL_FLOAT:
325 return "float";
326 case VAL_BOOL:
327 return "boolean";
328 case VAL_ARRAY:
329 return "array";
330 case VAL_MAP:
331 return "map";
332 case VAL_NIL:
333 return "nil";
334 case VAL_STRING:
335 return "string";
336 default:
337 return "unknown";
338 }
339}
340
350 for (int i = 0; i < vm->output_count; ++i) {
351 free_value(vm->output[i]);
352 }
353 vm->output_count = 0;
354 // reset partial flags
355 for (int i = 0; i < OUTPUT_SIZE; ++i)
356 vm->output_is_partial[i] = 0;
357}
358
367void vm_free(VM *vm) {
368 // currently nothing persistent allocated inside VM itself
369}
370
371/* forward declaration for helper used in vm_reset */
372static void vm_pop_frame(VM *vm);
373
382void vm_reset(VM *vm) {
383 // Pop all frames (free locals)
384 while (vm->fp >= 0) {
385 vm_pop_frame(vm);
386 }
387 // Clear stack
388 vm->sp = -1;
389 // Free globals
390 for (int i = 0; i < MAX_GLOBALS; ++i) {
391 free_value(vm->globals[i]);
392 vm->globals[i] = make_nil();
393 }
394 // Clear output buffer
396 // Reset exit code
397 vm->exit_code = 0;
398
399 // Reset debugger state (breakpoints, stepping)
401}
402
409 printf("=== globals ===\n");
410 for (int i = 0; i < MAX_GLOBALS; ++i) {
411 if (vm->globals[i].type != VAL_NIL) {
412 printf("[%d] ", i);
413 print_value(&vm->globals[i]);
414 printf("\n");
415 }
416 }
417 printf("===============\n");
418}
419
420/* --- Debugger API impl --- */
421
429void vm_debug_reset(VM *vm) {
430 for (int i = 0; i < vm->break_count; ++i) {
431 if (vm->breakpoints[i].file) {
432 free(vm->breakpoints[i].file);
433 vm->breakpoints[i].file = NULL;
434 }
435 vm->breakpoints[i].active = 0;
436 vm->breakpoints[i].line = 0;
437 }
438 vm->break_count = 0;
439 vm->debug_step_mode = 0;
440 vm->debug_step_target_fp = -1;
443}
444
453int vm_debug_add_breakpoint(VM *vm, const char *file, int line) {
454 if (!file || line <= 0) return -1;
455 if (vm->break_count >= (int)(sizeof(vm->breakpoints) / sizeof(vm->breakpoints[0]))) return -1;
456 int id = vm->break_count++;
457 vm->breakpoints[id].file = strdup(file);
458 vm->breakpoints[id].line = line;
459 vm->breakpoints[id].active = 1;
460 return id;
461}
462
473 if (id < 0 || id >= vm->break_count) return 0;
474 if (vm->breakpoints[id].file) free(vm->breakpoints[id].file);
475 for (int i = id + 1; i < vm->break_count; ++i) {
476 vm->breakpoints[i - 1] = vm->breakpoints[i];
477 }
478 vm->break_count--;
479 if (vm->break_count >= 0) {
480 vm->breakpoints[vm->break_count].file = NULL;
481 vm->breakpoints[vm->break_count].line = 0;
482 vm->breakpoints[vm->break_count].active = 0;
483 }
484 return 1;
485}
486
495
502 if (vm->break_count <= 0) {
503 printf("(no breakpoints)\n");
504 return;
505 }
506 for (int i = 0; i < vm->break_count; ++i) {
507 if (!vm->breakpoints[i].active) continue;
508 printf(" [%d] %s:%d\n", i, vm->breakpoints[i].file ? vm->breakpoints[i].file : "<unknown>", vm->breakpoints[i].line);
509 }
510}
511
518 vm->debug_step_mode = 1; // step
521}
522
529 vm->debug_step_mode = 2; // next (step over)
530 vm->debug_step_target_fp = vm->fp;
533}
534
541 vm->debug_step_mode = 3; // finish (until return)
542 vm->debug_step_target_fp = vm->fp;
544}
545
555
564static void push_value(VM *vm, Value v) {
565 if (vm->sp >= STACK_SIZE - 1) {
566 fprintf(stderr, "Runtime error: stack overflow\n");
567 exit(1);
568 }
569 vm->stack[++vm->sp] = v; /* take ownership of v */
570}
571
580static Value pop_value(VM *vm) {
581 if (vm->sp < 0) {
582 fprintf(stderr, "Runtime error: stack underflow\n");
583 exit(1);
584 }
585 return vm->stack[vm->sp--]; /* caller owns returned Value */
586}
587
588/* --- C ABI helpers for Rust FFI --- */
598int64_t vm_pop_i64(VM *vm) {
599 Value v = pop_value(vm);
600 int64_t out = 0;
601 if (v.type == VAL_INT) {
602 out = v.i;
603 } else if (v.type == VAL_FLOAT) {
604 out = (int64_t)v.d;
605 } else {
606 fprintf(stderr, "Runtime type error: expected int/float on stack, got %s\n", value_type_name(v.type));
608 exit(1);
609 }
610 /* free any dynamic payload (no-op for int/float) */
612 return out;
613}
614
621void vm_push_i64(VM *vm, int64_t v) {
622 push_value(vm, make_int(v));
623}
624
625/* --- Extended C ABI for Rust to access VM internals (unsafe) --- */
631size_t vm_sizeof(void) {
632 return sizeof(VM);
633}
634
640size_t vm_value_sizeof(void) {
641 return sizeof(Value);
642}
643
650void *vm_as_mut_ptr(VM *vm) {
651 return (void *)vm;
652}
653
660 return offsetof(VM, exit_code);
661}
662
668size_t vm_offset_of_sp(void) {
669 return offsetof(VM, sp);
670}
671
677size_t vm_offset_of_stack(void) {
678 return offsetof(VM, stack);
679}
680
687 return offsetof(VM, globals);
688}
689
698static void frame_init(Frame *f) {
699 f->fn = NULL;
700 f->ip = 0;
701 for (int i = 0; i < MAX_FRAME_LOCALS; ++i)
702 f->locals[i] = make_nil();
703 f->try_sp = -1;
704}
705
714void vm_init(VM *vm) {
715 vm->sp = -1;
716 vm->fp = -1;
717 vm->output_count = 0;
718 for (int i = 0; i < OUTPUT_SIZE; ++i)
719 vm->output_is_partial[i] = 0;
720 vm->instr_count = 0;
721 vm->exit_code = 0;
722 vm->trace_enabled = 0;
723 vm->repl_on_error = 0;
724 vm->on_error_repl = NULL;
725
726 /* Debugger state */
727 vm->debug_step_mode = 0;
728 vm->debug_step_target_fp = -1;
729 vm->debug_step_start_ic = 0;
731 vm->break_count = 0;
732 for (int i = 0; i < (int)(sizeof(vm->breakpoints) / sizeof(vm->breakpoints[0])); ++i) {
733 vm->breakpoints[i].file = NULL;
734 vm->breakpoints[i].line = 0;
735 vm->breakpoints[i].active = 0;
736 }
737
738 for (int i = 0; i < MAX_GLOBALS; ++i)
739 vm->globals[i] = make_nil();
740}
741
742/* push a new frame, transferring ownership of args[] into frame->locals[0..argc-1] */
754static void vm_push_frame(VM *vm, Bytecode *fn, int argc, Value *args) {
755 if (vm->fp >= MAX_FRAMES - 1) {
756 fprintf(stderr, "Runtime error: too many frames\n");
757 exit(1);
758 }
759 Frame *f = &vm->frames[++vm->fp];
760 frame_init(f);
761 f->fn = fn;
762 f->ip = 0;
763 /* move args into locals 0..argc-1 */
764 for (int i = 0; i < argc && i < MAX_FRAME_LOCALS; ++i) {
765 f->locals[i] = args[i]; /* transfer ownership */
766 }
767}
768
769/* pop current frame and free its locals */
777static void vm_pop_frame(VM *vm) {
778 if (vm->fp < 0) {
779 fprintf(stderr, "Runtime error: pop frame with empty frame stack\n");
780 exit(1);
781 }
782 Frame *f = &vm->frames[vm->fp];
783 for (int i = 0; i < MAX_FRAME_LOCALS; ++i) {
784 free_value(f->locals[i]);
785 f->locals[i] = make_nil();
786 }
787 vm->fp--;
788}
789
798 for (int i = 0; i < vm->output_count; ++i) {
799 print_value(&vm->output[i]);
800 if (!vm->output_is_partial[i]) {
801 printf("\n");
802 }
803 }
804}
805
816void vm_run(VM *vm, Bytecode *entry) {
817 /* reset instruction count for this run */
818 vm->instr_count = 0;
819 vm->current_line = 1;
820 g_active_vm = vm;
821
822 /* set error trap if REPL-on-error is enabled */
823 if (vm->repl_on_error) {
824 int jcode = setjmp(g_vm_err_jmp);
825 if (jcode != 0) {
826 /* We got here from a trapped exit() in an error path */
827 fprintf(stderr, "Entering REPL due to runtime error (code %d)\n", jcode);
828 if (vm->on_error_repl) {
829 vm->on_error_repl(vm);
830 }
831 g_active_vm = NULL;
832 return;
833 }
834 }
835
836 /* start with entry frame (no args) */
837 vm_push_frame(vm, entry, 0, NULL);
838
839 while (vm->fp >= 0) {
840 Frame *f = &vm->frames[vm->fp];
841
842 /* Stop conditions at top of loop (stepping/finish) */
843 if (vm->on_error_repl) {
844 int should_stop = 0;
845 if (vm->debug_stop_requested) {
846 should_stop = 1;
847 } else if (vm->debug_step_mode == 1 && vm->instr_count > vm->debug_step_start_ic) { /* step */
848 should_stop = 1;
849 vm->debug_step_mode = 0;
850 } else if (vm->debug_step_mode == 2 && vm->instr_count > vm->debug_step_start_ic && vm->fp <= vm->debug_step_target_fp) { /* next */
851 should_stop = 1;
852 vm->debug_step_mode = 0;
853 } else if (vm->debug_step_mode == 3 && vm->fp < vm->debug_step_target_fp) { /* finish */
854 should_stop = 1;
855 vm->debug_step_mode = 0;
856 }
857 if (should_stop) {
859 fprintf(stderr, "Paused (debug)\n");
860 vm->on_error_repl(vm);
861 /* Frame pointer might have changed (reset/cont); refresh f */
862 if (vm->fp < 0) break;
863 f = &vm->frames[vm->fp];
864 }
865 }
866
867 if (f->ip < 0 || f->ip >= f->fn->instr_count) {
868 /* no more instructions in this frame -> implicit return nil */
869 Value nilv = make_nil();
870 vm_pop_frame(vm);
871 push_value(vm, nilv);
872 continue;
873 }
874
875 Instruction inst = f->fn->instructions[f->ip++];
876 vm->instr_count++; /* count each executed instruction */
877
878 if (vm->trace_enabled) {
879 const char *opname = (inst.op >= 0 && inst.op < (int)(sizeof(opcode_names) / sizeof(opcode_names[0])))
880 ? opcode_names[inst.op]
881 : "???";
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>";
884 /* Dump up to top 4 stack values */
885 int count = vm->sp + 1;
886 int start = count - 4;
887 if (start < 0) start = 0;
888 fprintf(stdout, "TRACE %s:%d %s ip=%d %-14s %d | stack[%d]=[", sfile, vm->current_line, fname, f->ip - 1, opname, inst.operand, count);
889 for (int i = start; i < count; ++i) {
890 char *sv = value_to_string_alloc(&vm->stack[i]);
891 if (!sv) sv = strdup("<oom>");
892 fprintf(stdout, "%s%s", sv, (i == count - 1 ? "" : ", "));
893 free(sv);
894 }
895 fprintf(stdout, "]\n");
896 }
897
898 /* Breakpoint hit detection: breakpoints are set on source_file:line via LINE markers */
899 if (vm->on_error_repl && inst.op == OP_LINE && vm->break_count > 0) {
900 const char *sfile = (f->fn && f->fn->source_file) ? f->fn->source_file : NULL;
901 int line = inst.operand;
902 for (int bi = 0; bi < vm->break_count; ++bi) {
903 if (!vm->breakpoints[bi].active) continue;
904 if (vm->breakpoints[bi].line != line) continue;
905 if (!sfile || !vm->breakpoints[bi].file) continue;
906 if (strcmp(vm->breakpoints[bi].file, sfile) != 0) continue;
907 fprintf(stderr, "Breakpoint %d hit at %s:%d\n", bi, sfile, line);
908 vm->on_error_repl(vm);
909 /* After returning, refresh frame pointer and frame */
910 if (vm->fp < 0) break;
911 f = &vm->frames[vm->fp];
912 break;
913 }
914 }
915
916 switch (inst.op) {
917/* All opcode handlers as .c includes */
918#include "vm/arithmetic/add.c"
919#include "vm/arithmetic/div.c"
920#include "vm/arithmetic/mul.c"
921#include "vm/arithmetic/sub.c"
922
923#include "vm/arrays/apop.c"
924#include "vm/arrays/clear.c"
925#include "vm/arrays/contains.c"
926#include "vm/arrays/enumerate.c"
927#include "vm/arrays/index_get.c"
928#include "vm/arrays/index_of.c"
929#include "vm/arrays/index_set.c"
930#include "vm/arrays/insert.c"
931#include "vm/arrays/join.c"
933#include "vm/arrays/push.c"
934#include "vm/arrays/remove.c"
935#include "vm/arrays/set.c"
936#include "vm/arrays/slice.c"
937#include "vm/arrays/zip.c"
938
939/* Bitwise and shifts/rotates */
940#include "vm/bitwise/band.c"
941#include "vm/bitwise/bnot.c"
942#include "vm/bitwise/bor.c"
943#include "vm/bitwise/bxor.c"
944#include "vm/bitwise/rol.c"
945#include "vm/bitwise/ror.c"
946#include "vm/bitwise/shl.c"
947#include "vm/bitwise/shr.c"
948
949#include "vm/core/call.c"
950#include "vm/core/dup.c"
951#include "vm/core/exit.c"
952#include "vm/core/halt.c"
953#include "vm/core/jump.c"
955#include "vm/core/load_const.c"
956#include "vm/core/load_global.c"
957#include "vm/core/load_local.c"
958#include "vm/core/nop.c"
959#include "vm/core/pop.c"
960#include "vm/core/return.c"
962#include "vm/core/store_local.c"
963#include "vm/core/swap.c"
964#include "vm/core/throw.c"
965#include "vm/core/try_pop.c"
966#include "vm/core/try_push.c"
967
968#include "vm/io/input_line.c"
969#include "vm/io/read_file.c"
970#include "vm/io/write_file.c"
971
972#include "vm/logic/and.c"
973#include "vm/logic/eq.c"
974#include "vm/logic/gt.c"
975#include "vm/logic/gte.c"
976#include "vm/logic/lt.c"
977#include "vm/logic/lte.c"
978#include "vm/logic/neq.c"
979#include "vm/logic/not.c"
980#include "vm/logic/or.c"
981
982#include "vm/maps/has_key.c"
983#include "vm/maps/keys.c"
984#include "vm/maps/make_map.c"
985#include "vm/maps/values.c"
986
987#include "vm/math/abs.c"
988#include "vm/math/ceil.c"
989#include "vm/math/clamp.c"
990#include "vm/math/cos.c"
991#include "vm/math/exp.c"
992#include "vm/math/floor.c"
993#include "vm/math/fmax.c"
994#include "vm/math/fmin.c"
995#include "vm/math/gcd.c"
996#include "vm/math/isqrt.c"
997#include "vm/math/lcm.c"
998#include "vm/math/log.c"
999#include "vm/math/log10.c"
1000#include "vm/math/max.c"
1001#include "vm/math/min.c"
1002#include "vm/math/mod.c"
1003#include "vm/math/pow.c"
1004#include "vm/math/random_int.c"
1005#include "vm/math/random_seed.c"
1006#include "vm/math/round.c"
1007#include "vm/math/sign.c"
1008#include "vm/math/sin.c"
1009#include "vm/math/sqrt.c"
1010#include "vm/math/tan.c"
1011#include "vm/math/trunc.c"
1012
1013/* Rust FFI demo opcode(s) */
1014#include "vm/rust/get_sp.c"
1015#include "vm/rust/hello.c"
1016#include "vm/rust/hello_args.c"
1018#include "vm/rust/set_exit.c"
1019
1020#include "vm/os/clock_mono_ms.c"
1021#include "vm/os/date_format.c"
1022#include "vm/os/env.c"
1023#include "vm/os/env_all.c"
1024#include "vm/os/fun_version.c"
1025#include "vm/os/proc_run.c"
1026#include "vm/os/proc_system.c"
1027#include "vm/os/random_number.c"
1028#include "vm/os/serial_close.c"
1029#include "vm/os/serial_config.c"
1030#include "vm/os/serial_open.c"
1031#include "vm/os/serial_recv.c"
1032#include "vm/os/serial_send.c"
1033#include "vm/os/sleep_ms.c"
1034#include "vm/os/thread_join.c"
1035#include "vm/os/thread_spawn.c"
1036#include "vm/os/time_now_ms.c"
1037
1038/* Socket ops */
1039#include "vm/os/socket_close.c"
1040#include "vm/os/socket_recv.c"
1041#include "vm/os/socket_send.c"
1047
1048/* Async-friendly FD helpers (UNIX) */
1050#include "vm/os/fd_poll_read.c"
1051#include "vm/os/fd_poll_write.c"
1052
1053#ifdef FUN_WITH_PCSC
1054#include "vm/pcsc/connect.c"
1055#include "vm/pcsc/disconnect.c"
1056#include "vm/pcsc/establish.c"
1057#include "vm/pcsc/list_readers.c"
1058#include "vm/pcsc/release.c"
1059#include "vm/pcsc/transmit.c"
1060#endif
1061
1062/* JSON ops (implemented in jsonc.c, included above) */
1063#ifdef FUN_WITH_JSON
1064#include "vm/json/from_file.c"
1065#include "vm/json/parse.c"
1066#include "vm/json/stringify.c"
1067#include "vm/json/to_file.c"
1068#endif
1069
1070/* XML ops (libxml2) */
1071#ifdef FUN_WITH_XML2
1072#include "vm/xml/name.c"
1073#include "vm/xml/parse.c"
1074#include "vm/xml/root.c"
1075#include "vm/xml/text.c"
1076#endif
1077
1078/* INI ops (iniparser 4.2.6) */
1079#ifdef FUN_WITH_INI
1080#include "vm/ini/free.c"
1081#include "vm/ini/get_bool.c"
1082#include "vm/ini/get_double.c"
1083#include "vm/ini/get_int.c"
1084#include "vm/ini/get_string.c"
1085#include "vm/ini/load.c"
1086#include "vm/ini/save.c"
1087#include "vm/ini/set.c"
1088#include "vm/ini/unset.c"
1089#else
1090#include "vm/ini/stubs.c"
1091#endif
1092
1093/* CURL ops */
1094#ifdef FUN_WITH_CURL
1095#include "vm/curl/download.c"
1096#include "vm/curl/get.c"
1097#include "vm/curl/post.c"
1098#endif
1099
1100/* OpenSSL ops (md5/sha256/sha512/ripemd160) */
1101#ifdef FUN_WITH_OPENSSL
1102#include "vm/openssl/md5.c"
1103#include "vm/openssl/ripemd160.c"
1104#include "vm/openssl/sha256.c"
1105#include "vm/openssl/sha512.c"
1106#endif
1107
1108
1109/* Tcl/Tk support removed */
1110
1111/* Notcurses TUI ops removed */
1112
1113/* SQLite ops */
1114#ifdef FUN_WITH_SQLITE
1115#include "vm/sqlite/close.c"
1116#include "vm/sqlite/exec.c"
1117#include "vm/sqlite/open.c"
1118#include "vm/sqlite/query.c"
1119#endif
1120
1121/* C++ demo opcodes (guarded) */
1122#if defined(FUN_WITH_CPP)
1123 case OP_CPP_ADD: {
1124 int rc = fun_op_cpp_add(vm);
1125 if (rc != 0) {
1126 vm_raise_error(vm, "cpp_add failed");
1127 }
1128 break;
1129 }
1130#else
1131 case OP_CPP_ADD: {
1132 vm_raise_error(vm, "CPP support is not enabled (build with -DFUN_WITH_CPP=ON)");
1133 break;
1134 }
1135#endif
1136
1137/* libsql support removed */
1138
1139/* PCRE2 ops */
1140#ifdef FUN_WITH_PCRE2
1141#include "vm/pcre2/findall.c"
1142#include "vm/pcre2/match.c"
1143#include "vm/pcre2/test.c"
1144#endif
1145
1146#include "vm/strings/find.c"
1150#include "vm/strings/split.c"
1151#include "vm/strings/substr.c"
1152
1153#include "vm/cast.c"
1154#include "vm/echo.c"
1155#include "vm/len.c"
1156#include "vm/line.c"
1157#include "vm/os/list_dir.c"
1158#include "vm/print.c"
1159#include "vm/sclamp.c"
1160#include "vm/to_number.c"
1161#include "vm/to_string.c"
1162#include "vm/typeof.c"
1163#include "vm/uclamp.c"
1164
1165 default:
1166 if (!opcode_is_valid(inst.op)) {
1167 fprintf(stderr, "Runtime error: unknown opcode %d (%s) at instruction %d\n",
1168 inst.op,
1169 (inst.op >= 0 && inst.op < sizeof(opcode_names) / sizeof(opcode_names[0]))
1170 ? opcode_names[inst.op]
1171 : "???",
1172 f->ip - 1);
1173 exit(1);
1174 }
1175 break;
1176 }
1177
1178 /* Stream console output in realtime for scripts:
1179 * When PRINT/ECHO pushed items into the VM's output buffer, flush them
1180 * immediately to stdout and clear the buffer to avoid end-of-run bursts.
1181 * This keeps REPL compatibility (REPL still prints after each submit),
1182 * while regular script execution shows progress bars live.
1183 */
1184 if (inst.op == OP_PRINT || inst.op == OP_ECHO) {
1185 vm_print_output(vm);
1186 vm_clear_output(vm);
1187 fflush(stdout);
1188 }
1189 }
1190 g_active_vm = NULL;
1191}
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.
Value out
Definition apop.c:38
Implements the OP_SET opcode for setting elements in arrays in the VM.
Implements the OP_BAND opcode bitwise AND (uint32).
uint32_t r
Definition band.c:33
Implements the OP_BNOT opcode bitwise NOT (uint32).
Implements the OP_BOR opcode bitwise OR (uint32).
Implements the OP_BXOR opcode bitwise XOR (uint32).
@ OP_CPP_ADD
Definition bytecode.h:285
@ OP_LINE
Definition bytecode.h:67
@ OP_ECHO
Definition bytecode.h:64
@ OP_PRINT
Definition bytecode.h:63
Implements the OP_CALL opcode for function calls in the VM.
Value * args
Definition call.c:31
Implements the OP_CAST opcode for converting a value to a target type.
Value v
Definition cast.c:22
char target[32]
Definition cast.c:28
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 OP_DATE_FORMAT to format an epoch milliseconds timestamp using strftime.
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.
vm exit_code
Definition exit.c:37
Implements the OP_EXP opcode using C99 math.h exp().
Implements OP_FD_POLL_READ to check if a file descriptor is readable.
int rc
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_INPUT_LINE opcode for interactive console input.
char * buf
Definition input_line.c:103
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.
free(vals)
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.
int count
Definition parser.c:266
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.
int code
Definition proc_system.c:31
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.
FILE * f
Definition read_file.c:38
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.
long t
Definition sleep_ms.c:32
Implements the OP_SLICE opcode for array slicing in the VM.
Value start
Definition slice.c:34
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.
vm globals[idx]
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.
const char * source_file
Definition bytecode.h:302
Call frame representing one active function invocation.
Definition vm.h:93
Bytecode * fn
Definition vm.h:94
OpCode op
Definition bytecode.h:289
int32_t operand
Definition bytecode.h:290
The Fun virtual machine state.
Definition vm.h:110
int sp
Definition vm.h:112
long long instr_count
Definition vm.h:123
int debug_step_target_fp
Definition vm.h:135
Value output[OUTPUT_SIZE]
Definition vm.h:119
int line
Definition vm.h:141
int current_line
Definition vm.h:125
int repl_on_error
Definition vm.h:130
int fp
Definition vm.h:115
int output_is_partial[OUTPUT_SIZE]
Definition vm.h:121
int(* on_error_repl)(struct VM *vm)
Definition vm.h:131
int debug_stop_requested
Definition vm.h:137
int break_count
Definition vm.h:144
int active
Definition vm.h:142
int trace_enabled
Definition vm.h:129
int exit_code
Definition vm.h:127
int output_count
Definition vm.h:120
struct VM::@204221333366357065317066305241116055104274166224 breakpoints[64]
char * file
Definition vm.h:140
Value globals[MAX_GLOBALS]
Definition vm.h:117
int debug_step_mode
Definition vm.h:134
long long debug_step_start_ic
Definition vm.h:136
Frame frames[MAX_FRAMES]
Definition vm.h:114
Value stack[STACK_SIZE]
Definition vm.h:111
Tagged union representing a Fun value.
Definition value.h:68
ValueType type
Definition value.h:69
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.
vm stack[vm->sp]
Definition swap.c:32
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.
Definition value.c:552
Value make_nil(void)
Construct a nil Value.
Definition value.c:126
Value make_string(const char *s)
Construct a string Value by duplicating the given C string.
Definition value.c:95
void free_value(Value v)
Free dynamic storage owned by a Value.
Definition value.c:517
char * value_to_string_alloc(const Value *v)
Allocate a printable C string for a Value.
Definition value.c:641
Value make_int(int64_t v)
Construct a Value representing a 64-bit integer.
Definition value.c:51
Defines the Value type and associated functions for the Fun VM.
ValueType
Enumeration of all runtime value types supported by Fun.
Definition value.h:50
@ VAL_BOOL
Definition value.h:52
@ VAL_ARRAY
Definition value.h:55
@ VAL_MAP
Definition value.h:56
@ VAL_STRING
Definition value.h:53
@ VAL_FUNCTION
Definition value.h:54
@ VAL_NIL
Definition value.h:57
@ VAL_INT
Definition value.h:51
@ VAL_FLOAT
Definition value.h:58
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.
Definition vm.c:659
size_t vm_offset_of_globals(void)
Obtain offsetof(VM, globals) for FFI struct field access.
Definition vm.c:686
size_t vm_value_sizeof(void)
Return sizeof(Value) for external FFI consumers.
Definition vm.c:640
void vm_raise_error(VM *vm, const char *msg)
Raise a runtime error inside the VM, honoring try/catch/finally.
Definition vm.c:248
void vm_debug_request_finish(VM *vm)
Request finish (run until the current frame returns).
Definition vm.c:540
void vm_debug_clear_breakpoints(VM *vm)
Remove all breakpoints from the VM.
Definition vm.c:492
void vm_debug_request_continue(VM *vm)
Resume normal execution (clear stepping state and stop flag).
Definition vm.c:551
void vm_debug_request_step(VM *vm)
Request single-step execution (stop after next instruction).
Definition vm.c:517
int vm_debug_delete_breakpoint(VM *vm, int id)
Delete a breakpoint by id.
Definition vm.c:472
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:621
void vm_init(VM *vm)
Initialize a VM instance to its default state.
Definition vm.c:714
void vm_debug_reset(VM *vm)
Reset debugger state: breakpoints and stepping controls.
Definition vm.c:429
void vm_debug_request_next(VM *vm)
Request step-over (stop after next instruction in current frame).
Definition vm.c:528
#define fprintf
Definition vm.c:200
size_t vm_offset_of_stack(void)
Obtain offsetof(VM, stack) for FFI struct field access.
Definition vm.c:677
size_t vm_offset_of_sp(void)
Obtain offsetof(VM, sp) for FFI struct field access.
Definition vm.c:668
#define exit(code)
Definition vm.c:230
void vm_free(VM *vm)
Free resources owned directly by the VM structure.
Definition vm.c:367
size_t vm_sizeof(void)
Return sizeof(VM) for external FFI consumers.
Definition vm.c:631
int vm_debug_add_breakpoint(VM *vm, const char *file, int line)
Add a source breakpoint.
Definition vm.c:453
void vm_clear_output(VM *vm)
Clear the VM's buffered output values and partial flags.
Definition vm.c:349
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.
Definition vm.c:382
void * vm_as_mut_ptr(VM *vm)
Cast the VM pointer to an opaque mutable void* (unsafe FFI helper).
Definition vm.c:650
void vm_debug_list_breakpoints(VM *vm)
Print active breakpoints to stdout.
Definition vm.c:501
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.
Definition vm.c:797
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:598
void vm_dump_globals(VM *vm)
Print all non-nil global variables to stdout for debugging.
Definition vm.c:408
Core virtual machine data structures and public VM API.
#define MAX_GLOBALS
Definition vm.h:34
int fun_op_cpp_add(struct VM *vm)
Add two 64-bit integers from the VM stack and push the sum.
Definition add.cpp:47
#define MAX_FRAMES
Definition vm.h:26
#define STACK_SIZE
Definition vm.h:42
#define OUTPUT_SIZE
Definition vm.h:38
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...
#define MAX_FRAME_LOCALS
Definition vm.h:30
Implements the OP_WRITE_FILE opcode for writing to a file in the VM.
Value path
Definition write_file.c:33
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.