WIP: more parsers
This commit is contained in:
parent
ea98ddced7
commit
9307f48d17
176
src/parser.rs
176
src/parser.rs
|
@ -2,7 +2,7 @@ use std::char;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
branch::{alt, permutation},
|
branch::{alt, permutation},
|
||||||
bytes::streaming::{is_a, is_not, tag, take, take_till, take_until},
|
bytes::streaming::{is_a, is_not, tag, tag_no_case, take, take_till, take_until},
|
||||||
character::{
|
character::{
|
||||||
complete::one_of,
|
complete::one_of,
|
||||||
streaming::{alpha1, char, digit1, none_of, satisfy},
|
streaming::{alpha1, char, digit1, none_of, satisfy},
|
||||||
|
@ -16,13 +16,6 @@ use nom::{
|
||||||
|
|
||||||
// parser: parses tokens from lexer into events
|
// parser: parses tokens from lexer into events
|
||||||
|
|
||||||
type Comment<'s> = &'s str;
|
|
||||||
|
|
||||||
struct PI<'s> {
|
|
||||||
target: &'s str,
|
|
||||||
instruction: Option<&'s str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ContentItem<'s> {
|
enum ContentItem<'s> {
|
||||||
CharData(&'s str),
|
CharData(&'s str),
|
||||||
Element(Element<'s>),
|
Element(Element<'s>),
|
||||||
|
@ -197,79 +190,85 @@ pub fn pubid_char(input: &str) -> IResult<&str, PubidChar> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: wtf why doesn't this work how do i do thisjj
|
|
||||||
type CharData<'s> = &'s str;
|
type CharData<'s> = &'s str;
|
||||||
/// [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
|
/// [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
|
||||||
pub fn char_data(input: &str) -> IResult<&str, CharData> {
|
pub fn char_data(input: &str) -> IResult<&str, CharData> {
|
||||||
// tag(map(
|
recognize(many_till(
|
||||||
// peek(alt((
|
none_of("<&"),
|
||||||
// map_parser(
|
peek(alt((recognize(one_of("<&")), tag("]]>")))),
|
||||||
// peek(take_until("]]>")),
|
))(input)
|
||||||
// nom::bytes::complete::take_till(|c| c == '<' || c == '&'),
|
|
||||||
// ),
|
|
||||||
// map_parser(
|
|
||||||
// peek(take_till(|c| c == '<' || c == '&')),
|
|
||||||
// nom::bytes::complete::take_until("]]>"),
|
|
||||||
// ),
|
|
||||||
// ))),
|
|
||||||
// |(first, _)| first,
|
|
||||||
// ))(input)
|
|
||||||
|
|
||||||
// map(
|
// let tagg: &str;
|
||||||
// tuple((is_not("<&]"), peek(alt((tag("<"), tag("&"), tag("]]>")))))),
|
// if let Ok((_, tagg1)) = peek(take_until::<&str, &str, Error<&str>>("]]>"))(input) {
|
||||||
// |(first, _)| first,
|
// if let Ok((_, tagg2)) =
|
||||||
// )(input)
|
// peek::<&str, &str, Error<&str>, _>(take_till(|c: char| c == '<' || c == '&'))(input)
|
||||||
// map(
|
// {
|
||||||
// tuple((recognize(many0(none_of("<&"))), opt(peek(tag("]]>"))))),
|
// if tagg1.len() < tagg2.len() {
|
||||||
// |(first, _)| first,
|
// tagg = tagg1
|
||||||
// )(input)
|
// } else {
|
||||||
// alt((recognize(many0(none_of("<&"))), take_until("]]>")))(input)
|
// tagg = tagg2
|
||||||
let tagg: &str;
|
|
||||||
if let Ok((_, tagg1)) = peek(take_until::<&str, &str, Error<&str>>("]]>"))(input) {
|
|
||||||
if let Ok((_, tagg2)) =
|
|
||||||
peek::<&str, &str, Error<&str>, _>(take_till(|c: char| c == '<' || c == '&'))(input)
|
|
||||||
{
|
|
||||||
if tagg1.len() < tagg2.len() {
|
|
||||||
tagg = tagg1
|
|
||||||
} else {
|
|
||||||
tagg = tagg2
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tagg = tagg1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(_, tagg) = peek(take_till(|c| c == '<' || c == '&'))(input)?
|
|
||||||
}
|
|
||||||
tag(tagg)(input)
|
|
||||||
// let mut len = 0;
|
|
||||||
// let ch = input.chars().collect::<Vec<_>>();
|
|
||||||
// for (idx, char) in ch.as_ref().into_iter().enumerate() {
|
|
||||||
// match char {
|
|
||||||
// '<' | '&' => break,
|
|
||||||
// ']' => {
|
|
||||||
// if idx <= ch.len() - 3 {}
|
|
||||||
// },
|
|
||||||
// _ => todo!(),
|
|
||||||
// }
|
// }
|
||||||
|
// } else {
|
||||||
|
// tagg = tagg1;
|
||||||
// }
|
// }
|
||||||
// while let Some(char) = chars.next() {
|
// } else {
|
||||||
// if char == '<' || char == '&' {
|
// (_, tagg) = peek(take_till(|c| c == '<' || c == '&'))(input)?
|
||||||
// break;
|
|
||||||
// } else if char == ']' {
|
|
||||||
// if let Some(next) = chars.peek() {
|
|
||||||
// if next == ']' {
|
|
||||||
// if let Some(next) = chars.next_if_eq() {}
|
|
||||||
// }
|
// }
|
||||||
// }
|
// tag(tagg)(input)
|
||||||
// }
|
|
||||||
// len += 1;
|
|
||||||
// }
|
|
||||||
// todo!()
|
|
||||||
// recognize(many0(permutation((none_of("<&"), not(tag("]]>"))))))(input)
|
// recognize(many0(permutation((none_of("<&"), not(tag("]]>"))))))(input)
|
||||||
// recognize(many0(not(alt((tag("<"), tag("&"), tag("]]>"))))))(input)
|
// recognize(many0(not(alt((tag("<"), tag("&"), tag("]]>"))))))(input)
|
||||||
// take_till(|c| c == '<' || c == '&').and_then(take_until("]]>"))(input)
|
// take_till(|c| c == '<' || c == '&').and_then(take_until("]]>"))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Comment<'s> = &'s str;
|
||||||
|
/// Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
|
||||||
|
pub fn comment(input: &str) -> IResult<&str, Comment> {
|
||||||
|
delimited(
|
||||||
|
tag("<!--"),
|
||||||
|
recognize(many_till(xmlchar, peek(tag("--")))),
|
||||||
|
tag("-->"),
|
||||||
|
)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PI<'s> {
|
||||||
|
target: &'s str,
|
||||||
|
instruction: Option<&'s str>,
|
||||||
|
}
|
||||||
|
/// [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
|
||||||
|
pub fn pi(input: &str) -> IResult<&str, PI> {
|
||||||
|
let (rest, (target, instruction)) = delimited(
|
||||||
|
tag("<?"),
|
||||||
|
pair(
|
||||||
|
pi_target,
|
||||||
|
opt(recognize(pair(s, many_till(xmlchar, peek(tag("?>")))))),
|
||||||
|
),
|
||||||
|
tag("?>"),
|
||||||
|
)(input)?;
|
||||||
|
Ok((
|
||||||
|
rest,
|
||||||
|
PI {
|
||||||
|
target,
|
||||||
|
instruction,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
type PITarget<'s> = &'s str;
|
||||||
|
/// [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
|
||||||
|
pub fn pi_target(input: &str) -> IResult<&str, PITarget> {
|
||||||
|
let (rest, name) = name(input)?;
|
||||||
|
if name.to_lowercase() == "xml" {
|
||||||
|
return Err(Err::Error(Error {
|
||||||
|
input,
|
||||||
|
// TODO: check if better error to return
|
||||||
|
code: ErrorKind::Tag,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
return Ok((rest, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Prolog<'s> = (
|
type Prolog<'s> = (
|
||||||
Option<XMLDecl>,
|
Option<XMLDecl>,
|
||||||
Vec<Misc<'s>>,
|
Vec<Misc<'s>>,
|
||||||
|
@ -320,8 +319,8 @@ pub fn version_info(input: &str) -> IResult<&str, VersionInfo> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [25] Eq ::= S? '=' S?
|
/// [25] Eq ::= S? '=' S?
|
||||||
pub fn eq(input: &str) -> IResult<&str, (Option<&str>, char, Option<&str>)> {
|
pub fn eq(input: &str) -> IResult<&str, &str> {
|
||||||
tuple((opt(s), char('='), opt(s)))(input)
|
recognize(tuple((opt(s), char('='), opt(s))))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -363,9 +362,42 @@ mod tests {
|
||||||
assert_eq!(Ok(("&ghi", "abc]>def")), char_data("abc]>def&ghi"));
|
assert_eq!(Ok(("&ghi", "abc]>def")), char_data("abc]>def&ghi"));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(Err::Incomplete(nom::Needed::Size(
|
Err(Err::Incomplete(nom::Needed::Size(
|
||||||
NonZero::new(1usize).unwrap()
|
NonZero::new(3usize).unwrap()
|
||||||
))),
|
))),
|
||||||
char_data("abcdefghi")
|
char_data("abcdefghi")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_comment() {
|
||||||
|
assert_eq!(Ok(("", "")), comment("<!---->"));
|
||||||
|
assert_eq!(Ok(("", "asdf")), comment("<!--asdf-->"));
|
||||||
|
assert_eq!(Ok(("", "as-df")), comment("<!--as-df-->"));
|
||||||
|
assert_eq!(
|
||||||
|
Err(Err::Incomplete(nom::Needed::Size(
|
||||||
|
NonZero::new(2usize).unwrap()
|
||||||
|
))),
|
||||||
|
comment("<!--asdf")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pi_target() {
|
||||||
|
assert_eq!(Ok((" ", "asdf")), pi_target("asdf "));
|
||||||
|
assert_eq!(Ok((" ", "xmlasdf")), pi_target("xmlasdf "));
|
||||||
|
assert_eq!(
|
||||||
|
Err(Err::Error(Error {
|
||||||
|
input: "xml ",
|
||||||
|
code: ErrorKind::Tag
|
||||||
|
})),
|
||||||
|
pi_target("xml ")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(Err::Error(Error {
|
||||||
|
input: "xMl ",
|
||||||
|
code: ErrorKind::Tag
|
||||||
|
})),
|
||||||
|
pi_target("xMl ")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue