datex_core/decompiler/
mod.rs

1mod ast_from_bytecode;
2mod ast_from_value_container;
3mod ast_to_source_code;
4mod options;
5pub use options::*;
6
7use binrw::io::Cursor;
8use core::fmt::Write;
9
10use crate::ast::expressions::{DatexExpression, DatexExpressionData};
11use crate::ast::spanned::Spanned;
12use crate::decompiler::ast_to_source_code::AstToSourceCodeConverter;
13
14use crate::decompiler::ast_from_bytecode::ast_from_bytecode;
15use crate::dxb_parser::body::DXBParserError;
16use crate::values::value_container::ValueContainer;
17#[cfg(feature = "syntax_highlighting_legacy")]
18use syntect::{
19    easy::HighlightLines,
20    highlighting::{Style, Theme, ThemeSet},
21    parsing::{SyntaxDefinition, SyntaxSetBuilder},
22    util::{LinesWithEndings, as_24_bit_terminal_escaped},
23};
24
25/// Decompiles a DXB bytecode body into a human-readable string representation.
26pub fn decompile_body(
27    dxb_body: &[u8],
28    options: DecompileOptions,
29) -> Result<String, DXBParserError> {
30    let ast = ast_from_bytecode(dxb_body)?;
31    Ok(format_ast(ast, options))
32}
33
34/// Decompiles a single DATEX value into a human-readable string representation.
35pub fn decompile_value(
36    value: &ValueContainer,
37    options: DecompileOptions,
38) -> String {
39    let ast = DatexExpressionData::from(value).with_default_span();
40    format_ast(ast, options)
41}
42
43fn format_ast(ast: DatexExpression, options: DecompileOptions) -> String {
44    let colorized = options.formatting_options.colorized;
45    let formatter = AstToSourceCodeConverter::new(options.formatting_options);
46    // convert AST to source code
47    let source = formatter.format(&ast);
48    if colorized {
49        apply_syntax_highlighting(source).unwrap()
50    } else {
51        source
52    }
53}
54
55#[cfg(not(feature = "syntax_highlighting_legacy"))]
56pub fn apply_syntax_highlighting(
57    datex_script: String,
58) -> Result<String, DXBParserError> {
59    // skip syntax highlighting
60    Ok(datex_script)
61}
62
63#[cfg(feature = "syntax_highlighting_legacy")]
64pub fn apply_syntax_highlighting(
65    datex_script: String,
66) -> Result<String, DXBParserError> {
67    let mut output = String::new();
68
69    // load datex syntax + custom theme
70    static DATEX_SCRIPT_DEF: &str = include_str!(
71        "../../datex-language/datex.tmbundle/Syntaxes/datex.sublime-text"
72    );
73    static DATEX_THEME_DEF: &str =
74        include_str!("../../datex-language/themes/datex-dark.tmTheme");
75    let mut builder = SyntaxSetBuilder::new();
76    let syntax = SyntaxDefinition::load_from_str(DATEX_SCRIPT_DEF, true, None)
77        .expect("Failed to load syntax definition");
78    builder.add(syntax);
79    let theme: Theme =
80        ThemeSet::load_from_reader(&mut Cursor::new(DATEX_THEME_DEF))
81            .expect("Failed to load theme");
82
83    let ps = builder.build();
84    let syntax = ps.find_syntax_by_extension("dx").unwrap();
85    let mut h = HighlightLines::new(syntax, &theme);
86
87    for line in LinesWithEndings::from(&datex_script) {
88        let ranges: Vec<(Style, &str)> = h.highlight_line(line, &ps).unwrap();
89        let escaped = as_24_bit_terminal_escaped(&ranges[..], false);
90        core::write!(output, "{escaped}")?;
91    }
92    // reset style
93    core::write!(output, "\x1b[0m")?;
94    Ok(output)
95}