diff options
author | Thomas Voss <mail@thomasvoss.com> | 2023-09-09 23:03:57 +0200 |
---|---|---|
committer | Thomas Voss <mail@thomasvoss.com> | 2023-09-09 23:03:57 +0200 |
commit | 8fd0f17b7bcca4725046ca82d3193b9986fe1faa (patch) | |
tree | e0ab1680bba6bee3eb2cc653d88111b153fd396f /parser/parser.go | |
parent | 96aef4c6a473e380b027a7b9db87cbbbcbae1cba (diff) |
Add primitive support for doctypes and XML
Diffstat (limited to 'parser/parser.go')
-rw-r--r-- | parser/parser.go | 65 |
1 files changed, 63 insertions, 2 deletions
diff --git a/parser/parser.go b/parser/parser.go index 9e0a329..1101e65 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -12,9 +12,11 @@ import ( type nodeType uint const ( - Normal nodeType = iota + DocType nodeType = iota + Normal Tagless Text + XmlDocType ) type Attr struct { @@ -31,7 +33,66 @@ type AstNode struct { func ParseFile(file *os.File) (AstNode, error) { r := reader{r: bufio.NewReader(file)} - return r.parseNode() + return r.parseDocument() +} + +func (reader *reader) parseDocument() (AstNode, error) { + document := AstNode{Type: Tagless} + if doctype, err, exists := reader.parseDocType(); err != nil { + return AstNode{}, err + } else if exists { + document.Children = append(document.Children, doctype) + } + + if node, err := reader.parseNode(); err != nil { + return AstNode{}, err + } else { + document.Children = append(document.Children, node) + } + + return document, nil +} + +func (reader *reader) parseDocType() (AstNode, error, bool) { + doctype := AstNode{} + + r, err := reader.readNonSpaceRune() + if err != nil { + return AstNode{}, err, false + } + + switch r { + case '!': + doctype.Type = DocType + case '?': + doctype.Type = XmlDocType + default: + return AstNode{}, reader.unreadRune(), false + } + + if attrs, err := reader.parseAttrs(); err != nil { + return AstNode{}, err, false + } else { + doctype.Attrs = attrs + } + + // The above call to reader.parseAttrs() guarantees that we have the ā{ā + // token. + if _, err := reader.readRune(); err != nil { + return AstNode{}, err, false + } + + if r, err := reader.readNonSpaceRune(); err != nil { + return AstNode{}, err, false + } else if r != '}' { + return AstNode{}, invalidSyntax{ + pos: reader.pos, + expected: "empty body (doctypes must have empty bodies)", + found: fmt.Sprintf("ā%cā\n", r), + }, false + } + + return doctype, nil, true } func (reader *reader) parseNode() (AstNode, error) { |