summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/args.rs39
-rw-r--r--src/eval/convert.rs11
-rw-r--r--src/eval/state.rs2
-rw-r--r--src/eval/value.rs28
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>>;