1
0
Fork 0
forked from fun/fun

Added Rust support to the Fun core. (0.38.0)

This commit is contained in:
Johannes Findeisen 2026-01-27 04:26:54 +01:00
commit 149e135318
12 changed files with 299 additions and 1 deletions

View file

@ -206,6 +206,7 @@ static const char *opcode_name(OpCode op) {
case OP_SIGN: return "SIGN";
case OP_FMIN: return "FMIN";
case OP_FMAX: return "FMAX";
case OP_RUST_HELLO: return "RUST_HELLO";
default: return "???";
}
}

View file

@ -263,6 +263,9 @@ typedef enum {
OP_FMIN, // pops b, a (int/float); pushes fmin(a,b) (NaN handling per C99)
OP_FMAX, // pops b, a (int/float); pushes fmax(a,b) (NaN handling per C99)
// Rust FFI demo opcode(s)
OP_RUST_HELLO, // pushes string returned from Rust (hello world)
/* Notcurses TUI (optional) */
OP_NC_INIT, // initializes Notcurses; returns 1 on success, 0 on failure
OP_NC_SHUTDOWN, // shuts down Notcurses; returns 0

View file

@ -786,6 +786,13 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
free(name);
return 1;
}
if (strcmp(name, "rust_hello") == 0) {
(*pos)++; /* '(' */
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "rust_hello expects ()"); free(name); return 0; }
bytecode_add_instruction(bc, OP_RUST_HELLO, 0);
free(name);
return 1;
}
if (strcmp(name, "os_list_dir") == 0) {
(*pos)++; /* '(' */
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "os_list_dir expects (path)"); free(name); return 0; }

16
src/rust/Cargo.toml Normal file
View file

@ -0,0 +1,16 @@
[package]
name = "hello-c-world"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["staticlib"]
[profile.release]
panic = "abort"
# Optimize for minimal size
opt-level = "z"
codegen-units = 1
lto = true
# If Cargo is new enough, this strips symbols from Rust objects
strip = "symbols"

44
src/rust/src/lib.rs Normal file
View file

@ -0,0 +1,44 @@
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the Apache-2.0 license.
* https://opensource.org/license/apache-2-0
*
* Added: 2026-01-27
*/
#![no_std]
#[repr(C)]
pub struct Vm;
extern "C" {
fn vm_pop_i64(vm: *mut Vm) -> i64;
fn vm_push_i64(vm: *mut Vm, v: i64);
}
// Submodule with additional Rust VM math ops (exported via C ABI)
pub mod vm;
#[no_mangle]
pub extern "C" fn fun_op_radd(vm: *mut Vm) -> i32 {
unsafe {
let b = vm_pop_i64(vm);
let a = vm_pop_i64(vm);
vm_push_i64(vm, a + b);
}
0
}
#[no_mangle]
pub extern "C" fn fun_rust_get_string() -> *const core::ffi::c_char {
b"Hello from Rust ops!\0".as_ptr() as *const _
}
// Minimal panic handler for no_std; abort behavior requested via Cargo profile
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}

View file

@ -46,6 +46,29 @@ int main() {
}
vm_clear_output(&vm);
/* --- Rust FFI demo: call a Rust opcode and string function --- */
#ifdef FUN_WITH_RUST
extern int fun_op_radd(VM *vm);
extern const char *fun_rust_get_string(void);
printf("=== Rust FFI demo ===\n");
const char *rs = fun_rust_get_string();
if (rs) {
printf("Rust says: %s\n", rs);
}
/* prepare stack: push 10 and 32, then call Rust add -> expect 42 */
vm_push_i64(&vm, 10);
vm_push_i64(&vm, 32);
int rc = fun_op_radd(&vm);
printf("fun_op_radd rc=%d\n", rc);
long long sum = (long long)vm_pop_i64(&vm);
printf("Rust op result: %lld\n", sum);
#else
printf("=== Rust FFI demo (disabled; build with -DFUN_WITH_RUST=ON) ===\n");
#endif
vm_free(&vm);
bytecode_free(bc);
return 0;

View file

@ -466,6 +466,28 @@ static Value pop_value(VM *vm) {
return vm->stack[vm->sp--]; /* caller owns returned Value */
}
/* --- C ABI helpers for Rust FFI --- */
int64_t vm_pop_i64(VM *vm) {
Value v = pop_value(vm);
int64_t out = 0;
if (v.type == VAL_INT) {
out = v.i;
} else if (v.type == VAL_FLOAT) {
out = (int64_t) v.d;
} else {
fprintf(stderr, "Runtime type error: expected int/float on stack, got %s\n", value_type_name(v.type));
free_value(v);
exit(1);
}
/* free any dynamic payload (no-op for int/float) */
free_value(v);
return out;
}
void vm_push_i64(VM *vm, int64_t v) {
push_value(vm, make_int(v));
}
static void frame_init(Frame *f) {
f->fn = NULL;
f->ip = 0;
@ -734,6 +756,9 @@ void vm_run(VM *vm, Bytecode *entry) {
#include "vm/math/isqrt.c"
#include "vm/math/sign.c"
/* Rust FFI demo opcode(s) */
#include "vm/rust/hello.c"
#include "vm/os/env.c"
#include "vm/os/env_all.c"
#include "vm/os/fun_version.c"

View file

@ -54,6 +54,9 @@ static const char *opcode_names[] = {
"SERIAL_OPEN","SERIAL_CONFIG","SERIAL_SEND","SERIAL_RECV","SERIAL_CLOSE",
"TK_EVAL","TK_RESULT","TK_LOOP","TK_WM_TITLE","TK_LABEL","TK_BUTTON","TK_PACK",
"TRY_PUSH","TRY_POP","THROW",
"FMIN","FMAX",
/* Rust FFI demo */
"RUST_HELLO",
/* Notcurses TUI (optional) */
"NC_INIT","NC_SHUTDOWN","NC_CLEAR","NC_DRAW_TEXT","NC_GETCH"
};
@ -143,4 +146,16 @@ static inline int opcode_is_valid(int op) {
return op >= OP_NOP && op <= OP_NC_GETCH; // all current opcodes (including optional NC_*)
}
/* --- Minimal C ABI helpers for FFI (Rust opcode experiments) --- */
/* Pop an int64 from VM stack (errors if not an int/float); returns integer-converted value. */
int64_t vm_pop_i64(VM *vm);
/* Push an int64 onto VM stack. */
void vm_push_i64(VM *vm, int64_t v);
/* Example Rust-implemented opcode (adds top two ints on stack) */
int fun_op_radd(VM *vm);
/* Example Rust function returning a demo C string (null-terminated). */
const char *fun_rust_get_string(void);
#endif

27
src/vm/rust/hello.c Normal file
View file

@ -0,0 +1,27 @@
/*
* This file is part of the Fun programming language.
* https://fun-lang.xyz/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the Apache-2.0 license.
* https://opensource.org/license/apache-2-0
*
* Added: 2026-01-27
*/
/**
* Rust FFI demo opcode: OP_RUST_HELLO
* When executed, it pushes a hello string returned by Rust onto the VM stack.
*/
case OP_RUST_HELLO: {
#ifdef FUN_WITH_RUST
const char *s = fun_rust_get_string();
if (!s) s = "";
push_value(vm, make_string(s));
#else
vm_raise_error(vm, "RUST_HELLO requires FUN_WITH_RUST=ON at build time");
push_value(vm, make_nil());
#endif
break;
}