aw/picolisp-zig
Examples for using PicoLisp FFI with Zig
This repo provides a simple example of how to use PicoLisp with Zig using PicoLisp's FFI (native)
functionality.
This is similar to picolisp-rust except written for Zig.
v0.6+
v17.12+
or pil21
Once you've setup PicoLisp and Zig, simply type make
to build and test the shared library.
Before I explain what's going on, here's what the output should look like:
Received struct: pil.PilStruct{ .byte1 = 32, .byte2 = 33, .character1 = 67, .character2 = 68, .int = -1, .long = 1, .string = u8@4847464544434241, .array = { 1, 2, 3, 4, 5, 6, 7, 8 } }
Result code: 0
Extracted struct:
(de Extracted (42 43)
("A" "B")
65535
9223372036854775807
"pilzig"
(80 105 99 111 76 105 115 112) )
The code can be found in extract.l and pil.zig. The Zig code is designed as a shared library and can be called by PicoLisp's (native) function to pass data to/from between both languages.
First, the code allocates 32 bytes of memory, which will be used to store data in a struct.
It then creates a struct named P
with the following specification:
Then the following native call is made and its result is stored in the Res
variable:
(native "./libpil.so" "extract" 'I P)
This calls the extract
function from the Zig library, with the P
struct as its only parameter. It expects a 32-bit signed integer I
as the return value (it will be either 0
or -1
).
Next, the code will extract the P
structure using the specification described above:
(struct P '((B . 2) (C . 2) I N S (B . 8)))
Finally, the code will free the previously allocated memory and print the result of the P
structure.
Some tests run at the end to ensure the data received from Zig is what we expected.
Received struct:
.Extracted struct:
.The Zig code defines the struct for the received data; it is named PilStruct
and contains the exact same specification as the P
struct in the PicoLisp code explanation.
The extract()
function creates a new struct in the variable newstruct
which contains some new values, different from what was received by PicoLisp.
Luckily, the Zig pointers cannot be null so there's no need to check for that.
The code then dereferences the pointer and prints what it received (the entire struct) from PicoLisp as Received struct:
(mentioned earlier).
Finally, it writes the newstruct
struct to the pointer and returns 0
. PicoLisp can then read the return code and the new struct data.
There isn't much to this code, but I thought it would be fun to create a working FFI library that's not written in C or Rust and which works perfectly with PicoLisp.
Enjoy!
Copyright (c) 2023 Alexander Williams, On-Prem [email protected]