fix(tree-sitter): resolve if keyword ambiguity in behavior nodes
Separate if(expr) condition from if(expr) { child } decorator to fix
grammar conflicts. Simplify decorator_params to accept only integer,
range, or duration.
This commit is contained in:
@@ -130,7 +130,7 @@ module.exports = grammar({
|
||||
|
||||
time: $ => /[0-9]{2}:[0-9]{2}(:[0-9]{2})?/,
|
||||
|
||||
duration: $ => /[0-9]+[hms]([0-9]+[hms])*/,
|
||||
duration: $ => /[0-9]+[dhms]([0-9]+[dhms])*/,
|
||||
|
||||
list: $ => seq('[', commaSep($.value), ']'),
|
||||
|
||||
@@ -232,17 +232,83 @@ module.exports = grammar({
|
||||
behavior_node: $ => choice(
|
||||
$.selector_node,
|
||||
$.sequence_node,
|
||||
$.repeat_node,
|
||||
$.condition_node,
|
||||
$.if_decorator_node,
|
||||
$.decorator_node,
|
||||
$.action_node,
|
||||
$.subtree_node
|
||||
),
|
||||
|
||||
selector_node: $ => seq('?', '{', repeat1($.behavior_node), '}'),
|
||||
// Selector node: choose { ... }
|
||||
selector_node: $ => seq(
|
||||
'choose',
|
||||
optional(field('label', $.identifier)),
|
||||
'{',
|
||||
repeat1($.behavior_node),
|
||||
'}'
|
||||
),
|
||||
|
||||
sequence_node: $ => seq('>', '{', repeat1($.behavior_node), '}'),
|
||||
// Sequence node: then { ... }
|
||||
sequence_node: $ => seq(
|
||||
'then',
|
||||
optional(field('label', $.identifier)),
|
||||
'{',
|
||||
repeat1($.behavior_node),
|
||||
'}'
|
||||
),
|
||||
|
||||
repeat_node: $ => seq('*', '{', $.behavior_node, '}'),
|
||||
// Condition node: if(expr) or when(expr) - NO BRACES
|
||||
condition_node: $ => seq(
|
||||
choice('if', 'when'),
|
||||
'(',
|
||||
field('condition', $.expression),
|
||||
')'
|
||||
),
|
||||
|
||||
// If decorator: if(expr) { child } - WITH BRACES
|
||||
if_decorator_node: $ => seq(
|
||||
'if',
|
||||
'(',
|
||||
field('condition', $.expression),
|
||||
')',
|
||||
'{',
|
||||
field('child', $.behavior_node),
|
||||
'}'
|
||||
),
|
||||
|
||||
// Decorator node: repeat/retry/timeout/etc { child }
|
||||
decorator_node: $ => seq(
|
||||
field('decorator', $.decorator_keyword),
|
||||
optional(field('params', $.decorator_params)),
|
||||
'{',
|
||||
field('child', $.behavior_node),
|
||||
'}'
|
||||
),
|
||||
|
||||
decorator_keyword: $ => choice(
|
||||
'repeat',
|
||||
'invert',
|
||||
'retry',
|
||||
'timeout',
|
||||
'cooldown',
|
||||
'succeed_always',
|
||||
'fail_always'
|
||||
),
|
||||
|
||||
decorator_params: $ => seq(
|
||||
'(',
|
||||
choice(
|
||||
// min..max range (for repeat)
|
||||
seq($.integer, '..', $.integer),
|
||||
// N (for repeat, retry)
|
||||
$.integer,
|
||||
// duration (for timeout, cooldown)
|
||||
$.duration
|
||||
),
|
||||
')'
|
||||
),
|
||||
|
||||
// Action node: action_name or action_name(params)
|
||||
action_node: $ => choice(
|
||||
seq($.identifier, '(', commaSep($.action_param), ')'),
|
||||
$.identifier
|
||||
@@ -255,7 +321,8 @@ module.exports = grammar({
|
||||
$.value
|
||||
),
|
||||
|
||||
subtree_node: $ => seq('@', $.path),
|
||||
// Subtree node: include path::to::subtree
|
||||
subtree_node: $ => seq('include', $.path),
|
||||
|
||||
// Institution declaration
|
||||
institution: $ => seq(
|
||||
@@ -275,12 +342,10 @@ module.exports = grammar({
|
||||
),
|
||||
|
||||
participant: $ => choice(
|
||||
// name { fields }
|
||||
seq($.path, $.block),
|
||||
// name as role { fields }
|
||||
// name as role { fields } (role optional)
|
||||
seq($.path, 'as', $.identifier, $.block),
|
||||
// bare name
|
||||
$.path
|
||||
// name { fields } (block required)
|
||||
seq($.path, $.block)
|
||||
),
|
||||
|
||||
// Location declaration
|
||||
|
||||
Reference in New Issue
Block a user