1use std::fs;
2use std::path::PathBuf;
3
4use genco::prelude::*;
5use xshell::Shell;
6
7use crate::cairo_spec::get_spec;
8use crate::spec::{Member, Node, NodeKind, Variant, Variants};
9
10pub fn project_root() -> PathBuf {
11 let dir = env!("CARGO_MANIFEST_DIR");
13 let res = PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned();
15 assert!(res.join("Cargo.toml").exists(), "Could not find project root directory.");
16 res
17}
18
19pub fn ensure_file_content(filename: PathBuf, content: String) {
20 if let Ok(old_contents) = fs::read_to_string(&filename) {
21 if old_contents == content {
22 return;
23 }
24 }
25
26 fs::write(&filename, content).unwrap();
27}
28
29pub fn get_codes() -> Vec<(String, String)> {
30 vec![
31 (
32 "crates/cairo-lang-syntax/src/node/ast.rs".into(),
33 reformat_rust_code(generate_ast_code().to_string().unwrap()),
34 ),
35 (
36 "crates/cairo-lang-syntax/src/node/kind.rs".into(),
37 reformat_rust_code(generate_kinds_code().to_string().unwrap()),
38 ),
39 (
40 "crates/cairo-lang-syntax/src/node/key_fields.rs".into(),
41 reformat_rust_code(generate_key_fields_code().to_string().unwrap()),
42 ),
43 ]
44}
45
46pub fn reformat_rust_code(text: String) -> String {
47 reformat_rust_code_inner(reformat_rust_code_inner(text))
49}
50pub fn reformat_rust_code_inner(text: String) -> String {
51 let sh = Shell::new().unwrap();
52 let cmd = sh.cmd("rustfmt").env("RUSTUP_TOOLCHAIN", "nightly-2024-11-23");
53 let cmd_with_args = cmd.arg("--config-path").arg(project_root().join("rustfmt.toml"));
54 let mut stdout = cmd_with_args.stdin(text).read().unwrap();
55 if !stdout.ends_with('\n') {
56 stdout.push('\n');
57 }
58 stdout
59}
60
61fn generate_kinds_code() -> rust::Tokens {
62 let spec = get_spec();
63 let mut tokens = quote! {
64 $("// Autogenerated file. To regenerate, please run `cargo run --bin generate-syntax`.\n")
65 use core::fmt;
66 };
67
68 let kinds = name_tokens(&spec, |k| !matches!(k, NodeKind::Enum { .. }));
70 let token_kinds = name_tokens(&spec, |k| matches!(k, NodeKind::Token { .. }));
71 let keyword_token_kinds =
72 name_tokens(&spec, |k| matches!(k, NodeKind::Token { is_keyword } if *is_keyword));
73 let terminal_kinds = name_tokens(&spec, |k| matches!(k, NodeKind::Terminal { .. }));
74 let keyword_terminal_kinds =
75 name_tokens(&spec, |k| matches!(k, NodeKind::Terminal { is_keyword, .. } if *is_keyword));
76
77 tokens.extend(quote! {
78 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
79 pub enum SyntaxKind {
80 $(for t in kinds => $t,)
81 }
82 impl SyntaxKind {
83 pub fn is_token(&self) -> bool {
84 matches!(
85 *self,
86 $(for t in token_kinds join ( | ) => SyntaxKind::$t)
87 )
88 }
89 pub fn is_terminal(&self) -> bool {
90 matches!(
91 *self,
92 $(for t in terminal_kinds join ( | ) => SyntaxKind::$t)
93 )
94 }
95 pub fn is_keyword_token(&self) -> bool {
96 matches!(
97 *self,
98 $(for t in keyword_token_kinds join ( | ) => SyntaxKind::$t)
99 )
100 }
101 pub fn is_keyword_terminal(&self) -> bool {
102 matches!(
103 *self,
104 $(for t in keyword_terminal_kinds join ( | ) => SyntaxKind::$t)
105 )
106 }
107 }
108 impl fmt::Display for SyntaxKind {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 write!(f, "{self:?}")
111 }
112 }
113 });
114 tokens
115}
116
117fn name_tokens(spec: &[Node], predicate: impl Fn(&NodeKind) -> bool) -> impl Iterator<Item = &str> {
119 spec.iter().filter(move |n| predicate(&n.kind)).map(|n| n.name.as_str())
120}
121
122fn generate_key_fields_code() -> rust::Tokens {
123 let spec = get_spec();
124 let mut arms = rust::Tokens::new();
125
126 for Node { name, kind } in spec.into_iter() {
127 match kind {
128 NodeKind::Struct { members } | NodeKind::Terminal { members, .. } => {
129 let mut fields = rust::Tokens::new();
130 for (i, member) in members.into_iter().enumerate() {
131 let field_name = member.name;
132 if member.key {
133 fields.extend(quote! { $("/*") $field_name $("*/") children[$i], });
134 }
135 }
136 arms.extend(quote! {
137 SyntaxKind::$name => {vec![$fields]},
138 });
139 }
140 NodeKind::List { .. } | NodeKind::SeparatedList { .. } | NodeKind::Token { .. } => {
141 arms.extend(quote! {
142 SyntaxKind::$name => vec![],
143 });
144 }
145 NodeKind::Enum { .. } => {}
146 }
147 }
148 let tokens = quote! {
149 $("// Autogenerated file. To regenerate, please run `cargo run --bin generate-syntax`.\n")
150 use super::ids::GreenId;
151 use super::kind::SyntaxKind;
152
153 $("/// Gets the vector of children ids that are the indexing key for this SyntaxKind.\n")
154 $("///\n")
155 $("/// Each SyntaxKind has some children that are defined in the spec to be its indexing key\n")
156 $("/// for its stable pointer. See [super::stable_ptr].\n")
157 pub fn get_key_fields(kind: SyntaxKind, children: &[GreenId]) -> Vec<GreenId> {
158 match kind {
159 $arms
160 }
161 }
162 };
163 tokens
164}
165
166fn generate_ast_code() -> rust::Tokens {
167 let spec = get_spec();
168 let mut tokens = quote! {
169 $("// Autogenerated file. To regenerate, please run `cargo run --bin generate-syntax`.\n")
170 #![allow(clippy::match_single_binding)]
171 #![allow(clippy::too_many_arguments)]
172 #![allow(dead_code)]
173 #![allow(unused_variables)]
174 use std::ops::Deref;
175 use std::sync::Arc;
176
177 use cairo_lang_filesystem::span::TextWidth;
178 use cairo_lang_utils::{extract_matches, Intern, LookupIntern};
179 use smol_str::SmolStr;
180
181 use super::element_list::ElementList;
182 use super::green::GreenNodeDetails;
183 use super::kind::SyntaxKind;
184 use super::{
185 GreenId, GreenNode, SyntaxGroup, SyntaxNode, SyntaxStablePtr, SyntaxStablePtrId,
186 Terminal, Token, TypedStablePtr, TypedSyntaxNode,
187 };
188
189 #[path = "ast_ext.rs"]
190 mod ast_ext;
191 };
192 let spec_clone = spec.clone();
193 let all_tokens: Vec<_> =
194 spec_clone.iter().filter(|node| matches!(node.kind, NodeKind::Terminal { .. })).collect();
195 for Node { name, kind } in spec.into_iter() {
196 tokens.extend(match kind {
197 NodeKind::Enum { variants, missing_variant } => {
198 let variants_list = match variants {
199 Variants::List(variants) => variants,
200 Variants::AllTokens => all_tokens
201 .iter()
202 .map(|node| Variant { name: node.name.clone(), kind: node.name.clone() })
203 .collect(),
204 };
205 gen_enum_code(name, variants_list, missing_variant)
206 }
207 NodeKind::Struct { members } => gen_struct_code(name, members, false),
208 NodeKind::Terminal { members, .. } => gen_struct_code(name, members, true),
209 NodeKind::Token { .. } => gen_token_code(name),
210 NodeKind::List { element_type } => gen_list_code(name, element_type),
211 NodeKind::SeparatedList { element_type, separator_type } => {
212 gen_separated_list_code(name, element_type, separator_type)
213 }
214 });
215 }
216 tokens
217}
218
219fn gen_list_code(name: String, element_type: String) -> rust::Tokens {
220 let ptr_name = format!("{name}Ptr");
222 let green_name = format!("{name}Green");
223 let element_green_name = format!("{element_type}Green");
224 let common_code = gen_common_list_code(&name, &green_name, &ptr_name);
225 quote! {
226 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
227 pub struct $(&name)(ElementList<$(&element_type),1>);
228 impl Deref for $(&name){
229 type Target = ElementList<$(&element_type),1>;
230
231 fn deref(&self) -> &Self::Target {
232 &self.0
233 }
234 }
235 impl $(&name){
236 pub fn new_green(
237 db: &dyn SyntaxGroup, children: Vec<$(&element_green_name)>
238 ) -> $(&green_name) {
239 let width = children.iter().map(|id|
240 id.0.lookup_intern(db).width()).sum();
241 $(&green_name)(Arc::new(GreenNode {
242 kind: SyntaxKind::$(&name),
243 details: GreenNodeDetails::Node {
244 children: children.iter().map(|x| x.0).collect(),
245 width,
246 },
247 }).intern(db))
248 }
249 }
250 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
251 pub struct $(&ptr_name)(pub SyntaxStablePtrId);
252 impl TypedStablePtr for $(&ptr_name) {
253 type SyntaxNode = $(&name);
254 fn untyped(&self) -> SyntaxStablePtrId {
255 self.0
256 }
257 fn lookup(&self, db: &dyn SyntaxGroup) -> $(&name) {
258 $(&name)::from_syntax_node(db, self.0.lookup(db))
259 }
260 }
261 impl From<$(&ptr_name)> for SyntaxStablePtrId {
262 fn from(ptr: $(&ptr_name)) -> Self {
263 ptr.untyped()
264 }
265 }
266 $common_code
267 }
268}
269
270fn gen_separated_list_code(
271 name: String,
272 element_type: String,
273 separator_type: String,
274) -> rust::Tokens {
275 let ptr_name = format!("{name}Ptr");
277 let green_name = format!("{name}Green");
278 let element_or_separator_green_name = format!("{name}ElementOrSeparatorGreen");
279 let element_green_name = format!("{element_type}Green");
280 let separator_green_name = format!("{separator_type}Green");
281 let common_code = gen_common_list_code(&name, &green_name, &ptr_name);
282 quote! {
283 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
284 pub struct $(&name)(ElementList<$(&element_type),2>);
285 impl Deref for $(&name){
286 type Target = ElementList<$(&element_type),2>;
287
288 fn deref(&self) -> &Self::Target {
289 &self.0
290 }
291 }
292 impl $(&name){
293 pub fn new_green(
294 db: &dyn SyntaxGroup, children: Vec<$(&element_or_separator_green_name)>
295 ) -> $(&green_name) {
296 let width = children.iter().map(|id|
297 id.id().lookup_intern(db).width()).sum();
298 $(&green_name)(Arc::new(GreenNode {
299 kind: SyntaxKind::$(&name),
300 details: GreenNodeDetails::Node {
301 children: children.iter().map(|x| x.id()).collect(),
302 width,
303 },
304 }).intern(db))
305 }
306 }
307 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
308 pub struct $(&ptr_name)(pub SyntaxStablePtrId);
309 impl TypedStablePtr for $(&ptr_name) {
310 type SyntaxNode = $(&name);
311 fn untyped(&self) -> SyntaxStablePtrId {
312 self.0
313 }
314 fn lookup(&self, db: &dyn SyntaxGroup) -> $(&name) {
315 $(&name)::from_syntax_node(db, self.0.lookup(db))
316 }
317 }
318 impl From<$(&ptr_name)> for SyntaxStablePtrId {
319 fn from(ptr: $(&ptr_name)) -> Self {
320 ptr.untyped()
321 }
322 }
323 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
324 pub enum $(&element_or_separator_green_name) {
325 Separator($(&separator_green_name)),
326 Element($(&element_green_name)),
327 }
328 impl From<$(&separator_green_name)> for $(&element_or_separator_green_name) {
329 fn from(value: $(&separator_green_name)) -> Self {
330 $(&element_or_separator_green_name)::Separator(value)
331 }
332 }
333 impl From<$(&element_green_name)> for $(&element_or_separator_green_name) {
334 fn from(value: $(&element_green_name)) -> Self {
335 $(&element_or_separator_green_name)::Element(value)
336 }
337 }
338 impl $(&element_or_separator_green_name) {
339 fn id(&self) -> GreenId {
340 match self {
341 $(&element_or_separator_green_name)::Separator(green) => green.0,
342 $(&element_or_separator_green_name)::Element(green) => green.0,
343 }
344 }
345 }
346 $common_code
347 }
348}
349
350fn gen_common_list_code(name: &str, green_name: &str, ptr_name: &str) -> rust::Tokens {
351 quote! {
352 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
353 pub struct $green_name(pub GreenId);
354 impl TypedSyntaxNode for $name {
355 const OPTIONAL_KIND: Option<SyntaxKind> = Some(SyntaxKind::$name);
356 type StablePtr = $ptr_name;
357 type Green = $green_name;
358 fn missing(db: &dyn SyntaxGroup) -> Self::Green {
359 $green_name(Arc::new(
360 GreenNode {
361 kind: SyntaxKind::$name,
362 details: GreenNodeDetails::Node { children: vec![], width: TextWidth::default() },
363 }).intern(db)
364 )
365 }
366 fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self {
367 Self(ElementList::new(node))
368 }
369 fn as_syntax_node(&self) -> SyntaxNode {
370 self.node.clone()
371 }
372 fn stable_ptr(&self) -> Self::StablePtr {
373 $ptr_name(self.node.0.stable_ptr)
374 }
375 }
376 impl From<&$name> for SyntaxStablePtrId {
377 fn from(node: &$name) -> Self {
378 node.stable_ptr().untyped()
379 }
380 }
381 }
382}
383
384fn gen_enum_code(
385 name: String,
386 variants: Vec<Variant>,
387 missing_variant: Option<Variant>,
388) -> rust::Tokens {
389 let ptr_name = format!("{name}Ptr");
390 let green_name = format!("{name}Green");
391 let mut enum_body = quote! {};
392 let mut from_node_body = quote! {};
393 let mut ptr_conversions = quote! {};
394 let mut green_conversions = quote! {};
395 for variant in &variants {
396 let n = &variant.name;
397 let k = &variant.kind;
398
399 enum_body.extend(quote! {
400 $n($k),
401 });
402 from_node_body.extend(quote! {
403 SyntaxKind::$k => $(&name)::$n($k::from_syntax_node(db, node)),
404 });
405 let variant_ptr = format!("{k}Ptr");
406 ptr_conversions.extend(quote! {
407 impl From<$(&variant_ptr)> for $(&ptr_name) {
408 fn from(value: $(&variant_ptr)) -> Self {
409 Self(value.0)
410 }
411 }
412 });
413 let variant_green = format!("{k}Green");
414 green_conversions.extend(quote! {
415 impl From<$(&variant_green)> for $(&green_name) {
416 fn from(value: $(&variant_green)) -> Self {
417 Self(value.0)
418 }
419 }
420 });
421 }
422 let missing_body = match missing_variant {
423 Some(missing) => quote! {
424 $(&green_name)($(missing.kind)::missing(db).0)
425 },
426 None => quote! {
427 panic!("No missing variant.");
428 },
429 };
430 quote! {
431 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
432 pub enum $(&name){
433 $enum_body
434 }
435 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
436 pub struct $(&ptr_name)(pub SyntaxStablePtrId);
437 impl TypedStablePtr for $(&ptr_name) {
438 type SyntaxNode = $(&name);
439 fn untyped(&self) -> SyntaxStablePtrId {
440 self.0
441 }
442 fn lookup(&self, db: &dyn SyntaxGroup) -> $(&name) {
443 $(&name)::from_syntax_node(db, self.0.lookup(db))
444 }
445 }
446 impl From<$(&ptr_name)> for SyntaxStablePtrId {
447 fn from(ptr: $(&ptr_name)) -> Self {
448 ptr.untyped()
449 }
450 }
451 $ptr_conversions
452 $green_conversions
453 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
454 pub struct $(&green_name)(pub GreenId);
455 impl TypedSyntaxNode for $(&name){
456 const OPTIONAL_KIND: Option<SyntaxKind> = None;
457 type StablePtr = $(&ptr_name);
458 type Green = $(&green_name);
459 fn missing(db: &dyn SyntaxGroup) -> Self::Green {
460 $missing_body
461 }
462 fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self {
463 let kind = node.kind(db);
464 match kind{
465 $from_node_body
466 _ => panic!(
467 "Unexpected syntax kind {:?} when constructing {}.",
468 kind,
469 $[str]($[const](&name))),
470 }
471 }
472 fn as_syntax_node(&self) -> SyntaxNode {
473 match self {
474 $(for v in &variants => $(&name)::$(&v.name)(x) => x.as_syntax_node(),)
475 }
476 }
477 fn stable_ptr(&self) -> Self::StablePtr {
478 $(&ptr_name)(self.as_syntax_node().0.stable_ptr)
479 }
480 }
481 impl From<&$(&name)> for SyntaxStablePtrId {
482 fn from(node: &$(&name)) -> Self {
483 node.stable_ptr().untyped()
484 }
485 }
486 impl $(&name) {
487 $("/// Checks if a kind of a variant of [")$(&name)$("].\n")
488 pub fn is_variant(kind: SyntaxKind) -> bool {
489 matches!(kind, $(for v in &variants join (|) => SyntaxKind::$(&v.kind)))
490 }
491 }
492 }
493}
494
495fn gen_token_code(name: String) -> rust::Tokens {
496 let green_name = format!("{name}Green");
497 let ptr_name = format!("{name}Ptr");
498
499 quote! {
500 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
501 pub struct $(&name) {
502 node: SyntaxNode,
503 }
504 impl Token for $(&name) {
505 fn new_green(db: &dyn SyntaxGroup, text: SmolStr) -> Self::Green {
506 $(&green_name)(Arc::new(GreenNode {
507 kind: SyntaxKind::$(&name),
508 details: GreenNodeDetails::Token(text),
509 }).intern(db))
510 }
511 fn text(&self, db: &dyn SyntaxGroup) -> SmolStr {
512 extract_matches!(&self.node.0.green.lookup_intern(db).details,
513 GreenNodeDetails::Token).clone()
514 }
515 }
516 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
517 pub struct $(&ptr_name)(pub SyntaxStablePtrId);
518 impl TypedStablePtr for $(&ptr_name) {
519 type SyntaxNode = $(&name);
520 fn untyped(&self) -> SyntaxStablePtrId {
521 self.0
522 }
523 fn lookup(&self, db: &dyn SyntaxGroup) -> $(&name) {
524 $(&name)::from_syntax_node(db, self.0.lookup(db))
525 }
526 }
527 impl From<$(&ptr_name)> for SyntaxStablePtrId {
528 fn from(ptr: $(&ptr_name)) -> Self {
529 ptr.untyped()
530 }
531 }
532 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
533 pub struct $(&green_name)(pub GreenId);
534 impl $(&green_name) {
535 pub fn text(&self, db: &dyn SyntaxGroup) -> SmolStr {
536 extract_matches!(
537 &self.0.lookup_intern(db).details, GreenNodeDetails::Token).clone()
538 }
539 }
540 impl TypedSyntaxNode for $(&name){
541 const OPTIONAL_KIND: Option<SyntaxKind> = Some(SyntaxKind::$(&name));
542 type StablePtr = $(&ptr_name);
543 type Green = $(&green_name);
544 fn missing(db: &dyn SyntaxGroup) -> Self::Green {
545 $(&green_name)(Arc::new(GreenNode {
546 kind: SyntaxKind::TokenMissing,
547 details: GreenNodeDetails::Token("".into()),
548 }).intern(db))
549 }
550 fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self {
551 match node.0.green.lookup_intern(db).details {
552 GreenNodeDetails::Token(_) => Self { node },
553 GreenNodeDetails::Node { .. } => panic!(
554 "Expected a token {:?}, not an internal node",
555 SyntaxKind::$(&name)
556 ),
557 }
558 }
559 fn as_syntax_node(&self) -> SyntaxNode {
560 self.node.clone()
561 }
562 fn stable_ptr(&self) -> Self::StablePtr {
563 $(&ptr_name)(self.node.0.stable_ptr)
564 }
565 }
566 impl From<&$(&name)> for SyntaxStablePtrId {
567 fn from(node: &$(&name)) -> Self {
568 node.stable_ptr().untyped()
569 }
570 }
571 }
572}
573
574fn gen_struct_code(name: String, members: Vec<Member>, is_terminal: bool) -> rust::Tokens {
575 let green_name = format!("{name}Green");
576 let mut body = rust::Tokens::new();
577 let mut field_indices = quote! {};
578 let mut args = quote! {};
579 let mut params = quote! {};
580 let mut args_for_missing = quote! {};
581 let mut ptr_getters = quote! {};
582 let mut key_field_index: usize = 0;
583 for (i, Member { name, kind, key }) in members.iter().enumerate() {
584 let index_name = format!("INDEX_{}", name.to_uppercase());
585 field_indices.extend(quote! {
586 pub const $index_name : usize = $i;
587 });
588 let key_name_green = format!("{name}_green");
589 args.extend(quote! {$name.0,});
590 let child_green = format!("{kind}Green");
593 params.extend(quote! {$name: $(&child_green),});
594 body.extend(quote! {
595 pub fn $name(&self, db: &dyn SyntaxGroup) -> $kind {
596 $kind::from_syntax_node(db, self.children[$i].clone())
597 }
598 });
599 args_for_missing.extend(quote! {$kind::missing(db).0,});
600
601 if *key {
602 ptr_getters.extend(quote! {
603 pub fn $(&key_name_green)(self, db: &dyn SyntaxGroup) -> $(&child_green) {
604 let ptr = self.0.lookup_intern(db);
605 if let SyntaxStablePtr::Child { key_fields, .. } = ptr {
606 $(&child_green)(key_fields[$key_field_index])
607 } else {
608 panic!("Unexpected key field query on root.");
609 }
610 }
611 });
612 key_field_index += 1;
613 }
614 }
615 let ptr_name = format!("{name}Ptr");
616 let new_green_impl = if is_terminal {
617 let token_name = name.replace("Terminal", "Token");
618 quote! {
619 impl Terminal for $(&name) {
620 const KIND: SyntaxKind = SyntaxKind::$(&name);
621 type TokenType = $(&token_name);
622 fn new_green(
623 db: &dyn SyntaxGroup,
624 leading_trivia: TriviaGreen,
625 token: <<$(&name) as Terminal>::TokenType as TypedSyntaxNode>::Green,
626 trailing_trivia: TriviaGreen
627 ) -> Self::Green {
628 let children: Vec<GreenId> = vec![$args];
629 let width = children.iter().copied().map(|id|
630 id.lookup_intern(db).width()).sum();
631 $(&green_name)(Arc::new(GreenNode {
632 kind: SyntaxKind::$(&name),
633 details: GreenNodeDetails::Node { children, width },
634 }).intern(db))
635 }
636 fn text(&self, db: &dyn SyntaxGroup) -> SmolStr {
637 self.token(db).text(db)
638 }
639 }
640 }
641 } else {
642 quote! {
643 impl $(&name) {
644 $field_indices
645 pub fn new_green(db: &dyn SyntaxGroup, $params) -> $(&green_name) {
646 let children: Vec<GreenId> = vec![$args];
647 let width = children.iter().copied().map(|id|
648 id.lookup_intern(db).width()).sum();
649 $(&green_name)(Arc::new(GreenNode {
650 kind: SyntaxKind::$(&name),
651 details: GreenNodeDetails::Node { children, width },
652 }).intern(db))
653 }
654 }
655 }
656 };
657 quote! {
658 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
659 pub struct $(&name) {
660 node: SyntaxNode,
661 children: Arc<[SyntaxNode]>,
662 }
663 $new_green_impl
664 impl $(&name) {
665 $body
666 }
667 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
668 pub struct $(&ptr_name)(pub SyntaxStablePtrId);
669 impl $(&ptr_name) {
670 $ptr_getters
671 }
672 impl TypedStablePtr for $(&ptr_name) {
673 type SyntaxNode = $(&name);
674 fn untyped(&self) -> SyntaxStablePtrId {
675 self.0
676 }
677 fn lookup(&self, db: &dyn SyntaxGroup) -> $(&name) {
678 $(&name)::from_syntax_node(db, self.0.lookup(db))
679 }
680 }
681 impl From<$(&ptr_name)> for SyntaxStablePtrId {
682 fn from(ptr: $(&ptr_name)) -> Self {
683 ptr.untyped()
684 }
685 }
686 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
687 pub struct $(&green_name)(pub GreenId);
688 impl TypedSyntaxNode for $(&name) {
689 const OPTIONAL_KIND: Option<SyntaxKind> = Some(SyntaxKind::$(&name));
690 type StablePtr = $(&ptr_name);
691 type Green = $(&green_name);
692 fn missing(db: &dyn SyntaxGroup) -> Self::Green {
693 $(&green_name)(Arc::new(GreenNode {
696 kind: SyntaxKind::$(&name),
697 details: GreenNodeDetails::Node {
698 children: vec![$args_for_missing],
699 width: TextWidth::default(),
700 },
701 }).intern(db))
702 }
703 fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self {
704 let kind = node.kind(db);
705 assert_eq!(kind, SyntaxKind::$(&name), "Unexpected SyntaxKind {:?}. Expected {:?}.", kind, SyntaxKind::$(&name));
706 let children = db.get_children(node.clone());
707 Self { node, children }
708 }
709 fn as_syntax_node(&self) -> SyntaxNode {
710 self.node.clone()
711 }
712 fn stable_ptr(&self) -> Self::StablePtr {
713 $(&ptr_name)(self.node.0.stable_ptr)
714 }
715 }
716 impl From<&$(&name)> for SyntaxStablePtrId {
717 fn from(node: &$(&name)) -> Self {
718 node.stable_ptr().untyped()
719 }
720 }
721 }
722}