1mod dsl;
2#[cfg(test)]
3mod tests;
4mod trident;
5
6pub use dsl::*;
7pub use trident::trident_grammar;
8
9pub struct Grammar {
11 pub name: &'static str,
12 pub word: &'static str,
13 pub rules: Vec<(&'static str, Node)>,
14 pub extras: Vec<Node>,
15}
16
17pub enum Node {
20 Seq(Vec<Node>),
21 Choice(Vec<Node>),
22 Repeat(Box<Node>),
23 Repeat1(Box<Node>),
24 Str(&'static str),
25 Symbol(&'static str),
26 Pattern(&'static str),
27 Field {
28 name: &'static str,
29 content: Box<Node>,
30 },
31 Prec {
32 value: i32,
33 content: Box<Node>,
34 },
35 PrecLeft {
36 value: i32,
37 content: Box<Node>,
38 },
39 Alias {
40 content: Box<Node>,
41 value: &'static str,
42 named: bool,
43 },
44 Token(Box<Node>),
45 Blank,
46}
47
48impl Grammar {
49 pub fn to_json(&self) -> String {
50 let mut out = String::with_capacity(64 * 1024);
51 out.push_str("{\n");
52 out.push_str(" \"$schema\": \"https://tree-sitter.github.io/tree-sitter/assets/schemas/grammar.schema.json\",\n");
53 write_kv(&mut out, "name", self.name, 2);
54 out.push_str(",\n");
55 write_kv(&mut out, "word", self.word, 2);
56 out.push_str(",\n");
57
58 out.push_str(" \"rules\": {\n");
60 for (i, (name, node)) in self.rules.iter().enumerate() {
61 out.push_str(" \"");
62 out.push_str(name);
63 out.push_str("\": ");
64 node.write_json(&mut out, 4);
65 if i + 1 < self.rules.len() {
66 out.push(',');
67 }
68 out.push('\n');
69 }
70 out.push_str(" },\n");
71
72 out.push_str(" \"extras\": [\n");
74 for (i, node) in self.extras.iter().enumerate() {
75 out.push_str(" ");
76 node.write_json(&mut out, 4);
77 if i + 1 < self.extras.len() {
78 out.push(',');
79 }
80 out.push('\n');
81 }
82 out.push_str(" ],\n");
83
84 out.push_str(" \"conflicts\": [],\n");
85 out.push_str(" \"precedences\": [],\n");
86 out.push_str(" \"externals\": [],\n");
87 out.push_str(" \"inline\": [],\n");
88 out.push_str(" \"supertypes\": []\n");
89 out.push_str("}\n");
90 out
91 }
92}
93
94fn write_kv(out: &mut String, key: &str, val: &str, indent: usize) {
95 write_indent(out, indent);
96 out.push('"');
97 out.push_str(key);
98 out.push_str("\": \"");
99 json_escape(out, val);
100 out.push('"');
101}
102
103fn json_escape(out: &mut String, s: &str) {
104 for ch in s.chars() {
105 match ch {
106 '\\' => out.push_str("\\\\"),
107 '"' => out.push_str("\\\""),
108 '\n' => out.push_str("\\n"),
109 '\r' => out.push_str("\\r"),
110 '\t' => out.push_str("\\t"),
111 _ => out.push(ch),
112 }
113 }
114}
115
116fn write_indent(out: &mut String, n: usize) {
117 for _ in 0..n {
118 out.push(' ');
119 }
120}
121
122impl Node {
123 fn write_json(&self, out: &mut String, indent: usize) {
124 match self {
125 Node::Seq(members) => {
126 write_obj_open(out, "SEQ", indent);
127 write_members(out, "members", members, indent + 2);
128 out.push('\n');
129 write_indent(out, indent);
130 out.push('}');
131 }
132 Node::Choice(members) => {
133 write_obj_open(out, "CHOICE", indent);
134 write_members(out, "members", members, indent + 2);
135 out.push('\n');
136 write_indent(out, indent);
137 out.push('}');
138 }
139 Node::Repeat(content) => {
140 write_obj_open(out, "REPEAT", indent);
141 write_content(out, content, indent + 2);
142 out.push('\n');
143 write_indent(out, indent);
144 out.push('}');
145 }
146 Node::Repeat1(content) => {
147 write_obj_open(out, "REPEAT1", indent);
148 write_content(out, content, indent + 2);
149 out.push('\n');
150 write_indent(out, indent);
151 out.push('}');
152 }
153 Node::Str(value) => {
154 out.push_str("{\n");
155 write_indent(out, indent + 2);
156 out.push_str("\"type\": \"STRING\",\n");
157 write_kv(out, "value", value, indent + 2);
158 out.push('\n');
159 write_indent(out, indent);
160 out.push('}');
161 }
162 Node::Symbol(name) => {
163 out.push_str("{\n");
164 write_indent(out, indent + 2);
165 out.push_str("\"type\": \"SYMBOL\",\n");
166 write_kv(out, "name", name, indent + 2);
167 out.push('\n');
168 write_indent(out, indent);
169 out.push('}');
170 }
171 Node::Pattern(value) => {
172 out.push_str("{\n");
173 write_indent(out, indent + 2);
174 out.push_str("\"type\": \"PATTERN\",\n");
175 write_kv(out, "value", value, indent + 2);
176 out.push('\n');
177 write_indent(out, indent);
178 out.push('}');
179 }
180 Node::Field { name, content } => {
181 out.push_str("{\n");
182 write_indent(out, indent + 2);
183 out.push_str("\"type\": \"FIELD\",\n");
184 write_kv(out, "name", name, indent + 2);
185 out.push_str(",\n");
186 write_content(out, content, indent + 2);
187 out.push('\n');
188 write_indent(out, indent);
189 out.push('}');
190 }
191 Node::Prec { value, content } => {
192 out.push_str("{\n");
193 write_indent(out, indent + 2);
194 out.push_str("\"type\": \"PREC\",\n");
195 write_indent(out, indent + 2);
196 out.push_str("\"value\": ");
197 out.push_str(&value.to_string());
198 out.push_str(",\n");
199 write_content(out, content, indent + 2);
200 out.push('\n');
201 write_indent(out, indent);
202 out.push('}');
203 }
204 Node::PrecLeft { value, content } => {
205 out.push_str("{\n");
206 write_indent(out, indent + 2);
207 out.push_str("\"type\": \"PREC_LEFT\",\n");
208 write_indent(out, indent + 2);
209 out.push_str("\"value\": ");
210 out.push_str(&value.to_string());
211 out.push_str(",\n");
212 write_content(out, content, indent + 2);
213 out.push('\n');
214 write_indent(out, indent);
215 out.push('}');
216 }
217 Node::Alias {
218 content,
219 value,
220 named,
221 } => {
222 out.push_str("{\n");
223 write_indent(out, indent + 2);
224 out.push_str("\"type\": \"ALIAS\",\n");
225 write_content(out, content, indent + 2);
226 out.push_str(",\n");
227 write_indent(out, indent + 2);
228 out.push_str("\"named\": ");
229 out.push_str(if *named { "true" } else { "false" });
230 out.push_str(",\n");
231 write_kv(out, "value", value, indent + 2);
232 out.push('\n');
233 write_indent(out, indent);
234 out.push('}');
235 }
236 Node::Token(content) => {
237 out.push_str("{\n");
238 write_indent(out, indent + 2);
239 out.push_str("\"type\": \"TOKEN\",\n");
240 write_content(out, content, indent + 2);
241 out.push('\n');
242 write_indent(out, indent);
243 out.push('}');
244 }
245 Node::Blank => {
246 out.push_str("{\n");
247 write_indent(out, indent + 2);
248 out.push_str("\"type\": \"BLANK\"\n");
249 write_indent(out, indent);
250 out.push('}');
251 }
252 }
253 }
254}
255
256fn write_obj_open(out: &mut String, ty: &str, indent: usize) {
257 out.push_str("{\n");
258 write_indent(out, indent + 2);
259 out.push_str("\"type\": \"");
260 out.push_str(ty);
261 out.push_str("\",\n");
262}
263
264fn write_members(out: &mut String, key: &str, nodes: &[Node], indent: usize) {
265 write_indent(out, indent);
266 out.push('"');
267 out.push_str(key);
268 out.push_str("\": [\n");
269 for (i, node) in nodes.iter().enumerate() {
270 write_indent(out, indent + 2);
271 node.write_json(out, indent + 2);
272 if i + 1 < nodes.len() {
273 out.push(',');
274 }
275 out.push('\n');
276 }
277 write_indent(out, indent);
278 out.push(']');
279}
280
281fn write_content(out: &mut String, node: &Node, indent: usize) {
282 write_indent(out, indent);
283 out.push_str("\"content\": ");
284 node.write_json(out, indent);
285}