// Package ast defines AST nodes that represent markdown elements.
package ast import ( textm ) // A NodeType indicates what type a node belongs to. type NodeType int const ( // TypeBlock indicates that a node is kind of block nodes. TypeBlock NodeType = iota + 1 // TypeInline indicates that a node is kind of inline nodes. TypeInline // TypeDocument indicates that a node is kind of document nodes. TypeDocument ) // NodeKind indicates more specific type than NodeType. type NodeKind int func ( NodeKind) () string { return kindNames[] } var kindMax NodeKind var kindNames = []string{""} // NewNodeKind returns a new Kind value. func ( string) NodeKind { kindMax++ kindNames = append(kindNames, ) return kindMax } // An Attribute is an attribute of the Node. type Attribute struct { Name []byte Value interface{} } // A Node interface defines basic AST node functionalities. type Node interface { // Type returns a type of this node. Type() NodeType // Kind returns a kind of this node. Kind() NodeKind // NextSibling returns a next sibling node of this node. NextSibling() Node // PreviousSibling returns a previous sibling node of this node. PreviousSibling() Node // Parent returns a parent node of this node. Parent() Node // SetParent sets a parent node to this node. SetParent(Node) // SetPreviousSibling sets a previous sibling node to this node. SetPreviousSibling(Node) // SetNextSibling sets a next sibling node to this node. SetNextSibling(Node) // HasChildren returns true if this node has any children, otherwise false. HasChildren() bool // ChildCount returns a total number of children. ChildCount() int // FirstChild returns a first child of this node. FirstChild() Node // LastChild returns a last child of this node. LastChild() Node // AppendChild append a node child to the tail of the children. AppendChild(self, child Node) // RemoveChild removes a node child from this node. // If a node child is not children of this node, RemoveChild nothing to do. RemoveChild(self, child Node) // RemoveChildren removes all children from this node. RemoveChildren(self Node) // SortChildren sorts childrens by comparator. SortChildren(comparator func(n1, n2 Node) int) // ReplaceChild replace a node v1 with a node insertee. // If v1 is not children of this node, ReplaceChild append a insetee to the // tail of the children. ReplaceChild(self, v1, insertee Node) // InsertBefore inserts a node insertee before a node v1. // If v1 is not children of this node, InsertBefore append a insetee to the // tail of the children. InsertBefore(self, v1, insertee Node) // InsertAfterinserts a node insertee after a node v1. // If v1 is not children of this node, InsertBefore append a insetee to the // tail of the children. InsertAfter(self, v1, insertee Node) // OwnerDocument returns this node's owner document. // If this node is not a child of the Document node, OwnerDocument // returns nil. OwnerDocument() *Document // Dump dumps an AST tree structure to stdout. // This function completely aimed for debugging. // level is a indent level. Implementer should indent informations with // 2 * level spaces. Dump(source []byte, level int) // Text returns text values of this node. Text(source []byte) []byte // HasBlankPreviousLines returns true if the row before this node is blank, // otherwise false. // This method is valid only for block nodes. HasBlankPreviousLines() bool // SetBlankPreviousLines sets whether the row before this node is blank. // This method is valid only for block nodes. SetBlankPreviousLines(v bool) // Lines returns text segments that hold positions in a source. // This method is valid only for block nodes. Lines() *textm.Segments // SetLines sets text segments that hold positions in a source. // This method is valid only for block nodes. SetLines(*textm.Segments) // IsRaw returns true if contents should be rendered as 'raw' contents. IsRaw() bool // SetAttribute sets the given value to the attributes. SetAttribute(name []byte, value interface{}) // SetAttributeString sets the given value to the attributes. SetAttributeString(name string, value interface{}) // Attribute returns a (attribute value, true) if an attribute // associated with the given name is found, otherwise // (nil, false) Attribute(name []byte) (interface{}, bool) // AttributeString returns a (attribute value, true) if an attribute // associated with the given name is found, otherwise // (nil, false) AttributeString(name string) (interface{}, bool) // Attributes returns a list of attributes. // This may be a nil if there are no attributes. Attributes() []Attribute // RemoveAttributes removes all attributes from this node. RemoveAttributes() } // A BaseNode struct implements the Node interface partialliy. type BaseNode struct { firstChild Node lastChild Node parent Node next Node prev Node childCount int attributes []Attribute } func ensureIsolated( Node) { if := .Parent(); != nil { .RemoveChild(, ) } } // HasChildren implements Node.HasChildren . func ( *BaseNode) () bool { return .firstChild != nil } // SetPreviousSibling implements Node.SetPreviousSibling . func ( *BaseNode) ( Node) { .prev = } // SetNextSibling implements Node.SetNextSibling . func ( *BaseNode) ( Node) { .next = } // PreviousSibling implements Node.PreviousSibling . func ( *BaseNode) () Node { return .prev } // NextSibling implements Node.NextSibling . func ( *BaseNode) () Node { return .next } // RemoveChild implements Node.RemoveChild . func ( *BaseNode) (, Node) { if .Parent() != { return } .childCount-- := .PreviousSibling() := .NextSibling() if != nil { .SetNextSibling() } else { .firstChild = } if != nil { .SetPreviousSibling() } else { .lastChild = } .SetParent(nil) .SetPreviousSibling(nil) .SetNextSibling(nil) } // RemoveChildren implements Node.RemoveChildren . func ( *BaseNode) ( Node) { for := .firstChild; != nil; { .SetParent(nil) .SetPreviousSibling(nil) := .NextSibling() .SetNextSibling(nil) = } .firstChild = nil .lastChild = nil .childCount = 0 } // SortChildren implements Node.SortChildren. func ( *BaseNode) ( func(, Node) int) { var Node := .firstChild for != nil { := .NextSibling() if == nil || (, ) >= 0 { .SetNextSibling() if != nil { .SetPreviousSibling() } = .SetPreviousSibling(nil) } else { := for .NextSibling() != nil && (.NextSibling(), ) < 0 { = .NextSibling() } .SetNextSibling(.NextSibling()) .SetPreviousSibling() if .NextSibling() != nil { .NextSibling().SetPreviousSibling() } .SetNextSibling() } = } .firstChild = for := .firstChild; != nil; = .NextSibling() { .lastChild = } } // FirstChild implements Node.FirstChild . func ( *BaseNode) () Node { return .firstChild } // LastChild implements Node.LastChild . func ( *BaseNode) () Node { return .lastChild } // ChildCount implements Node.ChildCount . func ( *BaseNode) () int { return .childCount } // Parent implements Node.Parent . func ( *BaseNode) () Node { return .parent } // SetParent implements Node.SetParent . func ( *BaseNode) ( Node) { .parent = } // AppendChild implements Node.AppendChild . func ( *BaseNode) (, Node) { ensureIsolated() if .firstChild == nil { .firstChild = .SetNextSibling(nil) .SetPreviousSibling(nil) } else { := .lastChild .SetNextSibling() .SetPreviousSibling() } .SetParent() .lastChild = .childCount++ } // ReplaceChild implements Node.ReplaceChild . func ( *BaseNode) (, , Node) { .InsertBefore(, , ) .RemoveChild(, ) } // InsertAfter implements Node.InsertAfter . func ( *BaseNode) (, , Node) { .InsertBefore(, .NextSibling(), ) } // InsertBefore implements Node.InsertBefore . func ( *BaseNode) (, , Node) { .childCount++ if == nil { .AppendChild(, ) return } ensureIsolated() if .Parent() == { := := .PreviousSibling() if != nil { .SetNextSibling() .SetPreviousSibling() } else { .firstChild = .SetPreviousSibling(nil) } .SetNextSibling() .SetPreviousSibling() .SetParent() } } // OwnerDocument implements Node.OwnerDocument. func ( *BaseNode) () *Document { := .Parent() for { := .Parent() if == nil { if , := .(*Document); { return } break } = } return nil } // Text implements Node.Text . func ( *BaseNode) ( []byte) []byte { var bytes.Buffer for := .firstChild; != nil; = .NextSibling() { .Write(.Text()) } return .Bytes() } // SetAttribute implements Node.SetAttribute. func ( *BaseNode) ( []byte, interface{}) { if .attributes == nil { .attributes = make([]Attribute, 0, 10) } else { for , := range .attributes { if bytes.Equal(.Name, ) { .attributes[].Name = .attributes[].Value = return } } } .attributes = append(.attributes, Attribute{, }) } // SetAttributeString implements Node.SetAttributeString. func ( *BaseNode) ( string, interface{}) { .SetAttribute(util.StringToReadOnlyBytes(), ) } // Attribute implements Node.Attribute. func ( *BaseNode) ( []byte) (interface{}, bool) { if .attributes == nil { return nil, false } for , := range .attributes { if bytes.Equal(.Name, ) { return .attributes[].Value, true } } return nil, false } // AttributeString implements Node.AttributeString. func ( *BaseNode) ( string) (interface{}, bool) { return .Attribute(util.StringToReadOnlyBytes()) } // Attributes implements Node.Attributes. func ( *BaseNode) () []Attribute { return .attributes } // RemoveAttributes implements Node.RemoveAttributes. func ( *BaseNode) () { .attributes = nil } // DumpHelper is a helper function to implement Node.Dump. // kv is pairs of an attribute name and an attribute value. // cb is a function called after wrote a name and attributes. func ( Node, []byte, int, map[string]string, func(int)) { := .Kind().String() := strings.Repeat(" ", ) fmt.Printf("%s%s {\n", , ) := strings.Repeat(" ", +1) if .Type() == TypeBlock { fmt.Printf("%sRawText: \"", ) for := 0; < .Lines().Len(); ++ { := .Lines().At() fmt.Printf("%s", .Value()) } fmt.Printf("\"\n") fmt.Printf("%sHasBlankPreviousLines: %v\n", , .HasBlankPreviousLines()) } for , := range { fmt.Printf("%s%s: %s\n", , , ) } if != nil { ( + 1) } for := .FirstChild(); != nil; = .NextSibling() { .Dump(, +1) } fmt.Printf("%s}\n", ) } // WalkStatus represents a current status of the Walk function. type WalkStatus int const ( // WalkStop indicates no more walking needed. WalkStop WalkStatus = iota + 1 // WalkSkipChildren indicates that Walk wont walk on children of current // node. WalkSkipChildren // WalkContinue indicates that Walk can continue to walk. WalkContinue ) // Walker is a function that will be called when Walk find a // new node. // entering is set true before walks children, false after walked children. // If Walker returns error, Walk function immediately stop walking. type Walker func(n Node, entering bool) (WalkStatus, error) // Walk walks a AST tree by the depth first search algorithm. func ( Node, Walker) error { , := walkHelper(, ) return } func walkHelper( Node, Walker) (WalkStatus, error) { , := (, true) if != nil || == WalkStop { return , } if != WalkSkipChildren { for := .FirstChild(); != nil; = .NextSibling() { if , := (, ); != nil || == WalkStop { return WalkStop, } } } , = (, false) if != nil || == WalkStop { return WalkStop, } return WalkContinue, nil }