feat(ast,ipub): remove marshalling and unmarshalling logic from ast

This commit is contained in:
Guz
2025-05-26 09:28:20 -03:00
parent a4fc9176cd
commit acda6dbd24
5 changed files with 64 additions and 278 deletions

View File

@@ -1,95 +1,87 @@
package ast package ast
import ( import (
"encoding/xml"
"errors"
"fmt" "fmt"
"io"
"slices"
) )
type Element interface { type Node interface {
Name() ElementName Kind() NodeKind
Kind() ElementKind
NextSibling() Element NextSibling() Node
SetNextSibling(Element) SetNextSibling(Node)
PreviousSibling() Element PreviousSibling() Node
SetPreviousSibling(Element) SetPreviousSibling(Node)
Parent() Element Parent() Node
SetParent(Element) SetParent(Node)
HasChildren() bool HasChildren() bool
ChildCount() uint ChildCount() uint
FirstChild() Element FirstChild() Node
LastChild() Element LastChild() Node
AppendChild(self, v Element) AppendChild(self, v Node)
RemoveChild(self, v Element) RemoveChild(self, v Node)
RemoveChildren(self Element) RemoveChildren(self Node)
ReplaceChild(self, v1, insertee Element) ReplaceChild(self, v1, insertee Node)
InsertBefore(self, v1, insertee Element) InsertBefore(self, v1, insertee Node)
InsertAfter(self, v1, insertee Element) InsertAfter(self, v1, insertee Node)
xml.Marshaler
xml.Unmarshaler
} }
type BaseElement struct { type BaseNode struct {
next Element next Node
prev Element prev Node
parent Element parent Node
fisrtChild Element fisrtChild Node
lastChild Element lastChild Node
childCount uint childCount uint
} }
func (e *BaseElement) NextSibling() Element { func (e *BaseNode) NextSibling() Node {
return e.next return e.next
} }
func (e *BaseElement) SetNextSibling(v Element) { func (e *BaseNode) SetNextSibling(v Node) {
e.next = v e.next = v
} }
func (e *BaseElement) PreviousSibling() Element { func (e *BaseNode) PreviousSibling() Node {
return e.prev return e.prev
} }
func (e *BaseElement) SetPreviousSibling(v Element) { func (e *BaseNode) SetPreviousSibling(v Node) {
e.prev = v e.prev = v
} }
func (e *BaseElement) Parent() Element { func (e *BaseNode) Parent() Node {
return e.parent return e.parent
} }
func (e *BaseElement) SetParent(v Element) { func (e *BaseNode) SetParent(v Node) {
e.parent = v e.parent = v
} }
func (e *BaseElement) HasChildren() bool { func (e *BaseNode) HasChildren() bool {
return e.fisrtChild != nil return e.fisrtChild != nil
} }
func (e *BaseElement) ChildCount() uint { func (e *BaseNode) ChildCount() uint {
return e.childCount return e.childCount
} }
func (e *BaseElement) FirstChild() Element { func (e *BaseNode) FirstChild() Node {
return e.fisrtChild return e.fisrtChild
} }
func (e *BaseElement) LastChild() Element { func (e *BaseNode) LastChild() Node {
return e.lastChild return e.lastChild
} }
func (e *BaseElement) AppendChild(self, v Element) { func (e *BaseNode) AppendChild(self, v Node) {
ensureIsolated(v) ensureIsolated(v)
if e.fisrtChild == nil { if e.fisrtChild == nil {
@@ -107,7 +99,7 @@ func (e *BaseElement) AppendChild(self, v Element) {
e.childCount++ e.childCount++
} }
func (e *BaseElement) RemoveChild(self, v Element) { func (e *BaseNode) RemoveChild(self, v Node) {
if v.Parent() != self { if v.Parent() != self {
return return
} }
@@ -136,7 +128,7 @@ func (e *BaseElement) RemoveChild(self, v Element) {
v.SetPreviousSibling(nil) v.SetPreviousSibling(nil)
} }
func (e *BaseElement) RemoveChildren(_ Element) { func (e *BaseNode) RemoveChildren(_ Node) {
for c := e.fisrtChild; c != nil; { for c := e.fisrtChild; c != nil; {
c.SetParent(nil) c.SetParent(nil)
c.SetPreviousSibling(nil) c.SetPreviousSibling(nil)
@@ -149,16 +141,16 @@ func (e *BaseElement) RemoveChildren(_ Element) {
e.childCount = 0 e.childCount = 0
} }
func (e *BaseElement) ReplaceChild(self, v1, insertee Element) { func (e *BaseNode) ReplaceChild(self, v1, insertee Node) {
e.InsertBefore(self, v1, insertee) e.InsertBefore(self, v1, insertee)
e.RemoveChild(self, v1) e.RemoveChild(self, v1)
} }
func (e *BaseElement) InsertAfter(self, v1, insertee Element) { func (e *BaseNode) InsertAfter(self, v1, insertee Node) {
e.InsertBefore(self, v1.NextSibling(), insertee) e.InsertBefore(self, v1.NextSibling(), insertee)
} }
func (e *BaseElement) InsertBefore(self, v1, insertee Element) { func (e *BaseNode) InsertBefore(self, v1, insertee Node) {
e.childCount++ e.childCount++
if v1 == nil { if v1 == nil {
e.AppendChild(self, insertee) e.AppendChild(self, insertee)
@@ -183,149 +175,21 @@ func (e *BaseElement) InsertBefore(self, v1, insertee Element) {
} }
} }
func (e *BaseElement) UnmarshalXMLElement(self Element, d *xml.Decoder, start xml.StartElement) error { func ensureIsolated(e Node) {
elErr := fmt.Errorf("unable to unmarshal element kind %q", self.Kind())
if n := self.Name(); n != (xml.Name{}) {
if n != start.Name {
return errors.Join(
elErr,
fmt.Errorf("element has different name (%q) than expected (%q)",
fmtXMLName(start.Name), fmtXMLName(n)),
)
}
}
for {
token, err := d.Token()
if err != nil {
return err
}
if err == io.EOF {
return nil
}
switch tt := token.(type) {
case xml.StartElement:
elErr = errors.Join(elErr, fmt.Errorf("unable to unmarshal child element %q", fmtXMLName(tt.Name)))
i := slices.IndexFunc(tt.Attr, func(a xml.Attr) bool {
return a.Name == elementKindAttrName
})
if i == -1 {
return errors.Join(elErr, fmt.Errorf("element kind not specified"))
}
var k ElementKind
if err := k.UnmarshalXMLAttr(tt.Attr[i]); err != nil {
return errors.Join(elErr, err)
}
c := k.Element()
err := d.DecodeElement(c, &tt)
if err != nil && err != io.EOF {
return err
}
e.AppendChild(self, c)
}
}
}
func (e *BaseElement) MarshalXMLElement(self Element, enc *xml.Encoder, start xml.StartElement) error {
elErr := fmt.Errorf("unable to marshal element kind %q", self.Kind())
if n := self.Name(); n != (xml.Name{}) {
start.Name = self.Name()
}
ka, err := self.Kind().MarshalXMLAttr(elementKindAttrName)
if err != nil {
return errors.Join(elErr, err)
}
start.Attr = append(start.Attr, ka)
data := struct {
Children []Element `xml:",any"`
}{Children: []Element{}}
for c := self.FirstChild(); c != nil; {
data.Children = append(data.Children, c)
c = c.NextSibling()
}
err = enc.EncodeElement(&data, start)
if err != nil && err != io.EOF {
return err
return errors.Join(elErr, err)
}
return nil
}
func ensureIsolated(e Element) {
if p := e.Parent(); p != nil { if p := e.Parent(); p != nil {
p.RemoveChild(p, e) p.RemoveChild(p, e)
} }
} }
type ( type NodeKind string
ElementName = xml.Name
ElementKind string
)
func NewElementKind(kind string, e Element) ElementKind { func NewNodeKind(kind string, e Node) NodeKind {
k := ElementKind(kind) k := NodeKind(kind)
if _, ok := elementKindList[k]; ok { if _, ok := elementKindList[k]; ok {
panic(fmt.Sprintf("Element kind %q is already registered", k)) panic(fmt.Sprintf("Node kind %q is already registered", k))
} }
elementKindList[k] = e elementKindList[k] = e
return k return k
} }
var ( var elementKindList = make(map[NodeKind]Node)
_ xml.MarshalerAttr = ElementKind("")
_ xml.UnmarshalerAttr = (*ElementKind)(nil)
_ fmt.Stringer = ElementKind("")
)
func (k ElementKind) MarshalXMLAttr(n xml.Name) (xml.Attr, error) {
if n != elementKindAttrName {
return xml.Attr{}, ErrInvalidAttrName{Actual: n, Expected: elementKindAttrName}
}
return xml.Attr{
Name: elementKindAttrName,
Value: k.String(),
}, nil
}
func (k *ElementKind) UnmarshalXMLAttr(attr xml.Attr) error {
if attr.Name != elementKindAttrName {
return ErrInvalidAttrName{Actual: attr.Name, Expected: elementKindAttrName}
}
ak := ElementKind(attr.Value)
if _, ok := elementKindList[ak]; !ok {
return ErrInvalidAttrValue{Attr: attr, Message: "element kind not registered"}
}
*k = ak
return nil
}
func (k ElementKind) String() string {
return string(k)
}
func (k ElementKind) Element() Element {
return elementKindList[k]
}
var (
elementKindList = make(map[ElementKind]Element)
elementKindAttrName = xml.Name{Local: "data-ipub-element"}
)

View File

@@ -1,68 +1,27 @@
package ast package ast
import (
"encoding/xml"
"slices"
)
type Content struct { type Content struct {
BaseElement BaseNode
} }
var KindContent = NewElementKind("content", &Content{}) var KindContent = NewNodeKind("content", &Content{})
func (e Content) Name() ElementName { func (e Content) Kind() NodeKind {
return ElementName{Local: "section"}
}
func (e Content) Kind() ElementKind {
return KindContent return KindContent
} }
func (e *Content) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
return e.MarshalXMLElement(e, enc, start)
}
func (e *Content) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
return e.UnmarshalXMLElement(e, dec, start)
}
type Image struct { type Image struct {
src string src string
BaseElement BaseNode
} }
var KindImage = NewElementKind("image", &Image{}) var KindImage = NewNodeKind("image", &Image{})
func (e *Image) Name() ElementName { func (e *Image) Kind() NodeKind {
return ElementName{Local: "img"}
}
func (e *Image) Kind() ElementKind {
return KindImage return KindImage
} }
func (e *Image) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
if src := e.Source(); src != "" {
start.Attr = append(start.Attr, xml.Attr{
Name: xml.Name{Local: "src"},
Value: src,
})
}
return e.MarshalXMLElement(e, enc, start)
}
func (e *Image) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
i := slices.IndexFunc(start.Attr, func(a xml.Attr) bool {
return a.Name == xml.Name{Local: "src"}
})
if i > -1 {
e.SetSource(start.Attr[i].Value)
}
return e.UnmarshalXMLElement(e, dec, start)
}
func (e Image) Source() string { func (e Image) Source() string {
return e.src return e.src
} }

View File

@@ -1,36 +0,0 @@
package ast
import (
"encoding/xml"
"fmt"
)
type ErrInvalidAttrName struct {
Actual xml.Name
Expected xml.Name
}
var _ error = ErrInvalidAttrName{}
func (err ErrInvalidAttrName) Error() string {
return fmt.Sprintf("attribute %q has invalid name, expected %q", fmtXMLName(err.Expected), fmtXMLName(err.Actual))
}
type ErrInvalidAttrValue struct {
Attr xml.Attr
Message string
}
var _ error = ErrInvalidAttrValue{}
func (err ErrInvalidAttrValue) Error() string {
return fmt.Sprintf("attribute %q's value %q is invalid: %s", fmtXMLName(err.Attr.Name), err.Attr.Value, err.Message)
}
func fmtXMLName(n xml.Name) string {
s := n.Local
if n.Space != "" {
s = fmt.Sprintf("%s:%s", n.Space, n.Local)
}
return s
}

11
ipub/ast/package.go Normal file
View File

@@ -0,0 +1,11 @@
package ast
type Package struct {
BaseNode
}
var KindPackage = NewNodeKind("package", &Package{})
func (e Package) Kind() NodeKind {
return KindPackage
}

View File

@@ -10,23 +10,11 @@ type Section struct {
} }
type Body struct { type Body struct {
BaseElement BaseNode
} }
var KindBody = NewElementKind("body", &Body{}) var KindBody = NewNodeKind("body", &Body{})
func (e Body) Name() ElementName { func (e Body) Kind() NodeKind {
return ElementName{Local: "body"}
}
func (e Body) Kind() ElementKind {
return KindBody return KindBody
} }
func (e *Body) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
return e.MarshalXMLElement(e, enc, start)
}
func (e *Body) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
return e.UnmarshalXMLElement(e, dec, start)
}