swc_ecma_codegen/text_writer/
semicolon.rs

1use swc_common::{BytePos, Span, DUMMY_SP};
2
3use super::{Result, WriteJs};
4
5pub fn omit_trailing_semi<W: WriteJs>(w: W) -> impl WriteJs {
6    OmitTrailingSemi {
7        inner: w,
8        pending_semi: None,
9    }
10}
11
12#[derive(Debug, Clone)]
13struct OmitTrailingSemi<W: WriteJs> {
14    inner: W,
15    pending_semi: Option<Span>,
16}
17
18macro_rules! with_semi {
19    (
20        $fn_name:ident
21        (
22            $(
23                $arg_name:ident
24                :
25                $arg_ty:ty
26            ),*
27        )
28    ) => {
29        fn $fn_name(&mut self, $($arg_name: $arg_ty),* ) -> Result {
30            self.commit_pending_semi()?;
31
32            self.inner.$fn_name( $($arg_name),* )
33        }
34    };
35}
36
37impl<W: WriteJs> WriteJs for OmitTrailingSemi<W> {
38    with_semi!(increase_indent());
39
40    with_semi!(decrease_indent());
41
42    with_semi!(write_space());
43
44    with_semi!(write_comment(s: &str));
45
46    with_semi!(write_keyword(span: Option<Span>, s: &'static str));
47
48    with_semi!(write_operator(span: Option<Span>, s: &str));
49
50    with_semi!(write_param(s: &str));
51
52    with_semi!(write_property(s: &str));
53
54    with_semi!(write_line());
55
56    with_semi!(write_lit(span: Span, s: &str));
57
58    with_semi!(write_str_lit(span: Span, s: &str));
59
60    with_semi!(write_str(s: &str));
61
62    with_semi!(write_symbol(span: Span, s: &str));
63
64    fn write_semi(&mut self, span: Option<Span>) -> Result {
65        self.pending_semi = Some(span.unwrap_or(DUMMY_SP));
66        Ok(())
67    }
68
69    fn write_punct(&mut self, span: Option<Span>, s: &'static str) -> Result {
70        let bytes = s.as_bytes();
71        if bytes.len() == 1 {
72            let first = *unsafe { bytes.get_unchecked(0) };
73            static PUNCT_TABLE: [bool; 256] = {
74                let mut table = [false; 256];
75                table[b'"' as usize] = true;
76                table[b'\'' as usize] = true;
77                table[b'[' as usize] = true;
78                table[b'!' as usize] = true;
79                table[b'/' as usize] = true;
80                table[b'{' as usize] = true;
81                table[b'(' as usize] = true;
82                table[b'~' as usize] = true;
83                table[b'-' as usize] = true;
84                table[b'+' as usize] = true;
85                table[b'#' as usize] = true;
86                table[b'`' as usize] = true;
87                table[b'*' as usize] = true;
88                table
89            };
90            if PUNCT_TABLE[first as usize] {
91                self.commit_pending_semi()?;
92                return self.inner.write_punct(span, s);
93            }
94        }
95        self.pending_semi = None;
96        self.inner.write_punct(span, s)
97    }
98
99    #[inline]
100    fn care_about_srcmap(&self) -> bool {
101        self.inner.care_about_srcmap()
102    }
103
104    #[inline]
105    fn add_srcmap(&mut self, pos: BytePos) -> Result {
106        self.inner.add_srcmap(pos)
107    }
108
109    fn commit_pending_semi(&mut self) -> Result {
110        if let Some(span) = self.pending_semi {
111            self.inner.write_semi(Some(span))?;
112            self.pending_semi = None;
113        }
114        Ok(())
115    }
116
117    #[inline(always)]
118    fn can_ignore_invalid_unicodes(&mut self) -> bool {
119        self.inner.can_ignore_invalid_unicodes()
120    }
121}