Merge pull request #78 from wycats/improved-errors

Improve errors
This commit is contained in:
Yehuda Katz 2019-06-02 22:12:19 -07:00 committed by GitHub
commit b7dbb0a4b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 71 additions and 16 deletions

View file

@ -8,10 +8,10 @@ use crate::context::Context;
crate use crate::errors::ShellError; crate use crate::errors::ShellError;
use crate::evaluate::Scope; use crate::evaluate::Scope;
crate use crate::format::{EntriesListView, GenericView}; crate use crate::format::{EntriesListView, GenericView};
use crate::git::current_branch;
use crate::object::Value; use crate::object::Value;
use crate::parser::{ParsedCommand, Pipeline}; use crate::parser::{ParsedCommand, Pipeline};
use crate::stream::empty_stream; use crate::stream::empty_stream;
use crate::git::current_branch;
use log::debug; use log::debug;
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
@ -86,7 +86,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
context.env.lock().unwrap().cwd().display().to_string(), context.env.lock().unwrap().cwd().display().to_string(),
match current_branch() { match current_branch() {
Some(s) => format!("({})", s), Some(s) => format!("({})", s),
None => "".to_string() None => "".to_string(),
} }
)); ));
@ -110,6 +110,18 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
.unwrap(); .unwrap();
} }
ShellError::TypeError(desc) => context
.host
.lock()
.unwrap()
.stdout(&format!("TypeError: {}", desc)),
ShellError::MissingProperty { subpath, .. } => context
.host
.lock()
.unwrap()
.stdout(&format!("Missing property {}", subpath)),
ShellError::String(s) => context.host.lock().unwrap().stdout(&format!("{:?}", s)), ShellError::String(s) => context.host.lock().unwrap().stdout(&format!("{:?}", s)),
}, },

View file

@ -9,6 +9,8 @@ use serde_derive::{Deserialize, Serialize};
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
pub enum ShellError { pub enum ShellError {
String(StringError), String(StringError),
TypeError(String),
MissingProperty { subpath: String, expr: String },
Diagnostic(ShellDiagnostic, String), Diagnostic(ShellDiagnostic, String),
} }
@ -108,6 +110,8 @@ impl std::fmt::Display for ShellError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
ShellError::String(s) => write!(f, "{}", &s.title), ShellError::String(s) => write!(f, "{}", &s.title),
ShellError::TypeError { .. } => write!(f, "TypeError"),
ShellError::MissingProperty { .. } => write!(f, "MissingProperty"),
ShellError::Diagnostic(_, _) => write!(f, "<diagnostic>"), ShellError::Diagnostic(_, _) => write!(f, "<diagnostic>"),
} }
} }

View file

