feat(grammar): update tree-sitter grammar to v0.3.0

Updated tree-sitter grammar to match v0.3.0 LALRPOP parser:

Grammar updates:
- Schedule: block-based syntax with extends, override, recurrence
- Life arc: requires clause for field validation
- Template: uses behaviors/schedules syntax
- Behavior: correct keywords (choose/then/repeat with optional params)
- Type system: concept_comparison with any/is_condition
- Removed concept semicolon requirement

Query file updates:
- highlights.scm: updated node names to *_declaration
- outline.scm: updated for new declaration node names
- indents.scm: updated node names, removed concept semicolon

Corpus test updates:
- Created schedules.txt with v0.3.0 syntax tests
- Created highlights.txt for highlighting tests
- Updated type_system.txt for v0.3.0 type syntax
- Updated behaviors.txt for correct expression wrapping
- Updated declarations.txt to use correct node names
- Updated basic.txt to use character_declaration/character_body
- Deleted obsolete v0.2.0 syntax tests

Integration tests:
- Added tree_sitter_integration.rs test suite
- Fixed test_any_type to use correct v0.3.0 syntax
- Fixed test_tree_sitter_grammar_builds to use generate command
This commit is contained in:
2026-02-14 17:43:26 +00:00
parent 0c4994acd2
commit e6d297420c
15 changed files with 10449 additions and 7068 deletions

View File

