-
My usage example can be simplified as follows: I want to put operators of the same precedence level together, something like this: a < 1 < b == 3
=> [a, (<, 1), (<, b), (==, 3)] // ok
=> [a, <, 1, <, b, ==, 3] // also ok My idea is to write such rules module.exports = grammar({
name: 'calc',
extras: $ => [
/\s/,
],
supertypes: $ => [],
inline: $ => [
],
word: $ => $.id,
rules: {
program: $ => repeat(seq($.expression, $._eos)),
expression: $ => choice(
seq("(", $.expression, ")"),
$.id,
$.num,
$.arith_expr, // 20
$.cmp_expr, //10
),
arith_expr: $ => prec.left(20,
seq(
field("base", $.expression),
repeat1(seq(
field("op", $.arithmetic_op),
field("expr", $.expression),
))),
),
arithmetic_op: $ => choice(
"+", "-"
),
cmp_expr: $ => prec.left(10,
seq(
field("base", $.expression),
repeat1(seq(
field("op", $.compare_op),
field("expr", $.expression),
))),
),
compare_op: $ => choice(
">=", ">", "<=", "<", "=="
),
// Atomic
id: $ => /[a-zA-Z]/,
num: $ => token(/0|[1-9][0-9]*/),
_eos: $ => ";",
}
}); My expected result is: (program
(expression
(cmp_expr
(expression
(id))
(compare_op)
(expression
(num))
(compare_op)
(expression
(id))
(compare_op)
(expression
(num))))) But the result is like this: (program
(expression
(cmp_expr
(expression
(id))
(compare_op)
(expression
(cmp_expr
(expression
(num))
(compare_op)
(expression
(cmp_expr
(expression
(id))
(compare_op)
(expression
(num))))))))) This is too weird. It is clearly left-associative, but it turns out to be right-associative, and it's not flattened. How do I need to write rules to get the flattened node? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
I have something similar in my language but ended up deciding it just wasn't needed to parse it in this flat way vs. a nested left-associative tree. What is your use case? |
Beta Was this translation helpful? Give feedback.
-
To flatten you need to use a combination of visible and hidden rules like on a bellow example that does what you need: module.exports = grammar({
name: 'calc',
word: $ => $.id,
rules: {
program: $ => repeat(seq($.expression, $._eos)),
expression: $ => choice(
seq("(", $._expression, ")"),
$.id,
$.num,
$.arith_expr,
alias($._cmp_expr, $.cmp_expr), // Unhide only top level $.cmp_expr
),
_expression: $ => choice( // Hide recursive rule
seq("(", $._expression, ")"),
$.id,
$.num,
$.arith_expr, // 20
$._cmp_expr, // 10
),
arith_expr: $ => prec.left(20,
seq(
field("base", $._expression),
repeat1(seq(
field("op", $.arithmetic_op),
field("expr", $._expression),
))),
),
arithmetic_op: $ => choice(
"+", "-"
),
_cmp_expr: $ => prec.left(10, // Hide recursive rule
seq(
field("base", $._expression),
repeat1(seq(
field("op", $.compare_op),
field("expr", $._expression),
))),
),
compare_op: $ => choice(
">=", ">", "<=", "<", "=="
),
// Atomic
id: $ => /[a-zA-Z]+/,
num: $ => token(/0|[1-9][0-9]*/),
_eos: $ => ";",
}
}); |
Beta Was this translation helpful? Give feedback.
To flatten you need to use a combination of visible and hidden rules like on a bellow example that does what you need: