1#![recursion_limit = "128"]
2
3use proc_macro2::{Span, TokenStream};
4use rustc_hash::FxHashMap;
5
6pub mod css_token;
8use css_token::*;
9pub mod module;
10pub mod pseudo;
11pub mod style_sheet;
12pub mod write_css;
13
14#[derive(Debug, Clone)]
15pub struct ParseError {
16 err: syn::Error,
17}
18
19impl ParseError {
20 pub fn new(span: Span, message: impl ToString) -> Self {
21 Self {
22 err: syn::Error::new(span, message.to_string()),
23 }
24 }
25
26 pub fn into_syn_error(self) -> syn::Error {
27 self.err
28 }
29}
30
31impl std::fmt::Display for ParseError {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 f.write_str(&self.err.to_string())
34 }
35}
36
37impl From<syn::Error> for ParseError {
38 fn from(err: syn::Error) -> Self {
39 Self { err }
40 }
41}
42
43pub trait ParseWithVars: Sized {
44 fn parse_with_vars(
45 input: syn::parse::ParseStream,
46 scope: &mut ScopeVars,
47 ) -> Result<Self, syn::Error>;
48}
49
50#[derive(Debug)]
51pub struct ScopeVars {
52 cur_mod: Option<ModPath>,
53 vars: FxHashMap<String, ScopeVarValue>,
54 var_refs: Vec<VarRef>,
55}
56
57impl ScopeVars {
58 fn insert_var(&mut self, var_name: &VarName, value: ScopeVarValue) -> Result<(), syn::Error> {
59 let mut inserted = false;
60 let span = var_name.span();
61 self.vars.entry(var_name.to_string()).or_insert_with(|| {
62 inserted = true;
63 value
64 });
65 if inserted {
66 Ok(())
67 } else {
68 Err(syn::Error::new(span, "duplicated identifier"))
69 }
70 }
71}
72
73#[derive(Debug, Clone)]
74pub enum ScopeVarValue {
75 Token(CssToken),
76 DynStr(VarDynRef),
77 DynNum(VarDynRef),
78 StyleDefinition(Vec<(VarName, ArgType)>),
79}
80
81impl ScopeVarValue {
82 fn type_name(&self) -> &'static str {
83 match self {
84 Self::Token(_) => "value",
85 Self::DynStr(_) => "&str",
86 Self::DynNum(_) => "{number}",
87 Self::StyleDefinition(_) => "StyleDefinition",
88 }
89 }
90}
91
92#[derive(Debug, Clone, Copy)]
93pub enum ArgType {
94 Str(Span),
95 Num(Span),
96}
97
98impl ArgType {
99 pub fn type_tokens(self) -> TokenStream {
100 match self {
101 Self::Str(span) => quote::quote_spanned!(span=> &str ),
102 Self::Num(span) => quote::quote_spanned!(span=> f32 ),
103 }
104 }
105}
106
107#[derive(Debug, Clone)]
108pub struct VarDynRef {
109 pub span: Span,
110 pub index: usize,
111}
112
113impl PartialEq for VarDynRef {
114 fn eq(&self, other: &Self) -> bool {
115 self.index == other.index
116 }
117}
118
119#[derive(Debug, Clone)]
120pub struct VarDynValue {
121 pub span: Span,
122 pub kind: VarDynValueKind,
123}
124
125#[derive(Debug, Clone)]
126pub enum VarDynValueKind {
127 Placeholder,
128 Str(String),
129 Num(Number),
130}
131
132impl VarDynValue {
133 pub fn placeholder(span: Span) -> Self {
134 Self {
135 span,
136 kind: VarDynValueKind::Placeholder,
137 }
138 }
139
140 fn type_name(&self) -> &'static str {
141 match &self.kind {
142 VarDynValueKind::Placeholder => "{unknown}",
143 VarDynValueKind::Str(_) => "&str",
144 VarDynValueKind::Num(_) => "{number}",
145 }
146 }
147}
148
149#[derive(Debug, Clone, PartialEq)]
150pub enum MaybeDyn<T> {
151 Static(T),
152 Dyn(VarDynRef),
153}
154
155impl ParseWithVars for MaybeDyn<String> {
156 fn parse_with_vars(
157 input: syn::parse::ParseStream,
158 scope: &mut ScopeVars,
159 ) -> Result<Self, syn::Error> {
160 use syn::*;
161 let la = input.lookahead1();
162 let value = if la.peek(LitStr) {
163 let s: LitStr = input.parse()?;
164 MaybeDyn::Static(s.value())
165 } else if la.peek(Ident) {
166 let var_name: VarName = input.parse()?;
167 if let Some(v) = scope.vars.get(&var_name.to_string()) {
168 match v {
169 ScopeVarValue::DynStr(x) => {
170 scope.var_refs.push(var_name.into_ref());
171 MaybeDyn::Dyn(x.clone())
172 }
173 x => {
174 return Err(syn::Error::new(
175 var_name.span(),
176 format!("expected &str, found {}", x.type_name()),
177 ));
178 }
179 }
180 } else {
181 return Err(syn::Error::new(var_name.span(), "variable not declared"));
182 }
183 } else {
184 return Err(la.error());
185 };
186 Ok(value)
187 }
188}
189
190impl MaybeDyn<String> {
191 fn value<'a>(&'a self, values: &'a [VarDynValue]) -> Result<&'a str, syn::Error> {
192 match self {
193 Self::Static(x) => Ok(x),
194 Self::Dyn(x) => {
195 let v = values.get(x.index).unwrap();
196 match &v.kind {
197 VarDynValueKind::Str(x) => Ok(x),
198 _ => Err(syn::Error::new(
199 x.span,
200 format!("expected &str, found {}", v.type_name()),
201 )),
202 }
203 }
204 }
205 }
206}
207
208impl ParseWithVars for MaybeDyn<Number> {
209 fn parse_with_vars(
210 input: syn::parse::ParseStream,
211 scope: &mut ScopeVars,
212 ) -> Result<Self, syn::Error> {
213 use syn::*;
214 let la = input.lookahead1();
215 let value = if la.peek(LitInt) {
216 let v: LitInt = input.parse()?;
217 let value = v.base10_parse()?;
218 MaybeDyn::Static(Number::I32(value))
219 } else if la.peek(LitFloat) {
220 let v: LitFloat = input.parse()?;
221 let value = v.base10_parse()?;
222 MaybeDyn::Static(Number::F32(value))
223 } else if la.peek(Ident) {
224 let var_name: VarName = input.parse()?;
225 if let Some(v) = scope.vars.get(&var_name.to_string()) {
226 match v {
227 ScopeVarValue::DynNum(x) => {
228 scope.var_refs.push(var_name.into_ref());
229 MaybeDyn::Dyn(x.clone())
230 }
231 x => {
232 return Err(syn::Error::new(
233 var_name.span(),
234 format!("expected i32 or f32, found {}", x.type_name()),
235 ));
236 }
237 }
238 } else {
239 return Err(syn::Error::new(var_name.span(), "variable not declared"));
240 }
241 } else {
242 return Err(la.error());
243 };
244 Ok(value)
245 }
246}
247
248impl MaybeDyn<Number> {
249 fn value(&self, values: &[VarDynValue]) -> Result<Number, syn::Error> {
250 match self {
251 Self::Static(x) => Ok(x.clone()),
252 Self::Dyn(x) => {
253 let v = values.get(x.index).unwrap();
254 match &v.kind {
255 VarDynValueKind::Num(x) => Ok(x.clone()),
256 _ => Err(syn::Error::new(
257 x.span,
258 format!("expected {{number}}, found {}", v.type_name()),
259 )),
260 }
261 }
262 }
263 }
264}
265
266#[derive(Debug, Clone, PartialEq)]
267pub enum Number {
268 I32(i32),
269 F32(f32),
270}
271
272#[derive(Debug, Clone, Default)]
273pub struct ModPath {
274 segs: Vec<syn::Ident>,
275}
276
277impl ModPath {
278 fn visible_in(&self, src: &Self) -> bool {
279 for (index, seg) in self.segs.iter().enumerate() {
280 if Some(seg) != src.segs.get(index) {
281 return false;
282 }
283 }
284 true
285 }
286}