difftreelog
feat(evaluator) readable error messages
in: master
6 files changed
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -37,6 +37,8 @@
base64 = "0.12.3"
rustc-hash = "1.1.0"
+thiserror = "1.0.20"
+
# Serialized stdlib
[dependencies.serde]
version = "1.0.115"
crates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/format.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/format.rs
@@ -2,16 +2,23 @@
#![allow(clippy::too_many_arguments)]
use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val, ValType};
+use thiserror::Error;
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Error)]
pub enum FormatError {
+ #[error("truncated format code")]
TruncatedFormatCode,
+ #[error("unrecognized conversion type: {0}")]
UnrecognizedConversionType(char),
+ #[error("not enough values")]
NotEnoughValues,
+ #[error("cannot use * width with object")]
CannotUseStarWidthWithObject,
+ #[error("mapping keys required")]
MappingKeysRequired,
+ #[error("no such format field: {0}")]
NoSuchFormatField(Rc<str>),
}
crates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth1use crate::{2 error::{Error, LocError, Result},3 throw, Context, FuncVal, Val,4};5use std::rc::Rc;67#[derive(Debug, Clone)]8pub enum SortError {9 SortKeyShouldBeStringOrNumber,10 SortElementsShouldHaveEqualType,11}1213impl From<SortError> for LocError {14 fn from(s: SortError) -> Self {15 Self::new(Error::Sort(s))16 }17}1819#[derive(Copy, Clone)]20enum SortKeyType {21 Number,22 String,23 Unknown,24}2526#[derive(PartialEq)]27struct NonNaNF64(f64);28impl PartialOrd for NonNaNF64 {29 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {30 self.0.partial_cmp(&other.0)31 }32}33impl Eq for NonNaNF64 {}34impl Ord for NonNaNF64 {35 fn cmp(&self, other: &Self) -> std::cmp::Ordering {36 self.partial_cmp(other).expect("non nan")37 }38}3940fn get_sort_type<T>(41 values: &mut Vec<T>,42 key_getter: impl Fn(&mut T) -> &mut Val,43) -> Result<SortKeyType> {44 let mut sort_type = SortKeyType::Unknown;45 for i in values.iter_mut() {46 let i = key_getter(i);47 i.inplace_unwrap()?;48 match (i, sort_type) {49 (Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,50 (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,51 (Val::Str(_), SortKeyType::String) => {}52 (Val::Str(_), _) => throw!(SortError::SortElementsShouldHaveEqualType),53 (Val::Num(_), SortKeyType::Number) => {}54 (Val::Num(_), _) => throw!(SortError::SortElementsShouldHaveEqualType),55 _ => throw!(SortError::SortKeyShouldBeStringOrNumber),56 }57 }58 Ok(sort_type)59}6061pub fn sort(ctx: Context, mut values: Rc<Vec<Val>>, key_getter: &FuncVal) -> Result<Rc<Vec<Val>>> {62 if values.len() <= 1 {63 return Ok(values);64 }65 if key_getter.is_ident() {66 let mvalues = Rc::make_mut(&mut values);67 let sort_type = get_sort_type(mvalues, |k| k)?;68 match sort_type {69 SortKeyType::Number => mvalues.sort_by_key(|v| match v {70 Val::Num(n) => NonNaNF64(*n),71 _ => unreachable!(),72 }),73 SortKeyType::String => mvalues.sort_by_key(|v| match v {74 Val::Str(s) => s.clone(),75 _ => unreachable!(),76 }),77 SortKeyType::Unknown => unreachable!(),78 };79 Ok(values)80 } else {81 let mut vk = Vec::with_capacity(values.len());82 for value in values.iter() {83 vk.push((84 value.clone(),85 key_getter.evaluate_values(ctx.clone(), &[value.clone()])?,86 ));87 }88 let sort_type = get_sort_type(&mut vk, |v| &mut v.1)?;89 match sort_type {90 SortKeyType::Number => vk.sort_by_key(|v| match v.1 {91 Val::Num(n) => NonNaNF64(n),92 _ => unreachable!(),93 }),94 SortKeyType::String => vk.sort_by_key(|v| match &v.1 {95 Val::Str(s) => s.clone(),96 _ => unreachable!(),97 }),98 SortKeyType::Unknown => unreachable!(),99 };100 Ok(Rc::new(vk.into_iter().map(|v| v.0).collect()))101 }102}1use crate::{2 error::{Error, LocError, Result},3 throw, Context, FuncVal, Val,4};5use std::rc::Rc;67#[derive(Debug, Clone, thiserror::Error)]8pub enum SortError {9 #[error("sort key should be string or number")]10 SortKeyShouldBeStringOrNumber,11 #[error("sort elements should have equal types")]12 SortElementsShouldHaveEqualType,13}1415impl From<SortError> for LocError {16 fn from(s: SortError) -> Self {17 Self::new(Error::Sort(s))18 }19}2021#[derive(Copy, Clone)]22enum SortKeyType {23 Number,24 String,25 Unknown,26}2728#[derive(PartialEq)]29struct NonNaNF64(f64);30impl PartialOrd for NonNaNF64 {31 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {32 self.0.partial_cmp(&other.0)33 }34}35impl Eq for NonNaNF64 {}36impl Ord for NonNaNF64 {37 fn cmp(&self, other: &Self) -> std::cmp::Ordering {38 self.partial_cmp(other).expect("non nan")39 }40}4142fn get_sort_type<T>(43 values: &mut Vec<T>,44 key_getter: impl Fn(&mut T) -> &mut Val,45) -> Result<SortKeyType> {46 let mut sort_type = SortKeyType::Unknown;47 for i in values.iter_mut() {48 let i = key_getter(i);49 i.inplace_unwrap()?;50 match (i, sort_type) {51 (Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,52 (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,53 (Val::Str(_), SortKeyType::String) => {}54 (Val::Str(_), _) => throw!(SortError::SortElementsShouldHaveEqualType),55 (Val::Num(_), SortKeyType::Number) => {}56 (Val::Num(_), _) => throw!(SortError::SortElementsShouldHaveEqualType),57 _ => throw!(SortError::SortKeyShouldBeStringOrNumber),58 }59 }60 Ok(sort_type)61}6263pub fn sort(ctx: Context, mut values: Rc<Vec<Val>>, key_getter: &FuncVal) -> Result<Rc<Vec<Val>>> {64 if values.len() <= 1 {65 return Ok(values);66 }67 if key_getter.is_ident() {68 let mvalues = Rc::make_mut(&mut values);69 let sort_type = get_sort_type(mvalues, |k| k)?;70 match sort_type {71 SortKeyType::Number => mvalues.sort_by_key(|v| match v {72 Val::Num(n) => NonNaNF64(*n),73 _ => unreachable!(),74 }),75 SortKeyType::String => mvalues.sort_by_key(|v| match v {76 Val::Str(s) => s.clone(),77 _ => unreachable!(),78 }),79 SortKeyType::Unknown => unreachable!(),80 };81 Ok(values)82 } else {83 let mut vk = Vec::with_capacity(values.len());84 for value in values.iter() {85 vk.push((86 value.clone(),87 key_getter.evaluate_values(ctx.clone(), &[value.clone()])?,88 ));89 }90 let sort_type = get_sort_type(&mut vk, |v| &mut v.1)?;91 match sort_type {92 SortKeyType::Number => vk.sort_by_key(|v| match v.1 {93 Val::Num(n) => NonNaNF64(n),94 _ => unreachable!(),95 }),96 SortKeyType::String => vk.sort_by_key(|v| match &v.1 {97 Val::Str(s) => s.clone(),98 _ => unreachable!(),99 }),100 SortKeyType::Unknown => unreachable!(),101 };102 Ok(Rc::new(vk.into_iter().map(|v| v.0).collect()))103 }104}crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/ctx.rs
+++ b/crates/jrsonnet-evaluator/src/ctx.rs
@@ -63,7 +63,7 @@
.bindings
.get(&name)
.cloned()
- .ok_or_else(|| UnknownVariable(name))?)
+ .ok_or_else(|| VariableIsNotDefined(name))?)
}
pub fn into_future(self, ctx: FutureContext) -> Self {
{
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -4,75 +4,117 @@
};
use jrsonnet_parser::{BinaryOpType, ExprLocation, UnaryOpType};
use std::{path::PathBuf, rc::Rc};
+use thiserror::Error;
-#[derive(Debug, Clone)]
+#[derive(Error, Debug, Clone)]
pub enum Error {
+ #[error("intrinsic not found: {0}.{1}")]
IntrinsicNotFound(Rc<str>, Rc<str>),
+ #[error("argument reordering in intrisics not supported yet")]
IntrinsicArgumentReorderingIsNotSupportedYet,
+ #[error("operator {0} does not operate on type {1}")]
UnaryOperatorDoesNotOperateOnType(UnaryOpType, ValType),
+ #[error("binary operation {1} {0} {2} is not implemented")]
BinaryOperatorDoesNotOperateOnValues(BinaryOpType, ValType, ValType),
+ #[error("no top level object in this context")]
NoTopLevelObjectFound,
+ #[error("self is only usable inside objects")]
CantUseSelfOutsideOfObject,
+ #[error("super is only usable inside objects")]
CantUseSuperOutsideOfObject,
+ #[error("for loop can only iterate over arrays")]
InComprehensionCanOnlyIterateOverArray,
+ #[error("array out of bounds: {0} is not within [0,{1})")]
ArrayBoundsError(usize, usize),
+ #[error("assert failed: {0}")]
AssertionFailed(Rc<str>),
- VariableIsNotDefined(String),
+ #[error("variable is not defined: {0}")]
+ VariableIsNotDefined(Rc<str>),
+ #[error("type mismatch: expected {2}, got {1:?} {0}")]
TypeMismatch(&'static str, Vec<ValType>, ValType),
+ #[error("no such field: {0}")]
NoSuchField(Rc<str>),
- UnknownVariable(Rc<str>),
-
+ #[error("only functions can be called, got {0}")]
OnlyFunctionsCanBeCalledGot(ValType),
+ #[error("parameter {0} is not defined")]
UnknownFunctionParameter(String),
+ #[error("argument {0} is already bound")]
BindingParameterASecondTime(Rc<str>),
+ #[error("too many args, function has {0}")]
TooManyArgsFunctionHas(usize),
+ #[error("founction argument is not passed: {0}")]
FunctionParameterNotBoundInCall(Rc<str>),
+ #[error("external variable is not defined: {0}")]
UndefinedExternalVariable(Rc<str>),
+ #[error("native is not defined: {0}")]
UndefinedExternalFunction(Rc<str>),
+ #[error("field name should be string, got {0}")]
FieldMustBeStringGot(ValType),
+ #[error("attempted to index array with string {0}")]
AttemptedIndexAnArrayWithString(Rc<str>),
+ #[error("{0} index type should be {1}, got {2}")]
ValueIndexMustBeTypeGot(ValType, ValType, ValType),
+ #[error("cant index into {0}")]
CantIndexInto(ValType),
+ #[error("super can't be used standalone")]
StandaloneSuper,
+ #[error("can't resolve {1} from {0}")]
ImportFileNotFound(PathBuf, PathBuf),
+ #[error("resolved file not found: {0}")]
ResolvedFileNotFound(PathBuf),
+ #[error("imported file is not valid utf-8: {0:?}")]
ImportBadFileUtf8(PathBuf),
+ #[error("tried to import {1} from {0}, but imports is not supported")]
ImportNotSupported(PathBuf, PathBuf),
+ #[error("syntax error")]
ImportSyntaxError {
path: Rc<PathBuf>,
source_code: Rc<str>,
error: Box<jrsonnet_parser::ParseError>,
},
+ #[error("runtime error: {0}")]
RuntimeError(Rc<str>),
+ #[error("stack overflow, try to reduce recursion, or set --max-stack to bigger value")]
StackOverflow,
+ #[error("tried to index by fractional value")]
FractionalIndex,
+ #[error("attempted to divide by zero")]
DivisionByZero,
+ #[error("string manifest output is not an string")]
StringManifestOutputIsNotAString,
+ #[error("stream manifest output is not an array")]
StreamManifestOutputIsNotAArray,
+ #[error("multi manifest output is not an object")]
MultiManifestOutputIsNotAObject,
+ #[error("cant recurse stream manifest")]
StreamManifestOutputCannotBeRecursed,
+ #[error("stream manifest output cannot consist of raw strings")]
StreamManifestCannotNestString,
+ #[error("{0}")]
ImportCallbackError(String),
+ #[error("invalid unicode codepoint: {0}")]
InvalidUnicodeCodepointGot(u32),
- Format(FormatError),
- Sort(SortError),
+ #[error("format error: {0}")]
+ Format(#[from] FormatError),
+ #[error("sort error: {0}")]
+ Sort(#[from] SortError),
}
impl From<Error> for LocError {
fn from(e: Error) -> Self {
crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/trace/mod.rs
+++ b/crates/jrsonnet-evaluator/src/trace/mod.rs
@@ -86,7 +86,7 @@
evaluation_state: &EvaluationState,
error: &LocError,
) -> Result<(), std::fmt::Error> {
- writeln!(out, "{:?}", error.error())?;
+ writeln!(out, "{}", error.error())?;
let file_names = error
.trace()
.0
@@ -132,7 +132,7 @@
evaluation_state: &EvaluationState,
error: &LocError,
) -> Result<(), std::fmt::Error> {
- writeln!(out, "{:?}", error.error())?;
+ writeln!(out, "{}", error.error())?;
for (i, item) in error.trace().0.iter().enumerate() {
if i != 0 {
writeln!(out)?;
@@ -171,7 +171,7 @@
display_list::{DisplayList, FormatOptions},
snippet::{AnnotationType, Slice, Snippet, SourceAnnotation},
};
- writeln!(out, "{:?}", error.error())?;
+ writeln!(out, "{}", error.error())?;
let trace = &error.trace();
for item in trace.0.iter() {
let desc = &item.desc;