11 KiB
11 KiB
Stack Language Specification v0.1
1. Overview
A statically-typed, stack-based language with postfix notation combining the execution model of HP's RPL, the type system of C and Rust, and modern array operations from Uiua.
Design Principles
- All operations are postfix (RPN)
- Stack-based execution (no local variables)
- Static typing with type inference
- Manual heap memory management
- C-like syntax style adapted to postfix notation
- Functions manipulate the stack directly
2. Lexical Structure
2.1 Comments
// Single-line comment
2.2 Identifiers
- Start with letter or underscore:
[a-zA-Z_][a-zA-Z0-9_]* - Case-sensitive
2.3 Literals
Integer Literals
42 // i32 (default)
42i64 // i64
0xFF // hexadecimal
0b1010 // binary
Floating Point Literals
3.14 // f64 (default)
3.14f32 // f32
String Literals
"hello world"
"escape sequences: \n \t \\ \""
Boolean Literals
true
false
Array Literals
[1 2 3 4 5] // array of i32
[1.0 2.0 3.0] // array of f64
[[1 2] [3 4]] // 2D array
3. Type System
3.1 Primitive Types
i8,i16,i32,i64- Signed integersu8,u16,u32,u64- Unsigned integersf32,f64- Floating pointbool- Booleanchar- Single character (UTF-8)ptr<T>- Raw pointer to type T
3.2 Compound Types
Arrays
[T; N] // Fixed-size array
[T] // Dynamic array (heap-allocated)
Structs
struct Point {
x: f64,
y: f64,
}
Tagged Unions
union Result<T, E> {
Ok(T),
Err(E),
}
3.3 Type Inference
Types are inferred where possible but can be explicitly annotated:
42 :i64 // Annotate literal
x get :f32 // Annotate stack value
4. Stack Operations
4.1 Stack Manipulation
dup // ( a -- a a ) Duplicate top
drop // ( a -- ) Remove top
swap // ( a b -- b a ) Swap top two
over // ( a b -- a b a ) Copy second to top
rot // ( a b c -- b c a ) Rotate three items
-rot // ( a b c -- c a b ) Rotate three items reverse
2dup // ( a b -- a b a b ) Duplicate top two
2drop // ( a b -- ) Drop top two
nip // ( a b -- b ) Drop second
tuck // ( a b -- b a b ) Copy top below second
4.2 Stack Inspection
depth // ( -- n ) Push stack depth
pick // ( n -- x ) Copy nth item to top (0 = top)
roll // ( n -- ) Move nth item to top
5. Operators (Postfix)
5.1 Arithmetic
3 4 + // ( a b -- result ) Addition
10 3 - // Subtraction
5 6 * // Multiplication
20 4 / // Division
17 5 % // Modulo
2 8 ** // Exponentiation
5.2 Comparison
5 3 > // Greater than
5 3 >= // Greater or equal
5 3 < // Less than
5 3 <= // Less or equal
5 5 == // Equal
5 3 != // Not equal
5.3 Logical
true false && // Logical AND
true false || // Logical OR
true ! // Logical NOT
5.4 Bitwise
0xFF 0x0F & // Bitwise AND
0xFF 0x0F | // Bitwise OR
0xFF 0x0F ^ // Bitwise XOR
0xFF ~ // Bitwise NOT
8 2 << // Left shift
8 2 >> // Right shift
6. Functions
Functions consume arguments from the stack and push results to the stack.
6.1 Function Definition
fn add_point : (Point Point -- Point) {
// Stack: p1 p2
swap .x get // p2.x
swap .x get // p1.x
+ // sum_x
swap .y get // p2.y
swap .y get // p1.y
+ // sum_y
Point::new // Create new Point
}
6.2 Function Signature
Format: (input_types -- output_types)
fn square : (i32 -- i32) {
dup *
}
fn divmod : (i32 i32 -- i32 i32) {
2dup / -rot %
}
fn no_op : (-- ) {
// Takes nothing, returns nothing
}
6.3 Generic Functions
fn identity<T> : (T -- T) {
// Simply returns the input
}
fn swap_pair<T, U> : (T U -- U T) {
swap
}
7. Control Flow
7.1 Conditionals
// if-then
condition if {
// Executed if true
}
// if-then-else
x 0 > if {
// Positive
} else {
// Non-positive
}
7.2 Loops
While Loop
// While condition is true
{ condition } while {
// Loop body
}
// Example: sum 1 to 10
0 1 // sum counter
{ dup 10 <= } while {
2dup + // Add counter to sum
swap 1 + swap // Increment counter
}
drop // Drop counter, leave sum
For Loop (Range-based)
1 10 for i {
i print
}
// Equivalent to:
1 10 range each { print }
7.3 Loop Control
break // Exit loop
continue // Skip to next iteration
8. Memory Management
8.1 Stack vs Heap
- Stack: Automatic, fixed-size types
- Heap: Manual, dynamic allocations
8.2 Heap Operations
// Allocate
Point::new heap_alloc // ( Point -- ptr<Point> )
// Dereference
ptr @ // ( ptr<T> -- T )
// Store
value ptr ! // ( T ptr<T> -- )
// Free
ptr free // ( ptr<T> -- )
8.3 Example
// Create heap-allocated point
3.0 4.0 Point::new heap_alloc // ptr<Point>
dup .x get print // Print x (3.0)
free // Clean up
9. Data Structures
9.1 Struct Definition and Usage
struct Rectangle {
width: f64,
height: f64,
}
// Constructor (auto-generated)
10.0 20.0 Rectangle::new // Create Rectangle
// Field access (postfix)
rect .width get // Get width
rect .width 15.0 set // Set width
// Method-like functions
fn Rectangle::area : (Rectangle -- f64) {
dup .width get
swap .height get
*
}
// Usage
rect Rectangle::area // Calculate area
9.2 Tagged Unions
union Option<T> {
Some(T),
None,
}
// Construction
42 Option::Some // Create Some(42)
Option::None // Create None
// Pattern matching
value match {
Some(x) => {
x print
},
None => {
"Nothing" print
},
}
9.3 Enums
enum Status {
Pending,
Active,
Complete,
}
Status::Active // Create enum value
10. Traits
Traits define shared behavior across types.
10.1 Trait Definition
trait Drawable {
fn draw : (Self -- );
}
trait Add<T> {
fn add : (Self T -- Self);
}
10.2 Trait Implementation
impl Drawable for Rectangle {
fn draw : (Rectangle -- ) {
"Drawing rectangle" print
dup .width get print
.height get print
}
}
impl Add<Point> for Point {
fn add : (Point Point -- Point) {
// Implementation from earlier
swap .x get swap .x get +
swap .y get swap .y get +
Point::new
}
}
10.3 Trait Bounds
fn draw_twice<T: Drawable> : (T -- ) {
dup draw
draw
}
11. Array Operations (Uiua-inspired)
11.1 Basic Array Operations
// Creation
[1 2 3 4 5] range // Create range array
// Shape operations
arr shape // Get shape
arr [2 3] reshape // Reshape to 2x3
// Element access
arr 2 @ // Index access
arr [1 3] slice // Slice array
11.2 Array Combinators
// Map
[1 2 3 4] { 2 * } map // [2 4 6 8]
// Filter
[1 2 3 4 5] { 2 % 0 == } filter // [2 4]
// Reduce
[1 2 3 4] 0 { + } reduce // 10
// Each (apply to each element)
[[1 2] [3 4]] { sum } each // [3 7]
11.3 Array Arithmetic
[1 2 3] [4 5 6] .+ // Element-wise add: [5 7 9]
[1 2 3] [4 5 6] .* // Element-wise multiply: [4 10 18]
[1 2 3] 2 .* // Scalar multiply: [2 4 6]
11.4 Array Manipulation
[1 2 3] [4 5 6] ++ // Concatenate: [1 2 3 4 5 6]
[1 2 3] reverse // [3 2 1]
[[1 2] [3 4]] transpose // [[1 3] [2 4]]
[1 2 3 4] 2 window // [[1 2] [2 3] [3 4]]
12. Eval Operator
Execute code dynamically at runtime.
// Evaluate string as code
"2 3 +" eval // Pushes 5
// Build and execute code
"fn square : (i32 -- i32) { dup * }" eval
5 square // 25
// Dynamic dispatch
operation_name " get" ++ eval // Call function by name
Security Note: Eval should be used carefully as it can execute arbitrary code.
13. Standard Library Concepts
13.1 I/O
"Hello" print // Print to stdout
"Enter name: " input // Read from stdin
"file.txt" read // Read file contents
"data" "file.txt" write // Write to file
13.2 String Operations
"hello" " world" ++ // Concatenate: "hello world"
"hello" length // 5
"hello" 1 3 substr // "el"
"a,b,c" "," split // ["a" "b" "c"]
["a" "b"] "," join // "a,b"
13.3 Type Conversion
42 to_f64 // Convert i32 to f64
"123" parse_i32 // Parse string to i32
3.14 to_string // Convert to string
14. Example Programs
14.1 Factorial
fn factorial : (i32 -- i32) {
dup 1 <= if {
drop 1
} else {
dup 1 - factorial *
}
}
5 factorial print // 120
14.2 FizzBuzz
fn fizzbuzz : (i32 -- ) {
dup 15 % 0 == if {
drop "FizzBuzz" print
} else {
dup 3 % 0 == if {
drop "Fizz" print
} else {
dup 5 % 0 == if {
drop "Buzz" print
} else {
print
}
}
}
}
1 100 for i {
i fizzbuzz
}
14.3 Using Structs and Traits
struct Circle {
radius: f64,
}
impl Drawable for Circle {
fn draw : (Circle -- ) {
"Circle with radius: " print
.radius get print
}
}
fn Circle::area : (Circle -- f64) {
.radius get
2.0 **
3.14159 *
}
// Usage
5.0 Circle::new
dup draw // Draw the circle
Circle::area print // Print area
14.4 Array Processing
// Sum of squares of even numbers from 1 to 10
[1 2 3 4 5 6 7 8 9 10]
{ 2 % 0 == } filter // Keep even numbers
{ dup * } map // Square each
0 { + } reduce // Sum
print // 220
15. Implementation Notes
15.1 Type Checking
- Perform static type checking with full type inference
- Track stack types at compile time
- Ensure function signatures match actual stack effects
15.2 Interpreter Design
- Value stack: runtime execution stack
- Type stack: compile-time type tracking
- Call stack: function call management
- Heap: global allocator
15.3 Future Compilation
- Compile to bytecode for interpretation
- Potential LLVM backend for native compilation
- Stack optimization for register allocation
16. Syntax Summary
Stack Manipulation
dup drop swap over rot pick roll
Arithmetic (postfix)
a b + a b - a b * a b / a b % a b **
Comparison
a b < a b > a b <= a b >= a b == a b !=
Control Flow
cond if { ... }
cond if { ... } else { ... }
{ cond } while { ... }
start end for var { ... }
Functions
fn name : (inputs -- outputs) { body }
fn name<T, U> : (T U -- U) { body }
Memory
value heap_alloc ptr @ value ptr ! ptr free
Arrays
[1 2 3]
arr { fn } map
arr { fn } filter
arr init { fn } reduce
Version: 0.1
Status: Draft Specification
License: Define your license here