summaryrefslogtreecommitdiff
path: root/src/func.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/func.rs')
-rw-r--r--src/func.rs138
1 files changed, 29 insertions, 109 deletions
diff --git a/src/func.rs b/src/func.rs
index 09870895..57dad103 100644
--- a/src/func.rs
+++ b/src/func.rs
@@ -2,25 +2,31 @@
/// Useful things for creating functions.
pub mod prelude {
+ pub use async_trait::async_trait;
pub use crate::layout::prelude::*;
+ pub use crate::layout::Commands;
pub use crate::layout::Command::{self, *};
pub use crate::style::*;
- pub use crate::syntax::prelude::*;
- pub use super::{expect_no_body, parse_maybe_body, OptionExt};
+ pub use crate::syntax::expr::*;
+ pub use crate::syntax::parsing::{
+ parse, FuncArgs, FuncBody, FuncCall, FuncHeader, ParseState,
+ };
+ pub use crate::syntax::span::{Span, SpanVec, Spanned};
+ pub use crate::syntax::tree::{DynamicNode, SyntaxNode, SyntaxTree};
+ pub use crate::syntax::value::*;
+ pub use crate::{Pass, Feedback};
+ pub use super::*;
}
-use crate::syntax::parsing::{parse, ParseState};
-use crate::syntax::span::{Span, Spanned};
-use crate::syntax::tree::SyntaxTree;
-use crate::Feedback;
+use prelude::*;
/// Extra methods on `Option`s used for function argument parsing.
pub trait OptionExt<T>: Sized {
- /// Calls `f` with `val` if this is `Some(val)`.
+ /// Call `f` with `val` if this is `Some(val)`.
fn with(self, f: impl FnOnce(T));
- /// Reports an error about a missing argument with the given name and span
- /// if the option is `None`.
+ /// Report an error about a missing argument with the given name and span if
+ /// the option is `None`.
fn or_missing(self, span: Span, arg: &str, f: &mut Feedback) -> Self;
}
@@ -39,8 +45,19 @@ impl<T> OptionExt<T> for Option<T> {
}
}
-/// Parses a function's body if there is one or returns `None` otherwise.
-pub fn parse_maybe_body(
+/// Generate `unexpected argument` errors for all remaining arguments.
+pub fn drain_args(args: FuncArgs, f: &mut Feedback) {
+ for arg in args.pos.0 {
+ error!(@f, arg.span, "unexpected argument");
+ }
+
+ for arg in args.key.0 {
+ error!(@f, arg.span, "unexpected argument");
+ }
+}
+
+/// Parse a function's body if there is one or return `None` otherwise.
+pub fn parse_body_maybe(
body: Option<Spanned<&str>>,
state: &ParseState,
f: &mut Feedback,
@@ -52,106 +69,9 @@ pub fn parse_maybe_body(
})
}
-/// Generates an error if there is function body even though none was expected.
+/// Generate 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` module for examples on how the
-/// macro works.
-#[macro_export]
-macro_rules! function {
- // Entry point.
- ($(#[$outer:meta])* $v:vis $storage:ident $name:ident $($r:tt)*) => {
- function!(@def($name) $(#[$outer])* $v $storage $name $($r)*);
- };
- (@def($name:ident) $definition:item $($r:tt)*) => {
- $definition
- function!(@meta($name) $($r)*);
- };
-
- // Metadata.
- (@meta($name:ident) type Meta = $meta:ty; $($r:tt)*) => {
- function!(@parse($name, $meta) $($r)*);
- };
- (@meta($name:ident) $($r:tt)*) => {
- function!(@parse($name, ()) $($r)*);
- };
-
- // Parse trait.
- (@parse($($a:tt)*) parse(default) $($r:tt)*) => {
- function!(@parse($($a)*) parse(_h, _b, _c, _f, _m) { Default::default() } $($r)*);
- };
- (@parse($($a:tt)*) parse($h:ident, $b:ident, $c:ident, $f:ident) $($r:tt)* ) => {
- function!(@parse($($a)*) parse($h, $b, $c, $f, _metadata) $($r)*);
- };
- (@parse($name:ident, $meta:ty) parse(
- $header:ident,
- $body:ident,
- $state:ident,
- $feedback:ident,
- $metadata:ident
- ) $code:block $($r:tt)*) => {
- impl $crate::syntax::parsing::ParseCall for $name {
- type Meta = $meta;
-
- fn parse(
- #[allow(unused)] mut call: $crate::syntax::parsing::FuncCall,
- #[allow(unused)] $state: &$crate::syntax::parsing::ParseState,
- #[allow(unused)] $metadata: Self::Meta,
- ) -> $crate::Pass<Self>
- where
- Self: Sized,
- {
- let mut feedback = $crate::Feedback::new();
- #[allow(unused)] let $header = &mut call.header;
- #[allow(unused)] let $body = call.body;
- #[allow(unused)] let $feedback = &mut feedback;
-
- let func = $code;
-
- for arg in call.header.args.pos.0 {
- error!(@feedback, arg.span, "unexpected argument");
- }
-
- for arg in call.header.args.key.0 {
- error!(@feedback, arg.span, "unexpected argument");
- }
-
- $crate::Pass::new(func, feedback)
- }
- }
-
- function!(@layout($name) $($r)*);
- };
-
- (@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,
- #[allow(unused)] mut $ctx: $crate::layout::LayoutContext<'b>,
- ) -> $crate::DynFuture<'t, $crate::Pass<$crate::layout::Commands<'a>>>
- where
- 'a: 't,
- 'b: 't,
- Self: 't,
- {
- Box::pin(async move {
- let mut feedback = $crate::Feedback::new();
- #[allow(unused)] let $feedback = &mut feedback;
- let commands = $code;
- $crate::Pass::new(commands, feedback)
- })
- }
- }
- };
-}