Skip to content

Instantly share code, notes, and snippets.

@Oldes
Created March 22, 2023 10:49
Show Gist options
  • Save Oldes/5b186cc330eec2137708679eead3f62e to your computer and use it in GitHub Desktop.
Save Oldes/5b186cc330eec2137708679eead3f62e to your computer and use it in GitHub Desktop.
Rebol extension source code template generator
REBOL [
title: "Rebol extension source code template generator"
]
system/options/quiet: false
system/options/log/siskin: 3
;- File templates --------------------------------------------------------------
rebol-extension.r3: {REBOL [
title: "Rebol/#NAME# module builder"
type: module
date: #DATE#
home: https://github.com/Oldes/Rebol-#NAME#
version: 1.0.0
author: @Oldes
]
;- all extension command specifications ----------------------------------------
commands: [
info: ["Info about #NAME# extension"]
]
;-------------------------------------- ----------------------------------------
reb-code: {REBOL [Title: {Rebol #NAME# Extension} Type: module]}
enu-commands: "" ;; command name enumerations
cmd-declares: "" ;; command function declarations
cmd-dispatch: "" ;; command functionm dispatcher
;- generate C and Rebol code from the command specifications -------------------
foreach [name spec] commands [
append reb-code ajoin [lf name ": command "]
new-line/all spec false
append/only reb-code mold spec
name: form name
replace/all name #"-" #"_"
append enu-commands ajoin [LF TAB "#ENUM_PREFIX#" uppercase copy name #","]
append cmd-declares ajoin [LF "int cmd_" name "(RXIFRM *frm, void *ctx);"]
append cmd-dispatch ajoin [TAB "cmd_" name #"," LF]
]
;- additional Rebol initialization code ----------------------------------------
;append reb-code {}
;print reb-code
;- convert Rebol code to C-string ----------------------------------------------
init-code: copy ""
foreach line split reb-code lf [
replace/all line #"^"" {\"}
append init-code ajoin [{\^/^-"} line {\n"}]
]
;-- C file templates -----------------------------------------------------------
header: {
//
// auto-generated file, do not modify!
//
#include "rebol-extension.h"
#define MIN_REBOL_VER 3
#define MIN_REBOL_REV 5
#define MIN_REBOL_UPD 4
#define VERSION(a, b, c) (a << 16) + (b << 8) + c
#define MIN_REBOL_VERSION VERSION(MIN_REBOL_VER, MIN_REBOL_REV, MIN_REBOL_UPD)
enum ext_commands {$enu-commands
};
$cmd-declares
typedef int (*MyCommandPointer)(RXIFRM *frm, void *ctx);
#define #NAME#_EXT_INIT_CODE $init-code
#ifdef USE_TRACES
#include <stdio.h>
#define debug_print(fmt, ...) do { printf(fmt, __VA_ARGS__); } while (0)
#define trace(str) puts(str)
#else
#define debug_print(fmt, ...)
#define trace(str)
#endif
}
;;------------------------------------------------------------------------------
ctable: {
//
// auto-generated file, do not modify!
//
#include "#FILE_PREFIX#-rebol-extension.h"
MyCommandPointer Command[] = {
$cmd-dispatch};
}
;- output generated files ------------------------------------------------------
write %#FILE_PREFIX#-rebol-extension.h reword :header self
write %#FILE_PREFIX#-commands-table.c reword :ctable self
}
;-
commands.c: {
// =============================================================================
// Rebol/#NAME# extension commands
// =============================================================================
#include "#FILE_PREFIX#-rebol-extension.h"
#define COMMAND int
#define ARG_Double(n) RXA_DEC64(frm,n)
// Command implementations follows......
COMMAND cmd_info(RXIFRM *frm, void *ctx) {
const char text[] = "Hello from #NAME";
REBINT len = strlen(text);
REBSER* ser = RL_MAKE_STRING(len, FALSE);
memcpy(ser->data, text, len);
SERIES_TAIL(ser) = len;
RXA_SERIES(frm, 1) = ser;
RXA_TYPE(frm, 1) = RXT_STRING;
RXA_INDEX(frm, 1) = 0;
return RXR_VALUE;
}
}
;-
rebol-extension.c: {
// =============================================================================
// Rebol/BlurHash extension
// =============================================================================
#include "#FILE_PREFIX#-rebol-extension.h"
RL_LIB *RL; // Link back to reb-lib from embedded extensions
//==== Globals ===============================================================//
extern MyCommandPointer Command[];
//============================================================================//
static const char* init_block = #NAME#_EXT_INIT_CODE;
RXIEXT const char *RX_Init(int opts, RL_LIB *lib) {
RL = lib;
REBYTE ver[8];
RL_VERSION(ver);
debug_print(
"RXinit #FILE_PREFIX#-extension; Rebol v%i.%i.%i\n",
ver[1], ver[2], ver[3]);
if (MIN_REBOL_VERSION > VERSION(ver[1], ver[2], ver[3])) {
debug_print(
"Needs at least Rebol v%i.%i.%i!\n",
MIN_REBOL_VER, MIN_REBOL_REV, MIN_REBOL_UPD);
return 0;
}
if (!CHECK_STRUCT_ALIGN) {
trace("CHECK_STRUCT_ALIGN failed!");
return 0;
}
return init_block;
}
RXIEXT int RX_Call(int cmd, RXIFRM *frm, void *ctx) {
return Command[cmd](frm, ctx);
}
}
.nest: {
;- .-.
;- /'v'\ SISKIN-Builder 3.9.0 project file
;- (/uOu\) https://github.com/Siskin-framework/Builder/
;-===="="=======================================================================
compiler: clang
version: 1.0.0
optimize: 3
strip: off
;define: USE_TRACES
define: ENDIAN_LITTLE
cflag: fpermissive
flag: -Wno-pointer-sign
flag: shared
;- options common for all Rebol extensions ----------------------
#if Windows? [
define: _CRT_SECURE_NO_WARNINGS
define: _USE_MATH_DEFINES
define: TO_WINDOWS
upx: on
compiler: gcc
]
#if Linux? [
compiler: gcc
]
target-x86: [
arch: x86
]
target-x64: [
arch: x64
defines: [
_FILE_OFFSET_BITS=64
__LP64__ ; has long (integer) 64 bits
]
#if macOS? [ flag: "-arch x86_64" ]
]
target-arm64: [
arch: arm64
#if Linux? [
flag: "-arch arm64"
]
#if macOS? [
flag: "-target arm64-apple-darwin"
]
define: _FILE_OFFSET_BITS=64
define: __LP64__ ; has long (integer) 64 bits
define: __arm64__
]
target-armv7: [
arch: armv7
flag: "-march=armv7"
]
;----------------------------------------------------------------
files: [
%src/#FILE_PREFIX#-commands.c
%src/#FILE_PREFIX#-commands-table.c
%src/#FILE_PREFIX#-rebol-extension.c
]
#if Posix? [
cflags: fPIC
]
;- generate main extension header --------------------------------
do %src/#FILE_PREFIX#-rebol-extension.r3
eggs: only [
#if Windows? [
"Rebol #NAME# extension: windows_x86" [
name: %#FILE_PREFIX#-windows-x86
:target-x86
]
"Rebol #NAME# extension: windows_x64" [
name: %#FILE_PREFIX#-windows-x64
:target-x64
]
]
#if Linux? [
"Rebol #NAME# extension: linux_x86" [
name: %#FILE_PREFIX#-linux-x86
:target-x86
]
"Rebol #NAME# extension: linux_x64" [
name: %#FILE_PREFIX#-linux-x64
:target-x64
]
"Rebol #NAME# extension: linux_armv7" [
name: %#FILE_PREFIX#-linux-armv7
:target-armv7
]
"Rebol #NAME# extension: linux_arm64" [
name: %#FILE_PREFIX#-linux-arm64
:target-arm64
]
]
#if macOS? [
"Rebol #NAME# extension: macos_x64" [
name: %#FILE_PREFIX#-macos-x64
:target-x64
]
"Rebol #NAME# extension: macos_arm64" [
name: %#FILE_PREFIX#-macos-arm64
:target-arm64
]
]
]
}
until [all [
name: ask as-yellow "Extension name: "
trim/all name
parse name [some system/catalog/bitsets/alpha-numeric]
]]
values: make object! compose [
DATE: now/date
NAME: (uppercase/part name 1)
FILE_PREFIX: lowercase copy name
ENUM_PREFIX: ajoin ["CMD_" uppercase copy name #"_"]
]
? values
make-dir dir: rejoin [%Rebol- values/NAME %/]
make-dir srcdir: rejoin [dir %src/]
write-rebx-file: func[file [file! word!] data][
try/except [
write file data
sys/log/more 'SISKIN ["REBX Generated:^[[33m" to-local-file file]
][ sys/log/error 'SISKIN system/state/last-error ]
file
]
data: trim/head reword/escape .nest values [#"#" #"#"]
file: rejoin [dir %Rebol- values/NAME %.nest]
write-rebx-file file data
foreach file [
rebol-extension.r3
rebol-extension.c
commands.c
][
data: trim/head reword/escape get file values [#"#" #"#"]
file: rejoin [srcdir values/FILE_PREFIX %- file]
write-rebx-file file data
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment