luaur_compile_cli/functions/
compile_file.rs1use alloc::string::String;
2use core::ffi::{c_char, c_void, CStr};
3use std::io::Write;
4use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
5
6use luaur_ast::records::allocator::Allocator;
7use luaur_ast::records::ast_name_table::AstNameTable;
8use luaur_ast::records::parse_options::ParseOptions;
9use luaur_ast::records::parser::Parser;
10use luaur_bytecode::records::bytecode_builder::BytecodeBuilder;
11use luaur_cli_lib::functions::read_file::read_file;
12use luaur_code_gen::enums::code_gen_flags::CodeGenFlags;
13use luaur_code_gen::enums::include_cfg_info::IncludeCfgInfo;
14use luaur_code_gen::enums::include_ir_prefix::IncludeIrPrefix;
15use luaur_code_gen::enums::include_reg_flow_info::IncludeRegFlowInfo;
16use luaur_code_gen::enums::include_use_info::IncludeUseInfo;
17use luaur_code_gen::enums::target::Target;
18use luaur_code_gen::records::assembly_options::AssemblyOptions;
19use luaur_code_gen::records::compilation_options::CompilationOptions;
20use luaur_common::functions::get_clock::get_clock;
21use luaur_compiler::functions::compile_or_throw_compiler::compile_or_throw_bytecode_builder_parse_result_ast_name_table_compile_options;
22use luaur_compiler::records::compile_error::CompileError;
23
24use crate::enums::compile_format::CompileFormat;
25use crate::functions::annotate_instruction::annotate_instruction;
26use crate::functions::copts::copts;
27use crate::functions::get_codegen_assembly::get_codegen_assembly;
28use crate::functions::record_delta_time::record_delta_time;
29use crate::functions::report_error_compile::report_error_c_char_luau_parse_error;
30use crate::functions::report_error_compile_alt_b::report_error_c_char_luau_compile_error;
31use crate::records::compile_stats::CompileStats;
32use crate::records::global_options::globalOptions;
33
34pub fn compile_file(
35 name: *const c_char,
36 format: CompileFormat,
37 assembly_target: Target,
38 stats: &mut CompileStats,
39 dump_constants: bool,
40) -> bool {
41 let mut currts = get_clock();
42 let name_cstr = unsafe { CStr::from_ptr(name) };
43 let name_str = name_cstr.to_string_lossy();
44 let name_with_nul = String::from_utf8_lossy(name_cstr.to_bytes_with_nul()).into_owned();
45
46 let Some(source) = read_file(&name_with_nul) else {
47 eprintln!("Error opening {}", name_str);
48 return false;
49 };
50
51 stats.read_time += record_delta_time(&mut currts);
52
53 let result = catch_unwind(AssertUnwindSafe(|| {
54 let mut bcb = BytecodeBuilder::new(None);
55
56 let mut options = AssemblyOptions {
57 target: assembly_target,
58 compilation_options: CompilationOptions::default(),
59 output_binary: format == CompileFormat::CodegenNull,
60 include_assembly: false,
61 include_ir: false,
62 include_outlined_code: false,
63 include_ir_types: false,
64 include_ir_prefix: IncludeIrPrefix::default(),
65 include_use_info: IncludeUseInfo::default(),
66 include_cfg_info: IncludeCfgInfo::default(),
67 include_reg_flow_info: IncludeRegFlowInfo::default(),
68 annotator: Some(annotate_instruction),
69 annotator_context: &mut bcb as *mut BytecodeBuilder as *mut c_void,
70 };
71 options.compilation_options.flags = CodeGenFlags::CodeGen_ColdFunctions as u32;
72
73 if !options.output_binary {
74 options.include_assembly = format != CompileFormat::CodegenIr;
75 options.include_ir = format != CompileFormat::CodegenAsm;
76 options.include_ir_types = format != CompileFormat::CodegenAsm;
77 options.include_outlined_code = format == CompileFormat::CodegenVerbose;
78 }
79
80 if format == CompileFormat::Text {
81 let mut flags = BytecodeBuilder::DUMP_CODE
82 | BytecodeBuilder::DUMP_SOURCE
83 | BytecodeBuilder::DUMP_LOCALS
84 | BytecodeBuilder::DUMP_REMARKS
85 | BytecodeBuilder::DUMP_TYPES;
86 if dump_constants {
87 flags |= BytecodeBuilder::DUMP_CONSTANTS;
88 }
89 bcb.set_dump_flags(flags);
90 bcb.set_dump_source(&source);
91 } else if format == CompileFormat::Remarks {
92 bcb.set_dump_flags(BytecodeBuilder::DUMP_SOURCE | BytecodeBuilder::DUMP_REMARKS);
93 bcb.set_dump_source(&source);
94 } else if format == CompileFormat::Codegen
95 || format == CompileFormat::CodegenAsm
96 || format == CompileFormat::CodegenIr
97 || format == CompileFormat::CodegenVerbose
98 {
99 bcb.set_dump_flags(
100 BytecodeBuilder::DUMP_CODE
101 | BytecodeBuilder::DUMP_SOURCE
102 | BytecodeBuilder::DUMP_LOCALS
103 | BytecodeBuilder::DUMP_REMARKS,
104 );
105 bcb.set_dump_source(&source);
106 }
107
108 stats.misc_time += record_delta_time(&mut currts);
109
110 let mut allocator = Allocator::allocator();
111 let mut names = AstNameTable::new(&mut allocator);
112 let mut parse_options = ParseOptions::default();
113 parse_options.store_cst_data = unsafe { globalOptions.parseCst };
114
115 let parse_result = Parser::parse(
116 source.as_str(),
117 source.len(),
118 &mut names,
119 &mut allocator,
120 parse_options,
121 );
122
123 if !parse_result.errors.is_empty() {
124 for error in &parse_result.errors {
125 report_error_c_char_luau_parse_error(name, error);
126 }
127 return false;
128 }
129
130 stats.lines += parse_result.lines;
131 stats.parse_time += record_delta_time(&mut currts);
132
133 if unsafe { globalOptions.onlyParse } {
134 return true;
135 }
136
137 let compile_options = copts();
138 compile_or_throw_bytecode_builder_parse_result_ast_name_table_compile_options(
139 &mut bcb,
140 &parse_result,
141 &mut names,
142 &compile_options,
143 );
144
145 stats.bytecode += bcb.get_bytecode().len();
146 stats.bytecode_instruction_count = bcb.get_total_instruction_count();
147 stats.compile_time += record_delta_time(&mut currts);
148
149 match format {
150 CompileFormat::Text => {
151 print!("{}", bcb.dump_everything());
152 }
153 CompileFormat::Remarks => {
154 print!("{}", bcb.dump_source_remarks());
155 }
156 CompileFormat::Binary => {
157 let _ = std::io::stdout().write_all(bcb.get_bytecode().as_bytes());
158 }
159 CompileFormat::Codegen
160 | CompileFormat::CodegenAsm
161 | CompileFormat::CodegenIr
162 | CompileFormat::CodegenVerbose => {
163 print!(
164 "{}",
165 get_codegen_assembly(name, bcb.get_bytecode(), options, &mut stats.lower_stats)
166 );
167 }
168 CompileFormat::CodegenNull => {
169 let assembly =
170 get_codegen_assembly(name, bcb.get_bytecode(), options, &mut stats.lower_stats);
171 stats.codegen += assembly.len();
172 stats.codegen_time += record_delta_time(&mut currts);
173 }
174 CompileFormat::Null => {}
175 }
176
177 true
178 }));
179
180 match result {
181 Ok(success) => success,
182 Err(payload) => {
183 if let Some(error) = payload.downcast_ref::<CompileError>() {
184 report_error_c_char_luau_compile_error(name, error);
185 false
186 } else {
187 resume_unwind(payload);
188 }
189 }
190 }
191}