summaryrefslogtreecommitdiff
path: root/src/func/helpers.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/func/helpers.rs')
-rw-r--r--src/func/helpers.rs203
1 files changed, 0 insertions, 203 deletions
diff --git a/src/func/helpers.rs b/src/func/helpers.rs
deleted file mode 100644
index c82a90e1..00000000
--- a/src/func/helpers.rs
+++ /dev/null
@@ -1,203 +0,0 @@
-//! Helper types and macros for creating custom functions.
-
-use super::prelude::*;
-use Expression::*;
-
-/// Lets you implement the function trait more concisely.
-#[macro_export]
-macro_rules! function {
- (data: $ident:ident, $($tts:tt)*) => (
- #[allow(unused_imports)]
- use $crate::func::prelude::*;
-
- impl Function for $ident {
- function!(@parse $ident, $($tts)*);
- }
- );
-
- (@parse $ident:ident, parse: plain, $($tts:tt)*) => (
- fn parse(header: &FuncHeader, body: Option<&str>, _: ParseContext) -> ParseResult<Self>
- where Self: Sized {
- ArgParser::new(&header.args).done()?;
- if body.is_some() {
- perr!("expected no body");
- }
- Ok($ident)
- }
-
- function!(@layout $($tts)*);
- );
-
- (
- @parse $ident:ident,
- parse($args:ident, $body:ident, $ctx:ident)
- $block:block
- $($tts:tt)*
- ) => (
- fn parse(header: &FuncHeader, body: Option<&str>, ctx: ParseContext) -> ParseResult<Self>
- where Self: Sized {
- #[allow(unused_mut)]
- let mut $args = ArgParser::new(&header.args);
- let $body = body;
- let $ctx = ctx;
- $block
- }
-
- function!(@layout $($tts)*);
- );
-
- (@layout layout($this:pat, $ctx:pat) $block:block) => (
- fn layout(&self, ctx: LayoutContext) -> LayoutResult<CommandList> {
- let $ctx = ctx;
- let $this = self;
- $block
- }
- );
-}
-
-/// Parse the body of a function.
-/// - If the function does not expect a body, use `forbidden`.
-/// - If the function can have a body, use `optional`.
-/// - If the function must have a body, use `required`.
-#[macro_export]
-macro_rules! parse {
- (forbidden: $body:expr) => {
- if $body.is_some() {
- perr!("unexpected body");
- }
- };
-
- (optional: $body:expr, $ctx:expr) => (
- if let Some(body) = $body {
- Some($crate::syntax::parse(body, $ctx)?)
- } else {
- None
- }
- );
-
- (required: $body:expr, $ctx:expr) => (
- if let Some(body) = $body {
- $crate::syntax::parse(body, $ctx)?
- } else {
- perr!("expected body");
- }
- )
-}
-
-/// Early-return with a formatted parsing error or yield
-/// an error expression without returning when prefixed with `@`.
-#[macro_export]
-macro_rules! perr {
- (@$($tts:tt)*) => ($crate::syntax::ParseError::new(format!($($tts)*)));
- ($($tts:tt)*) => (return Err(perr!(@$($tts)*)););
-}
-
-/// Early-return with a formatted layouting error or yield
-/// an error expression without returning when prefixed with `@`.
-#[macro_export]
-macro_rules! lerr {
- (@$($tts:tt)*) => ($crate::layout::LayoutError::new(format!($($tts)*)));
- ($($tts:tt)*) => (return Err(lerr!(@$($tts)*)););
-}
-
-
-/// Easy parsing of function arguments.
-pub struct ArgParser<'a> {
- args: &'a FuncArgs,
- positional_index: usize,
-}
-
-impl<'a> ArgParser<'a> {
- pub fn new(args: &'a FuncArgs) -> ArgParser<'a> {
- ArgParser {
- args,
- positional_index: 0,
- }
- }
-
- /// Get the next positional argument of the given type.
- ///
- /// If there are no more arguments or the type is wrong,
- /// this will return an error.
- pub fn get_pos<T>(&mut self) -> ParseResult<Spanned<T::Output>> where T: Argument<'a> {
- self.get_pos_opt::<T>()?
- .ok_or_else(|| perr!(@"expected {}", T::ERROR_MESSAGE))
- }
-
- /// Get the next positional argument if there is any.
- ///
- /// If the argument is of the wrong type, this will return an error.
- pub fn get_pos_opt<T>(&mut self) -> ParseResult<Option<Spanned<T::Output>>>
- where T: Argument<'a> {
- let arg = self.args.positional
- .get(self.positional_index)
- .map(T::from_expr)
- .transpose();
-
- if let Ok(Some(_)) = arg {
- self.positional_index += 1;
- }
-
- arg
- }
-
- /// Get a keyword argument with the given key and type.
- pub fn get_key<T>(&mut self, key: &str) -> ParseResult<Spanned<T::Output>>
- where T: Argument<'a> {
- self.get_key_opt::<T>(key)?
- .ok_or_else(|| perr!(@"expected {}", T::ERROR_MESSAGE))
- }
-
- /// Get a keyword argument with the given key and type if it is present.
- pub fn get_key_opt<T>(&mut self, key: &str) -> ParseResult<Option<Spanned<T::Output>>>
- where T: Argument<'a> {
- self.args.keyword.iter()
- .find(|entry| entry.val.0.val == key)
- .map(|entry| T::from_expr(&entry.val.1))
- .transpose()
- }
-
- /// Assert that there are no positional arguments left. Returns an error, otherwise.
- pub fn done(&self) -> ParseResult<()> {
- if self.positional_index == self.args.positional.len() {
- Ok(())
- } else {
- perr!("unexpected argument");
- }
- }
-}
-
-/// A kind of argument.
-pub trait Argument<'a> {
- type Output;
- const ERROR_MESSAGE: &'static str;
-
- fn from_expr(expr: &'a Spanned<Expression>) -> ParseResult<Spanned<Self::Output>>;
-}
-
-macro_rules! arg {
- ($type:ident, $err:expr, $doc:expr, $output:ty, $wanted:pat => $converted:expr) => (
- #[doc = $doc]
- #[doc = " argument for use with the [`ArgParser`]."]
- pub struct $type;
- impl<'a> Argument<'a> for $type {
- type Output = $output;
- const ERROR_MESSAGE: &'static str = $err;
-
- fn from_expr(expr: &'a Spanned<Expression>) -> ParseResult<Spanned<Self::Output>> {
- #[allow(unreachable_patterns)]
- match &expr.val {
- $wanted => Ok(Spanned::new($converted, expr.span)),
- _ => perr!("expected {}", $err),
- }
- }
- }
- );
-}
-
-arg!(ArgExpr, "expression", "A generic expression", &'a Expression, expr => &expr);
-arg!(ArgIdent, "identifier", "An identifier (e.g. `horizontal`)", &'a str, Ident(s) => s.as_str());
-arg!(ArgStr, "string", "A string (e.g. `\"Hello\"`)", &'a str, Str(s) => s.as_str());
-arg!(ArgNum, "number", "A number (e.g. `5.4`)", f64, Num(n) => *n);
-arg!(ArgSize, "size", "A size (e.g. `12pt`)", crate::size::Size, Size(s) => *s);
-arg!(ArgBool, "bool", "A boolean (`true` or `false`)", bool, Bool(b) => *b);