Struct yggdrasil_rt::State
source · pub struct State<'i, R>where
R: YggdrasilRule,{ /* private fields */ }
Expand description
The complete state of a Parser
.
Implementations§
source§impl<'i, R> State<'i, R>where
R: YggdrasilRule,
impl<'i, R> State<'i, R>where
R: YggdrasilRule,
sourcepub fn new(input: &'i str) -> Box<Self>
pub fn new(input: &'i str) -> Box<Self>
Allocates a fresh ParserState
object to the heap and returns the owned Box
. This Box
will be passed from closure to closure based on the needs of the specified Parser
.
§Examples
let input = "";
let state: Box<State<&str>> = State::new(input);
sourcepub fn position(&self) -> &Position<'i>
pub fn position(&self) -> &Position<'i>
Returns a reference to the current Position
of the ParserState
.
§Examples
enum Rule {
ab,
}
let input = "ab";
let mut state: Box<State<'_, Rule>> = State::new(input);
let position = state.position();
assert_eq!(position.pos(), 0);
sourcepub fn rule<F>(self: Box<Self>, rule: R, f: F) -> Either<Box<Self>>
pub fn rule<F>(self: Box<Self>, rule: R, f: F) -> Either<Box<Self>>
Wrapper needed to generate tokens. This will associate the R
type rule to the closure
meant to match the rule.
§Examples
enum Rule {
a,
}
let input = "a";
let pairs: Vec<_> = state(input, |state| state.rule(Rule::a, |s| Ok(s))).unwrap().collect();
assert_eq!(pairs.len(), 1);
sourcepub fn tag_node(self: Box<Self>, tag: &'static str) -> Either<Box<Self>>
pub fn tag_node(self: Box<Self>, tag: &'static str) -> Either<Box<Self>>
Tag current node
§Examples
Try to recognize the one specified in a set of characters
use yggdrasil_rt::iterators::TokenPair;
enum Rule {
character,
}
fn mark_c(state: Box<State<Rule>>) -> Either<Box<State<Rule>>> {
state.sequence(|state| {
character(state)
.and_then(|state| character(state))
.and_then(|state| character(state))
.and_then(|state| state.tag_node("c"))
.and_then(|state| character(state))
})
}
fn character(state: Box<State<Rule>>) -> Either<Box<State<Rule>>> {
state.rule(Rule::character, |state| state.match_range('a'..'z'))
}
let input = "abcd";
let pairs = state(input, mark_c).unwrap();
// find all node tag as `c`
let find: Vec<TokenPair<Rule>> = pairs.filter(|s| s.get_tag() == Some("c")).collect();
assert_eq!(find[0].as_str(), "c")
sourcepub fn sequence<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
pub fn sequence<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
Starts a sequence of transformations provided by f
from the Box<ParserState>
. Returns
the same Result
returned by f
in the case of an Ok
, or Err
with the current
Box<ParserState>
otherwise.
This method is useful to parse sequences that only match together which usually come in the
form of chained Result
s with
Result::and_then
.
§Examples
enum Rule {
a,
}
let input = "a";
let pairs: Vec<_> = state(input, |state| {
state
.sequence(|s| s.rule(Rule::a, |s| Ok(s)).and_then(|s| s.match_string("b")))
.or_else(|s| Ok(s))
})
.unwrap()
.collect();
assert_eq!(pairs.len(), 0);
sourcepub fn repeat<F>(self: Box<Self>, range: Range<u32>, f: F) -> Either<Box<Self>>
pub fn repeat<F>(self: Box<Self>, range: Range<u32>, f: F) -> Either<Box<Self>>
Match rule*
, elements can appear any number of times
§Examples
enum Rule {
a,
}
let input = "aab";
let mut state: Box<State<'_, Rule>> = State::new(input);
let mut result = state.repeat(0..9, |s| s.match_string_exact("a"));
assert!(result.is_ok());
assert_eq!(result.unwrap().position().offset(), 2);
let input = "b";
let mut state: Box<State<'_, Rule>> = State::new(input);
let mut result = state.repeat(0..9, |s| s.match_string_exact("a"));
assert!(result.is_ok());
assert_eq!(result.unwrap().position().offset(), 0);
sourcepub fn optional<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
pub fn optional<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
Optionally applies the transformation provided by f
from the Box<ParserState>
. Returns
Ok
with the updated Box<ParserState>
returned by f
regardless of the Result
.
§Examples
enum Rule {
ab,
}
let input = "ab";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let result = state.optional(|s| s.match_string("ab"));
assert!(result.is_ok());
state = yggdrasil_rt::State::new(input);
let result = state.optional(|s| s.match_string("ac"));
assert!(result.is_ok());
sourcepub fn match_char_if<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
pub fn match_char_if<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
Attempts to match a single character based on a filter function. Returns Ok
with the
updated Box<ParserState>
if successful, or Err
with the updated Box<ParserState>
otherwise.
§Examples
enum Rule {}
let input = "ab";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let result = state.match_char_by(|c| c.is_ascii());
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 1);
let input = "❤";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let result = state.match_char_by(|c| c.is_ascii());
assert!(result.is_err());
assert_eq!(result.unwrap_err().position().pos(), 0);
sourcepub fn match_string(
self: Box<Self>,
string: &str,
insensitive: bool
) -> Either<Box<Self>>
pub fn match_string( self: Box<Self>, string: &str, insensitive: bool ) -> Either<Box<Self>>
Attempts to match the given string. Returns Ok
with the updated Box<ParserState>
if
successful, or Err
with the updated Box<ParserState>
otherwise.
§Examples
enum Rule {}
let input = "ab";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state.match_string("ab");
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 2);
state = yggdrasil_rt::State::new(input);
result = state.match_string("ac");
assert!(result.is_err());
assert_eq!(result.unwrap_err().position().pos(), 0);
sourcepub fn match_range(self: Box<Self>, range: Range<char>) -> Either<Box<Self>>
pub fn match_range(self: Box<Self>, range: Range<char>) -> Either<Box<Self>>
Attempts to match a single character from the given range. Returns Ok
with the updated
Box<ParserState>
if successful, or Err
with the updated Box<ParserState>
otherwise.
§Caution
The provided range
is interpreted as inclusive.
§Examples
enum Rule {}
let input = "ab";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state.match_range('a'..'z');
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 1);
state = yggdrasil_rt::State::new(input);
result = state.match_range('A'..'Z');
assert!(result.is_err());
assert_eq!(result.unwrap_err().position().pos(), 0);
sourcepub fn match_regex(self: Box<Self>, regex: &Regex) -> Either<Box<Self>>
pub fn match_regex(self: Box<Self>, regex: &Regex) -> Either<Box<Self>>
Attempts to match a single character from the given range. Returns Ok
with the updated
Box<ParserState>
if successful, or Err
with the updated Box<ParserState>
otherwise.
§Caution
The provided range
is interpreted as inclusive.
§Examples
enum Rule {}
let input = "ab";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state.match_range('a'..'z');
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 1);
state = yggdrasil_rt::State::new(input);
result = state.match_range('A'..'Z');
assert!(result.is_err());
assert_eq!(result.unwrap_err().position().pos(), 0);
sourcepub fn skip(self: Box<Self>, n: usize) -> Either<Box<Self>>
pub fn skip(self: Box<Self>, n: usize) -> Either<Box<Self>>
Attempts to skip n
characters forward. Returns Ok
with the updated Box<ParserState>
if successful, or Err
with the updated Box<ParserState>
otherwise.
§Examples
enum Rule {}
let input = "ab";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state.skip(1);
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 1);
state = yggdrasil_rt::State::new(input);
result = state.skip(3);
assert!(result.is_err());
assert_eq!(result.unwrap_err().position().pos(), 0);
sourcepub fn start_of_input(self: Box<Self>) -> Either<Box<Self>>
pub fn start_of_input(self: Box<Self>) -> Either<Box<Self>>
Attempts to match the start of the input. Returns Ok
with the current Box<ParserState>
if the parser has not yet advanced, or Err
with the current Box<ParserState>
otherwise.
§Examples
enum Rule {}
let input = "ab";
let mut state: Box<State<'_, Rule>> = State::new(input);
let mut result = state.start_of_input();
assert!(result.is_ok());
state = State::new(input);
state = state.match_string("ab").unwrap();
result = state.start_of_input();
assert!(result.is_err());
sourcepub fn end_of_input(self: Box<Self>) -> Either<Box<Self>>
pub fn end_of_input(self: Box<Self>) -> Either<Box<Self>>
Attempts to match the end of the input. Returns Ok
with the current Box<ParserState>
if
there is no input remaining, or Err
with the current Box<ParserState>
otherwise.
§Examples
enum Rule {}
let input = "ab";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state.end_of_input();
assert!(result.is_err());
state = yggdrasil_rt::State::new(input);
state = state.match_string("ab").unwrap();
result = state.end_of_input();
assert!(result.is_ok());
sourcepub fn rest_of_line(self: Box<Self>) -> Either<Box<Self>>
pub fn rest_of_line(self: Box<Self>) -> Either<Box<Self>>
Attempts to match the rest of line, never fails, return empty string if match nothing.
§Examples
enum Rule {}
let input = "a\nb";
let mut state: Box<State<'_, Rule>> = State::new(input);
state = State::new(input);
let out = state.rest_of_line().unwrap();
assert!(out.position().pos() == 2);
sourcepub fn lookahead<F>(
self: Box<Self>,
is_positive: bool,
f: F
) -> Either<Box<Self>>
pub fn lookahead<F>( self: Box<Self>, is_positive: bool, f: F ) -> Either<Box<Self>>
Starts a lookahead transformation provided by f
from the Box<ParserState>
. It returns
Ok
with the current Box<ParserState>
if f
also returns an Ok
, or Err
with the current
Box<ParserState>
otherwise. If is_positive
is false
, it swaps the Ok
and Err
together, negating the Result
.
§Examples
enum Rule {
a,
}
let input = "a";
let pairs: Vec<_> = yggdrasil_rt::state(input, |state| {
state.lookahead(true, |state| state.rule(Rule::a, |s| Ok(s)))
})
.unwrap()
.collect();
assert_eq!(pairs.len(), 0);
sourcepub fn stack_push<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
pub fn stack_push<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
Evaluates the result of closure f
and pushes the span of the input consumed from before
f
is called to after f
is called to the stack. Returns Ok(Box<ParserState>)
if f
is
called successfully, or Err(Box<ParserState>)
otherwise.
§Examples
enum Rule {}
let input = "ab";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state.stack_push(|state| state.match_string("a"));
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 1);
sourcepub fn stack_peek(self: Box<Self>) -> Either<Box<Self>>
pub fn stack_peek(self: Box<Self>) -> Either<Box<Self>>
Peeks the top of the stack and attempts to match the string. Returns Ok(Box<ParserState>)
if the string is matched successfully, or Err(Box<ParserState>)
otherwise.
§Examples
enum Rule {}
let input = "aa";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state
.stack_push(|state| state.match_string("a", false))
.and_then(|state| state.stack_peek());
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 2);
sourcepub fn stack_pop(self: Box<Self>) -> Either<Box<Self>>
pub fn stack_pop(self: Box<Self>) -> Either<Box<Self>>
Pops the top of the stack and attempts to match the string. Returns Ok(Box<ParserState>)
if the string is matched successfully, or Err(Box<ParserState>)
otherwise.
§Examples
enum Rule {}
let input = "aa";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result =
state.stack_push(|state| state.match_string("a")).and_then(|state| state.stack_pop());
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 2);
sourcepub fn stack_match_peek_slice(
self: Box<Self>,
start: i32,
end: Option<i32>,
match_dir: MatchDirection
) -> Either<Box<Self>>
pub fn stack_match_peek_slice( self: Box<Self>, start: i32, end: Option<i32>, match_dir: MatchDirection ) -> Either<Box<Self>>
Matches part of the state of the stack.
§Examples
enum Rule {}
let input = "abcd cd cb";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state
.stack_push(|state| state.match_string("a", false))
.and_then(|state| state.stack_push(|state| state.match_string("b", false)))
.and_then(|state| state.stack_push(|state| state.match_string("c", false)))
.and_then(|state| state.stack_push(|state| state.match_string("d", false)))
.and_then(|state| state.match_string(" ", false))
.and_then(|state| state.stack_match_peek_slice(2, None, MatchDir::BottomToTop))
.and_then(|state| state.match_string(" ", false))
.and_then(|state| state.stack_match_peek_slice(1, Some(-1), MatchDir::TopToBottom));
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 10);
sourcepub fn stack_match_peek(self: Box<Self>) -> Either<Box<Self>>
pub fn stack_match_peek(self: Box<Self>) -> Either<Box<Self>>
Matches the full state of the stack.
§Examples
enum Rule {}
let input = "abba";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state
.stack_push(|state| state.match_string("a", false))
.and_then(|state| state.stack_push(|state| state.match_string("b", false)))
.and_then(|state| state.stack_match_peek());
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 4);
sourcepub fn stack_match_pop(self: Box<Self>) -> Either<Box<Self>>
pub fn stack_match_pop(self: Box<Self>) -> Either<Box<Self>>
Matches the full state of the stack. This method will clear the stack as it evaluates.
§Examples
enum Rule {}
let input = "aaaa";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state
.stack_push(|state| state.match_string("a", false))
.and_then(|state| state.stack_push(|state| state.match_string("a", false)))
.and_then(|state| state.stack_match_peek());
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 4);
sourcepub fn stack_drop(self: Box<Self>) -> Either<Box<Self>>
pub fn stack_drop(self: Box<Self>) -> Either<Box<Self>>
Drops the top of the stack. Returns Ok(Box<ParserState>)
if there was a value to drop, or
Err(Box<ParserState>)
otherwise.
§Examples
enum Rule {}
let input = "aa";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state
.stack_push(|state| state.match_string("a", false))
.and_then(|state| state.stack_drop());
assert!(result.is_ok());
assert_eq!(result.unwrap().position().pos(), 1);
sourcepub fn restore_on_err<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
pub fn restore_on_err<F>(self: Box<Self>, f: F) -> Either<Box<Self>>
Restores the original state of the ParserState
when f
returns an Err
. Currently,
this method only restores the stack.
§Examples
enum Rule {}
let input = "ab";
let mut state: Box<yggdrasil_rt::State<'_, Rule>> = yggdrasil_rt::State::new(input);
let mut result = state.restore_on_err(|state| {
state
.stack_push(|state| state.match_string("a", false))
.and_then(|state| state.match_string("a", false))
});
assert!(result.is_err());
// Since the the rule doesn't match, the "a" pushed to the stack will be removed.
let catch_panic = std::panic::catch_unwind(|| result.unwrap_err().stack_pop());
assert!(catch_panic.is_err());