about summary refs log tree commit diff stats
path: root/js/scripting-lang/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'js/scripting-lang/README.md')
-rw-r--r--js/scripting-lang/README.md473
1 files changed, 343 insertions, 130 deletions
diff --git a/js/scripting-lang/README.md b/js/scripting-lang/README.md
index 5890a06..a194460 100644
--- a/js/scripting-lang/README.md
+++ b/js/scripting-lang/README.md
@@ -1,194 +1,407 @@
 # Baba Yaga
-## A Scripting Language
 
-Baba Yaga is a combinator-based scripting language that aims to be dangerously functional-brained, has minimal syntax, an intuitive approach to pattern matching, and hopefully enough of a standard library to be useful...but not too much of a standard library to be difficult to recall.
+> *A dangerously functional scripting language with minimal syntax and maximal expressiveness*
 
-This whole thing started as an aesthetic curiosity, and continued on from there. I wanted to be able to do pattern matching like this: 
+Baba Yaga is a combinator-based functional programming language designed for elegance, immutability, and expressive pattern matching. Born from an aesthetic curiosity about ML-style pattern matching, it has evolved into a complete functional programming environment with a focus on simplicity and power.
 
-```plaintext
-factorial : n -> 
-  when n is
-    0 then 1
-    _ then n * (factorial (n - 1));
-```
-
-I've implemented a whole bunch of [forths](https://git.sr.ht/~eli_oat/chupacabra), and a couple schemes, but never have I ever implemented something like a "regular" programming language. And, while, an [ML-flavored](https://en.wikipedia.org/wiki/Standard_ML) programming language isn't exactly regular, this has grown from an aesthetic curiosity to a full-blown aesthetic indulgence.
+## Language Philosophy
 
-Baba Yaga supports...
+- **Minimal Syntax**: Less code is better code. Every construct serves a clear purpose.
+- **Purely Functional**: Immutable data structures, function composition, and side-effect isolation.
+- **Pattern Matching First**: Conditional logic through expressive `when...is` expressions.
+- **Tables Only**: Single, flexible Lua-like data structure serving as arrays, objects, and more.
+- **Combinator-Heavy**: Rich standard library of functional combinators for data transformation.
 
