tree-sitter / tree-sitter-cpp

C++ grammar for tree-sitter
MIT License
262 stars 85 forks source link

bug: operator < is parsed as begnning of template argument list. #269

Closed scturtle closed 3 months ago

scturtle commented 4 months ago

Did you check existing issues?

Tree-Sitter CLI Version, if relevant (output of tree-sitter --version)

tree-sitter 0.22.6

Describe the bug

Operator < is parsed as beginning of template argument list.

Steps To Reproduce/Bad Parse Tree

(translation_unit
 (function_definition type: (primitive_type)
  declarator: 
   (function_declarator declarator: (identifier)
    parameters: (parameter_list ( )))
  body: 
   (compound_statement {
    (declaration
     type: 
      (struct_specifier struct name: (type_identifier)
       body: 
        (field_declaration_list {
         (field_declaration type: (primitive_type) declarator: (field_identifier) ;)
         }))
     declarator: (identifier) ;)
    (declaration type: (primitive_type)
     declarator: 
      (init_declarator declarator: (identifier) =
       value: 
        (field_expression argument: (identifier) operator: .
         field: 
          (template_method name: (field_identifier)
           arguments: (template_argument_list < (number_literal) >))))
     ;)
    })))

Expected Behavior/Parse Tree

(translation_unit
 (function_definition type: (primitive_type)
  declarator: 
   (function_declarator declarator: (identifier)
    parameters: (parameter_list ( )))
  body: 
   (compound_statement {
    (declaration
     type: 
      (struct_specifier struct name: (type_identifier)
       body: 
        (field_declaration_list {
         (field_declaration type: (primitive_type) declarator: (field_identifier) ;)
         }))
     declarator: (identifier) ;)
    (declaration type: (primitive_type)
     declarator: 
      (init_declarator declarator: (identifier) =
       value: 
        (binary_expression
         left: (field_expression argument: (identifier) operator: . field: (field_identifier))
         operator: < right: (number_literal)))
     ;)
    })))

Repro

int main() {
  struct A {int b;} a;
  bool t = a.b < 3;
}
touzeauv commented 4 months ago

You ran into the same problem that is described in issue https://github.com/tree-sitter/tree-sitter-cpp/issues/231. I suggested a fixed (see pull request https://github.com/tree-sitter/tree-sitter-cpp/pull/267) to solve it. My understanding is that when the parser has read "bool t = a.b < 3", it is in state where both interpretations (as a template or a comparison) are possible, but he gives priority to the template version and discard the other.

The change I introduced lead the parser to fork and consider both interpretations until one of them leads to an error and is then discarded. In case both could be valid, the comparison version is preferred.

Here is the tree I obtained:

(translation_unit
  (function_definition
    type: (primitive_type)
    declarator: (function_declarator
      declarator: (identifier)
      parameters: (parameter_list))
    body: (compound_statement
      (declaration
        type: (struct_specifier
          name: (type_identifier)
          body: (field_declaration_list
            (field_declaration
              type: (primitive_type)
              declarator: (field_identifier))))
        declarator: (identifier))
      (declaration
        type: (primitive_type)
        declarator: (init_declarator
          declarator: (identifier)
          value: (binary_expression
            left: (field_expression
              argument: (identifier)
              field: (field_identifier))
            right: (number_literal)))))))
jdrouhard commented 3 months ago

Fixed by #267