181 lines
3.4 KiB
V
181 lines
3.4 KiB
V
module yaml
|
|
|
|
struct FlowParser {
|
|
src string
|
|
mut:
|
|
pos int
|
|
}
|
|
|
|
fn parse_flow_value(src string) !Any {
|
|
mut parser := FlowParser{
|
|
src: src
|
|
}
|
|
value := parser.parse_value()!
|
|
parser.skip_space()
|
|
if parser.pos != parser.src.len {
|
|
return error('yaml: unexpected trailing flow content')
|
|
}
|
|
return value
|
|
}
|
|
|
|
fn (mut p FlowParser) parse_value() !Any {
|
|
p.skip_space()
|
|
if p.pos >= p.src.len {
|
|
return error('yaml: unexpected end of flow value')
|
|
}
|
|
return match p.src[p.pos] {
|
|
`[` { p.parse_array() }
|
|
`{` { p.parse_object() }
|
|
`"`, `'` { Any(parse_quoted_flow_string(mut p)!) }
|
|
else { parse_scalar(p.parse_plain_token()) }
|
|
}
|
|
}
|
|
|
|
fn (mut p FlowParser) parse_array() !Any {
|
|
p.pos++
|
|
mut items := []Any{}
|
|
for {
|
|
p.skip_space()
|
|
if p.pos >= p.src.len {
|
|
return error('yaml: unterminated flow array')
|
|
}
|
|
if p.src[p.pos] == `]` {
|
|
p.pos++
|
|
break
|
|
}
|
|
items << p.parse_value()!
|
|
p.skip_space()
|
|
if p.pos >= p.src.len {
|
|
return error('yaml: unterminated flow array')
|
|
}
|
|
if p.src[p.pos] == `,` {
|
|
p.pos++
|
|
continue
|
|
}
|
|
if p.src[p.pos] == `]` {
|
|
p.pos++
|
|
break
|
|
}
|
|
return error('yaml: expected `,` or `]` in flow array')
|
|
}
|
|
return Any(items)
|
|
}
|
|
|
|
fn (mut p FlowParser) parse_object() !Any {
|
|
p.pos++
|
|
mut result := map[string]Any{}
|
|
for {
|
|
p.skip_space()
|
|
if p.pos >= p.src.len {
|
|
return error('yaml: unterminated flow object')
|
|
}
|
|
if p.src[p.pos] == `}` {
|
|
p.pos++
|
|
break
|
|
}
|
|
key := p.parse_key()!
|
|
p.skip_space()
|
|
if p.pos >= p.src.len || p.src[p.pos] != `:` {
|
|
return error('yaml: expected `:` in flow object')
|
|
}
|
|
p.pos++
|
|
result[key] = p.parse_value()!
|
|
p.skip_space()
|
|
if p.pos >= p.src.len {
|
|
return error('yaml: unterminated flow object')
|
|
}
|
|
if p.src[p.pos] == `,` {
|
|
p.pos++
|
|
continue
|
|
}
|
|
if p.src[p.pos] == `}` {
|
|
p.pos++
|
|
break
|
|
}
|
|
return error('yaml: expected `,` or `}` in flow object')
|
|
}
|
|
return Any(result)
|
|
}
|
|
|
|
fn (mut p FlowParser) parse_key() !string {
|
|
p.skip_space()
|
|
if p.pos >= p.src.len {
|
|
return error('yaml: unexpected end of flow key')
|
|
}
|
|
if p.src[p.pos] in [`"`, `'`] {
|
|
return parse_quoted_flow_string(mut p)
|
|
}
|
|
start := p.pos
|
|
for p.pos < p.src.len {
|
|
ch := p.src[p.pos]
|
|
if ch == `:` {
|
|
break
|
|
}
|
|
p.pos++
|
|
}
|
|
return p.src[start..p.pos].trim_space()
|
|
}
|
|
|
|
fn (mut p FlowParser) parse_plain_token() string {
|
|
start := p.pos
|
|
mut bracket_depth := 0
|
|
mut brace_depth := 0
|
|
for p.pos < p.src.len {
|
|
ch := p.src[p.pos]
|
|
if ch == `[` {
|
|
bracket_depth++
|
|
} else if ch == `]` {
|
|
if bracket_depth == 0 {
|
|
break
|
|
}
|
|
bracket_depth--
|
|
} else if ch == `{` {
|
|
brace_depth++
|
|
} else if ch == `}` {
|
|
if brace_depth == 0 {
|
|
break
|
|
}
|
|
brace_depth--
|
|
} else if ch == `,` && bracket_depth == 0 && brace_depth == 0 {
|
|
break
|
|
}
|
|
p.pos++
|
|
}
|
|
return p.src[start..p.pos].trim_space()
|
|
}
|
|
|
|
fn (mut p FlowParser) skip_space() {
|
|
for p.pos < p.src.len && p.src[p.pos].is_space() {
|
|
p.pos++
|
|
}
|
|
}
|
|
|
|
fn parse_quoted_flow_string(mut p FlowParser) !string {
|
|
start := p.pos
|
|
quote := p.src[p.pos]
|
|
p.pos++
|
|
mut escape := false
|
|
for p.pos < p.src.len {
|
|
ch := p.src[p.pos]
|
|
if quote == `"` {
|
|
if escape {
|
|
escape = false
|
|
} else if ch == `\\` {
|
|
escape = true
|
|
} else if ch == `"` {
|
|
p.pos++
|
|
return parse_quoted_string(p.src[start..p.pos])
|
|
}
|
|
} else if ch == `'` {
|
|
if p.pos + 1 < p.src.len && p.src[p.pos + 1] == `'` {
|
|
p.pos += 2
|
|
continue
|
|
}
|
|
p.pos++
|
|
return parse_quoted_string(p.src[start..p.pos])
|
|
}
|
|
p.pos++
|
|
}
|
|
return error('yaml: unterminated quoted flow string')
|
|
}
|