1package parser
 2
 3import (
 4	"bytes"
 5
 6	"github.com/gomarkdown/markdown/ast"
 7)
 8
 9// citation parses a citation. In its most simple form [@ref], we allow multiple
10// being separated by semicolons and a sub reference inside ala pandoc: [@ref, p. 23].
11// Each citation can have a modifier: !, ? or - wich mean:
12//
13// ! - normative
14// ? - formative
15// - - suppressed
16//
17// The suffix starts after a comma, we strip any whitespace before and after. If the output
18// allows for it, this can be rendered.
19func citation(p *Parser, data []byte, offset int) (int, ast.Node) {
20	// look for the matching closing bracket
21	i := offset + 1
22	for level := 1; level > 0 && i < len(data); i++ {
23		switch {
24		case data[i] == '\n':
25			// no newlines allowed.
26			return 0, nil
27
28		case data[i-1] == '\\':
29			continue
30
31		case data[i] == '[':
32			level++
33
34		case data[i] == ']':
35			level--
36			if level <= 0 {
37				i-- // compensate for extra i++ in for loop
38			}
39		}
40	}
41
42	if i >= len(data) {
43		return 0, nil
44	}
45
46	node := &ast.Citation{}
47
48	citations := bytes.Split(data[1:i], []byte(";"))
49	for _, citation := range citations {
50		var suffix []byte
51		citation = bytes.TrimSpace(citation)
52		j := 0
53		if citation[j] != '@' {
54			// not a citation, drop out entirely.
55			return 0, nil
56		}
57		if c := bytes.Index(citation, []byte(",")); c > 0 {
58			part := citation[:c]
59			suff := citation[c+1:]
60			part = bytes.TrimSpace(part)
61			suff = bytes.TrimSpace(suff)
62
63			citation = part
64			suffix = suff
65		}
66
67		citeType := ast.CitationTypeInformative
68		j = 1
69		switch citation[j] {
70		case '!':
71			citeType = ast.CitationTypeNormative
72			j++
73		case '?':
74			citeType = ast.CitationTypeInformative
75			j++
76		case '-':
77			citeType = ast.CitationTypeSuppressed
78			j++
79		}
80		node.Destination = append(node.Destination, citation[j:])
81		node.Type = append(node.Type, citeType)
82		node.Suffix = append(node.Suffix, suffix)
83	}
84
85	return i + 1, node
86}