Compare commits

...

2 Commits

8 changed files with 124 additions and 62 deletions

View File

@ -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((input, _)) => Ok((input, vec![])), Err(r) => Ok((r.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((i, _)) => Ok((i, vec![])), Err(r) => Ok((r.input(), vec![])),
r => r, r => r,
}) })
} }

View File

@ -136,9 +136,9 @@ where
input = i; input = i;
result.push(r); result.push(r);
} else { } else {
return Err(( return Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new("End with other elements.".to_owned()), "End with other elements.",
)); ));
} }
} }
@ -174,9 +174,9 @@ where
result.push(r); result.push(r);
input = i; input = i;
} else { } else {
return Err(( return Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new("End with other elements.".to_owned()), "End with other elements.",
)); ));
} }
} }

View File

@ -10,33 +10,51 @@ 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 { pub struct FailedParserResult<'a, TToken: Debug> {
input: &'a [TToken],
message: String, message: String,
} }
impl FailedParserResult { impl<'a, TToken: Debug> FailedParserResult<'a, TToken> {
pub fn new(message: String) -> Self { pub fn new(input: &'a [TToken], message: String) -> Self {
Self { message } Self { input, 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()
} }
}
impl Display for FailedParserResult { pub fn input(&self) -> &'a [TToken] {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.input
write!(f, "Parse failed: {}.", self.message)
} }
} }
pub type ParserResult<'a, TToken, T> = impl<'a, TToken: Debug> Error for FailedParserResult<'a, TToken> {}
Result<(&'a [TToken], T), (&'a [TToken], FailedParserResult)>;
impl<'a, TToken: Debug> Display for FailedParserResult<'a, TToken> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Parse failed: {}, the input is '{:?}'.",
self.message, self.input
)
}
}
pub type ParserResult<'a, TToken, T> = Result<(&'a [TToken], T), FailedParserResult<'a, TToken>>;
pub struct ParserContext<TToken, TContext> pub struct ParserContext<TToken, TContext>
where where

View File

@ -121,11 +121,9 @@ 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(( return Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new( "Empty input, the 'literal' parser cann't get length of elememt.",
"Empty input, the 'literal' parser cann't get length of elememt.".to_owned(),
),
)); ));
} }
@ -156,11 +154,9 @@ 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(( return Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new( "Empty input, the 'literal' parser cann't get length of elememt.",
"Empty input, the 'literal' parser cann't get length of elememt.".to_owned(),
),
)); ));
} }
@ -212,11 +208,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((input, _)) => Err(( Ok(_) => Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new("Reverse failed succeeded.".to_owned()), "Reverse successful parser.",
)), )),
Err((input, _)) => Ok((input, self.result.clone())), Err(_) => Ok((input, self.result.clone())),
} }
} }
} }
@ -269,7 +265,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((input, FailedParserResult::new("What?".to_string()))), None => Err(FailedParserResult::new_with_str(input, "What?")),
Some(r) => Ok((input, Number(r as i32))), Some(r) => Ok((input, Number(r as i32))),
} }
} }
@ -300,7 +296,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((input, FailedParserResult::new("What?".to_string()))), None => Err(FailedParserResult::new_with_str(input, "What?")),
Some(r) => Ok((input, Number(r as i32))), Some(r) => Ok((input, Number(r as i32))),
}, },
Err(r) => Err(r), Err(r) => Err(r),

View File

@ -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(( Err(FailedParserResult::new_with_str(
input, input,
FailedParserResult::new("Default failed parser.".to_owned()), "Default failed parser.",
)) ))
} }
} }
@ -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((input, FailedParserResult::new(self.message.clone()))) Err(FailedParserResult::new(input, self.message.clone()))
} }
} }
@ -75,16 +75,13 @@ 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((input, FailedParserResult::new("Input is empty.".to_owned()))); return Err(FailedParserResult::new_with_str(input, "Input is empty"));
} }
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(( Err(FailedParserResult::new_with_str(input, "Predicate failed."))
input,
FailedParserResult::new("Predicate failed.".to_owned()),
))
} }
} }
} }
@ -101,7 +98,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((input, FailedParserResult::new("Input is empty.".to_owned()))) Err(FailedParserResult::new_with_str(input, "Input is empty"))
} else { } else {
Ok((&input[1..], input[0].clone())) Ok((&input[1..], input[0].clone()))
} }
@ -122,12 +119,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(( Err(FailedParserResult::new(
input, input,
FailedParserResult::new(format!( format!(
"The input doesn't contain enough {} elemements.", "The input doesn't contain enough {} elemements.",
self.count self.count
)), ),
)) ))
} else { } else {
Ok(( Ok((
@ -152,12 +149,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(( Err(FailedParserResult::new(
input, input,
FailedParserResult::new(format!( 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..], ()))

View File

@ -1,23 +1,16 @@
use crate::parser::{satisfy, take, FailedParserResult, Parser}; mod string_parsers;
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>(str: &'static str) -> impl Parser<'a, char, String, TContext> { pub fn string_parser<'a, TContext>(
take::<char, TContext>(str.chars().count()).next(move |result| { str: &'static str,
result.and_then(|(input, chars)| { ) -> impl Parser<'a, char, &'a [char], TContext> {
let chars: String = chars.iter().collect(); StringParser { str }
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> {
@ -25,6 +18,13 @@ 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,7 +52,11 @@ 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| string_parser("Hello").parse(context, input), |context, input| {
string_parser("Hello")
.map(|x| x.iter().collect())
.parse(context, input)
},
); );
fn test_parser( fn test_parser(
@ -62,7 +66,10 @@ 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((input, first + second.as_str())) Ok((
input,
first.iter().collect::<String>() + second.iter().collect::<String>().as_str(),
))
} }
parser_test_helper( parser_test_helper(
@ -76,4 +83,11 @@ 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)
});
}
} }

View File

@ -0,0 +1,37 @@
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),
))
}
}
}

View File

@ -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.1)))?; .or_else(|e| Err(anyhow!("{}", e)))?;
assert_eq!(nom_tokens.len(), zero_tokens.len()); assert_eq!(nom_tokens.len(), zero_tokens.len());