Skip to main content

swc_ecma_codegen/
text_writer.rs

1use swc_common::{LineCol, Span};
2
3pub use self::{basic_impl::JsWriter, semicolon::omit_trailing_semi};
4use super::*;
5
6mod basic_impl;
7mod semicolon;
8
9/// TODO
10pub type Symbol = Str;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum ScopeKind {
14    Global,
15    Module,
16    Function,
17    Block,
18    Catch,
19}
20
21impl ScopeKind {
22    #[inline]
23    pub const fn is_hoist_target(self) -> bool {
24        matches!(self, Self::Global | Self::Module | Self::Function)
25    }
26
27    #[inline]
28    pub const fn as_str(self) -> &'static str {
29        match self {
30            ScopeKind::Global => "global",
31            ScopeKind::Module => "module",
32            ScopeKind::Function => "function",
33            ScopeKind::Block => "block",
34            ScopeKind::Catch => "catch",
35        }
36    }
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum BindingStorage {
41    Hoisted,
42    Lexical,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct ScopeBindingRecord {
47    pub name: String,
48    pub expression: Option<String>,
49    pub storage: BindingStorage,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct ScopeRecord {
54    pub parent: Option<u32>,
55    pub generated_start: LineCol,
56    pub generated_end: Option<LineCol>,
57    pub original_span: Option<Span>,
58    pub kind: ScopeKind,
59    pub is_stack_frame: bool,
60    pub is_hidden: bool,
61    pub name: Option<String>,
62    pub bindings: Vec<ScopeBindingRecord>,
63}
64
65/// Ecmascript writer.
66///
67/// Ported from `EmitWriteJs`.
68pub trait WriteJs {
69    fn increase_indent(&mut self) -> Result;
70    fn decrease_indent(&mut self) -> Result;
71
72    /// This *may* write semicolon.
73    fn write_semi(&mut self, span: Option<Span>) -> Result;
74
75    fn write_space(&mut self) -> Result;
76    fn write_keyword(&mut self, span: Option<Span>, s: &'static str) -> Result;
77    fn write_operator(&mut self, span: Option<Span>, s: &str) -> Result;
78    fn write_param(&mut self, s: &str) -> Result;
79    fn write_property(&mut self, s: &str) -> Result;
80
81    fn write_line(&mut self) -> Result;
82
83    fn write_lit(&mut self, span: Span, s: &str) -> Result;
84    fn write_comment(&mut self, s: &str) -> Result;
85
86    fn write_str_lit(&mut self, span: Span, s: &str) -> Result;
87    fn write_str(&mut self, s: &str) -> Result;
88
89    fn write_symbol(&mut self, span: Span, s: &str) -> Result;
90
91    /// `commit_pending_semi` should be `true` if the punctuation requires a
92    /// preceding semicolon to be committed before writing. This is typically
93    /// needed for punctuation like `"`, `'`, `[`, `!`, `/`, `{`, `(`, `~`,
94    /// `-`, `+`, `#`, `` ` ``, `*` where ASI (Automatic Semicolon Insertion)
95    /// could cause issues.
96    fn write_punct(
97        &mut self,
98        span: Option<Span>,
99        s: &'static str,
100        commit_pending_semi: bool,
101    ) -> Result;
102
103    fn care_about_srcmap(&self) -> bool;
104
105    fn add_srcmap(&mut self, pos: BytePos) -> Result;
106
107    fn commit_pending_semi(&mut self) -> Result;
108
109    /// If true, the code generator will skip **modification** of invalid
110    /// unicode characters.
111    ///
112    /// Defaults to `false``
113    fn can_ignore_invalid_unicodes(&mut self) -> bool {
114        false
115    }
116
117    /// Returns true if scope tracking hooks should be emitted.
118    ///
119    /// This is used to avoid scope-tracking overhead on the hot codegen path
120    /// when source map scopes are disabled.
121    fn has_scope_tracking(&self) -> bool {
122        false
123    }
124
125    /// Starts a new scope in the generated output.
126    ///
127    /// This is used for source map scope tracking (ECMA-426).
128    fn start_scope(
129        &mut self,
130        _name: Option<&str>,
131        _kind: ScopeKind,
132        _is_stack_frame: bool,
133        _is_hidden: bool,
134        _original_span: Option<Span>,
135    ) -> Result {
136        Ok(())
137    }
138
139    /// Ends the current scope.
140    ///
141    /// This is used for source map scope tracking (ECMA-426).
142    fn end_scope(&mut self) -> Result {
143        Ok(())
144    }
145
146    /// Adds a variable binding to the current scope or its hoist target.
147    ///
148    /// This is used for source map scope tracking (ECMA-426).
149    fn add_scope_variable(
150        &mut self,
151        _name: &str,
152        _expression: Option<&str>,
153        _storage: BindingStorage,
154    ) -> Result {
155        Ok(())
156    }
157}
158
159impl<W> WriteJs for Box<W>
160where
161    W: ?Sized + WriteJs,
162{
163    #[inline]
164    fn increase_indent(&mut self) -> Result {
165        (**self).increase_indent()
166    }
167
168    #[inline]
169    fn decrease_indent(&mut self) -> Result {
170        (**self).decrease_indent()
171    }
172
173    #[inline]
174    fn write_semi(&mut self, span: Option<Span>) -> Result {
175        (**self).write_semi(span)
176    }
177
178    #[inline]
179    fn write_space(&mut self) -> Result {
180        (**self).write_space()
181    }
182
183    #[inline]
184    fn write_keyword(&mut self, span: Option<Span>, s: &'static str) -> Result {
185        (**self).write_keyword(span, s)
186    }
187
188    #[inline]
189    fn write_operator(&mut self, span: Option<Span>, s: &str) -> Result {
190        (**self).write_operator(span, s)
191    }
192
193    #[inline]
194    fn write_param(&mut self, s: &str) -> Result {
195        (**self).write_param(s)
196    }
197
198    #[inline]
199    fn write_property(&mut self, s: &str) -> Result {
200        (**self).write_property(s)
201    }
202
203    #[inline]
204    fn write_line(&mut self) -> Result {
205        (**self).write_line()
206    }
207
208    #[inline]
209    fn write_lit(&mut self, span: Span, s: &str) -> Result {
210        (**self).write_lit(span, s)
211    }
212
213    #[inline]
214    fn write_comment(&mut self, s: &str) -> Result {
215        (**self).write_comment(s)
216    }
217
218    #[inline]
219    fn write_str_lit(&mut self, span: Span, s: &str) -> Result {
220        (**self).write_str_lit(span, s)
221    }
222
223    #[inline]
224    fn write_str(&mut self, s: &str) -> Result {
225        (**self).write_str(s)
226    }
227
228    #[inline]
229    fn write_symbol(&mut self, span: Span, s: &str) -> Result {
230        (**self).write_symbol(span, s)
231    }
232
233    #[inline]
234    fn write_punct(
235        &mut self,
236        span: Option<Span>,
237        s: &'static str,
238        commit_pending_semi: bool,
239    ) -> Result {
240        (**self).write_punct(span, s, commit_pending_semi)
241    }
242
243    #[inline]
244    fn care_about_srcmap(&self) -> bool {
245        (**self).care_about_srcmap()
246    }
247
248    #[inline]
249    fn add_srcmap(&mut self, pos: BytePos) -> Result {
250        (**self).add_srcmap(pos)
251    }
252
253    fn commit_pending_semi(&mut self) -> Result {
254        (**self).commit_pending_semi()
255    }
256
257    #[inline(always)]
258    fn can_ignore_invalid_unicodes(&mut self) -> bool {
259        (**self).can_ignore_invalid_unicodes()
260    }
261
262    #[inline(always)]
263    fn has_scope_tracking(&self) -> bool {
264        (**self).has_scope_tracking()
265    }
266
267    #[inline]
268    fn start_scope(
269        &mut self,
270        name: Option<&str>,
271        kind: ScopeKind,
272        is_stack_frame: bool,
273        is_hidden: bool,
274        original_span: Option<Span>,
275    ) -> Result {
276        (**self).start_scope(name, kind, is_stack_frame, is_hidden, original_span)
277    }
278
279    #[inline]
280    fn end_scope(&mut self) -> Result {
281        (**self).end_scope()
282    }
283
284    #[inline]
285    fn add_scope_variable(
286        &mut self,
287        name: &str,
288        expression: Option<&str>,
289        storage: BindingStorage,
290    ) -> Result {
291        (**self).add_scope_variable(name, expression, storage)
292    }
293}
294
295impl<W> WriteJs for &'_ mut W
296where
297    W: ?Sized + WriteJs,
298{
299    #[inline]
300    fn increase_indent(&mut self) -> Result {
301        (**self).increase_indent()
302    }
303
304    #[inline]
305    fn decrease_indent(&mut self) -> Result {
306        (**self).decrease_indent()
307    }
308
309    #[inline]
310    fn write_semi(&mut self, span: Option<Span>) -> Result {
311        (**self).write_semi(span)
312    }
313
314    #[inline]
315    fn write_space(&mut self) -> Result {
316        (**self).write_space()
317    }
318
319    #[inline]
320    fn write_keyword(&mut self, span: Option<Span>, s: &'static str) -> Result {
321        (**self).write_keyword(span, s)
322    }
323
324    #[inline]
325    fn write_operator(&mut self, span: Option<Span>, s: &str) -> Result {
326        (**self).write_operator(span, s)
327    }
328
329    #[inline]
330    fn write_param(&mut self, s: &str) -> Result {
331        (**self).write_param(s)
332    }
333
334    #[inline]
335    fn write_property(&mut self, s: &str) -> Result {
336        (**self).write_property(s)
337    }
338
339    #[inline]
340    fn write_line(&mut self) -> Result {
341        (**self).write_line()
342    }
343
344    #[inline]
345    fn write_lit(&mut self, span: Span, s: &str) -> Result {
346        (**self).write_lit(span, s)
347    }
348
349    #[inline]
350    fn write_comment(&mut self, s: &str) -> Result {
351        (**self).write_comment(s)
352    }
353
354    #[inline]
355    fn write_str_lit(&mut self, span: Span, s: &str) -> Result {
356        (**self).write_str_lit(span, s)
357    }
358
359    #[inline]
360    fn write_str(&mut self, s: &str) -> Result {
361        (**self).write_str(s)
362    }
363
364    #[inline]
365    fn write_symbol(&mut self, span: Span, s: &str) -> Result {
366        (**self).write_symbol(span, s)
367    }
368
369    #[inline]
370    fn write_punct(
371        &mut self,
372        span: Option<Span>,
373        s: &'static str,
374        commit_pending_semi: bool,
375    ) -> Result {
376        (**self).write_punct(span, s, commit_pending_semi)
377    }
378
379    #[inline]
380    fn care_about_srcmap(&self) -> bool {
381        (**self).care_about_srcmap()
382    }
383
384    #[inline]
385    fn add_srcmap(&mut self, pos: BytePos) -> Result {
386        (**self).add_srcmap(pos)
387    }
388
389    #[inline(always)]
390    fn commit_pending_semi(&mut self) -> Result {
391        (**self).commit_pending_semi()
392    }
393
394    #[inline(always)]
395    fn can_ignore_invalid_unicodes(&mut self) -> bool {
396        (**self).can_ignore_invalid_unicodes()
397    }
398
399    #[inline(always)]
400    fn has_scope_tracking(&self) -> bool {
401        (**self).has_scope_tracking()
402    }
403
404    #[inline]
405    fn start_scope(
406        &mut self,
407        name: Option<&str>,
408        kind: ScopeKind,
409        is_stack_frame: bool,
410        is_hidden: bool,
411        original_span: Option<Span>,
412    ) -> Result {
413        (**self).start_scope(name, kind, is_stack_frame, is_hidden, original_span)
414    }
415
416    #[inline]
417    fn end_scope(&mut self) -> Result {
418        (**self).end_scope()
419    }
420
421    #[inline]
422    fn add_scope_variable(
423        &mut self,
424        name: &str,
425        expression: Option<&str>,
426        storage: BindingStorage,
427    ) -> Result {
428        (**self).add_scope_variable(name, expression, storage)
429    }
430}