summaryrefslogtreecommitdiff
path: root/src/func.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-08-02 22:21:58 +0200
committerLaurenz <laurmaedje@gmail.com>2020-08-02 22:21:58 +0200
commit5a8f2fb73ddafba9fdbe952385ae2676126183ae (patch)
treef65dcc5c8fc3809171e0cc1a985d466159ccb254 /src/func.rs
parent266d457292e7461d448f9141030028ea68b573d1 (diff)
Replace body! macro with functions 🧰
Diffstat (limited to 'src/func.rs')
-rw-r--r--src/func.rs107
1 files changed, 39 insertions, 68 deletions
diff --git a/src/func.rs b/src/func.rs
index afc796ae..bb2862d2 100644
--- a/src/func.rs
+++ b/src/func.rs
@@ -1,44 +1,20 @@
-//! Trait and prelude for custom functions.
+//! Tools for building custom functions.
-use crate::{Pass, Feedback};
-use crate::syntax::parsing::{FuncCall, ParseState};
-use crate::syntax::span::Span;
+use crate::Feedback;
+use crate::syntax::span::{Span, Spanned};
+use crate::syntax::parsing::{parse, ParseState};
+use crate::syntax::tree::SyntaxTree;
-/// Types that are useful for creating your own functions.
+/// Useful things for creating functions.
pub mod prelude {
- pub use crate::{function, body, error, warning};
pub use crate::layout::prelude::*;
pub use crate::layout::Command::{self, *};
- pub use crate::style::{LayoutStyle, PageStyle, TextStyle};
- pub use crate::syntax::expr::*;
- pub use crate::syntax::tree::SyntaxTree;
- pub use crate::syntax::span::{Span, Spanned};
- pub use crate::syntax::value::*;
- pub use super::OptionExt;
+ pub use crate::syntax::prelude::*;
+ pub use crate::style::*;
+ pub use super::{OptionExt, parse_maybe_body, expect_no_body};
}
-/// Parse a function from source code.
-pub trait ParseFunc {
- /// A metadata type whose value is passed into the function parser. This
- /// allows a single function to do different things depending on the value
- /// that needs to be given when inserting the function into a
- /// [scope](crate::syntax::Scope).
- ///
- /// For example, the functions `word.spacing`, `line.spacing` and
- /// `par.spacing` are actually all the same function
- /// [`ContentSpacingFunc`](crate::library::ContentSpacingFunc) with the
- /// metadata specifiy which content should be spaced.
- type Meta: Clone;
-
- /// Parse the header and body into this function given a context.
- fn parse(
- header: FuncCall,
- state: &ParseState,
- metadata: Self::Meta,
- ) -> Pass<Self> where Self: Sized;
-}
-
-/// Extra methods on [`Options`](Option) used for argument parsing.
+/// Extra methods on [`Options`](Option) used for function argument parsing.
pub trait OptionExt<T>: Sized {
/// Calls `f` with `val` if this is `Some(val)`.
fn with(self, f: impl FnOnce(T));
@@ -63,10 +39,30 @@ impl<T> OptionExt<T> for Option<T> {
}
}
-/// Allows to implement a function type concisely.
+/// Parses a function's body if there is one or returns `None` otherwise.
+pub fn parse_maybe_body(
+ body: Option<Spanned<&str>>,
+ state: &ParseState,
+ f: &mut Feedback,
+) -> Option<SyntaxTree> {
+ body.map(|body| {
+ let parsed = parse(body.v, body.span.start, state);
+ f.extend(parsed.feedback);
+ parsed.output
+ })
+}
+
+/// Generates an error if there is function body even though none was expected.
+pub fn expect_no_body(body: Option<Spanned<&str>>, f: &mut Feedback) {
+ if let Some(body) = body {
+ error!(@f, body.span, "unexpected body");
+ }
+}
+
+/// Implement a custom function concisely.
///
/// # Examples
-/// Look at the source code of the [`library`](crate::library) module for more
+/// Look at the source code of the [`library`](crate::library) module for
/// examples on how the macro works.
#[macro_export]
macro_rules! function {
@@ -101,7 +97,7 @@ macro_rules! function {
$feedback:ident,
$metadata:ident
) $code:block $($r:tt)*) => {
- impl $crate::func::ParseFunc for $name {
+ impl $crate::syntax::parsing::ParseCall for $name {
type Meta = $meta;
fn parse(
@@ -111,7 +107,7 @@ macro_rules! function {
) -> $crate::Pass<Self> where Self: Sized {
let mut feedback = $crate::Feedback::new();
#[allow(unused)] let $header = &mut call.header;
- #[allow(unused)] let $body = &mut call.body;
+ #[allow(unused)] let $body = call.body;
#[allow(unused)] let $feedback = &mut feedback;
let func = $code;
@@ -131,7 +127,11 @@ macro_rules! function {
function!(@layout($name) $($r)*);
};
- (@layout($name:ident) layout($this:ident, $ctx:ident, $feedback:ident) $code:block) => {
+ (@layout($name:ident) layout(
+ $this:ident,
+ $ctx:ident,
+ $feedback:ident
+ ) $code:block) => {
impl $crate::layout::Layout for $name {
fn layout<'a, 'b, 't>(
#[allow(unused)] &'a $this,
@@ -152,32 +152,3 @@ macro_rules! function {
}
};
}
-
-/// Parse the body of a function.
-///
-/// - If the function does not expect a body, use `body!(nope: body, feedback)`.
-/// - If the function can have a body, use `body!(opt: body, state, feedback,
-/// decos)`.
-///
-/// # Arguments
-/// - The `$body` should be of type `Option<Spanned<&str>>`.
-/// - The `$state` is the parse state to use.
-/// - The `$feedback` should be a mutable references to a
-/// [`Feedback`](crate::Feedback) struct which is filled with the feedback
-/// information arising from parsing.
-#[macro_export]
-macro_rules! body {
- (opt: $body:expr, $state:expr, $feedback:expr) => ({
- $body.map(|body| {
- let parsed = $crate::syntax::parsing::parse(body.v, body.span.start, $state);
- $feedback.extend(parsed.feedback);
- parsed.output
- })
- });
-
- (nope: $body:expr, $feedback:expr) => {
- if let Some(body) = $body {
- error!(@$feedback, body.span, "unexpected body");
- }
- };
-}