blob: dbafa23059c74c8a626b843f4f789f1495817338 [file] [log] [blame]
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +01001package yaml
2
3import (
Marcel van Lohuizen2156c812018-12-10 16:05:07 +01004 "bytes"
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +01005 "encoding/base64"
Marcel van Lohuizen2156c812018-12-10 16:05:07 +01006 "errors"
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +01007 "fmt"
8 "io"
Marcel van Lohuizen2156c812018-12-10 16:05:07 +01009 "io/ioutil"
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +010010 "math"
11 "reflect"
12 "strconv"
Marcel van Lohuizen2156c812018-12-10 16:05:07 +010013 "strings"
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +010014 "time"
Marcel van Lohuizen2156c812018-12-10 16:05:07 +010015 "unicode"
16
17 "cuelang.org/go/cue/ast"
18 "cuelang.org/go/cue/token"
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +010019)
20
21const (
22 documentNode = 1 << iota
23 mappingNode
24 sequenceNode
25 scalarNode
26 aliasNode
27)
28
29type node struct {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +010030 kind int
31 startPos yaml_mark_t
32 endPos yaml_mark_t
33 tag string
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +010034 // For an alias node, alias holds the resolved alias.
35 alias *node
36 value string
37 implicit bool
38 children []*node
39 anchors map[string]*node
40}
41
42// ----------------------------------------------------------------------------
43// Parser, produces a node tree out of a libyaml event stream.
44
45type parser struct {
46 parser yaml_parser_t
47 event yaml_event_t
48 doc *node
Marcel van Lohuizen2156c812018-12-10 16:05:07 +010049 info *token.File
50 last *node
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +010051 doneInit bool
52}
53
Marcel van Lohuizen2156c812018-12-10 16:05:07 +010054func readSource(filename string, src interface{}) ([]byte, error) {
55 if src != nil {
56 switch s := src.(type) {
57 case string:
58 return []byte(s), nil
59 case []byte:
60 return s, nil
61 case *bytes.Buffer:
62 // is io.Reader, but src is already available in []byte form
63 if s != nil {
64 return s.Bytes(), nil
65 }
66 case io.Reader:
67 var buf bytes.Buffer
68 if _, err := io.Copy(&buf, s); err != nil {
69 return nil, err
70 }
71 return buf.Bytes(), nil
72 }
73 return nil, errors.New("invalid source")
74 }
75 return ioutil.ReadFile(filename)
76}
77
Marcel van Lohuizen3c7c40b2019-05-22 11:31:27 -040078func newParser(filename string, src interface{}) (*parser, error) {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +010079 b, err := readSource(filename, src)
80 if err != nil {
81 return nil, err
82 }
Marcel van Lohuizen4697b782019-07-12 22:19:43 +020083 info := token.NewFile(filename, -1, len(b)+2)
Marcel van Lohuizen2156c812018-12-10 16:05:07 +010084 info.SetLinesForContent(b)
85 p := parser{info: info}
86 if !yaml_parser_initialize(&p.parser, filename) {
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +010087 panic("failed to initialize YAML emitter")
88 }
89 if len(b) == 0 {
90 b = []byte{'\n'}
91 }
92 yaml_parser_set_input_string(&p.parser, b)
Marcel van Lohuizen2156c812018-12-10 16:05:07 +010093 return &p, nil
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +010094}
95
96func (p *parser) init() {
97 if p.doneInit {
98 return
99 }
100 p.expect(yaml_STREAM_START_EVENT)
101 p.doneInit = true
102}
103
104func (p *parser) destroy() {
105 if p.event.typ != yaml_NO_EVENT {
106 yaml_event_delete(&p.event)
107 }
108 yaml_parser_delete(&p.parser)
109}
110
111// expect consumes an event from the event stream and
112// checks that it's of the expected type.
113func (p *parser) expect(e yaml_event_type_t) {
114 if p.event.typ == yaml_NO_EVENT {
115 if !yaml_parser_parse(&p.parser, &p.event) {
116 p.fail()
117 }
118 }
119 if p.event.typ == yaml_STREAM_END_EVENT {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100120 p.failf(p.event.end_mark.line, "attempted to go past the end of stream; corrupted value?")
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100121 }
122 if p.event.typ != e {
123 p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
124 p.fail()
125 }
126 yaml_event_delete(&p.event)
127 p.event.typ = yaml_NO_EVENT
128}
129
130// peek peeks at the next event in the event stream,
131// puts the results into p.event and returns the event type.
132func (p *parser) peek() yaml_event_type_t {
133 if p.event.typ != yaml_NO_EVENT {
134 return p.event.typ
135 }
136 if !yaml_parser_parse(&p.parser, &p.event) {
137 p.fail()
138 }
139 return p.event.typ
140}
141
142func (p *parser) fail() {
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100143 var line int
144 if p.parser.problem_mark.line != 0 {
145 line = p.parser.problem_mark.line
146 // Scanner errors don't iterate line before returning error
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100147 if p.parser.error != yaml_SCANNER_ERROR {
148 line--
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100149 }
150 } else if p.parser.context_mark.line != 0 {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100151 line = p.parser.context_mark.line - 1
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100152 }
153 var msg string
154 if len(p.parser.problem) > 0 {
155 msg = p.parser.problem
156 } else {
157 msg = "unknown problem parsing YAML content"
158 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100159 p.failf(line, msg)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100160}
161
162func (p *parser) anchor(n *node, anchor []byte) {
163 if anchor != nil {
164 p.doc.anchors[string(anchor)] = n
165 }
166}
167
168func (p *parser) parse() *node {
169 p.init()
170 switch p.peek() {
171 case yaml_SCALAR_EVENT:
172 return p.scalar()
173 case yaml_ALIAS_EVENT:
174 return p.alias()
175 case yaml_MAPPING_START_EVENT:
176 return p.mapping()
177 case yaml_SEQUENCE_START_EVENT:
178 return p.sequence()
179 case yaml_DOCUMENT_START_EVENT:
180 return p.document()
181 case yaml_STREAM_END_EVENT:
182 // Happens when attempting to decode an empty buffer.
183 return nil
184 default:
185 panic("attempted to parse unknown event: " + p.event.typ.String())
186 }
187}
188
189func (p *parser) node(kind int) *node {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100190 n := &node{
191 kind: kind,
192 startPos: p.event.start_mark,
193 endPos: p.event.end_mark,
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100194 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100195 return n
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100196}
197
198func (p *parser) document() *node {
199 n := p.node(documentNode)
200 n.anchors = make(map[string]*node)
201 p.doc = n
202 p.expect(yaml_DOCUMENT_START_EVENT)
203 n.children = append(n.children, p.parse())
204 p.expect(yaml_DOCUMENT_END_EVENT)
205 return n
206}
207
208func (p *parser) alias() *node {
209 n := p.node(aliasNode)
210 n.value = string(p.event.anchor)
211 n.alias = p.doc.anchors[n.value]
212 if n.alias == nil {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100213 p.failf(n.startPos.line, "unknown anchor '%s' referenced", n.value)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100214 }
215 p.expect(yaml_ALIAS_EVENT)
216 return n
217}
218
219func (p *parser) scalar() *node {
220 n := p.node(scalarNode)
221 n.value = string(p.event.value)
222 n.tag = string(p.event.tag)
223 n.implicit = p.event.implicit
224 p.anchor(n, p.event.anchor)
225 p.expect(yaml_SCALAR_EVENT)
226 return n
227}
228
229func (p *parser) sequence() *node {
230 n := p.node(sequenceNode)
231 p.anchor(n, p.event.anchor)
232 p.expect(yaml_SEQUENCE_START_EVENT)
233 for p.peek() != yaml_SEQUENCE_END_EVENT {
234 n.children = append(n.children, p.parse())
235 }
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200236 if len(n.children) > 0 {
237 n.endPos = n.children[len(n.children)-1].endPos
238 }
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100239 p.expect(yaml_SEQUENCE_END_EVENT)
240 return n
241}
242
243func (p *parser) mapping() *node {
244 n := p.node(mappingNode)
245 p.anchor(n, p.event.anchor)
246 p.expect(yaml_MAPPING_START_EVENT)
247 for p.peek() != yaml_MAPPING_END_EVENT {
248 n.children = append(n.children, p.parse(), p.parse())
249 }
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200250 if len(n.children) > 0 {
251 n.endPos = n.children[len(n.children)-1].endPos
252 }
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100253 p.expect(yaml_MAPPING_END_EVENT)
254 return n
255}
256
257// ----------------------------------------------------------------------------
258// Decoder, unmarshals a node into a provided value.
259
260type decoder struct {
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200261 p *parser
262 doc *node
263 aliases map[*node]bool
264 mapType reflect.Type
265 terrors []string
266 prev token.Pos
267 lastNode ast.Node
268 forceNewline bool
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100269}
270
271var (
272 mapItemType = reflect.TypeOf(MapItem{})
273 durationType = reflect.TypeOf(time.Duration(0))
274 defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100275 timeType = reflect.TypeOf(time.Time{})
276 ptrTimeType = reflect.TypeOf(&time.Time{})
277)
278
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100279func newDecoder(p *parser) *decoder {
280 d := &decoder{p: p, mapType: defaultMapType}
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100281 d.aliases = make(map[*node]bool)
282 return d
283}
284
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100285func (d *decoder) terror(n *node, tag string) string {
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100286 if n.tag != "" {
287 tag = n.tag
288 }
289 value := n.value
290 if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG {
291 if len(value) > 10 {
292 value = " `" + value[:7] + "...`"
293 } else {
294 value = " `" + value + "`"
295 }
296 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100297 msg := fmt.Sprintf("line %d: cannot unmarshal %s%s", n.startPos.line+1, shortTag(tag), value)
298 d.terrors = append(d.terrors, msg)
299 return msg
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100300}
301
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100302func (d *decoder) unmarshal(n *node) (node ast.Expr) {
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100303 switch n.kind {
304 case documentNode:
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100305 node = d.document(n)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100306 case aliasNode:
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100307 node = d.alias(n)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100308 default:
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100309 switch n.kind {
310 case scalarNode:
311 node = d.scalar(n)
312 case mappingNode:
313 node = d.mapping(n)
314 case sequenceNode:
315 node = d.sequence(n)
316 default:
317 panic("internal error: unknown node kind: " + strconv.Itoa(n.kind))
318 }
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100319 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100320 return node
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100321}
322
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100323func (d *decoder) attachDocComments(m yaml_mark_t, pos int8, expr ast.Node) {
324 comments := []*ast.Comment{}
Marcel van Lohuizenb50aecd2019-09-09 18:30:33 +0200325 line := 0
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100326 for len(d.p.parser.comments) > 0 {
327 c := d.p.parser.comments[0]
328 if c.mark.index >= m.index {
329 break
330 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100331 comments = append(comments, &ast.Comment{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200332 Slash: d.pos(c.mark),
333 Text: "//" + c.text[1:],
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100334 })
335 d.p.parser.comments = d.p.parser.comments[1:]
Marcel van Lohuizenb50aecd2019-09-09 18:30:33 +0200336 line = c.mark.line
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100337 }
338 if len(comments) > 0 {
339 expr.AddComment(&ast.CommentGroup{
Marcel van Lohuizenb50aecd2019-09-09 18:30:33 +0200340 Doc: pos == 0 && line+1 == m.line,
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100341 Position: pos,
342 List: comments,
343 })
344 }
345}
346
347func (d *decoder) attachLineComment(m yaml_mark_t, pos int8, expr ast.Node) {
348 if len(d.p.parser.comments) == 0 {
349 return
350 }
351 c := d.p.parser.comments[0]
352 if c.mark.index == m.index {
353 comment := &ast.Comment{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200354 Slash: d.pos(c.mark),
355 Text: "//" + c.text[1:],
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100356 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100357 expr.AddComment(&ast.CommentGroup{
358 Line: true,
359 Position: pos,
360 List: []*ast.Comment{comment},
361 })
362 }
363}
364
365func (d *decoder) pos(m yaml_mark_t) token.Pos {
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200366 pos := d.p.info.Pos(m.index+1, token.NoRelPos)
367
368 if d.forceNewline {
369 d.forceNewline = false
370 pos = pos.WithRel(token.Newline)
371 } else if d.prev.IsValid() {
372 c := pos.Position()
373 p := d.prev.Position()
374 switch {
375 case c.Line-p.Line >= 2:
376 pos = pos.WithRel(token.NewSection)
377 case c.Line-p.Line == 1:
378 pos = pos.WithRel(token.Newline)
379 case c.Column-p.Column > 0:
380 pos = pos.WithRel(token.Blank)
381 default:
382 pos = pos.WithRel(token.NoSpace)
383 }
384 if pos.Before(d.prev) {
385 return token.NoPos
386 }
387 }
388
389 d.prev = pos
390 return pos
391}
392
393func (d *decoder) absPos(m yaml_mark_t) token.Pos {
394 return d.p.info.Pos(m.index+1, token.NoRelPos)
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100395}
396
397func (d *decoder) start(n *node) token.Pos {
Adieu5cb6ffe2019-12-03 19:31:03 +0100398 if n.startPos == n.endPos {
399 return token.NoPos
400 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100401 return d.pos(n.startPos)
402}
403
404func (d *decoder) ident(n *node, name string) *ast.Ident {
405 return &ast.Ident{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200406 NamePos: d.pos(n.startPos),
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100407 Name: name,
408 }
409}
410
411func (d *decoder) document(n *node) ast.Expr {
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100412 if len(n.children) == 1 {
413 d.doc = n
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100414 return d.unmarshal(n.children[0])
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100415 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100416 return &ast.BottomLit{} // TODO: more informatives
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100417}
418
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100419func (d *decoder) alias(n *node) ast.Expr {
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100420 if d.aliases[n] {
421 // TODO this could actually be allowed in some circumstances.
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100422 d.p.failf(n.startPos.line, "anchor '%s' value contains itself", n.value)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100423 }
424 d.aliases[n] = true
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100425 node := d.unmarshal(n.alias)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100426 delete(d.aliases, n)
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100427 return node
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100428}
429
430var zeroValue reflect.Value
431
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100432func (d *decoder) scalar(n *node) ast.Expr {
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100433 var tag string
434 var resolved interface{}
435 if n.tag == "" && !n.implicit {
436 tag = yaml_STR_TAG
437 resolved = n.value
438 } else {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100439 tag, resolved = d.resolve(n)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100440 if tag == yaml_BINARY_TAG {
441 data, err := base64.StdEncoding.DecodeString(resolved.(string))
442 if err != nil {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100443 d.p.failf(n.startPos.line, "!!binary value contains invalid base64 data")
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100444 }
445 resolved = string(data)
446 }
447 }
448 if resolved == nil {
Adieu503fecd2019-11-22 08:29:32 -0800449 return &ast.BasicLit{
Adieu5cb6ffe2019-12-03 19:31:03 +0100450 ValuePos: d.start(n).WithRel(token.Blank),
Adieu503fecd2019-11-22 08:29:32 -0800451 Kind: token.NULL,
452 Value: "null",
453 }
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100454 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100455 switch tag {
456 // TODO: use parse literal or parse expression instead.
457 case yaml_TIMESTAMP_TAG:
458 return &ast.BasicLit{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200459 ValuePos: d.start(n),
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100460 Kind: token.STRING,
461 Value: strconv.Quote(n.value),
462 }
463
464 case yaml_STR_TAG:
465 return &ast.BasicLit{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200466 ValuePos: d.start(n),
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100467 Kind: token.STRING,
468 Value: d.quoteString(n.value),
469 }
470
471 case yaml_BINARY_TAG:
472 buf := strconv.AppendQuote(nil, resolved.(string))
473 buf[0] = '\''
474 buf[len(buf)-1] = '\''
475 return &ast.BasicLit{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200476 ValuePos: d.start(n),
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100477 Kind: token.STRING,
478 Value: string(buf),
479 }
480
481 case yaml_BOOL_TAG:
Marcel van Lohuizen12335942019-07-11 18:05:29 +0200482 tok := token.FALSE
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100483 str := "false"
484 if b, _ := resolved.(bool); b {
Marcel van Lohuizen12335942019-07-11 18:05:29 +0200485 tok = token.TRUE
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100486 str = "true"
487 }
Marcel van Lohuizen12335942019-07-11 18:05:29 +0200488 return &ast.BasicLit{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200489 ValuePos: d.start(n),
Marcel van Lohuizen12335942019-07-11 18:05:29 +0200490 Kind: tok,
491 Value: str,
492 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100493
494 case yaml_INT_TAG:
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100495 // Convert YAML octal to CUE octal. If YAML accepted an invalid
496 // integer, just convert it as well to ensure CUE will fail.
497 s := n.value
498 if len(s) > 1 && s[0] == '0' && s[1] <= '9' {
499 s = "0o" + s[1:]
500 }
501 return d.makeNum(n, s, token.INT)
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100502
503 case yaml_FLOAT_TAG:
504 value := n.value
505 if f, ok := resolved.(float64); ok {
506 switch {
507 case math.IsInf(f, -1),
508 math.IsInf(f, 1),
509 math.IsNaN(f):
510 value = fmt.Sprint(f)
511 }
512 }
513 if n.tag != "" {
514 if p := strings.IndexAny(value, ".eEiInN"); p == -1 {
515 // TODO: float(v) when we have conversions
516 value = fmt.Sprintf("float & %s", value)
517 }
518 }
519 return d.makeNum(n, value, token.FLOAT)
520
521 case yaml_NULL_TAG:
Marcel van Lohuizen12335942019-07-11 18:05:29 +0200522 return &ast.BasicLit{
Adieu5cb6ffe2019-12-03 19:31:03 +0100523 ValuePos: d.start(n).WithRel(token.Blank),
Marcel van Lohuizen12335942019-07-11 18:05:29 +0200524 Kind: token.NULL,
525 Value: "null",
526 }
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100527 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100528 err := &ast.BottomLit{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200529 Bottom: d.pos(n.startPos),
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100530 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100531 comment := &ast.Comment{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200532 Slash: d.start(n),
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100533 Text: "// " + d.terror(n, tag),
534 }
535 err.AddComment(&ast.CommentGroup{
536 Line: true,
537 Position: 1,
538 List: []*ast.Comment{comment},
539 })
540 return err
541}
542
543func (d *decoder) label(n *node) ast.Label {
544 var tag string
545 if n.tag == "" && !n.implicit {
546 tag = yaml_STR_TAG
547 } else {
548 tag, _ = d.resolve(n)
549 }
550 if tag == yaml_STR_TAG {
551 // TODO: improve
552 for i, r := range n.value {
553 if !unicode.In(r, unicode.L) && r != '_' {
554 if i == 0 || !unicode.In(r, unicode.N) {
555 goto stringLabel
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100556 }
557 }
558 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100559 return d.ident(n, n.value)
560 }
561stringLabel:
562 return &ast.BasicLit{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200563 ValuePos: d.start(n),
564 Kind: token.STRING,
565 Value: strconv.Quote(n.value),
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100566 }
567}
568
569func (d *decoder) makeNum(n *node, val string, kind token.Token) (expr ast.Expr) {
570 minuses := 0
571 for ; val[0] == '-'; val = val[1:] {
572 minuses++
573 }
574 expr = &ast.BasicLit{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200575 ValuePos: d.start(n), // + minuses.Pos(),
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100576 Kind: kind,
577 Value: val,
578 }
579 if minuses > 0 {
580 expr = &ast.UnaryExpr{
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200581 OpPos: d.start(n),
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100582 Op: token.SUB,
583 X: expr,
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100584 }
585 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100586 return expr
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100587}
588
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100589// quoteString converts a string to a CUE multiline string if needed.
590func (d *decoder) quoteString(s string) string {
591 lines := []string{}
592 last := 0
593 for i, c := range s {
594 if c == '\n' {
595 lines = append(lines, s[last:i])
596 last = i + 1
597 }
598 if c == '\r' {
599 goto quoted
600 }
601 }
602 lines = append(lines, s[last:])
603 if len(lines) >= 2 {
604 buf := []byte{}
605 buf = append(buf, `"""`+"\n"...)
606 for _, l := range lines {
607 if l == "" {
608 // no indentation for empty lines
609 buf = append(buf, '\n')
610 continue
611 }
612 buf = append(buf, '\t')
613 p := len(buf)
614 buf = strconv.AppendQuote(buf, l)
615 // remove quotes
616 buf[p] = '\t'
617 buf[len(buf)-1] = '\n'
618 }
619 buf = append(buf, "\t\t"+`"""`...)
620 return string(buf)
621 }
622quoted:
623 return strconv.Quote(s)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100624}
625
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100626func (d *decoder) sequence(n *node) ast.Expr {
627 list := &ast.ListLit{}
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200628 list.Lbrack = d.pos(n.startPos).WithRel(token.Blank)
629 switch ln := len(n.children); ln {
630 case 0:
631 d.prev = list.Lbrack
632 default:
633 d.prev = d.pos(n.children[ln-1].endPos)
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100634 }
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200635 list.Rbrack = d.pos(n.endPos)
636
637 noNewline := true
638 single := d.isOneLiner(n.startPos, n.endPos)
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100639 for _, c := range n.children {
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200640 d.forceNewline = !single
641 elem := d.unmarshal(c)
642 list.Elts = append(list.Elts, elem)
643 _, noNewline = elem.(*ast.StructLit)
644 }
645 if !single && !noNewline {
646 list.Rbrack = list.Rbrack.WithRel(token.Newline)
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100647 }
648 return list
649}
650
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200651func (d *decoder) isOneLiner(start, end yaml_mark_t) bool {
652 s := d.absPos(start).Position()
653 e := d.absPos(end).Position()
654 return s.Line == e.Line
655}
656
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100657func (d *decoder) mapping(n *node) ast.Expr {
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200658 newline := d.forceNewline
659
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100660 structure := &ast.StructLit{}
661 d.insertMap(n, structure, false)
Marcel van Lohuizen4697b782019-07-12 22:19:43 +0200662
663 // NOTE: we currently translate YAML without curly braces to CUE with
664 // curly braces, even for single elements. Removing the following line
665 // would generate the folded form.
666 structure.Lbrace = d.absPos(n.startPos).WithRel(token.NoSpace)
667 structure.Rbrace = d.absPos(n.endPos).WithRel(token.Newline)
668 if d.isOneLiner(n.startPos, n.endPos) && !newline {
669 if len(structure.Elts) != 1 {
670 structure.Lbrace = d.absPos(n.startPos).WithRel(token.Blank)
671 }
672 if len(structure.Elts) != 1 || structure.Elts[0].Pos().RelPos() < token.Newline {
673 structure.Rbrace = structure.Rbrace.WithRel(token.Blank)
674 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100675 }
676 return structure
677}
678
679func (d *decoder) insertMap(n *node, m *ast.StructLit, merge bool) {
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100680 l := len(n.children)
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100681outer:
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100682 for i := 0; i < l; i += 2 {
683 if isMerge(n.children[i]) {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100684 merge = true
685 d.merge(n.children[i+1], m)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100686 continue
687 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100688 switch n.children[i].kind {
689 case mappingNode:
690 d.p.failf(n.startPos.line, "invalid map key: map")
691 case sequenceNode:
692 d.p.failf(n.startPos.line, "invalid map key: sequence")
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100693 }
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100694
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100695 field := &ast.Field{}
696 d.attachDocComments(n.children[i].startPos, 0, field)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100697
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100698 label := d.label(n.children[i])
699 field.Label = label
700 d.attachLineComment(n.children[i].endPos, 1, label)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100701
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100702 if merge {
703 key := labelStr(label)
704 for _, decl := range m.Elts {
705 f := decl.(*ast.Field)
Marcel van Lohuizen92408e32019-09-12 11:47:12 +0200706 name, _, err := ast.LabelName(f.Label)
707 if err == nil && name == key {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100708 f.Value = d.unmarshal(n.children[i+1])
709 continue outer
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100710 }
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100711 }
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100712 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100713
714 value := d.unmarshal(n.children[i+1])
715 field.Value = value
716 d.attachDocComments(n.children[i+1].startPos, 0, value)
717 d.attachLineComment(n.children[i+1].endPos, 10, value)
718
719 m.Elts = append(m.Elts, field)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100720 }
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100721}
722
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100723func labelStr(l ast.Label) string {
724 switch x := l.(type) {
725 case *ast.Ident:
726 return x.Name
727 case *ast.BasicLit:
728 s, _ := strconv.Unquote(x.Value)
729 return s
730 }
731 return ""
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100732}
733
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100734func (d *decoder) failWantMap(n *node) {
735 d.p.failf(n.startPos.line, "map merge requires map or sequence of maps as the value")
736}
737
738func (d *decoder) merge(n *node, m *ast.StructLit) {
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100739 switch n.kind {
740 case mappingNode:
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100741 d.insertMap(n, m, true)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100742 case aliasNode:
743 an, ok := d.doc.anchors[n.value]
744 if ok && an.kind != mappingNode {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100745 d.failWantMap(n)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100746 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100747 d.insertMap(an, m, true)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100748 case sequenceNode:
749 // Step backwards as earlier nodes take precedence.
750 for i := len(n.children) - 1; i >= 0; i-- {
751 ni := n.children[i]
752 if ni.kind == aliasNode {
753 an, ok := d.doc.anchors[ni.value]
754 if ok && an.kind != mappingNode {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100755 d.failWantMap(n)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100756 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100757 d.insertMap(an, m, true)
758 continue
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100759 } else if ni.kind != mappingNode {
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100760 d.failWantMap(n)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100761 }
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100762 d.insertMap(ni, m, true)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100763 }
764 default:
Marcel van Lohuizen2156c812018-12-10 16:05:07 +0100765 d.failWantMap(n)
Marcel van Lohuizen07ee2ab2018-12-10 15:57:15 +0100766 }
767}
768
769func isMerge(n *node) bool {
770 return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
771}