Skip to content

query fails to match+capture with predicates against alternating and repeating s-expressions #98

Description

@dmfay

I'm attempting to capture the value of required_prop and, where it equals "the right value", that of conditional_prop. My query does not yield the results I expect, and diverges from the output on the tree-sitter playground. I discovered different incorrect alternation behavior there in tree-sitter/tree-sitter#1584, but I suspect node-tree-sitter is having its own problem with predicates as well.

index.js
import * as TreeSitter from 'tree-sitter';
import Python from 'tree-sitter-python';

const code = `
  class One(args):
        required_prop = 'i will match, because conditional_prop may be omitted'

  class Two(args):
        required_prop = 'i will match, because conditional_prop can be anything'
        conditional_prop = 'i do not have the correct value to be captured'

  class Three(args):
        required_prop = 'i will match, as will conditional_prop'
        conditional_prop = 'the right value'

  class Four(args):
        conditional_prop = 'the right value'
        required_prop = 'i will also match along with conditional_prop'
  `;

const query = `(class_definition
  name: (identifier) @ref
  body: (block [
    (expression_statement
      (assignment
        left: (identifier) @required
        right: (string) @required_val)
      (#match? @required "required_prop")
    )
    (_)
    (expression_statement
      (assignment
        left: (identifier) @conditional
        right: (string) @conditional_val
      (#match? @conditional "conditional_prop")
      (#match? @conditional_val "the right value")
    ))
  ]+))`;

(() => {
  const parser = TreeSitter.default();

  parser.setLanguage(Python);

  const tree = parser.parse(code);

  const matches = new TreeSitter.Query(parser.getLanguage(), query).matches(tree.rootNode);

  matches.forEach(m => {
    m.captures.forEach(c => console.log(c.name, tree.getText(c.node)));

    console.log();
  });
})();
package.json
{
  "name": "tree-sitter-query-testing",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "tree-sitter": "^0.20.0",
    "tree-sitter-python": "^0.19.0"
  }
}

I expect all classes to match, and all required_props to be captured. With the query as-is, the only matches are Three and Four (output is capture name and text):

> node index.js
ref Three
required required_prop
required_val 'i will match, as will conditional_prop'
conditional conditional_prop
conditional_val 'the right value'

ref Four
conditional conditional_prop
conditional_val 'the right value'
required required_prop
required_val 'i will also match along with conditional_prop'

In the playground, removing the repetition + on the prop alternation yields the expected results, but in node-tree-sitter instead nothing matches.

Removing both conditional predicates allows all @required and @required_vals to be captured, but no @conditional or @conditional_vals are found in spite of there being seven expression_statements that meet its definition in the program.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions