-
Notifications
You must be signed in to change notification settings - Fork 5
Native Interoperability
Because cish is an interpreted language, it is impossible to compile/work with statically linked libraries. Therefore all c libraries created for superforth, like C#, must be a DLL.
-
If you haven't already, please download the external native-interoperation SDK. Once you have the folder on your computer, simply run make on the MakeFil in the folder. It should produce a
superforth.o
file immediately thereafter. -
Copy these two files,
superforth.h
andsuperforth.o
to the folder you intend to develop the DLL in. You may freely referencesuperforth.h
, but make sure that you link your program withsuperforth.o
after compilation.
To add a foreign function to cish's FFI, simply call the following function defined in superforth.h
:
int ffi_include_func(ffi_t* ffi_table, foreign_func func)
Where foreign_func
is a function pointer defined like the following:
typedef int (*foreign_func)(machine_t* machine, machine_reg_t* input, machine_reg_t* output);
You can retrieve a cish vm's(machine_t
) foreign function table via the ffi_t ffi_table
property.
You can interact with cish by providing heap allocations that can be interpreted as structures, arrays, or potentially other allocation types. In addition these heap allocations are garbage-collected as well, so do not use them to store static memory. Read this article about record layouts, and how to interact with their runtime representations.
The heap allocation function itself is defined like the following:
heap_alloc_t* machine_alloc(machine_t* machine, uint16_t req_size, gc_trace_mode_t trace_mode);
-
uint16_t req_size
is the length(the amount of elements/properties). -
gc_trace_mode_t trace_mode
represents the trace coniguration. Read more here about heap allocations during runtime. - The return value is a memory safe, garbage collected SuperForth heap allocation.
Fundamentally, interoperation with C is done through foreign functions. They are function pointer types defined as:
typedef int (*foreign_func)(machine_t* machine, machine_reg_t* input, machine_reg_t* output);
Put in non-C terms, all foreign functions take in the current instance's virtual machine,an input and an output SuperForth register, and return an integer status. They are called from within cish like this.
Take the dynamic-library-import foreign function for example:
static int std_import(machine_t* machine, machine_reg_t* in, machine_reg_t* out) {
char* import_name = read_str_from_heap_alloc(in->heap_alloc);
PANIC_ON_FAIL(import_name, machine, ERROR_MEMORY);
out->long_int = machine->ffi_table.func_count;
if (!dynamic_library_load(machine->dynamic_library_table, machine, import_name)) {
out->long_int = -1;
}
return 1;
}
It takes in the vm-instance, and an input and output register. All output must be written to the output register. Although there aren't any guards against writing to the input registers location, it is highly unrecomended to do so.
Keep in mind that while each foreign function may only interact with a few parameters in a somewhat limited manner, you can also interact with static-memory/other more-complex functions to provide more powerful, feature-rich functionality. Read more about SuperForth's Foreign Function Interface's Design Philosophy here.
When cish imports a native dynamically linked library, the first think it'll do is search for it's SUPERFORTH_ENTRY
function, and invoke it immediately. It is recomended that your initialization code be performed in this entry point. Initialization tasks include, but are not limited to: Adding foreign functions to a vm's foreign function table.
Include superforth.h
if you haven't already. Using the SUPERFORTH_ENTRY
macro, define superforth's entry point as such:
SUPERFORTH_ENTRY({
//your entry point code here
return 1;
});
The SUPERFORTH_ENTRY
macro expands into a function with the following parameters and return value, each provided by the calling cish instance:
int superforth_entry(machine_t* machine);
Note: The parameter machine_t* machine
is a pointer to the calling cish instances virtual machine. Use this oppurtunity to add foreign functions to the vm's foreign function table, and perform other relevant initialization.
Note: that the cish entry function's return value: this signals cish if the initialization process has suceded or not. In addition the vm instance has an error_t last_err
property defined; set this flag to the one of the following errors to provide a more detailed reason for faliure.
- Getting Started
- The Language and Syntax
- Type Declarations
- Primitive Values
- Collection/Object Values
- Operators
-
The Standard Library
- More docs coming soon after APs.
- FFI and Interoperability
- The Implementation