REBOL 3 Docs | Guide | Concepts | Functions | Datatypes | Errors |
TOC < Back Next > | Updated: 9-Nov-2010 Edit History |
Editor note: This page has fallen out of date with recent changes.
You can find a small package that contains source files for getting started at: example REBOL extension source code and binary It's a 12K zip.
To try it: run REBOL R3 with the test-ext.r script and ext-test.dll file in the same directory.
A few notes to be aware of at this time:
Here's a blank extension that does nothing useful, but shows the general format:
#include "reb-c.h" #include "reb-ext.h" const char *init_block = "REBOL [\n" "Title: {Blank extension}\n" "Type: module\n" "Exports: [nothing]\n" "]\n" "nothing: command [{Does nothing.}]\n" ; RXIEXT const char *RX_Init(int opts, RL_LIB *lib) { RL = lib; if (!CHECK_STRUCT_ALIGN) return 0; return init_block; } RXIEXT int RX_Quit(int opts) { return 0; } RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { return RXR_NONE }
Each example section below will show the REBOL code and the C code as separate sections. To fully understand the details of this code, read the extensions: making extensions section.
For example, if the REBOL module code is:
REBOL [ Title: "Add two integers" Type: module Export: [addi] ] addi: command [i1 [integer!] i2 [integer!]
and the C code is:
RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { RXA_INT64(frm,1) = RXA_INT64(frm, 1) + RXA_INT64(frm, 2); return RXR_VALUE; }
The extension source code would be:
#include "reb-c.h" #include "reb-ext.h" const char *init_block = "REBOL [\n" "Title: {Add two integers}\n" "Type: module\n" "Export: [addi]\n" "]\n" "addi: command [i1 [integer!] i2 [integer!]\n" ; RXIEXT const char *RX_Init(int opts, RL_LIB *lib) { RL = lib; if (!CHECK_STRUCT_ALIGN) return 0; return 0; } RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { RXA_INT64(frm,1) = RXA_INT64(frm, 1) + RXA_INT64(frm, 2); return RXR_VALUE; }
Once you go beyond a simple init block, it gets tedious to maintain it as C strings. To make it easier to build the init_block text, we provide the make-ext.r script.
Using this script will convert the extension .r source file into a C data statement (as UTF-8). It will also create the exports block and will generate an enum constant for each command.
#include "reb-c.h" #include "reb-ext.h" #include "ext-data.h" RXIEXT const char *RX_Init(int opts, RL_LIB *lib) { RL = lib; if (!CHECK_STRUCT_ALIGN) return 0; return init_block; } RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { switch (cmd) { case CMD_MY_CMD1: ... case CMD_MY_CMD2: ...
Here is an example that shows how to return a few different values.
The REBOL module code is:
REBOL [ Title: {Example} Type: module Exports: [t-unset t-none t-true t-false t-value t-block] ] t-unset: command [] t-none: command [] t-true: command [] t-false: command [] t-value: command [v] t-block: command [a b c]
The relevant C code is:
RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { switch (cmd) { case 0: return RXR_UNSET; case 1: return RXR_NONE; case 2: return RXR_TRUE; case 3: return RXR_FALSE; case 4: return RXR_VALUE; // return first arg case 5: return RXR_BLOCK; // 3 args become a block } }
This extension provides two functions to compute the Fibonacci number and the factorial.
The REBOL extension module definition:
REBOL [ Title: {Math functions} Type: module Exports: [fibonacci factorial] ] fibonacci: command [n [integer!]] factorial: command [n [integer!]]
The C code:
RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { switch (cmd) { case 0: // fibonacci { i64 n, a, b, c, i; n = RXA_INT64(frm, 1); for (a = b = 1, i = 3; i <= n; i++) { c = b; b += a; a = c; } RXA_INT64(frm, 1) = b; RXA_TYPE(frm, 1) = RXT_INTEGER; // not strictly necessary break; } case 1: // factorial { i64 n, i, f = 1; n = RXA_INT64(frm, 1); for (i = 2; i <= n; i++) f *= i; RXA_INT64(frm, 1) = f; RXA_TYPE(frm, 1) = RXT_INTEGER; // not strictly necessary break; } default: return RXR_NO_COMMAND; } return RXR_VALUE; }
The test code:
print fibonacci 80
23416728348467685
print factorial 20
2432902008176640000
If you time these functions, you will find that they are about 25 times faster than interpreted code.
Here's an extension that provides a function to compute a 64 bit checksum on a string chars. It works for both types of strings (Latin-1 and Unicode).
The REBOL extension module definition:
REBOL [ Title: {String 64 bit checksum} Type: module Exports: [sum-chars] ] sum-chars: command [str [string!]]
The C code:
RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { switch (cmd) { case 0: { i32 idx, tail; i64 sum = 0; REBSER *ser; ser = RXA_SERIES(frm, 1); idx = RXA_INDEX(frm, 1); tail = RXI_SERIES_INFO(ser, RXI_INFO_TAIL); for (; idx < tail; idx++) { sum += RXI_GET_CHAR(ser, idx); } RXA_INT64(frm, 1) = sum; RXA_TYPE(frm, 1) = RXT_INTEGER; break; } // ...other command cases... default: return RXR_NO_COMMAND; } return RXR_VALUE; }
Test code:
probe sum-chars "testing"
766
probe sum-chars to-string read http://www.rebol.com
751827
Although REBOL provides the reverse function, here's a simple example that helps show how strings can be modified.
The REBOL extension module definition:
REBOL [ Title: {String example} Type: module Exports: [reverse-str] ] reverse-str: command [str [string!]]
The C code:
RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { switch (cmd) { case 0: { u32 idx, tail, chr; REBSER *ser; ser = RXA_SERIES(frm, 1); idx = RXA_INDEX(frm, 1); tail = RXI_SERIES_INFO(ser, RXI_INFO_TAIL); if (tail > 0) tail--; for (; idx < tail; idx++, tail--) { chr = RXI_GET_CHAR(ser, idx); RXI_SET_CHAR(ser, idx, RXI_GET_CHAR(ser, tail)); RXI_SET_CHAR(ser, tail, chr); } break; // returns same string } default: return RXR_NO_COMMAND; } return RXR_VALUE; }
Test code:
probe reverse-str ""
""
probe reverse-str "ab"
"ba"
probe reverse-str "abc"
"cba"
probe reverse-str "abcd"
"dcba"
probe head reverse-str next "ab"
"ab"
probe head reverse-str next "abc"
"acb"
probe head reverse-str next "abcd"
"adcb"
This extension shows how to handle values within a block. It provides a function that returns a sum of all integer and decimal values within the block. If the block contains other datatypes, they are ignored.
The REBOL extension module definition:
REBOL [ Title: {Sum a block of integers and decimals} Type: module Exports: [sum-nums] ] sum-nums: command [blk [block!]]
The C code:
RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { switch (cmd) { case 0: { i32 idx, tail, type; REBDEC sum = 0.0; REBSER *ser; RXIARG val; ser = RXA_SERIES(frm, 1); idx = RXA_INDEX(frm, 1); tail = RXI_SERIES_INFO(ser, RXI_INFO_TAIL); for (; idx < tail; idx++) { type = RXI_GET_VALUE(ser, idx, &val); if (type == RXT_INTEGER) sum += (REBDEC)val.int64; else if (type == RXT_DECIMAL) sum += val.dec64; // else skip it } RXA_DEC64(frm, 1) = sum; RXA_TYPE(frm, 1) = RXT_DECIMAL; break; } default: return RXR_NO_COMMAND; } return RXR_VALUE; }
Here's some test code:
probe sum-nums []
0.0
probe sum-nums [1 2 3]
6.0
probe sum-nums [1 2.3 4 5.6]
12.9
Although REBOL provides the reverse function, here's a simple example that helps show how blocks can be modified.
Note that this code only works for values that extensions are allowed to access. See the list in the prior section.
The REBOL extension module definition:
REBOL [ Title: {Block example} Type: module Exports: [reverse-blk] ] reverse-blk: command [blk [block!]]
The C code:
RXIEXT int RX_Call(int cmd, RXIFRM *frm, REBCEC *ctx) { switch (cmd) { case 0: { u32 idx, tail, type1, type2; REBSER *ser; RXIARG arg1, arg2; ser = RXA_SERIES(frm, 1); idx = RXA_INDEX(frm, 1); tail = RXI_SERIES_INFO(ser, RXI_INFO_TAIL); if (tail > 0) tail--; for (; idx < tail; idx++, tail--) { type1 = RXI_GET_VALUE(ser, idx, &arg1); type2 = RXI_GET_VALUE(ser, tail, &arg2); RXI_SET_VALUE(ser, idx, arg2, type2); RXI_SET_VALUE(ser, tail, arg1, type1); } break; // returns same block } default: return RXR_NO_COMMAND; } return RXR_VALUE; }
The test code:
probe reverse-blk []
[]
probe reverse-blk [1]
[1]
probe reverse-blk [1 2]
[2 1]
probe reverse-blk [1 2 3]
[3 2 1]
probe reverse-blk [1 2 3 4]
[4 3 2 1]
probe head reverse-blk next [1 2]
[1 2]
probe head reverse-blk next [1 2 3]
[1 3 2]
probe head reverse-blk next [1 2 3 4]
[1 4 3 2]
TOC < Back Next > | REBOL.com - WIP Wiki | Feedback Admin |