-
Notifications
You must be signed in to change notification settings - Fork 89
/
parse.go
114 lines (86 loc) · 2.21 KB
/
parse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package ace
import "strings"
// ParseSource parses the source and returns the result.
func ParseSource(src *source, opts *Options) (*result, error) {
// Initialize the options.
opts = InitializeOptions(opts)
rslt := newResult(nil, nil, nil)
base, err := parseBytes(src.base.data, rslt, src, opts, src.base)
if err != nil {
return nil, err
}
inner, err := parseBytes(src.inner.data, rslt, src, opts, src.inner)
if err != nil {
return nil, err
}
includes := make(map[string][]element)
for _, f := range src.includes {
includes[f.path], err = parseBytes(f.data, rslt, src, opts, f)
if err != nil {
return nil, err
}
}
rslt.base = base
rslt.inner = inner
rslt.includes = includes
return rslt, nil
}
// parseBytes parses the byte data and returns the elements.
func parseBytes(data []byte, rslt *result, src *source, opts *Options, f *File) ([]element, error) {
var elements []element
lines := strings.Split(formatLF(string(data)), lf)
i := 0
l := len(lines)
// Ignore the last empty line.
if l > 0 && lines[l-1] == "" {
l--
}
for i < l {
// Fetch a line.
ln := newLine(i+1, lines[i], opts, f)
i++
// Ignore the empty line.
if ln.isEmpty() {
continue
}
if ln.isTopIndent() {
e, err := newElement(ln, rslt, src, nil, opts)
if err != nil {
return nil, err
}
// Append child elements to the element.
if err := appendChildren(e, rslt, lines, &i, l, src, opts, f); err != nil {
return nil, err
}
elements = append(elements, e)
}
}
return elements, nil
}
// appendChildren parses the lines and appends the children to the element.
func appendChildren(parent element, rslt *result, lines []string, i *int, l int, src *source, opts *Options, f *File) error {
for *i < l {
// Fetch a line.
ln := newLine(*i+1, lines[*i], opts, f)
// Check if the line is a child of the parent.
ok, err := ln.childOf(parent)
if err != nil {
return err
}
if !ok {
return nil
}
child, err := newElement(ln, rslt, src, parent, opts)
if err != nil {
return err
}
parent.AppendChild(child)
*i++
if child.CanHaveChildren() {
if err := appendChildren(child, rslt, lines, i, l, src, opts, f); err != nil {
return err
}
}
}
return nil
}