1 | package gcss
|
---|
2 |
|
---|
3 | import "strings"
|
---|
4 |
|
---|
5 | // Special characters
|
---|
6 | const (
|
---|
7 | cr = "\r"
|
---|
8 | lf = "\n"
|
---|
9 | crlf = "\r\n"
|
---|
10 | space = " "
|
---|
11 | colon = ":"
|
---|
12 | comma = ","
|
---|
13 | openBrace = "{"
|
---|
14 | closeBrace = "}"
|
---|
15 | semicolon = ";"
|
---|
16 | ampersand = "&"
|
---|
17 | atMark = "@"
|
---|
18 | dollarMark = "$"
|
---|
19 | openParenthesis = "("
|
---|
20 | closeParenthesis = ")"
|
---|
21 | slash = "/"
|
---|
22 | doubleSlash = slash + slash
|
---|
23 | )
|
---|
24 |
|
---|
25 | // parse parses the string, generates the elements
|
---|
26 | // and returns the two channels: the first one returns
|
---|
27 | // the generated elements and the last one returns
|
---|
28 | // an error when it occurs.
|
---|
29 | func parse(lines []string) (<-chan element, <-chan error) {
|
---|
30 | elemc := make(chan element, len(lines))
|
---|
31 | errc := make(chan error)
|
---|
32 |
|
---|
33 | go func() {
|
---|
34 | i := 0
|
---|
35 | l := len(lines)
|
---|
36 |
|
---|
37 | for i < l {
|
---|
38 | // Fetch a line.
|
---|
39 | ln := newLine(i+1, lines[i])
|
---|
40 | i++
|
---|
41 |
|
---|
42 | // Ignore the empty line.
|
---|
43 | if ln.isEmpty() {
|
---|
44 | continue
|
---|
45 | }
|
---|
46 |
|
---|
47 | if ln.isTopIndent() {
|
---|
48 | elem, err := newElement(ln, nil)
|
---|
49 |
|
---|
50 | if err != nil {
|
---|
51 | errc <- err
|
---|
52 | return
|
---|
53 | }
|
---|
54 |
|
---|
55 | if err := appendChildren(elem, lines, &i, l); err != nil {
|
---|
56 | errc <- err
|
---|
57 | return
|
---|
58 | }
|
---|
59 |
|
---|
60 | elemc <- elem
|
---|
61 | }
|
---|
62 | }
|
---|
63 |
|
---|
64 | close(elemc)
|
---|
65 | }()
|
---|
66 |
|
---|
67 | return elemc, errc
|
---|
68 | }
|
---|
69 |
|
---|
70 | // appendChildren parses the lines and appends the child elements
|
---|
71 | // to the parent element.
|
---|
72 | func appendChildren(parent element, lines []string, i *int, l int) error {
|
---|
73 | for *i < l {
|
---|
74 | // Fetch a line.
|
---|
75 | ln := newLine(*i+1, lines[*i])
|
---|
76 |
|
---|
77 | // Ignore the empty line.
|
---|
78 | if ln.isEmpty() {
|
---|
79 | *i++
|
---|
80 | return nil
|
---|
81 | }
|
---|
82 |
|
---|
83 | ok, err := ln.childOf(parent)
|
---|
84 |
|
---|
85 | if err != nil {
|
---|
86 | return err
|
---|
87 | }
|
---|
88 |
|
---|
89 | if !ok {
|
---|
90 | return nil
|
---|
91 | }
|
---|
92 |
|
---|
93 | child, err := newElement(ln, parent)
|
---|
94 |
|
---|
95 | if err != nil {
|
---|
96 | return err
|
---|
97 | }
|
---|
98 |
|
---|
99 | parent.AppendChild(child)
|
---|
100 |
|
---|
101 | *i++
|
---|
102 |
|
---|
103 | if err := appendChildren(child, lines, i, l); err != nil {
|
---|
104 | return err
|
---|
105 | }
|
---|
106 | }
|
---|
107 |
|
---|
108 | return nil
|
---|
109 | }
|
---|
110 |
|
---|
111 | // formatLF replaces the line feed codes with LF and
|
---|
112 | // returns the result string.
|
---|
113 | func formatLF(s string) string {
|
---|
114 | return strings.Replace(strings.Replace(s, crlf, lf, -1), cr, lf, -1)
|
---|
115 | }
|
---|