Skip to content

Commit

Permalink
Move examples to new macro
Browse files Browse the repository at this point in the history
  • Loading branch information
rscarson committed Oct 17, 2023
1 parent 21fe2d5 commit 966be8c
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 55 deletions.
52 changes: 25 additions & 27 deletions examples/adding_functionality.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
use lavendeux_parser::Error;
use lavendeux_parser::ExpectedTypes;
use lavendeux_parser::{DecoratorDefinition, FunctionArgument, FunctionDefinition};
use lavendeux_parser::{ParserState, Token, Value};
use lavendeux_parser::{
define_decorator, define_function, Error, ExpectedTypes, ParserState, Token, Value,
};

// Define a function for the parser
define_function!(
name = echo,
description = "Echo back the provided input",
arguments = [function_arg!("input":String)],
handler = |function, token, state, args| {
Ok(Value::String(args.get("input").required().as_string()))
}
);

// Define a decorator for the parser
define_decorator!(
name = upper,
aliases = ["uppercase"],
description = "Outputs an uppercase version of the input",
input = ExpectedTypes::Any,
handler = |decorator, token, input| Ok(input.as_string().to_uppercase())
);

fn main() -> Result<(), Error> {
// Load the extensions into our parser
let mut state: ParserState = ParserState::new();

// Register a new function
state.functions.register(FunctionDefinition {
name: "echo",
category: None,
description: "Echo back the provided input",
arguments: || {
vec![FunctionArgument::new_required(
"input",
ExpectedTypes::String,
)]
},
handler: |_function, _token, _state, args| {
Ok(Value::String(args.get("input").required().as_string()))
},
});

// Register a new decorator
state.decorators.register(DecoratorDefinition {
name: &["upper", "uppercase"],
description: "Outputs an uppercase version of the input",
argument: ExpectedTypes::Any,
handler: |_, _token, input| Ok(input.as_string().to_uppercase()),
});
// Register a new function and decorator
state.functions.register(echo);
state.decorators.register(upper);

// Now we can use the new functions and @decorators
let token = Token::new("echo('test') @upper", &mut state)?;
Expand Down
19 changes: 18 additions & 1 deletion src/decorators/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,24 @@ use std::collections::HashMap;

#[macro_use]
pub mod decorator_macros {
/// Defines a function for registration as a builtin
/// Defines a decorator for registration as a builtin
///
/// name = identifier for the new function, and the callable name,
/// category = Optional string category for the help menu
/// description = String describing the function
/// arguments = Set of arguments defined with function_arg!
/// handler = closure taking in |function, token, state, args|
///
/// Example:
/// ```ignore
/// define_decorator!(
/// name = upper
/// aliases = ["uppercase"],
/// description = "Outputs an uppercase version of the input",
/// input = ExpectedTypes::Any,
/// handler = |decorator, token, input| Ok(input.as_string().to_uppercase())
/// );
/// ```
#[macro_export]
macro_rules! define_decorator {
(
Expand Down
40 changes: 33 additions & 7 deletions src/functions/function_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,52 @@ pub mod function_macros {
}

/// Describes the requirements of an argument to a builtin function
///
/// Examples:
/// ```ignore
/// function_arg!("name_of_variable")
/// function_arg!("plural", "name_of_variable_array")
/// function_arg!("optional", "name_of__optional_variable")
/// function_arg!("plural+optional", "name_of__optional_variable_array")
/// ```
#[macro_export]
macro_rules! function_arg {
($name:literal:$type:ident) => {
FunctionArgument::new($name, crate::ExpectedTypes::$type, false)
$crate::FunctionArgument::new($name, crate::ExpectedTypes::$type, false)
};

("plural", $name:literal:$type:ident) => {
FunctionArgument::new_plural($name, crate::ExpectedTypes::$type, false)
$crate::FunctionArgument::new_plural($name, crate::ExpectedTypes::$type, false)
};

("optional", $name:literal:$type:ident) => {
FunctionArgument::new($name, crate::ExpectedTypes::$type, true)
$crate::FunctionArgument::new($name, crate::ExpectedTypes::$type, true)
};

("plural+optional", $name:literal:$type:ident) => {
FunctionArgument::new_plural($name, crate::ExpectedTypes::$type, true)
$crate::FunctionArgument::new_plural($name, crate::ExpectedTypes::$type, true)
};
}

/// Defines a function for registration as a builtin
///
/// name = identifier for the new function, and the callable name,
/// category = Optional string category for the help menu
/// description = String describing the function
/// arguments = Set of arguments defined with function_arg!
/// handler = closure taking in |function, token, state, args|
///
/// Example:
/// ```ignore
/// define_function!(
/// name = echo,
/// description = "Echo back the provided input",
/// arguments = [function_arg!("input":String)],
/// handler = |function, token, state, args| {
/// Ok(Value::String(args.get("input").required().as_string()))
/// }
/// );
/// ```
#[macro_export]
macro_rules! define_function {
(
Expand All @@ -52,14 +78,14 @@ pub mod function_macros {
#[doc = stringify!($function_name)]
/// );
#[allow(non_upper_case_globals, unused_variables)]
const $function_name: FunctionDefinition = FunctionDefinition {
const $function_name: $crate::FunctionDefinition = $crate::FunctionDefinition {
name: stringify!($function_name),
category: $crate::_define_function_category!($($function_cat)?),
description: "Returns the SHA256 hash of a given string",
arguments: || {
vec![FunctionArgument::new_plural(
vec![$crate::FunctionArgument::new_plural(
"input",
crate::ExpectedTypes::Any,
$crate::ExpectedTypes::Any,
false,
)]
},
Expand Down
40 changes: 20 additions & 20 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,28 +54,28 @@
//!
//! A number of functions and @decorators are available for expressions to use - add more using the state:
//! ```rust
//! use lavendeux_parser::{ParserState, Error, DecoratorDefinition, FunctionDefinition, FunctionArgument, Value, ExpectedTypes};
//!
//! let mut state : ParserState = ParserState::new();
//! state.decorators.register(DecoratorDefinition {
//! name: &["upper", "uppercase"],
//! description: "Outputs an uppercase version of the input",
//! argument: ExpectedTypes::Any,
//! handler: |_, _token, input| Ok(input.as_string().to_uppercase())
//! });
//!
//! // Functions take in an array of values, and return a single value
//! state.functions.register(FunctionDefinition {
//! name: "echo",
//! category: None,
//! description: "Echo back the provided input",
//! arguments: || vec![
//! FunctionArgument::new_required("input", ExpectedTypes::String),
//! ],
//! handler: |_function, _token, _state, args| {
//! use lavendeux_parser::{ParserState, Error, define_function, define_decorator, Value, ExpectedTypes};
//!
//! define_function!(
//! name = echo,
//! description = "Echo back the provided input",
//! arguments = [function_arg!("input":String)],
//! handler = |function, token, state, args| {
//! Ok(Value::String(args.get("input").required().as_string()))
//! }
//! });
//! );
//!
//! define_decorator!(
//! name = upper,
//! aliases = ["uppercase"],
//! description = "Outputs an uppercase version of the input",
//! input = ExpectedTypes::Any,
//! handler = |decorator, token, input| Ok(input.as_string().to_uppercase())
//! );
//!
//! let mut state : ParserState = ParserState::new();
//! state.decorators.register(upper);
//! state.functions.register(echo);
//!
//! // Expressions being parsed can now call new_function(), and use the @new_decorator
//! ```
Expand Down

0 comments on commit 966be8c

Please sign in to comment.