1mod element_node;
14mod for_node;
15mod if_node;
16mod match_node;
17
18pub use element_node::ElementNode;
19pub use for_node::ForNode;
20pub use if_node::IfNode;
21pub use match_node::MatchNode;
22
23use proc_macro2::Ident;
24use proc_macro2::Span;
25use proc_macro2::TokenStream;
26
27use syn::Token;
28use syn::ext::IdentExt;
29use syn::parse::Parse;
30use syn::parse::ParseStream;
31
32use crate::Expand;
33
34pub enum AtNode {
38 If(IfNode),
40 For(ForNode),
42 Match(MatchNode),
44 Element(ElementNode),
46}
47
48impl AtNode {
49 pub fn is_if(&self) -> bool {
51 matches!(self, Self::If(_))
52 }
53
54 pub fn is_for(&self) -> bool {
56 matches!(self, Self::For(_))
57 }
58
59 pub fn is_match(&self) -> bool {
61 matches!(self, Self::Match(_))
62 }
63
64 pub fn is_element(&self) -> bool {
66 matches!(self, Self::Element(_))
67 }
68}
69
70impl AtNode {
71 pub fn as_if(&self) -> &IfNode {
73 match self {
74 Self::If(v) => v,
75 _ => panic!("called as_if on non-If node"),
76 }
77 }
78
79 pub fn as_for(&self) -> &ForNode {
81 match self {
82 Self::For(v) => v,
83 _ => panic!("called as_for on non-For node"),
84 }
85 }
86
87 pub fn as_match(&self) -> &MatchNode {
89 match self {
90 Self::Match(v) => v,
91 _ => panic!("called as_match on non-Match node"),
92 }
93 }
94
95 pub fn as_element(&self) -> &ElementNode {
97 match self {
98 Self::Element(v) => v,
99 _ => panic!("called as_element on non-Element node"),
100 }
101 }
102}
103
104impl AtNode {
105 pub fn span(&self) -> Span {
107 match self {
108 Self::If(v) => v.span(),
109 Self::For(v) => v.span(),
110 Self::Match(v) => v.span(),
111 Self::Element(v) => v.span(),
112 }
113 }
114}
115
116impl From<IfNode> for AtNode {
117 fn from(v: IfNode) -> Self {
118 Self::If(v)
119 }
120}
121
122impl From<ForNode> for AtNode {
123 fn from(v: ForNode) -> Self {
124 Self::For(v)
125 }
126}
127
128impl From<MatchNode> for AtNode {
129 fn from(v: MatchNode) -> Self {
130 Self::Match(v)
131 }
132}
133
134impl From<ElementNode> for AtNode {
135 fn from(v: ElementNode) -> Self {
136 Self::Element(v)
137 }
138}
139
140impl Expand for AtNode {
141 fn expand(&self, output: &Ident, idents: &mut crate::ident::Iter) -> TokenStream {
142 match self {
143 Self::If(v) => v.expand(output, idents),
144 Self::For(v) => v.expand(output, idents),
145 Self::Match(v) => v.expand(output, idents),
146 Self::Element(v) => v.expand(output, idents),
147 }
148 }
149}
150
151impl Parse for AtNode {
152 fn parse(input: ParseStream) -> syn::Result<Self> {
153 let at_span = input.parse::<Token![@]>()?.span;
154 let ident: syn::Ident = input.call(syn::Ident::parse_any)?;
155 let name = ident.to_string();
156
157 match name.as_str() {
158 "if" => {
159 let mut v = input.parse::<IfNode>()?;
160 v.span = at_span;
161 Ok(v.into())
162 }
163 "for" => {
164 let mut v = input.parse::<ForNode>()?;
165 v.span = at_span;
166 Ok(v.into())
167 }
168 "match" => {
169 let mut v = input.parse::<MatchNode>()?;
170 v.span = at_span;
171 Ok(v.into())
172 }
173 "else" => Err(syn::Error::new(at_span, "unexpected @else without @if")),
174 _ => {
175 let mut v = ElementNode::parse_with_ident(input, ident)?;
176 v.span = at_span;
177 Ok(v.into())
178 }
179 }
180 }
181}