# 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