1use std::rc::Rc;
7use syn::{
8 ext::IdentExt as _,
9 parse::{Parse, ParseStream},
10 *,
11};
12
13pub enum StmtSyn {
15 Layout(LayoutTempl),
19 Use(UseTempl),
21 Render(RenderTempl),
23 Yield(YieldTempl),
25
26 Block(BlockTempl),
30 If(IfTempl),
32 Else(ElseTempl),
34 For(ForTempl),
36 Endblock(kw::endblock),
38 EndIf(kw::endif),
40 EndFor(kw::endfor),
42
43 Item(Rc<ItemTempl>),
47 Expr(Rc<Expr>),
49}
50
51pub struct LayoutTempl {
53 pub layout_token: kw::layout,
54 pub path: LitStr,
55}
56
57pub struct UseTempl {
59 pub use_token: Token![use],
60 pub path: LitStr,
61 pub as_token: Token![as],
62 pub ident: Ident,
63}
64
65pub struct RenderTempl {
67 pub render_token: kw::render,
68 pub value: RenderValue,
69 pub block: Option<(kw::block,Ident)>
70}
71
72pub enum RenderValue {
74 Ident(Ident),
75 Path(LitStr),
76}
77
78pub struct YieldTempl {
80 pub yield_token: Token![yield],
81 pub block: Option<(kw::block, Ident)>
82}
83
84pub struct BlockTempl {
86 pub pub_token: Option<Token![pub]>,
87 pub static_token: Option<Token![static]>,
88 pub block_token: kw::block,
89 pub name: Ident,
90}
91
92pub struct IfTempl {
94 pub if_token: Token![if],
95 pub cond: Rc<Expr>,
96}
97
98pub struct ElseTempl {
100 pub else_token: Token![else],
101 pub elif_branch: Option<(Token![if],Rc<Expr>)>
102}
103
104pub struct ForTempl {
106 pub for_token: Token![for],
107 pub pat: Rc<Pat>,
108 pub in_token: Token![in],
109 pub expr: Rc<Expr>,
110}
111
112pub enum ItemTempl {
114 Use(ItemUse),
115 Const(ItemConst),
116}
117
118impl Parse for StmtSyn {
121 fn parse(input: ParseStream) -> Result<Self> {
122 match () {
123 _ if input.peek(kw::layout) => input.parse().map(Self::Layout),
124 _ if input.peek(kw::extends) => input.parse().map(Self::Layout),
125 _ if UseTempl::peek(input) => input.parse().map(Self::Use),
126 _ if input.peek(kw::render) => input.parse().map(Self::Render),
127 _ if input.peek(Token![yield]) => input.parse().map(Self::Yield),
128
129 _ if BlockTempl::peek(input) => input.parse().map(Self::Block),
130 _ if input.peek(Token![if]) => input.parse().map(Self::If),
131 _ if input.peek(Token![else]) => input.parse().map(Self::Else),
132 _ if input.peek(Token![for]) => input.parse().map(Self::For),
133 _ if input.peek(kw::endblock) => input.parse().map(Self::Endblock),
134 _ if input.peek(kw::endif) => input.parse().map(Self::EndIf),
135 _ if input.peek(kw::endfor) => input.parse().map(Self::EndFor),
136
137 _ if ItemTempl::peek(input) => input.parse().map(Rc::new).map(Self::Item),
138 _ => input.parse().map(Rc::new).map(Self::Expr),
139 }
140 }
141}
142
143impl UseTempl {
144 pub fn peek(input: ParseStream) -> bool {
145 input.peek(Token![use]) && input.peek2(LitStr)
146 }
147}
148
149impl BlockTempl {
150 pub fn peek(input: ParseStream) -> bool {
151 (input.peek(Token![pub]) && input.peek2(Token![static]) && input.peek3(kw::block)) ||
152 (input.peek(Token![pub]) && input.peek2(kw::block)) ||
153 (input.peek(Token![static]) && input.peek2(kw::block)) ||
154 input.peek(kw::block)
155 }
156}
157
158impl ItemTempl {
159 pub fn peek(input: ParseStream) -> bool {
160 input.peek(Token![use]) ||
161 input.peek(Token![const])
162 }
163}
164
165impl Parse for LayoutTempl {
166 fn parse(input: ParseStream) -> Result<Self> {
167 Ok(Self {
168 layout_token: match () {
169 _ if input.peek(kw::layout) => input.parse()?,
170 _ if input.peek(kw::extends) => kw::layout(input.parse::<kw::extends>()?.span),
171 _ => unreachable!()
172 },
173 path: input.parse()?,
174 })
175 }
176}
177
178impl Parse for UseTempl {
179 fn parse(input: ParseStream) -> Result<Self> {
180 Ok(Self {
181 use_token: input.parse()?,
182 path: input.parse()?,
183 as_token: input.parse()?,
184 ident: input.call(Ident::parse_any)?,
185 })
186 }
187}
188
189impl Parse for RenderTempl {
190 fn parse(input: ParseStream) -> Result<Self> {
191 Ok(Self {
192 render_token: input.parse()?,
193 value: input.parse()?,
194 block: if input.peek(kw::block) {
195 Some((input.parse()?,input.call(Ident::parse_any)?))
196 } else {
197 None
198 },
199 })
200 }
201}
202
203impl Parse for RenderValue {
204 fn parse(input: ParseStream) -> Result<Self> {
205 let look = input.lookahead1();
206 match () {
207 _ if look.peek(LitStr) => input.parse().map(Self::Path),
208 _ if look.peek(Ident::peek_any) => input.call(Ident::parse_any).map(Self::Ident),
209 _ => Err(look.error()),
210 }
211 }
212}
213
214impl Parse for YieldTempl {
215 fn parse(input: ParseStream) -> Result<Self> {
216 Ok(Self {
217 yield_token: input.parse()?,
218 block: if input.peek(kw::block) {
219 Some((input.parse()?,input.call(Ident::parse_any)?))
220 } else {
221 None
222 },
223 })
224 }
225}
226
227impl Parse for BlockTempl {
228 fn parse(input: ParseStream) -> Result<Self> {
229 Ok(Self {
230 pub_token: input.parse()?,
231 static_token: input.parse()?,
232 block_token: input.parse()?,
233 name: input.call(Ident::parse_any)?,
234 })
235 }
236}
237
238impl Parse for IfTempl {
239 fn parse(input: ParseStream) -> Result<Self> {
240 Ok(Self {
241 if_token: input.parse()?,
242 cond: Rc::new(input.parse()?),
243 })
244 }
245}
246
247impl Parse for ElseTempl {
248 fn parse(input: ParseStream) -> Result<Self> {
249 Ok(Self {
250 else_token: input.parse()?,
251 elif_branch: if input.peek(Token![if]) {
252 Some((input.parse()?,Rc::new(input.parse()?)))
253 } else {
254 None
255 },
256 })
257 }
258}
259
260impl Parse for ForTempl {
261 fn parse(input: ParseStream) -> Result<Self> {
262 Ok(Self {
263 for_token: input.parse()?,
264 pat: Rc::new(Pat::parse_multi_with_leading_vert(input)?),
266 in_token: input.parse()?,
267 expr: Rc::new(input.parse()?),
268 })
269 }
270}
271
272impl Parse for ItemTempl {
273 fn parse(input: ParseStream) -> Result<Self> {
274 let look = input.lookahead1();
275 match () {
276 _ if look.peek(Token![use]) => input.parse().map(Self::Use),
277 _ if look.peek(Token![const]) => input.parse().map(Self::Const),
278 _ => Err(look.error()),
279 }
280 }
281}
282
283mod kw {
284 syn::custom_keyword!(layout);
285 syn::custom_keyword!(extends);
286 syn::custom_keyword!(block);
287 syn::custom_keyword!(render);
288 syn::custom_keyword!(endblock);
289 syn::custom_keyword!(endif);
290 syn::custom_keyword!(endfor);
291}
292