1

I'm learning how to use tree sitter and making a grammar for parsing simple predicate logic. I'll clearly need precedence to make negation, ~, bind more tightly than conjunction and dis-junction, (/\ and \/). I think I've applied precedence correctly, practically copying the example in the documentation.

Here is the grammar:

module.exports = grammar({
    name: 'Predicate_Calculus',

    rules: {
      // TODO: add the actual grammar rules
      source_file: $ => repeat($._expression),
      _expression: $ => choice($.identifier,
                               $._unary_expression,
                               $._binary_expression,
                               seq('(', $._expression, ')')),
      _binary_expression: $ => choice(
        $.and,
        $.or
      ),
      _unary_expression: $ => prec(2, choice(
        $.not
      )),
      not: $ => seq('~', $._expression),
      and: $ => prec.left(seq($._expression, "/\\", $._expression)),
      or: $ => prec.left(seq($._expression, "\\/", $._expression)),
      identifier: $ => /[a-z_]+/

    }
  });

However, when I run tree-sitter generate I get this error:

╰─➤ tree-sitter generate
Unresolved conflict for symbol sequence:

  '~'  _expression  •  '/\'  …

Possible interpretations:

  1:  '~'  (and  _expression  •  '/\'  _expression)  (precedence: 0, associativity: Left)
  2:  (not  '~'  _expression)  •  '/\'  …

Possible resolutions:

  1:  Specify a higher precedence in `and` than in the other rules.
  2:  Specify a higher precedence in `not` than in the other rules.
  3:  Specify a left or right associativity in `not`
  4:  Add a conflict for these rules: `not`, `and`

I believe what I've done with the prec(2 choice($.not)) is option 2 but it doesn't seem to be in effect in the grammar. I'm using tree-sitter 0.20.7 installed via cargo.

asm
  • 8,758
  • 3
  • 27
  • 48

1 Answers1

2

Okay, after experimenting with some more permutations I found that moving the precedence directive into the not definition fixes this issue.

      _unary_expression: $ => choice(
        $.not
      ),
      not: $ => prec(2, seq('~', $._expression)),

Removing the precedence from _unary_expression and moving it to inside not.

asm
  • 8,758
  • 3
  • 27
  • 48