This commit is contained in:
Kyler Olsen 2025-10-26 17:18:46 -06:00
parent 0bd7259fc3
commit 621ca16440
1 changed files with 94 additions and 103 deletions

View File

@ -1,6 +1,6 @@
# Stack Language Specification
**Version**: 0.6.2
**Version**: 0.7
**Status**: Draft Specification
**Changes**:
- 0.5 (AI)
@ -41,17 +41,25 @@
2. **Inheritance before trait** - Decision: Yes, inheritance declarations must come before trait definition
3. **`inher` operator** - Decision: No, merge inheritance into trait operator (removed `inher`)
4. **Separate `inher` vs `impl`** - Decision: Keep them separate (impl is for implementations only)
- 0.6.2 (Human) - In progress
- 0.6.2 (Human)
1. Created TODOs
2. Made various corrections (not everything was corrected)
3. Reviewed and corrected some code blocks
4. Made a few adjustments manually
5. Reversed removing `inher`
- 0.7 (AI)
1. **Operator definition** - Clarified that operators can be user/library defined via trait implementation
2. **Generic function syntax** - Fixed to use trait constraints in type tuple, not generic parameters
3. **Variable arguments with Iterable** - Changed array syntax to Iterable trait for variable args
4. **Example classifications** - Cleaned up "Actual Language Definitions" vs examples distinction
5. **Struct field access** - Clarified that get and set consume their arguments
6. **Section 6 rename** - Renamed "Operators (Postfix)" to "Built-in Operators"
7. **Module syntax** - Added `::` prefix for module imports
8. **Module alias options** - Added multiple alias syntax options
> **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.
> **TODO: (FOR HUMAN)** These specifications may need to be reorganized. ie. do we need both "Stack Manipulation Trait" in 4.1 and "5. Stack Operations", etc. Should some of these be in the appendix. What is the best structure for this document?
> **TODO:** Syntax like `(T -- T) { dup * } ::square<T:Multiplyable> fn` is not allowed, the correct syntax is `(Multiplyable -- Multiplyable) { dup * } ::square fn`.
> **TODO:** "Example - Actual Language Definitions" and variations of this are listed all over, but they are mostly not definitions of parts of the base language, just examples of language syntax. Other times they are definitions of parts of the base language used as examples and should just be examples. Basically this is improperly used and needs to be cleared out.
> **TODO: (FOR HUMAN)** These specifications may need to be reorganized. ie. do we need both "Stack Manipulation Trait" in 4.1 and "5. Stack Operations", etc. Should some of these be in the appendix. What is the best structure for this document?
---
@ -70,13 +78,14 @@ A statically-typed, stack-based language with pure postfix notation combining th
### Operators vs Functions
> **TODO:** Operators are not necessarily primitive operations, they can be human or library defined (still by implementing a trait).
**Operators** are primitive operations that implement trait methods. They:
- Must be backed by a trait
**Operators** are operations that implement trait methods. They can be:
- Built-in primitive operations provided by the language
- User-defined operations implementing custom trait methods
- Library-defined operations
- All operators must be backed by a trait
- Cannot share names with functions
- Are the fundamental building blocks of the language
- Examples: `+`, `-`, `dup`, `swap`, `if`, `while`
- Examples: `+`, `-`, `dup`, `swap`, `if`, `while` (built-in), custom operators via trait implementation
**Functions** are user-defined or library-defined procedures. They:
- Do not implement traits directly (though they may use operators that do)
@ -175,25 +184,24 @@ Type tuples represent stack effects and are used in function signatures to speci
(---) // No inputs, no outputs (side effects only)
```
**Variable Arguments**: For operations that need variable numbers of arguments, use array syntax:
> **TODO:** `(String [Stringifiable] --) printf:` should be `(String Iterable<Stringifiable> --) printf:`
**Variable Arguments**: For operations that need variable numbers of arguments, use the `Iterable` trait:
```
(-- Size) depth: // Zero arguments, returns stack depth
(String [Stringifiable] --) printf: // String plus array of printable values
([T] -- T) sum: // Array of values, returns sum
(-- Size) depth: // Zero arguments, returns stack depth
(String Iterable<Stringifiable> --) printf: // String plus iterable of printable values
(Iterable<T> -- T) sum: // Iterable of values, returns sum
```
This approach:
- Keeps the type system simple (no special variadic syntax)
- Makes it clear that arguments are grouped together
- Works naturally with the existing array literal syntax
- Works with arrays, ranges, and other iterable types
- Trait-based, consistent with language design
**Usage Example**:
**Usage Examples**:
```
"x=%d, y=%d, z=%d" [x y z] printf // Format string with array of values
[1 2 3 4 5] sum // Sum array of numbers
1 100 range sum // Sum range (also iterable)
depth print // No arguments needed
```
@ -318,7 +326,7 @@ When inheriting from a generic trait, you must either:
```
// Generic identity - works with any type (no operations performed)
(---) { } ::identity fn
(T -- T) { } ::identity fn
```
## 4. Trait System
@ -530,7 +538,7 @@ Traits for defining and working with traits themselves:
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**:
**Examples**:
```
// Trait with methods (no inheritance)
{
@ -577,9 +585,7 @@ Within the TokenString (the `{ }` block), identifiers like `Self`, `add:`, `draw
3. It is not required for all operators of a trait to be in the same implementation block - implementations can be split across multiple blocks
4. Later implementations can override earlier ones for the same type
> **TODO:** Yes the following is an example. No correction is needed.
**Example**:
**Examples**:
> **For AI Reviewers @ 0.5:** 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.
@ -605,10 +611,6 @@ Within the TokenString (the `{ }` block), identifiers like `Self`, `add:`, `draw
} ::Rectangle impl
```
> **TODO:** Yes the following are actual language definitions, but they are also list here as an example.
**Example - Actual Language Definitions (Human Verified)**:
> **For AI Reviewers @ 0.5:** 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.
```
@ -683,13 +685,9 @@ Within the TokenString (the `{ }` block), identifiers like `Self`, `add:`, `draw
**Syntax**: `[ identifier_list ] ::identifier<type_params>? inher { methods } ::identifier<type_params>? trait`
Trait inheritance is specified by providing an array of trait identifiers before the trait body in the trait definition. The trait body may be empty if the trait only serves to combine inherited traits.
Trait inheritance is specified by providing an array of trait identifiers, followed by the trait identifier and the `inher` operator, then the trait body and trait definition.
**Inheritance Declaration**: The array of inherited traits must appear directly before the trait body TokenString. No separate `inher` operator is needed.
> **TODO:** Are these actual language definitions just used as examples or actually specification definitions?
**Example - Actual Language Definitions**:
**Examples**:
```
// Combine multiple arithmetic traits
[ ::Addable ::Multiplyable ] ::BasicNumber inher
@ -740,9 +738,7 @@ Trait inheritance is specified by providing an array of trait identifiers before
### 4.5 Using Traits in Functions
> **TODO:** These are not actual language definitions, they are just examples.
**Example - Using Actual Definitions**:
**Examples**:
```
// Function requiring Drawable trait
(Drawable -- ) {
@ -766,7 +762,7 @@ 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
rot // ( a b c -- b c a) Rotate top three items
```
### 5.2 Stack Inspection
@ -786,9 +782,9 @@ roll // ( n times -- ) Rotate n items, times times
4 3 roll // Rotate top 4 items three times: a d e c b
```
## 6. Operators
## 6. Built-in Operators
> **TODO:** This should be renamed where it does not include all operators.
**Every operator is backed by a trait and must be implemented for types that use it.**
### 6.1 Arithmetic
@ -841,10 +837,10 @@ Functions are defined in postfix notation. The signature and body come before th
**Syntax**: `(inputs -- outputs) { body } ::name fn`
**Example - Using Actual Definitions**:
**Examples**:
```
// Define a square function (requires Multiplyable)
(T -- T) { dup * } ::square<T:Multiplyable> fn
// Define a square function (requires Multiplyable trait)
(Multiplyable -- Multiplyable) { dup * } ::square fn
// Use it
5 square // 25
@ -859,19 +855,19 @@ Functions are defined in postfix notation. The signature and body come before th
### 7.2 Generic Functions with Trait Constraints
**Syntax**: `(type_sig) { body } ::name<type_params> fn`
**Syntax**: `(type_sig) { body } ::name fn`
**Example - Using Actual Definitions**:
**Examples**:
```
// Generic identity - works with any type (no operations, no constraint needed)
(T -- T) { } ::identity<T> fn
(T -- T) { } ::identity fn
// Requires Addable
(T T -- T) {
// Requires Addable - use trait name in type tuple
(Addable Addable -- Addable) {
+
} ::add_values<T:Addable> fn
} ::add_values fn
// Requires Number, alternate syntax
// Requires Number
(Number -- Number) {
dup 0 > { } { 0 swap - } if
} ::abs fn
@ -885,7 +881,7 @@ Functions are defined in postfix notation. The signature and body come before th
The `if` operator parses both TokenStrings as code blocks (then/else branches).
**Example - Using Actual Definitions**:
**Examples**:
```
// if-then (else block is empty)
x 0 > { "positive" print } {} if
@ -922,7 +918,7 @@ if
The `while` operator parses both TokenStrings as code blocks (condition/body).
**Example - Using Actual Definitions**:
**Examples**:
```
// Sum 1 to 10
0 1 // sum counter
@ -947,7 +943,7 @@ drop // Drop counter, leave sum
The `for` operator parses the TokenString as a code block (loop body).
**Example - Using Actual Definitions**:
**Examples**:
```
// The loop variable is implicitly pushed to stack in each iteration
1 10 {
@ -973,7 +969,7 @@ continue // Skip to the next iteration of the current loop
The `match` operator parses the TokenString as pattern matching arms.
**Example - Using Actual Definitions**:
**Examples**:
```
value {
Some(x) => { x print }
@ -994,7 +990,7 @@ status {
**Syntax**: `(field_types -- ) { field_names } ::name<type_params> struct`
**Example - Actual Language Definitions**:
**Examples**:
> **For AI Reviewers @ 0.5:** 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.
@ -1018,16 +1014,16 @@ status {
### 9.2 Struct Field Access
> **TODO:** get consumes the identifier and struct, set consumes value and identifier.
**Syntax**:
- **get**: `struct ::field get` consumes struct and field identifier, returns field value
- **set**: `value ::field set` consumes value and field identifier, returns modified struct
**Syntax**: `struct ::field get` or `struct value ::field set`
**Example - Using Actual Definitions**:
**Examples**:
```
point dup ::x get // Get x field
point 15.0 ::x set // Set x field to 15.0
point ::x get // Get x field (consumes point and ::x)
15.0 ::x set // Set x field to 15.0 (consumes value and ::x)
// Chaining
// Chaining with duplication
point dup ::x get 2 * over ::y get + // (point.x * 2) + point.y
```
@ -1035,7 +1031,7 @@ point dup ::x get 2 * over ::y get + // (point.x * 2) + point.y
**Syntax**: `(variant_types -- ) { variants } ::name<type_params> union`
**Example - Actual Language Definitions**:
**Examples**:
```
// Option type - generic over T
(T --) {
@ -1060,7 +1056,7 @@ Option::None // Creates Option::None
**Syntax**: `{ variants } ::name enum`
**Example - Actual Language Definitions**:
**Examples**:
```
{
Pending 1: // Normally starts at 0
@ -1077,7 +1073,7 @@ Status::Active // Creates Status::Active
### 10.1 Basic Array Operations
**Example - Using Actual Definitions**:
**Examples**:
```
// Creation
1 10 range // Create range array [1..10]
@ -1095,7 +1091,7 @@ arr 1 3 slice // Slice from index 1 to 3
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**:
**Examples**:
```
// Map - apply function to each element
[1 2 3 4] { 2 * } map // [2 4 6 8]
@ -1112,7 +1108,7 @@ Array combinators take TokenString arguments containing the function bodies to a
### 10.3 Array Arithmetic
**Example - Using Actual Definitions**:
**Examples**:
```
[1 2 3] [4 5 6] +. // Element-wise add: [5 7 9]
[1 2 3] [4 5 6] *. // Element-wise multiply: [4 10 18]
@ -1121,7 +1117,7 @@ Array combinators take TokenString arguments containing the function bodies to a
### 10.4 Array Manipulation
**Example - Using Actual Definitions**:
**Examples**:
```
[1 2 3] [4 5 6] concat // Concatenate: [1 2 3 4 5 6]
[1 2 3] reverse // Reverse: [3 2 1]
@ -1133,13 +1129,13 @@ Array combinators take TokenString arguments containing the function bodies to a
Execute code dynamically at runtime. The `eval` operator parses and executes its TokenString argument immediately.
**Example - Using Actual Definitions**:
**Examples**:
```
// Evaluate string as code
"2 3 +" eval // Pushes 5
// Build and execute code
"(T -- T) { dup * } ::square<T:Multiplyable> fn" eval
"(Multiplyable -- Multiplyable) { dup * } ::square fn" eval
5 square // 25
// Dynamic dispatch
@ -1152,7 +1148,7 @@ All standard library functions and traits are automatically in scope (no imports
### 12.1 I/O
**Example - Using Actual Definitions**:
**Examples**:
```
"Hello" print // Print string to stdout
"Enter name: " input // Read line from stdin
@ -1162,7 +1158,7 @@ All standard library functions and traits are automatically in scope (no imports
### 12.2 String Operations
**Example - Using Actual Definitions**:
**Examples**:
```
"hello" " world" concat // Concatenate: "hello world"
"hello" length // Get length: 5
@ -1175,7 +1171,7 @@ All standard library functions and traits are automatically in scope (no imports
Type conversion uses explicit conversion functions:
**Example - Using Actual Definitions**:
**Examples**:
```
42 to_f64 // Convert i32 to f64: 42.0
3.14 to_i32 // Convert f64 to i32: 3 (truncates)
@ -1525,12 +1521,12 @@ Cons: Less granular control, memory held until arena freed
**Example**:
```
(T -- T) { dup * } ::square<T> fn // Currently no error even without Multiplyable constraint
(T -- T) { dup * } ::square 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
(Multiplyable -- Multiplyable) { dup * } ::square fn // Enforced constraint
```
This would provide stronger type safety but add complexity to the type checker.
@ -1543,32 +1539,35 @@ This would provide stronger type safety but add complexity to the type checker.
**Future Design**: A module system for organizing code and managing namespaces.
> **TODO:** I want the syntax to be `::std::math use`.
> **TODO:** What options for aliases are there in addition to `{ ::std::io::File ::F as } use` and `::std::io::File ::F use_as`?
**Proposed Syntax**:
```
// Import entire module
"std::math" use
// Import entire module (using :: prefix)
::std::math use
// Import specific items
"std::collections::HashMap" use
::std::collections::HashMap use
// Import with alias
"std::io::File" ::F use
// Import with alias - Option 1: Inline alias
::std::io::File ::F as use
// Import with alias - Option 2: Separate alias operator
::std::io::File ::F use_as
// Import with alias - Option 3: Block syntax
{ ::std::io::File ::F as } use
// Export from current module
::Point "geometry" export
::distance "geometry" export
::Point ::geometry export
::distance ::geometry export
// Module declaration
"my_module" module {
::my_module module {
// Module contents
}
```
**Module Resolution**:
- Standard library: `std::<module>::<item>`
- Standard library: `::std::<module>::<item>`
- User modules: Relative to current file
- Third-party: Package manager integration (future)
@ -1584,7 +1583,6 @@ This would provide stronger type safety but add complexity to the type checker.
### D.1 Trait Implementation Example
**Example - Actual Language Definitions**:
```
// Define the Addable trait
{
@ -1621,7 +1619,6 @@ This would provide stronger type safety but add complexity to the type checker.
### D.2 Trait Inheritance Example
**Example - Actual Language Definitions**:
```
// Define base traits
{ (Self Self -- Self) +: (Self Self -- Self) -: } ::Addable trait
@ -1636,7 +1633,6 @@ This would provide stronger type safety but add complexity to the type checker.
### D.3 Logarithm Usage
**Example - Using Actual Definitions**:
```
// Calculate log base 10
100 log print // 2.0
@ -1652,23 +1648,21 @@ This would provide stronger type safety but add complexity to the type checker.
### D.4 Factorial
**Example - Using Actual Definitions**:
```
(T -- T) {
(Number -- Number) {
dup 1
{ drop 1 }
{ dup 1 - factorial * }
<= if
} ::factorial<T:Number> fn
} ::factorial fn
5 factorial print // 120
```
### D.5 FizzBuzz
**Example - Using Actual Definitions**:
```
(T -- ) {
(Number -- ) {
dup 15 % 0 ==
{ drop "FizzBuzz" print }
{
@ -1683,14 +1677,13 @@ This would provide stronger type safety but add complexity to the type checker.
if
}
if
} ::fizzbuzz<T:Number> fn
} ::fizzbuzz 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
@ -1703,7 +1696,6 @@ This would provide stronger type safety but add complexity to the type checker.
### 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]
@ -1715,7 +1707,6 @@ print // 220
### D.8 Identifier Literals in Practice
**Example - Using Actual Definitions**:
```
// Push identifier literal to stack
::Point // Pushes identifier "Point"
@ -1784,7 +1775,7 @@ type_param ::= identifier (":" trait_constraint)?
```
// Function definition
function_def ::= type_tuple (trait_constraint)? token_string identifier_literal "fn"
function_def ::= type_tuple token_string identifier_literal "fn"
// Struct definition
struct_def ::= type_tuple token_string identifier_literal generic_params? "struct"
@ -1823,7 +1814,7 @@ match_expr ::= expression token_string "match"
### E.5 Complete Grammar Patterns
**Functions**: `(inputs -- outputs) trait_constraint? { body } ::name<type_params> fn`
**Functions**: `(inputs -- outputs) { body } ::name fn`
**Structs**: `(field_types --) { field_names: } ::name<type_params> struct`
@ -1831,11 +1822,11 @@ match_expr ::= expression token_string "match"
**Enums**: `{ Variant value?: ... } ::name enum`
**Traits**: `inheritance? { (sig) method: ... } ::identifier<type_params>? trait`
**Traits**: `{ (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`
**Trait Inheritance**: `[ identifier_list ] ::identifier<type_params> inher { } ::identifier<type_params> trait`
**If**: `condition { then } { else } if`