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