Compare commits
No commits in common. "dd00a373691b054c3ea50b316c43a5b4d8fe9831" and "91c6c42a028b57aa7c33a53c0cb08ccb11103337" have entirely different histories.
dd00a37369
...
91c6c42a02
|
@ -219,7 +219,7 @@ where
|
||||||
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
|
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
|
||||||
{
|
{
|
||||||
separate_by1(parser, separator).next(|r| match r {
|
separate_by1(parser, separator).next(|r| match r {
|
||||||
Err(r) => Ok((r.input(), vec![])),
|
Err((input, _)) => Ok((input, vec![])),
|
||||||
r => r,
|
r => r,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ where
|
||||||
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
|
PSeparator: Parser<'a, TToken, TSeparator, TContext>,
|
||||||
{
|
{
|
||||||
separate_or_end_by1(parser, separator).next(|r| match r {
|
separate_or_end_by1(parser, separator).next(|r| match r {
|
||||||
Err(r) => Ok((r.input(), vec![])),
|
Err((i, _)) => Ok((i, vec![])),
|
||||||
r => r,
|
r => r,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,9 +136,9 @@ where
|
||||||
input = i;
|
input = i;
|
||||||
result.push(r);
|
result.push(r);
|
||||||
} else {
|
} else {
|
||||||
return Err(FailedParserResult::new_with_str(
|
return Err((
|
||||||
input,
|
input,
|
||||||
"End with other elements.",
|
FailedParserResult::new("End with other elements.".to_owned()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,9 +174,9 @@ where
|
||||||
result.push(r);
|
result.push(r);
|
||||||
input = i;
|
input = i;
|
||||||
} else {
|
} else {
|
||||||
return Err(FailedParserResult::new_with_str(
|
return Err((
|
||||||
input,
|
input,
|
||||||
"End with other elements.",
|
FailedParserResult::new("End with other elements.".to_owned()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,51 +10,33 @@ use crate::parser::primitive_parsers::{
|
||||||
TakeParser,
|
TakeParser,
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FailedParserResult<'a, TToken: Debug> {
|
pub struct FailedParserResult {
|
||||||
input: &'a [TToken],
|
|
||||||
message: String,
|
message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, TToken: Debug> FailedParserResult<'a, TToken> {
|
impl FailedParserResult {
|
||||||
pub fn new(input: &'a [TToken], message: String) -> Self {
|
pub fn new(message: String) -> Self {
|
||||||
Self { input, message }
|
Self { message }
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_str(input: &'a [TToken], message: &'static str) -> Self {
|
|
||||||
Self {
|
|
||||||
input,
|
|
||||||
message: message.to_owned(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message(&self) -> &str {
|
pub fn message(&self) -> &str {
|
||||||
self.message.as_str()
|
self.message.as_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&self) -> &'a [TToken] {
|
|
||||||
self.input
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, TToken: Debug> Error for FailedParserResult<'a, TToken> {}
|
impl Display for FailedParserResult {
|
||||||
|
|
||||||
impl<'a, TToken: Debug> Display for FailedParserResult<'a, TToken> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(f, "Parse failed: {}.", self.message)
|
||||||
f,
|
|
||||||
"Parse failed: {}, the input is '{:?}'.",
|
|
||||||
self.message, self.input
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ParserResult<'a, TToken, T> = Result<(&'a [TToken], T), FailedParserResult<'a, TToken>>;
|
pub type ParserResult<'a, TToken, T> =
|
||||||
|
Result<(&'a [TToken], T), (&'a [TToken], FailedParserResult)>;
|
||||||
|
|
||||||
pub struct ParserContext<TToken, TContext>
|
pub struct ParserContext<TToken, TContext>
|
||||||
where
|
where
|
||||||
|
|
|
@ -121,9 +121,11 @@ where
|
||||||
let (input, _) = self.parser.parse(context, input)?;
|
let (input, _) = self.parser.parse(context, input)?;
|
||||||
|
|
||||||
if origin_input.is_empty() {
|
if origin_input.is_empty() {
|
||||||
return Err(FailedParserResult::new_with_str(
|
return Err((
|
||||||
input,
|
input,
|
||||||
"Empty input, the 'literal' parser cann't get length of elememt.",
|
FailedParserResult::new(
|
||||||
|
"Empty input, the 'literal' parser cann't get length of elememt.".to_owned(),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,9 +156,11 @@ where
|
||||||
let (input, _) = self.parser.parse(context, input)?;
|
let (input, _) = self.parser.parse(context, input)?;
|
||||||
|
|
||||||
if origin_input.is_empty() {
|
if origin_input.is_empty() {
|
||||||
return Err(FailedParserResult::new_with_str(
|
return Err((
|
||||||
input,
|
input,
|
||||||
"Empty input, the 'literal' parser cann't get length of elememt.",
|
FailedParserResult::new(
|
||||||
|
"Empty input, the 'literal' parser cann't get length of elememt.".to_owned(),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,11 +212,11 @@ where
|
||||||
input: &'a [TToken],
|
input: &'a [TToken],
|
||||||
) -> ParserResult<'a, TToken, TResult> {
|
) -> ParserResult<'a, TToken, TResult> {
|
||||||
match self.parser.parse(context, input) {
|
match self.parser.parse(context, input) {
|
||||||
Ok(_) => Err(FailedParserResult::new_with_str(
|
Ok((input, _)) => Err((
|
||||||
input,
|
input,
|
||||||
"Reverse successful parser.",
|
FailedParserResult::new("Reverse failed succeeded.".to_owned()),
|
||||||
)),
|
)),
|
||||||
Err(_) => Ok((input, self.result.clone())),
|
Err((input, _)) => Ok((input, self.result.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,7 +269,7 @@ mod test {
|
||||||
let (input, result) = satisfy(|c: &char| c.is_numeric()).parse(context, input)?;
|
let (input, result) = satisfy(|c: &char| c.is_numeric()).parse(context, input)?;
|
||||||
|
|
||||||
match result.to_digit(10) {
|
match result.to_digit(10) {
|
||||||
None => Err(FailedParserResult::new_with_str(input, "What?")),
|
None => Err((input, FailedParserResult::new("What?".to_string()))),
|
||||||
Some(r) => Ok((input, Number(r as i32))),
|
Some(r) => Ok((input, Number(r as i32))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,7 +300,7 @@ mod test {
|
||||||
satisfy(|c: &char| c.is_numeric())
|
satisfy(|c: &char| c.is_numeric())
|
||||||
.next(|r| match r {
|
.next(|r| match r {
|
||||||
Ok((input, result)) => match result.to_digit(10) {
|
Ok((input, result)) => match result.to_digit(10) {
|
||||||
None => Err(FailedParserResult::new_with_str(input, "What?")),
|
None => Err((input, FailedParserResult::new("What?".to_string()))),
|
||||||
Some(r) => Ok((input, Number(r as i32))),
|
Some(r) => Ok((input, Number(r as i32))),
|
||||||
},
|
},
|
||||||
Err(r) => Err(r),
|
Err(r) => Err(r),
|
||||||
|
|
|
@ -35,9 +35,9 @@ where
|
||||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
input: &'a [TToken],
|
input: &'a [TToken],
|
||||||
) -> ParserResult<'a, TToken, T> {
|
) -> ParserResult<'a, TToken, T> {
|
||||||
Err(FailedParserResult::new_with_str(
|
Err((
|
||||||
input,
|
input,
|
||||||
"Default failed parser.",
|
FailedParserResult::new("Default failed parser.".to_owned()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ where
|
||||||
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
|
||||||
input: &'a [TToken],
|
input: &'a [TToken],
|
||||||
) -> ParserResult<'a, TToken, T> {
|
) -> ParserResult<'a, TToken, T> {
|
||||||
Err(FailedParserResult::new(input, self.message.clone()))
|
Err((input, FailedParserResult::new(self.message.clone())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,13 +75,16 @@ where
|
||||||
input: &'a [TToken],
|
input: &'a [TToken],
|
||||||
) -> ParserResult<'a, TToken, TToken> {
|
) -> ParserResult<'a, TToken, TToken> {
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
return Err(FailedParserResult::new_with_str(input, "Input is empty"));
|
return Err((input, FailedParserResult::new("Input is empty.".to_owned())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.predicate)(&input[0]) {
|
if (self.predicate)(&input[0]) {
|
||||||
Ok((&input[1..], input[0].clone()))
|
Ok((&input[1..], input[0].clone()))
|
||||||
} else {
|
} else {
|
||||||
Err(FailedParserResult::new_with_str(input, "Predicate failed."))
|
Err((
|
||||||
|
input,
|
||||||
|
FailedParserResult::new("Predicate failed.".to_owned()),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +101,7 @@ where
|
||||||
input: &'a [TToken],
|
input: &'a [TToken],
|
||||||
) -> ParserResult<'a, TToken, TToken> {
|
) -> ParserResult<'a, TToken, TToken> {
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
Err(FailedParserResult::new_with_str(input, "Input is empty"))
|
Err((input, FailedParserResult::new("Input is empty.".to_owned())))
|
||||||
} else {
|
} else {
|
||||||
Ok((&input[1..], input[0].clone()))
|
Ok((&input[1..], input[0].clone()))
|
||||||
}
|
}
|
||||||
|
@ -119,12 +122,12 @@ where
|
||||||
input: &'a [TToken],
|
input: &'a [TToken],
|
||||||
) -> ParserResult<'a, TToken, Vec<TToken>> {
|
) -> ParserResult<'a, TToken, Vec<TToken>> {
|
||||||
if input.len() < self.count {
|
if input.len() < self.count {
|
||||||
Err(FailedParserResult::new(
|
Err((
|
||||||
input,
|
input,
|
||||||
format!(
|
FailedParserResult::new(format!(
|
||||||
"The input doesn't contain enough {} elemements.",
|
"The input doesn't contain enough {} elemements.",
|
||||||
self.count
|
self.count
|
||||||
),
|
)),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok((
|
Ok((
|
||||||
|
@ -149,12 +152,12 @@ where
|
||||||
input: &'a [TToken],
|
input: &'a [TToken],
|
||||||
) -> ParserResult<'a, TToken, ()> {
|
) -> ParserResult<'a, TToken, ()> {
|
||||||
if input.len() < self.count {
|
if input.len() < self.count {
|
||||||
Err(FailedParserResult::new(
|
Err((
|
||||||
input,
|
input,
|
||||||
format!(
|
FailedParserResult::new(format!(
|
||||||
"The input doesn't contain enough {} elemements.",
|
"The input doesn't contain enough {} elemements.",
|
||||||
self.count
|
self.count
|
||||||
),
|
)),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok((&input[self.count..], ()))
|
Ok((&input[self.count..], ()))
|
||||||
|
|
48
src/text.rs
48
src/text.rs
|
@ -1,16 +1,23 @@
|
||||||
mod string_parsers;
|
use crate::parser::{satisfy, take, FailedParserResult, Parser};
|
||||||
|
|
||||||
use crate::parser::{satisfy, Parser};
|
|
||||||
use crate::text::string_parsers::StringParser;
|
|
||||||
|
|
||||||
pub fn char_parser<'a, TContext>(c: char) -> impl Parser<'a, char, char, TContext> {
|
pub fn char_parser<'a, TContext>(c: char) -> impl Parser<'a, char, char, TContext> {
|
||||||
satisfy(move |x| *x == c)
|
satisfy(move |x| *x == c)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string_parser<'a, TContext>(
|
pub fn string_parser<'a, TContext>(str: &'static str) -> impl Parser<'a, char, String, TContext> {
|
||||||
str: &'static str,
|
take::<char, TContext>(str.chars().count()).next(move |result| {
|
||||||
) -> impl Parser<'a, char, &'a [char], TContext> {
|
result.and_then(|(input, chars)| {
|
||||||
StringParser { str }
|
let chars: String = chars.iter().collect();
|
||||||
|
if chars == str {
|
||||||
|
Ok((input, chars))
|
||||||
|
} else {
|
||||||
|
Err((
|
||||||
|
input,
|
||||||
|
FailedParserResult::new(format!("Failed to parse '{}'.", str)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn one_of<'a, TContext>(str: &'static str) -> impl Parser<'a, char, char, TContext> {
|
pub fn one_of<'a, TContext>(str: &'static str) -> impl Parser<'a, char, char, TContext> {
|
||||||
|
@ -18,13 +25,6 @@ pub fn one_of<'a, TContext>(str: &'static str) -> impl Parser<'a, char, char, TC
|
||||||
satisfy(move |c: &char| str.contains(c))
|
satisfy(move |c: &char| str.contains(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn char_satisfy<'a, TContext, F>(condition: F) -> impl Parser<'a, char, char, TContext>
|
|
||||||
where
|
|
||||||
F: Fn(&char) -> bool,
|
|
||||||
{
|
|
||||||
satisfy(move |x: &char| condition(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -52,11 +52,7 @@ mod test {
|
||||||
parser_test_helper(
|
parser_test_helper(
|
||||||
ParserContext::new_with_str("Hello, world!", ()),
|
ParserContext::new_with_str("Hello, world!", ()),
|
||||||
&"Hello".to_owned(),
|
&"Hello".to_owned(),
|
||||||
|context, input| {
|
|context, input| string_parser("Hello").parse(context, input),
|
||||||
string_parser("Hello")
|
|
||||||
.map(|x| x.iter().collect())
|
|
||||||
.parse(context, input)
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
fn test_parser(
|
fn test_parser(
|
||||||
|
@ -66,10 +62,7 @@ mod test {
|
||||||
let (input, first) = string_parser("hello, ").parse(context.clone(), input)?;
|
let (input, first) = string_parser("hello, ").parse(context.clone(), input)?;
|
||||||
let (input, second) = string_parser("world!").parse(context.clone(), input)?;
|
let (input, second) = string_parser("world!").parse(context.clone(), input)?;
|
||||||
|
|
||||||
Ok((
|
Ok((input, first + second.as_str()))
|
||||||
input,
|
|
||||||
first.iter().collect::<String>() + second.iter().collect::<String>().as_str(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_test_helper(
|
parser_test_helper(
|
||||||
|
@ -83,11 +76,4 @@ mod test {
|
||||||
|context, input| test_parser.map(|_| ()).parse(context, input),
|
|context, input| test_parser.map(|_| ()).parse(context, input),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn char_satsify_test() {
|
|
||||||
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
|
|
||||||
char_satisfy(char::is_ascii).parse(c, i)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult};
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct StringParser {
|
|
||||||
pub(crate) str: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, TContext> Parser<'a, char, &'a [char], TContext> for StringParser {
|
|
||||||
fn parse(
|
|
||||||
&self,
|
|
||||||
_: Rc<RefCell<ParserContext<char, TContext>>>,
|
|
||||||
input: &'a [char],
|
|
||||||
) -> ParserResult<'a, char, &'a [char]> {
|
|
||||||
let length = self.str.chars().count();
|
|
||||||
if input.len() < length {
|
|
||||||
return Err(FailedParserResult::new(
|
|
||||||
input,
|
|
||||||
format!("Failed to get enough elements for string '{}'.", self.str),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (&input[..length])
|
|
||||||
.iter()
|
|
||||||
.zip(self.str.chars())
|
|
||||||
.map(|(x, y)| *x == y)
|
|
||||||
.all(|x| x)
|
|
||||||
{
|
|
||||||
Ok((&input[length..], &input[..length]))
|
|
||||||
} else {
|
|
||||||
Err(FailedParserResult::new(
|
|
||||||
input,
|
|
||||||
format!("Input is not string '{}'", self.str),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -78,7 +78,7 @@ fn file_lexical_parser_test() -> anyhow::Result<()> {
|
||||||
let context = ParserContext::new_with_str(source_file.content.as_str(), ());
|
let context = ParserContext::new_with_str(source_file.content.as_str(), ());
|
||||||
let borrowed_context = context.borrow();
|
let borrowed_context = context.borrow();
|
||||||
let (_, zero_tokens) = zero_lexical_parser(context.clone(), borrowed_context.input_slice())
|
let (_, zero_tokens) = zero_lexical_parser(context.clone(), borrowed_context.input_slice())
|
||||||
.or_else(|e| Err(anyhow!("{}", e)))?;
|
.or_else(|e| Err(anyhow!("{}", e.1)))?;
|
||||||
|
|
||||||
assert_eq!(nom_tokens.len(), zero_tokens.len());
|
assert_eq!(nom_tokens.len(), zero_tokens.len());
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user