Skip to content

Commit 4977b91

Browse files
committed
Detect compilation error and return Result when using Compiler::compile() interface.
Closes #387
1 parent 6317b8e commit 4977b91

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

src/chunk.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,9 @@ impl Compiler {
240240
}
241241

242242
/// Compiles the `source` into bytecode.
243-
pub fn compile(&self, source: impl AsRef<[u8]>) -> Vec<u8> {
243+
///
244+
/// Returns `Error::SyntaxError` if the source code is invalid.
245+
pub fn compile(&self, source: impl AsRef<[u8]>) -> Result<Vec<u8>> {
244246
use std::os::raw::c_int;
245247
use std::ptr;
246248

@@ -274,7 +276,7 @@ impl Compiler {
274276
vec2cstring_ptr!(mutable_globals, mutable_globals_ptr);
275277
vec2cstring_ptr!(userdata_types, userdata_types_ptr);
276278

277-
unsafe {
279+
let bytecode = unsafe {
278280
let mut options = ffi::lua_CompileOptions::default();
279281
options.optimizationLevel = self.optimization_level as c_int;
280282
options.debugLevel = self.debug_level as c_int;
@@ -286,7 +288,19 @@ impl Compiler {
286288
options.mutableGlobals = mutable_globals_ptr;
287289
options.userdataTypes = userdata_types_ptr;
288290
ffi::luau_compile(source.as_ref(), options)
291+
};
292+
293+
if bytecode.first() == Some(&0) {
294+
// The rest of the bytecode is the error message starting with `:`
295+
// See https://github.com/luau-lang/luau/blob/0.640/Compiler/src/Compiler.cpp#L4336
296+
let message = String::from_utf8_lossy(&bytecode[2..]).to_string();
297+
return Err(Error::SyntaxError {
298+
incomplete_input: message.ends_with("<eof>"),
299+
message,
300+
});
289301
}
302+
303+
Ok(bytecode)
290304
}
291305
}
292306

@@ -443,13 +457,12 @@ impl<'a> Chunk<'a> {
443457

444458
/// Compiles the chunk and changes mode to binary.
445459
///
446-
/// It does nothing if the chunk is already binary.
460+
/// It does nothing if the chunk is already binary or invalid.
447461
fn compile(&mut self) {
448462
if let Ok(ref source) = self.source {
449463
if self.detect_mode() == ChunkMode::Text {
450464
#[cfg(feature = "luau")]
451-
{
452-
let data = self.compiler.get_or_insert_with(Default::default).compile(source);
465+
if let Ok(data) = self.compiler.get_or_insert_with(Default::default).compile(source) {
453466
self.source = Ok(Cow::Owned(data));
454467
self.mode = Some(ChunkMode::Binary);
455468
}
@@ -516,6 +529,7 @@ impl<'a> Chunk<'a> {
516529
.compiler
517530
.as_ref()
518531
.map(|c| c.compile(&source))
532+
.transpose()?
519533
.unwrap_or(source);
520534

521535
let name = Self::convert_name(self.name.clone())?;

tests/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ fn test_load_mode() -> Result<()> {
147147
#[cfg(not(feature = "luau"))]
148148
let bytecode = lua.load("return 1 + 1").into_function()?.dump(true);
149149
#[cfg(feature = "luau")]
150-
let bytecode = mlua::Compiler::new().compile("return 1 + 1");
150+
let bytecode = mlua::Compiler::new().compile("return 1 + 1")?;
151151
assert_eq!(lua.load(&bytecode).eval::<i32>()?, 2);
152152
assert_eq!(lua.load(&bytecode).set_mode(ChunkMode::Binary).eval::<i32>()?, 2);
153153
match lua.load(&bytecode).set_mode(ChunkMode::Text).exec() {

0 commit comments

Comments
 (0)