Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: flat structure for else if chain #198

Open
1 task done
tomtomjhj opened this issue Mar 16, 2024 · 0 comments · May be fixed by #199
Open
1 task done

feature: flat structure for else if chain #198

tomtomjhj opened this issue Mar 16, 2024 · 0 comments · May be fixed by #199

Comments

@tomtomjhj
Copy link

Did you check the tree-sitter docs?

Is your feature request related to a problem? Please describe.

Currently, else if blocks are parsed as nested if statements. For example,

int main() {
  if (0) {
    ;
  } else if (0) {
    ;
  } else if (0) {
    ;
  }
}
(translation_unit ; [0, 0] - [9, 0]
  (function_definition ; [0, 0] - [8, 1]
    type: (primitive_type) ; [0, 0] - [0, 3]
    declarator: (function_declarator ; [0, 4] - [0, 10]
      declarator: (identifier) ; [0, 4] - [0, 8]
      parameters: (parameter_list)) ; [0, 8] - [0, 10]
    body: (compound_statement ; [0, 11] - [8, 1]
      (if_statement ; [1, 2] - [7, 3]
        condition: (parenthesized_expression ; [1, 5] - [1, 8]
          (number_literal)) ; [1, 6] - [1, 7]
        consequence: (compound_statement ; [1, 9] - [3, 3]
          (expression_statement)) ; [2, 4] - [2, 5]
        alternative: (else_clause ; [3, 4] - [7, 3]
          (if_statement ; [3, 9] - [7, 3]
            condition: (parenthesized_expression ; [3, 12] - [3, 15]
              (number_literal)) ; [3, 13] - [3, 14]
            consequence: (compound_statement ; [3, 16] - [5, 3]
              (expression_statement)) ; [4, 4] - [4, 5]
            alternative: (else_clause ; [5, 4] - [7, 3]
              (if_statement ; [5, 9] - [7, 3]
                condition: (parenthesized_expression ; [5, 12] - [5, 15]
                  (number_literal)) ; [5, 13] - [5, 14]
                consequence: (compound_statement ; [5, 16] - [7, 3]
                  (expression_statement)))))))))) ; [6, 4] - [6, 5]

This structure is suboptimal for various reasons.

  1. If the source contains very long else if chain, and a query pattern has a (editor-specific) predicate that climbs up the tree, processing the predicate can be very slow. For example, Neovim's #has-ancestor? predicate can be slow: Poor performance with Treesitter highlighting on deep if-else in c neovim/neovim#24965.

  2. Naively folding each (if_statement) would create a nested fold for each else if, resulting in deeply nested folds. What user would want is to have fold for each body of else if.

Describe the solution you'd like

The entire if-else if-else should be parsed as flat list. Something like this:

(if_statement
  (alternative (condition) (consequence)) ; the first `if`
  (alternative (condition) (consequence)) ; the first `else if`
  (alternative (condition) (consequence)) ; the second `else if`
  ...
  (else (consequence)) ; `else`
)

Describe alternatives you've considered

  1. For predicate performance, the predicate implementor can limit the traversal length. See perf(treesitter): bound has-ancestor? for highlighter neovim/neovim#27783. Other solutions: Poor performance with Treesitter highlighting on deep if-else in c neovim/neovim#24965 (comment)
  2. For folds, one could fold each consequence: (compound_statement) instead of if_statement.

Additional context

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant