From 8fd0f17b7bcca4725046ca82d3193b9986fe1faa Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Sat, 9 Sep 2023 23:03:57 +0200 Subject: Add primitive support for doctypes and XML --- parser/parser.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) (limited to 'parser') 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) { -- cgit v1.2.3