Philosophy
Raden is built around a simple value stack. Everything is a value on the stack — integers, doubles, strings, booleans, nulls, lists, and functions. Operations consume values from the stack and push results back. This keeps the language small, predictable, and easy to embed.
Features
- Stack-based — postfix evaluation, minimal syntax
- First-class functions — named with
defun, anonymous withapply - Protected calls —
pcallcatches errors without crashing - Rich builtins — lists, strings, operators, containers
- Native module API — extend Raden in C via shared libraries
- Embeddable — single
rdn_mainentry point - REPL — interactive prompt for experimentation
- 14 standard libraries — files, math, strings, JSON, networking, and more
Quick Start
Install
Use the installer script to fetch, build, and install Raden automatically:
curl -fsSL https://raw.githubusercontent.com/abdorayden/rdn/master/install | sh
# or from a cloned checkout
./install
By default, libraries install to /usr/local/share/rdn/libs and native modules install to
/usr/local/share/rdn/nativelibs.
Build
git clone https://github.com/abdorayden/rdn.git
cd rdn
make
./main script.rdn
REPL
Run ./main without arguments to enter the REPL:
$ ./main
raden repl
press Ctrl-D to exit
RDN >> 2 3 + print
Run a script
$ cat hello.rdn
"hello, world!\n" print
$ ./main hello.rdn
hello, world!
Test suite
bash test/run.sh
Command-line flags
./main --version # print version and exit
./main -v # same
./main script.rdn # run script
./main # start REPL
Values & Types
Raden has six value types. Values are pushed onto the stack, then operations consume them.
| Type | Syntax | Example |
|---|---|---|
| Integer | 123 |
42 |
| Double | 123.456 |
3.14 |
| String | "..." |
"hello" |
| Boolean | true / false |
true |
| Null | null |
null |
| List | (...) |
(1 2 "three") |
[*values*]
42
3.14
"hello"
true
null
(1 2 3)
[*inspect type*]
42 type print [*integer*]
3.14 type print [*double*]
"hi" type print [*string*]
String escapes
| Escape | Meaning |
|---|---|
\n |
newline |
\t |
tab |
\" |
double quote |
\\ |
backslash |
\e |
escape |
Comments
[* this is a comment *]
42 [* inline comment *] print
Operators
Operators consume values from the stack and push results. They are postfix — operands first, operator second.
Arithmetic
| Operator | Description | Example |
|---|---|---|
+ |
addition | 2 3 + |
- |
subtraction | 5 3 - |
* |
multiplication | 4 5 * |
/ |
division | 10 2 / |
Comparison
| Operator | Description |
|---|---|
= |
equal |
!= |
not equal |
< |
less than |
> |
greater than |
<= |
less or equal |
>= |
greater or equal |
Boolean
| Operator | Description |
|---|---|
! |
logical NOT |
& |
logical AND (boolean) / bitwise AND (integer) |
| |
logical OR (boolean) / bitwise OR (integer) |
Bitwise
| Operator | Description |
|---|---|
<< |
left shift |
>> |
right shift |
^ |
bitwise XOR |
[*arithmetic*]
2 3 + print [*5*]
10 3 - print [*7*]
4 5 * print [*20*]
[*comparison*]
5 3 > print [*true*]
"hi" "hi" = print [*true*]
[*boolean*]
true ! print [*false*]
true false & print [*false*]
Variables
let — bind a value
10 x let
x print [* 10*]
unlet — unbind a value it's like del in python
10 x let
x unlet [* stack is empty*]
set — update an existing variable
x 1 + x set
x print [* 11*]
const — immutable binding
100 limit const
limit print [* 100*]
limit 5 + const [* error: limit already exists*]
enum — auto-incrementing constants
enum ONE const [* ONE == 0*]
enum TWO const [* TWO == 1*]
enum THREE const [* THREE == 2*]
reset [* reset back to 0*]
Built-in environment variables
| Variable | Value |
|---|---|
__host_os |
"linux", "macos", "windows", etc. |
__sharedlib_ext |
".so", ".dylib", ".dll" |
__argv |
list of command-line arguments (script path first) |
__line_col |
push col and line of called variable into the stack |
Functions
defun — named functions
double defun
2 *
end
5 double call print [*10*]
apply — it's like functions but used as keyword it called without call keyword
triple apply
3 *
end
4 triple print [*12*]
pcall — protected calls
risky defun
null 0 index
end
risky pcall
if
"success: " print print "\n" print
else
"error: " print print "\n" print [*this runs*]
end
pcall calls a function and catches any error. On success the stack gets
[result, true]. On error it gets [error_string, false] with no stderr
output.
call — invoke by name
"double" call call [*looks up function by string name*]
Function scope
Functions create a new variable scope. Variables defined inside are local unless they already
exist in an outer scope (in which case set updates the outer binding).
counter defun
0 i let [*local i*]
i 1 + i set [*update local*]
i
end
counter call print [*1*]
counter call print [*1 (each call gets its own scope)*]
Control Flow
if / else / end
true if
"yes" print
else
"no" print
end
loop / end
The loop body must leave a boolean on the stack to continue or stop:
0 i let
i 5 < cond let
cond loop
i print "\n" print
i 1 + i set
i 5 < cond set
cond
end
break / continue
0 i let
true loop
i 10 > if break end
i 5 = if i 1 + i set continue end
i print "\n" print
i 1 + i set
true
end
exit
0 exit [* exit with status 0*]
1 exit [* exit with status 1*]
Builtins
Stack
| Builtin | Signature | Description |
|---|---|---|
print |
value -> | Print value to stdout |
pop |
value -> | Pop and discard top of stack |
dup |
value -> value value | Duplicate top of stack |
swap |
a b -> b a | Swap top two values |
type |
value -> string | Return type name as string |
to_string |
value -> string | Convert value to string representation |
Variables
let |
value name -> | Bind value to name (mutable) |
set |
value name -> | Update existing variable |
const |
value name -> | Bind value to name (immutable) |
enum |
name -> | Push next enum integer |
reset |
-> | Reset enum counter |
Containers
index |
target index -> value | Index into list or string |
append |
target value -> target | Append to list or string (mutates var targets) |
remove |
target index -> target | Remove item at index (mutates var targets) |
len |
target -> integer | Length of list or string |
Loading
load |
path -> | Execute a .rdn file (source-relative) |
loadnative |
path -> | Load a native shared library |
add_load_path |
path -> | Add a search path for load |
add_native_path |
path -> | Add a search path for loadnative |
Functions
defun |
name ... end -> | Define a named function |
apply |
name ... end -> | Define an anonymous function |
call |
name args... -> results... | Call a function by name |
pcall |
name args... -> result true|error false | Protected call — catches errors |
error |
str -> error | declare an error by the interpreter |
Control flow
if |
cond true-body else? false-body? end -> | Conditional execution |
loop |
body... bool end -> | Loop while body leaves true |
break |
-> | Exit enclosing loop |
continue |
-> | Skip to next loop iteration |
exit |
status -> | Exit program with status code |
Lists & Strings
Lists
(1 2 3) print [* (1 2 3)*]
[* index*]
(10 20 30) 1 index print [* 20*]
[* append*]
(1 2) 3 append print [* (1 2 3)*]
[* remove*]
(1 2 3) 1 remove print [* (1 3)*]
[* length*]
(1 2 3) len print [* 3*]
Strings
All sequence builtins work on strings too:
"hello" 1 index print [* "e"*]
"hello" 1 remove print [* "hllo"*]
"hi" len print [* 2*]
[* append to string variable (mutates)*]
"hi" text let
text "!" append
text print [* "hi!"*]
Nesting
(1 (2 3) 4) 1 index 0 index print [*2*]
Error Handling
pcall — protected call
pcall invokes a function and catches any error that occurs during execution. It is the
primary error-handling mechanism.
| Situation | Stack after pcall |
|---|---|
| Success | ... function_result true |
| Error caught | ... "error message" false |
div defun
/ [* expects divisor and dividend on stack*]
end
[* protected division*]
"div" pcall pop
if
"result: " swap print "\n" print
else
"error: " print "\n" print
end
Error messages include call traces
When a function calls another function and the inner one fails, the error message includes the full call chain:
inner defun null 0 index end
outer defun inner call end
"outer" pcall pop
if else print "\n" print end
[* prints: index requires list or string target*]
[* while calling function 'inner'*]
[* while calling function 'outer'*]
Setup errors are not caught
Errors that happen before the function executes (e.g. missing function name) propagate normally and are not caught by pcall.
Loading Code
load — Raden scripts
[*libs/math.rdn*]
"./libs/math.rdn" load
4 sqrt call print
Paths are resolved relative to the currently running source file.
loadnative — shared libraries
"../nativelibs/files.so" loadnative
"./Makefile" readLines call print
Use __sharedlib_ext for cross-platform paths:
"../nativelibs/math" __sharedlib_ext to_string swap pop append loadnative
Search paths
"./my-libs" add_load_path
"./my-natives" add_native_path
Standard Library — core
libs/core.rdn Small aliases for core builtins and general-purpose helpers.
Operator aliases
| Function | Wraps | Example |
|---|---|---|
| not | ! | true not call |
| add, sub, mul, div | + - * / | 2 3 add call |
| eq, neq, lt, gt, le, ge | = != < > <= >= | 5 3 gt call |
| and, or, xor | & | ^ | true false and call |
| shl, shr | << >> | 4 1 shl call |
Type predicates
| is_null | null is_null call |
| is_int | 42 is_int call |
| is_float | 3.14 is_float call |
| is_bool | true is_bool call |
| is_str | "hi" is_str call |
| is_list | (1 2) is_list call |
Numeric helpers
| inc, dec | 5 inc call → 6 |
| neg, abs | -3 abs call → 3 |
| even, odd | 4 even call → true |
| min, max | 3 7 min call → 3 |
| between | 5 1 10 between call → true |
| clamp | 15 0 10 clamp call → 10 |
Functional
| pipe | 3 inc pipe call → 4 |
| tap | call fn for side effects, return value |
| select | true "a" "b" select call → "a" |
| when, unless | conditional transformation |
| times | 3 inc times call 0 → 3 |
| range | 0 5 range call → (0 1 2 3 4) |
| in | iterate over list with callback |
Standard Library — lists
libs/lists.rdn List-oriented helpers.
| Function | Signature | Description |
|---|---|---|
| each / foreach / map | list callback -> | Iterate with side effects |
| collect | list callback -> list | Map — collect callback results |
| filter | list callback -> list | Keep items where callback returns true |
| reduce | list initial callback -> value | Fold left |
| copy | list -> list | Clone list |
| reverse | list -> list | Reversed clone |
| concat | a b -> list | Concatenate two lists |
| first / head | list -> value|null | First item |
| last | list -> value|null | Last item |
| tail / rest | list -> list | List without first item |
| count | list -> integer | Length |
| isEmpty | list -> boolean | Is the list empty? |
| includes | list value -> boolean | Does it contain the value? |
| any | list callback -> boolean | Any item matches? |
| all | list callback -> boolean | All items match? |
| shift | var -> value|null | Remove and return first (mutates var) |
| popLast | var -> value|null | Remove and return last (mutates var) |
| unpack | list -> values... | Push all items to stack |
| insert | list index value -> list | Insert value at index |
[* each / collect / filter*]
(1 2 3) dup collect call print [* (1 2 3)*]
(1 2 3) 2 > filter call print [* (3)*]
(1 2 3) 0 add reduce call print [* 6*]
doubler defun 2 * end
(1 2 3) doubler collect call print [* (2 4 6)*]
Standard Library — strings
libs/strings.rdn String helpers. Also loads the native
strings module.
| Function | Signature | Description |
|---|---|---|
| concat | a b -> string | Concatenate two values as strings |
| concatBy | a b sep -> string | Join with separator |
| contains | text part -> boolean | Substring check |
| hasPrefix | text prefix -> boolean | Prefix check |
| hasSuffix | text suffix -> boolean | Suffix check |
| trimSpace | text -> string | Trim whitespace |
| split | text sep -> list | Split by separator |
| replaceAll | text old new -> string | Replace all occurrences |
Standard Library — io
libs/io.rdn Input/output helpers.
| Function | Signature | Description |
|---|---|---|
| readLine / readln | -> string|null | Read one line from stdin |
| readAll | -> string | Read remaining stdin |
| prompt | text -> string|null | Print prompt, then read line |
| nl | -> | Print newline |
| println / say | value -> | Print value then newline |
| printAll | list -> | Print all items |
| printLines | list -> | Print each item on its own line |
| printJoin | list sep -> | Print items joined by separator |
Standard Library — files
libs/files.rdn Text file operations.
| Function | Signature | Description |
|---|---|---|
| readLines | path -> list | Read file lines |
| writeLines | path list -> true | Write lines to file |
| appendLines | path list -> true | Append lines to file |
| readText | path -> string | Read entire file |
| writeText | path text -> true | Write text to file |
| appendText | path text -> true | Append text to file |
| slurp | path -> string | Alias for readText |
| spit | path text -> true | Alias for writeText |
"./libs/files.rdn" load
"./data.txt" readLines call lines let
lines each call print
Standard Library — math
libs/math.rdn Math constants and functions.
| Function | Signature | Description |
|---|---|---|
| sqrt | number -> double | Square root |
| powf | base exp -> double | Power |
| pow | base exp -> double | Power (alias) |
Constants: M_E, M_LOG2E, M_LOG10E, M_LN2, M_LN10, M_PI, M_PI_2, M_PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, M_SQRT2, M_SQRT1_2
"./libs/math.rdn" load
4 sqrt call print [* 2.0*]
2 8 pow call print [* 256.0*]
M_PI print [* 3.14159...*]
Standard Library — os
libs/os.rdn Operating system runtime helpers.
| Function | Signature | Description |
|---|---|---|
| pid | -> integer | Current process ID |
| env | name -> string|null | Environment variable lookup |
| sleep | ms -> true | Sleep for milliseconds |
| now | -> integer | Unix epoch seconds |
Standard Library — unix
libs/unix.rdn Filesystem and working-directory helpers.
| Function | Signature | Description |
|---|---|---|
| pwd | -> string | Current working directory |
| exists | path -> boolean | Does path exist? |
| mkdir | path -> true | Create directory |
| rmPath | path -> true | Remove file or empty directory |
| ls | path -> list | List directory entries |
Standard Library — path
libs/path.rdn Cross-platform path manipulation.
| Function | Signature | Description |
|---|---|---|
| join | left right -> string | Join path components |
| basename | path -> string | Final path component |
| dirname | path -> string | Parent directory |
| extname | path -> string|null | File extension (no dot) |
| absolute | path -> boolean | Is path absolute? |
Standard Library — process
libs/process.rdn External command execution.
| Function | Signature | Description |
|---|---|---|
| status | command -> integer | Run command, return exit status |
| output | command -> string | Run command, capture stdout |
Standard Library — net
libs/net.rdn Networking utilities.
| Function | Signature | Description |
|---|---|---|
| host | -> string | Local hostname |
| encodeUrl | text -> string | Percent-encode a URL |
| decodeUrl | text -> string | Percent-decode a URL |
Standard Library — json
libs/json.rdn JSON parsing and serialization.
| Function | Signature | Description |
|---|---|---|
| parse | text -> value | Parse JSON — arrays become lists, objects become list of (key value) pairs |
| stringify | value -> text | Serialize value to JSON |
"./libs/json.rdn" load
"[1, 2, 3]" parse call print [* (1 2 3)*]
(1 2 3) stringify call print [* [1,2,3]*]
Standard Library — strconv
libs/strconv.rdn String conversion utilities (Go-inspired).
| Function | Signature | Description |
|---|---|---|
| atoi | text -> integer | Parse string as integer |
| atof | text -> double | Parse string as float |
| parseBool | text -> boolean | Parse "true"/"false"/"1"/"0" |
| itoa | integer -> string | Format integer as string |
| formatBool | boolean -> string | Format boolean as "true"/"false" |
Standard Library — flag
libs/flag.rdn Command-line flag parser.
"./libs/flag.rdn" load
"o" "output" true "output file" defun
output let
"writing to: " print output print "\n" print
end addFlag call
"v" "verbose" false "verbose output" defun
"verbose mode\n" print
end addFlag call
execute call
positionals call each call print
| Function | Description |
|---|---|
| resetFlags | Clear state, reinstall -h/--help |
| addFlag | short long takesValue description callback → register flag |
| execute / executeOn | Run the parser |
| positionals | Get positional arguments |
| programName | Get program name |
| printHelp | Print usage and flags |
Native Module — files
nativelibs/files.c Text file I/O.
| Function | Signature |
|---|---|
| readLines | path -> list of strings |
| readText | path -> string |
| writeLines | path list -> true |
| appendLines | path list -> true |
| writeText | path text -> true |
| appendText | path text -> true |
Native Module — io
nativelibs/io.c Stdin reading.
| Function | Signature |
|---|---|
| readLine | -> string or null |
| readAllInput | -> string |
Native Module — json
nativelibs/json.c JSON parse/serialize.
| Function | Signature |
|---|---|
| parseJson | text -> value |
| stringifyJson | value -> text |
Native Module — math
nativelibs/math.c Math functions.
| Function | Signature |
|---|---|
| powerOf | base exponent -> double |
| sqrtOf | number -> double |
Native Module — net
nativelibs/net.c Network utilities.
| Function | Signature |
|---|---|
| hostName | -> string |
| urlEncode | text -> string |
| urlDecode | text -> string |
Native Module — path
nativelibs/path.c Path manipulation.
| Function | Signature |
|---|---|
| joinPath | left right -> string |
| baseName | path -> string |
| dirName | path -> string |
| extName | path -> string or null |
| isAbsolutePath | path -> boolean |
Native Module — process
nativelibs/process.c Command execution.
| Function | Signature |
|---|---|
| execStatus | command -> integer |
| execOutput | command -> string |
Native Module — strconv
nativelibs/strconv.c String conversion.
| Function | Signature |
|---|---|
| atoi | text -> integer |
| atof | text -> double |
| parseBool | text -> boolean |
| itoa | integer -> string |
| formatBool | boolean -> string |
Native Module — strings
nativelibs/strings.c String operations.
| Function | Signature |
|---|---|
| strContains | text part -> boolean |
| strHasPrefix | text prefix -> boolean |
| strHasSuffix | text suffix -> boolean |
| strTrimSpace | text -> string |
| strSplit | text sep -> list |
| strReplaceAll | text old new -> string |
Native Module — syscall
nativelibs/syscall.c System-level helpers.
| Function | Signature |
|---|---|
| pid | -> integer |
| getEnv | name -> string or null |
| sleepMs | ms -> true |
| epochTime | -> integer |
Native Module — unix
nativelibs/unix.c Filesystem operations.
| Function | Signature |
|---|---|
| cwd | -> string |
| pathExists | path -> boolean |
| makeDir | path -> true |
| removePath | path -> true |
| listDir | path -> list |
Embedding API
Raden exposes a single entry point for embedding:
// embed.c
#include "./include/src.h"
int main(void) {
char *argv[] = {
"host",
"./script.rdn",
};
return rdn_main(2, argv);
}
rdn_main
int rdn_main(int argc, char **argv) |
The first argument is the program name, the second is the script path. Returns 0 on success,
EXIT_FAILURE on error. If argc < 2, it starts the REPL.
Current embedding notes:
- The public embedding surface is minimal —
rdn_mainexecutes a file path - Native modules are loaded with
loadnativeat script runtime - Source-relative
loadandloadnativepath resolution works in the embedded context
Writing Native Modules
Native modules are shared libraries that register C functions callable from Raden. The public header is
include/rdn_native.h.
Module entry point
Every native module must export:
bool rdn_module_init(RDNModule *module);
Register functions
static bool myFunc(RDNApi *api) {
// ...
}
bool rdn_module_init(RDNModule *module) {
return module->register_function(module, "myFunc", myFunc);
}
Stack API
| Function | Description |
|---|---|
api->stack_size(api) |
Number of items on the stack |
api->type(api, index) |
Type of value at index (-1 = top) |
api->to_integer(api, index, &out) |
Get integer at index |
api->to_number(api, index, &out) |
Get double at index |
api->to_boolean(api, index, &out) |
Get boolean at index |
api->to_string(api, index) |
Get string at index (const char*) |
api->pop(api, count) |
Pop N items |
api->push_integer(api, value) |
Push an integer |
api->push_number(api, value) |
Push a double |
api->push_boolean(api, value) |
Push a boolean |
api->push_string(api, value) |
Push a string (copied) |
api->raise_error(api, message) |
Raise an error (return false) |
List API
| Function | Description |
|---|---|
api->push_list(api) |
Push an empty list |
api->list_len(api, index, &len) |
Get list length |
api->list_append(api, list_idx, value_idx) |
Append (cloned) value to list |
api->list_index(api, list_idx, item_idx) |
Push cloned item from list |
api->list_remove(api, list_idx, item_idx) |
Remove item from list |
Full example
// nativelibs/example.c
#include "../include/rdn_native.h"
static bool native_add(RDNApi *api) {
long left = 0, right = 0;
if (api->stack_size(api) < 2)
return api->raise_error(api, "add requires 2 operands");
if (!api->to_integer(api, -2, &left) ||
!api->to_integer(api, -1, &right))
return api->raise_error(api, "add requires integers");
api->pop(api, 2);
return api->push_integer(api, left + right);
}
bool rdn_module_init(RDNModule *module) {
return module->register_function(module, "add", native_add);
}
Build a native module
gcc -Wall -Wextra -Werror -ggdb -std=c11 -fPIC -shared \
mymodule.c -I. -o mymodule.so
Load a native module
"./mymodule.so" loadnative
[* now call registered functions by name*]
3 4 add call print [* 7*]
Editor Support
Neovim
The repo includes a Neovim runtime package:
cp -r ./nvim/* ~/.config/nvim/
This provides:
- File detection (
.rdn) - Syntax highlighting
- ftplugin defaults
- Basic indent rules
For LazyVim / lazy.nvim:
return {
{
dir = "/path/to/rdn/nvim",
name = "raden.nvim",
ft = "raden",
},
}
Treesitter
A starter Treesitter grammar scaffold is at treesitter/raden/.
Test Suite
Raden includes 50+ regression tests:
bash test/run.sh
Each test is a .rdn file in test/ with expected output in
test/expected/. The test runner compares stdout+stderr against the expected output and
verifies the exit code.
To add a new test:
touch test/my_test.rdn [* your test script*]
touch test/expected/my_test.out [* expected output*]
echo 0 > test/expected/my_test.status [* expected exit code (optional)*]