diff options
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/cast.rs | 26 | ||||
| -rw-r--r-- | src/eval/func.rs | 160 | ||||
| -rw-r--r-- | src/eval/mod.rs | 5 | ||||
| -rw-r--r-- | src/eval/scope.rs | 7 |
4 files changed, 123 insertions, 75 deletions
diff --git a/src/eval/cast.rs b/src/eval/cast.rs index 840ceb05..806f7e92 100644 --- a/src/eval/cast.rs +++ b/src/eval/cast.rs @@ -1,6 +1,6 @@ pub use typst_macros::{cast_from_value, cast_to_value}; -use std::num::NonZeroUsize; +use std::num::{NonZeroI64, NonZeroUsize}; use std::ops::Add; use ecow::EcoString; @@ -128,6 +128,20 @@ cast_to_value! { } cast_from_value! { + NonZeroI64, + int: i64 => int.try_into() + .map_err(|_| if int <= 0 { + "number must be positive" + } else { + "number too large" + })?, +} + +cast_to_value! { + v: NonZeroI64 => Value::Int(v.get()) +} + +cast_from_value! { char, string: Str => { let mut chars = string.chars(); @@ -211,6 +225,16 @@ impl<T: Into<Value>> From<Vec<T>> for Value { } } +/// A container for a variadic argument. +pub trait Variadics { + /// The contained type. + type Inner; +} + +impl<T> Variadics for Vec<T> { + type Inner = T; +} + /// Describes a possible value for a cast. #[derive(Debug, Clone, Hash)] pub enum CastInfo { diff --git a/src/eval/func.rs b/src/eval/func.rs index 6f98e316..79ae142c 100644 --- a/src/eval/func.rs +++ b/src/eval/func.rs @@ -6,10 +6,14 @@ use std::sync::Arc; use comemo::{Prehashed, Track, Tracked, TrackedMut}; use ecow::EcoString; +use once_cell::sync::Lazy; -use super::{Args, CastInfo, Dict, Eval, Flow, Route, Scope, Scopes, Tracer, Value, Vm}; +use super::{ + cast_to_value, Args, CastInfo, Dict, Eval, Flow, Route, Scope, Scopes, Tracer, Value, + Vm, +}; use crate::diag::{bail, SourceResult, StrResult}; -use crate::model::{Node, NodeId, Selector, StyleMap}; +use crate::model::{Content, NodeId, Selector, StyleMap}; use crate::syntax::ast::{self, AstNode, Expr}; use crate::syntax::{SourceId, Span, SyntaxNode}; use crate::util::hash128; @@ -22,8 +26,10 @@ pub struct Func(Arc<Prehashed<Repr>>, Span); /// The different kinds of function representations. #[derive(Hash)] enum Repr { - /// A native rust function. - Native(Native), + /// A native Rust function. + Native(NativeFunc), + /// A function for a node. + Node(NodeFunc), /// A user-defined closure. Closure(Closure), /// A nested function with pre-applied arguments. @@ -31,50 +37,11 @@ enum Repr { } impl Func { - /// Create a new function from a type that can be turned into a function. - pub fn from_type<T: FuncType>(name: &'static str) -> Self { - T::create_func(name) - } - - /// Create a new function from a native rust function. - pub fn from_fn( - func: fn(&Vm, &mut Args) -> SourceResult<Value>, - info: FuncInfo, - ) -> Self { - Self( - Arc::new(Prehashed::new(Repr::Native(Native { - func, - set: None, - node: None, - info, - }))), - Span::detached(), - ) - } - - /// Create a new function from a native rust node. - pub fn from_node<T: Node>(mut info: FuncInfo) -> Self { - info.params.extend(T::params()); - Self( - Arc::new(Prehashed::new(Repr::Native(Native { - func: |vm, args| T::construct(vm, args).map(Value::Content), - set: Some(T::set), - node: Some(NodeId::of::<T>()), - info, - }))), - Span::detached(), - ) - } - - /// Create a new function from a closure. - pub(super) fn from_closure(closure: Closure, span: Span) -> Self { - Self(Arc::new(Prehashed::new(Repr::Closure(closure))), span) - } - /// The name of the function. pub fn name(&self) -> Option<&str> { match &**self.0 { Repr::Native(native) => Some(native.info.name), + Repr::Node(node) => Some(node.info.name), Repr::Closure(closure) => closure.name.as_deref(), Repr::With(func, _) => func.name(), } @@ -84,6 +51,7 @@ impl Func { pub fn info(&self) -> Option<&FuncInfo> { match &**self.0 { Repr::Native(native) => Some(&native.info), + Repr::Node(node) => Some(&node.info), Repr::With(func, _) => func.info(), _ => None, } @@ -119,6 +87,11 @@ impl Func { args.finish()?; Ok(value) } + Repr::Node(node) => { + let value = (node.construct)(vm, &mut args)?; + args.finish()?; + Ok(Value::Content(value)) + } Repr::Closure(closure) => { // Determine the route inside the closure. let fresh = Route::new(closure.location); @@ -172,8 +145,8 @@ impl Func { /// Execute the function's set rule and return the resulting style map. pub fn set(&self, mut args: Args) -> SourceResult<StyleMap> { Ok(match &**self.0 { - Repr::Native(Native { set: Some(set), .. }) => { - let styles = set(&mut args)?; + Repr::Node(node) => { + let styles = (node.set)(&mut args)?; args.finish()?; styles } @@ -183,13 +156,13 @@ impl Func { /// Create a selector for this function's node type. pub fn select(&self, fields: Option<Dict>) -> StrResult<Selector> { - match **self.0 { - Repr::Native(Native { node: Some(id), .. }) => { - if id == item!(text_id) { + match &**self.0 { + Repr::Node(node) => { + if node.id == item!(text_id) { Err("to select text, please use a string or regex instead")?; } - Ok(Selector::Node(id, fields)) + Ok(Selector::Node(node.id, fields)) } _ => Err("this function is not selectable")?, } @@ -211,32 +184,75 @@ impl PartialEq for Func { } } -/// Types that can be turned into functions. -pub trait FuncType { - /// Create a function with the given name from this type. - fn create_func(name: &'static str) -> Func; +impl From<Repr> for Func { + fn from(repr: Repr) -> Self { + Self(Arc::new(Prehashed::new(repr)), Span::detached()) + } } -/// A function defined by a native rust function or node. -struct Native { - /// The function pointer. - func: fn(&Vm, &mut Args) -> SourceResult<Value>, - /// The set rule. - set: Option<fn(&mut Args) -> SourceResult<StyleMap>>, - /// The id of the node to customize with this function's show rule. - node: Option<NodeId>, - /// Documentation of the function. - info: FuncInfo, +/// A native Rust function. +pub struct NativeFunc { + /// The function's implementation. + pub func: fn(&Vm, &mut Args) -> SourceResult<Value>, + /// Details about the function. + pub info: Lazy<FuncInfo>, } -impl Hash for Native { +impl Hash for NativeFunc { fn hash<H: Hasher>(&self, state: &mut H) { (self.func as usize).hash(state); - self.set.map(|set| set as usize).hash(state); - self.node.hash(state); } } +impl From<NativeFunc> for Func { + fn from(native: NativeFunc) -> Self { + Repr::Native(native).into() + } +} + +cast_to_value! { + v: NativeFunc => Value::Func(v.into()) +} + +impl<F> From<F> for Value +where + F: Fn() -> NativeFunc, +{ + fn from(f: F) -> Self { + f().into() + } +} + +/// A function defined by a native Rust node. +pub struct NodeFunc { + /// The node's id. + pub id: NodeId, + /// The node's constructor. + pub construct: fn(&Vm, &mut Args) -> SourceResult<Content>, + /// The node's set rule. + pub set: fn(&mut Args) -> SourceResult<StyleMap>, + /// Details about the function. + pub info: Lazy<FuncInfo>, +} + +impl Hash for NodeFunc { + fn hash<H: Hasher>(&self, state: &mut H) { + self.id.hash(state); + (self.construct as usize).hash(state); + (self.set as usize).hash(state); + } +} + +impl From<NodeFunc> for Func { + fn from(node: NodeFunc) -> Self { + Repr::Node(node).into() + } +} + +cast_to_value! { + v: NodeFunc => Value::Func(v.into()) +} + /// Details about a function. #[derive(Debug, Clone)] pub struct FuncInfo { @@ -375,6 +391,16 @@ impl Closure { } } +impl From<Closure> for Func { + fn from(closure: Closure) -> Self { + Repr::Closure(closure).into() + } +} + +cast_to_value! { + v: Closure => Value::Func(v.into()) +} + /// A visitor that determines which variables to capture for a closure. pub(super) struct CapturesVisitor<'a> { external: &'a Scopes<'a>, diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 0e0828e3..fcfda263 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -20,6 +20,9 @@ mod ops; mod scope; mod symbol; +#[doc(hidden)] +pub use once_cell::sync::Lazy; + pub use self::args::*; pub use self::array::*; pub use self::cast::*; @@ -1152,7 +1155,7 @@ impl Eval for ast::Closure { body: self.body(), }; - Ok(Value::Func(Func::from_closure(closure, self.span()))) + Ok(Value::Func(Func::from(closure).spanned(self.span()))) } } diff --git a/src/eval/scope.rs b/src/eval/scope.rs index f6bd2164..d1590063 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -4,7 +4,7 @@ use std::hash::Hash; use ecow::EcoString; -use super::{Func, FuncType, Library, Value}; +use super::{Library, Value}; use crate::diag::StrResult; /// A stack of scopes. @@ -96,11 +96,6 @@ impl Scope { self.0.insert(name, Slot::new(value.into(), Kind::Normal)); } - /// Define a function through a native rust function. - pub fn def_func<T: FuncType>(&mut self, name: &'static str) { - self.define(name, Func::from_type::<T>(name)); - } - /// Define a captured, immutable binding. pub fn define_captured( &mut self, |