-- **Function definitions** using arrow syntax with lexical scoping
-- **Pattern matching** with a single `when ... is ... then` expression that handles wildcards and arbitrarily nested features
-- **Tables** inspired by Lua's tables, with array-like and key-value entries, including boolean keys
-- **Function references** using an `@` operator for higher-order programming
-- **IO Operations** including input, output, and assertions, plus an `..emit` and `..listen` pattern for interfacing a functional core with the outside world. This contains side effects to a very limited surface area
-- **Standard Library** with a complete set of arithmetic, comparison, logical, and higher-order combinators...I think (let me know if I'm missing anything)
-- **APL-style operations** with element-wise and immutable table operations so that you can use broadcasting instead of looping
-- **Function composition** with `compose`, `pipe`, and `via` operators, supporting a bunch of different ways to chain functions together
-- **Currying by default** - all functions are automatically curried
-- **Combinator-based architecture** everything is "just" a function call or reference under the hood...because this supposedly made parsing easier...but I'm not yet totally sold on that reasoning
+## Quick Start
 
-## Example Script
-```plaintext
-/* Basic arithmetic */
-result : 5 + 3 * 2;
-..out result;
+### Hello World
+```baba-yaga
+/* Your first Baba Yaga program */
+..out "Hello, World!";
+```
 
-/* Function definition */
+### Factorial with Pattern Matching
+```baba-yaga
 factorial : n -> 
   when n is
     0 then 1
     _ then n * (factorial (n - 1));
 
-/* Function composition */
-double : x -> x * 2;
-increment : x -> x + 1;
-composed : compose @double @increment 5;
-..out composed;
-
-/* Pattern matching */
-classify : x y -> 
-  when x y is
-    0 0 then "both zero"
-    0 _ then "x is zero"
-    _ 0 then "y is zero"
-    _ _ then "neither zero";
-
-/* Tables */
-person : {name: "Baba Yaga", age: 99, active: true};
-..out person.name;
-..out person["age"];
+result : factorial 5;
+..out result; /* Outputs: 120 */
+```
 
+### Table Operations
+```baba-yaga
+/* Tables are the only data structure */
+person : {name: "Alice", age: 30, active: true};
 numbers : {1, 2, 3, 4, 5};
-doubled : map @double numbers;
-..out doubled[1]; 
 
-/* APL-style element-wise operations over tables */
-table1 : {a: 1, b: 2, c: 3};
-table2 : {a: 10, b: 20, c: 30};
-sum : each @add table1 table2;
-..out sum.a;
+/* Functional table transformations */
+doubled : t.map (x -> x * 2) numbers;
+adults : filter (p -> p.age >= 18) people_list;
+total : reduce (x y -> x + y) 0 numbers;
 ```
 
-Baba Yaga files should use either the `.txt` file extension, or the `.baba` extension.
+## Core Language Features
 
-## Key Features
+### 1. **Function Definitions**
+```baba-yaga
+/* Simple function */
+double : x -> x * 2;
+
+/* Multi-parameter function */
+add : x y -> x + y;
+
+/* Nested function with local scope */
+make_adder : n -> x -> x + n;
+add_five : make_adder 5;
+```
 
-### Function Application
+### 2. **Pattern Matching**
+```baba-yaga
+/* Basic pattern matching */
+classify : grade -> when grade is
+  90 then "A"
+  80 then "B" 
+  70 then "C"
+  _ then "F";
+
+/* Multi-parameter patterns */
+compare : x y -> when x y is
+  0 0 then "both zero"
+  _ 0 then "y is zero"
+  0 _ then "x is zero"
+  _ _ then "neither zero";
+
+/* Table pattern matching */
+process_user : user -> when user is
+  {status: "admin"} then "Admin access granted"
+  {status: "user", verified: true} then "User access granted"
+  _ then "Access denied";
+```
 
-Functions are applied using juxtaposition (space-separated), and you can use parentheses to help disambiguate precedence: 
-```plaintext
-f x          /* Apply function f to argument x */
-f x y        /* Apply f to x, then apply result to y */
-f (g x)      /* Apply g to x, then apply f to result */
+### 3. **Tables (Lua-like)**
+```baba-yaga
+/* Array-like tables */
+numbers : {1, 2, 3, 4, 5};
+first : numbers[1];  /* 1-indexed */
+
+/* Object-like tables */
+person : {name: "Bob", age: 25};
+name : person.name;
+
+/* Mixed tables */
+mixed : {1: "first", name: "Alice", 2: "second"};
+
+/* Nested tables */
+company : {
+  name: "TechCorp",
+  employees: {
+    {name: "Alice", role: "Engineer"},
+    {name: "Bob", role: "Designer"}
+  }
+};
 ```
 
-### Pattern Matching
+### 4. **Function References & Composition**
+```baba-yaga
+/* Function references with @ */
+double_ref : @double;
+result : double_ref 5; /* 10 */
 
-Use `when` expressions for pattern matching:
-```plaintext
-result : when value is
-  0 then "zero"
-  1 then "one"
-  _ then "other";
+/* Function composition */
+increment : x -> x + 1;
+composed : compose @double @increment 5; /* double(increment(5)) = 12 */
+piped : pipe @increment @double 5; /* increment(double(5)) = 11 */
+
+/* Partial application */
+add_ten : add 10;  /* Partially applied function */
+result : add_ten 5; /* 15 */
 ```
 
-### Tables
+### 5. **Immutable Table Operations**
+```baba-yaga
+/* t.* namespace for table operations */
+original : {name: "Alice", age: 30};
 
-Create and access data structures:
-```plaintext
-/* Array-like */
+/* All operations return new tables */
+updated : t.set original "age" 31;
+deleted : t.delete original "age";
+merged : t.merge original {city: "NYC"};
+
+/* Functional transformations */
 numbers : {1, 2, 3, 4, 5};
+doubled : t.map (x -> x * 2) numbers;
+evens : t.filter (x -> x % 2 = 0) numbers;
+sum : t.reduce (x y -> x + y) 0 numbers;
+
+/* Table metadata */
+shape : t.shape numbers; /* {size: 5, type: "array"} */
+has_name : t.has original "name"; /* true */
+length : t.length original; /* 2 */
+```
+
+### 6. **IO Operations**
+```baba-yaga
+/* Output */
+..out "Hello";
+..out 42;
+..out {name: "Alice"};
 
-/* Key-value pairs */
-person : {name: "Beatrice", age: 26};
+/* Input (context-dependent) */
+input_value : ..listen;
 
-/* Boolean keys */
-flags : {true: "enabled", false: "disabled"};
+/* Assertions for testing */
+..assert 2 + 2 = 4;
+..assert factorial 5 = 120;
+
+/* Event emission (for integration) */
+..emit "user_logged_in" {user_id: 123};
 ```
 
-### Function References
+## Style Guide & Best Practices
 
-Use the `@` to make reference to functions as arguments for other functions: 
-```plaintext
-numbers : {1, 2, 3, 4, 5};
-doubled : map @double numbers;
+### **Naming Conventions**
+```baba-yaga
+/* Variables: snake_case */
+user_count : 42;
+max_retries : 3;
+
+/* Functions: descriptive verbs */
+calculate_tax : amount -> amount * 0.08;
+validate_email : email -> /* validation logic */;
+
+/* Constants: ALL_CAPS (when obvious) */
+PI : 3.14159;
+MAX_CONNECTIONS : 100;
 ```
 
-## Combinators and Higher-Order Functions
+### **Function Design**
+```baba-yaga
+/* DO: Good: Pure, composable functions */
+add_tax : rate amount -> amount * (1 + rate);
+format_currency : amount -> "$" + amount;
 
-Baba Yaga tries to provide a comprehensive set of combinators for functional programming:
+/* DO: Good: Single responsibility */
+is_adult : person -> person.age >= 18;
+get_adult_names : people -> 
+  map (p -> p.name) (filter @is_adult people);
 
-### Core Combinators
+/* DON'T: Avoid: Complex nested logic */
+/* Use helper functions instead */
+```
 
-- `map f x` - Transform elements in collections
-- `filter p x` - Select elements based on predicates  
-- `reduce f init x` - Accumulate values into a single result
-- `each f x` - Multi-argument element-wise operations
+### **Pattern Matching Style**
+```baba-yaga
+/* DO: Good: Exhaustive patterns */
+handle_response : response -> when response is
+  {status: 200, data: data} then process_success data
+  {status: 404} then handle_not_found
+  {status: _} then handle_error response
+  _ then handle_unexpected response;
+
+/* DO: Good: Guard patterns for ranges */
+categorize_age : age -> when (age < 13) is
+  true then "child"
+  false then when (age < 20) is 
+    true then "teen"
+    false then when (age < 65) is
+      true then "adult"
+      false then "senior";
+```
 
-### Function Composition
+### **Table Operations**
+```baba-yaga
+/* DO: Good: Functional pipeline style */
+positive_numbers : filter (x -> x > 0) numbers;
+doubled_numbers : map (x -> x * 2) positive_numbers;
+result : reduce (x y -> x + y) 0 doubled_numbers;
 
-- `compose f g` - Right-to-left composition (mathematical style)
-- `pipe f g` - Left-to-right composition (pipeline style)
-- `via` - Kinda like `.` composition syntax: `f via g via h`
+/* DO: Good: Immutable updates */
+user_with_login : t.set user "last_login" "2023-12-01";
+updated_user : t.set user_with_login "login_count" (user.login_count + 1);
 
-### Table Operations
+/* DON'T: Avoid: Complex nested table access */
+/* Extract to helper functions */
+```
 
-All table operations are immutable so they return new tables. 
+### **Error Handling**
+```baba-yaga
+/* DO: Good: Use pattern matching for error cases */
+safe_divide : x y -> when y is
+  0 then {error: "Division by zero"}
+  _ then {result: x / y};
+
+/* DO: Good: Validate inputs early */
+process_user : user -> when user is
+  {name: name, age: age} then 
+    when (age >= 0) is
+      true then {status: "valid", user: user}
+      false then {error: "Invalid age"}
+  _ then {error: "Invalid user data"};
+```
 
-- `t.map`, `t.filter`, `t.set`, `t.delete`, `t.merge`, `t.get`, `t.has`, `t.length`
+## Language Limitations & Workarounds
+
+### **Parser Limitations**
+```baba-yaga
+/* DON'T: Nested lambda expressions not supported */
+/* y_comb : f -> (x -> f (x x)) (x -> f (x x)); */
+
+/* DO: Use helper functions instead */
+y_helper : f x -> f (x x);
+y_inner : f x -> y_helper f x;
+y_comb : f -> y_helper f @y_inner;
+
+/* DON'T: Complex when expressions in table literals */
+/* classifier : {
+     classify: x -> when x is
+       0 then "zero"
+       1 then "one"
+       _ then "other"
+   }; */
+
+/* DO: Define functions externally */
+classify_func : x -> when x is 0 then "zero" 1 then "one" _ then "other";
+classifier : {classify: classify_func};
+```
 
-### When to Use Which Combinator
+### **When Expression Syntax**
+```baba-yaga
+/* DON'T: Direct boolean conditions */
+/* abs : x -> when x < 0 then -x; */
 
-- Use `map` for general collections, `t.map` to emphasize table operations
-- Use `map` for single-table transformations, `each` for combining multiple collections.
+/* DO: Explicit boolean patterns */
+abs : x -> when (x < 0) is 
+  true then -x 
+  _ then x;
+```
 
+### **No Array Literals**
+```baba-yaga
+/* DON'T: Array syntax not supported */
+/* list : [1, 2, 3]; */
 
-### Standard Library
+/* DO: Use table syntax */
+list : {1, 2, 3};
 
-The language includes a comprehensive standard library:
+/* DON'T: Array concatenation */
+/* result : list concat [4, 5]; */
 
-**Arithmetic**: `add`, `subtract`, `multiply`, `divide`, `modulo`, `power`, `negate`  
-**Comparison**: `equals`, `notEquals`, `lessThan`, `greaterThan`, `lessEqual`, `greaterEqual`  
-**Logical**: `logicalAnd`, `logicalOr`, `logicalXor`, `logicalNot`  
-**Higher-Order**: `map`, `compose`, `pipe`, `apply`, `filter`, `reduce`, `fold`, `curry`, `each`  
-**Enhanced**: `identity`, `constant`, `flip`, `on`, `both`, `either`  
-**Table Operations**: `t.map`, `t.filter`, `t.set`, `t.delete`, `t.merge`, `t.get`, `t.has`, `t.length`
+/* DO: Use table operations */
+result : t.append (t.append list 4) 5;
+/* Or use a helper function for multiple appends */
+```
 
-## Architecture
+## Standard Library Highlights
 
-Baba Yaga uses a combinator-based architecture where all operations are translated to function calls:
+### **Combinators**
+```baba-yaga
+/* map, filter, reduce - work on tables */
+doubled : map (x -> x * 2) numbers;
+evens : filter (x -> x % 2 = 0) numbers;
+sum : reduce (x y -> x + y) 0 numbers;
 
-1. **Lexer**: Converts source code into tokens
-2. **Parser**: Translates tokens into AST, converting operators to combinator calls
-3. **Interpreter**: Executes combinator functions from the standard library
+/* Function composition */
+f_g : compose @f @g;
+g_f : pipe @g @f;
+applied : apply @f x;
 
-The idea behind this approach is that it should eliminate parsing ambiguity while preserving syntax and enabling functional programming patterns like currying and composition, but the implementation is likely a little bit janky.
+/* Currying and partial application */
+add_ten : add 10;
+multiply_by : flip @multiply;
+```
 
-## Testing
+### **Table Operations (t. namespace)**
+```baba-yaga
+/* Core operations */
+length : t.length table;
+has_key : t.has table "key";
+value : t.get table "key" "default";
+
+/* Transformations */
+mapped : t.map @function table;
+filtered : t.filter @predicate table;
+reduced : t.reduce @combiner initial table;
+
+/* Updates (immutable) */
+updated : t.set table "key" value;
+removed : t.delete table "key";
+combined : t.merge table1 table2;
+
+/* New operations */
+shape : t.shape table; /* {size: N, type: "array"|"object"} */
+extended : t.append table value;
+prefixed : t.prepend table value;
+```
 
-Run the complete test suite!
-```bash
-./run_tests.sh
+### **Utilities**
+```baba-yaga
+/* Arithmetic with type coercion */
+"Alice" + 10;     /* "Alice10" - string concatenation */
+true + 10;        /* 11 - boolean to number */
+30 + 12;          /* 42 - numeric addition */
+
+/* Logical operations with truthiness */
+result : 1 and 1;     /* true */
+result : 0 or "text"; /* "text" */
+result : not false;   /* true */
 ```
 
-This assumes you are using bun, but I've also tested extensively with both node and the browser, too. I haven't validated it, yet, but I think Baba Yaga should work with quickjs, too.
+## Integration Patterns
 
-### Debug Mode
+### **Side-Effect Isolation**
+```baba-yaga
+/* Pure functional core */
+process_data : data ->
+  calculate (transform (validate data));
 
-Enable debug output for development using the flag `DEBUG=1` or `DEBUG=2`:
-```bash
-DEBUG=1 node lang.js your-script.txt
+/* Side effects at boundaries */
+main : input_data ->
+  result : process_data input_data;
+  ..emit "data_processed" result;
 ```
 
-This'll output a lot of debug info, including the AST (as JSON). 
+### **Testing Pattern**
+```baba-yaga
+/* Test with assertions */
+test_factorial : ->
+  ..assert factorial 0 = 1
+  ..assert factorial 5 = 120
+  ..assert factorial 1 = 1;
+
+/* Property testing */
+test_reverse_property : list ->
+  ..assert (reverse (reverse list)) = list;
+```
+
+## Implementation Status
+
+- **JavaScript**: Reference implementation (100% complete)
+- **C**: Production implementation (97.1% test compatibility)
+- **Shared Test Suite**: 34/35 tests passing (97.1% success rate)
+
+## Further Reading
+
+- **Detailed Tutorials**: `js/tutorials/` - Comprehensive language guide
+- **API Reference**: `js/tutorials/11_Standard_Library.md` - Complete function reference  
+- **Advanced Patterns**: `js/tutorials/14_Advanced_Combinators.md` - Complex functional patterns
+- **Integration Guide**: `js/tutorials/15_Integration_Patterns.md` - Using Baba Yaga in larger systems
+
+## Philosophy & Design
+
+Baba Yaga emerged from a simple question: *What if pattern matching was the primary control flow mechanism?* 
+
+The language embraces:
+- **Functional purity** with controlled side effects
+- **Immutable data** with efficient operations  
+- **Combinator composition** over imperative loops
+- **Expression-based** rather than statement-based syntax
+- **Minimal but powerful** standard library
 
-### Adding Features
+The result is a language that encourages thinking in terms of data transformations and function composition, leading to more declarative and maintainable code.
 
-If you wanna add language features, the easiest way to do it is to see if you can implement them in Baba Yaga script, if you need to get into the guts of the thing, though, you wanna follow this pattern, 
+---
 
-1. Add tests in `tests/`
-2. Add tokens in `lexer.js`
-3. Add parsing logic in `parser.js`
-4. Add evaluation logic in `lang.js`
-5. Validate against the tests you added earlier
-6. Update documentation
\ No newline at end of file
+*"In the deep dark woods, where functions compose and data flows immutably, there lives Baba Yaga - a language both beautiful and dangerous, simple yet powerful."*
\ No newline at end of file