diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-12-02 18:00:29 +0100 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-12-05 02:52:23 +0100 |
| commit | 580721440657a9fe5334b6bf095fb70b584fa4f6 (patch) | |
| tree | ba857c3ce7cdd42d8da515a39e27da0d1162d54d /core | |
| parent | 23baf56c8784901f67970760db5025c9c9f03b67 (diff) | |
[xml] Improvements.
Diffstat (limited to 'core')
| -rw-r--r-- | core/encoding/xml/example/xml_example.odin | 69 | ||||
| -rw-r--r-- | core/encoding/xml/helpers.odin | 49 | ||||
| -rw-r--r-- | core/encoding/xml/tokenizer.odin | 6 | ||||
| -rw-r--r-- | core/encoding/xml/xml_reader.odin | 2 |
4 files changed, 94 insertions, 32 deletions
diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin index 82938c223..085252e92 100644 --- a/core/encoding/xml/example/xml_example.odin +++ b/core/encoding/xml/example/xml_example.odin @@ -1,45 +1,55 @@ package xml_example import "core:encoding/xml" +import "core:os" +import "core:path" import "core:mem" -import "core:strings" import "core:fmt" -Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) { +/* + Silent error handler for the parser. +*/ +Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} -} - -FILENAME :: "../../../../tests/core/assets/xml/nl_NL-xliff-1.0.xliff" -DOC :: #load(FILENAME) - -OPTIONS :: xml.Options{ - flags = { - .Ignore_Unsupported, .Intern_Comments, - }, - expected_doctype = "", -} +OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } -_main :: proc() { +example :: proc() { using fmt - println("--- DOCUMENT TO PARSE ---") - println(string(DOC)) - println("--- /DOCUMENT TO PARSE ---\n") + filename := path.join(ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml") + defer delete(filename) - doc, err := xml.parse(DOC, OPTIONS, FILENAME, Error_Handler) + doc, err := xml.parse(filename, OPTIONS, Error_Handler) defer xml.destroy(doc) - buf: strings.Builder - defer strings.destroy_builder(&buf) - w := strings.to_writer(&buf) + if err != .None { + printf("Load/Parse error: %v\n", err) + if err == .File_Error { + printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename) + } + os.exit(1) + } - xml.print(w, doc) - println(strings.to_string(buf)) + printf("\"%v\" loaded and parsed.\n", filename) - if err != .None { - printf("Parse error: %v\n", err) - } else { - println("DONE!") + charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist") + if !charlist_ok { + eprintln("Could not locate top-level `<charlist>` tag.") + os.exit(1) + } + + printf("Found `<charlist>` with %v children.\n", len(charlist.children)) + + for char in charlist.children { + if char.ident != "character" { + eprintf("Expected `<character>`, got `<%v>`\n", char.ident) + os.exit(1) + } + + if _, ok := xml.find_attribute_val_by_key(char, "dec"); !ok { + eprintln("`<character dec=\"...\">` attribute not found.") + os.exit(1) + } } } @@ -50,12 +60,13 @@ main :: proc() { mem.tracking_allocator_init(&track, context.allocator) context.allocator = mem.tracking_allocator(&track) - _main() + example() if len(track.allocation_map) > 0 { println() for _, v in track.allocation_map { printf("%v Leaked %v bytes.\n", v.location, v.size) } - } + } + println("Done and cleaned up!") }
\ No newline at end of file diff --git a/core/encoding/xml/helpers.odin b/core/encoding/xml/helpers.odin new file mode 100644 index 000000000..14597ddbd --- /dev/null +++ b/core/encoding/xml/helpers.odin @@ -0,0 +1,49 @@ +package xml +/* + An XML 1.0 / 1.1 parser + + Copyright 2021 Jeroen van Rijn <nom@duclavier.com>. + Made available under Odin's BSD-3 license. + + This file contains helper functions. +*/ + + +/* + Find `tag`'s nth child with a given ident. +*/ +find_child_by_ident :: proc(tag: ^Element, ident: string, nth := 0) -> (res: ^Element, found: bool) { + if tag == nil { return nil, false } + + count := 0 + for child in tag.children { + /* + Skip commments. They have no name. + */ + if child.kind != .Element { continue } + + /* + If the ident matches and it's the nth such child, return it. + */ + if child.ident == ident { + if count == nth { return child, true } + count += 1 + } + } + return nil, false +} + +/* + Find an attribute by key. +*/ +find_attribute_val_by_key :: proc(tag: ^Element, key: string) -> (val: string, found: bool) { + if tag == nil { return "", false } + + for attr in tag.attribs { + /* + If the ident matches, we're done. There can only ever be one attribute with the same name. + */ + if attr.key == key { return attr.val, true } + } + return "", false +}
\ No newline at end of file diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 95024518d..2da3b7683 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -403,11 +403,11 @@ scan :: proc(t: ^Tokenizer) -> Token { case ':': kind = .Colon case '"', '\'': + kind = .Invalid + lit, err = scan_string(t, t.offset, ch, true, false) if err == .None { kind = .String - } else { - kind = .Invalid } case '\n': @@ -418,7 +418,7 @@ scan :: proc(t: ^Tokenizer) -> Token { } } - if lit == "" { + if kind != .String && lit == "" { lit = string(t.src[offset : t.offset]) } return Token{kind, lit, pos} diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 146c278cb..563294309 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -519,6 +519,8 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attr, offset: int, err: Error) _ = expect(t, .Eq) or_return value := expect(t, .String) or_return + error(t, t.offset, "String: %v\n", value) + attr.key = strings.intern_get(&doc.intern, key.text) attr.val = strings.intern_get(&doc.intern, value.text) |