cairo_lang_syntax_codegen/
spec.rs1#[derive(Clone)]
3pub struct Node {
4 pub name: String,
5 pub kind: NodeKind,
6}
7
8#[derive(Clone)]
10pub enum Variants {
11 List(Vec<Variant>),
13 AllTokens,
15}
16#[derive(Clone)]
17pub enum NodeKind {
18 Enum { variants: Variants, missing_variant: bool },
19 Struct { members: Vec<Member> },
20 Terminal { is_keyword: bool, members: Vec<Member> },
21 List { element_type: String },
22 SeparatedList { element_type: String, separator_type: String },
23 Token { is_keyword: bool },
24 Missing,
25}
26#[derive(Clone)]
27pub struct Member {
28 pub name: String,
29 pub kind: String,
30 pub key: bool,
33}
34#[derive(Clone)]
35pub struct Variant {
36 pub name: String,
37 pub kind: String,
38}
39
40pub struct StructBuilder {
44 name: String,
45 members: Vec<Member>,
46 is_terminal: bool,
47 is_keyword: bool,
48}
49impl StructBuilder {
50 pub fn new(name: &str) -> Self {
51 Self { name: name.into(), members: Vec::new(), is_terminal: false, is_keyword: false }
52 }
53 pub fn new_terminal(name: &str, is_keyword: bool) -> Self {
54 Self { name: name.into(), members: Vec::new(), is_terminal: true, is_keyword }
55 }
56 pub fn node(mut self, field: &str, kind: &str) -> StructBuilder {
57 self.members.push(Member { name: field.into(), kind: kind.into(), key: false });
58 self
59 }
60 pub fn key_node(mut self, field: &str, kind: &str) -> StructBuilder {
61 self.members.push(Member { name: field.into(), kind: kind.into(), key: true });
62 self
63 }
64 pub fn build(self) -> Node {
65 Node {
66 name: self.name,
67 kind: if self.is_terminal {
68 NodeKind::Terminal { is_keyword: self.is_keyword, members: self.members }
69 } else {
70 NodeKind::Struct { members: self.members }
71 },
72 }
73 }
74}
75pub struct EnumBuilder {
77 name: String,
78 variants: Vec<Variant>,
79 include_missing_variant: bool,
80}
81impl EnumBuilder {
82 pub fn new(name: &str) -> Self {
83 Self { name: name.into(), variants: Vec::new(), include_missing_variant: false }
84 }
85 pub fn include_missing(mut self) -> EnumBuilder {
88 self.include_missing_variant = true;
89 self
90 }
91 pub fn node(self, name: &str) -> EnumBuilder {
92 let kind_name = self.name.clone() + name;
93 self.node_with_explicit_kind(name, &kind_name)
94 }
95 pub fn node_with_explicit_kind(mut self, name: &str, kind: &str) -> EnumBuilder {
96 self.variants.push(Variant { name: name.to_string(), kind: kind.to_string() });
97 self
98 }
99 pub fn build(mut self) -> Node {
100 if self.include_missing_variant {
101 self.variants
102 .push(Variant { name: "Missing".into(), kind: self.name.clone() + "Missing" });
103 }
104 Node {
105 name: self.name,
106 kind: NodeKind::Enum {
107 variants: Variants::List(self.variants),
108 missing_variant: self.include_missing_variant,
109 },
110 }
111 }
112}
113
114#[derive(Default)]
116pub struct NodesAggregator {
117 nodes: Vec<Node>,
118}
119impl NodesAggregator {
120 pub fn get(self) -> Vec<Node> {
122 self.nodes
123 }
124
125 pub fn add_struct(mut self, builder: StructBuilder) -> Self {
127 self.nodes.push(builder.build());
128 self
129 }
130
131 pub fn add_enum(mut self, builder: EnumBuilder) -> Self {
133 if builder.include_missing_variant {
134 self.nodes
135 .push(Node { name: builder.name.clone() + "Missing", kind: NodeKind::Missing });
136 }
137 self.nodes.push(builder.build());
138 self
139 }
140
141 pub fn add_list(mut self, name: &str, element_type: &str) -> Self {
143 self.nodes.push(Node {
144 name: name.into(),
145 kind: NodeKind::List { element_type: element_type.into() },
146 });
147 self
148 }
149
150 pub fn add_separated_list(
152 mut self,
153 name: &str,
154 element_type: &str,
155 separator_type: &str,
156 ) -> Self {
157 self.nodes.push(Node {
158 name: name.into(),
159 kind: NodeKind::SeparatedList {
160 element_type: element_type.into(),
161 separator_type: separator_type.into(),
162 },
163 });
164 self
165 }
166
167 pub fn add_token(mut self, pure_name: &str) -> Self {
169 self.nodes.push(Node {
170 name: format!("Token{pure_name}"),
171 kind: NodeKind::Token { is_keyword: false },
172 });
173 self
174 }
175
176 pub fn add_keyword_token(mut self, pure_name: &str) -> Self {
178 self.nodes.push(Node {
179 name: format!("Token{pure_name}"),
180 kind: NodeKind::Token { is_keyword: true },
181 });
182 self
183 }
184
185 pub fn add_terminal(self, pure_name: &str, is_keyword: bool) -> Self {
187 self.add_struct(
188 StructBuilder::new_terminal(format!("Terminal{pure_name}").as_str(), is_keyword)
189 .node("leading_trivia", "Trivia")
190 .node("token", format!("Token{pure_name}").as_str())
191 .node("trailing_trivia", "Trivia"),
192 )
193 }
194
195 pub fn add_keyword_token_and_terminal(self, pure_name: &str) -> Self {
198 self.add_keyword_token(pure_name).add_terminal(pure_name, true)
199 }
200
201 pub fn add_token_and_terminal(self, pure_name: &str) -> Self {
204 self.add_token(pure_name).add_terminal(pure_name, false)
205 }
206
207 pub fn add_option(self, name: &str) -> Self {
215 self.add_enum(
216 EnumBuilder::new(format!("Option{name}").as_str())
217 .node("Empty")
218 .node_with_explicit_kind(name, name),
219 )
220 .add_struct(StructBuilder::new(format!("Option{name}Empty").as_str()))
221 }
222
223 pub fn add_all_tokens_enum(mut self, name: &str) -> Self {
225 self.nodes.push(Node {
226 name: name.into(),
227 kind: NodeKind::Enum { variants: Variants::AllTokens, missing_variant: false },
228 });
229 self
230 }
231}