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
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
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) |
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 |
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)