@@ -21,7 +21,8 @@ module.exports = grammar({
conflicts: $ => [
[$.path_segments],
[$.sub_concept_enum_body, $.sub_concept_record_body]
[$.sub_concept_enum_body, $.sub_concept_record_body],
[$.uses_behaviors]
],
word: $ => $.identifier,
@@ -37,15 +38,15 @@ module.exports = grammar({
// Declarations
declaration: $ => choice(
$.use_declaration,
$.character,
$.template,
$.life_arc,
$.schedule,
$.behavior,
$.institution,
$.relationship,
$.location,
$.species,
$.character_declaration,
$.template_declaration,
$.life_arc_declaration,
$.schedule_declaration,
$.behavior_declaration,
$.institution_declaration,
$.relationship_declaration,
$.location_declaration,
$.species_declaration,
$.enum_declaration,
$.concept_declaration,
$.sub_concept,
@@ -68,28 +69,59 @@ module.exports = grammar({
path_segments: $ => sep1($.identifier, token('::')),
// Character declaration
character: $ => seq(
character_declaration: $ => seq(
'character',
field('name', $.identifier),
optional(seq(':', field('species', $.identifier))),
optional(field('template', $.template_clause)),
field('body', $.block)
field('body', $.character_body)
),
character_body: $ => seq(
'{',
repeat($.field),
'}'
),
template_clause: $ => seq('from', commaSep1($.identifier)),
// Template declaration
template: $ => seq(
template_declaration: $ => seq(
'template',
field('name', $.identifier),
optional(seq(':', field('species', $.identifier))),
optional('strict'),
field('body', $.template_body)
),
template_body: $ => seq(
'{',
repeat($.include),
repeat($.field),
repeat(choice(
$.include,
$.uses_behaviors,
$.uses_schedule,
$.field
)),
'}'
),
uses_behaviors: $ => seq(
'uses',
'behaviors',
':',
commaSep1($.identifier)
),
uses_schedule: $ => seq(
'uses',
choice('schedule', 'schedules'),
':',
choice(
$.identifier,
seq('[', commaSep1($.identifier), ']')
)
),
include: $ => seq('include', $.identifier),
// Fields (key: value pairs)
@@ -177,18 +209,36 @@ module.exports = grammar({
)))),
// Life arc declaration
life_arc: $ => seq(
life_arc_declaration: $ => seq(
'life_arc',
field('name', $.identifier),
optional(field('requires', $.requires_clause)),
'{',
repeat($.field),
repeat($.arc_state),
repeat($.state_block),
'}'
),
arc_state: $ => seq(
requires_clause: $ => seq(
'requires',
'{',
commaSep1($.required_field),
'}'
),
required_field: $ => seq(
field('name', $.identifier),
':',
field('type', $.identifier)
),
state_block: $ => seq(
'state',
field('name', $.identifier),
field('body', $.state_body)
),
state_body: $ => seq(
'{',
optional($.on_enter),
repeat($.field),
@@ -206,28 +256,76 @@ module.exports = grammar({
),
// Schedule declaration
schedule: $ => seq(
schedule_declaration: $ => seq(
'schedule',
field('name', $.identifier),
optional(seq('extends', field('extends', $.identifier))),
field('body', $.schedule_body)
),
schedule_body: $ => seq(
'{',
repeat($.field),
repeat($.schedule_block),
repeat(choice(
$.field,
$.schedule_block,
$.override_block,
$.recurrence_block
)),
'}'
),
// Named block: block name { time range, action, fields }
schedule_block: $ => seq(
'block',
field('name', $.identifier),
'{',
field('time_range', $.time_range),
repeat($.block_field),
'}'
),
// Override block: override name { time range, action, fields }
override_block: $ => seq(
'override',
field('name', $.identifier),
'{',
field('time_range', $.time_range),
repeat($.block_field),
'}'
),
// Recurrence: recurrence Name on DayOfWeek { blocks }
recurrence_block: $ => seq(
'recurrence',
field('name', $.identifier),
'on',
field('day', $.identifier),
'{',
repeat1($.schedule_block),
'}'
),
time_range: $ => seq(
field('start', $.time),
'->',
field('end', $.time),
optional(',')
),
block_field: $ => seq(
field('name', $.identifier),
':',
field('activity', $.identifier),
$.block
field('value', choice($.identifier, $.string, $.integer, $.float))
),
// Behavior tree declaration
behavior: $ => seq(
behavior_declaration: $ => seq(
'behavior',
field('name', $.identifier),
field('body', $.behavior_body)
),
behavior_body: $ => seq(
'{',
repeat($.field),
field('root', $.behavior_node),
@@ -239,6 +337,7 @@ module.exports = grammar({
$.sequence_node,
$.condition_node,
$.if_decorator_node,
$.repeat_node,
$.decorator_node,
$.action_node,
$.subtree_node
@@ -281,7 +380,20 @@ module.exports = grammar({
'}'
),
// Decorator node: repeat/retry/timeout/etc { child }
// Repeat node: repeat { child } or repeat(N) { child } or repeat(min..max) { child }
repeat_node: $ => seq(
'repeat',
optional(field('params', choice(
seq('(', $.integer, ')'),
seq('(', $.integer, '..', $.integer, ')'),
seq('(', $.duration, ')')
))),
'{',
field('child', $.behavior_node),
'}'
),
// Decorator node: retry/timeout/etc { child }
decorator_node: $ => seq(
field('decorator', $.decorator_keyword),
optional(field('params', $.decorator_params)),
@@ -291,7 +403,6 @@ module.exports = grammar({
),
decorator_keyword: $ => choice(
'repeat',
'invert',
'retry',
'timeout',
@@ -330,16 +441,20 @@ module.exports = grammar({
subtree_node: $ => seq('include', $.path),
// Institution declaration
institution: $ => seq(
institution_declaration: $ => seq(
'institution',
field('name', $.identifier),
$.block
field('body', $.block)
),
// Relationship declaration
relationship: $ => seq(
relationship_declaration: $ => seq(
'relationship',
field('name', $.identifier),
field('body', $.relationship_body)
),
relationship_body: $ => seq(
'{',
repeat1($.participant),
repeat($.field),
@@ -354,22 +469,42 @@ module.exports = grammar({
),
// Location declaration
location: $ => seq(
location_declaration: $ => seq(
'location',
field('name', $.identifier),
$.block
field('body', $.block)
),
// Species declaration
species: $ => seq(
species_declaration: $ => seq(
'species',
field('name', $.identifier),
field('body', $.species_body)
),
species_body: $ => seq(
'{',
repeat($.include),
repeat($.field),
repeat($.species_field),
'}'
),
species_field: $ => choice(
// Field with range: name: min..max
seq(
field('name', $.identifier),
':',
field('value', $.range)
),
// Field with single value: name: value
seq(
field('name', $.identifier),
':',
field('value', choice($.integer, $.float, $.boolean, $.string))
),
$.prose_block
),
// Enum declaration
enum_declaration: $ => seq(
'enum',
@@ -382,8 +517,7 @@ module.exports = grammar({
// Concept declaration - base type with no structure
concept_declaration: $ => seq(
'concept',
field('name', $.identifier),
';'
field('name', $.identifier)
),
// Sub-concept declaration - enum or record subtype with dot notation
@@ -403,13 +537,13 @@ module.exports = grammar({
// Enum form: Variant1, Variant2, Variant3
sub_concept_enum_body: $ => commaSep1($.identifier),
// Record form: field_name: Type, field_name: any
// Record form: field_name: value, field_name: value
sub_concept_record_body: $ => commaSep1($.sub_concept_field),
sub_concept_field: $ => seq(
field('name', $.identifier),
':',
field('type', choice($.identifier, $.any_type))
field('value', choice($.integer, $.float, $.string, $.boolean))
),
any_type: $ => 'any',
@@ -432,25 +566,26 @@ module.exports = grammar({
'}'
),
// A condition on a sub_concept field
// Field condition: field_name: any OR field_name: Type is Value [or Type is Value]*
field_condition: $ => seq(
field('sub_concept', $.dotted_path),
field('name', $.identifier),
':',
field('condition', $.condition_expr)
field('condition', choice(
$.any_type,
$.is_condition
))
),
// Condition: either 'any' or 'Type is Value or Type is Value2'
condition_expr: $ => choice(
$.any_type,
$.is_condition
),
// Pattern: DottedPath is Ident [or DottedPath is Ident]*
// Is condition: Type is Value [or Type is Value]*
is_condition: $ => seq(
$.dotted_path,
$.is_value,
repeat(seq('or', $.is_value))
),
is_value: $ => seq(
field('field', $.identifier),
'is',
$.identifier,
repeat(seq('or', $.dotted_path, 'is', $.identifier))
field('value', $.identifier)
),
// Expressions (for conditions in life arcs)