Lispeum
Lispeum is a Lisp‑inspired language with postfix application and a compact low‑level stack machine. Programs are lists; the list’s tail decides how it runs.
Language At A Glance
- Postfix calls:
(arg1 arg2 name)
— callee in last position. - Only lists: code is nested lists; the tail position drives evaluation.
- Bytes as data: numeric values are two’s‑complement byte strings.
- Functions: define with
fn
; emit low‑level code withsk
.
Core Expressions
- Byte — a single 0–255 value.
- List —
( ... )
a sequence; the tail determines meaning. - Symbol — identifiers like
add
,int.sub
. - Error — a short error (e.g.,
"underflow"
).
Postfix Evaluation
- Call:
(a b fn-value)
— evaluate args, then call the tail function value. - Define:
(value name def)
— evaluatevalue
, bind atname
. - Inline function:
(args... ( body params fn ))
— define and call in one list. - Stack kernel:
(args... ( (low‑level‑body) sk ))
— build & run stack code. - Default: resolve each element; return the list of results.
The Low‑Level Stack Machine
Low‑level programs are sequences of tokens. Each token is either an opcode (one of the operations below) or a literal byte string. Literals are pushed; opcodes pop arguments and push results.
Execution Model
- Stack: last‑in/first‑out of byte strings.
- PC: program counter over tokens.
- Return: on end, if exactly one item on stack, return it; else error.
- Two’s‑complement: arithmetic interprets bytes as signed integers.
Opcodes
- add —
(a b -- sum)
; width grows to fit the result. - nand —
(a b -- ~(a & b))
on zero‑extended operands. - jump —
(tgt --)
set pc to signed tgt (bounds‑checked). - heap_set —
(key val --)
store val by key. - heap_get —
(key -- val)
fetch or empty bytes. - storage_set —
(key val --)
persist val. - storage_get —
(key -- val)
fetch or empty bytes.
Cost Model (Metering)
- Total‑only counter; optional limit caps all work.
- add: charge
len(a) + len(b)
. - nand: charge
2 * max(len(a), len(b))
. - jump: charge
1
. - heap_set/storage_set: charge
len(val)
. - heap_get/storage_get: charge
1
.
Building Functions
Create functions with fn
. The body can emit low‑level code with sk
using
positional placeholders $0
, $1
, … for arguments.
Inline
(1 2 ( ( ; body
$0 $1 add ; use args 0 and 1, add
) sk ))
Named function
(
( a b ( ( $0 $1 add ) sk ) ) ; body
( a b ) ; params
fn
) int.add def
; call (postfix)
(1 2 int.add) ; => 3
Examples
Add two numbers (low level)
[ 0x02 0x03 add ] ; => 0x05
Store and load from heap
[ "k" 0x02 0x03 add heap_set ; heap["k"] = 5
"k" heap_get ; => 0x05
]
Subtraction via two’s complement in sk
( 7 4 ( ( $1 $1 nand 1 add $0 add ) sk ) ) ; 7 - 4 => 3