diff --git a/mps-interpreter/README.md b/mps-interpreter/README.md index dc08c43..ea7b371 100644 --- a/mps-interpreter/README.md +++ b/mps-interpreter/README.md @@ -126,6 +126,10 @@ Repeat the iterable count times, or infinite times if count is omitted. Retrieve all files from a folder, matching a regex pattern. +#### empty(); + +Empty iterator. Useful for deleting items using replacement filters. + ### Sorters Operations to sort the items in an iterable: iterable~(sorter) OR iterable.sort(sorter) diff --git a/mps-interpreter/src/interpretor.rs b/mps-interpreter/src/interpretor.rs index 106a097..182d675 100644 --- a/mps-interpreter/src/interpretor.rs +++ b/mps-interpreter/src/interpretor.rs @@ -174,5 +174,6 @@ pub(crate) fn standard_vocab(vocabulary: &mut MpsLanguageDictionary) { .add(crate::lang::vocabulary::repeat_function_factory()) .add(crate::lang::vocabulary::AssignStatementFactory) .add(crate::lang::vocabulary::sql_init_function_factory()) - .add(crate::lang::vocabulary::files_function_factory()); + .add(crate::lang::vocabulary::files_function_factory()) + .add(crate::lang::vocabulary::empty_function_factory()); } diff --git a/mps-interpreter/src/lang/vocabulary/empty.rs b/mps-interpreter/src/lang/vocabulary/empty.rs new file mode 100644 index 0000000..2fcd9ec --- /dev/null +++ b/mps-interpreter/src/lang/vocabulary/empty.rs @@ -0,0 +1,88 @@ +use std::collections::VecDeque; +use std::fmt::{Debug, Display, Error, Formatter}; +use std::iter::Iterator; + +use crate::tokens::MpsToken; +use crate::MpsContext; + +#[cfg(debug_assertions)] +use crate::lang::utility::assert_empty; +use crate::lang::MpsLanguageDictionary; +use crate::lang::{MpsFunctionFactory, MpsFunctionStatementFactory, MpsIteratorItem, MpsOp}; +use crate::lang::{RuntimeError, SyntaxError}; + +#[derive(Debug)] +pub struct EmptyStatement { + context: Option, +} + +impl Display for EmptyStatement { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + write!(f, "empty()") + } +} + +impl std::clone::Clone for EmptyStatement { + fn clone(&self) -> Self { + Self { + context: None, + } + } +} + +impl Iterator for EmptyStatement { + type Item = MpsIteratorItem; + + fn next(&mut self) -> Option { + None + } +} + +impl MpsOp for EmptyStatement { + fn enter(&mut self, ctx: MpsContext) { + self.context = Some(ctx) + } + + fn escape(&mut self) -> MpsContext { + self.context.take().unwrap() + } + + fn is_resetable(&self) -> bool { + true + } + + fn reset(&mut self) -> Result<(), RuntimeError> { + Ok(()) + } +} + +pub struct EmptyFunctionFactory; + +impl MpsFunctionFactory for EmptyFunctionFactory { + fn is_function(&self, name: &str) -> bool { + name == "empty" || name == "_" + } + + fn build_function_params( + &self, + _name: String, + #[allow(unused_variables)] + tokens: &mut VecDeque, + _dict: &MpsLanguageDictionary, + ) -> Result { + // empty() + #[cfg(debug_assertions)] + assert_empty(tokens)?; + Ok(EmptyStatement { + context: None, + }) + } +} + +pub type EmptyStatementFactory = MpsFunctionStatementFactory; + +#[inline(always)] +pub fn empty_function_factory() -> EmptyStatementFactory { + EmptyStatementFactory::new(EmptyFunctionFactory) +} + diff --git a/mps-interpreter/src/lang/vocabulary/mod.rs b/mps-interpreter/src/lang/vocabulary/mod.rs index 7dd0dba..596b119 100644 --- a/mps-interpreter/src/lang/vocabulary/mod.rs +++ b/mps-interpreter/src/lang/vocabulary/mod.rs @@ -1,4 +1,5 @@ mod comment; +mod empty; mod files; mod repeat; mod sql_init; @@ -7,6 +8,7 @@ mod sql_simple_query; mod variable_assign; pub use comment::{CommentStatement, CommentStatementFactory}; +pub use empty::{empty_function_factory, EmptyStatementFactory}; pub use files::{files_function_factory, FilesStatementFactory}; pub use repeat::{repeat_function_factory, RepeatStatementFactory}; pub use sql_init::{sql_init_function_factory, SqlInitStatementFactory}; diff --git a/mps-interpreter/src/lib.rs b/mps-interpreter/src/lib.rs index d340108..ba828b2 100644 --- a/mps-interpreter/src/lib.rs +++ b/mps-interpreter/src/lib.rs @@ -124,6 +124,10 @@ //! //! Retrieve all files from a folder, matching a regex pattern. //! +//! ### empty(); +//! +//! Empty iterator. Useful for deleting items using replacement filters. +//! //! ## Sorters //! Operations to sort the items in an iterable: iterable~(sorter) OR iterable.sort(sorter) //! diff --git a/mps-interpreter/tests/single_line.rs b/mps-interpreter/tests/single_line.rs index 968803f..d17e50f 100644 --- a/mps-interpreter/tests/single_line.rs +++ b/mps-interpreter/tests/single_line.rs @@ -367,3 +367,12 @@ fn execute_blisssort_line() -> Result<(), Box> { true, ) } + +#[test] +fn execute_emptyfn_line() -> Result<(), Box> { + execute_single_line( + "empty()", + true, + true, + ) +} diff --git a/src/help.rs b/src/help.rs index c397d72..451e465 100644 --- a/src/help.rs +++ b/src/help.rs @@ -31,7 +31,10 @@ These always return an iterable which can be manipulated. Repeat the iterable count times, or infinite times if count is omitted. files(folder = `path/to/music`, recursive = true|false, regex = `pattern`) - Retrieve all files from a folder, matching a regex pattern."; + Retrieve all files from a folder, matching a regex pattern. + + empty() + Empty iterator. Useful for deleting items using replacement filters."; pub const FILTERS: &str = "FILTERS (?filters)