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 cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option<Self> {
370 if node.kind(db) == SyntaxKind::$name {
371 Some(Self(ElementList::new(node)))
372 } else {
373 None
374 }
375 }
376 fn as_syntax_node(&self) -> SyntaxNode {
377 self.node.clone()
378 }
379 fn stable_ptr(&self) -> Self::StablePtr {
380 $ptr_name(self.node.0.stable_ptr)
381 }
382 }
383 impl From<&$name> for SyntaxStablePtrId {
384 fn from(node: &$name) -> Self {
385 node.stable_ptr().untyped()
386 }
387 }
388 }
389}
390
391fn gen_enum_code(
392 name: String,
393 variants: Vec<Variant>,
394 missing_variant: Option<Variant>,
395) -> rust::Tokens {
396 let ptr_name = format!("{name}Ptr");
397 let green_name = format!("{name}Green");
398 let mut enum_body = quote! {};
399 let mut from_node_body = quote! {};
400 let mut cast_body = quote! {};
401 let mut ptr_conversions = quote! {};
402 let mut green_conversions = quote! {};
403 for variant in &variants {
404 let n = &variant.name;
405 let k = &variant.kind;
406
407 enum_body.extend(quote! {
408 $n($k),
409 });
410 from_node_body.extend(quote! {
411 SyntaxKind::$k => $(&name)::$n($k::from_syntax_node(db, node)),
412 });
413 cast_body.extend(quote! {
414 SyntaxKind::$k => Some($(&name)::$n($k::from_syntax_node(db, node))),
415 });
416 let variant_ptr = format!("{k}Ptr");
417 ptr_conversions.extend(quote! {
418 impl From<$(&variant_ptr)> for $(&ptr_name) {
419 fn from(value: $(&variant_ptr)) -> Self {
420 Self(value.0)
421 }
422 }
423 });
424 let variant_green = format!("{k}Green");
425 green_conversions.extend(quote! {
426 impl From<$(&variant_green)> for $(&green_name) {
427 fn from(value: $(&variant_green)) -> Self {
428 Self(value.0)
429 }
430 }
431 });
432 }
433 let missing_body = match missing_variant {
434 Some(missing) => quote! {
435 $(&green_name)($(missing.kind)::missing(db).0)
436 },
437 None => quote! {
438 panic!("No missing variant.");
439 },
440 };
441 quote! {
442 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
443 pub enum $(&name){
444 $enum_body
445 }
446 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
447 pub struct $(&ptr_name)(pub SyntaxStablePtrId);
448 impl TypedStablePtr for $(&ptr_name) {
449 type SyntaxNode = $(&name);
450 fn untyped(&self) -> SyntaxStablePtrId {
451 self.0
452 }
453 fn lookup(&self, db: &dyn SyntaxGroup) -> $(&name) {
454 $(&name)::from_syntax_node(db, self.0.lookup(db))
455 }
456 }
457 impl From<$(&ptr_name)> for SyntaxStablePtrId {
458 fn from(ptr: $(&ptr_name)) -> Self {
459 ptr.untyped()
460 }
461 }
462 $ptr_conversions
463 $green_conversions
464 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
465 pub struct $(&green_name)(pub GreenId);
466 impl TypedSyntaxNode for $(&name){
467 const OPTIONAL_KIND: Option<SyntaxKind> = None;
468 type StablePtr = $(&ptr_name);
469 type Green = $(&green_name);
470 fn missing(db: &dyn SyntaxGroup) -> Self::Green {
471 $missing_body
472 }
473 fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self {
474 let kind = node.kind(db);
475 match kind{
476 $from_node_body
477 _ => panic!(
478 "Unexpected syntax kind {:?} when constructing {}.",
479 kind,
480 $[str]($[const](&name))),
481 }
482 }
483 fn cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option<Self> {
484 let kind = node.kind(db);
485 match kind {
486 $cast_body
487 _ => None,
488 }
489 }
490 fn as_syntax_node(&self) -> SyntaxNode {
491 match self {
492 $(for v in &variants => $(&name)::$(&v.name)(x) => x.as_syntax_node(),)
493 }
494 }
495 fn stable_ptr(&self) -> Self::StablePtr {
496 $(&ptr_name)(self.as_syntax_node().0.stable_ptr)
497 }
498 }
499 impl From<&$(&name)> for SyntaxStablePtrId {
500 fn from(node: &$(&name)) -> Self {
501 node.stable_ptr().untyped()
502 }
503 }
504 impl $(&name) {
505 $("/// Checks if a kind of a variant of [")$(&name)$("].\n")
506 pub fn is_variant(kind: SyntaxKind) -> bool {
507 matches!(kind, $(for v in &variants join (|) => SyntaxKind::$(&v.kind)))
508 }
509 }
510 }
511}
512
513fn gen_token_code(name: String) -> rust::Tokens {
514 let green_name = format!("{name}Green");
515 let ptr_name = format!("{name}Ptr");
516
517 quote! {
518 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
519 pub struct $(&name) {
520 node: SyntaxNode,
521 }
522 impl Token for $(&name) {
523 fn new_green(db: &dyn SyntaxGroup, text: SmolStr) -> Self::Green {
524 $(&green_name)(Arc::new(GreenNode {
525 kind: SyntaxKind::$(&name),
526 details: GreenNodeDetails::Token(text),
527 }).intern(db))
528 }
529 fn text(&self, db: &dyn SyntaxGroup) -> SmolStr {
530 extract_matches!(&self.node.0.green.lookup_intern(db).details,
531 GreenNodeDetails::Token).clone()
532 }
533 }
534 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
535 pub struct $(&ptr_name)(pub SyntaxStablePtrId);
536 impl TypedStablePtr for $(&ptr_name) {
537 type SyntaxNode = $(&name);
538 fn untyped(&self) -> SyntaxStablePtrId {
539 self.0
540 }
541 fn lookup(&self, db: &dyn SyntaxGroup) -> $(&name) {
542 $(&name)::from_syntax_node(db, self.0.lookup(db))
543 }
544 }
545 impl From<$(&ptr_name)> for SyntaxStablePtrId {
546 fn from(ptr: $(&ptr_name)) -> Self {
547 ptr.untyped()
548 }
549 }
550 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
551 pub struct $(&green_name)(pub GreenId);
552 impl $(&green_name) {
553 pub fn text(&self, db: &dyn SyntaxGroup) -> SmolStr {
554 extract_matches!(
555 &self.0.lookup_intern(db).details, GreenNodeDetails::Token).clone()
556 }
557 }
558 impl TypedSyntaxNode for $(&name){
559 const OPTIONAL_KIND: Option<SyntaxKind> = Some(SyntaxKind::$(&name));
560 type StablePtr = $(&ptr_name);
561 type Green = $(&green_name);
562 fn missing(db: &dyn SyntaxGroup) -> Self::Green {
563 $(&green_name)(Arc::new(GreenNode {
564 kind: SyntaxKind::TokenMissing,
565 details: GreenNodeDetails::Token("".into()),
566 }).intern(db))
567 }
568 fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self {
569 match node.0.green.lookup_intern(db).details {
570 GreenNodeDetails::Token(_) => Self { node },
571 GreenNodeDetails::Node { .. } => panic!(
572 "Expected a token {:?}, not an internal node",
573 SyntaxKind::$(&name)
574 ),
575 }
576 }
577 fn cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option<Self> {
578 match node.0.green.lookup_intern(db).details {
579 GreenNodeDetails::Token(_) => Some(Self { node }),
580 GreenNodeDetails::Node { .. } => None,
581 }
582 }
583 fn as_syntax_node(&self) -> SyntaxNode {
584 self.node.clone()
585 }
586 fn stable_ptr(&self) -> Self::StablePtr {
587 $(&ptr_name)(self.node.0.stable_ptr)
588 }
589 }
590 impl From<&$(&name)> for SyntaxStablePtrId {
591 fn from(node: &$(&name)) -> Self {
592 node.stable_ptr().untyped()
593 }
594 }
595 }
596}
597
598fn gen_struct_code(name: String, members: Vec<Member>, is_terminal: bool) -> rust::Tokens {
599 let green_name = format!("{name}Green");
600 let mut body = rust::Tokens::new();
601 let mut field_indices = quote! {};
602 let mut args = quote! {};
603 let mut params = quote! {};
604 let mut args_for_missing = quote! {};
605 let mut ptr_getters = quote! {};
606 let mut key_field_index: usize = 0;
607 for (i, Member { name, kind, key }) in members.iter().enumerate() {
608 let index_name = format!("INDEX_{}", name.to_uppercase());
609 field_indices.extend(quote! {
610 pub const $index_name : usize = $i;
611 });
612 let key_name_green = format!("{name}_green");
613 args.extend(quote! {$name.0,});
614 let child_green = format!("{kind}Green");
617 params.extend(quote! {$name: $(&child_green),});
618 body.extend(quote! {
619 pub fn $name(&self, db: &dyn SyntaxGroup) -> $kind {
620 $kind::from_syntax_node(db, self.children[$i].clone())
621 }
622 });
623 args_for_missing.extend(quote! {$kind::missing(db).0,});
624
625 if *key {
626 ptr_getters.extend(quote! {
627 pub fn $(&key_name_green)(self, db: &dyn SyntaxGroup) -> $(&child_green) {
628 let ptr = self.0.lookup_intern(db);
629 if let SyntaxStablePtr::Child { key_fields, .. } = ptr {
630 $(&child_green)(key_fields[$key_field_index])
631 } else {
632 panic!("Unexpected key field query on root.");
633 }
634 }
635 });
636 key_field_index += 1;
637 }
638 }
639 let ptr_name = format!("{name}Ptr");
640 let new_green_impl = if is_terminal {
641 let token_name = name.replace("Terminal", "Token");
642 quote! {
643 impl Terminal for $(&name) {
644 const KIND: SyntaxKind = SyntaxKind::$(&name);
645 type TokenType = $(&token_name);
646 fn new_green(
647 db: &dyn SyntaxGroup,
648 leading_trivia: TriviaGreen,
649 token: <<$(&name) as Terminal>::TokenType as TypedSyntaxNode>::Green,
650 trailing_trivia: TriviaGreen
651 ) -> Self::Green {
652 let children: Vec<GreenId> = vec![$args];
653 let width = children.iter().copied().map(|id|
654 id.lookup_intern(db).width()).sum();
655 $(&green_name)(Arc::new(GreenNode {
656 kind: SyntaxKind::$(&name),
657 details: GreenNodeDetails::Node { children, width },
658 }).intern(db))
659 }
660 fn text(&self, db: &dyn SyntaxGroup) -> SmolStr {
661 self.token(db).text(db)
662 }
663 }
664 }
665 } else {
666 quote! {
667 impl $(&name) {
668 $field_indices
669 pub fn new_green(db: &dyn SyntaxGroup, $params) -> $(&green_name) {
670 let children: Vec<GreenId> = vec![$args];
671 let width = children.iter().copied().map(|id|
672 id.lookup_intern(db).width()).sum();
673 $(&green_name)(Arc::new(GreenNode {
674 kind: SyntaxKind::$(&name),
675 details: GreenNodeDetails::Node { children, width },
676 }).intern(db))
677 }
678 }
679 }
680 };
681 quote! {
682 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
683 pub struct $(&name) {
684 node: SyntaxNode,
685 children: Arc<[SyntaxNode]>,
686 }
687 $new_green_impl
688 impl $(&name) {
689 $body
690 }
691 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
692 pub struct $(&ptr_name)(pub SyntaxStablePtrId);
693 impl $(&ptr_name) {
694 $ptr_getters
695 }
696 impl TypedStablePtr for $(&ptr_name) {
697 type SyntaxNode = $(&name);
698 fn untyped(&self) -> SyntaxStablePtrId {
699 self.0
700 }
701 fn lookup(&self, db: &dyn SyntaxGroup) -> $(&name) {
702 $(&name)::from_syntax_node(db, self.0.lookup(db))
703 }
704 }
705 impl From<$(&ptr_name)> for SyntaxStablePtrId {
706 fn from(ptr: $(&ptr_name)) -> Self {
707 ptr.untyped()
708 }
709 }
710 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
711 pub struct $(&green_name)(pub GreenId);
712 impl TypedSyntaxNode for $(&name) {
713 const OPTIONAL_KIND: Option<SyntaxKind> = Some(SyntaxKind::$(&name));
714 type StablePtr = $(&ptr_name);
715 type Green = $(&green_name);
716 fn missing(db: &dyn SyntaxGroup) -> Self::Green {
717 $(&green_name)(Arc::new(GreenNode {
720 kind: SyntaxKind::$(&name),
721 details: GreenNodeDetails::Node {
722 children: vec![$args_for_missing],
723 width: TextWidth::default(),
724 },
725 }).intern(db))
726 }
727 fn from_syntax_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> Self {
728 let kind = node.kind(db);
729 assert_eq!(kind, SyntaxKind::$(&name), "Unexpected SyntaxKind {:?}. Expected {:?}.", kind, SyntaxKind::$(&name));
730 let children = db.get_children(node.clone());
731 Self { node, children }
732 }
733 fn cast(db: &dyn SyntaxGroup, node: SyntaxNode) -> Option<Self> {
734 let kind = node.kind(db);
735 if kind == SyntaxKind::$(&name) {
736 Some(Self::from_syntax_node(db, node))
737 } else {
738 None
739 }
740 }
741 fn as_syntax_node(&self) -> SyntaxNode {
742 self.node.clone()
743 }
744 fn stable_ptr(&self) -> Self::StablePtr {
745 $(&ptr_name)(self.node.0.stable_ptr)
746 }
747 }
748 impl From<&$(&name)> for SyntaxStablePtrId {
749 fn from(node: &$(&name)) -> Self {
750 node.stable_ptr().untyped()
751 }
752 }
753 }
754}