v / vlib / yaml / flow.v
180 lines · 171 sloc · 3.43 KB · d96fe54c0a96fd6d651e9cb3c61b137ccc5c7dbe
Raw
1module yaml
2
3struct FlowParser {
4 src string
5mut:
6 pos int
7}
8
9fn parse_flow_value(src string) !Any {
10 mut parser := FlowParser{
11 src: src
12 }
13 value := parser.parse_value()!
14 parser.skip_space()
15 if parser.pos != parser.src.len {
16 return error('yaml: unexpected trailing flow content')
17 }
18 return value
19}
20
21fn (mut p FlowParser) parse_value() !Any {
22 p.skip_space()
23 if p.pos >= p.src.len {
24 return error('yaml: unexpected end of flow value')
25 }
26 return match p.src[p.pos] {
27 `[` { p.parse_array() }
28 `{` { p.parse_object() }
29 `"`, `'` { Any(parse_quoted_flow_string(mut p)!) }
30 else { parse_scalar(p.parse_plain_token()) }
31 }
32}
33
34fn (mut p FlowParser) parse_array() !Any {
35 p.pos++
36 mut items := []Any{}
37 for {
38 p.skip_space()
39 if p.pos >= p.src.len {
40 return error('yaml: unterminated flow array')
41 }
42 if p.src[p.pos] == `]` {
43 p.pos++
44 break
45 }
46 items << p.parse_value()!
47 p.skip_space()
48 if p.pos >= p.src.len {
49 return error('yaml: unterminated flow array')
50 }
51 if p.src[p.pos] == `,` {
52 p.pos++
53 continue
54 }
55 if p.src[p.pos] == `]` {
56 p.pos++
57 break
58 }
59 return error('yaml: expected `,` or `]` in flow array')
60 }
61 return Any(items)
62}
63
64fn (mut p FlowParser) parse_object() !Any {
65 p.pos++
66 mut result := map[string]Any{}
67 for {
68 p.skip_space()
69 if p.pos >= p.src.len {
70 return error('yaml: unterminated flow object')
71 }
72 if p.src[p.pos] == `}` {
73 p.pos++
74 break
75 }
76 key := p.parse_key()!
77 p.skip_space()
78 if p.pos >= p.src.len || p.src[p.pos] != `:` {
79 return error('yaml: expected `:` in flow object')
80 }
81 p.pos++
82 result[key] = p.parse_value()!
83 p.skip_space()
84 if p.pos >= p.src.len {
85 return error('yaml: unterminated flow object')
86 }
87 if p.src[p.pos] == `,` {
88 p.pos++
89 continue
90 }
91 if p.src[p.pos] == `}` {
92 p.pos++
93 break
94 }
95 return error('yaml: expected `,` or `}` in flow object')
96 }
97 return Any(result)
98}
99
100fn (mut p FlowParser) parse_key() !string {
101 p.skip_space()
102 if p.pos >= p.src.len {
103 return error('yaml: unexpected end of flow key')
104 }
105 if p.src[p.pos] in [`"`, `'`] {
106 return parse_quoted_flow_string(mut p)
107 }
108 start := p.pos
109 for p.pos < p.src.len {
110 ch := p.src[p.pos]
111 if ch == `:` {
112 break
113 }
114 p.pos++
115 }
116 return p.src[start..p.pos].trim_space()
117}
118
119fn (mut p FlowParser) parse_plain_token() string {
120 start := p.pos
121 mut bracket_depth := 0
122 mut brace_depth := 0
123 for p.pos < p.src.len {
124 ch := p.src[p.pos]
125 if ch == `[` {
126 bracket_depth++
127 } else if ch == `]` {
128 if bracket_depth == 0 {
129 break
130 }
131 bracket_depth--
132 } else if ch == `{` {
133 brace_depth++
134 } else if ch == `}` {
135 if brace_depth == 0 {
136 break
137 }
138 brace_depth--
139 } else if ch == `,` && bracket_depth == 0 && brace_depth == 0 {
140 break
141 }
142 p.pos++
143 }
144 return p.src[start..p.pos].trim_space()
145}
146
147fn (mut p FlowParser) skip_space() {
148 for p.pos < p.src.len && p.src[p.pos].is_space() {
149 p.pos++
150 }
151}
152
153fn parse_quoted_flow_string(mut p FlowParser) !string {
154 start := p.pos
155 quote := p.src[p.pos]
156 p.pos++
157 mut escape := false
158 for p.pos < p.src.len {
159 ch := p.src[p.pos]
160 if quote == `"` {
161 if escape {
162 escape = false
163 } else if ch == `\\` {
164 escape = true
165 } else if ch == `"` {
166 p.pos++
167 return parse_quoted_string(p.src[start..p.pos])
168 }
169 } else if ch == `'` {
170 if p.pos + 1 < p.src.len && p.src[p.pos + 1] == `'` {
171 p.pos += 2
172 continue
173 }
174 p.pos++
175 return parse_quoted_string(p.src[start..p.pos])
176 }
177 p.pos++
178 }
179 return error('yaml: unterminated quoted flow string')
180}
181