diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-09-20 19:49:47 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-09-20 19:49:47 +0200 |
| commit | 3760748fddd3b793c79c370398a9d4a3fc5afc04 (patch) | |
| tree | b1a615e510aa231cfe9757a9c0a35a375e32e3ba /src/library/utility | |
| parent | 757a701c1aa2a6fb80033c7e75666661818da6f9 (diff) | |
Refactor error handling
Diffstat (limited to 'src/library/utility')
| -rw-r--r-- | src/library/utility/color.rs | 6 | ||||
| -rw-r--r-- | src/library/utility/data.rs | 47 | ||||
| -rw-r--r-- | src/library/utility/math.rs | 20 | ||||
| -rw-r--r-- | src/library/utility/mod.rs | 8 | ||||
| -rw-r--r-- | src/library/utility/string.rs | 16 |
5 files changed, 55 insertions, 42 deletions
diff --git a/src/library/utility/color.rs b/src/library/utility/color.rs index a7d55d1c..a5a5704d 100644 --- a/src/library/utility/color.rs +++ b/src/library/utility/color.rs @@ -3,13 +3,13 @@ use std::str::FromStr; use crate::library::prelude::*; /// Create a grayscale color. -pub fn luma(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn luma(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Component(luma) = args.expect("gray component")?; Ok(Value::Color(LumaColor::new(luma).into())) } /// Create an RGB(A) color. -pub fn rgb(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn rgb(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(Value::Color( if let Some(string) = args.find::<Spanned<EcoString>>()? { match RgbaColor::from_str(&string.v) { @@ -27,7 +27,7 @@ pub fn rgb(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Create a CMYK color. -pub fn cmyk(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn cmyk(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let RatioComponent(c) = args.expect("cyan component")?; let RatioComponent(m) = args.expect("magenta component")?; let RatioComponent(y) = args.expect("yellow component")?; diff --git a/src/library/utility/data.rs b/src/library/utility/data.rs index 59f3d351..1ae8949a 100644 --- a/src/library/utility/data.rs +++ b/src/library/utility/data.rs @@ -1,30 +1,43 @@ +use std::fmt::Write; + use crate::library::prelude::*; /// Read structured data from a CSV file. -pub fn csv(vm: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn csv(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: path, span } = args.expect::<Spanned<EcoString>>("path to csv file")?; let path = vm.locate(&path).at(span)?; - let try_load = || -> io::Result<Value> { - let data = vm.world.file(&path)?; + let data = vm.world.file(&path).at(span)?; - let mut builder = csv::ReaderBuilder::new(); - builder.has_headers(false); + let mut builder = csv::ReaderBuilder::new(); + builder.has_headers(false); - let mut reader = builder.from_reader(data.as_slice()); - let mut vec = vec![]; + let mut reader = builder.from_reader(data.as_slice()); + let mut vec = vec![]; - for result in reader.records() { - vec.push(Value::Array( - result?.iter().map(|field| Value::Str(field.into())).collect(), - )) - } + for result in reader.records() { + let row = result.map_err(format_csv_error).at(span)?; + let array = row.iter().map(|field| Value::Str(field.into())).collect(); + vec.push(Value::Array(array)) + } - Ok(Value::Array(Array::from_vec(vec))) - }; + Ok(Value::Array(Array::from_vec(vec))) +} - try_load() - .map_err(|err| failed_to_load("csv file", &path, err)) - .at(span) +/// Format the user-facing CSV error message. +fn format_csv_error(error: csv::Error) -> String { + match error.kind() { + csv::ErrorKind::Utf8 { .. } => "file is not valid utf-8".into(), + csv::ErrorKind::UnequalLengths { pos, expected_len, len } => { + let mut msg = format!( + "failed to parse csv file: found {len} instead of {expected_len} fields" + ); + if let Some(pos) = pos { + write!(msg, " in line {}", pos.line()).unwrap(); + } + msg + } + _ => "failed to parse csv file".into(), + } } diff --git a/src/library/utility/math.rs b/src/library/utility/math.rs index 47648282..7c3af490 100644 --- a/src/library/utility/math.rs +++ b/src/library/utility/math.rs @@ -3,7 +3,7 @@ use std::cmp::Ordering; use crate::library::prelude::*; /// Convert a value to an integer. -pub fn int(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn int(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("value")?; Ok(Value::Int(match v { Value::Bool(v) => v as i64, @@ -18,7 +18,7 @@ pub fn int(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Convert a value to a float. -pub fn float(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn float(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("value")?; Ok(Value::Float(match v { Value::Int(v) => v as f64, @@ -32,7 +32,7 @@ pub fn float(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// The absolute value of a numeric value. -pub fn abs(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn abs(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("numeric value")?; Ok(match v { Value::Int(v) => Value::Int(v.abs()), @@ -48,17 +48,17 @@ pub fn abs(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// The minimum of a sequence of values. -pub fn min(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn min(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { minmax(args, Ordering::Less) } /// The maximum of a sequence of values. -pub fn max(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn max(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { minmax(args, Ordering::Greater) } /// Find the minimum or maximum of a sequence of values. -fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> { +fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> { let mut extremum = args.expect::<Value>("value")?; for Spanned { v, span } in args.all::<Spanned<Value>>()? { match v.partial_cmp(&extremum) { @@ -79,17 +79,17 @@ fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> { } /// Whether an integer is even. -pub fn even(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn even(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0)) } /// Whether an integer is odd. -pub fn odd(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn odd(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0)) } /// The modulo of two numbers. -pub fn mod_(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn mod_(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: v1, span: span1 } = args.expect("integer or float")?; let Spanned { v: v2, span: span2 } = args.expect("integer or float")?; @@ -119,7 +119,7 @@ pub fn mod_(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Create a sequence of numbers. -pub fn range(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn range(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let first = args.expect::<i64>("end")?; let (start, end) = match args.eat::<i64>()? { Some(second) => (first, second), diff --git a/src/library/utility/mod.rs b/src/library/utility/mod.rs index 40a107ba..3fc413f7 100644 --- a/src/library/utility/mod.rs +++ b/src/library/utility/mod.rs @@ -15,12 +15,12 @@ use crate::library::prelude::*; use crate::source::Source; /// The name of a value's type. -pub fn type_(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn type_(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(args.expect::<Value>("value")?.type_name().into()) } /// Ensure that a condition is fulfilled. -pub fn assert(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn assert(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?; if !v { bail!(span, "assertion failed"); @@ -29,7 +29,7 @@ pub fn assert(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Evaluate a string as Typst markup. -pub fn eval(vm: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn eval(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?; // Parse the source and set a synthetic span for all nodes. @@ -44,7 +44,7 @@ pub fn eval(vm: &mut Vm, args: &mut Args) -> TypResult<Value> { // Handle control flow. if let Some(flow) = sub.flow { - return Err(flow.forbidden()); + bail!(flow.forbidden()); } Ok(Value::Content(result?)) diff --git a/src/library/utility/string.rs b/src/library/utility/string.rs index d825d84b..91a990a9 100644 --- a/src/library/utility/string.rs +++ b/src/library/utility/string.rs @@ -2,12 +2,12 @@ use crate::eval::Regex; use crate::library::prelude::*; /// The string representation of a value. -pub fn repr(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn repr(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { Ok(args.expect::<Value>("value")?.repr().into()) } /// Convert a value to a string. -pub fn str(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn str(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect("value")?; Ok(Value::Str(match v { Value::Int(v) => format_str!("{}", v), @@ -18,33 +18,33 @@ pub fn str(_: &mut Vm, args: &mut Args) -> TypResult<Value> { } /// Create blind text. -pub fn lorem(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn lorem(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let words: usize = args.expect("number of words")?; Ok(Value::Str(lipsum::lipsum(words).into())) } /// Create a regular expression. -pub fn regex(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn regex(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?; Ok(Regex::new(&v).at(span)?.into()) } /// Converts an integer into one or multiple letters. -pub fn letter(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn letter(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { numbered(Numbering::Letter, args) } /// Converts an integer into a roman numeral. -pub fn roman(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn roman(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { numbered(Numbering::Roman, args) } /// Convert a number into a symbol. -pub fn symbol(_: &mut Vm, args: &mut Args) -> TypResult<Value> { +pub fn symbol(_: &mut Vm, args: &mut Args) -> SourceResult<Value> { numbered(Numbering::Symbol, args) } -fn numbered(numbering: Numbering, args: &mut Args) -> TypResult<Value> { +fn numbered(numbering: Numbering, args: &mut Args) -> SourceResult<Value> { let n = args.expect::<usize>("non-negative integer")?; Ok(Value::Str(numbering.apply(n).into())) } |
