diff options
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/args.rs | 39 | ||||
| -rw-r--r-- | src/eval/convert.rs | 11 | ||||
| -rw-r--r-- | src/eval/state.rs | 2 | ||||
| -rw-r--r-- | src/eval/value.rs | 28 |
4 files changed, 57 insertions, 23 deletions
diff --git a/src/eval/args.rs b/src/eval/args.rs index d71cc374..b89ee61f 100644 --- a/src/eval/args.rs +++ b/src/eval/args.rs @@ -2,7 +2,9 @@ use std::mem; -use super::*; +use super::{Convert, RefKey, ValueDict}; +use crate::layout::LayoutContext; +use crate::syntax::{SpanWith, Spanned}; /// A wrapper around a dictionary value that simplifies argument parsing in /// functions. @@ -21,14 +23,44 @@ impl Args { { self.0.v.remove(key).and_then(|entry| { let span = entry.value.span; - let (t, diag) = T::convert(entry.value); + let (result, diag) = T::convert(entry.value); if let Some(diag) = diag { ctx.f.diags.push(diag.span_with(span)) } - t.ok() + result.ok() }) } + /// This is the same as [`get`], except that it generates an error about a + /// missing argument with the given `name` if the key does not exist. + /// + /// [`get`]: #method.get + pub fn need<'a, K, T>( + &mut self, + ctx: &mut LayoutContext, + key: K, + name: &str, + ) -> Option<T> + where + K: Into<RefKey<'a>>, + T: Convert, + { + match self.0.v.remove(key) { + Some(entry) => { + let span = entry.value.span; + let (result, diag) = T::convert(entry.value); + if let Some(diag) = diag { + ctx.f.diags.push(diag.span_with(span)) + } + result.ok() + } + None => { + ctx.f.diags.push(error!(self.0.span, "missing argument: {}", name)); + None + } + } + } + /// Retrieve and remove the first matching positional argument. pub fn find<T>(&mut self) -> Option<T> where @@ -104,6 +136,7 @@ impl Args { #[cfg(test)] mod tests { + use super::super::{Dict, SpannedEntry, Value}; use super::*; fn entry(value: Value) -> SpannedEntry<Value> { diff --git a/src/eval/convert.rs b/src/eval/convert.rs index a32d5912..4c177c5b 100644 --- a/src/eval/convert.rs +++ b/src/eval/convert.rs @@ -4,11 +4,12 @@ use std::ops::Deref; use fontdock::{FontStretch, FontStyle, FontWeight}; -use super::*; +use super::{Value, ValueDict, ValueFunc}; use crate::diag::Diag; use crate::geom::Linear; use crate::layout::{Dir, SpecAlign}; use crate::paper::Paper; +use crate::syntax::{Ident, SpanWith, Spanned, SynTree}; /// Types that values can be converted into. pub trait Convert: Sized { @@ -96,9 +97,9 @@ macro_rules! impl_match { } impl_match!(Value, "value", v => v); -impl_match!(Ident, "ident", Value::Ident(v) => v); +impl_match!(Ident, "identifier", Value::Ident(v) => v); impl_match!(bool, "bool", Value::Bool(v) => v); -impl_match!(i64, "int", Value::Int(v) => v); +impl_match!(i64, "integer", Value::Int(v) => v); impl_match!(f64, "float", Value::Int(v) => v as f64, Value::Float(v) => v, @@ -112,9 +113,9 @@ impl_match!(Linear, "linear", ); impl_match!(String, "string", Value::Str(v) => v); impl_match!(SynTree, "tree", Value::Content(v) => v); -impl_match!(ValueDict, "dict", Value::Dict(v) => v); +impl_match!(ValueDict, "dictionary", Value::Dict(v) => v); impl_match!(ValueFunc, "function", Value::Func(v) => v); -impl_match!(StringLike, "ident or string", +impl_match!(StringLike, "identifier or string", Value::Ident(Ident(v)) => StringLike(v), Value::Str(v) => StringLike(v), ); diff --git a/src/eval/state.rs b/src/eval/state.rs index e4e9f793..3a9f05a4 100644 --- a/src/eval/state.rs +++ b/src/eval/state.rs @@ -1,4 +1,4 @@ -//! State. +//! Evaluation state. use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight}; diff --git a/src/eval/value.rs b/src/eval/value.rs index 2d83c8d0..85cb261c 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -1,4 +1,4 @@ -//! Computational values: Syntactical expressions can be evaluated into these. +//! Computational values. use std::fmt::{self, Debug, Formatter}; use std::ops::Deref; @@ -57,9 +57,9 @@ impl Value { pub fn ty(&self) -> &'static str { match self { Self::None => "none", - Self::Ident(_) => "ident", + Self::Ident(_) => "identifier", Self::Bool(_) => "bool", - Self::Int(_) => "int", + Self::Int(_) => "integer", Self::Float(_) => "float", Self::Relative(_) => "relative", Self::Length(_) => "length", @@ -88,6 +88,9 @@ impl Spanned<Value> { /// the value is represented as layoutable content in a reasonable way. pub fn into_commands(self) -> Vec<Command> { match self.v { + // Don't print out none values. + Value::None => vec![], + // Pass-through. Value::Commands(commands) => commands, Value::Content(tree) => vec![Command::LayoutSyntaxTree(tree)], @@ -109,9 +112,6 @@ impl Spanned<Value> { commands } - // Don't print out none values. - Value::None => vec![], - // Format with debug. val => { let fmt = format!("{:?}", val); @@ -144,6 +144,14 @@ impl Debug for Value { } } +/// A dictionary of values. +/// +/// # Example +/// ```typst +/// (false, 12cm, greeting="hi") +/// ``` +pub type ValueDict = Dict<SpannedEntry<Value>>; + /// An wrapper around a reference-counted executable function value. /// /// The dynamic function object is wrapped in an `Rc` to keep [`Value`] @@ -192,11 +200,3 @@ impl Debug for ValueFunc { f.pad("<function>") } } - -/// A dictionary of values. -/// -/// # Example -/// ```typst -/// (false, 12cm, greeting="hi") -/// ``` -pub type ValueDict = Dict<SpannedEntry<Value>>; |
