node.go

  1package ast
  2
  3// ListType contains bitwise or'ed flags for list and list item objects.
  4type ListType int
  5
  6// These are the possible flag values for the ListItem renderer.
  7// Multiple flag values may be ORed together.
  8// These are mostly of interest if you are writing a new output format.
  9const (
 10	ListTypeOrdered ListType = 1 << iota
 11	ListTypeDefinition
 12	ListTypeTerm
 13
 14	ListItemContainsBlock
 15	ListItemBeginningOfList // TODO: figure out if this is of any use now
 16	ListItemEndOfList
 17)
 18
 19// CellAlignFlags holds a type of alignment in a table cell.
 20type CellAlignFlags int
 21
 22// These are the possible flag values for the table cell renderer.
 23// Only a single one of these values will be used; they are not ORed together.
 24// These are mostly of interest if you are writing a new output format.
 25const (
 26	TableAlignmentLeft CellAlignFlags = 1 << iota
 27	TableAlignmentRight
 28	TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight)
 29)
 30
 31func (a CellAlignFlags) String() string {
 32	switch a {
 33	case TableAlignmentLeft:
 34		return "left"
 35	case TableAlignmentRight:
 36		return "right"
 37	case TableAlignmentCenter:
 38		return "center"
 39	default:
 40		return ""
 41	}
 42}
 43
 44// DocumentMatters holds the type of a {front,main,back}matter in the document
 45type DocumentMatters int
 46
 47// These are all possible Document divisions.
 48const (
 49	DocumentMatterNone DocumentMatters = iota
 50	DocumentMatterFront
 51	DocumentMatterMain
 52	DocumentMatterBack
 53)
 54
 55// CitationTypes holds the type of a citation, informative, normative or suppressed
 56type CitationTypes int
 57
 58const (
 59	CitationTypeNone CitationTypes = iota
 60	CitationTypeSuppressed
 61	CitationTypeInformative
 62	CitationTypeNormative
 63)
 64
 65// Node defines an ast node
 66type Node interface {
 67	AsContainer() *Container
 68	AsLeaf() *Leaf
 69	GetParent() Node
 70	SetParent(newParent Node)
 71	GetChildren() []Node
 72	SetChildren(newChildren []Node)
 73}
 74
 75// Container is a type of node that can contain children
 76type Container struct {
 77	Parent   Node
 78	Children []Node
 79
 80	Literal []byte // Text contents of the leaf nodes
 81	Content []byte // Markdown content of the block nodes
 82
 83	*Attribute // Block level attribute
 84}
 85
 86// AsContainer returns itself as *Container
 87func (c *Container) AsContainer() *Container {
 88	return c
 89}
 90
 91// AsLeaf returns nil
 92func (c *Container) AsLeaf() *Leaf {
 93	return nil
 94}
 95
 96// GetParent returns parent node
 97func (c *Container) GetParent() Node {
 98	return c.Parent
 99}
