Compiler: $EXTERN pragma for calling C functions from BASIC (Level 2 FFI) - #1
Conversation
…FFI) Add a '$EXTERN NAME(ARGTYPES) AS RET pragma so compiled BASIC can call C functions directly, the natural follow-up to Level 1 (--emit-obj / --main-name). The pragma is an apostrophe comment, so the interpreter ignores it while the compiler registers it. Map INTEGER/SINGLE/DOUBLE/STRING to int16_t/float/double/const char* at the boundary: a string argument crosses as a temporary C copy that is freed after the call, and a string return is copied into the pool. The call name is matched case-insensitively but emitted as the C symbol with the case written in the pragma. Names are recognized before parse_var() truncates identifiers to two significant characters, so multi-character C function names work. A string return that aliases a char* argument is copied before the argument temporaries are freed, which avoids a use-after-free. Over-supplied arguments are consumed without desyncing the token stream and warn on arity mismatch. Docs: getting-started.md "Foreign Functions from BASIC". Test: tests/run_ffi_test.sh, wired into CI. 63/63 compiler, 72/72 interpreter, 68/68 compat still pass. Also refile the roadmap "Next Up" backlog as git-bug issues and prune docs/roadmap.md to point at git-bug as the source of truth for planned work.
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThis PR implements Level 2 cross-language FFI, enabling BASIC programs to call C/Fortran functions via ChangesCross-Language FFI (Level 2)
🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Adds Level 2 cross-language linking: a
'$EXTERN NAME(ARGTYPES) AS RETpragma lets compiled BASIC call C functions directly, the natural follow-up to Level 1 (--emit-obj/--main-name). The pragma is an apostrophe comment, so the interpreter ignores it while the compiler registers it.INTEGER/SINGLE/DOUBLE/STRINGmap toint16_t/float/double/const char *at the boundary. The call name is matched case-insensitively but emitted as the C symbol with the case written in the pragma, and is recognized beforeparse_var()truncates identifiers to two significant characters (so multi-character C names work). The host project supplies the symbols at link time; from Fortran, declare the routinebind(c).Implementation
Compiler-only (
src/analysis.c,src/codegen.c); the interpreter is untouched.$EXTERNdeclarations and keeps their names out of the variable census.peek_full_ident()recognizes full extern names before truncation;emit_extern_call()emits a statement-expression with BASIC↔C coercion; prototypes are emitted in the C prologue.emit_atom/emit_str_atom/peek_expr_type/emit_printroute extern calls correctly.Review-driven hardening
A
codex+agyreview caught three bugs the smoke test missed, all fixed here:char *argument is now copied into the pool before the argument temporaries are freed (avoids a use-after-free).Remaining edge cases (INSTR/WRITE dispatch sites, suffix/name validation) are tracked in git-bug
8329647.Tests
tests/run_ffi_test.sh(new, wired into CI) builds a BASIC program that calls C functions, links against a companion C object, and checks the output, including a regression case where the callee returns its own string argument. Existing suites stay green: 63/63 compiler, 72/72 interpreter, 68/68 compat.Docs
docs/getting-started.mdgains a "Foreign Functions from BASIC" section.docs/roadmap.mdis pruned to point at git-bug as the source of truth for planned work.Summary by CodeRabbit
New Features
$EXTERNpragma with automatic type mapping between BASIC and C typesDocumentation
Tests