Prepare for task scheduler, improve error formatting

This commit is contained in:
Filip Tibell 2023-01-21 16:40:57 -05:00
parent 7aa35d8130
commit 7814282d3d
No known key found for this signature in database
5 changed files with 75 additions and 79 deletions

View file

@ -3,7 +3,7 @@ use std::fs::read_to_string;
use anyhow::Result;
use clap::{CommandFactory, Parser};
use lune::Lune;
use lune::run_lune;
use crate::utils::{files::find_parse_file_path, github::Client as GithubClient};
@ -96,11 +96,7 @@ impl Cli {
// Display the file path relative to cwd with no extensions in stack traces
let file_display_name = file_path.with_extension("").display().to_string();
// Create a new lune object with all globals & run the script
Lune::new()?
.with_args(self.script_args)?
.with_default_globals()?
.run_with_name(&file_contents, &file_display_name)
.await?;
run_lune(&file_display_name, &file_contents, self.script_args).await?;
Ok(())
}
}

View file

@ -9,3 +9,5 @@ pub use fs::new as new_fs;
pub use net::new as new_net;
pub use process::new as new_process;
pub use task::new as new_task;
pub use task::WaitingThread as WaitingTaskThread;

View file

@ -1,13 +1,24 @@
use std::time::Duration;
use std::{
sync::{Arc, Mutex},
time::Duration,
};
use mlua::{Function, Lua, Result, Table, Value, Variadic};
use mlua::{Function, Lua, Result, Table, Thread, Value, Variadic};
use tokio::time;
use crate::utils::table_builder::ReadonlyTableBuilder;
const DEFAULT_SLEEP_DURATION: f32 = 1.0 / 60.0;
pub fn new(lua: &Lua) -> Result<Table> {
pub struct WaitingThread<'a> {
is_delayed_for: Option<f32>,
is_deferred: Option<bool>,
thread: Thread<'a>,
args: Variadic<Value<'a>>,
}
pub fn new<'a>(lua: &'a Lua, threads: &Arc<Mutex<Vec<WaitingThread<'a>>>>) -> Result<Table<'a>> {
// TODO: Figure out how to insert into threads vec
ReadonlyTableBuilder::new(lua)?
.with_async_function(
"defer",

View file

@ -1,4 +1,6 @@
use anyhow::Result;
use std::sync::{Arc, Mutex};
use anyhow::{bail, Result};
use mlua::Lua;
pub mod globals;
@ -6,63 +8,39 @@ pub mod utils;
use crate::{
globals::{new_console, new_fs, new_net, new_process, new_task},
utils::formatting::{pretty_print_luau_error, print_label},
utils::formatting::{format_label, pretty_format_luau_error},
};
pub struct Lune {
lua: Lua,
args: Vec<String>,
}
impl Lune {
pub fn new() -> Result<Self> {
pub async fn run_lune(name: &str, chunk: &str, args: Vec<String>) -> Result<()> {
let lua = Lua::new();
let threads = Arc::new(Mutex::new(Vec::new()));
lua.sandbox(true)?;
Ok(Self { lua, args: vec![] })
}
pub fn with_args(mut self, args: Vec<String>) -> Result<Self> {
self.args = args;
Ok(self)
}
pub fn with_default_globals(self) -> Result<Self> {
// Add in all globals
{
let globals = self.lua.globals();
globals.raw_set("console", new_console(&self.lua)?)?;
globals.raw_set("fs", new_fs(&self.lua)?)?;
globals.raw_set("net", new_net(&self.lua)?)?;
globals.raw_set("process", new_process(&self.lua, self.args.clone())?)?;
globals.raw_set("task", new_task(&self.lua)?)?;
let globals = lua.globals();
globals.raw_set("console", new_console(&lua)?)?;
globals.raw_set("fs", new_fs(&lua)?)?;
globals.raw_set("net", new_net(&lua)?)?;
globals.raw_set("process", new_process(&lua, args.clone())?)?;
globals.raw_set("task", new_task(&lua, &threads)?)?;
globals.set_readonly(true);
}
Ok(self)
}
pub async fn run(&self, chunk: &str) -> Result<()> {
self.handle_result(self.lua.load(chunk).exec_async().await)
}
pub async fn run_with_name(&self, chunk: &str, name: &str) -> Result<()> {
self.handle_result(self.lua.load(chunk).set_name(name)?.exec_async().await)
}
fn handle_result(&self, result: mlua::Result<()>) -> Result<()> {
// Run the requested chunk asynchronously
let result = lua.load(chunk).set_name(name)?.exec_async().await;
match result {
Ok(_) => Ok(()),
Err(e) => {
eprintln!();
print_label("ERROR").unwrap();
eprintln!();
pretty_print_luau_error(&e);
Err(e.into())
}
}
Err(e) => bail!(
"\n{}\n{}",
format_label("ERROR"),
pretty_format_luau_error(&e)
),
}
}
#[cfg(test)]
mod tests {
use crate::run_lune;
macro_rules! run_tests {
($($name:ident: $value:expr,)*) => {
$(
@ -75,16 +53,10 @@ mod tests {
let path = std::env::current_dir()
.unwrap()
.join(format!("src/tests/{}.luau", $value));
let lune = crate::Lune::new()
.unwrap()
.with_args(args)
.unwrap()
.with_default_globals()
.unwrap();
let script = tokio::fs::read_to_string(&path)
.await
.unwrap();
if let Err(e) = lune.run_with_name(&script, $value).await {
if let Err(e) = run_lune($value, &script, args).await {
panic!("Test '{}' failed!\n{}", $value, e.to_string())
}
}

View file

@ -39,8 +39,8 @@ fn can_be_plain_lua_table_key(s: &mlua::String) -> bool {
}
}
pub fn print_label<S: AsRef<str>>(s: S) -> mlua::Result<()> {
print!(
pub fn format_label<S: AsRef<str>>(s: S) -> String {
format!(
"{}[{}{}{}{}]{} ",
STYLE_BOLD,
match s.as_ref().to_ascii_lowercase().as_str() {
@ -53,7 +53,11 @@ pub fn print_label<S: AsRef<str>>(s: S) -> mlua::Result<()> {
COLOR_RESET,
STYLE_BOLD,
STYLE_RESET
);
)
}
pub fn print_label<S: AsRef<str>>(s: S) -> mlua::Result<()> {
print!("{}", format_label(s));
flush_stdout()?;
Ok(())
}
@ -186,34 +190,45 @@ pub fn pretty_format_multi_value(multi: &MultiValue) -> mlua::Result<String> {
Ok(buffer)
}
pub fn pretty_print_luau_error(e: &mlua::Error) {
pub fn pretty_format_luau_error(e: &mlua::Error) -> String {
match e {
mlua::Error::RuntimeError(e) => {
eprintln!("{e}");
let err_string = e.to_string();
let mut err_lines = err_string.lines().collect::<Vec<_>>();
for (index, line) in err_lines.clone().iter().enumerate().rev() {
if *line == "stack traceback:" {
err_lines[index] = "Stack Begin";
break;
}
}
err_lines.push("Stack End");
err_lines.join("\n")
}
mlua::Error::CallbackError { cause, traceback } => {
pretty_print_luau_error(cause.as_ref());
eprintln!("Traceback:");
eprintln!("{}", traceback.strip_prefix("stack traceback:\n").unwrap());
format!(
"{}\nStack Begin{}Stack End",
pretty_format_luau_error(cause.as_ref()),
traceback.strip_prefix("stack traceback:\n").unwrap()
)
}
mlua::Error::ToLuaConversionError { from, to, message } => {
let msg = message
.clone()
.map_or_else(String::new, |m| format!("\nDetails:\n\t{m}"));
eprintln!(
format!(
"Failed to convert Rust type '{}' into Luau type '{}'!{}",
from, to, msg
);
)
}
mlua::Error::FromLuaConversionError { from, to, message } => {
let msg = message
.clone()
.map_or_else(String::new, |m| format!("\nDetails:\n\t{m}"));
eprintln!(
format!(
"Failed to convert Luau type '{}' into Rust type '{}'!{}",
from, to, msg
);
)
}
e => eprintln!("{e}"),
e => format!("{e}"),
}
}