diff --git a/src/glxml.gleam b/src/glxml.gleam index da1d18d..5c417db 100644 --- a/src/glxml.gleam +++ b/src/glxml.gleam @@ -39,16 +39,16 @@ pub type Element { pub fn main() { parse_document( - "\r\n \n", + "\r\n \n", ) |> echo } pub fn default_entities() -> dict.Dict(String, Entity) { dict.from_list([ - #("lt", InternalEntity("&#60;")), - #("gt", InternalEntity("#62;")), - #("amp", InternalEntity("&#38;")), + #("lt", InternalEntity("<")), + #("gt", InternalEntity(">")), + #("amp", InternalEntity("&")), #("apos", InternalEntity("'")), #("quot", InternalEntity(""")), ]) @@ -60,7 +60,7 @@ fn parse_document(doc: String) -> Result(Document, Nil) { use #(element, doc) <- result.try(parse_element(doc, doctype)) let doc = parse_misc(doc) - case doc |> echo { + case doc { "" -> Ok(Document(decl, doctype, Some(element))) _ -> Error(Nil) } @@ -77,7 +77,7 @@ fn parse_empty_elem( doc: String, doctype: Option(DocType), ) -> Result(#(Element, String), Nil) { - case doc |> echo { + case doc { "<" <> tail -> { use #(name, doc) <- result.try(parse_name(tail)) use #(attrs, doc) <- result.try(parse_attributes(doc, doctype, [])) @@ -184,19 +184,19 @@ fn parse_reference( ";" <> tail -> { use value <- result.try(int.base_parse(digits, 16)) use codepoint <- result.try(string.utf_codepoint(value)) - Ok(#("", string.from_utf_codepoints([codepoint]) <> tail)) + Ok(#(string.from_utf_codepoints([codepoint]), tail)) } _ -> Error(Nil) } } _ -> { use #(digits, doc) <- result.try(parse_multiple(tail, parse_digit)) - case doc { ";" <> tail -> { use value <- result.try(int.base_parse(digits, 10)) use codepoint <- result.try(string.utf_codepoint(value)) - Ok(#("", string.from_utf_codepoints([codepoint]) <> tail)) + + Ok(#(string.from_utf_codepoints([codepoint]), tail)) } _ -> Error(Nil) } @@ -207,7 +207,10 @@ fn parse_reference( use #(name, doc) <- result.try(parse_name(tail)) case doc { - ";" <> tail -> Ok(#(char <> name <> ";", tail)) + ";" <> tail -> { + use value <- result.try(process_reference(name, doctype)) + Ok(#("", value <> tail)) + } _ -> Error(Nil) } } @@ -215,6 +218,36 @@ fn parse_reference( } } +fn process_reference( + ref: String, + doctype: Option(DocType), +) -> Result(String, Nil) { + case doctype { + Some(DocType(_, entities)) -> { + get_reference(entities, ref) + } + None -> { + get_reference(default_entities(), ref) + } + } +} + +fn get_reference( + entities: dict.Dict(String, Entity), + ref: String, +) -> Result(String, Nil) { + case dict.get(entities, ref) { + Ok(InternalEntity(val)) -> Ok(val) + Ok(PublicExternalEntity(_, _)) | Ok(SystemExternalEntity(_)) -> Error(Nil) + Error(_) -> { + case entities == default_entities() { + True -> Error(Nil) + False -> get_reference(default_entities(), ref) + } + } + } +} + fn parse_name(doc: String) -> Result(#(String, String), Nil) { case parse_name_start_char(doc) { Ok(#(char, tail)) -> {