1use std::fmt;
2use std::fmt::Write;
3
4use crate::TmplError;
5
6mod expr;
7mod tag;
8
9const VAR_NAME_CHARS: [char; 63] = [
10 '_', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
11 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a',
12 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
13 'u', 'v', 'w', 'x', 'y', 'z',
14];
15const VAR_NAME_START_CHARS: [char; 52] = [
16 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
17 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
18 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
19];
20const VAR_NAME_INDEX_PRESERVE: usize = 26; #[derive(Debug, Clone)]
23pub(crate) struct JsIdent {
24 name: String,
25}
26
27impl JsIdent {
28 fn new(name: String) -> Self {
29 Self { name }
30 }
31}
32
33impl fmt::Display for JsIdent {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 write!(f, "{}", self.name)
36 }
37}
38
39#[derive(Clone)]
40struct JsBlockStat {
41 need_stat_sep: bool,
42 ident_id_inc: usize,
43 private_ident_id_inc: usize,
44}
45
46impl JsBlockStat {
47 fn new() -> Self {
48 Self {
49 need_stat_sep: false,
50 ident_id_inc: VAR_NAME_INDEX_PRESERVE,
51 private_ident_id_inc: 0,
52 }
53 }
54
55 fn extend(&self) -> Self {
56 Self {
57 need_stat_sep: false,
58 ident_id_inc: self.ident_id_inc,
59 private_ident_id_inc: self.private_ident_id_inc,
60 }
61 }
62
63 fn align(&mut self, extended: &Self) {
64 self.ident_id_inc = extended.ident_id_inc;
65 self.private_ident_id_inc = extended.private_ident_id_inc;
66 }
67}
68
69pub(crate) struct JsTopScopeWriter<W: fmt::Write> {
70 w: W,
71 top_declares: Vec<String>,
72 sub_strs: Vec<String>,
73 block: JsBlockStat,
74}
75
76impl<'a, W: fmt::Write> JsTopScopeWriter<W> {
77 pub(crate) fn new(w: W) -> Self {
78 Self {
79 w,
80 top_declares: vec![],
81 sub_strs: vec![],
82 block: JsBlockStat::new(),
83 }
84 }
85
86 pub(crate) fn align<WW: fmt::Write>(&mut self, w: &JsFunctionScopeWriter<'a, WW>) {
87 self.block.align(w.get_block());
88 }
89
90 pub(crate) fn finish(self) -> W {
91 let mut w = self.w;
92 let mut first = true;
93 if self.top_declares.len() > 0 {
94 write!(w, "var ").unwrap();
95 for (index, top_declare) in self.top_declares.iter().enumerate() {
96 if index > 0 {
97 write!(w, ",").unwrap();
98 }
99 write!(w, "{}", top_declare).unwrap();
100 }
101 first = false;
102 }
103 for sub_str in self.sub_strs.iter() {
104 if first {
105 first = false
106 } else {
107 write!(w, ";").unwrap();
108 }
109 write!(w, "{}", sub_str).unwrap();
110 }
111 w
112 }
113
114 pub(crate) fn function_scope<R>(
115 &mut self,
116 f: impl FnOnce(&mut JsFunctionScopeWriter<W>) -> Result<R, TmplError>,
117 ) -> Result<R, TmplError> {
118 let mut sub_str = String::new();
119 let need_stat_sep = self.block.need_stat_sep;
120 self.block.need_stat_sep = false;
121 let ret = f(&mut JsFunctionScopeWriter {
122 w: &mut sub_str,
123 block: None,
124 top_scope: self,
125 });
126 self.sub_strs.push(sub_str);
127 self.block.need_stat_sep = need_stat_sep;
128 ret
129 }
130
131 pub(crate) fn expr_scope<R>(
132 &mut self,
133 f: impl FnOnce(&mut JsExprWriter<W>) -> Result<R, TmplError>,
134 ) -> Result<R, TmplError> {
135 self.function_scope(|w| w.expr_stmt(f))
136 }
137
138 pub(crate) fn declare_on_top(&mut self, name: &str) -> Result<(), TmplError> {
139 let mut sub_str = String::new();
140 let need_stat_sep = self.block.need_stat_sep;
141 self.block.need_stat_sep = false;
142 write!(sub_str, "{}", name).unwrap();
143 self.top_declares.push(sub_str);
144 self.block.need_stat_sep = need_stat_sep;
145 Ok(())
146 }
147
148 pub(crate) fn declare_on_top_init<R>(
149 &mut self,
150 name: &str,
151 init: impl FnOnce(&mut JsExprWriter<W>) -> Result<R, TmplError>,
152 ) -> Result<R, TmplError> {
153 let mut sub_str = String::new();
154 let need_stat_sep = self.block.need_stat_sep;
155 self.block.need_stat_sep = false;
156 write!(sub_str, "{}=", name).unwrap();
157 let ret = init(&mut JsExprWriter {
158 w: &mut sub_str,
159 block: None,
160 top_scope: self,
161 });
162 self.top_declares.push(sub_str);
163 self.block.need_stat_sep = need_stat_sep;
164 ret
165 }
166}
167
168pub(crate) struct JsFunctionArgsAssigner<'a, W: fmt::Write> {
169 block: Option<&'a mut JsBlockStat>,
170 top_scope: &'a mut JsTopScopeWriter<W>,
171}
172
173impl<'a, W: fmt::Write> JsFunctionArgsAssigner<'a, W> {
174 fn get_block_mut(&mut self) -> &mut JsBlockStat {
175 if self.block.is_some() {
176 self.block.as_mut().unwrap()
177 } else {
178 &mut self.top_scope.block
179 }
180 }
181
182 pub(crate) fn gen_ident(&mut self) -> JsIdent {
183 let block = self.get_block_mut();
184 let var_id = block.ident_id_inc;
185 block.ident_id_inc += 1;
186 JsIdent {
187 name: get_var_name(var_id),
188 }
189 }
190}
191
192pub(crate) struct JsFunctionScopeWriter<'a, W: fmt::Write> {
193 w: &'a mut String,
194 block: Option<&'a mut JsBlockStat>,
195 top_scope: &'a mut JsTopScopeWriter<W>,
196}
197
198fn get_var_name(mut var_id: usize) -> String {
199 let mut var_name = String::new();
200 var_name.push(VAR_NAME_START_CHARS[var_id % VAR_NAME_START_CHARS.len()]);
201 var_id /= VAR_NAME_START_CHARS.len();
202 while var_id > 0 {
203 var_name.push(VAR_NAME_CHARS[var_id % VAR_NAME_CHARS.len()]);
204 var_id /= VAR_NAME_CHARS.len();
205 }
206 var_name
207}
208
209impl<'a, W: fmt::Write> JsFunctionScopeWriter<'a, W> {
210 fn get_block(&self) -> &JsBlockStat {
211 if self.block.is_some() {
212 self.block.as_ref().unwrap()
213 } else {
214 &self.top_scope.block
215 }
216 }
217
218 fn get_block_mut(&mut self) -> &mut JsBlockStat {
219 if self.block.is_some() {
220 self.block.as_mut().unwrap()
221 } else {
222 &mut self.top_scope.block
223 }
224 }
225
226 pub(crate) fn gen_ident(&mut self) -> JsIdent {
227 let block = self.get_block_mut();
228 let var_id = block.ident_id_inc;
229 block.ident_id_inc += 1;
230 JsIdent {
231 name: get_var_name(var_id),
232 }
233 }
234
235 pub(crate) fn gen_private_ident(&mut self) -> JsIdent {
236 let block = self.get_block_mut();
237 let var_id = block.private_ident_id_inc;
238 block.private_ident_id_inc += 1;
239 JsIdent {
240 name: format!("${}", get_var_name(var_id)),
241 }
242 }
243
244 pub(crate) fn custom_stmt_str(&mut self, content: &str) -> Result<(), TmplError> {
245 let block = self.get_block_mut();
246 if block.need_stat_sep {
247 block.need_stat_sep = false;
248 write!(&mut self.w, ";")?;
249 }
250 write!(&mut self.w, "{}", content)?;
251 Ok(())
252 }
253
254 fn stat<R>(
255 &mut self,
256 f: impl FnOnce(&mut Self) -> Result<R, TmplError>,
257 ) -> Result<R, TmplError> {
258 let block = self.get_block_mut();
259 if block.need_stat_sep {
260 write!(&mut self.w, ";")?;
261 } else {
262 block.need_stat_sep = true;
263 }
264 let ret = f(self)?;
265 Ok(ret)
266 }
267
268 pub(crate) fn expr_stmt<R>(
269 &mut self,
270 f: impl FnOnce(&mut JsExprWriter<W>) -> Result<R, TmplError>,
271 ) -> Result<R, TmplError> {
272 self.stat(|this| {
273 let ret = f(&mut JsExprWriter {
274 w: this.w,
275 block: if this.block.is_some() {
276 Some(this.block.as_mut().unwrap())
277 } else {
278 None
279 },
280 top_scope: &mut this.top_scope,
281 })?;
282 Ok(ret)
283 })
284 }
285
286 #[allow(dead_code)]
287 pub(crate) fn set_var_on_top_scope(&mut self, name: &str) -> Result<(), TmplError> {
288 self.top_scope.declare_on_top(name)
289 }
290
291 pub(crate) fn set_var_on_top_scope_init<R>(
292 &mut self,
293 name: &str,
294 init: impl FnOnce(&mut JsExprWriter<W>) -> Result<R, TmplError>,
295 ) -> Result<R, TmplError> {
296 self.top_scope.declare_on_top_init(name, init)
297 }
298
299 pub(crate) fn declare_var_on_top_scope(&mut self) -> Result<JsIdent, TmplError> {
300 let block = &mut self.top_scope.block;
301 let var_id = block.ident_id_inc;
302 block.ident_id_inc += 1;
303 let ident = JsIdent {
304 name: get_var_name(var_id),
305 };
306 self.top_scope.declare_on_top(&ident.name)?;
307 Ok(ident)
308 }
309
310 pub(crate) fn declare_var_on_top_scope_init<R>(
311 &mut self,
312 init: impl FnOnce(&mut JsExprWriter<W>, JsIdent) -> Result<R, TmplError>,
313 ) -> Result<R, TmplError> {
314 let block = &mut self.top_scope.block;
315 let var_id = block.ident_id_inc;
316 block.ident_id_inc += 1;
317 let var_name = get_var_name(var_id);
318 let ident = JsIdent {
319 name: var_name.clone(),
320 };
321 self.top_scope
322 .declare_on_top_init(&var_name, |w| init(w, ident))
323 }
324}
325
326pub(crate) struct JsExprWriter<'a, W: fmt::Write> {
327 w: &'a mut String,
328 block: Option<&'a mut JsBlockStat>,
329 top_scope: &'a mut JsTopScopeWriter<W>,
330}
331
332impl<'a, W: fmt::Write> JsExprWriter<'a, W> {
333 fn get_block(&mut self) -> &mut JsBlockStat {
334 if self.block.is_some() {
335 self.block.as_mut().unwrap()
336 } else {
337 &mut self.top_scope.block
338 }
339 }
340
341 pub(crate) fn function<R>(
342 &mut self,
343 f: impl FnOnce(&mut JsFunctionScopeWriter<W>) -> Result<R, TmplError>,
344 ) -> Result<R, TmplError> {
345 write!(&mut self.w, "()=>{{")?;
346
347 let mut block = self.get_block().extend();
348 let ret = f(&mut JsFunctionScopeWriter {
349 w: self.w,
350 block: Some(&mut block),
351 top_scope: &mut self.top_scope,
352 })?;
353 write!(&mut self.w, "}}")?;
354 Ok(ret)
355 }
356
357 pub(crate) fn function_args<R>(
358 &mut self,
359 args: &str,
360 f: impl FnOnce(&mut JsFunctionScopeWriter<W>) -> Result<R, TmplError>,
361 ) -> Result<R, TmplError> {
362 write!(&mut self.w, "({})=>{{", args)?;
363 let mut block = self.get_block().extend();
364 let ret = f(&mut JsFunctionScopeWriter {
365 w: self.w,
366 block: Some(&mut block),
367 top_scope: &mut self.top_scope,
368 })?;
369 write!(&mut self.w, "}}")?;
370 Ok(ret)
371 }
372
373 pub(crate) fn function_dyn_args<R>(
374 &mut self,
375 args_f: impl FnOnce(&mut JsFunctionArgsAssigner<W>) -> Result<Vec<JsIdent>, TmplError>,
376 f: impl FnOnce(&mut JsFunctionScopeWriter<W>, Vec<JsIdent>) -> Result<R, TmplError>,
377 ) -> Result<R, TmplError> {
378 let mut block = self.get_block().extend();
379 let args = args_f(&mut JsFunctionArgsAssigner {
380 block: Some(&mut block),
381 top_scope: &mut self.top_scope,
382 })?;
383 write!(
384 &mut self.w,
385 "({})=>{{",
386 args.iter()
387 .map(|x| x.to_string())
388 .collect::<Vec<_>>()
389 .join(",")
390 )?;
391 let ret = f(
392 &mut JsFunctionScopeWriter {
393 w: self.w,
394 block: Some(&mut block),
395 top_scope: &mut self.top_scope,
396 },
397 args,
398 )?;
399 write!(&mut self.w, "}}")?;
400 Ok(ret)
401 }
402
403 pub(crate) fn brace_block<R>(
404 &mut self,
405 f: impl FnOnce(&mut JsFunctionScopeWriter<W>) -> Result<R, TmplError>,
406 ) -> Result<R, TmplError> {
407 write!(&mut self.w, "{{")?;
408 let block = self.get_block();
409 let mut child_block = block.extend();
410 let mut child_scope = JsFunctionScopeWriter {
411 w: self.w,
412 block: Some(&mut child_block),
413 top_scope: &mut self.top_scope,
414 };
415 let ret = f(&mut child_scope)?;
416 write!(&mut self.w, "}}")?;
417 Ok(ret)
418 }
419
420 pub(crate) fn paren<R>(
421 &mut self,
422 f: impl FnOnce(&mut Self) -> Result<R, TmplError>,
423 ) -> Result<R, TmplError> {
424 write!(&mut self.w, "(")?;
425 let ret = f(self)?;
426 write!(&mut self.w, ")")?;
427 Ok(ret)
428 }
429
430 #[allow(dead_code)]
431 pub(crate) fn declare_var_on_top_scope(&mut self) -> Result<JsIdent, TmplError> {
432 let block = &mut self.top_scope.block;
433 let var_id = block.ident_id_inc;
434 block.ident_id_inc += 1;
435 let ident = JsIdent {
436 name: get_var_name(var_id),
437 };
438 self.top_scope.declare_on_top(&ident.name)?;
439 Ok(ident)
440 }
441}
442
443impl<'a, W: fmt::Write> fmt::Write for JsExprWriter<'a, W> {
444 fn write_str(&mut self, s: &str) -> fmt::Result {
445 write!(&mut self.w, "{}", s)
446 }
447}
448
449pub(crate) struct ScopeVar {
450 pub(crate) var: JsIdent,
451 pub(crate) update_path_tree: Option<JsIdent>,
452 pub(crate) lvalue_path: ScopeVarLvaluePath,
453}
454
455pub(crate) enum ScopeVarLvaluePath {
456 Invalid,
457 Var {
458 var_name: JsIdent,
459 from_data_scope: bool,
460 },
461 Script {
462 abs_path: String,
463 },
464 InlineScript {
465 path: String,
466 mod_name: String,
467 },
468}