1use syn::{parse::Parse, Token};
3
4#[derive(Debug)]
12pub struct PropertyValue {
13 pub name: syn::Ident,
15 #[allow(missing_docs)]
16 pub colon_token: Token![:],
17 pub expr: syn::Expr,
19}
20
21#[derive(Debug)]
29pub struct TransitionDefinition {
30 pub source_state: syn::Ident,
32 #[allow(missing_docs)]
33 pub arrow_token: Token![=>],
34 pub destination_state: syn::Ident,
36 pub action: syn::Block,
38}
39
40impl Parse for TransitionDefinition {
41 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
42 let source_state: syn::Ident = input.parse()?;
43 let arrow_token: Token![=>] = input.parse()?;
44 let destination_state: syn::Ident = input.parse()?;
45 let action: syn::Block = input.parse()?;
46 Ok(TransitionDefinition {
47 source_state,
48 arrow_token,
49 destination_state,
50 action,
51 })
52 }
53}
54
55#[derive(Debug)]
65pub struct OnValue {
66 #[allow(missing_docs)]
67 pub on_keyword: syn::Ident,
68 pub name: syn::Ident,
70 #[allow(missing_docs)]
71 pub colon_token: Token![:],
72 pub transition_definitions: syn::punctuated::Punctuated<TransitionDefinition, Token![,]>,
74}
75
76#[derive(Debug)]
78enum ComponentContent {
79 Id(syn::Ident),
80 Property(PropertyValue),
81 Child(ComponentInput),
82 On(OnValue),
83}
84
85#[derive(Debug)]
101pub struct ComponentInput {
102 pub name: syn::Ident,
104 #[allow(missing_docs)]
105 pub brace_token: syn::token::Brace,
106 pub id: Option<syn::Ident>,
108 pub properties: Vec<PropertyValue>,
110 pub children: Vec<ComponentInput>,
112 pub on_expressions: Vec<OnValue>,
114 pub visibility: syn::Visibility,
116}
117
118impl Parse for ComponentContent {
119 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
120 if input.cursor().ident().map_or(false, |(i, _)| i == "on") && !input.peek2(Token![:]) {
121 let on_keyword: syn::Ident = input.parse()?;
122 let name: syn::Ident = input.parse()?;
123 let colon_token: Token![:] = input.parse()?;
124 let transition_definitions = if input.peek(syn::token::Bracket) {
125 let unparsed_content;
126 let _ = syn::bracketed!(unparsed_content in input);
127 unparsed_content.parse_terminated(TransitionDefinition::parse, Token![,])?
128 } else {
129 let mut p = syn::punctuated::Punctuated::<TransitionDefinition, Token![,]>::new();
130 p.push(TransitionDefinition::parse(input)?);
131 p
132 };
133
134 let on = OnValue {
135 on_keyword,
136 name,
137 colon_token,
138 transition_definitions,
139 };
140 Ok(ComponentContent::On(on))
141 } else if input.peek2(Token![:]) {
142 let lookahead1 = input.lookahead1();
143 if lookahead1.peek(syn::Ident) {
144 let name: syn::Ident = input.parse()?;
145 if name == "id" {
146 let _: Token![:] = input.parse()?;
147 let id: syn::Ident = input.parse()?;
148 Ok(ComponentContent::Id(id))
149 } else {
150 let colon_token: Token![:] = input.parse()?;
151 let expr: syn::Expr = input.parse()?;
152 Ok(ComponentContent::Property(PropertyValue {
153 name,
154 colon_token,
155 expr,
156 }))
157 }
158 } else {
159 Err(lookahead1.error())
160 }
161 } else {
162 Ok(Self::Child(ComponentInput::parse(input)?))
163 }
164 }
165}
166
167impl syn::parse::Parse for ComponentInput {
168 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
169 let visibility: syn::Visibility = input.parse()?;
170
171 let name = input.parse::<syn::Ident>()?;
172
173 let unparsed_content;
174 let brace_token = syn::braced!(unparsed_content in input);
175 let content = unparsed_content.parse_terminated(ComponentContent::parse, Token![,])?;
176
177 let mut id = Default::default();
178 let mut properties: Vec<PropertyValue> = Default::default();
179 let mut children: Vec<ComponentInput> = Default::default();
180 let mut on_expressions: Vec<OnValue> = Default::default();
181
182 for item in content {
183 match item {
184 ComponentContent::Id(idid) => id = Some(idid),
185 ComponentContent::Property(prop) => {
186 properties.push(prop);
187 }
188 ComponentContent::Child(child) => {
189 children.push(child);
190 }
191 ComponentContent::On(on_expr) => {
192 on_expressions.push(on_expr);
193 }
194 }
195 }
196
197 Ok(Self {
198 name,
199 brace_token,
200 id,
201 properties,
202 children,
203 on_expressions,
204 visibility,
205 })
206 }
207}