Skip to main content

glass_easel_template_compiler/proc_gen/
mod.rs

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; // 'A' ~ 'Z' are preserved
21
22#[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}