about summary refs log tree commit diff stats
path: root/js/baba-yaga/docs/07_gotchyas.md
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/docs/07_gotchyas.md')
-rw-r--r--js/baba-yaga/docs/07_gotchyas.md642
1 files changed, 642 insertions, 0 deletions
diff --git a/js/baba-yaga/docs/07_gotchyas.md b/js/baba-yaga/docs/07_gotchyas.md
new file mode 100644
index 0000000..dc71b38
--- /dev/null
+++ b/js/baba-yaga/docs/07_gotchyas.md
@@ -0,0 +1,642 @@
+# Baba Yaga Syntax Gotchas
+
+This document catalogs the strict syntax requirements and common pitfalls discovered during development and testing of the `with` and `with rec` functionality.
+
+## Table of Contents
+
+1. [When Expression Syntax](#when-expression-syntax)
+2. [With Block Syntax](#with-block-syntax)
+3. [Operator Precedence and Parenthesization Rules](#operator-precedence-and-parenthesization-rules)
+4. [Type System Requirements](#type-system-requirements)
+5. [Function Definitions](#function-definitions)
+6. [Data Structure Syntax](#data-structure-syntax)
+7. [Common Error Patterns](#common-error-patterns)
+8. [JavaScript Interop Gotchas](#javascript-interop-gotchas)
+
+## When Expression Syntax
+
+### **Incorrect: Using `else` keyword**
+```baba
+// WRONG - Baba Yaga doesn't use 'else'
+status : when x is
+  0 then "zero"
+  _ else "other";
+```
+
+### **Correct: Using `_ then` pattern**
+```baba
+// CORRECT - Use '_ then' for fallback
+status : when x is
+  0 then "zero"
+  _ then "other";
+```
+
+### **Incorrect: Nested when without proper structure**
+```baba
+// WRONG - Missing 'then when' introduction
+status : when x is
+  0 then "zero"
+  _ when x < 10 then "small"  // Missing 'then when'
+  _ then "large";
+```
+
+### **Correct: Proper nested when structure**
+```baba
+// CORRECT - Use 'then when' for nested conditions
+status : when x is
+  0 then "zero"
+  _ then when (x < 10) is
+    true then "small"
+    _ then "large";
+```
+
+### **Incorrect: Complex when without parentheses**
+```baba
+// WRONG - Missing parentheses around complex conditions
+status : when x > 0 and x < 10 is
+  true then "small"
+  _ then "large";
+```
+
+### **Correct: Parentheses around complex conditions**
+```baba
+// CORRECT - Wrap complex conditions in parentheses
+status : when (x > 0 and x < 10) is
+  true then "small"
+  _ then "large";
+```
+
+## With Block Syntax
+
+### **Incorrect: Missing semicolons**
+```baba
+// WRONG - Missing semicolon after when expression
+with (
+  status : when x > 0 is true then "positive" _ then "negative"  // Missing ;
+) -> status;
+```
+
+### **Correct: Proper semicolon usage**
+```baba
+// CORRECT - Semicolon after each entry
+with (
+  status : when x > 0 is true then "positive" _ then "negative";
+) -> status;
+```
+
+### **Incorrect: with rec with non-function bindings**
+```baba
+// WRONG - with rec only allows function bindings
+with rec (
+  x : 5;  // Not a function!
+  f : y -> y + 1;
+) -> f x;
+```
+
+### **Correct: with rec with function bindings only**
+```baba
+// CORRECT - All bindings must be functions
+with rec (
+  f : x -> x + 1;
+  g : y -> y * 2;
+) -> f (g 5);
+```
+
+**Important**: `with rec` is **strictly function-only**. It does not allow any non-function bindings, even when functions are also present. This is by design to ensure mutual recursion works correctly. For non-function bindings, use regular `with` blocks instead.
+
+### **Incorrect: Complex list literals with when expressions**
+```baba
+// WRONG - Complex when expressions in list literals
+tags : [name, when age >= 18 is true then "adult" _ then "minor"];
+```
+
+### **Correct: Pre-compute values before list creation**
+```baba
+// CORRECT - Compute values first, then create list
+with (
+  ageGroup : when age >= 18 is true then "adult" _ then "minor";
+  tags : [name, ageGroup];
+) -> tags;
+```
+
+## Type System Requirements
+
+### **Incorrect: Function type annotations**
+```baba
+// WRONG - Function type annotations not supported
+factorial : (x: Int) -> Int -> x + 1;
+```
+
+### **Correct: Simple type declarations**
+```baba
+// CORRECT - Use simple type declarations
+factorial : x -> x + 1;
+```
+
+**Note**: While Baba Yaga supports function type annotations in function signatures (e.g., `add : (x: Int, y: Int) -> Int -> x + y;`), it does NOT support function type annotations in `with` blocks. See [Types Documentation](./04_types.md) for details on supported type annotations.
+
+### **Incorrect: Non-existent functions**
+```baba
+// WRONG - These functions don't exist in Baba Yaga
+str.toString x;     // No str.toString function
+math.floor x;       // No math.floor function
+type x;             // No type function
+null;               // No null value
+```
+
+### **Correct: Use existing functions**
+```baba
+// CORRECT - Use documented functions
+str.upper x;        // str.upper exists
+math.sqrt x;        // math.sqrt exists
+math.abs x;         // math.abs exists
+```
+
+**Note**: For a complete list of available functions, see the [Types Documentation](./04_types.md) and [Crash Course](./00_crash-course.md). Baba Yaga has a focused set of built-in functions rather than trying to replicate all JavaScript functionality.
+
+## Function Definitions
+
+### **Incorrect: Missing arrow syntax**
+```baba
+// WRONG - Missing -> arrow
+f x { x + 1 }
+```
+
+### **Correct: Proper arrow syntax**
+```baba
+// CORRECT - Use -> arrow
+f : x -> x + 1;
+```
+
+### **Incorrect: Missing semicolon after function body**
+```baba
+// WRONG - Missing semicolon
+f : x -> x + 1  // Missing ;
+```
+
+### **Correct: Proper semicolon usage**
+```baba
+// CORRECT - Semicolon after function definition
+f : x -> x + 1;
+```
+
+## Operator Precedence and Parenthesization Rules
+
+Baba Yaga has strict requirements for operator precedence that differ from many other languages. Understanding these rules is crucial for writing correct code.
+
+### **Operator Precedence Hierarchy (Highest to Lowest)**
+
+1. **Function Calls and Member Access** - `f x`, `obj.property`
+2. **Unary Operators** - `-x`, `!x`
+3. **Arithmetic** - `*`, `/`, `%` (left-associative)
+4. **Arithmetic** - `+`, `-` (left-associative)
+5. **Comparison** - `=`, `!=`, `<`, `<=`, `>`, `>=` (non-associative)
+6. **Logical** - `and`, `or` (left-associative)
+
+### **Critical Rule: Function Calls in Comparisons**
+
+**Incorrect: Function calls without parentheses in comparisons**
+```baba
+// WRONG - Function calls need parentheses in comparisons
+length list > 5;           // Error: Unexpected token: OPERATOR (>)
+math.abs x < 0.001;        // Error: Unexpected token: OPERATOR (<)
+str.length input >= 10;     // Error: Unexpected token: OPERATOR (>=)
+```
+
+**Correct: Function calls wrapped in parentheses**
+```baba
+// CORRECT - Wrap function calls in parentheses
+(length list) > 5;         // ✓ Works correctly
+(math.abs x) < 0.001;      // ✓ Works correctly
+(str.length input) >= 10;  // ✓ Works correctly
+```
+
+### **Critical Rule: Logical Operator Precedence**
+
+**Incorrect: Logical operators without parentheses**
+```baba
+// WRONG - Logical operators need parentheses
+a > 0 and b > 0;          // Error: Unexpected token: KEYWORD (and)
+x = y or y = z;            // Error: Unexpected token: KEYWORD (or)
+isValid and hasData;       // Error: Unexpected token: KEYWORD (and)
+```
+
+**Correct: Logical operators wrapped in parentheses**
+```baba
+// CORRECT - Wrap logical expressions in parentheses
+(a > 0) and (b > 0);      // ✓ Works correctly
+(x = y) or (y = z);        // ✓ Works correctly
+(isValid) and (hasData);   // ✓ Works correctly
+```
+
+### **Critical Rule: Complex Comparison Chains**
+
+**Incorrect: Complex comparisons without parentheses**
+```baba
+// WRONG - Complex comparisons need parentheses
+math.abs (x * x + y * y) - (z * z) < 0.001;  // Error: Unexpected token: OPERATOR (-)
+side1 + side2 > side3;                         // Error: Unexpected token: OPERATOR (>)
+```
+
+**Correct: Complex comparisons wrapped in parentheses**
+```baba
+// CORRECT - Wrap complex comparisons in parentheses
+(math.abs ((x * x + y * y) - (z * z))) < 0.001;  // ✓ Works correctly
+((side1 + side2) > side3);                         // ✓ Works correctly
+```
+
+### **Automation Rules for Future Tooling**
+
+For future syntax correction tools, apply these rules in order:
+
+#### **Rule 1: Function Call Wrapping**
+- **Pattern**: `function_name args OPERATOR value`
+- **Action**: Wrap function call: `(function_name args) OPERATOR value`
+- **Examples**:
+  - `length list > 0` → `(length list) > 0`
+  - `math.sqrt x < 10` → `(math.sqrt x) < 10`
+  - `str.trim input >= 5` → `(str.trim input) >= 5`
+
+#### **Rule 2: Logical Operator Wrapping**
+- **Pattern**: `expression1 and expression2` or `expression1 or expression2`
+- **Action**: Wrap each expression: `(expression1) and (expression2)`
+- **Examples**:
+  - `a > 0 and b > 0` → `(a > 0) and (b > 0)`
+  - `x = y or y = z` → `(x = y) or (y = z)`
+  - `isValid and hasData and isReady` → `(isValid) and (hasData) and (isReady)`
+
+#### **Rule 3: Complex Expression Wrapping**
+- **Pattern**: `arithmetic_expression OPERATOR value`
+- **Action**: Wrap arithmetic expression: `(arithmetic_expression) OPERATOR value`
+- **Examples**:
+  - `x + y > z` → `(x + y) > z`
+  - `a * b + c <= d` → `(a * b + c) <= d`
+  - `math.abs (x - y) < 0.001` → `(math.abs (x - y)) < 0.001`
+
+#### **Rule 4: Nested Function Call Wrapping**
+- **Pattern**: `function_call (args) OPERATOR value`
+- **Action**: Wrap entire function call: `(function_call (args)) OPERATOR value`
+- **Examples**:
+  - `math.abs (x * x + y * y) < 0.001` → `(math.abs (x * x + y * y)) < 0.001`
+  - `str.length (str.trim input) >= 5` → `(str.length (str.trim input)) >= 5`
+
+### **Common Patterns That Always Need Parentheses**
+
+```baba
+// These patterns ALWAYS need parentheses:
+
+// 1. Function calls in comparisons
+(length list) > 0;
+(math.sqrt x) < 10;
+(str.trim input) >= 5;
+
+// 2. Logical combinations
+(a > 0) and (b > 0);
+(x = y) or (y = z);
+(isValid) and (hasData);
+
+// 3. Complex arithmetic in comparisons
+((a + b) > c);
+((x * y + z) <= 100);
+((math.abs (x - y)) < 0.001);
+
+// 4. Nested function calls in comparisons
+((math.abs (x * x + y * y)) < 0.001);
+((str.length (str.trim input)) >= 10);
+```
+
+### **Why These Rules Exist**
+
+Baba Yaga's parser is designed for clarity and explicit precedence. Unlike languages that use operator precedence rules, Baba Yaga requires explicit parentheses to:
+
+1. **Eliminate ambiguity** - No guessing about operator precedence
+2. **Improve readability** - Intent is always clear
+3. **Prevent errors** - Compile-time detection of precedence issues
+4. **Enable parsing** - Simpler, more predictable parsing logic
+
+### **Regex Patterns for Automated Correction**
+
+For future tooling, these regex patterns can identify and fix common parenthesization issues:
+
+#### **Pattern 1: Function Calls in Comparisons**
+```regex
+# Find: function_name args OPERATOR value
+(\w+(?:\.\w+)?(?:\s+[^><=!]+)*)\s*([><=!]=?)\s*([^;,\s]+)
+
+# Replace: (function_name args) OPERATOR value
+($1) $2 $3
+
+# Examples:
+# length list > 0 → (length list) > 0
+# math.abs x < 0.001 → (math.abs x) < 0.001
+# str.trim input >= 5 → (str.trim input) >= 5
+```
+
+#### **Pattern 2: Logical Operators**
+```regex
+# Find: expression1 and expression2
+([^;\s]+)\s+(and|or)\s+([^;\s]+)
+
+# Replace: (expression1) and (expression2)
+($1) $2 ($3)
+
+# Examples:
+# a > 0 and b > 0 → (a > 0) and (b > 0)
+# x = y or y = z → (x = y) or (y = z)
+```
+
+#### **Pattern 3: Complex Arithmetic in Comparisons**
+```regex
+# Find: arithmetic_expression OPERATOR value
+([^;\s]*[\+\-\*\/][^;\s]*)\s*([><=!]=?)\s*([^;,\s]+)
+
+# Replace: (arithmetic_expression) OPERATOR value
+($1) $2 $3
+
+# Examples:
+# x + y > z → (x + y) > z
+# a * b + c <= d → (a * b + c) <= d
+```
+
+#### **Pattern 4: Nested Function Calls in Comparisons**
+```regex
+# Find: function_call (args) OPERATOR value
+(\w+(?:\.\w+)?\s*\([^)]+\))\s*([><=!]=?)\s*([^;,\s]+)
+
+# Replace: (function_call (args)) OPERATOR value
+($1) $2 $3
+
+# Examples:
+# math.abs (x - y) < 0.001 → (math.abs (x - y)) < 0.001
+# str.length (str.trim input) >= 5 → (str.length (str.trim input)) >= 5
+```
+
+### **Automated Correction Algorithm**
+
+```python
+def fix_baba_yaga_syntax(code):
+    """
+    Apply parenthesization rules to Baba Yaga code.
+    Apply rules in order to avoid conflicts.
+    """
+    
+    # Rule 1: Fix function calls in comparisons
+    code = re.sub(
+        r'(\w+(?:\.\w+)?(?:\s+[^><=!]+)*)\s*([><=!]=?)\s*([^;,\s]+)',
+        r'(\1) \2 \3',
+        code
+    )
+    
+    # Rule 2: Fix logical operators
+    code = re.sub(
+        r'([^;\s]+)\s+(and|or)\s+([^;\s]+)',
+        r'(\1) \2 (\3)',
+        code
+    )
+    
+    # Rule 3: Fix complex arithmetic in comparisons
+    code = re.sub(
+        r'([^;\s]*[\+\-\*\/][^;\s]*)\s*([><=!]=?)\s*([^;,\s]+)',
+        r'(\1) \2 \3',
+        code
+    )
+    
+    # Rule 4: Fix nested function calls in comparisons
+    code = re.sub(
+        r'(\w+(?:\.\w+)?\s*\([^)]+\))\s*([><=!]=?)\s*([^;,\s]+)',
+        r'(\1) \2 \3',
+        code
+    )
+    
+    return code
+```
+
+### **Validation Rules**
+
+After applying corrections, validate that:
+
+1. **All comparisons have balanced parentheses**
+2. **Logical operators are properly wrapped**
+3. **Function calls in comparisons are wrapped**
+4. **No syntax errors remain**
+
+### **Edge Cases and Limitations**
+
+- **Nested parentheses**: May require multiple passes
+- **Complex expressions**: May need manual review
+- **String literals**: Avoid modifying content inside quotes
+- **Comments**: Preserve comment formatting
+- **Line breaks**: Handle multi-line expressions carefully
+
+## Type System Gotchas
+
+### **Incorrect: Expecting JavaScript-like type behavior**
+```baba
+// WRONG - Baba Yaga has different type semantics
+x : null;           // No null value
+x : undefined;      // No undefined
+x : NaN;            // No NaN
+```
+
+### **Correct: Use Baba Yaga type system**
+```baba
+// CORRECT - Use Result type for optional values
+x : Ok 5;           // Success case
+x : Err "error";    // Error case
+
+// CORRECT - Use when expressions for conditional logic
+x : when (y > 0) is true then y _ then 0;
+```
+
+### **Incorrect: Ignoring type widening rules**
+```baba
+// WRONG - May cause type errors
+floatVal Float; floatVal : 3.14;  // Float literal
+intVal Int; intVal : floatVal;    // Error: Float cannot be assigned to Int
+```
+
+### **Correct: Follow type widening hierarchy**
+```baba
+// CORRECT - Int ⊂ Float ⊂ Number
+intVal Int; intVal : 5;
+floatVal Float; floatVal : intVal;        // Int → Float ✓
+numberVal Number; numberVal : floatVal;   // Float → Number ✓
+```
+
+## Data Structure Syntax
+
+### **Incorrect: Table literal shorthand**
+```baba
+// WRONG - Baba Yaga requires key: value pairs
+{ sum, product, difference }  // Missing colons
+```
+
+### **Correct: Explicit key-value pairs**
+```baba
+// CORRECT - Explicit key: value syntax
+{ sum: sum, product: product, difference: difference }
+```
+
+### **Incorrect: Dynamic property access**
+```baba
+// WRONG - Dynamic indexing not supported
+items.(count - 1)  // Unsupported property access
+```
+
+### **Correct: Use when expressions for conditional access**
+```baba
+// CORRECT - Use when for conditional access
+with (
+  item : when count is
+    1 then items.0
+    _ then when count is
+      2 then items.1
+      _ then items.2;
+) -> item;
+```
+
+### **Incorrect: Expecting JavaScript-like object access**
+```baba
+// WRONG - Baba Yaga objects have different structure
+result.property;           // May not work as expected
+result['property'];        // Not supported
+```
+
+### **Correct: Use Baba Yaga object access patterns**
+```baba
+// CORRECT - Baba Yaga objects use properties Map
+result.properties.get('property');
+
+// CORRECT - For table literals, use dot notation
+{ name: "John", age: 30 }.name;  // "John"
+```
+
+## Cross-References
+
+For comprehensive information about Baba Yaga's type system, see:
+- **[Types Documentation](./04_types.md)** - Complete type system reference
+- **[Recursion Documentation](./05_recursion-and-composition.md)** - Details on `with rec` usage
+- **[Crash Course](./00_crash-course.md)** - Examples and patterns
+- **[JavaScript Interop](./09_js-interop.md)** - Complete JS interop reference
+
+## Common Error Patterns
+
+### 1. **Unexpected SEMICOLON errors**
+- **Cause**: Missing semicolon after `when` expressions in `with` blocks
+- **Solution**: Always add semicolon after each `with` block entry
+
+### 2. **Unexpected COLON errors**
+- **Cause**: Incorrect table literal syntax
+- **Solution**: Use `{ key: value }` not `{ key, value }`
+
+### 3. **Unexpected KEYWORD errors**
+- **Cause**: Incorrect when expression structure
+- **Solution**: Use `_ then when (condition) is` pattern
+
+### 4. **Unexpected RBRACKET errors**
+- **Cause**: Complex expressions in list literals
+- **Solution**: Pre-compute values before creating lists
+
+### 5. **"with rec expects function-valued bindings" errors**
+- **Cause**: Non-function bindings in with rec
+- **Solution**: Only use function bindings in with rec
+
+### 6. **"Undefined property" errors**
+- **Cause**: Using non-existent functions
+- **Solution**: Check documentation for available functions
+
+## Best Practices
+
+### 1. **When Expressions**
+- Always use `_ then` for fallback cases
+- Use `then when` for nested conditions
+- Wrap complex conditions in parentheses
+- Add semicolons after when expressions in `with` blocks
+
+### 2. **With vs With Rec**
+- **Use `with`** for:
+  - Simple local bindings
+  - Computed values
+  - Mixed types (functions, values, expressions)
+  - Non-recursive local functions
+  
+- **Use `with rec`** for:
+  - Mutually recursive functions only
+  - When local functions need to reference each other
+  - Never for non-function bindings
+
+### 3. **With Blocks**
+- Add semicolons after each entry
+- Use with rec only for mutually recursive functions
+- Pre-compute complex values before using in data structures
+
+### 4. **Type System**
+- Use simple type declarations: `x Int; x : 5;`
+- Avoid function type annotations
+
+### 5. **Data Structures**
+- Use explicit `key: value` pairs in tables
+- Use `when` expressions for conditional access
+- Avoid dynamic property access
+
+## Debugging Tips
+
+### 1. **Check Semicolons**
+- Ensure every `with` block entry ends `with` semicolon
+- Check `when` expressions in `with` blocks
+
+### 2. **Verify When Structure**
+- Use `_ then when (condition) is` pattern
+- Avoid `else` keyword
+- Wrap complex conditions in parentheses
+
+### 3. **Validate Functions**
+- Check function names against documentation
+- Ensure `with rec` only has function bindings
+- Verify function syntax `with` arrows and semicolons
+
+### 4. **Check Data Structure Syntax**
+- Use explicit `key: value` pairs
+
+### 5. **Check Type System Usage**
+- Follow type widening rules: `Int` → `Float` → `Number`
+- Use `Result` type for optional values
+
+### 6. **Check Operator Precedence and Parentheses**
+- Wrap function calls in comparisons: `(length list) > 0`
+- Wrap logical expressions: `(a > 0) and (b > 0)`
+- Wrap complex arithmetic: `(x + y) > z`
+- See [Operator Precedence Rules](#operator-precedence-and-parenthesization-rules) for details
+
+## JavaScript Interop Gotchas
+
+When working with JavaScript interop, there are some specific gotchas to be aware of:
+
+### **JSValue Wrapper Behavior**
+
+```baba
+// WRONG - Expecting direct value access
+result : io.callJS "Math.abs" [-42];
+value : result.value;  // This is a JSValue wrapper, not the raw number
+
+// CORRECT - Pass JSValue directly to other io.* functions
+result : io.callJS "Math.abs" [-42];
+when result is
+  Ok jsValue then io.objectToTable jsValue  // JSValue accepted directly
+  Err msg then Err msg;
+```
+
+### **Type Conversion Timing**
+
+```baba
+// WRONG - Premature conversion can lose JS semantics
+parsed : io.callJS "JSON.parse" [jsonString];
+table : when parsed is
+  Ok jsValue then io.objectToTable jsValue;  // Converts immediately
+
+// CORRECT - Keep as JSValue until needed
+parsed : io.callJS "JSON.parse" [jsonString];
+// Work with JSValue directly, convert only when needed
+```
+
+For comprehensive JavaScript interop documentation, see [JavaScript Interop](./09_js-interop.md).
\ No newline at end of file