treesitter_types/codegen/
grammar_ir.rs1use serde::Deserialize;
2use std::collections::BTreeMap;
3
4#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
6pub struct TypeRef {
7 #[serde(rename = "type")]
8 pub type_name: String,
9 pub named: bool,
10}
11
12#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
14pub struct FieldInfo {
15 pub multiple: bool,
16 pub required: bool,
17 pub types: Vec<TypeRef>,
18}
19
20#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
22pub struct NodeType {
23 #[serde(rename = "type")]
24 pub type_name: String,
25 pub named: bool,
26 #[serde(default)]
28 pub fields: BTreeMap<String, FieldInfo>,
29 pub children: Option<FieldInfo>,
31 pub subtypes: Option<Vec<TypeRef>>,
33}
34
35pub fn parse_node_types(json: &str) -> Result<Vec<NodeType>, serde_json::Error> {
37 serde_json::from_str(json)
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn test_parse_leaf_node() {
46 let json = r#"[{"type": "identifier", "named": true}]"#;
47 let nodes = parse_node_types(json).unwrap();
48 assert_eq!(nodes.len(), 1);
49 assert_eq!(nodes[0].type_name, "identifier");
50 assert!(nodes[0].named);
51 assert!(nodes[0].fields.is_empty());
52 assert!(nodes[0].children.is_none());
53 assert!(nodes[0].subtypes.is_none());
54 }
55
56 #[test]
57 fn test_parse_anonymous_node() {
58 let json = r#"[{"type": ".", "named": false}]"#;
59 let nodes = parse_node_types(json).unwrap();
60 assert_eq!(nodes.len(), 1);
61 assert_eq!(nodes[0].type_name, ".");
62 assert!(!nodes[0].named);
63 }
64
65 #[test]
66 fn test_parse_node_with_fields() {
67 let json = r#"[{
68 "type": "import_spec",
69 "named": true,
70 "fields": {
71 "name": {
72 "multiple": false,
73 "required": false,
74 "types": [
75 {"type": ".", "named": false},
76 {"type": "identifier", "named": true}
77 ]
78 },
79 "path": {
80 "multiple": false,
81 "required": true,
82 "types": [
83 {"type": "interpreted_string_literal", "named": true}
84 ]
85 }
86 }
87 }]"#;
88 let nodes = parse_node_types(json).unwrap();
89 assert_eq!(nodes.len(), 1);
90 let node = &nodes[0];
91 assert_eq!(node.type_name, "import_spec");
92 assert!(node.named);
93 assert_eq!(node.fields.len(), 2);
94
95 let name_field = &node.fields["name"];
96 assert!(!name_field.multiple);
97 assert!(!name_field.required);
98 assert_eq!(name_field.types.len(), 2);
99 assert_eq!(name_field.types[0].type_name, ".");
100 assert!(!name_field.types[0].named);
101 assert_eq!(name_field.types[1].type_name, "identifier");
102 assert!(name_field.types[1].named);
103
104 let path_field = &node.fields["path"];
105 assert!(!path_field.multiple);
106 assert!(path_field.required);
107 assert_eq!(path_field.types.len(), 1);
108 }
109
110 #[test]
111 fn test_parse_node_with_children() {
112 let json = r#"[{
113 "type": "import_spec_list",
114 "named": true,
115 "fields": {},
116 "children": {
117 "multiple": true,
118 "required": false,
119 "types": [
120 {"type": "import_spec", "named": true}
121 ]
122 }
123 }]"#;
124 let nodes = parse_node_types(json).unwrap();
125 let node = &nodes[0];
126 let children = node.children.as_ref().unwrap();
127 assert!(children.multiple);
128 assert!(!children.required);
129 assert_eq!(children.types.len(), 1);
130 assert_eq!(children.types[0].type_name, "import_spec");
131 }
132
133 #[test]
134 fn test_parse_supertype_node() {
135 let json = r#"[{
136 "type": "_expression",
137 "named": true,
138 "subtypes": [
139 {"type": "binary_expression", "named": true},
140 {"type": "call_expression", "named": true},
141 {"type": "identifier", "named": true}
142 ]
143 }]"#;
144 let nodes = parse_node_types(json).unwrap();
145 let node = &nodes[0];
146 assert_eq!(node.type_name, "_expression");
147 let subtypes = node.subtypes.as_ref().unwrap();
148 assert_eq!(subtypes.len(), 3);
149 assert_eq!(subtypes[0].type_name, "binary_expression");
150 assert_eq!(subtypes[1].type_name, "call_expression");
151 assert_eq!(subtypes[2].type_name, "identifier");
152 }
153
154 #[test]
155 fn test_parse_multiple_nodes() {
156 let json = r#"[
157 {"type": "identifier", "named": true},
158 {"type": ".", "named": false},
159 {"type": "source_file", "named": true, "fields": {}, "children": {
160 "multiple": true, "required": false,
161 "types": [{"type": "identifier", "named": true}]
162 }}
163 ]"#;
164 let nodes = parse_node_types(json).unwrap();
165 assert_eq!(nodes.len(), 3);
166 }
167}