@ -1,17 +1,21 @@
use crate::object::Primitive;
use crate::parser::ast; use crate::parser::ast;
use crate::prelude::*; use crate::prelude::*;
use crate::object::Primitive;
use derive_new::new; use derive_new::new;
use indexmap::IndexMap;
#[derive(new)] #[derive(new)]
crate struct Scope { crate struct Scope {
it: Value, it: Value,
#[new(default)]
vars: IndexMap<String, Value>,
} }
impl Scope { impl Scope {
crate fn empty() -> Scope { crate fn empty() -> Scope {
Scope { Scope {
it: Value::nothing(), it: Value::nothing(),
vars: IndexMap::new(),
} }
} }
} }
@ -46,10 +50,11 @@ fn evaluate_reference(r: &ast::Variable, scope: &Scope) -> Result<Value, ShellEr
match r { match r {
It => Ok(scope.it.copy()), It => Ok(scope.it.copy()),
Other(s) => Err(ShellError::string(&format!( Other(s) => Ok(scope
"Unimplemented variable reference: {}", .vars
s .get(s)
))), .map(|v| v.copy())
.unwrap_or_else(|| Value::nothing())),
} }
} }
@ -59,9 +64,10 @@ fn evaluate_binary(binary: &ast::Binary, scope: &Scope) -> Result<Value, ShellEr
match left.compare(binary.operator, &right) { match left.compare(binary.operator, &right) {
Some(v) => Ok(Value::boolean(v)), Some(v) => Ok(Value::boolean(v)),
None => Err(ShellError::string(&format!( None => Err(ShellError::TypeError(format!(
"Unimplemented evaluate_binary:\n{:#?}", "Can't compare {} and {}",
binary left.type_name(),
right.type_name()
))), ))),
} }
} }
@ -73,17 +79,18 @@ fn evaluate_block(block: &ast::Block, _scope: &Scope) -> Result<Value, ShellErro
fn evaluate_path(path: &ast::Path, scope: &Scope) -> Result<Value, ShellError> { fn evaluate_path(path: &ast::Path, scope: &Scope) -> Result<Value, ShellError> {
let head = path.head(); let head = path.head();
let mut value = &evaluate_expr(head, scope)?; let mut value = &evaluate_expr(head, scope)?;
let mut seen = vec![];
for name in path.tail() { for name in path.tail() {
let next = value.get_data_by_key(&name); let next = value.get_data_by_key(&name);
seen.push(name);
match next { match next {
None => { None => {
return Err(ShellError::string(&format!( return Err(ShellError::MissingProperty {
"No key {} found in {}", expr: path.print(),
name, subpath: itertools::join(seen, "."),
path.print(), });
)))
} }
Some(v) => value = v, Some(v) => value = v,
} }

View file

@ -63,7 +63,6 @@ fn main() -> Result<(), Box<dyn Error>> {
None => {} None => {}
Some(values) => { Some(values) => {
for item in values { for item in values {
println!("filtering {:?}", item);
builder.filter_module(&format!("nu::{}", item), LevelFilter::Trace); builder.filter_module(&format!("nu::{}", item), LevelFilter::Trace);
} }
} }

View file

@ -60,6 +60,21 @@ impl Serialize for Primitive {
} }
impl Primitive { impl Primitive {
crate fn type_name(&self) -> String {
use Primitive::*;
match self {
Nothing => "nothing",
Int(_) => "int",
Float(_) => "float",
Bytes(_) => "bytes",
String(_) => "string",
Boolean(_) => "boolean",
Date(_) => "date",
}
.to_string()
}
crate fn format(&self, field_name: Option<&str>) -> String { crate fn format(&self, field_name: Option<&str>) -> String {
match self { match self {
Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")), Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")),
@ -142,6 +157,16 @@ pub enum Value {
} }
impl Value { impl Value {
crate fn type_name(&self) -> String {
match self {
Value::Primitive(p) => p.type_name(),
Value::Object(_) => format!("object"),
Value::List(_) => format!("list"),
Value::Block(_) => format!("block"),
Value::Error(_) => format!("error"),
}
}
crate fn data_descriptors(&self) -> Vec<DataDescriptor> { crate fn data_descriptors(&self) -> Vec<DataDescriptor> {
match self { match self {
Value::Primitive(_) => vec![DataDescriptor::value_of()], Value::Primitive(_) => vec![DataDescriptor::value_of()],

View file

@ -206,6 +206,7 @@ pub enum Variable {
Other(String), Other(String),
} }
#[cfg(test)]
crate fn var(name: &str) -> Expression { crate fn var(name: &str) -> Expression {
match name { match name {
"it" => Expression::VariableReference(Variable::It), "it" => Expression::VariableReference(Variable::It),
@ -235,6 +236,7 @@ impl Variable {
} }
} }
#[cfg(test)]
pub fn bare(s: &str) -> BarePath { pub fn bare(s: &str) -> BarePath {
BarePath { BarePath {
head: s.into(), head: s.into(),
@ -296,6 +298,7 @@ impl Unit {
} }
} }
#[cfg(test)]
pub fn unit(num: i64, unit: impl Into<Unit>) -> Expression { pub fn unit(num: i64, unit: impl Into<Unit>) -> Expression {
Expression::Leaf(Leaf::Unit(num, unit.into())) Expression::Leaf(Leaf::Unit(num, unit.into()))
} }
@ -360,6 +363,7 @@ impl Binary {
} }
} }
#[cfg(test)]
crate fn binary( crate fn binary(
left: impl Into<Expression>, left: impl Into<Expression>,
operator: impl Into<Operator>, operator: impl Into<Operator>,
@ -398,10 +402,12 @@ pub enum Flag {
Longhand(String), Longhand(String),
} }
#[cfg(test)]
crate fn flag(s: &str) -> Flag { crate fn flag(s: &str) -> Flag {
Flag::Longhand(s.into()) Flag::Longhand(s.into())
} }
#[cfg(test)]
crate fn short(s: &str) -> Flag { crate fn short(s: &str) -> Flag {
Flag::Shorthand(s.into()) Flag::Shorthand(s.into())
} }
@ -428,6 +434,7 @@ pub struct ParsedCommand {
} }
impl ParsedCommand { impl ParsedCommand {
#[allow(unused)]
fn print(&self) -> String { fn print(&self) -> String {
let mut out = vec![]; let mut out = vec![];
@ -472,6 +479,7 @@ impl Pipeline {
Pipeline { commands } Pipeline { commands }
} }
#[allow(unused)]
crate fn print(&self) -> String { crate fn print(&self) -> String {
itertools::join(self.commands.iter().map(|i| i.print()), " | ") itertools::join(self.commands.iter().map(|i| i.print()), " | ")
} }