interpreter/
interpreter.rs1use lunka::prelude::*;
4use std::{
5 env::args,
6 ffi::{
7 CStr, c_int, c_uint,
8 },
9 io::{
10 stderr,
11 Write
12 },
13 process::ExitCode
14};
15
16fn c_eprintln(data: &CStr) {
17 let mut out = stderr();
18 let _ = out.write_all(data.to_bytes());
19 let _ = out.write_all(b"\n");
20}
21
22fn report(lua: &mut LuaThread, status: LuaStatus) -> bool {
23 if !status.is_ok() {
24 if let Some(message) = lua.to_c_str(-1) {
25 c_eprintln(message);
26 }
27 lua.run_managed(|mut mg| unsafe { mg.pop(1) });
28 false
29 } else {
30 true
31 }
32}
33
34unsafe extern "C-unwind" fn l_err_handler(l: *mut LuaState) -> c_int {
35 let lua = unsafe { LuaThread::from_ptr_mut(l) };
36
37 if let Some(msg) = lua.to_c_str(1) {
38 lua.traceback(lua, Some(msg), 1);
39 return 1
40 }
41
42 let ok = lua.run_managed(|mut mg| unsafe {
43 mg.call_metamethod(1, c"__tostring")
44 });
45
46 if ok && lua.type_of(-1) == LuaType::String {
47 return 1
48 }
49
50 unsafe { lua_push_fmt_string!(lua, c"(error object is a %s value)", lua.type_name_of(1)) };
51
52 1
53}
54
55unsafe extern "C-unwind" fn l_main(l: *mut LuaState) -> c_int {
56 let lua = unsafe { LuaThread::from_ptr_mut(l) };
57
58 lua.check_version();
59 lua.run_managed(|mut mg| mg.open_libs());
60
61 lua.push_c_function(l_err_handler);
62 let base = lua.top();
63
64 let mut arguments = args().skip(1);
65 let load_status = if let Some(mut file_name) = arguments.next() {
66 lua.load_file(unsafe {
67 file_name.push('\0');
68 CStr::from_bytes_until_nul(file_name.as_bytes()).unwrap_unchecked()
69 })
70 } else {
71 lua.load_stdin()
72 };
73
74 if !report(lua, load_status) {
75 return 0
76 }
77
78 let mut arg_count: c_uint = 0;
79 for arg in arguments {
80 lua.push_string(arg.as_bytes());
81 arg_count += 1;
82 }
83
84 let run_status = lua.run_managed(|mut mg| {
85 mg.restart_gc();
86 let run_status = unsafe { mg.pcall(arg_count, 0, base) };
87 mg.stop_gc();
88 run_status
89 });
90 if !report(lua, run_status) {
91 return 0
92 }
93
94 lua.push_boolean(true);
95 1
96}
97
98fn main() -> ExitCode {
99 let mut lua = Lua::new();
100
101 lua.push_c_function(l_main);
102 let status = lua.run_managed(|mut mg| unsafe { mg.pcall(0, 1, 0) });
103 let is_ok = lua.to_boolean(-1);
104 report(&mut lua, status);
105
106 if status.is_ok() && is_ok {
107 ExitCode::SUCCESS
108 } else {
109 ExitCode::FAILURE
110 }
111}