diff options
Diffstat (limited to 'js/scripting-lang/design/HISTORY/PRECEDENCE_RESOLUTION_PLAN.md')
-rw-r--r-- | js/scripting-lang/design/HISTORY/PRECEDENCE_RESOLUTION_PLAN.md | 163 |
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 |