luaur_ast/records/
string_writer.rs1use crate::records::position::Position;
2use alloc::string::String;
3
4#[derive(Debug, Clone)]
9pub struct StringWriter {
10 pub(crate) ss: String,
11 pub(crate) pos: Position,
12 pub(crate) last_char: char,
13}
14
15impl StringWriter {
16 pub(crate) fn str(&self) -> &String {
17 &self.ss
18 }
19
20 pub(crate) fn advance(&mut self, newPos: &Position) {
21 while self.pos.line < newPos.line {
22 self.newline();
23 }
24
25 if self.pos.column < newPos.column {
26 let count = (newPos.column - self.pos.column) as usize;
27 self.write(&" ".repeat(count));
28 }
29 }
30
31 pub(crate) fn maybe_space(&mut self, newPos: &Position, reserve: i32) {
32 if self.pos.column + (reserve as u32) < newPos.column {
33 self.space();
34 }
35 }
36
37 pub(crate) fn newline(&mut self) {
38 self.ss.push('\n');
39 self.pos.column = 0;
40 self.pos.line += 1;
41 self.last_char = '\n';
42 }
43
44 pub(crate) fn space(&mut self) {
45 self.ss.push(' ');
46 self.pos.column += 1;
47 self.last_char = ' ';
48 }
49
50 pub(crate) fn write_multiline(&mut self, s: &str) {
51 if s.is_empty() {
52 return;
53 }
54
55 self.ss.push_str(s);
56 self.last_char = s.chars().last().unwrap_or('\0');
57
58 let mut index = 0;
59 let mut numLines = 0;
60 let bytes = s.as_bytes();
61 for (i, &b) in bytes.iter().enumerate() {
62 if b == b'\n' {
63 numLines += 1;
64 index = i + 1;
65 }
66 }
67
68 self.pos.line += numLines as u32;
69 if numLines > 0 {
70 self.pos.column = (s.len() - index) as u32;
71 } else {
72 self.pos.column += s.len() as u32;
73 }
74 }
75
76 pub(crate) fn write(&mut self, s: &str) {
77 if s.is_empty() {
78 return;
79 }
80
81 self.ss.push_str(s);
82 self.pos.column += s.len() as u32;
83 self.last_char = s.chars().last().unwrap_or('\0');
84 }
85
86 pub(crate) fn write_char(&mut self, c: char) {
87 self.ss.push(c);
88 self.pos.column += 1;
89 self.last_char = c;
90 }
91
92 pub(crate) fn identifier(&mut self, s: &str) {
93 if s.is_empty() {
94 return;
95 }
96
97 if crate::records::string_writer::is_identifier_char(self.last_char) {
98 self.space();
99 }
100
101 self.write(s);
102 }
103
104 pub(crate) fn keyword(&mut self, s: &str) {
105 if s.is_empty() {
106 return;
107 }
108
109 if crate::records::string_writer::is_identifier_char(self.last_char) {
110 self.space();
111 }
112
113 self.write(s);
114 }
115
116 pub(crate) fn symbol(&mut self, s: &str) {
117 self.write(s);
118 }
119
120 pub(crate) fn literal(&mut self, s: &str) {
121 if s.is_empty() {
122 return;
123 } else if crate::records::string_writer::is_identifier_char(self.last_char)
124 && s.chars().next().map_or(false, |c| c.is_ascii_digit())
125 {
126 self.space();
127 }
128
129 self.write(s);
130 }
131
132 pub(crate) fn string(&mut self, s: &str) {
133 let mut quote = '\'';
134 if s.contains('\'') {
135 quote = '\"';
136 }
137
138 self.write_char(quote);
139 self.write(&luaur_common::functions::escape::escape(s, false));
140 self.write_char(quote);
141 }
142
143 pub(crate) fn source_string(
144 &mut self,
145 s: &str,
146 quote_style: crate::enums::quote_style_cst::QuoteStyle,
147 block_depth: u32,
148 ) {
149 use crate::enums::quote_style_cst::QuoteStyle;
150 if quote_style == QuoteStyle::QuotedRaw {
151 let blocks = "=".repeat(block_depth as usize);
152 self.write_char('[');
153 self.write(&blocks);
154 self.write_char('[');
155 self.write_multiline(s);
156 self.write_char(']');
157 self.write(&blocks);
158 self.write_char(']');
159 } else {
160 debug_assert!(block_depth == 0);
161
162 let quote = match quote_style {
163 QuoteStyle::QuotedDouble => '"',
164 QuoteStyle::QuotedSingle => '\'',
165 QuoteStyle::QuotedInterp => '`',
166 _ => {
167 debug_assert!(false, "Unhandled quote type");
168 '"'
169 }
170 };
171
172 self.write_char(quote);
173 self.write_multiline(s);
174 self.write_char(quote);
175 }
176 }
177}
178
179#[inline]
180fn is_identifier_char(c: char) -> bool {
181 c.is_ascii_alphanumeric() || c == '_'
182}