feat(grammar): add type system nodes to tree-sitter

Added grammar rules for v0.3 type system declarations:
- concept_declaration: semicolon-terminated base type
- sub_concept: enum and record forms with dot notation
- concept_comparison: nested pattern matching with variant_pattern
- any_type: named node for the 'any' keyword
- template species extension: optional ': Species' syntax

Updated query files:
- highlights.scm: new keywords and named field highlights
- outline.scm: concept/sub_concept/concept_comparison in outline
- indents.scm: indentation for new brace-delimited nodes

Fixed pre-existing query issues:
- Replaced invalid repeat_node reference with decorator_node
- Removed invalid '?' punctuation reference

Added comprehensive test corpus (type_system.txt) covering:
- concept declaration (simple and multiple)
- sub_concept enum and record forms
- concept_comparison with any/is conditions
- template with species extension
- full combined example
This commit is contained in:
2026-02-14 14:29:29 +00:00
parent 4ce325e4ac
commit c49b00a2dc
8 changed files with 7402 additions and 4648 deletions

View File

@@ -20,7 +20,8 @@ module.exports = grammar({
], ],
conflicts: $ => [ conflicts: $ => [
[$.path_segments] [$.path_segments],
[$.sub_concept_enum_body, $.sub_concept_record_body]
], ],
word: $ => $.identifier, word: $ => $.identifier,
@@ -45,7 +46,10 @@ module.exports = grammar({
$.relationship, $.relationship,
$.location, $.location,
$.species, $.species,
$.enum_declaration $.enum_declaration,
$.concept_declaration,
$.sub_concept,
$.concept_comparison
), ),
// Use declarations // Use declarations
@@ -78,6 +82,7 @@ module.exports = grammar({
template: $ => seq( template: $ => seq(
'template', 'template',
field('name', $.identifier), field('name', $.identifier),
optional(seq(':', field('species', $.identifier))),
optional('strict'), optional('strict'),
'{', '{',
repeat($.include), repeat($.include),
@@ -374,6 +379,80 @@ module.exports = grammar({
'}' '}'
), ),
// Concept declaration - base type with no structure
concept_declaration: $ => seq(
'concept',
field('name', $.identifier),
';'
),
// Sub-concept declaration - enum or record subtype with dot notation
sub_concept: $ => seq(
'sub_concept',
field('parent', $.identifier),
'.',
field('name', $.identifier),
'{',
field('body', choice(
$.sub_concept_record_body,
$.sub_concept_enum_body
)),
'}'
),
// Enum form: Variant1, Variant2, Variant3
sub_concept_enum_body: $ => commaSep1($.identifier),
// Record form: field_name: Type, field_name: any
sub_concept_record_body: $ => commaSep1($.sub_concept_field),
sub_concept_field: $ => seq(
field('name', $.identifier),
':',
field('type', choice($.identifier, $.any_type))
),
any_type: $ => 'any',
// Concept comparison - compile-time pattern matching
concept_comparison: $ => seq(
'concept_comparison',
field('name', $.identifier),
'{',
commaSep1($.variant_pattern),
'}'
),
// A named variant with field conditions
variant_pattern: $ => seq(
field('name', $.identifier),
':',
'{',
commaSep1($.field_condition),
'}'
),
// A condition on a sub_concept field
field_condition: $ => seq(
field('sub_concept', $.dotted_path),
':',
field('condition', $.condition_expr)
),
// 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: $ => seq(
$.dotted_path,
'is',
$.identifier,
repeat(seq('or', $.dotted_path, 'is', $.identifier))
),
// Expressions (for conditions in life arcs) // Expressions (for conditions in life arcs)
expression: $ => choice( expression: $ => choice(
$.or_expression, $.or_expression,

View File

@@ -18,6 +18,9 @@
"species" "species"
"enum" "enum"
"state" "state"
"concept"
"sub_concept"
"concept_comparison"
] @keyword.declaration ] @keyword.declaration
; Keywords - Control flow and modifiers ; Keywords - Control flow and modifiers
@@ -45,6 +48,7 @@
"remove" "remove"
"append" "append"
"is" "is"
"any"
] @keyword.special ] @keyword.special
; Boolean literals ; Boolean literals
@@ -74,9 +78,16 @@
(species name: (identifier) @type.species) (species name: (identifier) @type.species)
(enum_declaration name: (identifier) @type.enum) (enum_declaration name: (identifier) @type.enum)
(arc_state name: (identifier) @type.state) (arc_state name: (identifier) @type.state)
(concept_declaration name: (identifier) @type.concept)
(sub_concept parent: (identifier) @type.concept)
(sub_concept name: (identifier) @type.sub_concept)
(concept_comparison name: (identifier) @type.concept_comparison)
(variant_pattern name: (identifier) @type.variant)
(template species: (identifier) @type.builtin)
; Field names ; Field names
(field name: (dotted_path) @property) (field name: (dotted_path) @property)
(sub_concept_field name: (identifier) @property)
; Species reference ; Species reference
(character species: (identifier) @type.builtin) (character species: (identifier) @type.builtin)
@@ -124,14 +135,10 @@
"." "."
".." ".."
"*" "*"
"?"
"@" "@"
] @punctuation.delimiter ] @punctuation.delimiter
; Behavior tree nodes ; Behavior tree nodes
(selector_node "?" @keyword.behavior.selector)
(sequence_node ">" @keyword.behavior.sequence)
(repeat_node "*" @keyword.behavior.repeat)
(action_node (identifier) @function.action) (action_node (identifier) @function.action)
; Transitions ; Transitions

