tree-sitter-javascript icon indicating copy to clipboard operation
tree-sitter-javascript copied to clipboard

Use new reserved words API to improve error recovery

Open maxbrunsfeld opened this issue 3 years ago • 0 comments

⚠️ Depends on https://github.com/tree-sitter/tree-sitter/pull/1635. Don't merge yet. ⚠️

This PR makes use of Tree-sitter's upcoming "reserved words" feature in order to provide better error recovery in many common cases.

For example, the following code contains an error on line 2.

var a = {if: 1}; // <- valid
b =              // <- incomplete
if (c) {         // <- error should be detected at this "if"
  a.if();        // <- valid
}

Previously, the parser would correctly allow the word if to be used as a property name on lines 1 and 4, but it would incorrectly allow the word if on line 3, which would prevent it from finding a good error recovery for the incomplete code on line 2.

Old Parse Tree - It would interpret the word if as an identifier, preventing it from correctly recognizing the if_statement below the error:

(program [0, 0] - [5, 0]
  (variable_declaration [0, 0] - [0, 16]
    (variable_declarator [0, 4] - [0, 15]
      name: (identifier [0, 4] - [0, 5])
      value: (object [0, 8] - [0, 15]
        (pair [0, 9] - [0, 14]
          key: (property_identifier [0, 9] - [0, 11])
          value: (number [0, 13] - [0, 14])))))
  (comment [0, 17] - [0, 28])
  (expression_statement [1, 0] - [2, 6]
    (assignment_expression [1, 0] - [2, 6]
      left: (identifier [1, 0] - [1, 1])
      (comment [1, 17] - [1, 33])
      right: (call_expression [2, 0] - [2, 6]
        function: (identifier [2, 0] - [2, 2])
        arguments: (arguments [2, 3] - [2, 6]
          (identifier [2, 4] - [2, 5])))))
  (statement_block [2, 7] - [4, 1]
    (comment [2, 17] - [2, 60])
    (expression_statement [3, 2] - [3, 9]
      (call_expression [3, 2] - [3, 8]
        function: (member_expression [3, 2] - [3, 6]
          object: (identifier [3, 2] - [3, 3])
          property: (property_identifier [3, 4] - [3, 6]))
        arguments: (arguments [3, 6] - [3, 8])))
    (comment [3, 17] - [3, 28])))
test.js	0 ms	(MISSING ";" [2, 6] - [2, 6])

New Parse Tree - On this branch, the if_statement is still parsed correctly, despite the error on the preceding line.

(program [0, 0] - [5, 0]
  (variable_declaration [0, 0] - [0, 19]
    (variable_declarator [0, 4] - [0, 18]
      name: (identifier [0, 4] - [0, 5])
      value: (object [0, 8] - [0, 18]
        (pair [0, 9] - [0, 17]
          key: (property_identifier [0, 9] - [0, 11])
          value: (true [0, 13] - [0, 17])))))
  (comment [0, 20] - [0, 31])
  (ERROR [1, 0] - [1, 3]
    (identifier [1, 0] - [1, 1]))
  (comment [1, 20] - [1, 36])
  (if_statement [2, 0] - [4, 1]
    condition: (parenthesized_expression [2, 3] - [2, 10]
      (member_expression [2, 4] - [2, 9]
        object: (identifier [2, 4] - [2, 5])
        property: (property_identifier [2, 6] - [2, 9])))
    consequence: (statement_block [2, 11] - [4, 1]
      (comment [2, 24] - [2, 67])
      (expression_statement [3, 2] - [3, 9]
        (call_expression [3, 2] - [3, 8]
          function: (member_expression [3, 2] - [3, 6]
            object: (identifier [3, 2] - [3, 3])
            property: (property_identifier [3, 4] - [3, 6]))
          arguments: (arguments [3, 6] - [3, 8])))
      (comment [3, 20] - [3, 31]))))

maxbrunsfeld avatar Apr 03 '22 17:04 maxbrunsfeld