package ast
import (
"bytes"
"fmt"
"strings"
textm "github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
type NodeType int
const (
TypeBlock NodeType = iota + 1
TypeInline
TypeDocument
)
type NodeKind int
func (k NodeKind ) String () string {
return kindNames [k ]
}
var kindMax NodeKind
var kindNames = []string {"" }
func NewNodeKind (name string ) NodeKind {
kindMax ++
kindNames = append (kindNames , name )
return kindMax
}
type Attribute struct {
Name []byte
Value interface {}
}
type Node interface {
Type () NodeType
Kind () NodeKind
NextSibling () Node
PreviousSibling () Node
Parent () Node
SetParent (Node )
SetPreviousSibling (Node )
SetNextSibling (Node )
HasChildren () bool
ChildCount () int
FirstChild () Node
LastChild () Node
AppendChild (self, child Node )
RemoveChild (self, child Node )
RemoveChildren (self Node )
SortChildren (comparator func (n1, n2 Node ) int )
ReplaceChild (self, v1, insertee Node )
InsertBefore (self, v1, insertee Node )
InsertAfter (self, v1, insertee Node )
OwnerDocument () *Document
Dump (source []byte , level int )
Text (source []byte ) []byte
HasBlankPreviousLines () bool
SetBlankPreviousLines (v bool )
Lines () *textm .Segments
SetLines (*textm .Segments )
IsRaw () bool
SetAttribute (name []byte , value interface {})
SetAttributeString (name string , value interface {})
Attribute (name []byte ) (interface {}, bool )
AttributeString (name string ) (interface {}, bool )
Attributes () []Attribute
RemoveAttributes ()
}
type BaseNode struct {
firstChild Node
lastChild Node
parent Node
next Node
prev Node
childCount int
attributes []Attribute
}
func ensureIsolated(v Node ) {
if p := v .Parent (); p != nil {
p .RemoveChild (p , v )
}
}
func (n *BaseNode ) HasChildren () bool {
return n .firstChild != nil
}
func (n *BaseNode ) SetPreviousSibling (v Node ) {
n .prev = v
}
func (n *BaseNode ) SetNextSibling (v Node ) {
n .next = v
}
func (n *BaseNode ) PreviousSibling () Node {
return n .prev
}
func (n *BaseNode ) NextSibling () Node {
return n .next
}
func (n *BaseNode ) RemoveChild (self , v Node ) {
if v .Parent () != self {
return
}
n .childCount --
prev := v .PreviousSibling ()
next := v .NextSibling ()
if prev != nil {
prev .SetNextSibling (next )
} else {
n .firstChild = next
}
if next != nil {
next .SetPreviousSibling (prev )
} else {
n .lastChild = prev
}
v .SetParent (nil )
v .SetPreviousSibling (nil )
v .SetNextSibling (nil )
}
func (n *BaseNode ) RemoveChildren (self Node ) {
for c := n .firstChild ; c != nil ; {
c .SetParent (nil )
c .SetPreviousSibling (nil )
next := c .NextSibling ()
c .SetNextSibling (nil )
c = next
}
n .firstChild = nil
n .lastChild = nil
n .childCount = 0
}
func (n *BaseNode ) SortChildren (comparator func (n1 , n2 Node ) int ) {
var sorted Node
current := n .firstChild
for current != nil {
next := current .NextSibling ()
if sorted == nil || comparator (sorted , current ) >= 0 {
current .SetNextSibling (sorted )
if sorted != nil {
sorted .SetPreviousSibling (current )
}
sorted = current
sorted .SetPreviousSibling (nil )
} else {
c := sorted
for c .NextSibling () != nil && comparator (c .NextSibling (), current ) < 0 {
c = c .NextSibling ()
}
current .SetNextSibling (c .NextSibling ())
current .SetPreviousSibling (c )
if c .NextSibling () != nil {
c .NextSibling ().SetPreviousSibling (current )
}
c .SetNextSibling (current )
}
current = next
}
n .firstChild = sorted
for c := n .firstChild ; c != nil ; c = c .NextSibling () {
n .lastChild = c
}
}
func (n *BaseNode ) FirstChild () Node {
return n .firstChild
}
func (n *BaseNode ) LastChild () Node {
return n .lastChild
}
func (n *BaseNode ) ChildCount () int {
return n .childCount
}
func (n *BaseNode ) Parent () Node {
return n .parent
}
func (n *BaseNode ) SetParent (v Node ) {
n .parent = v
}
func (n *BaseNode ) AppendChild (self , v Node ) {
ensureIsolated (v )
if n .firstChild == nil {
n .firstChild = v
v .SetNextSibling (nil )
v .SetPreviousSibling (nil )
} else {
last := n .lastChild
last .SetNextSibling (v )
v .SetPreviousSibling (last )
}
v .SetParent (self )
n .lastChild = v
n .childCount ++
}
func (n *BaseNode ) ReplaceChild (self , v1 , insertee Node ) {
n .InsertBefore (self , v1 , insertee )
n .RemoveChild (self , v1 )
}
func (n *BaseNode ) InsertAfter (self , v1 , insertee Node ) {
n .InsertBefore (self , v1 .NextSibling (), insertee )
}
func (n *BaseNode ) InsertBefore (self , v1 , insertee Node ) {
n .childCount ++
if v1 == nil {
n .AppendChild (self , insertee )
return
}
ensureIsolated (insertee )
if v1 .Parent () == self {
c := v1
prev := c .PreviousSibling ()
if prev != nil {
prev .SetNextSibling (insertee )
insertee .SetPreviousSibling (prev )
} else {
n .firstChild = insertee
insertee .SetPreviousSibling (nil )
}
insertee .SetNextSibling (c )
c .SetPreviousSibling (insertee )
insertee .SetParent (self )
}
}
func (n *BaseNode ) OwnerDocument () *Document {
d := n .Parent ()
for {
p := d .Parent ()
if p == nil {
if v , ok := d .(*Document ); ok {
return v
}
break
}
d = p
}
return nil
}
func (n *BaseNode ) Text (source []byte ) []byte {
var buf bytes .Buffer
for c := n .firstChild ; c != nil ; c = c .NextSibling () {
buf .Write (c .Text (source ))
}
return buf .Bytes ()
}
func (n *BaseNode ) SetAttribute (name []byte , value interface {}) {
if n .attributes == nil {
n .attributes = make ([]Attribute , 0 , 10 )
} else {
for i , a := range n .attributes {
if bytes .Equal (a .Name , name ) {
n .attributes [i ].Name = name
n .attributes [i ].Value = value
return
}
}
}
n .attributes = append (n .attributes , Attribute {name , value })
}
func (n *BaseNode ) SetAttributeString (name string , value interface {}) {
n .SetAttribute (util .StringToReadOnlyBytes (name ), value )
}
func (n *BaseNode ) Attribute (name []byte ) (interface {}, bool ) {
if n .attributes == nil {
return nil , false
}
for i , a := range n .attributes {
if bytes .Equal (a .Name , name ) {
return n .attributes [i ].Value , true
}
}
return nil , false
}
func (n *BaseNode ) AttributeString (s string ) (interface {}, bool ) {
return n .Attribute (util .StringToReadOnlyBytes (s ))
}
func (n *BaseNode ) Attributes () []Attribute {
return n .attributes
}
func (n *BaseNode ) RemoveAttributes () {
n .attributes = nil
}
func DumpHelper (v Node , source []byte , level int , kv map [string ]string , cb func (int )) {
name := v .Kind ().String ()
indent := strings .Repeat (" " , level )
fmt .Printf ("%s%s {\n" , indent , name )
indent2 := strings .Repeat (" " , level +1 )
if v .Type () == TypeBlock {
fmt .Printf ("%sRawText: \"" , indent2 )
for i := 0 ; i < v .Lines ().Len (); i ++ {
line := v .Lines ().At (i )
fmt .Printf ("%s" , line .Value (source ))
}
fmt .Printf ("\"\n" )
fmt .Printf ("%sHasBlankPreviousLines: %v\n" , indent2 , v .HasBlankPreviousLines ())
}
for name , value := range kv {
fmt .Printf ("%s%s: %s\n" , indent2 , name , value )
}
if cb != nil {
cb (level + 1 )
}
for c := v .FirstChild (); c != nil ; c = c .NextSibling () {
c .Dump (source , level +1 )
}
fmt .Printf ("%s}\n" , indent )
}
type WalkStatus int
const (
WalkStop WalkStatus = iota + 1
WalkSkipChildren
WalkContinue
)
type Walker func (n Node , entering bool ) (WalkStatus , error )
func Walk (n Node , walker Walker ) error {
_ , err := walkHelper (n , walker )
return err
}
func walkHelper(n Node , walker Walker ) (WalkStatus , error ) {
status , err := walker (n , true )
if err != nil || status == WalkStop {
return status , err
}
if status != WalkSkipChildren {
for c := n .FirstChild (); c != nil ; c = c .NextSibling () {
if st , err := walkHelper (c , walker ); err != nil || st == WalkStop {
return WalkStop , err
}
}
}
status , err = walker (n , false )
if err != nil || status == WalkStop {
return WalkStop , err
}
return WalkContinue , nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .