Skip to main content

luaur_ast/methods/
printer_visualize_pretty_printer_alt_b.rs

1use 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}