diff options
Diffstat (limited to 'js/scripting-lang/README.md')
-rw-r--r-- | js/scripting-lang/README.md | 860 |
1 files changed, 216 insertions, 644 deletions
diff --git a/js/scripting-lang/README.md b/js/scripting-lang/README.md index 5630e93..cc650de 100644 --- a/js/scripting-lang/README.md +++ b/js/scripting-lang/README.md @@ -1,722 +1,294 @@ -# Simple Scripting Language +# Scripting Language: A Combinator-Based Functional Language -A minimal, interpreted scripting language designed for learning language implementation concepts. This language demonstrates the core components needed for an interpreter: lexer, parser, and interpreter. +A functional programming language built on a **combinator foundation** that eliminates parsing ambiguity while preserving intuitive syntax. Every operation is a function call under the hood, creating a consistent and extensible language architecture. -## Features +## Why This Approach? -- **Arithmetic operations**: `+`, `-`, `*`, `/`, `%` (modulo), `^` (power) -- **Comparison operators**: `=`, `<`, `>`, `<=`, `>=`, `!=` -- **Logical operators**: `and`, `or`, `xor`, `not` -- **Variable assignment**: Immutable variables with `:` syntax -- **Function definitions**: Arrow function syntax with pattern matching -- **Pattern matching**: Case expressions with wildcard support -- **Function calls**: Direct function application -- **First-class functions**: Functions can be passed as arguments using `@` syntax -- **Function composition**: Higher-order functions for combining functions -- **Lexical scoping**: Functions create their own scope -- **Input/Output**: Built-in IO operations with `..in`, `..out`, and `..assert` -- **Standard Library**: Built-in functional programming utilities -- **Comments**: C-style block comments with `/* ... */` syntax -- **Tables**: Lua-style immutable tables with array and object capabilities +### The Problem We Solved +Traditional language parsers struggle with **operator precedence ambiguity**. Consider `f x + y` - should this be `(f x) + y` or `f (x + y)`? Most languages solve this with complex precedence tables, but we took a different approach. -## Syntax +### The Combinator Solution +We translate **every operation into a function call**: +- `x + y` becomes `add(x, y)` +- `x - y` becomes `subtract(x, y)` +- `f x` becomes `apply(f, x)` +- `true and false` becomes `logicalAnd(true, false)` -### Variables +This eliminates ambiguity entirely while keeping the syntax clean and intuitive. -Variables are immutable and assigned using the `:` operator: +### Benefits +- **Zero Ambiguity**: Every expression has exactly one interpretation +- **Functional Foundation**: Everything is a function, enabling powerful abstractions +- **Extensible**: Add new operations by simply adding combinator functions +- **Consistent**: All operations follow the same pattern +- **Preserves Syntax**: Existing code continues to work unchanged -``` -x : 5; -y : 10; -``` - -### Arithmetic Operations - -Arithmetic operations are supported with parentheses grouping: - -``` -sum : x + y; -diff : x - y; -product : x * y; -quotient : x / y; -modulo : 17 % 5; /* Returns 2 */ -power : 2 ^ 3; /* Returns 8 */ -grouped : (5 + 3) * 2; /* Returns 16 */ -nested : ((5 + 3) * 2) + 1; /* Returns 17 */ -``` - -### Function Definitions - -Functions are defined using arrow syntax (`->`): - -``` -add : x y -> x + y; -double : x -> x * 2; -``` - -### Function Calls - -Functions are called by providing arguments directly after the function name: +## How It Works +### Architecture Overview ``` -result : add 3 4; -doubled : double 5; +Source Code → Lexer → Parser → AST → Interpreter → Result + ↓ ↓ ↓ ↓ + Tokens → Combinator Translation → Function Calls ``` -#### Function Calls with Parentheses - -Function calls support parenthesized arguments for complex expressions: - -``` -/* Simple function call */ -result1 : add 3 4; - -/* Function call with parenthesized arithmetic */ -result2 : add (3 + 2) (4 + 1); - -/* Function call with function calls in parentheses */ -result3 : add (double 3) (square 2); - -/* Complex nested function calls with parentheses */ -result4 : add (add 1 2) (add 3 4); +### The Magic: Operator Translation +When you write `x + y * z`, the parser automatically translates it to: +```javascript +add(x, multiply(y, z)) ``` -**Note:** Parentheses provide explicit grouping and are the recommended way to handle complex nested function calls. - -### Tables - -The language supports Lua-style immutable tables that can serve as both arrays and objects: - -#### Table Creation - -Tables are created using curly braces `{}`: +This happens transparently - you write natural syntax, but get functional semantics. +### Function Application with Juxtaposition +Functions are applied by placing arguments next to them: +```javascript +f : x -> x * 2; +result : f 5; // apply(f, 5) → 10 ``` -/* Empty table */ -empty : {}; - -/* Array-like table (1-indexed) */ -numbers : {1, 2, 3, 4, 5}; - -/* Key-value table */ -person : {name: "Alice", age: 30, active: true}; -/* Mixed table (array-like and key-value) */ -mixed : {1, name: "Bob", 2, active: false}; +### Function Composition with `via` +Compose functions naturally: +```javascript +f : x -> x * 2; +g : x -> x + 1; +result : f via g 5; // compose(f, g)(5) → 12 ``` -#### Table Access +## Language Features -Tables support both bracket notation and dot notation for accessing values: +### Core Philosophy +- **Immutable by Default**: Variables cannot be reassigned +- **Functions First**: Everything is a function or function application +- **Pattern Matching**: Natural case expressions with wildcards +- **Lexical Scoping**: Functions create their own scope -``` -/* Array access with bracket notation */ -first : numbers[1]; /* Returns 1 */ -second : numbers[2]; /* Returns 2 */ - -/* Object access with dot notation */ -name : person.name; /* Returns "Alice" */ -age : person.age; /* Returns 30 */ - -/* Object access with bracket notation */ -name_bracket : person["name"]; /* Returns "Alice" */ -age_bracket : person["age"]; /* Returns 30 */ - -/* Mixed table access */ -first_mixed : mixed[1]; /* Returns 1 */ -name_mixed : mixed.name; /* Returns "Bob" */ -second_mixed : mixed[2]; /* Returns 2 */ -``` +### Key Features +- **Combinator Foundation**: All operations are function calls +- **Function Composition**: `via` operator for natural composition +- **Pattern Matching**: `when` expressions with wildcard support +- **Tables**: Lua-style tables with array and key-value support +- **Standard Library**: Higher-order functions (`map`, `compose`, `pipe`, etc.) +- **IO Operations**: Built-in input/output (`..in`, `..out`, `..assert`) -#### Table Features +## Development Workflow -- **Immutable**: Tables cannot be modified after creation -- **1-indexed arrays**: Array-like tables start indexing at 1 -- **Mixed types**: Tables can contain numbers, strings, booleans, and functions -- **Nested access**: Tables can contain other tables for complex data structures -- **Unified syntax**: Same syntax for arrays and objects +### Testing Strategy +We use a **progressive testing approach** to ensure quality: -#### Tables with Case Expressions +#### 1. Scratch Tests (`scratch_tests/`) +**Purpose**: Rapid prototyping and debugging +- **Location**: `scratch_tests/*.txt` +- **Use Case**: Isolating specific issues, testing new features +- **Naming**: `test_<feature>_<purpose>.txt` (e.g., `test_precedence_simple.txt`) +- **Lifecycle**: Temporary, can be deleted after issue resolution -Tables work well with case expressions for pattern matching: +#### 2. Unit Tests (`tests/`) +**Purpose**: Comprehensive feature coverage +- **Location**: `tests/*.txt` +- **Use Case**: Validating complete feature implementations +- **Naming**: `##_<feature_name>.txt` (e.g., `01_lexer_basic.txt`) +- **Lifecycle**: Permanent, part of regression testing -``` -/* Case expressions with table values */ -person : {name: "Alice", age: 30, active: true}; -result : case person.age of - 0 : 30 : "Person is 30" - 1 : _ : "Person is different age" -; - -/* Case expressions with boolean values */ -status : case person.active of - 0 : true : "Person is active" - 1 : false : "Person is inactive" -; - -/* Case expressions with array-like access */ -numbers : {1: 10, 2: 20, 3: 30}; -element : case numbers[2] of - 0 : 20 : "Second element is 20" - 1 : _ : "Unexpected second element" -; -``` +#### 3. Integration Tests (`tests/`) +**Purpose**: Testing feature combinations +- **Location**: `tests/integration_*.txt` +- **Use Case**: Ensuring features work together +- **Naming**: `integration_##_<description>.txt` -**Current Limitations:** -- Function calls from tables (e.g., `table.func args`) are not supported -- Function definitions inside table literals are not supported -- Tables can store function references, but they cannot be called directly +### Development Process -### First-Class Functions +#### When Adding New Features +1. **Create scratch test** to explore the feature +2. **Implement incrementally** with frequent testing +3. **Debug with `DEBUG=1`** for detailed output +4. **Promote to unit test** when feature is stable +5. **Add integration tests** for feature combinations + +#### When Fixing Bugs +1. **Create minimal scratch test** reproducing the issue +2. **Debug with `DEBUG=1`** to understand the problem +3. **Fix the issue** and verify with scratch test +4. **Update existing tests** if needed +5. **Clean up scratch tests** after resolution -Functions can be passed as arguments to other functions using the `@` prefix: - -``` -double : x -> x * 2; -square : x -> x * x; -compose : f g x -> f g x; - -composed : compose @double @square 3; /* double(square(3)) = 18 */ -``` - -**Function Reference Syntax:** -- `@functionName` - Creates a function reference (doesn't execute the function) -- `functionName args` - Calls the function with arguments - -### Pattern Matching - -The language supports pattern matching with case expressions in function bodies: - -``` -compare : x y -> - case x y of - 0 0 : "both zero" - 0 _ : "x is zero" - _ 0 : "y is zero" - _ _ : "neither zero"; -``` - -#### Pattern Matching Syntax - -- **Exact matches**: `0 0` matches when both values are 0 -- **Wildcards**: `_` matches any value -- **Mixed patterns**: `0 _` matches when first value is 0 and second can be anything - -### Comparison and Logical Operations - -The language supports comparison and logical operations: - -``` -/* Comparison operators */ -less : 3 < 5; /* true */ -greater : 10 > 5; /* true */ -equal : 5 = 5; /* true */ -not_equal : 3 != 5; /* true */ -less_equal : 5 <= 5; /* true */ -greater_equal : 5 >= 3; /* true */ - -/* Logical operators */ -and_result : 1 and 1; /* true */ -or_result : 0 or 1; /* true */ -xor_result : 1 xor 0; /* true */ -not_result : not 0; /* true */ -``` - -### Comments - -The language supports C-style block comments: - -``` -/* This is a single line comment */ - -/* This is a multi-line comment - that spans multiple lines */ - -x : 5; /* Comment on same line as code */ - -/* Nested comments are supported */ -/* Outer comment /* Inner comment */ More outer comment */ -``` - -**Comment Features:** -- Block comments start with `/*` and end with `*/` -- Comments can span multiple lines -- Comments can appear on the same line as code -- Nested comments are supported -- Comments are completely ignored by the lexer and parser - -### Input/Output Operations - -The language provides built-in IO operations for reading from stdin and writing to stdout: - -``` -name : ..in; /* Read input from stdin */ -..out name; /* Output to stdout */ -..out "Hello"; /* Output string literal */ -..out 42; /* Output number */ -..assert x = 5; /* Assert that x equals 5 */ -..assert y > 3; /* Assert that y is greater than 3 */ -..assert z != 0; /* Assert that z is not equal to 0 */ -``` - -**IO Functions:** -- `..in` - Reads a line from stdin, returns a number if possible, otherwise a string -- `..out` - Outputs a value to stdout and returns the value -- `..assert` - Asserts that a comparison is true, throws an error if it's false. Supports all comparison operators: `=`, `<`, `>`, `<=`, `>=`, `!=` - -**Note:** The `..` prefix indicates these are impure operations that have side effects. - -## Standard Library - -The language includes a built-in standard library with functional programming utilities: - -### Higher-Order Functions - -- **map**: Apply a function to a value (`map f x = f x`) -- **compose**: Compose two functions (`compose f g x = f(g(x))`) -- **curry**: Explicit currying (`curry f x y = f x y`) -- **apply**: Apply a function to an argument (`apply f x = f x`) -- **pipe**: Compose functions left-to-right (`pipe f g x = g(f(x))`) -- **filter**: Filter based on a predicate (`filter p x = p(x) ? x : 0`) -- **reduce**: Reduce to a single value (`reduce f init x = f(init, x)`) -- **fold**: Same as reduce (`fold f init x = f(init, x)`) - -### Usage Examples - -``` -double : x -> x * 2; -square : x -> x * x; - -/* Using map */ -result1 : map @double 5; /* Returns 10 */ -result2 : map @square 3; /* Returns 9 */ - -/* Using compose */ -composed : compose @double @square 3; /* double(square(3)) = 18 */ +#### When Promoting Scratch Tests +```bash +# Test the scratch test +bun run lang.js scratch_tests/test_new_feature.txt -/* Using pipe */ -piped : pipe @double @square 2; /* square(double(2)) = 16 */ +# If it passes, promote to unit test +cp scratch_tests/test_new_feature.txt tests/16_new_feature.txt -/* Using filter */ -isPositive : x -> x > 0; -filtered : filter @isPositive 5; /* Returns 5 (since 5 > 0) */ +# Update test numbering if needed +# Clean up scratch test +rm scratch_tests/test_new_feature.txt ``` +### Debugging Tools -## Language Components - -### Lexer - -The lexer tokenizes input into meaningful units: -- Numbers: `123` -- Identifiers: `variable_name` -- Operators: `+`, `-`, `*`, `/` -- Keywords: `case`, `of`, `function` -- Symbols: `:`, `->`, `_` - -### Parser - -The parser builds an Abstract Syntax Tree (AST) from tokens, supporting: -- Number literals -- Arithmetic expressions -- Variable assignments -- Function declarations -- Function calls -- Case expressions -- Pattern matching - -### Interpreter - -The interpreter executes the AST with: -- Global scope management -- Function evaluation -- Pattern matching execution -- Arithmetic computation -- Immutable variable semantics - -## Example Programs - -### Basic Arithmetic and Variables - -``` -/* Simple arithmetic with variables */ -x : 5; -y : 10; -sum : x + y; -diff : x - y; -product : x * y; -quotient : y / x; -modulo : 17 % 5; /* Returns 2 */ -power : 2 ^ 3; /* Returns 8 */ - -..out sum; /* 15 */ -..out diff; /* -5 */ -..out product; /* 50 */ -..out quotient; /* 2 */ -..out modulo; /* 2 */ -..out power; /* 8 */ - -/* Grouped expressions with parentheses */ -grouped : (5 + 3) * 2; /* 16 */ -nested : ((5 + 3) * 2) + 1; /* 17 */ -complex : (2 ^ 3) % 3 and 5 > 3; /* true */ +#### Enable Debug Mode +```bash +DEBUG=1 bun run lang.js script.txt ``` -### Function Definitions and Calls +This shows: +- Token stream from lexer +- AST structure from parser +- Function call traces +- Scope information +#### Call Stack Tracking +The interpreter tracks function calls to detect infinite recursion: +```bash +# Shows call statistics after execution +bun run lang.js script.txt ``` -/* Basic function definition */ -add : x y -> x + y; -multiply : x y -> x * y; -double : x -> x * 2; -square : x -> x * x; - -/* Function calls */ -result1 : add 3 4; /* 7 */ -result2 : multiply 5 6; /* 30 */ -result3 : double 8; /* 16 */ -result4 : square 4; /* 16 */ - -/* Function calls with parenthesized arguments */ -result5 : add (3 + 2) (4 + 1); /* 15 */ -result6 : add (double 3) (square 2); /* 10 */ -result7 : add (add 1 2) (add 3 4); /* 10 */ -``` - -### Tables and Data Structures -``` -/* Create various table types */ -empty : {}; -numbers : {1, 2, 3, 4, 5}; -person : {name: "Alice", age: 30, active: true}; -mixed : {1, name: "Bob", 2, active: false}; - -/* Access array elements */ -first : numbers[1]; -second : numbers[2]; -last : numbers[5]; - -/* Access object properties */ -name : person.name; -age : person.age; -active : person.active; - -/* Access mixed table */ -first_mixed : mixed[1]; -name_mixed : mixed.name; -second_mixed : mixed[2]; - -/* Output results */ -..out "First number: "; -..out first; -..out "Person name: "; -..out name; -..out "Mixed first: "; -..out first_mixed; -..out "Mixed name: "; -..out name_mixed; -``` +### Running Tests +```bash +# Run all tests +./run_tests.sh -### Pattern Matching with Case Expressions +# Run individual test +bun run lang.js tests/01_lexer_basic.txt +# Run scratch test +bun run lang.js scratch_tests/test_debug_issue.txt ``` -/* Pattern matching in function bodies */ -compare : x y -> - case x y of - 0 0 : "both zero" - 0 _ : "x is zero" - _ 0 : "y is zero" - _ _ : "neither zero"; - -/* Testing pattern matching */ -test1 : compare 0 0; /* "both zero" */ -test2 : compare 0 5; /* "x is zero" */ -test3 : compare 5 0; /* "y is zero" */ -test4 : compare 5 5; /* "neither zero" */ - -/* Single-parameter case expressions */ -factorial : n -> - case n of - 0 : 1 - _ : n * (factorial (n - 1)); - -/* Single-parameter grade function */ -grade : score -> - case score of - 90 : "A" - 80 : "B" - 70 : "C" - _ : "F"; - -fact5 : factorial 5; /* 120 */ -grade1 : grade 95; /* "A" */ -grade2 : grade 85; /* "B" */ -grade3 : grade 65; /* "F" */ -``` - -### First-Class Functions and Composition -``` -/* Function references and composition */ -double : x -> x * 2; -square : x -> x * x; -add1 : x -> x + 1; +## Current Status -/* Using standard library functions */ -composed : compose @double @square 3; /* double(square(3)) = 18 */ -piped : pipe @double @square 2; /* square(double(2)) = 16 */ -applied : apply @double 5; /* double(5) = 10 */ +### ✅ Recently Completed +- **Function Composition**: `via` operator and `@` function references +- **Enhanced Standard Library**: `compose` and `pipe` with partial application +- **Combinator Foundation**: All operators translate to function calls -/* Higher-order functions */ -mapped1 : map @double 5; /* 10 */ -mapped2 : map @square 3; /* 9 */ +### 🔧 Active Issues +- **Priority 1**: Precedence issues (binary minus operator) +- **Priority 2**: Test suite failures (blocked by precedence fix) -/* Function references in case expressions */ -getFunction : type -> - case type of - "double" : @double - "square" : @square - _ : @add1; +### 📋 Implementation Plans +See `design/implementation/` for detailed plans: +- `PRECEDENCE_RESOLUTION_PLAN.md` - Active precedence fix +- `FUNCTION_COMPOSITION_PLAN.md` - Completed composition features -func1 : getFunction "double"; /* Function reference */ -func2 : getFunction "square"; /* Function reference */ -``` +## Quick Start -### Recursion and Complex Functions +### Installation +```bash +# Clone the repository +git clone <repository-url> +cd scripting-lang -``` -/* Recursive factorial function (using single-parameter case) */ -factorial : n -> - case n of - 0 : 1 - _ : n * (factorial (n - 1)); - -/* Recursive countdown function */ -countdown : n -> - case n of - 0 : "done" - _ : countdown (n - 1); - -/* Testing recursive functions */ -fact5 : factorial 5; /* 120 */ -count : countdown 3; /* "done" */ +# Install dependencies (if any) +npm install +# or +bun install ``` -### Comparison and Logical Operators +### Running Scripts +```bash +# Basic script execution +bun run lang.js script.txt -``` -/* Comparison operators */ -a : 5; -b : 10; - -less : a < b; /* true */ -greater : b > a; /* true */ -equal : a = a; /* true */ -notEqual : a != b; /* true */ -lessEqual : a <= 5; /* true */ -greaterEqual : b >= 10; /* true */ - -/* Logical operators */ -logicalAnd : 1 and 1; /* true */ -logicalOr : 0 or 1; /* true */ -logicalXor : 1 xor 0; /* true */ -logicalNot : not 0; /* true */ - -/* Complex logical expressions */ -complex1 : a < b and b > 5; /* true */ -complex2 : a = 5 or b = 15; /* true */ -complex3 : not (a = b); /* true */ +# With debug output +DEBUG=1 bun run lang.js script.txt ``` -### Input/Output and Assertions - -``` -/* Interactive input/output */ -..out "Enter your name: "; -name : ..in; -..out "Hello, "; -..out name; -..out "!"; - -/* Assertions for testing */ +### Example Script +```javascript +/* Basic arithmetic with combinator translation */ x : 5; y : 3; -sum : x + y; - -..assert x = 5; /* Passes */ -..assert y = 3; /* Passes */ -..assert sum = 8; /* Passes */ -..assert x > 3; /* Passes */ -..assert y < 10; /* Passes */ -..assert sum != 0; /* Passes */ -..assert (add 3 4) = 7; /* Passes (with parentheses) */ - -/* String comparisons */ -..assert "hello" = "hello"; /* Passes */ -..assert "world" != "hello"; /* Passes */ -``` - -### Standard Library Functions +result : x + y; // becomes add(x, y) internally -``` -/* Using all standard library functions */ +/* Function definition and application */ double : x -> x * 2; -square : x -> x * x; -add : x y -> x + y; -isPositive : x -> x > 0; - -/* Map function */ -mapped1 : map @double 5; /* 10 */ -mapped2 : map @square 3; /* 9 */ - -/* Compose function */ -composed : compose @double @square 3; /* 18 */ - -/* Pipe function */ -piped : pipe @double @square 2; /* 16 */ +result : double 5; // becomes apply(double, 5) internally -/* Apply function */ -applied : apply @double 7; /* 14 */ - -/* Filter function */ -filtered : filter @isPositive 5; /* 5 (since 5 > 0) */ -filtered2 : filter @isPositive -3; /* 0 (since -3 <= 0) */ - -/* Reduce and Fold functions */ -reduced : reduce @add 0 5; /* 5 */ -folded : fold @add 0 5; /* 5 */ - -/* Curry function (explicit currying) */ -curried : curry @add 3 4; /* 7 */ -``` +/* Function composition */ +add1 : x -> x + 1; +result : double via add1 5; // becomes compose(double, add1)(5) internally -### Complete Program Example +/* Pattern matching */ +message : when result is + 10 then "ten" + 12 then "twelve" + _ then "other"; +/* Output */ +..out message; ``` -/* A complete program demonstrating multiple features */ -..out "Welcome to the Calculator!"; -/* Define arithmetic functions */ -add : x y -> x + y; -subtract : x y -> x - y; -multiply : x y -> x * y; -divide : x y -> x / y; +## Architecture Deep Dive -/* Define utility functions */ -double : x -> x * 2; -square : x -> x * x; -isEven : x -> x % 2 = 0; - -/* Get user input */ -..out "Enter first number: "; -num1 : ..in; -..out "Enter second number: "; -num2 : ..in; - -/* Perform calculations */ -sum : add num1 num2; -diff : subtract num1 num2; -prod : multiply num1 num2; -quot : divide num1 num2; - -/* Display results */ -..out "Sum: "; -..out sum; -..out "Difference: "; -..out diff; -..out "Product: "; -..out prod; -..out "Quotient: "; -..out quot; - -/* Use higher-order functions */ -doubledSum : double sum; -squaredDiff : square diff; - -..out "Doubled sum: "; -..out doubledSum; -..out "Squared difference: "; -..out squaredDiff; - -/* Pattern matching for number classification */ -classify : num -> - case num of - 0 : "zero" - _ : case isEven num of - true : "even" - _ : "odd"; - -classification : classify num1; -..out "First number is: "; -..out classification; - -/* Assertions to verify calculations */ -..assert sum = add num1 num2; -..assert diff = subtract num1 num2; -..assert prod = multiply num1 num2; - -..out "All calculations verified!"; -``` +### Combinator Foundation +Every operation is implemented as a function call to standard library combinators: -## Running Programs +```javascript +// Arithmetic +x + y → add(x, y) +x - y → subtract(x, y) +x * y → multiply(x, y) -The language supports file execution mode only: +// Comparison +x = y → equals(x, y) +x > y → greaterThan(x, y) -### File Execution Mode -Run a script file by providing the file path as an argument: +// Logical +x and y → logicalAnd(x, y) +not x → logicalNot(x) -```bash -node lang.js script.txt +// Function application +f x → apply(f, x) ``` -**Note:** REPL mode has been removed in the simplified version. The language now only supports file execution. - -## Language Design Principles - -- **Simplicity**: Minimal syntax for maximum clarity -- **Immutability**: Variables cannot be reassigned -- **Functional**: Functions are first-class values with composition support -- **Pattern-oriented**: Pattern matching as a core feature -- **Recursive**: Support for recursive function calls in function bodies -- **Grouped**: Parentheses support for complex arithmetic expressions -- **Expressive**: Rich set of arithmetic, comparison, and logical operators -- **IO-aware**: Built-in input/output operations with clear impurity markers -- **Educational**: Designed to teach language implementation concepts - -## Limitations +### Standard Library Combinators +The language includes a comprehensive set of combinators: +- **Arithmetic**: `add`, `subtract`, `multiply`, `divide`, `negate` +- **Comparison**: `equals`, `greaterThan`, `lessThan`, etc. +- **Logical**: `logicalAnd`, `logicalOr`, `logicalNot` +- **Higher-Order**: `map`, `compose`, `pipe`, `apply`, `filter` -This is a learning language with intentional limitations: -- Complex nested function calls (e.g., `add double 3 square 2`) are ambiguous without explicit grouping -- There's one known issue with function calls inside assertions (e.g., ..assert add 3 4 = 7), which is a parsing edge case. Workaround: use parentheses around function calls in assertions (e.g., ..assert (add 3 4) = 7) -- Limited to immutable data structures (no mutation operations) -- No error handling beyond basic validation -- No modules or imports -- IO operations are synchronous and block execution +### Parser Architecture +The parser uses a **precedence climbing** approach with combinator translation: +1. **Lexer**: Converts source to tokens +2. **Parser**: Builds AST with operator-to-function translation +3. **Interpreter**: Evaluates AST using combinator functions -## Future Enhancements +## Contributing -Planned features for future versions: -- Ambiguous function call detection and error reporting -- Lists and data structures -- Error handling -- Modules and imports -- Performance optimizations +### Development Guidelines +1. **Follow the combinator approach** for new operations +2. **Use scratch tests** for rapid prototyping +3. **Promote to unit tests** when features are stable +4. **Maintain backward compatibility** - existing code must work +5. **Document changes** in design documents -## Implementation Details +### Code Style +- **Functional approach**: Prefer pure functions +- **Combinator translation**: All operations become function calls +- **Clear naming**: Descriptive function and variable names +- **Comprehensive testing**: Test edge cases and combinations -The language is implemented in JavaScript with three main components: +### Testing Requirements +- **Unit tests** for all new features +- **Integration tests** for feature combinations +- **Backward compatibility** tests for existing code +- **Edge case coverage** for robust implementation -1. **Lexer** (`lexer()`): Converts source code to tokens -2. **Parser** (`parser()`): Builds AST from tokens -3. **Interpreter** (`interpreter()`): Executes AST +## Documentation -Each component is designed to be modular and extensible for adding new language features. +### Design Documents +- `design/PROJECT_ROADMAP.md` - Current status and next steps +- `design/COMBINATORS.md` - Combinator foundation explanation +- `design/implementation/` - Detailed implementation plans -## Files +### Architecture +- **Combinator Foundation**: Eliminates parsing ambiguity +- **Functional Semantics**: Everything is a function +- **Extensible Design**: Easy to add new operations +- **Consistent Patterns**: All operations follow the same structure -- `lang.js` - Main language implementation -- `table_basic_test.txt` - Basic table functionality tests -- `table_edge_cases_test.txt` - Advanced table edge cases (some features may not work) -- `README.md` - This documentation -- `NEXT-STEPS.md` - Development roadmap and notes \ No newline at end of file +This language demonstrates how **functional programming principles** can solve real parsing problems while maintaining intuitive syntax. The combinator foundation provides a solid base for building powerful abstractions. \ No newline at end of file |