sycamore_view_parser/
parse.rs1use syn::ext::IdentExt;
4use syn::parse::{Parse, ParseStream};
5use syn::token::{Brace, Paren};
6use syn::{braced, parenthesized, token, Ident, LitStr, Result, Token};
7
8use crate::ir::*;
9
10impl Parse for Root {
11 fn parse(input: ParseStream) -> Result<Self> {
12 let mut children = Vec::new();
13
14 while !input.is_empty() {
15 children.push(input.parse()?);
16 }
17
18 Ok(Self(children))
19 }
20}
21
22impl Node {
23 fn peek_type(input: ParseStream) -> Option<NodeType> {
24 let input = input.fork(); if input.peek(LitStr) {
27 Some(NodeType::Text)
28 } else if input.peek(Paren) {
29 Some(NodeType::Dyn)
30 } else if input.peek(Token![::]) || input.peek(Ident::peek_any) {
31 Some(NodeType::Tag)
32 } else {
33 None
34 }
35 }
36}
37
38impl Parse for Node {
39 fn parse(input: ParseStream) -> Result<Self> {
40 let ty = match Self::peek_type(input) {
41 Some(ty) => ty,
42 None => return Err(input.error("expected a valid node")),
43 };
44
45 Ok(match ty {
46 NodeType::Tag => Self::Tag(input.parse()?),
47 NodeType::Text => Self::Text(input.parse()?),
48 NodeType::Dyn => Self::Dyn(input.parse()?),
49 })
50 }
51}
52
53impl Parse for TagNode {
54 fn parse(input: ParseStream) -> Result<Self> {
55 let ident = input.parse()?;
56
57 let has_paren = input.peek(token::Paren);
58 let attrs = if has_paren {
59 let content;
60 parenthesized!(content in input);
61 content
62 .parse_terminated(Prop::parse, Token![,])?
63 .into_iter()
64 .collect()
65 } else {
66 Vec::new()
67 };
68
69 if !has_paren && !input.peek(Brace) {
70 return Err(input.error("expected either `(` or `{` after element tag"));
71 }
72
73 let mut children = Vec::new();
74 if input.peek(Brace) {
75 let content;
76 braced!(content in input);
77 while !content.is_empty() {
78 children.push(content.parse()?);
79 }
80 }
81
82 Ok(Self {
83 ident,
84 props: attrs,
85 children: Root(children),
86 })
87 }
88}
89
90impl Parse for TagIdent {
91 fn parse(input: ParseStream) -> Result<Self> {
92 let is_hyphenated = input.peek2(Token![-]);
93 if is_hyphenated {
94 let mut segments: Vec<Ident> = vec![input.call(Ident::parse_any)?];
95 while input.peek(Token![-]) {
96 let _: Token![-] = input.parse()?;
97 segments.push(input.parse()?);
98 }
99 let tag = segments
100 .into_iter()
101 .map(|i| i.to_string())
102 .collect::<Vec<_>>()
103 .join("-");
104 Ok(Self::Hyphenated(tag))
105 } else {
106 Ok(Self::Path(input.parse()?))
107 }
108 }
109}
110
111impl Parse for Prop {
112 fn parse(input: ParseStream) -> Result<Self> {
113 let span = input.span();
114 let ty = input.parse()?;
115 if !matches!(ty, PropType::Spread) {
116 let _eqs: Token![=] = input.parse()?;
117 }
118 let value = input.parse()?;
119 Ok(Self { ty, value, span })
120 }
121}
122
123impl Parse for PropType {
124 fn parse(input: ParseStream) -> Result<Self> {
125 let lookahead = input.lookahead1();
126 if lookahead.peek(Token![..]) {
127 let _2dot = input.parse::<Token![..]>()?;
128 Ok(Self::Spread)
129 } else if lookahead.peek(Ident::peek_any) {
130 if input.peek2(Token![-]) {
132 let mut segments: Vec<Ident> = vec![input.call(Ident::parse_any)?];
133 while input.peek(Token![-]) {
134 let _: Token![-] = input.parse()?;
135 segments.push(input.call(Ident::parse_any)?);
136 }
137 let ident = segments
138 .into_iter()
139 .map(|i| i.to_string())
140 .collect::<Vec<_>>()
141 .join("-");
142 Ok(Self::PlainHyphenated { ident })
143 } else {
144 let name: Ident = input.call(Ident::parse_any)?;
145
146 if name == "ref" {
147 Ok(Self::Ref)
148 } else if input.peek(Token![:]) {
149 let _colon: Token![:] = input.parse()?;
150 let ident = input.call(Ident::parse_any)?;
151 Ok(Self::Directive { dir: name, ident })
152 } else {
153 Ok(Self::Plain { ident: name })
154 }
155 }
156 } else if lookahead.peek(LitStr) {
157 let name: String = <LitStr as Parse>::parse(input).map(|s| s.value())?;
158 Ok(Self::PlainQuoted { ident: name })
159 } else {
160 Err(lookahead.error())
161 }
162 }
163}
164
165impl Parse for TextNode {
166 fn parse(input: ParseStream) -> Result<Self> {
167 Ok(Self {
168 value: input.parse()?,
169 })
170 }
171}
172
173impl Parse for DynNode {
174 fn parse(input: ParseStream) -> Result<Self> {
175 let content;
176 parenthesized!(content in input);
177 Ok(Self {
178 value: content.parse()?,
179 })
180 }
181}