Refactor script parsing and error handling

integration-not-installation
trivernis 2 years ago
parent a1b8750a8e
commit 69e7b98404
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -1,23 +1,29 @@
use std::path::PathBuf; use std::path::PathBuf;
use miette::Diagnostic; use miette::Diagnostic;
use nu_protocol::ShellError;
use thiserror::Error; use thiserror::Error;
pub type AppResult<T> = std::result::Result<T, AppError>; pub type AppResult<T> = std::result::Result<T, AppError>;
#[derive(Error, Diagnostic, Debug)] #[derive(Error, Diagnostic, Debug)]
pub enum AppError { pub enum AppError {
#[error("Miette error")]
#[diagnostic(code(tourmaline::error))]
Miette(miette::Error),
#[error("Error while evaluating nu script")] #[error("Error while evaluating nu script")]
#[diagnostic()] #[diagnostic()]
Nu(miette::Error), Nu(#[from] ShellError),
#[error("Could not find the script file {0}")] #[error("Could not find the script file")]
ScriptNotFound(PathBuf), ScriptNotFound(PathBuf),
#[diagnostic()] #[diagnostic()]
#[error("Could not parse the source file {0}")] #[error("Could not parse the source file")]
ParseError(#[from] nu_parser::ParseError), ParseError(#[from] nu_parser::ParseError),
#[diagnostic()]
#[error("Could not find the main mehod in the script file {0}")] #[error("Could not find the main mehod in the script file {0}")]
MissingMain(PathBuf), MissingMain(PathBuf),
@ -27,6 +33,6 @@ pub enum AppError {
impl From<miette::Error> for AppError { impl From<miette::Error> for AppError {
fn from(e: miette::Error) -> Self { fn from(e: miette::Error) -> Self {
Self::Nu(e) Self::Miette(e)
} }
} }

@ -4,7 +4,7 @@ use tourmaline::{
}; };
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() { async fn main() -> miette::Result<()> {
color_eyre::install().unwrap(); color_eyre::install().unwrap();
dotenv::dotenv().unwrap(); dotenv::dotenv().unwrap();
let executor = TaskExecutor::new(); let executor = TaskExecutor::new();
@ -24,5 +24,7 @@ async fn main() {
}, },
], ],
}; };
executor.setup_users(user_cfg).await.unwrap(); executor.setup_users(user_cfg).await?;
Ok(())
} }

@ -5,6 +5,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use nu_cli::gather_parent_env_vars;
use tokio::fs; use tokio::fs;
use miette::IntoDiagnostic; use miette::IntoDiagnostic;
@ -72,6 +73,7 @@ impl NuExecutor {
let mut engine_state = nu_command::create_default_context(); let mut engine_state = nu_command::create_default_context();
let mut stack = nu_protocol::engine::Stack::new(); let mut stack = nu_protocol::engine::Stack::new();
let init_cwd = nu_cli::get_init_cwd(); let init_cwd = nu_cli::get_init_cwd();
gather_parent_env_vars(&mut engine_state, &init_cwd);
nu_engine::convert_env_values(&mut engine_state, &mut stack); nu_engine::convert_env_values(&mut engine_state, &mut stack);
let vars = mem::take(&mut self.global_vars); let vars = mem::take(&mut self.global_vars);
@ -87,7 +89,7 @@ impl NuExecutor {
&engine_state, &engine_state,
&mut stack, &mut stack,
&block, &block,
PipelineData::new(Span::new(0, 0)), empty_pipeline(),
false, false,
false, false,
) )
@ -99,17 +101,20 @@ impl NuExecutor {
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
// TODO: Create the AST for the call here instead of parsing it from a string // TODO: Create the AST for the call here instead of parsing it from a string
let args = format!("main {}", args.join(" ")); let args = format!("main {}", args.join(" "));
if !nu_cli::eval_source( let (call_block, working_set) = parse_nu(&mut engine_state, args.as_bytes(), None)?;
&mut engine_state, let delta = working_set.render();
engine_state.merge_delta(delta);
nu_engine::eval_block(
&engine_state,
&mut stack, &mut stack,
args.as_bytes(), &call_block,
"<commandline>", empty_pipeline(),
PipelineData::new(Span::new(0, 0)), false,
) { false,
Err(AppError::FailedToExecuteScript) )?;
} else {
Ok(()) AppResult::Ok(())
}
}) })
.await .await
.unwrap()?; .unwrap()?;
@ -145,31 +150,39 @@ fn add_variables_to_state(
/// Reads the nu script file and /// Reads the nu script file and
/// returns its root block /// returns its root block
async fn read_script_file(path: &Path, engine_state: &mut EngineState) -> AppResult<Block> { async fn read_script_file(path: &Path, engine_state: &mut EngineState) -> AppResult<Block> {
let mut working_set = StateWorkingSet::new(engine_state);
// TODO: Async
let script_contents = fs::read(&path).await.into_diagnostic()?; let script_contents = fs::read(&path).await.into_diagnostic()?;
let string_path = path.to_string_lossy().into_owned(); let string_path = path.to_string_lossy().into_owned();
// parse the source file // parse the source file
let (block, err) = nu_parser::parse( let (block, working_set) = parse_nu(engine_state, &script_contents, Some(&string_path))?;
&mut working_set,
Some(&string_path),
&script_contents,
false,
&[],
);
if let Some(err) = err {
return Err(AppError::from(err));
}
// check if a main method exists in the block // check if a main method exists in the block
if !working_set.find_decl(b"main", &Type::Block).is_some() { if !working_set.find_decl(b"main", &Type::Block).is_some() {
return Err(AppError::MissingMain(PathBuf::from(path))); return Err(AppError::MissingMain(PathBuf::from(path)));
} }
engine_state.merge_delta(working_set.render()); let delta = working_set.render();
engine_state.merge_delta(delta);
Ok(block) Ok(block)
} }
fn parse_nu<'a>(
engine_state: &'a mut EngineState,
script: &[u8],
script_path: Option<&str>,
) -> AppResult<(Block, StateWorkingSet<'a>)> {
let mut working_set = StateWorkingSet::new(engine_state);
let (block, err) = nu_parser::parse(&mut working_set, script_path, script, false, &[]);
if let Some(err) = err {
Err(AppError::from(err))
} else {
Ok((block, working_set))
}
}
fn empty_pipeline() -> PipelineData {
PipelineData::new(Span::new(0, 0))
}
fn map_var_to_value(var: VarValue) -> Value { fn map_var_to_value(var: VarValue) -> Value {
let span = Span::new(0, 0); let span = Span::new(0, 0);

Loading…
Cancel
Save