diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-03-10 12:55:21 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-03-10 12:55:21 +0100 |
| commit | 62f35602a87574dcc607f1637aeae1be574981ff (patch) | |
| tree | 363a1918006e06d7d79dc2ace5f8e59cd3b6bb19 /src | |
| parent | c38d72383d2068361d635d6c1c78ba97aa917801 (diff) | |
New #[func] macro
Diffstat (limited to 'src')
| -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 | ||||
| -rw-r--r-- | src/ide/complete.rs | 6 | ||||
| -rw-r--r-- | src/model/content.rs | 17 | ||||
| -rw-r--r-- | src/model/mod.rs | 2 | ||||
| -rw-r--r-- | src/model/styles.rs | 2 |
8 files changed, 133 insertions, 92 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, diff --git a/src/ide/complete.rs b/src/ide/complete.rs index f5eece93..2e810ee9 100644 --- a/src/ide/complete.rs +++ b/src/ide/complete.rs @@ -627,10 +627,6 @@ fn param_completions( } } - if callee.as_str() == "text" { - ctx.font_completions(); - } - if ctx.before.ends_with(',') { ctx.enrich(" ", ""); } @@ -653,7 +649,7 @@ fn named_param_value_completions( ctx.cast_completions(¶m.cast); - if callee.as_str() == "text" && name == "family" { + if callee.as_str() == "text" && name == "font" { ctx.font_completions(); } diff --git a/src/model/content.rs b/src/model/content.rs index 6b4f5e5d..d845ce1e 100644 --- a/src/model/content.rs +++ b/src/model/content.rs @@ -9,7 +9,7 @@ use ecow::{EcoString, EcoVec}; use super::{node, Guard, Recipe, Style, StyleMap}; use crate::diag::{SourceResult, StrResult}; -use crate::eval::{cast_from_value, Args, Cast, ParamInfo, Value, Vm}; +use crate::eval::{cast_from_value, Args, Cast, NodeFunc, Value, Vm}; use crate::syntax::Span; use crate::World; @@ -330,12 +330,10 @@ impl Sum for Content { #[node] pub struct StyledNode { /// The styles. - #[positional] #[required] pub map: StyleMap, /// The styled content. - #[positional] #[required] pub body: Content, } @@ -353,7 +351,6 @@ cast_from_value! { /// Category: special #[node] pub struct SequenceNode { - #[positional] #[variadic] pub children: Vec<Content>, } @@ -370,14 +367,14 @@ impl Debug for Label { /// A constructable, stylable content node. pub trait Node: Construct + Set + Sized + 'static { - /// Pack a node into type-erased content. - fn pack(self) -> Content; - /// The node's ID. fn id() -> NodeId; - /// List the fields of the node. - fn params() -> Vec<ParamInfo>; + /// Pack a node into type-erased content. + fn pack(self) -> Content; + + /// The node's function. + fn func() -> NodeFunc; } /// A unique identifier for a node. @@ -425,6 +422,7 @@ pub struct NodeMeta { pub vtable: fn(of: TypeId) -> Option<*const ()>, } +/// A node's constructor function. pub trait Construct { /// Construct a node from the arguments. /// @@ -433,6 +431,7 @@ pub trait Construct { fn construct(vm: &Vm, args: &mut Args) -> SourceResult<Content>; } +/// A node's set rule. pub trait Set { /// Parse relevant arguments into style properties for this node. fn set(args: &mut Args) -> SourceResult<StyleMap>; diff --git a/src/model/mod.rs b/src/model/mod.rs index 07329e3f..6015c365 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -11,6 +11,4 @@ pub use self::realize::*; pub use self::styles::*; pub use self::typeset::*; -#[doc(hidden)] -pub use once_cell; pub use typst_macros::node; diff --git a/src/model/styles.rs b/src/model/styles.rs index 0b74e162..3239bb17 100644 --- a/src/model/styles.rs +++ b/src/model/styles.rs @@ -86,7 +86,7 @@ impl Debug for StyleMap { } } -/// A single style property, recipe or barrier. +/// A single style property or recipe. #[derive(Clone, Hash)] pub enum Style { /// A style property originating from a set rule or constructor. |
