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
.
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
.