Skip to content

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

@dmfay

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions