Spress
Spress is a tiny, dynamically-typed programming language implemented in a single C++ header. It supports integers, floats, booleans, strings, lists, hash maps, first-class functions, control flow, iteration, slicing, and external variable injection.
This language was made as a test to test the limits of state of the art LLMs.
Caution
DO NOT USE IN PRODUCTION. This is completely vibe coded with o4-mini-high.
Table of Contents
- Installation
- Getting Started
- Limitations
- Data Types
- Variables and Assignment
- Expressions
- Statements and Control Flow
- Functions
- Built-in Functions
- Iteration and Slicing
- External Variables Injection
- Grammar
Installation
Download this repo, cd to the directory where this code is, then run the
following commands.
Run an example:
spress example/quicksort.spress
Getting Started
Include spress.h in your C++ project and call:
#include "spress.h" // Evaluate code without injections: auto result = spress::Eval(R"( func main() { print("Hello, SPRESS!"); return 0; } )"); // Evaluate code with external injections: std::unordered_map<std::string, spress::Value> inj = {{"x", 3}, {"y", 4}}; auto sum = spress::Eval(R"( x = external; y = external; func main() { return x + y; } )", inj);
Limitations
- No classes.
- No stack traces.
- No optimizer.
- Probably many bugs (it was vibe coded).
Data Types
| Type | Literal Syntax | Example |
|---|---|---|
| Integer | 42 |
a = 10; |
| Float | 3.14 |
f = 2.0; |
| Boolean | true, false |
b = false; |
| String | "hello" |
s = "world"; |
| List | [ expr₁, expr₂, … ] |
l = [1,2,3]; |
| Map | { key₁:val₁, key₂:val₂, … } |
m = {"a":1,"b":2}; |
| Function | via func declaration |
see Functions |
Variables and Assignment
Global vs Local
- Assignments at the top level create global variables.
- Assignments inside functions create local variables (unless a global with the same name already exists).
Assignment Operator
- Uses
=to bind a value to a variable. - The assignment expression itself evaluates to the assigned value.
x = 100; # Defines a global variable x with value 100
func inc() {
x = x + 1; # Inside a function: if x was global, this refers to the global x
return x; # Returns the new value of x
}
func demo() {
a = 5; # Defines local variable a
b = a * 2; # Defines local variable b based on a
return b; # Returns 10
}
Expressions
Literals
Numbers (42, 3.14), strings ("hello"), booleans (true, false).
Variables
Identifiers referencing values.
Binary Operators
Arithmetic: +, -, *, /
Comparison: ==, !=, <, <=, >, >=
Bitwise: &, |, ^, <<, >>
Logical: &&, ||
Unary Operators
Logical NOT: !
Negation: -
Bitwise NOT: ~
Concatenation
- Lists:
[1,2] + [3]→[1,2,3] - Strings:
"a" + "b"→"ab"
Indexing & Slicing
- Single index:
a[2] - Slice:
a[start:end] - See Iteration & Slicing for details.
Function Calls
- Direct:
f(a, b) - First-class: assign functions to variables and call via
fnVar(args…)
Map Literals
{ key1: expr1, key2: expr2, … }
External Keyword
external denotes a value provided at runtime via injection.
Statements and Control Flow
<statement> ::= <expr>; # expression statement
| return <expr>; # return
| if (e) {…} # conditional
| while (e) {…} # loop
| for (v in e) {…}# for-in
if (x > 0) {
print("positive");
} else {
print("non-positive");
}
while (n > 0) {
n = n - 1;
}
for (i in [1,2,3]) {
print(i);
}
for (k, v in {"a":1,"b":2}) {
print(k, "→", v);
}
Functions
-
Defined with
func name(params…) { body } -
Parameters are passed by value.
-
Return via return expr;. Implicitly returns 0 if none.
func fib(n) {
if (n < 2) return n;
return fib(n-1) + fib(n-2);
}
print(fib(5)); # → 5
Built-in Functions
-
print(arg₁, arg₂, …)*: writes to stdout, returns 0. -
length(x): returns size of list, string, or map.
Iteration and Slicing
-
List or string indexing:
a[2] -
Slicing:
a[start:end]yields sub-list or substring -
Map indexing:
m["key"] -
Slice assignment:
l = [0,1,2,3];
l[1:3] = [9,9]; # → [0,9,9,3]
External Variables Injection
Use external in a top-level assignment to mark a variable for injection:
x = external;
func main() { return x * 2; }
Then provide at runtime:
spress::Eval(source, {{"x", 10}}); // → 20
Grammar
<program> ::= { <declaration> }
<declaration> ::= <function-decl> | <statement>
<function-decl> ::= "func" <identifier> "("
[ <identifier> { "," <identifier> } ]
")" <block>
<statement> ::= <expr-stmt>
| <return-stmt>
| <if-stmt>
| <while-stmt>
| <for-stmt>
<expr-stmt> ::= <expression> ";"
<return-stmt> ::= "return" <expression> ";"
<if-stmt> ::= "if" "(" <expression> ")" <block>
[ "else" <block> ]
<while-stmt> ::= "while" "(" <expression> ")" <block>
<for-stmt> ::= "for" "(" <identifier>
[ "," <identifier> ]
"in" <expression> ")"
<block>
<block> ::= "{" { <declaration> } "}"
<expression> ::= <assignment>
<assignment> ::= <logical-or> [ "=" <assignment> ]
<logical-or> ::= <logical-and> { "||" <logical-and> }
<logical-and> ::= <