Recoil logo

Recoil

The f00 scripting VM & embedded targets

  • Home
  • Getting Started
  • Guide
  • Reference
  • PARSE
  • State Machines
  • FFI & Systems
  • Ports
  • Packages
  • f00 & Embedded
  • Examples
  • Internals

On this page

Loading…

The f00 scripting VM

std/f00 embeds a small Rebol/Red-like interpreter inside a compiled Recoil program. You load script text at runtime, evaluate it against a VM you own, and read back a typed result — without recompiling.

The VM holds no globals; all of its state lives in a heap arena you size at construction, which keeps it viable on low-memory targets.

Running a script

Recoil [
    Title: "f00 host" Type: module Module: examples/f00-host
    Imports: [
        std/f00 [
            vm-new vm-free f00-do-string
            f00-result-status f00-result-value-string result-ok-code
        ]
    ]
]

; arena bytes, symbol-table capacity
vm: make c-pointer! vm-new 65536 128

f00-do-string :vm make string! {x: 10 either x > 5 ["big"] ["small"]}
either (f00-result-status :vm) = result-ok-code [
    print f00-result-value-string :vm        ; => big
] [
    print f00-result-error-message :vm
]

vm-free vm

Bindings persist across f00-do-string calls on the same VM, so a REPL can keep state. Check f00-result-status against result-ok-code (and the result-load-error-code / result-bind-error-code / result-eval-error-code variants).

Exposing compiled functions to scripts

List the functions you want reachable from f00 in a F00-Natives: header field, then call f00-register-natives :vm once. Each listed function is bound as a bare word in the VM's root context.

Recoil [
    Title: "f00 natives" Type: module Module: examples/f00-natives
    Imports: [
        std/f00 [ vm-new vm-free f00-do-string f00-result-value-string f00-register-natives ]
    ]
    F00-Natives: [ add2 shout ]
]

add2:  func [a [i64!] b [i64!] return: [i64!]] [return a + b]
shout: func [s [string!] return: [string!]] [return rejoin [s "!"]]

vm: make c-pointer! vm-new 65536 128
f00-register-natives :vm

f00-do-string :vm make string! {add2 3 4}     print f00-result-value-string :vm   ; => 7
f00-do-string :vm make string! {shout "hi"}   print f00-result-value-string :vm   ; => hi!

The compiler reads each signature and generates a uniform adapter plus a single registration routine — nothing is generated unless the program imports std/f00. Boundary parameter/return types are limited to i64!, f64!, logic!, and string!; a runtime type/arity mismatch is reported as a structured f00 eval error, not a crash. An exposed function may take at most 8 parameters.

ESP32 / ESP-IDF builds

Recoil can target the ESP32 through ESP-IDF. You need Rebol 3 (with -s), an installed ESP-IDF for your chip, and the IDF environment exported in the shell so idf.py and IDF_PATH are available.

# export the ESP-IDF environment first
. "$HOME/esp/esp-idf/export.sh"

Building for ESP32

r3 -s recoil.r3 --target esp32 -o cache/esp32/simple.elf tests/simple-test.rcl

The output path is the copied ELF; when ESP-IDF also emits a .bin it is copied beside the ELF. The generated ESP-IDF project (with CMakeLists.txt, sdkconfig.defaults, and the generated main/ C) is kept under cache/esp-idf/ for flashing and monitoring with idf.py.

Calling ESP-IDF APIs

Beyond print, programs call ESP-IDF / FreeRTOS C functions directly through the foreign FFI. FFI is not capability-gated, so peripheral access (GPIO, timers, FreeRTOS delays) needs no special capability. Recoil derives the ESP-IDF component REQUIRES from the headers you include:

foreign headerESP-IDF component
driver/*driver
freertos/*freertos
esp_timer.hesp_timer
esp_log.hlog
nvs_flash.hnvs_flash

Capability surface

The ESP32 target is intentionally conservative today:

  • Enabled: console (core language features and print).
  • Not yet enabled: file, env, tcp, dns, tls, http, https, js-host.

Imports that need an unsupported capability fail before C compilation (for example std/io, which requires env and console). Peripheral access remains available through the foreign FFI. The repository's ESP32 guide has the flashing procedure and the code-size baseline.

↑

Recoil — an ownership-first, statically-typed language with a static borrow checker.

codeberg.org/rebolek/recoil · boleslav@brezovsky.eu · Apache-2.0