diff options
Diffstat (limited to 'js/baba-yaga/docs/07_gotchyas.md')
-rw-r--r-- | js/baba-yaga/docs/07_gotchyas.md | 642 |
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 |