luaur_repl_cli/functions/
run_code.rs1use 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_compiler::functions::compile::compile;
7use luaur_vm::functions::lua_checkstack::lua_checkstack;
8use luaur_vm::functions::lua_debugtrace::lua_debugtrace;
9use luaur_vm::functions::lua_gettop::lua_gettop;
10use luaur_vm::functions::lua_insert::lua_insert;
11use luaur_vm::functions::lua_l_checkstack::lua_l_checkstack;
12use luaur_vm::functions::lua_newthread::lua_newthread;
13use luaur_vm::functions::lua_pcall::lua_pcall;
14use luaur_vm::functions::lua_pushvalue::lua_pushvalue;
15use luaur_vm::functions::lua_remove::lua_remove;
16use luaur_vm::functions::lua_resume::lua_resume;
17use luaur_vm::functions::lua_tolstring::lua_tolstring;
18use luaur_vm::functions::lua_xmove::lua_xmove;
19use luaur_vm::functions::luau_load::luau_load;
20use luaur_vm::macros::lua_getglobal::lua_getglobal;
21use luaur_vm::macros::lua_isnil::lua_isnil;
22use luaur_vm::macros::lua_minstack::LUA_MINSTACK;
23use luaur_vm::macros::lua_pop::lua_pop;
24use luaur_vm::macros::lua_tostring::lua_tostring;
25use luaur_vm::type_aliases::lua_state::lua_State;
26
27use crate::functions::copts::copts;
28
29pub unsafe fn run_code(l: *mut lua_State, source: &str) -> String {
30 lua_checkstack(l, LUA_MINSTACK);
31
32 struct NoopEncoder;
33 impl BytecodeEncoder for NoopEncoder {
34 fn encode(&mut self, _data: &mut [u32]) {}
35 }
36 let options = copts();
37 let parse_options = ParseOptions::default();
38 let mut encoder = NoopEncoder;
39 let source_owned: String = source.into();
40 let bytecode = compile(
41 &source_owned,
42 &options,
43 &parse_options,
44 &mut encoder as *mut dyn BytecodeEncoder,
45 );
46
47 if luau_load(
48 l,
49 c"=stdin".as_ptr(),
50 bytecode.as_ptr() as *const c_char,
51 bytecode.len(),
52 0,
53 ) != 0
54 {
55 let mut len: usize = 0;
56 let msg = lua_tolstring(l, -1, &mut len as *mut usize);
57
58 let error = lua_string_from(msg, len);
59 lua_pop(l, 1);
60
61 return error;
62 }
63
64 let t = lua_newthread(l);
65
66 lua_pushvalue(l, -2);
67 lua_remove(l, -3);
68 lua_xmove(l, t, 1);
69
70 let status = lua_resume(t, core::ptr::null_mut(), 0);
71
72 if status == 0 {
73 let n = lua_gettop(t);
74
75 if n != 0 {
76 lua_l_checkstack(t, LUA_MINSTACK, "too many results to print");
77 lua_getglobal(t, c"_PRETTYPRINT".as_ptr());
78 if lua_isnil!(t, -1) {
80 lua_pop(t, 1);
81 lua_getglobal(t, c"print".as_ptr());
82 }
83 lua_insert(t, 1);
84 lua_pcall(t, n, 0, 0);
85 }
86
87 lua_pop(l, 1);
88 String::new()
89 } else {
90 let mut error: String;
91
92 if status == luaur_vm::enums::lua_status::lua_Status::LUA_YIELD as i32 {
93 error = "thread yielded unexpectedly".into();
94 } else {
95 let str_ptr = lua_tostring!(t, -1);
96 if !str_ptr.is_null() {
97 error = CStr::from_ptr(str_ptr).to_string_lossy().into_owned();
98 } else {
99 error = String::new();
100 }
101 }
102
103 error.push_str("\nstack backtrace:\n");
104 let trace = lua_debugtrace(t);
105 if !trace.is_null() {
106 error.push_str(&CStr::from_ptr(trace).to_string_lossy());
107 }
108
109 lua_pop(l, 1);
110 error
111 }
112}
113
114unsafe fn lua_string_from(msg: *const c_char, len: usize) -> String {
117 if msg.is_null() {
118 return String::new();
119 }
120 let bytes = core::slice::from_raw_parts(msg as *const u8, len);
121 String::from_utf8_lossy(bytes).into_owned()
122}