48 KiB
Stack Language Specification
Version: 0.6
Status: Draft Specification
Changes:
- 0.5 (AI)
- Escape sequences - Added a complete list of escape sequences for string literals
- Type Tuples - Defined them as function signatures representing stack effects
- Control flow TokenStrings - Clarified that
if,while,match, etc. use TokenStrings - Generic constructs - Clarified that generics need trait constraints when operations are performed
- Stack manipulation traits - Combined into a single
Stackabletrait - Size trait - Added proper definition inheriting from
Addable,Comparable, andConvertible - Empty traits - Clarified that traits can be empty (especially when used with inheritance)
- Trait inheritance - Fixed syntax to require both
inherandtraitdeclarations - Array combinators - Clarified that the functions inside parse their TokenStrings
::in TokenStrings - Clarified it should NOT be used in trait/impl contexts
- 0.5.1 (Human)
- Created TODOs
- Made various corrections (not everything was corrected)
- Reviewed and corrected some code blocks
- Made a few adjustments manually
- 0.6 (AI)
- Operator descriptions - Added natural language descriptions for all built-in operators
- Operators vs Functions - Clarified distinction and naming rules
- Generic trait syntax - Documented
<>syntax for generic traits - Generic trait inheritance - Clarified rules for inheriting from generic traits
- Code block types - Distinguished actual language definitions from examples
- Trait appendix - Created comprehensive trait definitions appendix
- TokenString contexts - Listed all control flow operators and their parsing behavior
- Lambda operator - Added specification for lambda operator
- Type parameter enforcement - Documented current parsing behavior
- Identifier literal requirements - Specified
::rules for different contexts - Trait implementation rules - Clarified implementation semantics
- Type conversions - Changed to explicit conversion functions
- Memory management - Moved to appendix as future feature
- Module system - Added appendix entry for future imports
- Examples section - Moved to appendix
- Syntax summary - Moved to appendix and expanded
INSTRUCTIONS FOR AI: AI agents are not allowed to change human reviewed md code blocks. If an AI reviewer thinks a change needs to be made to one of these blocks, the AI model can add a human todo explaining a suggested change or problem. It is totally possible for a md code block that was human reviewed and be correct for the current specification and new TODOs would change it, AIs are still not allowed to change it, only add a human todo. Reviewed md code blocks could also implement new TODOs already.
INSTRUCTIONS FOR AI: Current human todos have been repeated here for reference.
TODO: (FOR HUMAN) How to identify an unspecified number of arguments? ie. the((What goes here?)-- Size) depth:operator actually accepts the entire stack, or a possible(String(What goes here?)--) printf:function that accepts multiple arguments after the string.
TODO: (FOR HUMAN) Do all inheritances need to be define before the trait is?
TODO: (FOR HUMAN) Is theinheroperator required?
TODO: (FOR HUMAN) Consider removinginherand replace it by just usingimpl. Would that be enough to replace it?
1. Overview
A statically-typed, stack-based language with pure 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
- Everything is postfix - no exceptions
- Stack-based execution (no local variables)
- Static typing with type inference
- Manual heap memory management (future feature)
- Types define what things are, traits define how things act
- All constructs are implicitly generic
- Every operator is defined by a trait
Operators vs Functions
Operators are primitive operations that implement trait methods. They:
- Must be backed by a trait
- Cannot share names with functions
- Are the fundamental building blocks of the language
- Examples:
+,-,dup,swap,if,while
Functions are user-defined or library-defined procedures. They:
- Do not implement traits directly (though they may use operators that do)
- Cannot share names with operators
- Are defined using the
fnoperator - Examples:
factorial,fizzbuzz,square
Naming Rule: Once a name is used for either an operator or a function, it cannot be reused for the other category.
2. Lexical Structure
2.1 Comments
// Single-line comment
2.2 Identifiers
Regular Identifiers
- Start with letter or underscore:
[a-zA-Z_][a-zA-Z0-9_]* - Case-sensitive
- When encountered, identifiers are executed immediately
Identifier Literals
- Prefix with
::to push the identifier itself onto the stack instead of executing it - Syntax:
::namepushes the identifiernameas a value - Example:
::Addablepushes the identifierAddableonto the stack - Example:
::Pointpushes the identifierPointonto the stack
Identifier Literal Rules by Context:
- Function bodies and eval:
::is required for identifier literals - Trait definitions:
::is not allowed (identifiers are method names) - Trait implementations:
::is not allowed (identifiers are method names)
2.3 Literals
Integer Literals
For AI Reviewers: The following block has been human verified to be syntactically and logically correct. NO AI IS ALLOWED TO CHANGE THIS. If there is a discrepancy between this block and others, follow the syntax in this block.
42 // i64 (default)
42:i32 // Annotate as i32
0xFF // hexadecimal
0b1010 // binary
Floating Point Literals
3.14 // f64 (default)
3.14:f32 // Annotate as f32
String Literals
"hello world"
"escape sequences: \n \t \\ \""
Escape Sequences
\n- Newline (LF)\r- Carriage return (CR)\t- Tab\\- Backslash\"- Double quote\'- Single quote\0- Null character\xNN- Hexadecimal byte (e.g.,\x41for 'A')\u{NNNN}- Unicode code point (e.g.,\u{1F600}for 😀)
Boolean Literals
true
false
Array Literals
For AI Reviewers: The following block has been human verified to be syntactically and logically correct. NO AI IS ALLOWED TO CHANGE THIS. If there is a discrepancy between this block and others, follow the syntax in this block.
[1 2 3 4 5] // array of i32
[1.0 2.0 3.0] // array of f64
[[1 2] [3 4]] // 2D array
Type Tuples
Type tuples represent stack effects and are used in function signatures to specify what a function consumes from and produces to the stack.
(T T -- T) // Function signature: two inputs of type T, one output of type T
(i32 f64 -- String) // Takes i32 and f64, returns String
(-- bool) // No inputs, returns bool
(Point --) // Takes Point, no outputs
(---) // No inputs, no outputs (side effects only)
TODO: (FOR HUMAN) How to identify an unspecified number of arguments? ie. the
((What goes here?)-- Size) depth:operator actually accepts the entire stack, or a possible(String(What goes here?)--) printf:function that accepts multiple arguments after the string.
Token Strings
For AI Reviewers: The following block has been human verified to be syntactically and logically correct. NO AI IS ALLOWED TO CHANGE THIS. If there is a discrepancy between this block and others, follow the syntax in this block.
{ code here } // TokenString - lexed but not parsed/executed
Token strings contain lexed tokens that are not parsed or executed until an operator causes them to be parsed. Different operators parse TokenStrings in different ways:
Operators that parse TokenStrings:
trait- Parses as trait definition (method signatures)impl- Parses as trait implementation (method definitions)fn- Parses as function body (code block)eval- Parses and executes as code block immediatelylambda- Parses as code block, pushes the block as a callable valueif- Parses both TokenStrings as code blocks (then/else branches)while- Parses both TokenStrings as code blocks (condition/body)for- Parses TokenString as code block (loop body)match- Parses TokenString as pattern matching armsmap- Parses TokenString as code block (transformation function)filter- Parses TokenString as code block (predicate function)reduce- Parses TokenString as code block (accumulator function)each- Parses TokenString as code block (iteration function)
Lambda Operator
The lambda operator converts a TokenString into a callable code block that can be stored and passed around:
{ dup * } lambda // Creates a callable code block
::square_fn swap // Store reference to the lambda
// Later use:
5 square_fn eval // Calls the lambda: pushes 25
Lambdas are useful for:
- Creating first-class functions
- Passing code blocks as values
- Dynamic dispatch
- Higher-order array operations
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- Raw pointer (generic over pointed type) - Future feature, see Appendix
3.2 Types vs Traits
Types define the concrete structure and memory layout:
Point struct- Point is a typeRectangle struct- Rectangle is a type
Traits define behavioral contracts - how things act:
{ ... } ::Addable trait- Addable is a trait{ ... } ::Drawable trait- Drawable is a trait
Key Distinction:
- A value has a type (what it is structurally)
- A value implements a trait (how it behaves)
- Types are concrete; traits are interfaces
- Functions can be generic over traits
- Functions can have types and traits defined as return types
- Every operator must be backed by a trait
3.3 Generic Constructs
Functions, structs, and unions can be generic over type parameters using the <> syntax. Type parameters must be constrained by traits when operations are performed on them.
Note on Type Parameters: Type parameters are currently only suggestions when parsing code blocks. The compiler does not yet enforce that type parameters actually constrain how operators and functions act at parse time. This is documented as a possible future enhancement in the Appendix.
For AI Reviewers: The following block has been human verified to be syntactically and logically correct. NO AI IS ALLOWED TO CHANGE THIS. If there is a discrepancy between this block and others, follow the syntax in this block.
// Function generic over any type with Multiplyable constraint
(T -- T) { dup * } ::square<T:Multiplyable> fn
// Struct generic over field type T
(T T --) { x: y: } ::Point<T> struct
// Union generic over variant type T
(T --) { Some(T) None } ::Option<T> union
Generic Trait Syntax
Traits can be generic using the <> syntax:
// Generic trait over type T
{ (Self T -- Self) append: } ::Container<T> trait
// Generic trait with multiple type parameters
{ (Self K -- V) get: (Self K V -- Self) insert: } ::Map<K V> trait
Generic Trait Inheritance
When inheriting from a generic trait, you must either:
- Make the inheriting trait similarly generic with the same parameters
- Specify concrete types for the generic parameters
// Inheriting trait is also generic
[ ::Container<T> ] ::Stack<T> inher
{ (Self -- T) pop: } ::Stack<T> trait
// Inheriting trait specifies concrete type
[ ::Container<i32> ] ::IntStack inher
{ (Self -- i32) pop: } ::IntStack trait
Important: Unconstrained generic functions (those that don't perform operations on their type parameters) can omit trait constraints.
// Generic identity - works with any type (no operations performed)
(T -- T) { } ::identity fn
4. Trait System
4.1 Standard Traits
Traits define behavioral contracts. Every operator in the language is backed by one or more traits. See Appendix A for complete trait definitions.
Stack Manipulation Trait
The Stackable trait provides fundamental stack manipulation operations:
{
(Self -- Self Self) dup: // Duplicate the top item
(Self -- ) drop: // Remove the top item
(Self Self -- Self Self) swap: // Swap the top two items
(Self Self -- Self Self Self) over: // Copy second item to top
(Self Self Self -- Self Self Self) rot: // Rotate top three items
(Size -- Self) pick: // Copy nth item to top (0 = top)
(Size Size -- ) roll: // Rotate n items, times times
(-- Size) depth: // Push current stack depth
} ::Stackable trait
Size Trait
The Size trait represents types suitable for indexing and sizing operations:
[ ::Addable ::Comparable ::Convertible<i64> ] ::Size inher
{ } ::Size trait
Types implementing Size can be used as indices, loop bounds, and array sizes. Standard implementations include all integer types (i8, i16, i32, i64, u8, u16, u32, u64).
Arithmetic Traits
// Addition and subtraction operations
{
(Self Self -- Self) +: // Add two values
(Self Self -- Self) -: // Subtract two values
} ::Addable trait
// Multiplication, division, and modulo operations
{
(Self Self -- Self) *: // Multiply two values
(Self Self -- Self) /: // Divide two values
(Self Self -- Self) %: // Modulo operation
} ::Multiplyable trait
// Exponentiation operations
{
(Self Self -- Self) ^: // Raise to power
} ::Exponentiable trait
// Logarithmic operations
{
(Self Self -- Self) logb: // Logarithm with custom base
(Self -- Self) log: // Logarithm base 10
(Self -- Self) ln: // Natural logarithm
} ::Logarithmic trait
Comparison Traits
// Ordering operations
{
(Self Self -- bool) >: // Greater than
(Self Self -- bool) >=: // Greater than or equal
(Self Self -- bool) <: // Less than
(Self Self -- bool) <=: // Less than or equal
} ::Orderable trait
// Equality operations
{
(Self Self -- bool) ==: // Equal to
(Self Self -- bool) !=: // Not equal to
} ::Equatable trait
// Comparable combines ordering and equality
[ ::Orderable ::Equatable ] ::Comparable inher
{ } ::Comparable trait
Logical Operations Traits
// Logical operations
{
(Self -- bool) truthy: // Convert to boolean (truthiness)
(Self Self -- Self) and: // Logical AND
(Self Self -- Self) or: // Logical OR
(Self -- Self) not: // Logical NOT
} ::Logical trait
Bitwise Operations Traits
// Bitwise operations
{
(Self Self -- Self) bitand: // Bitwise AND
(Self Self -- Self) bitor: // Bitwise OR
(Self Self -- Self) bitxor: // Bitwise XOR
(Self -- Self) bitnot: // Bitwise NOT
(Self Size -- Self) shl: // Left shift
(Self Size -- Self) shr: // Right shift
} ::Bitwise trait
Container Traits
// Size information
{
(Self -- i64) length: // Get length/size of container
} ::Sized trait
// Element selection
{
(Self Size -- T) at: // Access element at index
} ::Selectable<T> trait
// Concatenation
{
(Self Self -- Self) concat: // Concatenate two containers
} ::Concatenable trait
// Slicing
{
(Self Size Size -- Self) slice: // Extract slice from start to end
} ::Sliceable trait
// ArrayOf combines container operations
[ ::Sized ::Selectable<T> ::Sliceable ] ::ArrayOf<T> inher
{ } ::ArrayOf<T> trait
String Traits
// String operations
[ ::Concatenable ] ::String inher
{
(Self Size Size -- Self) substr: // Extract substring
(Self Self -- ArrayOf<Self>) split: // Split by delimiter
} ::String trait
Conversion Traits
// Type conversion (uses explicit conversion functions)
{
(Self -- i8) to_i8:
(Self -- i16) to_i16:
(Self -- i32) to_i32:
(Self -- i64) to_i64:
(Self -- u8) to_u8:
(Self -- u16) to_u16:
(Self -- u32) to_u32:
(Self -- u64) to_u64:
(Self -- f32) to_f32:
(Self -- f64) to_f64:
} ::Convertible trait
// String conversion
{
(Self -- String) to_str: // Convert to string representation
} ::Stringifiable trait
// Parse from string
{
(String -- Self) parse: // Parse from string
} ::Parseable trait
Numeric Composite Trait
The Number trait represents the full suite of numeric operations by inheriting from multiple traits:
[ ::Addable ::Multiplyable ::Exponentiable ::Comparable ::Logarithmic ] ::Number inher
{ } ::Number trait
Meta-Traits
Traits for defining and working with traits themselves:
// Marks identifiers
{ } ::Identifier trait
// Operations for trait manipulation
{
(TokenString Identifier --) trait: // Define a trait
(Identifier TokenString Identifier --) impl: // Implement a trait
(ArrayOf<Identifier> Identifier --) inher: // Declare trait inheritance
} ::Implementable trait
4.2 Trait Definition
Syntax: { function_signatures } ::identifier trait
Traits can be defined with or without method signatures. Empty traits are valid and are typically used when inheriting from other traits to create composite traits (marker traits).
Example - Actual Language Definitions:
// Trait with methods
{
(Self -- ) draw:
} ::Drawable trait
// Trait with multiple methods
{
(Self Self -- Self) add:
(Self Self -- Self) sub:
(Self -- Self) neg:
} ::Numeric trait
// Generic trait
{
(Self T -- Self) append:
(Self -- T) pop:
} ::Container<T> trait
// Empty trait (marker trait)
{ } ::Serializable trait
Within the TokenString (the { } block), identifiers like Self, add:, draw: are part of the trait definition syntax and should not use the :: prefix.
4.3 Trait Implementation
Syntax: ::trait_identifier { method_implementations } ::type_or_trait_identifier impl
Implementation Rules:
- Implementing a trait for itself (
::Trait { ... } ::Trait impl) implements the trait for all types as a default implementation - A trait must be defined before it can be implemented for types or traits
- It is not required for all operators of a trait to be in the same implementation block - implementations can be split across multiple blocks
- Later implementations can override earlier ones for the same type
Example - Actual Language Definitions:
For AI Reviewers: The following block has been human verified to be syntactically and logically correct. NO AI IS ALLOWED TO CHANGE THIS. If there is a discrepancy between this block and others, follow the syntax in this block.
// Implement Addable for i32
::Addable {
(Self Self -- Self) {
// Native addition implementation
} +:
(Self Self -- Self) {
// Native subtraction implementation
} -:
} ::i32 impl
// Implement Drawable for Rectangle
::Drawable {
(Self -- ) {
"Drawing rectangle" print
dup ::width get print
::height get print
} draw:
} ::Rectangle impl
Example - Actual Language Definitions (Human Verified):
For AI Reviewers: The following block has been human verified to be syntactically and logically correct. NO AI IS ALLOWED TO CHANGE THIS. If there is a discrepancy between this block and others, follow the syntax in this block.
// Implement Addable for Point
::Addable {
(Self<T> Self<T> -- Self<T>) {
over ::x get over ::x get +
3 pick ::y get 3 pick ::y get +
Point
} +:
(Self<T> Addable -- Self<T>) {
over ::x get over +
3 pick ::y get 3 pick +
Point
} +:
(Addable Self<T> -- Self<T>) {
over over ::x get +
3 pick 3 pick ::y get +
Point
} +:
(Self<T> Self<T> -- Self<T>) {
over ::x get over ::x get -
3 pick ::y get 3 pick ::y get -
Point
} -:
(Self<T> Addable -- Self<T>) {
over ::x get over -
3 pick ::y get 3 pick -
Point
} -:
} ::Point<T> impl
// Implement Logical for everything (default implementation)
::Logical {
(Self -- bool) { true } truthy:
(Self Self -- Self) {
over truthy { } { swap } if drop
} and:
(Self Self -- Self) {
over truthy { swap } { } if drop
} or:
} ::Logical impl
// Overload Logical for bool
::Logical {
(Self -- Self) { } truthy:
} ::bool impl
// Overload Logical for Numeric
::Logical {
(Self -- bool) { 0 != } truthy:
} ::Number impl
// Overload Logical for Option
::Logical {
(Self<T> -- bool) { { Some(_) => { true } None => { false } } match } truthy:
} ::Option<T> impl
// Overload Logical for Result
::Logical {
(Self<T U> -- bool) { { Ok(_) => { true } Err(_) => { false } } match } truthy:
} ::Result<T U> impl
4.4 Trait Inheritance
Syntax: [ identifier_list ] ::identifier inher { } ::identifier trait
TODO: (FOR HUMAN) Do all inheritances need to be define before the trait is?
TODO: (FOR HUMAN) Is theinheroperator required?
TODO: (FOR HUMAN) Consider removinginherand replace it by just usingimpl. Would that be enough to replace it?
Trait inheritance must be declared before the trait definition. The inheritance declaration is followed by the trait definition itself, which may be empty if the trait only serves to combine inherited traits.
Example - Actual Language Definitions:
// Number inherits from multiple arithmetic traits
[ ::Addable ::Multiplyable ] ::BasicNumber inher
{ } ::BasicNumber trait
// Full Number inherits everything numeric
[ ::Addable ::Multiplyable ::Exponentiable ::Comparable ::Logarithmic ] ::Number inher
{ } ::Number trait
// Complex inheritance with additional methods
[ ::Drawable ::Transformable ::Collidable ] ::GameObject inher
{
(Self -- ) update:
(Self -- ) destroy:
} ::GameObject trait
// Size trait inherits and defines composite behavior
[ ::Addable ::Comparable ::Convertible<i64> ] ::Size inher
{ } ::Size trait
4.5 Using Traits in Functions
Example - Using Actual Definitions:
// Function requiring Drawable trait
(Drawable -- ) {
draw
} ::draw_twice fn
// Function requiring multiple trait bounds
(Number Number -- Number) {
dup * swap dup * + // Pythagorean: a² + b²
} ::sum_of_squares fn
5. Stack Operations
5.1 Stack Manipulation
All stack operations are backed by the Stackable trait.
dup // ( a -- a a ) Duplicate top item
drop // ( a -- ) Remove top item
swap // ( a b -- b a ) Swap top two items
over // ( a b -- a b a ) Copy second item to top
rot // ( a b c -- b c a ) Rotate top three items
5.2 Stack Inspection
depth // ( -- n ) Push current stack depth
pick // ( n -- x ) Copy nth item to top (0 = top)
roll // ( n times -- ) Rotate n items, times times
Roll Examples:
// Stack: a b c d e
3 1 roll // Rotate top 3 items once: a b d e c
3 2 roll // Rotate top 3 items twice: a b e c d
5 1 roll // Rotate all 5 items once: b c d e a
4 3 roll // Rotate top 4 items three times: a d e c b
6. Operators (Postfix)
Every operator is backed by a trait and must be implemented for types that use it.
6.1 Arithmetic
3 4 + // ( a b -- result ) Addition - add two numbers
10 3 - // ( a b -- result ) Subtraction - subtract b from a
5 6 * // ( a b -- result ) Multiplication - multiply two numbers
20 4 / // ( a b -- result ) Division - divide a by b
17 5 % // ( a b -- result ) Modulo - remainder of a divided by b
2 8 ^ // ( a b -- result ) Exponentiation - raise a to power b
100 log // ( a -- result ) Logarithm base 10 of a
2.718 ln // ( a -- result ) Natural logarithm of a
6.2 Comparison
5 3 > // ( a b -- bool ) Greater than - true if a > b
5 3 >= // ( a b -- bool ) Greater or equal - true if a >= b
5 3 < // ( a b -- bool ) Less than - true if a < b
5 3 <= // ( a b -- bool ) Less or equal - true if a <= b
5 5 == // ( a b -- bool ) Equal - true if a == b
5 3 != // ( a b -- bool ) Not equal - true if a != b
6.3 Logical
true false and // ( a b -- result ) Logical AND - true if both are truthy
true false or // ( a b -- result ) Logical OR - true if either is truthy
true not // ( a -- result ) Logical NOT - inverts truthiness
6.4 Bitwise
0xFF 0x0F bitand // ( a b -- result ) Bitwise AND - AND each bit
0xFF 0x0F bitor // ( a b -- result ) Bitwise OR - OR each bit
0xFF 0x0F bitxor // ( a b -- result ) Bitwise XOR - XOR each bit
0xFF bitnot // ( a -- result ) Bitwise NOT - invert all bits
8 2 shl // ( a n -- result ) Left shift - shift a left by n bits
8 2 shr // ( a n -- result ) Right shift - shift a right by n bits
7. Functions (Postfix Definition)
Functions are defined in postfix notation. The signature and body come before the name.
7.1 Basic Function Definition
Syntax: (inputs -- outputs) { body } ::name fn
Example - Using Actual Definitions:
// Define a square function (requires Multiplyable)
(T -- T) { dup * } ::square<T:Multiplyable> fn
// Use it
5 square // 25
// Multiple inputs and outputs
(Number Number -- Number Number) {
over over / swap %
} ::divmod fn
10 3 divmod // 3 1 (quotient remainder)
7.2 Generic Functions with Trait Constraints
Syntax: (type_sig) { body } ::name<type_params> fn
Example - Using Actual Definitions:
// Generic identity - works with any type (no operations, no constraint needed)
(T -- T) { } ::identity<T> fn
// Requires Addable
(T T -- T) {
+
} ::add_values<T:Addable> fn
// Requires Number
(T -- T) {
dup 0 > { } { 0 swap - } if
} ::abs<T:Number> fn
8. Control Flow (Postfix)
8.1 Conditionals
Syntax: condition { then-block } { else-block } if
The if operator parses both TokenStrings as code blocks (then/else branches).
Example - Using Actual Definitions:
// if-then (else block is empty)
x 0 > { "positive" print } {} if
// if-then-else
x 0 >
{ "positive" print }
{ "non-positive" print }
if
// The condition comes first, then both blocks, then 'if'
a b >
{ a }
{ b }
if
// Nested
x 0 >
{
y 0 >
{ "both positive" print }
{ "x positive, y not" print }
if
}
{ "x not positive" print }
if
8.2 Loops
While Loop
Syntax: { condition-block } { body-block } while
The while operator parses both TokenStrings as code blocks (condition/body).
Example - Using Actual Definitions:
// Sum 1 to 10
0 1 // sum counter
{ dup 10 <= } // condition block
{ // body block
over over + // Add counter to sum
swap 1 + swap // Increment counter
}
while
drop // Drop counter, leave sum
// Infinite loop with break
{ true } {
// body
condition { break } {} if
} while
For Loop
Syntax: start end { body-with-counter } for
The for operator parses the TokenString as a code block (loop body).
Example - Using Actual Definitions:
// The loop variable is implicitly pushed to stack in each iteration
1 10 {
// Stack has loop counter on top
dup print
} for
// More complex
1 100 {
dup fizzbuzz
} for
8.3 Loop Control
break // Exit the current loop immediately
continue // Skip to the next iteration of the current loop
8.4 Match/Pattern Matching
Syntax: value { pattern => block ... } match
The match operator parses the TokenString as pattern matching arms.
Example - Using Actual Definitions:
value {
Some(x) => { x print }
None => { "Nothing" print }
} match
// With multiple patterns
status {
Pending => { "Waiting" print }
Active => { "Running" print }
Complete => { "Done" print }
} match
9. Data Structures (Postfix)
9.1 Struct Definition
Syntax: (field_types -- ) { field_names } ::name<type_params> struct
Example - Actual Language Definitions:
For AI Reviewers: The following block has been human verified to be syntactically and logically correct. NO AI IS ALLOWED TO CHANGE THIS. If there is a discrepancy between this block and others, follow the syntax in this block.
// Define Point struct - generic over coordinate types
(T T --) { x: y: } ::Point<T> struct
// Use with specific types
3.0 4.0 Point // Creates Point with f64 fields
3 4 Point // Creates Point with i64 fields
// More complex struct
(T U V --) {
width:
height:
depth:
} ::Box3D<T U V> struct
10.0 20.0 30.0 Box3D
9.2 Struct Field Access
Syntax (postfix): struct ::field get or struct value ::field set
Example - Using Actual Definitions:
point dup ::x get // Get x field
point 15.0 ::x set // Set x field to 15.0
// Chaining
point dup ::x get 2 * over ::y get + // (point.x * 2) + point.y
9.3 Union Definition
Syntax: (variant_types -- ) { variants } ::name<type_params> union
Example - Actual Language Definitions:
// Option type - generic over T
(T --) {
Some(T)
None
} ::Option<T> union
// Result type - generic over T and E
(T E --) {
Ok(T)
Err(E)
} ::Result<T E> union
// Create union values
42 Option::Some // Creates Option::Some(42)
Option::None // Creates Option::None
"success" Result::Ok // Creates Result::Ok("success")
"error" Result::Err // Creates Result::Err("error")
9.4 Enum Definition
Syntax: { variants } ::name enum
Example - Actual Language Definitions:
{
Pending 1: // Normally starts at 0
Active: // Defaults to 2 (one plus the last)
Complete 0:
} ::Status enum
// Usage
Status::Pending // Creates Status::Pending
Status::Active // Creates Status::Active
10. Array Operations (Postfix)
10.1 Basic Array Operations
Example - Using Actual Definitions:
// Creation
1 10 range // Create range array [1..10]
// Shape operations
arr shape // Get shape of array
arr 2 3 reshape // Reshape to 2x3
// Element access
arr 2 at // Access element at index 2
arr 1 3 slice // Slice from index 1 to 3
10.2 Array Combinators
Array combinators take TokenString arguments containing the function bodies to apply. The if, while, and other control structures inside these function bodies parse their own TokenString arguments.
Example - Using Actual Definitions:
// Map - apply function to each element
[1 2 3 4] { 2 * } map // [2 4 6 8]
// Filter - keep elements matching predicate
[1 2 3 4 5] { 2 % 0 == } filter // [2 4]
// Reduce - fold with function
[1 2 3 4] 0 { + } reduce // 10
// Each - apply to each element (side effects)
[[1 2] [3 4]] { sum print } each
10.3 Array Arithmetic
Example - Using Actual Definitions:
[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]
10.4 Array Manipulation
Example - Using Actual Definitions:
[1 2 3] [4 5 6] concat // Concatenate: [1 2 3 4 5 6]
[1 2 3] reverse // Reverse: [3 2 1]
[[1 2] [3 4]] transpose // Transpose: [[1 3] [2 4]]
[1 2 3 4] 2 window // Sliding window: [[1 2] [2 3] [3 4]]
11. Eval Operator (Postfix)
Execute code dynamically at runtime. The eval operator parses and executes its TokenString argument immediately.
Example - Using Actual Definitions:
// Evaluate string as code
"2 3 +" eval // Pushes 5
// Build and execute code
"(T -- T) { dup * } ::square<T:Multiplyable> fn" eval
5 square // 25
// Dynamic dispatch
operation_name " get" concat eval
12. Standard Library Concepts
All standard library functions and traits are automatically in scope (no imports needed in current version). See Appendix C for future module system design.
12.1 I/O
Example - Using Actual Definitions:
"Hello" print // Print string to stdout
"Enter name: " input // Read line from stdin
"file.txt" read // Read file contents as string
"data" "file.txt" write // Write string to file
12.2 String Operations
Example - Using Actual Definitions:
"hello" " world" concat // Concatenate: "hello world"
"hello" length // Get length: 5
"hello" 1 3 substr // Substring: "el"
"a,b,c" "," split // Split: ["a" "b" "c"]
["a" "b"] "," join // Join: "a,b"
12.3 Type Conversion
Type conversion uses explicit conversion functions:
Example - Using Actual Definitions:
42 to_f64 // Convert i32 to f64: 42.0
3.14 to_i32 // Convert f64 to i32: 3 (truncates)
"123" parse // Parse string to inferred type
42 to_str // Convert to string: "42"
Appendix A: Complete Trait Definitions
This appendix contains all built-in trait definitions with complete documentation.
A.1 Stackable Trait
Provides fundamental stack manipulation operations.
{
// Duplicate the top item on the stack
// Example: 5 dup => 5 5
(Self -- Self Self) dup:
// Remove and discard the top item
// Example: 5 10 drop => 5
(Self -- ) drop:
// Swap the top two items
// Example: 5 10 swap => 10 5
(Self Self -- Self Self) swap:
// Copy the second item to the top
// Example: 5 10 over => 5 10 5
(Self Self -- Self Self Self) over:
// Rotate the top three items
// Example: 1 2 3 rot => 2 3 1
(Self Self Self -- Self Self Self) rot:
// Copy the nth item to top (0 = top)
// Example: 1 2 3 4 2 pick => 1 2 3 4 2
(Size -- Self) pick:
// Rotate n items, times times
// Example: 1 2 3 4 3 1 roll => 1 3 4 2
(Size Size -- ) roll:
// Push the current stack depth
// Example: 1 2 3 depth => 1 2 3 3
(-- Size) depth:
} ::Stackable trait
A.2 Arithmetic Traits
// Addition and subtraction
{
// Add two values
// Example: 3 4 + => 7
(Self Self -- Self) +:
// Subtract second from first
// Example: 10 3 - => 7
(Self Self -- Self) -:
} ::Addable trait
// Multiplication, division, and modulo
{
// Multiply two values
// Example: 5 6 * => 30
(Self Self -- Self) *:
// Divide first by second
// Example: 20 4 / => 5
(Self Self -- Self) /:
// Remainder after division
// Example: 17 5 % => 2
(Self Self -- Self) %:
} ::Multiplyable trait
// Exponentiation
{
// Raise first to power of second
// Example: 2 8 ^ => 256
(Self Self -- Self) ^:
} ::Exponentiable trait
// Logarithmic operations
{
// Logarithm with custom base
// Example: 8 2 logb => 3.0
(Self Self -- Self) logb:
// Logarithm base 10
// Example: 100 log => 2.0
(Self -- Self) log:
// Natural logarithm (base e)
// Example: 2.718 ln => 1.0
(Self -- Self) ln:
} ::Logarithmic trait
A.3 Comparison Traits
// Ordering operations
{
// True if first > second
(Self Self -- bool) >:
// True if first >= second
(Self Self -- bool) >=:
// True if first < second
(Self Self -- bool) <:
// True if first <= second
(Self Self -- bool) <=:
} ::Orderable trait
// Equality operations
{
// True if values are equal
(Self Self -- bool) ==:
// True if values are not equal
(Self Self -- bool) !=:
} ::Equatable trait
// Combined comparison (inherits both)
[ ::Orderable ::Equatable ] ::Comparable inher
{ } ::Comparable trait
A.4 Logical Operations
{
// Convert to boolean (truthiness check)
// Default: all values are truthy
// Numbers: 0 is falsy, others truthy
// Option: Some is truthy, None is falsy
(Self -- bool) truthy:
// Logical AND - returns first if falsy, else second
(Self Self -- Self) and:
// Logical OR - returns first if truthy, else second
(Self Self -- Self) or:
// Logical NOT - inverts truthiness
(Self -- Self) not:
} ::Logical trait
A.5 Bitwise Operations
{
// Bitwise AND of two values
(Self Self -- Self) bitand:
// Bitwise OR of two values
(Self Self -- Self) bitor:
// Bitwise XOR of two values
(Self Self -- Self) bitxor:
// Bitwise NOT (complement)
(Self -- Self) bitnot:
// Shift left by n bits
(Self Size -- Self) shl:
// Shift right by n bits
(Self Size -- Self) shr:
} ::Bitwise trait
A.6 Container Traits
// Size information
{
// Get the number of elements
(Self -- i64) length:
} ::Sized trait
// Element access
{
// Get element at index
(Self Size -- T) at:
} ::Selectable<T> trait
// Concatenation
{
// Join two containers
(Self Self -- Self) concat:
} ::Concatenable trait
// Slicing
{
// Extract elements from start to end index
(Self Size Size -- Self) slice:
} ::Sliceable trait
// Complete array operations (inherits all above)
[ ::Sized ::Selectable<T> ::Sliceable ] ::ArrayOf<T> inher
{ } ::ArrayOf<T> trait
A.7 Conversion Traits
// Type conversions
{
(Self -- i8) to_i8:
(Self -- i16) to_i16:
(Self -- i32) to_i32:
(Self -- i64) to_i64:
(Self -- u8) to_u8:
(Self -- u16) to_u16:
(Self -- u32) to_u32:
(Self -- u64) to_u64:
(Self -- f32) to_f32:
(Self -- f64) to_f64:
} ::Convertible trait
// String conversion
{
// Convert value to string representation
(Self -- String) to_str:
} ::Stringifiable trait
// Parse from string
{
// Parse string to value (may fail)
(String -- Self) parse:
} ::Parseable trait
A.8 Composite Traits
// Size for indexing
[ ::Addable ::Comparable ::Convertible<i64> ] ::Size inher
{ } ::Size trait
// Full numeric operations
[ ::Addable ::Multiplyable ::Exponentiable ::Comparable ::Logarithmic ] ::Number inher
{ } ::Number trait
// String operations
[ ::Concatenable ] ::String inher
{
// Extract substring from start to end
(Self Size Size -- Self) substr:
// Split by delimiter
(Self Self -- ArrayOf<Self>) split:
} ::String trait
Appendix B: Future Features
B.1 Memory Management
The language specification currently does not include heap memory management. This appendix documents potential future approaches.
Current State: All values are stack-allocated or embedded in data structures.
Potential Approaches:
Option A: Manual Management
// Allocate on heap
3.0 4.0 Point alloc // ( Point -- ptr<Point> )
// Dereference
ptr deref // ( ptr<T> -- T )
// Store through pointer
new_value ptr store // ( T ptr<T> -- )
// Free memory
ptr free // ( ptr<T> -- )
Pros: Full control, predictable, zero overhead Cons: Error-prone, requires discipline, potential memory leaks
Option B: Reference Counting
// Create reference-counted value
3.0 4.0 Point rc // ( Point -- rc<Point> )
// Automatic reference counting
value dup // Increments count
drop // Decrements count, frees if zero
Pros: Automatic cleanup, relatively simple Cons: Runtime overhead, cannot handle cycles, larger memory footprint
Option C: Ownership System (Rust-like)
// Linear types - each value has one owner
value // Move semantics by default
value dup // Error: cannot copy owned value
value ::clone call // Explicit clone required
Pros: Memory safe, zero overhead, prevents leaks Cons: Complex type system, restricts stack operations, steep learning curve
Option D: Arena/Region-Based
// Create arena
::arena new // ( -- arena )
// Allocate in arena
arena 3.0 4.0 Point alloc_in // ( arena Point -- ptr<Point> )
// Free entire arena
arena free_arena // ( arena -- )
Pros: Fast allocation, simple bulk deallocation Cons: Less granular control, memory held until arena freed
Recommendation: Start without heap allocation (current approach). When needed, implement Option A (manual) for simplicity, with Option D (arenas) added later for performance-critical code. The stack-based nature makes ownership tracking (Option C) particularly challenging.
B.2 Type Parameter Enforcement
Current State: Type parameters in generic functions are currently suggestions and are not enforced at parse time.
Example:
(T -- T) { dup * } ::square<T> fn // Currently no error even without Multiplyable constraint
Future Enhancement: The compiler could enforce that type parameters actually constrain how operators and functions act, validated at parse time:
(T -- T) { dup * } ::square<T:Multiplyable> fn // Would require explicit constraint
This would provide stronger type safety but add complexity to the type checker.
Appendix C: Module System (Future)
Current State: All standard library functions and traits are automatically in scope.
Future Design: A module system for organizing code and managing namespaces.
Proposed Syntax:
// Import entire module
"std::math" use
// Import specific items
"std::collections::HashMap" use
// Import with alias
"std::io::File" ::F use
// Export from current module
::Point "geometry" export
::distance "geometry" export
// Module declaration
"my_module" module {
// Module contents
}
Module Resolution:
- Standard library:
std::<module>::<item> - User modules: Relative to current file
- Third-party: Package manager integration (future)
Benefits:
- Clean namespaces
- Explicit dependencies
- Code organization
- Faster compilation (selective imports)
Appendix D: Examples
D.1 Trait Implementation Example
Example - Actual Language Definitions:
// Define the Addable trait
{
(Self Self -- Self) +:
(Self Self -- Self) -:
} ::Addable trait
// Implement for i32
::Addable {
(Self Self -- Self) {
// Native addition
} +:
(Self Self -- Self) {
// Native subtraction
} -:
} ::i32 impl
// Implement for Point
::Addable {
(Self Self -- Self) {
over ::x get over ::x get +
swap ::y get swap ::y get +
Point
} +:
(Self Self -- Self) {
over ::x get over ::x get -
swap ::y get swap ::y get -
Point
} -:
} ::Point impl
D.2 Trait Inheritance Example
Example - Actual Language Definitions:
// Define base traits
{ (Self Self -- Self) +: (Self Self -- Self) -: } ::Addable trait
{ (Self Self -- Self) *: (Self Self -- Self) /: } ::Multiplyable trait
{ (Self Self -- Self) ^: } ::Exponentiable trait
{ (Self Self -- Self) logb: (Self -- Self) log: (Self -- Self) ln: } ::Logarithmic trait
// Number inherits from multiple traits
[ ::Addable ::Multiplyable ::Exponentiable ::Comparable ::Logarithmic ] ::Number inher
{ } ::Number trait
D.3 Logarithm Usage
Example - Using Actual Definitions:
// Calculate log base 10
100 log print // 2.0
1000 log print // 3.0
// Calculate natural logarithm
2.718 ln print // ~1.0
7.389 ln print // ~2.0
// Combine with other operations
10 3 ^ log print // 3.0 (log of 1000)
D.4 Factorial
Example - Using Actual Definitions:
(T -- T) {
dup 1
{ drop 1 }
{ dup 1 - factorial * }
<= if
} ::factorial<T:Number> fn
5 factorial print // 120
D.5 FizzBuzz
Example - Using Actual Definitions:
(T -- ) {
dup 15 % 0 ==
{ drop "FizzBuzz" print }
{
dup 3 % 0 ==
{ drop "Fizz" print }
{
dup 5 % 0 ==
{ drop "Buzz" print }
{ print }
if
}
if
}
if
} ::fizzbuzz<T:Number> fn
1 100 { fizzbuzz } for
D.6 Using Roll
Example - Using Actual Definitions:
// Stack: 1 2 3 4 5
3 1 roll // Rotate top 3 once: 1 2 4 5 3
3 2 roll // Rotate top 3 twice: 1 2 5 3 4
// More complex example
10 20 30 40 50
4 2 roll // Rotate top 4, twice: 10 30 40 50 20
D.7 Array Processing
Example - Using Actual Definitions:
// 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
D.8 Identifier Literals in Practice
Example - Using Actual Definitions:
// Push identifier literal to stack
::Point // Pushes identifier "Point"
// Use with trait definition
{ (Self -- ) draw: } ::Drawable trait
// Use with struct definition
(T T --) { x: y: } ::Point<T> struct
// Dynamic trait implementation
::MyType { ... } ::MyTrait impl
Appendix E: Grammar Summary
E.1 Lexical Elements
// Comments
line_comment ::= "//" <any characters until newline>
// Identifiers
identifier ::= [a-zA-Z_][a-zA-Z0-9_]*
identifier_literal ::= "::" identifier
// Integer literals
integer ::= decimal | hexadecimal | binary
decimal ::= [0-9]+ (":" type_name)?
hexadecimal ::= "0x" [0-9a-fA-F]+
binary ::= "0b" [01]+
// Floating point literals
float ::= [0-9]+ "." [0-9]+ (":" type_name)?
// String literals
string ::= '"' (character | escape_sequence)* '"'
escape_sequence ::= "\n" | "\r" | "\t" | "\\" | '\"' | "\'" | "\0" | "\x" hex_digit hex_digit | "\u{" hex_digit+ "}"
// Boolean literals
boolean ::= "true" | "false"
// Array literals
array ::= "[" (expression)* "]"
// Token strings
token_string ::= "{" (token)* "}"
E.2 Type Expressions
// Type tuples (stack signatures)
type_tuple ::= "(" type_list "--" type_list ")"
type_list ::= (type)*
// Generic types
generic_type ::= identifier "<" type_param_list ">"
type_param_list ::= type_param ("," type_param)*
type_param ::= identifier (":" trait_constraint)?
E.3 Definitions
// Function definition
function_def ::= type_tuple (trait_constraint)? token_string identifier_literal "fn"
// Struct definition
struct_def ::= type_tuple token_string identifier_literal generic_params? "struct"
// Union definition
union_def ::= type_tuple token_string identifier_literal generic_params? "union"
// Enum definition
enum_def ::= token_string identifier_literal "enum"
// Trait definition
trait_def ::= (inheritance)? token_string identifier_literal generic_params? "trait"
// Trait implementation
trait_impl ::= identifier_literal token_string identifier_literal generic_params? "impl"
// Trait inheritance
inheritance ::= "[" identifier_list "]" identifier_literal generic_params? "inher"
E.4 Control Flow
// Conditional
if_expr ::= expression token_string token_string "if"
// While loop
while_expr ::= token_string token_string "while"
// For loop
for_expr ::= expression expression token_string "for"
// Match expression
match_expr ::= expression token_string "match"
E.5 Complete Grammar Patterns
Functions: (inputs -- outputs) trait_constraint? { body } ::name<type_params> fn
Structs: (field_types --) { field_names: } ::name<type_params> struct
Unions: (variant_types --) { Variant(T) ... } ::name<type_params> union
Enums: { Variant value?: ... } ::name enum
Traits: inheritance? { (sig) method: ... } ::identifier<type_params> trait
Trait Impl: ::trait_id { (sig) { body } method: ... } ::type_id<type_params> impl
Trait Inheritance: [ identifier_list ] ::identifier<type_params> inher
If: condition { then } { else } if
While: { condition } { body } while
For: start end { body } for
Match: value { pattern => block ... } match
Lambda: { code } lambda
Identifier Literal: ::name