-
Notifications
You must be signed in to change notification settings - Fork 5
Foreign Function Interface
cish's foreign function interface is more akin to a strange concoction of high-level opcode assembly. Generally speaking, there will be wrapper functions implemented via cish's standard library. This documentation only applies to those who are developing foreign functions, those looking to modify cish, and most likely not you, a high-level developer.
SuperForth Foreign functions are composed of the foreign
keyword, followed by a value representing the foreign funcion's opcode, followed by a operand value. No typechecking occurs duirng this phase, except for the foreign function opcode expression. Beware of too many automatic definitions to the degree in which type inference becomes impossible. when they are used with foreign. For example:
int output_var = foreign[123]("michael")
or conversley with a variable foreign id
int lib_offset = foreign[17]("./lib.so");
foriegn[lib_offset + 9](100); $invokes behavior from lib_offset
would find function number 123, which may have a different functionality depending on how you modify cish, send in the operand value "michael"
, and write the output into output_var
. Errors may occur because, as mentioned before foreign functions don't perform any meaningful type checking. The function will carry out its purpose regardless of whether the input values are correct.
However, if an foreign call has no input, it must have no output. Foreign call may always have inputs regardless of whether it has an output. Foreigns undergo the least amount of enforcement, so be sure to read/use foreigns correctly as described by their authors documentation.
This table details the opcodes on a standard, unmodified cish implementation. If you're using a modified version of cish, consult it's developers before directly accessing foreign functions. Otherwise, it's best to use the wrapper functions they provide.
OpCode | Expected Operand Value | Expected Output Value | Functionality |
---|---|---|---|
0 | int |
float |
Converts a int to float |
1 | float |
int |
Gets the floor of a float. |
2 | float |
int |
Gets the ciel of a float. |
3 | float |
int |
Rounds a float. |
4 | float |
array<char> |
Converts a float to a string. |
5 | array<char> |
float |
Converts a string to a float. |
6 | int |
array<char> |
Converts an int to a string. |
7 | array<char> |
int |
Converts a string to an int. |
8 | char |
None | Prints a character to stdout. |
9 | None | char |
Reads a character, returns '\0' if waiting for more input. |
10 | None |
int /float
|
Generates a random int, or float. |
11 | float |
float |
Returns the sin of a radian angle. |
12 | float |
float |
Returns the cos of a radian angle. |
13 | float |
float |
Returns the tan of a radian angle. |
14 | int |
char |
Converts an int to it's equivalent ASCII char. |
15 | char |
int |
Converts a ASCII char to its int representation. |
16 | None | int |
Returns the UNIX time. |
17 | int |
None | Sleeps for a given amount of milliseconds. |
18 | int |
array<any> |
Reallocs an array - output register is also used as input. |
OpCode | Expected Operand Value | Expected Output Value | Functionality |
---|---|---|---|
19 | array<char> |
int |
Loads a library, imports it's foreigns, and returns it's library offset |
20 | int |
array<int> |
Initializes an array full of zero-values. Works for char , int , and bool . |
OpCode | Expected Operand Value | Expected Output Value | Functionality |
---|---|---|---|
19 | None | int |
Returns the competition mode |
20 | array<char> |
None | Logs a message to the robot and stdout. |
21 | int |
None | Selects a Vex Port. |
22 | int |
None | Gets a motor encoding at a port. |
23 |
int * |
None | Configures a motors gearset. |
24 |
int * |
None | Configures motor encoding units for motor. |
25 |
bool * |
None | Configures motor in reverse mode or not. |
26 | int |
None | Gets the RPM of a motor. |
27 | int |
None | Sets a motors encoding position to zero. |
The asterisk means a motor port must be selected prior to calling the said foreign function, via foreign function 21
, in addition to the requested operand.
The cish Foreign Function interface designed to interop with native-C code, especially for things that cannot be done by cish: for example interoperating with c to provide low-level functionality like matrix multiplication at higher speeds, or interacting with system components. Often times, the FFI serves as a bridge between an existing c-library and cish
As such, because the FFI is one of multiple layers (the other being the cish compatible DLL, or some builtin standard functionality) in-between the metaphorical bridge, the average high-level user shouldn't be exposed to such lower-level, implementation details on a frequent basis.
Because of the low level of exposure between the average user and the FFI directly, the FFI's syntax is designed to be as simple to implement, understand, and maintain as possible. Only allowing for one or zero inputs, and a potential output drastically reduces cish's implementation complexity.
cish doesn't perform any type-checking on foreign functions chiefly because it is expected that the developer of any said library would provide a cish wrapper function around any ffi-functionality. This shifts the development overhead towards the library creator, but is consistent with the cish's principle of keeping it simple for high-level users. These wrappers would provide much more flexibility, potentially much more than any type-checked foreign function possibly could.
The odd variable-numerical way of addressing foreign functions at an index stems from the desire to keep cish's implementation relatively simple and easy to maintain. It also provides a fairly large degree of dynamism and flexibility for importing multiple libraries and interacting with native plugins.
- 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