luaur_ast/methods/
printer_visualize_pretty_printer_alt_b.rs1use crate::records::ast_expr::AstExpr;
2use crate::records::ast_expr_binary::{AstExprBinary, AstExprBinary_Op};
3use crate::records::ast_expr_call::AstExprCall;
4use crate::records::ast_expr_constant_bool::AstExprConstantBool;
5use crate::records::ast_expr_constant_integer::AstExprConstantInteger;
6use crate::records::ast_expr_constant_nil::AstExprConstantNil;
7use crate::records::ast_expr_constant_number::AstExprConstantNumber;
8use crate::records::ast_expr_constant_string::AstExprConstantString;
9use crate::records::ast_expr_error::AstExprError;
10use crate::records::ast_expr_function::AstExprFunction;
11use crate::records::ast_expr_global::AstExprGlobal;
12use crate::records::ast_expr_group::AstExprGroup;
13use crate::records::ast_expr_if_else::AstExprIfElse;
14use crate::records::ast_expr_index_expr::AstExprIndexExpr;
15use crate::records::ast_expr_index_name::AstExprIndexName;
16use crate::records::ast_expr_instantiate::AstExprInstantiate;
17use crate::records::ast_expr_interp_string::AstExprInterpString;
18use crate::records::ast_expr_local::AstExprLocal;
19use crate::records::ast_expr_table::{AstExprTable, ItemKind};
20use crate::records::ast_expr_type_assertion::AstExprTypeAssertion;
21use crate::records::ast_expr_unary::{AstExprUnary, AstExprUnaryOp};
22use crate::records::ast_expr_varargs::AstExprVarargs;
23use crate::records::ast_node::AstNode;
24use crate::records::comma_separator_inserter::CommaSeparatorInserter;
25use crate::records::cst_expr_call::CstExprCall;
26use crate::records::cst_expr_constant_integer::CstExprConstantInteger;
27use crate::records::cst_expr_constant_number::CstExprConstantNumber;
28use crate::records::cst_expr_constant_string::CstExprConstantString;
29use crate::records::cst_expr_explicit_type_instantiation::CstExprExplicitTypeInstantiation;
30use crate::records::cst_expr_group::CstExprGroup;
31use crate::records::cst_expr_index_expr::CstExprIndexExpr;
32use crate::records::cst_expr_interp_string::CstExprInterpString;
33use crate::records::cst_expr_op::CstExprOp;
34use crate::records::cst_expr_table::{CstExprTable, CstExprTableSeparator};
35use crate::records::cst_expr_type_assertion::CstExprTypeAssertion;
36use crate::records::printer::Printer;
37use crate::rtti::{ast_node_as, ast_node_is};
38
39pub trait IntoAstExprMut {
40 unsafe fn into_ast_expr_mut(self) -> *mut AstExpr;
41}
42
43impl IntoAstExprMut for *mut AstExpr {
44 unsafe fn into_ast_expr_mut(self) -> *mut AstExpr {
45 self
46 }
47}
48
49impl IntoAstExprMut for &*mut AstExpr {
50 unsafe fn into_ast_expr_mut(self) -> *mut AstExpr {
51 *self
52 }
53}
54
55impl IntoAstExprMut for &mut AstExpr {
56 unsafe fn into_ast_expr_mut(self) -> *mut AstExpr {
57 self
58 }
59}
60
61impl<'a> Printer<'a> {
62 pub fn visualize_ast_expr<E: IntoAstExprMut>(&mut self, expr: E) {
63 let expr = unsafe { expr.into_ast_expr_mut() };
64 if expr.is_null() {
65 return;
66 }
67
68 let node = expr as *mut AstNode;
69 let expr_ref = unsafe { &mut *expr };
70 self.advance(&expr_ref.base.location.begin);
71
72 if let Some(a) = unsafe { ast_node_as::<AstExprGroup>(node).as_mut() } {
73 self.writer.symbol("(");
74 self.visualize_ast_expr(a.expr);
75
76 let cst_node = self.lookup_cst_node_impl::<CstExprGroup>(node);
77 if !cst_node.is_null() {
78 self.maybe_advance_and_write(unsafe { &(*cst_node).close_position }, ")", false);
79 } else {
80 self.advance_before(a.base.base.location.end, 1);
81 self.writer.symbol(")");
82 }
83 } else if unsafe { ast_node_is::<AstExprConstantNil>(node) } {
84 self.writer.keyword("nil");
85 } else if let Some(a) = unsafe { ast_node_as::<AstExprConstantBool>(node).as_mut() } {
86 self.writer.keyword(if a.value { "true" } else { "false" });
87 } else if let Some(a) = unsafe { ast_node_as::<AstExprConstantNumber>(node).as_mut() } {
88 let cst_node = self.lookup_cst_node_impl::<CstExprConstantNumber>(node);
89 if !cst_node.is_null() {
90 let value = unsafe {
91 core::str::from_utf8_unchecked(core::slice::from_raw_parts(
92 (*cst_node).value.data as *const u8,
93 (*cst_node).value.size,
94 ))
95 };
96 self.writer.literal(value);
97 } else if a.value.is_infinite() {
98 self.writer.literal(if a.value.is_sign_positive() {
99 "1e500"
100 } else {
101 "-1e500"
102 });
103 } else if a.value.is_nan() {
104 self.writer.literal("0/0");
105 } else if Printer::printer_is_integerish(a.value) {
106 self.writer.literal(&(a.value as i32).to_string());
107 } else {
108 self.writer
109 .literal(&luaur_common::functions::format_g::format_g(a.value, 17));
110 }
111 } else if let Some(a) = unsafe { ast_node_as::<AstExprConstantInteger>(node).as_mut() } {
112 let cst_node = self.lookup_cst_node_impl::<CstExprConstantInteger>(node);
113 if !cst_node.is_null() {
114 let value = unsafe {
115 core::str::from_utf8_unchecked(core::slice::from_raw_parts(
116 (*cst_node).value.data as *const u8,
117 (*cst_node).value.size,
118 ))
119 };
120 self.writer.literal(value);
121 } else if a.value >= 0 {
122 self.writer.literal(&format!("{}i", a.value));
123 } else {
124 self.writer.literal(&format!("0x{:x}i", a.value as u64));
125 }
126 } else if let Some(a) = unsafe { ast_node_as::<AstExprConstantString>(node).as_mut() } {
127 let cst_node = self.lookup_cst_node_impl::<CstExprConstantString>(node);
128 if !cst_node.is_null() {
129 let source = unsafe {
130 core::str::from_utf8_unchecked(core::slice::from_raw_parts(
131 (*cst_node).source_string.data as *const u8,
132 (*cst_node).source_string.size,
133 ))
134 };
135 self.writer
136 .source_string(source, unsafe { (*cst_node).quote_style }, unsafe {
137 (*cst_node).block_depth
138 });
139 } else {
140 let value = unsafe {
141 core::str::from_utf8_unchecked(core::slice::from_raw_parts(
142 a.value.data as *const u8,
143 a.value.size,
144 ))
145 };
146 self.writer.string(value);
147 }
148 } else if let Some(a) = unsafe { ast_node_as::<AstExprLocal>(node).as_mut() } {
149 let name =
150 unsafe { core::ffi::CStr::from_ptr((*a.local).name.value).to_string_lossy() };
151 self.writer.identifier(&name);
152 } else if let Some(a) = unsafe { ast_node_as::<AstExprGlobal>(node).as_mut() } {
153 let name = unsafe { core::ffi::CStr::from_ptr(a.name.value).to_string_lossy() };
154 self.writer.identifier(&name);
155 } else if unsafe { ast_node_is::<AstExprVarargs>(node) } {
156 self.writer.symbol("...");
157 } else if let Some(a) = unsafe { ast_node_as::<AstExprCall>(node).as_mut() } {
158 self.visualize_ast_expr(a.func);
159
160 let cst_node = self.lookup_cst_node_impl::<CstExprCall>(node);
161
162 if self.write_types
163 && (a.type_arguments.size > 0
164 || (!cst_node.is_null() && unsafe { !(*cst_node).explicit_types.is_null() }))
165 {
166 self.visualize_explicit_type_instantiation(
167 a.type_arguments,
168 if !cst_node.is_null() {
169 unsafe { (*cst_node).explicit_types }
170 } else {
171 core::ptr::null_mut()
172 },
173 );
174 }
175
176 if !cst_node.is_null() {
177 self.maybe_advance_and_write(unsafe { &(*cst_node).open_parens }, "(", false);
178 } else {
179 self.writer.symbol("(");
180 }
181
182 let mut comma = CommaSeparatorInserter::new(
183 self.writer,
184 if !cst_node.is_null() {
185 unsafe { (*cst_node).comma_positions.data }
186 } else {
187 core::ptr::null()
188 },
189 );
190 for arg in a.args.iter() {
191 comma.operator_call(self.writer);
192 self.visualize_ast_expr(*arg);
193 }
194
195 if !cst_node.is_null() {
196 self.maybe_advance_and_write(unsafe { &(*cst_node).close_parens }, ")", false);
197 } else {
198 self.writer.symbol(")");
199 }
200 } else if let Some(a) = unsafe { ast_node_as::<AstExprIndexName>(node).as_mut() } {
201 self.visualize_ast_expr(a.expr);
202 self.advance(&a.op_position);
203 let op = (a.op as u8 as char).to_string();
204 self.writer.symbol(&op);
205 self.advance(&a.index_location.begin);
206 let index = unsafe { core::ffi::CStr::from_ptr(a.index.value).to_string_lossy() };
207 self.writer.write(&index);
208 } else if let Some(a) = unsafe { ast_node_as::<AstExprIndexExpr>(node).as_mut() } {
209 let cst_node = self.lookup_cst_node_impl::<CstExprIndexExpr>(node);
210 self.visualize_ast_expr(a.expr);
211
212 if !cst_node.is_null() {
213 self.maybe_advance_and_write(
214 unsafe { &(*cst_node).open_bracket_position },
215 "[",
216 false,
217 );
218 } else {
219 self.writer.symbol("[");
220 }
221
222 self.visualize_ast_expr(a.index);
223
224 if !cst_node.is_null() {
225 self.maybe_advance_and_write(
226 unsafe { &(*cst_node).close_bracket_position },
227 "]",
228 false,
229 );
230 } else {
231 self.writer.symbol("]");
232 }
233 } else if let Some(a) = unsafe { ast_node_as::<AstExprFunction>(node).as_mut() } {
234 for attr in a.attributes.iter() {
235 self.visualize_attribute(unsafe { &mut **attr });
236 }
237 self.writer.keyword("function");
238 self.visualize_function_body(a);
239 } else if let Some(a) = unsafe { ast_node_as::<AstExprTable>(node).as_mut() } {
240 self.writer.symbol("{");
241
242 let cst_node = self.lookup_cst_node_impl::<CstExprTable>(node);
243 let mut cst_item = if !cst_node.is_null() {
244 luaur_common::LUAU_ASSERT!(unsafe { (*cst_node).items.size == a.items.size });
245 unsafe { (*cst_node).items.data }
246 } else {
247 core::ptr::null()
248 };
249 let mut first = true;
250
251 for item in a.items.iter() {
252 if cst_item.is_null() {
253 if first {
254 first = false;
255 } else {
256 self.writer.symbol(",");
257 }
258 }
259
260 match item.kind {
261 ItemKind::List => {}
262 ItemKind::Record => {
263 let key = unsafe {
264 ast_node_as::<AstExprConstantString>(
265 item.key as *mut crate::records::ast_node::AstNode,
266 )
267 };
268 luaur_common::LUAU_ASSERT!(!key.is_null());
269 let key = unsafe { &mut *key };
270 self.advance(&key.base.base.location.begin);
271 let value = unsafe {
272 core::str::from_utf8_unchecked(core::slice::from_raw_parts(
273 key.value.data as *const u8,
274 key.value.size,
275 ))
276 };
277 self.writer.identifier(value);
278
279 if !cst_item.is_null() {
280 self.advance(unsafe { (*cst_item).equals_position });
281 } else {
282 unsafe {
283 self.writer
284 .maybe_space(&(*item.value).base.location.begin, 1);
285 }
286 }
287 self.writer.symbol("=");
288 }
289 ItemKind::General => {
290 if !cst_item.is_null() {
291 luaur_common::LUAU_ASSERT!(unsafe {
292 (*cst_item).indexer_open_position.has_value()
293 });
294 self.maybe_advance_and_write(
295 unsafe { &(*cst_item).indexer_open_position },
296 "[",
297 true,
298 );
299 self.visualize_ast_expr(item.key);
300 self.maybe_advance_and_write(
301 unsafe { &(*cst_item).indexer_close_position },
302 "]",
303 false,
304 );
305 self.maybe_advance_and_write(
306 unsafe { &(*cst_item).equals_position },
307 "=",
308 false,
309 );
310 } else {
311 self.writer.symbol("[");
312 self.visualize_ast_expr(item.key);
313 self.writer.symbol("]");
314 unsafe {
315 self.writer
316 .maybe_space(&(*item.value).base.location.begin, 1);
317 }
318 self.writer.symbol("=");
319 }
320 }
321 }
322
323 unsafe {
324 self.advance(&(*item.value).base.location.begin);
325 }
326 self.visualize_ast_expr(item.value);
327
328 if !cst_item.is_null() {
329 let separator = unsafe { (*cst_item).separator };
330 if separator != CstExprTableSeparator::Missing {
331 luaur_common::LUAU_ASSERT!(unsafe {
332 (*cst_item).separator_position.has_value()
333 });
334 self.maybe_advance_and_write(
335 unsafe { &(*cst_item).separator_position },
336 if separator == CstExprTableSeparator::Comma {
337 ","
338 } else {
339 ";"
340 },
341 true,
342 );
343 }
344 cst_item = unsafe { cst_item.add(1) };
345 }
346 }
347
348 let mut end_pos = expr_ref.base.location.end;
349 if end_pos.column > 0 {
350 end_pos.column -= 1;
351 }
352 self.advance(end_pos);
353 self.writer.symbol("}");
354 self.advance(expr_ref.base.location.end);
355 } else if let Some(a) = unsafe { ast_node_as::<AstExprUnary>(node).as_mut() } {
356 let cst_node = self.lookup_cst_node_impl::<CstExprOp>(node);
357 if !cst_node.is_null() {
358 self.advance(unsafe { (*cst_node).op_position });
359 }
360
361 match a.op {
362 AstExprUnaryOp::Not => self.writer.keyword("not"),
363 AstExprUnaryOp::Minus => self.writer.symbol("-"),
364 AstExprUnaryOp::Len => self.writer.symbol("#"),
365 }
366 self.visualize_ast_expr(a.expr);
367 } else if let Some(a) = unsafe { ast_node_as::<AstExprBinary>(node).as_mut() } {
368 self.visualize_ast_expr(a.left);
369
370 let cst_node = self.lookup_cst_node_impl::<CstExprOp>(node);
371 if !cst_node.is_null() {
372 self.advance(unsafe { (*cst_node).op_position });
373 } else {
374 match a.op {
375 AstExprBinary_Op::Add
376 | AstExprBinary_Op::Sub
377 | AstExprBinary_Op::Mul
378 | AstExprBinary_Op::Div
379 | AstExprBinary_Op::FloorDiv
380 | AstExprBinary_Op::Mod
381 | AstExprBinary_Op::Pow
382 | AstExprBinary_Op::CompareLt
383 | AstExprBinary_Op::CompareGt => unsafe {
384 self.writer.maybe_space(&(*a.right).base.location.begin, 2);
385 },
386 AstExprBinary_Op::Concat
387 | AstExprBinary_Op::CompareNe
388 | AstExprBinary_Op::CompareEq
389 | AstExprBinary_Op::CompareLe
390 | AstExprBinary_Op::CompareGe
391 | AstExprBinary_Op::Or => unsafe {
392 self.writer.maybe_space(&(*a.right).base.location.begin, 3);
393 },
394 AstExprBinary_Op::And => unsafe {
395 self.writer.maybe_space(&(*a.right).base.location.begin, 4);
396 },
397 AstExprBinary_Op::Op__Count => luaur_common::LUAU_ASSERT!(false),
398 }
399 }
400
401 let op = crate::functions::to_string_ast_alt_b::to_string(a.op);
402 self.writer.symbol(&op);
403 self.visualize_ast_expr(a.right);
404 } else if let Some(a) = unsafe { ast_node_as::<AstExprTypeAssertion>(node).as_mut() } {
405 self.visualize_ast_expr(a.expr);
406
407 if self.write_types {
408 let cst_node = self.lookup_cst_node_impl::<CstExprTypeAssertion>(node);
409 if !cst_node.is_null() {
410 self.advance(unsafe { (*cst_node).op_position });
411 } else {
412 unsafe {
413 self.writer
414 .maybe_space(&(*a.annotation).base.location.begin, 2);
415 }
416 }
417 self.writer.symbol("::");
418 unsafe {
419 self.visualize_type_annotation(&mut *a.annotation);
420 }
421 }
422 } else if let Some(a) = unsafe { ast_node_as::<AstExprIfElse>(node).as_mut() } {
423 self.writer.keyword("if");
424 self.visualize_else_if_expr(a);
425 } else if let Some(a) = unsafe { ast_node_as::<AstExprInterpString>(node).as_mut() } {
426 let cst_node = self.lookup_cst_node_impl::<CstExprInterpString>(node);
427
428 self.writer.symbol("`");
429
430 for index in 0..a.strings.size {
431 if !cst_node.is_null() {
432 if index > 0 {
433 self.advance(unsafe { *(*cst_node).string_positions.data.add(index) });
434 self.writer.symbol("}");
435 }
436
437 let source_string = unsafe { *(*cst_node).source_strings.data.add(index) };
438 let source = unsafe {
439 core::str::from_utf8_unchecked(core::slice::from_raw_parts(
440 source_string.data as *const u8,
441 source_string.size,
442 ))
443 };
444 self.writer.write_multiline(source);
445 } else {
446 let string = unsafe { *a.strings.data.add(index) };
447 let value = unsafe {
448 core::str::from_utf8_unchecked(core::slice::from_raw_parts(
449 string.data as *const u8,
450 string.size,
451 ))
452 };
453 self.writer
454 .write(&luaur_common::functions::escape::escape(value, true));
455 }
456
457 if index < a.expressions.size {
458 self.writer.symbol("{");
459 self.visualize_ast_expr(unsafe { *a.expressions.data.add(index) });
460 if cst_node.is_null() {
461 self.writer.symbol("}");
462 }
463 }
464 }
465
466 self.writer.symbol("`");
467 } else if let Some(a) = unsafe { ast_node_as::<AstExprError>(node).as_mut() } {
468 self.writer.symbol("(error-expr");
469
470 for i in 0..a.expressions.size {
471 self.writer.symbol(if i == 0 { ": " } else { ", " });
472 self.visualize_ast_expr(unsafe { *a.expressions.data.add(i as usize) });
473 }
474
475 self.writer.symbol(")");
476 } else if let Some(a) = unsafe { ast_node_as::<AstExprInstantiate>(node).as_mut() } {
477 self.visualize_ast_expr(a.expr);
478
479 if self.write_types {
480 let cst_expr_node =
481 self.lookup_cst_node_impl::<CstExprExplicitTypeInstantiation>(node);
482 self.visualize_explicit_type_instantiation(
483 a.type_arguments,
484 if !cst_expr_node.is_null() {
485 unsafe { &(*cst_expr_node).instantiation }
486 } else {
487 core::ptr::null()
488 },
489 );
490 }
491 } else {
492 luaur_common::LUAU_ASSERT!(false);
493 }
494 }
495}