No results found for
Raden logo

Raden

A small stack-based scripting language with a C interpreter and native module API. Postfix syntax, first-class functions, and seamless C integration.

# hello.rdn
                        "hello, world!\n" print

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

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:

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:

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)*]
Raden — MIT License — GitHub