diff options
Diffstat (limited to 'src/model')
| -rw-r--r-- | src/model/content.rs | 6 | ||||
| -rw-r--r-- | src/model/eval.rs | 2 | ||||
| -rw-r--r-- | src/model/func.rs | 37 | ||||
| -rw-r--r-- | src/model/mod.rs | 2 | ||||
| -rw-r--r-- | src/model/scope.rs | 21 | ||||
| -rw-r--r-- | src/model/value.rs | 4 |
6 files changed, 44 insertions, 28 deletions
diff --git a/src/model/content.rs b/src/model/content.rs index f261f9b1..e73fa4a8 100644 --- a/src/model/content.rs +++ b/src/model/content.rs @@ -10,7 +10,9 @@ use siphasher::sip128::{Hasher128, SipHasher}; use thin_vec::ThinVec; use typst_macros::node; -use super::{capability, Args, Guard, Key, Property, Recipe, Style, StyleMap, Value, Vm}; +use super::{ + capability, capable, Args, Guard, Key, Property, Recipe, Style, StyleMap, Value, Vm, +}; use crate::diag::{SourceResult, StrResult}; use crate::syntax::Span; use crate::util::{EcoString, ReadableTypeId}; @@ -342,6 +344,7 @@ impl Hash for dyn Bounds { } /// A node with applied styles. +#[capable] #[derive(Clone, Hash)] pub struct StyledNode { /// The styled content. @@ -364,6 +367,7 @@ impl Debug for StyledNode { /// /// Combines other arbitrary content. So, when you write `[Hi] + [you]` in /// Typst, the two text nodes are combined into a single sequence node. +#[capable] #[derive(Clone, Hash)] pub struct SequenceNode(pub Vec<Content>); diff --git a/src/model/eval.rs b/src/model/eval.rs index ef9ba0a8..d54acf0a 100644 --- a/src/model/eval.rs +++ b/src/model/eval.rs @@ -1147,7 +1147,7 @@ impl Eval for ast::ModuleImport { match self.imports() { ast::Imports::Wildcard => { for (var, value) in module.scope.iter() { - vm.scopes.top.define(var, value.clone()); + vm.scopes.top.define(var.clone(), value.clone()); } } ast::Imports::Items(idents) => { diff --git a/src/model/func.rs b/src/model/func.rs index 60f36bd4..0261b5e2 100644 --- a/src/model/func.rs +++ b/src/model/func.rs @@ -30,16 +30,22 @@ 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( name: &'static str, func: fn(&Vm, &mut Args) -> SourceResult<Value>, + doc: &'static str, ) -> Self { - Self(Arc::new(Repr::Native(Native { name, func, set: None, node: None }))) + Self(Arc::new(Repr::Native(Native { name, func, set: None, node: None, doc }))) } /// Create a new function from a native rust node. - pub fn from_node<T: Node>(name: &'static str) -> Self { + pub fn from_node<T: Node>(name: &'static str, doc: &'static str) -> Self { Self(Arc::new(Repr::Native(Native { name, func: |ctx, args| { @@ -49,6 +55,7 @@ impl Func { }, set: Some(|args| T::set(args, false)), node: Some(NodeId::of::<T>()), + doc, }))) } @@ -66,6 +73,15 @@ impl Func { } } + /// Documentation for the function. + pub fn doc(&self) -> Option<&str> { + match self.0.as_ref() { + Repr::Native(native) => Some(native.doc), + Repr::With(func, _) => func.doc(), + _ => None, + } + } + /// The number of positional arguments this function takes, if known. pub fn argc(&self) -> Option<usize> { match self.0.as_ref() { @@ -159,16 +175,24 @@ 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; +} + /// A function defined by a native rust function or node. struct Native { /// The name of the function. - pub name: &'static str, + name: &'static str, /// The function pointer. - pub func: fn(&Vm, &mut Args) -> SourceResult<Value>, + func: fn(&Vm, &mut Args) -> SourceResult<Value>, /// The set rule. - pub set: Option<fn(&mut Args) -> SourceResult<StyleMap>>, + set: Option<fn(&mut Args) -> SourceResult<StyleMap>>, /// The id of the node to customize with this function's show rule. - pub node: Option<NodeId>, + node: Option<NodeId>, + /// Documentation of the function. + doc: &'static str, } impl Hash for Native { @@ -177,6 +201,7 @@ impl Hash for Native { (self.func as usize).hash(state); self.set.map(|set| set as usize).hash(state); self.node.hash(state); + self.doc.hash(state); } } diff --git a/src/model/mod.rs b/src/model/mod.rs index fa047746..015df9b3 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -26,7 +26,7 @@ mod typeset; #[doc(hidden)] pub use once_cell; -pub use typst_macros::{capability, node}; +pub use typst_macros::{capability, capable, func, node}; pub use self::args::*; pub use self::array::*; diff --git a/src/model/scope.rs b/src/model/scope.rs index d21d0587..c54cf1b3 100644 --- a/src/model/scope.rs +++ b/src/model/scope.rs @@ -2,8 +2,8 @@ use std::collections::BTreeMap; use std::fmt::{self, Debug, Formatter}; use std::hash::Hash; -use super::{Args, Func, Node, Value, Vm}; -use crate::diag::{SourceResult, StrResult}; +use super::{Func, FuncType, Value}; +use crate::diag::StrResult; use crate::util::EcoString; /// A stack of scopes. @@ -75,17 +75,8 @@ impl Scope { } /// Define a function through a native rust function. - pub fn def_fn( - &mut self, - name: &'static str, - func: fn(&Vm, &mut Args) -> SourceResult<Value>, - ) { - self.define(name, Func::from_fn(name, func)); - } - - /// Define a function through a native rust node. - pub fn def_node<T: Node>(&mut self, name: &'static str) { - self.define(name, Func::from_node::<T>(name)); + pub fn def_func<T: FuncType>(&mut self, name: &'static str) { + self.define(name, Func::from_type::<T>(name)); } /// Define a captured, immutable binding. @@ -108,8 +99,8 @@ impl Scope { } /// Iterate over all definitions. - pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> { - self.0.iter().map(|(k, v)| (k.as_str(), v.read())) + pub fn iter(&self) -> impl Iterator<Item = (&EcoString, &Value)> { + self.0.iter().map(|(k, v)| (k, v.read())) } } diff --git a/src/model/value.rs b/src/model/value.rs index 59dac720..98d11e15 100644 --- a/src/model/value.rs +++ b/src/model/value.rs @@ -424,9 +424,5 @@ mod tests { test(dict![], "(:)"); test(dict!["one" => 1], "(one: 1)"); test(dict!["two" => false, "one" => 1], "(one: 1, two: false)"); - - // Functions, content and dynamics. - test(Func::from_fn("nil", |_, _| Ok(Value::None)), "<function nil>"); - test(Dynamic::new(1), "1"); } } |