View File

@@ -38,8 +38,12 @@
(enum_declaration) (enum_declaration)
(selector_node) (selector_node)
(sequence_node) (sequence_node)
(repeat_node) (decorator_node)
(sub_concept)
(concept_comparison)
(variant_pattern)
] @indent.begin ] @indent.begin
; Dedent after semicolon at top level ; Dedent after semicolon at top level
(use_declaration ";" @indent.end) (use_declaration ";" @indent.end)
(concept_declaration ";" @indent.end)

View File

@@ -55,3 +55,18 @@
(enum_declaration (enum_declaration
name: (identifier) @name name: (identifier) @name
) @symbol.enum ) @symbol.enum
; Concepts
(concept_declaration
name: (identifier) @name
) @symbol.concept
; Sub-concepts
(sub_concept
name: (identifier) @name
) @symbol.sub_concept
; Concept comparisons
(concept_comparison
name: (identifier) @name
) @symbol.concept_comparison

View File

@@ -91,6 +91,18 @@
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "enum_declaration" "name": "enum_declaration"
},
{
"type": "SYMBOL",
"name": "concept_declaration"
},
{
"type": "SYMBOL",
"name": "sub_concept"
},
{
"type": "SYMBOL",
"name": "concept_comparison"
} }
] ]
}, },
@@ -350,6 +362,31 @@
"name": "identifier" "name": "identifier"
} }
}, },
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ":"
},
{
"type": "FIELD",
"name": "species",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
}
]
},
{
"type": "BLANK"
}
]
},
{ {
"type": "CHOICE", "type": "CHOICE",
"members": [ "members": [
@@ -1704,6 +1741,396 @@
} }
] ]
}, },
"concept_declaration": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "concept"
},
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "STRING",
"value": ";"
}
]
},
"sub_concept": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "sub_concept"
},
{
"type": "FIELD",
"name": "parent",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "STRING",
"value": "."
},
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "STRING",
"value": "{"
},
{
"type": "FIELD",
"name": "body",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "sub_concept_record_body"
},
{
"type": "SYMBOL",
"name": "sub_concept_enum_body"
}
]
}
},
{
"type": "STRING",
"value": "}"
}
]
},
"sub_concept_enum_body": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "identifier"
}
]
}
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
}
]
},
"sub_concept_record_body": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "sub_concept_field"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "sub_concept_field"
}
]
}
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
}
]
},
"sub_concept_field": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "STRING",
"value": ":"
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "SYMBOL",
"name": "any_type"
}
]
}
}
]
},
"any_type": {
"type": "STRING",
"value": "any"
},
"concept_comparison": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "concept_comparison"
},
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "STRING",
"value": "{"
},
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "variant_pattern"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "variant_pattern"
}
]
}
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
}
]
},
{
"type": "STRING",
"value": "}"
}
]
},
"variant_pattern": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "STRING",
"value": ":"
},
{
"type": "STRING",
"value": "{"
},
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "field_condition"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "field_condition"
}
]
}
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
}
]
},
{
"type": "STRING",
"value": "}"
}
]
},
"field_condition": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "sub_concept",
"content": {
"type": "SYMBOL",
"name": "dotted_path"
}
},
{
"type": "STRING",
"value": ":"
},
{
"type": "FIELD",
"name": "condition",
"content": {
"type": "SYMBOL",
"name": "condition_expr"
}
}
]
},
"condition_expr": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "any_type"
},
{
"type": "SYMBOL",
"name": "is_condition"
}
]
},
"is_condition": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "dotted_path"
},
{
"type": "STRING",
"value": "is"
},
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "or"
},
{
"type": "SYMBOL",
"name": "dotted_path"
},
{
"type": "STRING",
"value": "is"
},
{
"type": "SYMBOL",
"name": "identifier"
}
]
}
}
]
},
"expression": { "expression": {
"type": "CHOICE", "type": "CHOICE",
"members": [ "members": [
@@ -1914,6 +2341,10 @@
"conflicts": [ "conflicts": [
[ [
"path_segments" "path_segments"
],
[
"sub_concept_enum_body",
"sub_concept_record_body"
] ]
], ],
"precedences": [], "precedences": [],

View File

@@ -269,6 +269,67 @@
] ]
} }
}, },
{
"type": "concept_comparison",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "variant_pattern",
"named": true
}
]
}
},
{
"type": "concept_declaration",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
}
},
{
"type": "condition_expr",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "any_type",
"named": true
},
{
"type": "is_condition",
"named": true
}
]
}
},
{ {
"type": "condition_node", "type": "condition_node",
"named": true, "named": true,
@@ -301,6 +362,14 @@
"type": "character", "type": "character",
"named": true "named": true
}, },
{
"type": "concept_comparison",
"named": true
},
{
"type": "concept_declaration",
"named": true
},
{ {
"type": "enum_declaration", "type": "enum_declaration",
"named": true "named": true
@@ -329,6 +398,10 @@
"type": "species", "type": "species",
"named": true "named": true
}, },
{
"type": "sub_concept",
"named": true
},
{ {
"type": "template", "type": "template",
"named": true "named": true
@@ -531,6 +604,32 @@
] ]
} }
}, },
{
"type": "field_condition",
"named": true,
"fields": {
"condition": {
"multiple": false,
"required": true,
"types": [
{
"type": "condition_expr",
"named": true
}
]
},
"sub_concept": {
"multiple": false,
"required": true,
"types": [
{
"type": "dotted_path",
"named": true
}
]
}
}
},
{ {
"type": "if_decorator_node", "type": "if_decorator_node",
"named": true, "named": true,
@@ -598,6 +697,25 @@
] ]
} }
}, },
{
"type": "is_condition",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "dotted_path",
"named": true
},
{
"type": "identifier",
"named": true
}
]
}
},
{ {
"type": "life_arc", "type": "life_arc",
"named": true, "named": true,
@@ -1119,6 +1237,106 @@
] ]
} }
}, },
{
"type": "sub_concept",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "sub_concept_enum_body",
"named": true
},
{
"type": "sub_concept_record_body",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"parent": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
}
},
{
"type": "sub_concept_enum_body",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
{
"type": "sub_concept_field",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"type": {
"multiple": false,
"required": true,
"types": [
{
"type": "any_type",
"named": true
},
{
"type": "identifier",
"named": true
}
]
}
}
},
{
"type": "sub_concept_record_body",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "sub_concept_field",
"named": true
}
]
}
},
{ {
"type": "subtree_node", "type": "subtree_node",
"named": true, "named": true,
@@ -1147,6 +1365,16 @@
"named": true "named": true
} }
] ]
},
"species": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
} }
}, },
"children": { "children": {
@@ -1283,6 +1511,32 @@
] ]
} }
}, },
{
"type": "variant_pattern",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "field_condition",
"named": true
}
]
}
},
{ {
"type": "(", "type": "(",
"named": false "named": false
@@ -1355,6 +1609,10 @@
"type": "and", "type": "and",
"named": false "named": false
}, },
{
"type": "any_type",
"named": true
},
{ {
"type": "append", "type": "append",
"named": false "named": false
@@ -1379,6 +1637,14 @@
"type": "choose", "type": "choose",
"named": false "named": false
}, },
{
"type": "concept",
"named": false
},
{
"type": "concept_comparison",
"named": false
},
{ {
"type": "cooldown", "type": "cooldown",
"named": false "named": false
@@ -1515,6 +1781,10 @@
"type": "string", "type": "string",
"named": true "named": true
}, },
{
"type": "sub_concept",
"named": false
},
{ {
"type": "succeed_always", "type": "succeed_always",
"named": false "named": false

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,360 @@
==================
Concept declaration
==================
concept Cup;
---
(source_file
(declaration
(concept_declaration
name: (identifier))))
==================
Multiple concept declarations
==================
concept Cup;
concept Customer;
concept Vendor;
---
(source_file
(declaration
(concept_declaration
name: (identifier)))
(declaration
(concept_declaration
name: (identifier)))
(declaration
(concept_declaration
name: (identifier))))
==================
Sub-concept - enum form
==================
sub_concept Cup.Size {
Small,
Medium,
Large
}
---
(source_file
(declaration
(sub_concept
parent: (identifier)
name: (identifier)
body: (sub_concept_enum_body
(identifier)
(identifier)
(identifier)))))
==================
Sub-concept - record form with any
==================
sub_concept Vendor.Inventory {
Bread: any,
Pastries: any,
Cakes: any,
Cup: any
}
---
(source_file
(declaration
(sub_concept
parent: (identifier)
name: (identifier)
body: (sub_concept_record_body
(sub_concept_field
name: (identifier)
type: (any_type))
(sub_concept_field
name: (identifier)
type: (any_type))
(sub_concept_field
name: (identifier)
type: (any_type))
(sub_concept_field
name: (identifier)
type: (any_type))))))
==================
Sub-concept - record form with typed fields
==================
sub_concept Vendor.Inventory {
Bread: any,
Pastries: Number
}
---
(source_file
(declaration
(sub_concept
parent: (identifier)
name: (identifier)
body: (sub_concept_record_body
(sub_concept_field
name: (identifier)
type: (any_type))
(sub_concept_field
name: (identifier)
type: (identifier))))))
==================
Concept comparison with any conditions
==================
concept_comparison NotInterested {
NotInterested: {
Cup.Size: any,
Cup.Type: any,
Cup.Color: any
}
}
---
(source_file
(declaration
(concept_comparison
name: (identifier)
(variant_pattern
name: (identifier)
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(any_type)))
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(any_type)))
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(any_type)))))))
==================
Concept comparison with is conditions
==================
concept_comparison Interest {
Interested: {
Cup.Type: Cup.Type is Glass or Cup.Type is Plastic,
Cup.Color: Cup.Color is Red
}
}
---
(source_file
(declaration
(concept_comparison
name: (identifier)
(variant_pattern
name: (identifier)
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(is_condition
(dotted_path
(identifier)
(identifier))
(identifier)
(dotted_path
(identifier)
(identifier))
(identifier))))
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(is_condition
(dotted_path
(identifier)
(identifier))
(identifier))))))))
==================
Concept comparison with multiple variants
==================
concept_comparison FoodQuality {
Excellent: {
Food.Freshness: Food.Freshness is Fresh
},
Poor: {
Food.Freshness: Food.Freshness is Stale or Food.Freshness is Spoiled
}
}
---
(source_file
(declaration
(concept_comparison
name: (identifier)
(variant_pattern
name: (identifier)
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(is_condition
(dotted_path
(identifier)
(identifier))
(identifier)))))
(variant_pattern
name: (identifier)
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(is_condition
(dotted_path
(identifier)
(identifier))
(identifier)
(dotted_path
(identifier)
(identifier))
(identifier))))))))
==================
Template with species extension
==================
template Person: Human {
age: 0..100
name: ""
}
---
(source_file
(declaration
(template
name: (identifier)
species: (identifier)
(field
name: (dotted_path (identifier))
value: (value (range (integer) (integer))))
(field
name: (dotted_path (identifier))
value: (value (string))))))
==================
Full type system example
==================
concept Cup;
sub_concept Cup.Size {
Small,
Medium,
Large
}
sub_concept Cup.Type {
Ceramic,
Glass,
Plastic
}
concept_comparison CupPreference {
Preferred: {
Cup.Size: any,
Cup.Type: Cup.Type is Glass or Cup.Type is Ceramic
},
Avoided: {
Cup.Size: any,
Cup.Type: Cup.Type is Plastic
}
}
---
(source_file
(declaration
(concept_declaration
name: (identifier)))
(declaration
(sub_concept
parent: (identifier)
name: (identifier)
body: (sub_concept_enum_body
(identifier)
(identifier)
(identifier))))
(declaration
(sub_concept
parent: (identifier)
name: (identifier)
body: (sub_concept_enum_body
(identifier)
(identifier)
(identifier))))
(declaration
(concept_comparison
name: (identifier)
(variant_pattern
name: (identifier)
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(any_type)))
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(is_condition
(dotted_path
(identifier)
(identifier))
(identifier)
(dotted_path
(identifier)
(identifier))
(identifier)))))
(variant_pattern
name: (identifier)
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(any_type)))
(field_condition
sub_concept: (dotted_path
(identifier)
(identifier))
condition: (condition_expr
(is_condition
(dotted_path
(identifier)
(identifier))
(identifier))))))))