From d79815e366bc318f8fe28599e86651f4bd6e6134 Mon Sep 17 00:00:00 2001 From: hanez Date: Thu, 29 Jan 2026 05:09:15 +0100 Subject: [PATCH] What is CPP? Holy shit... (0.38.4) --- CMakeLists.txt | 45 ++++++++++++++++++++++++++--- examples/cpp_add.fun | 28 ++++++++++++++++++ examples/rust_hello_args_return.fun | 0 examples/rust_vm_access.fun | 2 +- make | 27 +++++++++++++++++ src/bytecode.h | 3 ++ src/parser.c | 10 +++++++ src/vm.c | 16 ++++++++++ src/vm.h | 5 ++++ src/vm/cpp/add.cpp | 28 ++++++++++++++++++ 10 files changed, 159 insertions(+), 5 deletions(-) create mode 100755 examples/cpp_add.fun mode change 100644 => 100755 examples/rust_hello_args_return.fun mode change 100644 => 100755 examples/rust_vm_access.fun create mode 100644 src/vm/cpp/add.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 25f330e..dbf627a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(fun VERSION 0.38.3 LANGUAGES C) +project(fun VERSION 0.38.4 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) @@ -19,14 +19,21 @@ else() set(_FUN_DEBUG_STATE "DISABLED") endif() -if(FUN_WITH_RUST) - set(_FUN_WITH_RUST_STATE "ENABLED") +if(FUN_WITH_CPP) + set(_FUN_WITH_CPP_STATE "ENABLED") else() - set(_FUN_WITH_RUST_STATE "DISABLED") + set(_FUN_WITH_CPP_STATE "DISABLED") +endif() + +if(FUN_WITH_RUST) + set(_FUN_WITH_RUST_STATE "ENABLED") +else() + set(_FUN_WITH_RUST_STATE "DISABLED") endif() message(STATUS "==== Fun build options ====") message(STATUS " FUN_DEBUG: ${_FUN_DEBUG_STATE}") +message(STATUS " FUN_WITH_CPP: ${_FUN_WITH_CPP_STATE}") message(STATUS " FUN_WITH_RUST: ${_FUN_WITH_RUST_STATE}") message(STATUS "===========================") @@ -98,6 +105,36 @@ if(FUN_WITH_RUST) endif() endif() +# --- Optional C++ opcode demo --- +option(FUN_WITH_CPP "Build and link C++ opcode demo" OFF) +if(FUN_WITH_CPP) + enable_language(CXX) + + add_library(fun_cpp_ops STATIC + src/vm/cpp/add.cpp + ) + + # Compile definitions propagate to C targets that dispatch the opcode + target_compile_definitions(fun_cpp_ops PUBLIC FUN_WITH_CPP) + target_include_directories(fun_cpp_ops PUBLIC ${CMAKE_SOURCE_DIR}/src) + + # Link the C++ ops into the core so executables can call them + if(TARGET fun_core) + target_link_libraries(fun_core PRIVATE fun_cpp_ops) + target_compile_definitions(fun_core PRIVATE FUN_WITH_CPP) + endif() + + # Also propagate to test targets (if they might use it) + if(TARGET test_opcodes) + target_link_libraries(test_opcodes PRIVATE fun_cpp_ops) + target_compile_definitions(test_opcodes PRIVATE FUN_WITH_CPP) + endif() + + if(TARGET fun) + target_compile_definitions(fun PRIVATE FUN_WITH_CPP) + endif() +endif() + # --- Size optimization for final binaries (Release) --- # Enable function/data sectioning for better GC; safe for all configs. add_compile_options(-ffunction-sections -fdata-sections) diff --git a/examples/cpp_add.fun b/examples/cpp_add.fun new file mode 100755 index 0000000..52a5dfa --- /dev/null +++ b/examples/cpp_add.fun @@ -0,0 +1,28 @@ +#!/usr/bin/env fun + +/* + * This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2026 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2026-01-29 + */ + +/* +Build: + cmake -S . -B build_debug -DFUN_WITH_CPP=ON + cmake --build build_debug --target fun +Run: + build_debug/fun examples/cpp_add.fun +*/ + +number x = cpp_add(2, 40) +//print("typeof(x): " + typeof(x)) +print(x) + +/* Expected output: +42 +*/ diff --git a/examples/rust_hello_args_return.fun b/examples/rust_hello_args_return.fun old mode 100644 new mode 100755 diff --git a/examples/rust_vm_access.fun b/examples/rust_vm_access.fun old mode 100644 new mode 100755 index b4e2474..99da016 --- a/examples/rust_vm_access.fun +++ b/examples/rust_vm_access.fun @@ -23,7 +23,7 @@ print("[Rust VM access demo]") print("vm.sp (from Rust) = " + to_string(rust_get_sp())) /* Write vm.exit_code via Rust (not directly observable without VM inspection) */ -print("Setting vm.exit_code to 5 via Rust...") +print("Setting vm.exit_code to 42 via Rust...") rust_set_exit(42) print("Now exiting...") diff --git a/make b/make index 18c5969..573ba26 100755 --- a/make +++ b/make @@ -31,6 +31,7 @@ if [ "$target" = "all" ]; then -DFUN_WITH_TCLTK=ON \ -DFUN_WITH_INI=ON \ -DFUN_WITH_NOTCURSES=ON \ + -DFUN_WITH_CPP=ON \ && cmake --build build --target fun elif [ "$target" = "all_debug" ]; then rm -rf build \ @@ -46,6 +47,7 @@ elif [ "$target" = "all_debug" ]; then -DFUN_WITH_TCLTK=ON \ -DFUN_WITH_INI=ON \ -DFUN_WITH_NOTCURSES=ON \ + -DFUN_WITH_CPP=ON \ -DFUN_DEBUG=ON \ && cmake --build build --target fun elif [ "$target" = "alpine" ]; then @@ -59,7 +61,29 @@ elif [ "$target" = "alpine" ]; then -DFUN_WITH_XML2=ON \ -DFUN_WITH_JSON=ON \ -DFUN_WITH_INI=ON \ + -DFUN_WITH_CPP=ON \ && cmake --build build --target fun +elif [ "$target" = "cpp_all" ]; then + rm -rf build \ + && cmake -S . -B build \ + -DFUN_WITH_PCSC=ON \ + -DFUN_WITH_REPL=ON \ + -DFUN_WITH_LIBSQL=ON \ + -DFUN_WITH_SQLITE=ON \ + -DFUN_WITH_CURL=ON \ + -DFUN_WITH_PCRE2=ON \ + -DFUN_WITH_XML2=ON \ + -DFUN_WITH_JSON=ON \ + -DFUN_WITH_TCLTK=ON \ + -DFUN_WITH_INI=ON \ + -DFUN_WITH_NOTCURSES=ON \ + -DFUN_WITH_CPP=ON \ + && cmake --build build --target fun + elif [ "$target" = "cpp_minimal" ]; then + rm -rf build \ + && cmake -S . -B build \ + -DFUN_WITH_CPP=ON \ + && cmake --build build --target fun elif [ "$target" = "debug" ]; then rm -rf build \ && cmake -S . -B build \ @@ -102,6 +126,7 @@ elif [ "$target" = "rust_all" ]; then -DFUN_WITH_TCLTK=ON \ -DFUN_WITH_INI=ON \ -DFUN_WITH_RUST=ON \ + -DFUN_WITH_CPP=ON \ -DFUN_DEBUG=OFF \ && cmake --build build --target fun elif [ "$target" = "rust_minimal" ]; then @@ -115,6 +140,8 @@ else echo " - all"; echo " - all_debug"; echo " - alpine"; + echo " - cpp_all"; + echo " - cpp_minimal"; echo " - debug"; echo " - freebsd"; echo " - install"; diff --git a/src/bytecode.h b/src/bytecode.h index 9731664..5eb3de4 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -270,6 +270,9 @@ typedef enum { OP_RUST_GET_SP, // pushes current VM stack pointer (via Rust reading VM memory) OP_RUST_SET_EXIT, // pops int and sets VM exit_code (via Rust writing VM memory) + // C++ demo opcode(s) + OP_CPP_ADD, // pops b, a; pushes (a + b) + /* Notcurses TUI (optional) */ OP_NC_INIT, // initializes Notcurses; returns 1 on success, 0 on failure OP_NC_SHUTDOWN, // shuts down Notcurses; returns 0 diff --git a/src/parser.c b/src/parser.c index 14a44d5..ad8dd1b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -824,6 +824,16 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos) free(name); return 1; } + if (strcmp(name, "cpp_add") == 0) { + (*pos)++; /* '(' */ + if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "cpp_add expects (a:int, b:int)"); free(name); return 0; } + if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "cpp_add expects two arguments"); free(name); return 0; } + if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "cpp_add expects (a:int, b:int)"); free(name); return 0; } + if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after cpp_add args"); free(name); return 0; } + bytecode_add_instruction(bc, OP_CPP_ADD, 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; } diff --git a/src/vm.c b/src/vm.c index 3464f60..c8f42e4 100644 --- a/src/vm.c +++ b/src/vm.c @@ -897,6 +897,22 @@ void vm_run(VM *vm, Bytecode *entry) { #include "vm/sqlite/query.c" #endif + /* C++ demo opcodes (guarded) */ + #if defined(FUN_WITH_CPP) + case OP_CPP_ADD: { + int rc = fun_op_cpp_add(vm); + if (rc != 0) { + vm_raise_error(vm, "cpp_add failed"); + } + break; + } + #else + case OP_CPP_ADD: { + vm_raise_error(vm, "CPP support is not enabled (build with -DFUN_WITH_CPP=ON)"); + break; + } + #endif + /* libsql ops (independent) */ #ifdef FUN_WITH_LIBSQL #include "vm/libsql/open.c" diff --git a/src/vm.h b/src/vm.h index 05a94f2..fdca9b6 100644 --- a/src/vm.h +++ b/src/vm.h @@ -58,6 +58,8 @@ static const char *opcode_names[] = { "FMIN","FMAX", /* Rust FFI demo */ "RUST_HELLO","RUST_HELLO_ARGS","RUST_HELLO_ARGS_RETURN","RUST_GET_SP","RUST_SET_EXIT", + /* C++ demo */ + "CPP_ADD", /* Notcurses TUI (optional) */ "NC_INIT","NC_SHUTDOWN","NC_CLEAR","NC_DRAW_TEXT","NC_GETCH" }; @@ -165,6 +167,9 @@ char *fun_rust_echo_string(const char *input); /* Free a C string previously returned by fun_rust_echo_string. */ void fun_rust_string_free(char *ptr); +/* C++ demo opcode entry point (C ABI) */ +int fun_op_cpp_add(struct VM *vm); + /* --- Extended C ABI for Rust to access VM internals (unsafe) --- */ /* Size helpers for Rust side to compute offsets and do pointer math */ size_t vm_sizeof(void); diff --git a/src/vm/cpp/add.cpp b/src/vm/cpp/add.cpp new file mode 100644 index 0000000..9f9f493 --- /dev/null +++ b/src/vm/cpp/add.cpp @@ -0,0 +1,28 @@ +/* +* This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2026 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2026-01-29 + */ + +/* + * Minimal C++ opcode for Fun VM — cpp_add + * Build is gated by -DFUN_WITH_CPP=ON (see CMake). + */ + +#include + +extern "C" { +#include "vm.h" // C header; provides VM, vm_pop_i64, vm_push_i64 +} + +extern "C" int fun_op_cpp_add(VM *vm) { + int64_t b = vm_pop_i64(vm); + int64_t a = vm_pop_i64(vm); + vm_push_i64(vm, a + b); + return 0; // success +}