Skip to main content

luaur_repl_cli/functions/
run_file.rs

1use alloc::string::String;
2use core::ffi::{c_char, CStr};
3
4use luaur_ast::records::parse_options::ParseOptions;
5use luaur_bytecode::records::bytecode_encoder::BytecodeEncoder;
6use luaur_cli_lib::functions::normalize_path::normalize_path;
7use luaur_cli_lib::functions::read_file::read_file;
8use luaur_code_gen::functions::luau_codegen_compile::luau_codegen_compile;
9use luaur_compiler::functions::compile::compile;
10use luaur_vm::enums::lua_status::lua_Status;
11use luaur_vm::functions::lua_debugtrace::lua_debugtrace;
12use luaur_vm::functions::lua_l_sandboxthread::lua_l_sandboxthread;
13use luaur_vm::functions::lua_newthread::lua_newthread;
14use luaur_vm::functions::lua_resume::lua_resume;
15use luaur_vm::functions::luau_load::luau_load;
16use luaur_vm::macros::lua_pop::lua_pop;
17use luaur_vm::macros::lua_tostring::lua_tostring;
18use luaur_vm::type_aliases::lua_state::lua_State;
19
20use crate::functions::copts::copts;
21use crate::functions::counters_active::counters_active;
22use crate::functions::counters_track::counters_track;
23use crate::functions::coverage_active::coverage_active;
24use crate::functions::coverage_track::coverage_track;
25use crate::functions::repl_main::{program_argc, program_argv, repl_codegen_enabled};
26use crate::functions::run_repl_impl::run_repl_impl;
27use crate::functions::setup_arguments::setup_arguments;
28
29// `repl` is used to indicate if a repl should be started after executing the file.
30pub unsafe fn run_file(name: &str, gl: *mut lua_State, repl: bool) -> bool {
31    let source = read_file(name);
32    let source = match source {
33        Some(s) => s,
34        None => {
35            eprintln!("Error opening {}", name);
36            return false;
37        }
38    };
39
40    // module needs to run in a new thread, isolated from the rest
41    let l = lua_newthread(gl);
42
43    // new thread needs to have the globals sandboxed
44    lua_l_sandboxthread(l);
45
46    let chunkname = String::from("@") + &normalize_path(name) + "\0";
47
48    struct NoopEncoder;
49    impl BytecodeEncoder for NoopEncoder {
50        fn encode(&mut self, _data: &mut [u32]) {}
51    }
52    let options = copts();
53    let parse_options = ParseOptions::default();
54    let mut encoder = NoopEncoder;
55    let bytecode = compile(
56        &source,
57        &options,
58        &parse_options,
59        &mut encoder as *mut dyn BytecodeEncoder,
60    );
61
62    let status: i32 = if luau_load(
63        l,
64        chunkname.as_ptr() as *const c_char,
65        bytecode.as_ptr() as *const c_char,
66        bytecode.len(),
67        0,
68    ) == 0
69    {
70        if repl_codegen_enabled() {
71            // C++ sets CodeGen_ColdFunctions / recordCounters on the
72            // CompilationOptions; the public Rust codegen API takes neither.
73            luau_codegen_compile(l, -1);
74        }
75
76        if coverage_active() {
77            coverage_track(l, -1);
78        }
79
80        if counters_active() {
81            counters_track(l, -1);
82        }
83
84        setup_arguments(l, program_argc(), program_argv());
85        lua_resume(l, core::ptr::null_mut(), program_argc())
86    } else {
87        lua_Status::LUA_ERRSYNTAX as i32
88    };
89
90    if status != 0 {
91        let mut error: String;
92
93        if status == lua_Status::LUA_YIELD as i32 {
94            error = "thread yielded unexpectedly".into();
95        } else {
96            let str_ptr = lua_tostring!(l, -1);
97            if !str_ptr.is_null() {
98                error = CStr::from_ptr(str_ptr).to_string_lossy().into_owned();
99            } else {
100                error = String::new();
101            }
102        }
103
104        error.push_str("\nstacktrace:\n");
105        let trace = lua_debugtrace(l);
106        if !trace.is_null() {
107            error.push_str(&CStr::from_ptr(trace).to_string_lossy());
108        }
109
110        eprint!("{}", error);
111    }
112
113    if repl {
114        run_repl_impl(l);
115    }
116    lua_pop(gl, 1);
117    status == 0
118}