about summary refs log tree commit diff stats
path: root/js/scripting-lang/design/HISTORY/PRECEDENCE_RESOLUTION_PLAN.md
diff options
context:
space:
mode:
Diffstat (limited to 'js/scripting-lang/design/HISTORY/PRECEDENCE_RESOLUTION_PLAN.md')
-rw-r--r--js/scripting-lang/design/HISTORY/PRECEDENCE_RESOLUTION_PLAN.md163
1 files changed, 163 insertions, 0 deletions
diff --git a/js/scripting-lang/design/HISTORY/PRECEDENCE_RESOLUTION_PLAN.md b/js/scripting-lang/design/HISTORY/PRECEDENCE_RESOLUTION_PLAN.md
new file mode 100644
index 0000000..e2a7b0c
--- /dev/null
+++ b/js/scripting-lang/design/HISTORY/PRECEDENCE_RESOLUTION_PLAN.md
@@ -0,0 +1,163 @@
+# Precedence Resolution Plan
+
+## Problem Summary
+
+The parser is incorrectly translating `x - y` as `apply(x, negate(y))` instead of `subtract(x, y)`. This is caused by the `TokenType.MINUS` being included in `isValidArgumentStart`, which triggers function application when it should trigger binary operator parsing.
+
+## Root Cause Analysis
+
+1. **Function Application Interference**: The juxtaposition-based function application is interfering with operator parsing
+2. **Precedence Chain Issue**: The precedence chain doesn't properly distinguish between unary and binary operators
+3. **Context Sensitivity**: The minus operator can be either unary or binary depending on context
+
+## Solution Options
+
+### Option 1: Fix isValidArgumentStart (Recommended)
+**Approach**: Remove `TokenType.MINUS` from `isValidArgumentStart` and handle unary minus properly in the precedence chain
+
+**Pros**:
+- Minimal changes to existing code
+- Maintains combinator approach
+- Fixes the core issue directly
+
+**Cons**:
+- Requires careful handling of unary minus in precedence chain
+
+**Implementation**:
+1. Remove `TokenType.MINUS` from `isValidArgumentStart`
+2. Ensure unary minus is handled in `parseExpression()` at the beginning
+3. Test thoroughly
+
+### Option 2: Context-Aware Parsing
+**Approach**: Modify parsing to distinguish between unary and binary operators based on context
+
+**Pros**:
+- More accurate parsing
+- Handles complex cases correctly
+
+**Cons**:
+- Increases parser complexity significantly
+- May require major refactoring
+
+### Option 3: Separate Unary and Binary Parsing
+**Approach**: Handle unary operators separately from binary operators
+
+**Pros**:
+- Clear separation of concerns
+- Easier to understand and maintain
+
+**Cons**:
+- May require significant refactoring
+- Could break existing functionality
+
+## Recommended Implementation Plan
+
+### Phase 1: Fix the Core Issue (Option 1)
+1. **Remove MINUS from isValidArgumentStart**
+   ```javascript
+   function isValidArgumentStart(token) {
+       return token.type === TokenType.IDENTIFIER ||
+              token.type === TokenType.NUMBER ||
+              token.type === TokenType.STRING ||
+              token.type === TokenType.LEFT_PAREN ||
+              token.type === TokenType.LEFT_BRACE ||
+              token.type === TokenType.TRUE ||
+              token.type === TokenType.FALSE ||
+              token.type === TokenType.FUNCTION_REF ||
+              // Remove: token.type === TokenType.MINUS ||
+              token.type === TokenType.NOT;
+   }
+   ```
+
+2. **Ensure unary minus is handled in parseExpression()**
+   ```javascript
+   function parseExpression() {
+       // Handle unary minus at the beginning of expressions
+       if (current < tokens.length && tokens[current].type === TokenType.MINUS) {
+           current++;
+           const operand = parseTerm();
+           return {
+               type: 'FunctionCall',
+               name: 'negate',
+               args: [operand]
+           };
+       }
+       
+       let left = parseTerm();
+       // ... rest of function
+   }
+   ```
+
+3. **Add case in parsePrimary() for unary minus**
+   ```javascript
+   case TokenType.MINUS:
+       // Delegate unary minus to parseExpression for proper precedence
+       return parseExpression();
+   ```
+
+### Phase 2: Comprehensive Testing
+1. **Create test suite** covering all operator combinations
+2. **Test edge cases** like `x * -y`, `-x + y`, etc.
+3. **Verify function composition** still works
+4. **Check backward compatibility**
+
+### Phase 3: Fix Related Issues
+1. **Handle other precedence issues** that may be revealed
+2. **Fix any broken tests** in the main test suite
+3. **Document the final precedence rules**
+
+## Expected Outcomes
+
+### After Phase 1:
+- `x - y` → `subtract(x, y)` ✅
+- `-x` → `negate(x)` ✅
+- `x * -y` → `multiply(x, negate(y))` ✅
+- Function composition continues to work ✅
+
+### After Phase 2:
+- All operator combinations work correctly
+- Edge cases are handled properly
+- No regressions in existing functionality
+
+### After Phase 3:
+- Full test suite passes
+- Precedence rules are well-documented
+- Parser is stable and maintainable
+
+## Risk Assessment
+
+### Low Risk:
+- Removing `TokenType.MINUS` from `isValidArgumentStart`
+- Adding unary minus handling in `parseExpression()`
+
+### Medium Risk:
+- Changes to precedence chain
+- Potential regressions in existing functionality
+
+### High Risk:
+- Major refactoring of parser architecture
+- Breaking changes to existing syntax
+
+## Success Criteria
+
+1. **Binary minus works correctly**: `x - y` → `subtract(x, y)`
+2. **Unary minus works correctly**: `-x` → `negate(x)`
+3. **Mixed operations work**: `x * -y` → `multiply(x, negate(y))`
+4. **Function composition works**: `f via g x` → `compose(f, g)(x)`
+5. **All existing tests pass**
+6. **No new precedence issues introduced**
+
+## Timeline
+
+- **Phase 1**: 1-2 hours
+- **Phase 2**: 2-3 hours
+- **Phase 3**: 1-2 hours
+- **Total**: 4-7 hours
+
+## Next Steps
+
+1. **Implement Phase 1** (Option 1 - Fix isValidArgumentStart)
+2. **Test thoroughly** with comprehensive test suite
+3. **Fix any issues** that arise
+4. **Document final precedence rules**
+5. **Update test suite** to prevent regressions 
\ No newline at end of file