diff --git a/src/glxml.gleam b/src/glxml.gleam index 2fd15a7..f8fe4db 100644 --- a/src/glxml.gleam +++ b/src/glxml.gleam @@ -38,11 +38,13 @@ pub type Element { Text(content: String) Comment(content: String) CData(content: String) + PI(name: String, content: String) + Whitespace } pub fn main() { parse_document( - "\r\n \n]]>", + "\r\n \n]]>", ) |> echo } @@ -153,13 +155,9 @@ fn parse_content( try_parsers( [ parse_element(_, doctype), - fn(doc) { - case parse_comment(doc) { - Ok(#(comment, doc)) -> Ok(#(Comment(comment), doc)) - Error(_) -> Error(Nil) - } - }, + parse_comment, parse_cdata, + parse_pi, ], doc, ) @@ -172,6 +170,38 @@ fn parse_content( } } +fn parse_pi(doc: String) -> Result(#(Element, String), Nil) { + case doc { + " tail -> { + use #(name, doc) <- result.try(parse_name(tail)) + use <- bool.guard( + when: string.lowercase(name) == "xml", + return: Error(Nil), + ) + let doc = trim_space(doc) + use #(content, doc) <- result.try(parse_pi_content(doc, "")) + case doc { + "?>" <> tail -> Ok(#(PI(name, content), tail)) + _ -> Error(Nil) + } + } + _ -> Error(Nil) + } +} + +fn parse_pi_content(doc: String, pi: String) -> Result(#(String, String), Nil) { + case doc { + "?>" <> _ -> Ok(#(pi, doc)) + "" -> Error(Nil) + _ -> { + case parse_char(doc) { + Ok(#(char, doc)) -> parse_pi_content(doc, pi <> char) + Error(_) -> Ok(#(pi, doc)) + } + } + } +} + fn parse_cdata(doc: String) -> Result(#(Element, String), Nil) { case doc { " tail -> { @@ -404,13 +434,22 @@ fn parse_prolog( } fn parse_misc(doc: String) -> String { - let #(_, doc) = - parse_multiple_optional( + case + try_parsers( + [ + parse_comment, + fn(doc) { + parse_space(doc) + |> result.map(fn(sp) { #(Whitespace, sp.1) }) + }, + parse_pi, + ], doc, - try_parsers([parse_comment, parse_space], _), - "", ) - doc + { + Ok(#(_element, doc)) -> parse_misc(doc) + Error(Nil) -> doc + } } fn parse_decl(doc: String) -> Result(#(Declaration, String), Nil) { @@ -640,12 +679,12 @@ fn parse_alpha(doc: String) -> Result(#(String, String), Nil) { } } -fn parse_comment(doc: String) -> Result(#(String, String), Nil) { +fn parse_comment(doc: String) -> Result(#(Element, String), Nil) { case doc { "" <> tail -> Ok(#(comment, tail)) + "-->" <> tail -> Ok(#(Comment(comment), tail)) _ -> Error(Nil) } }