100
101// SetParent sets the parent node
102func (c *Container) SetParent(newParent Node) {
103	c.Parent = newParent
104}
105
106// GetChildren returns children nodes
107func (c *Container) GetChildren() []Node {
108	return c.Children
109}
110
111// SetChildren sets children node
112func (c *Container) SetChildren(newChildren []Node) {
113	c.Children = newChildren
114}
115
116// Leaf is a type of node that cannot have children
117type Leaf struct {
118	Parent Node
119
120	Literal []byte // Text contents of the leaf nodes
121	Content []byte // Markdown content of the block nodes
122
123	*Attribute // Block level attribute
124}
125
126// AsContainer returns nil
127func (l *Leaf) AsContainer() *Container {
128	return nil
129}
130
131// AsLeaf returns itself as *Leaf
132func (l *Leaf) AsLeaf() *Leaf {
133	return l
134}
135
136// GetParent returns parent node
137func (l *Leaf) GetParent() Node {
138	return l.Parent
139}
140
141// SetParent sets the parent nodd
142func (l *Leaf) SetParent(newParent Node) {
143	l.Parent = newParent
144}
145
146// GetChildren returns nil because Leaf cannot have children
147func (l *Leaf) GetChildren() []Node {
148	return nil
149}
150
151// SetChildren will panic becuase Leaf cannot have children
152func (l *Leaf) SetChildren(newChildren []Node) {
153	panic("leaf node cannot have children")
154}
155
156// Document represents markdown document node, a root of ast
157type Document struct {
158	Container
159}
160
161// DocumentMatter represents markdown node that signals a document
162// division: frontmatter, mainmatter or backmatter.
163type DocumentMatter struct {
164	Container
165
166	Matter DocumentMatters
167}
168
169// BlockQuote represents markdown block quote node
170type BlockQuote struct {
171	Container
172}
173
174// Aside represents an markdown aside node.
175type Aside struct {
176	Container
177}
178
179// List represents markdown list node
180type List struct {
181	Container
182
183	ListFlags       ListType
184	Tight           bool   // Skip <p>s around list item data if true
185	BulletChar      byte   // '*', '+' or '-' in bullet lists
186	Delimiter       byte   // '.' or ')' after the number in ordered lists
187	Start           int    // for ordered lists this indicates the starting number if > 0
188	RefLink         []byte // If not nil, turns this list item into a footnote item and triggers different rendering
189	IsFootnotesList bool   // This is a list of footnotes
190}
191
192// ListItem represents markdown list item node
193type ListItem struct {
194	Container
195
196	ListFlags       ListType
197	Tight           bool   // Skip <p>s around list item data if true
198	BulletChar      byte   // '*', '+' or '-' in bullet lists
199	Delimiter       byte   // '.' or ')' after the number in ordered lists
200	RefLink         []byte // If not nil, turns this list item into a footnote item and triggers different rendering
201	IsFootnotesList bool   // This is a list of footnotes
202}
203
204// Paragraph represents markdown paragraph node
205type Paragraph struct {
206	Container
207}
208
209// Math represents markdown MathAjax inline node
210type Math struct {
211	Leaf
212}
213
214// MathBlock represents markdown MathAjax block node
215type MathBlock struct {
216	Container
217}
218
219// Heading represents markdown heading node
220type Heading struct {
221	Container
222
223	Level        int    // This holds the heading level number
224	HeadingID    string // This might hold heading ID, if present
225	IsTitleblock bool   // Specifies whether it's a title block
226	IsSpecial    bool   // We are a special heading (starts with .#)
227}
228
229// HorizontalRule represents markdown horizontal rule node
230type HorizontalRule struct {
231	Leaf
232}
233
234// Emph represents markdown emphasis node
235type Emph struct {
236	Container
237}
238
239// Strong represents markdown strong node
240type Strong struct {
241	Container
242}
243
244// Del represents markdown del node
245type Del struct {
246	Container
247}
248
249// Link represents markdown link node
250type Link struct {
251	Container
252
253	Destination []byte // Destination is what goes into a href
254	Title       []byte // Title is the tooltip thing that goes in a title attribute
255	NoteID      int    // NoteID contains a serial number of a footnote, zero if it's not a footnote
256	Footnote    Node   // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil.
257	DeferredID  []byte // If a deferred link this holds the original ID.
258}
259
260// CrossReference is a reference node.
261type CrossReference struct {
262	Container
263
264	Destination []byte // Destination is where the reference points to
265}
266
267// Citation is a citation node.
268type Citation struct {
269	Leaf
270
271	Destination [][]byte        // Destination is where the citation points to. Multiple ones are allowed.
272	Type        []CitationTypes // 1:1 mapping of destination and citation type
273	Suffix      [][]byte        // Potential citation suffix, i.e. [@!RFC1035, p. 144]
274}
275
276// Image represents markdown image node
277type Image struct {
278	Container
279
280	Destination []byte // Destination is what goes into a href
281	Title       []byte // Title is the tooltip thing that goes in a title attribute
282}
283
284// Text represents markdown text node
285type Text struct {
286	Leaf
287}
288
289// HTMLBlock represents markdown html node
290type HTMLBlock struct {
291	Leaf
292}
293
294// CodeBlock represents markdown code block node
295type CodeBlock struct {
296	Leaf
297
298	IsFenced    bool   // Specifies whether it's a fenced code block or an indented one
299	Info        []byte // This holds the info string
300	FenceChar   byte
301	FenceLength int
302	FenceOffset int
303}
304
305// Softbreak represents markdown softbreak node
306// Note: not used currently
307type Softbreak struct {
308	Leaf
309}
310
311// Hardbreak represents markdown hard break node
312type Hardbreak struct {
313	Leaf
314}
315
316// NonBlockingSpace represents markdown non-blocking space node
317type NonBlockingSpace struct {
318	Leaf
319}
320
321// Code represents markdown code node
322type Code struct {
323	Leaf
324}
325
326// HTMLSpan represents markdown html span node
327type HTMLSpan struct {
328	Leaf
329}
330
331// Table represents markdown table node
332type Table struct {
333	Container
334}
335
336// TableCell represents markdown table cell node
337type TableCell struct {
338	Container
339
340	IsHeader bool           // This tells if it's under the header row
341	Align    CellAlignFlags // This holds the value for align attribute
342}
343
344// TableHeader represents markdown table head node
345type TableHeader struct {
346	Container
347}
348
349// TableBody represents markdown table body node
350type TableBody struct {
351	Container
352}
353
354// TableRow represents markdown table row node
355type TableRow struct {
356	Container
357}
358
359// TableFooter represents markdown table foot node
360type TableFooter struct {
361	Container
362}
363
364// Caption represents a figure, code or quote caption
365type Caption struct {
366	Container
367}
368
369// CaptionFigure is a node (blockquote or codeblock) that has a caption
370type CaptionFigure struct {
371	Container
372
373	HeadingID string // This might hold heading ID, if present
374}
375
376// Callout is a node that can exist both in text (where it is an actual node) and in a code block.
377type Callout struct {
378	Leaf
379
380	ID []byte // number of this callout
381}
382
383// Index is a node that contains an Index item and an optional, subitem.
384type Index struct {
385	Leaf
386
387	Primary bool
388	Item    []byte
389	Subitem []byte
390	ID      string // ID of the index
391}
392
393// Subscript is a subscript node
394type Subscript struct {
395	Leaf
396}
397
398// Subscript is a superscript node
399type Superscript struct {
400	Leaf
401}
402
403// Footnotes is a node that contains all footnotes
404type Footnotes struct {
405	Container
406}
407
408func removeNodeFromArray(a []Node, node Node) []Node {
409	n := len(a)
410	for i := 0; i < n; i++ {
411		if a[i] == node {
412			return append(a[:i], a[i+1:]...)
413		}
414	}
415	return nil
416}
417
418// AppendChild appends child to children of parent
419// It panics if either node is nil.
420func AppendChild(parent Node, child Node) {
421	RemoveFromTree(child)
422	child.SetParent(parent)
423	newChildren := append(parent.GetChildren(), child)
424	parent.SetChildren(newChildren)
425}
426
427// RemoveFromTree removes this node from tree
428func RemoveFromTree(n Node) {
429	if n.GetParent() == nil {
430		return
431	}
432	// important: don't clear n.Children if n has no parent
433	// we're called from AppendChild and that might happen on a node
434	// that accumulated Children but hasn't been inserted into the tree
435	n.SetChildren(nil)
436	p := n.GetParent()
437	newChildren := removeNodeFromArray(p.GetChildren(), n)
438	if newChildren != nil {
439		p.SetChildren(newChildren)
440	}
441}
442
443// GetLastChild returns last child of node n
444// It's implemented as stand-alone function to keep Node interface small
445func GetLastChild(n Node) Node {
446	a := n.GetChildren()
447	if len(a) > 0 {
448		return a[len(a)-1]
449	}
450	return nil
451}
452
453// GetFirstChild returns first child of node n
454// It's implemented as stand-alone function to keep Node interface small
455func GetFirstChild(n Node) Node {
456	a := n.GetChildren()
457	if len(a) > 0 {
458		return a[0]
459	}
460	return nil
461}
462
463// GetNextNode returns next sibling of node n (node after n)
464// We can't make it part of Container or Leaf because we loose Node identity
465func GetNextNode(n Node) Node {
466	parent := n.GetParent()
467	if parent == nil {
468		return nil
469	}
470	a := parent.GetChildren()
471	len := len(a) - 1
472	for i := 0; i < len; i++ {
473		if a[i] == n {
474			return a[i+1]
475		}
476	}
477	return nil
478}
479
480// GetPrevNode returns previous sibling of node n (node before n)
481// We can't make it part of Container or Leaf because we loose Node identity
482func GetPrevNode(n Node) Node {
483	parent := n.GetParent()
484	if parent == nil {
485		return nil
486	}
487	a := parent.GetChildren()
488	len := len(a)
489	for i := 1; i < len; i++ {
490		if a[i] == n {
491			return a[i-1]
492		}
493	}
494	return nil
495}
496
497// WalkStatus allows NodeVisitor to have some control over the tree traversal.
498// It is returned from NodeVisitor and different values allow Node.Walk to
499// decide which node to go to next.
500type WalkStatus int
501
502const (
503	// GoToNext is the default traversal of every node.
504	GoToNext WalkStatus = iota
505	// SkipChildren tells walker to skip all children of current node.
506	SkipChildren
507	// Terminate tells walker to terminate the traversal.
508	Terminate
509)
510
511// NodeVisitor is a callback to be called when traversing the syntax tree.
512// Called twice for every node: once with entering=true when the branch is
513// first visited, then with entering=false after all the children are done.
514type NodeVisitor interface {
515	Visit(node Node, entering bool) WalkStatus
516}
517
518// NodeVisitorFunc casts a function to match NodeVisitor interface
519type NodeVisitorFunc func(node Node, entering bool) WalkStatus
520
521// Walk traverses tree recursively
522func Walk(n Node, visitor NodeVisitor) WalkStatus {
523	isContainer := n.AsContainer() != nil
524	status := visitor.Visit(n, true) // entering
525	if status == Terminate {
526		// even if terminating, close container node
527		if isContainer {
528			visitor.Visit(n, false)
529		}
530		return status
531	}
532	if isContainer && status != SkipChildren {
533		children := n.GetChildren()
534		for _, n := range children {
535			status = Walk(n, visitor)
536			if status == Terminate {
537				return status
538			}
539		}
540	}
541	if isContainer {
542		status = visitor.Visit(n, false) // exiting
543		if status == Terminate {
544			return status
545		}
546	}
547	return GoToNext
548}
549
550// Visit calls visitor function
551func (f NodeVisitorFunc) Visit(node Node, entering bool) WalkStatus {
552	return f(node, entering)
553}
554
555// WalkFunc is like Walk but accepts just a callback function
556func WalkFunc(n Node, f NodeVisitorFunc) {
557	visitor := NodeVisitorFunc(f)
558	Walk(n, visitor)
559}