Skip to content

Commit

Permalink
Merge pull request go-yaml#304 from rogpeppe/013-read-on-demand
Browse files Browse the repository at this point in the history
do not read ahead unnecessarily
  • Loading branch information
rogpeppe authored Jan 5, 2018
2 parents 0ee3698 + 18e5f12 commit 39e59aa
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 25 deletions.
62 changes: 37 additions & 25 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@ func (p *parser) init() {
if p.doneInit {
return
}
p.skip()
if p.event.typ != yaml_STREAM_START_EVENT {
panic("expected stream start event, got " + strconv.Itoa(int(p.event.typ)))
}
p.skip()
p.expect(yaml_STREAM_START_EVENT)
p.doneInit = true
}

Expand All @@ -81,16 +77,35 @@ func (p *parser) destroy() {
yaml_parser_delete(&p.parser)
}

func (p *parser) skip() {
if p.event.typ != yaml_NO_EVENT {
if p.event.typ == yaml_STREAM_END_EVENT {
failf("attempted to go past the end of stream; corrupted value?")
// expect consumes an event from the event stream and
// checks that it's of the expected type.
func (p *parser) expect(e yaml_event_type_t) {
if p.event.typ == yaml_NO_EVENT {
if !yaml_parser_parse(&p.parser, &p.event) {
p.fail()
}
yaml_event_delete(&p.event)
}
if p.event.typ == yaml_STREAM_END_EVENT {
failf("attempted to go past the end of stream; corrupted value?")
}
if p.event.typ != e {
p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
p.fail()
}
yaml_event_delete(&p.event)
p.event.typ = yaml_NO_EVENT
}

// peek peeks at the next event in the event stream,
// puts the results into p.event and returns the event type.
func (p *parser) peek() yaml_event_type_t {
if p.event.typ != yaml_NO_EVENT {
return p.event.typ
}
if !yaml_parser_parse(&p.parser, &p.event) {
p.fail()
}
return p.event.typ
}

func (p *parser) fail() {
Expand Down Expand Up @@ -121,7 +136,7 @@ func (p *parser) anchor(n *node, anchor []byte) {

func (p *parser) parse() *node {
p.init()
switch p.event.typ {
switch p.peek() {
case yaml_SCALAR_EVENT:
return p.scalar()
case yaml_ALIAS_EVENT:
Expand All @@ -136,7 +151,7 @@ func (p *parser) parse() *node {
// Happens when attempting to decode an empty buffer.
return nil
default:
panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ)))
panic("attempted to parse unknown event: " + p.event.typ.String())
}
}

Expand All @@ -152,12 +167,9 @@ func (p *parser) document() *node {
n := p.node(documentNode)
n.anchors = make(map[string]*node)
p.doc = n
p.skip()
p.expect(yaml_DOCUMENT_START_EVENT)
n.children = append(n.children, p.parse())
if p.event.typ != yaml_DOCUMENT_END_EVENT {
panic("expected end of document event but got " + strconv.Itoa(int(p.event.typ)))
}
p.skip()
p.expect(yaml_DOCUMENT_END_EVENT)
return n
}

Expand All @@ -168,7 +180,7 @@ func (p *parser) alias() *node {
if n.alias == nil {
failf("unknown anchor '%s' referenced", n.value)
}
p.skip()
p.expect(yaml_ALIAS_EVENT)
return n
}

Expand All @@ -178,29 +190,29 @@ func (p *parser) scalar() *node {
n.tag = string(p.event.tag)
n.implicit = p.event.implicit
p.anchor(n, p.event.anchor)
p.skip()
p.expect(yaml_SCALAR_EVENT)
return n
}

func (p *parser) sequence() *node {
n := p.node(sequenceNode)
p.anchor(n, p.event.anchor)
p.skip()
for p.event.typ != yaml_SEQUENCE_END_EVENT {
p.expect(yaml_SEQUENCE_START_EVENT)
for p.peek() != yaml_SEQUENCE_END_EVENT {
n.children = append(n.children, p.parse())
}
p.skip()
p.expect(yaml_SEQUENCE_END_EVENT)
return n
}

func (p *parser) mapping() *node {
n := p.node(mappingNode)
p.anchor(n, p.event.anchor)
p.skip()
for p.event.typ != yaml_MAPPING_END_EVENT {
p.expect(yaml_MAPPING_START_EVENT)
for p.peek() != yaml_MAPPING_END_EVENT {
n.children = append(n.children, p.parse(), p.parse())
}
p.skip()
p.expect(yaml_MAPPING_END_EVENT)
return n
}

Expand Down
5 changes: 5 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,11 @@ var unmarshalTests = []struct {
"Override anchor": "Bar",
},
},
// Single document with garbage following it.
{
"---\nhello\n...\n}not yaml",
"hello",
},
}

type M map[interface{}]interface{}
Expand Down
22 changes: 22 additions & 0 deletions yamlh.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package yaml

import (
"fmt"
"io"
)

Expand Down Expand Up @@ -239,6 +240,27 @@ const (
yaml_MAPPING_END_EVENT // A MAPPING-END event.
)

var eventStrings = []string{
yaml_NO_EVENT: "none",
yaml_STREAM_START_EVENT: "stream start",
yaml_STREAM_END_EVENT: "stream end",
yaml_DOCUMENT_START_EVENT: "document start",
yaml_DOCUMENT_END_EVENT: "document end",
yaml_ALIAS_EVENT: "alias",
yaml_SCALAR_EVENT: "scalar",
yaml_SEQUENCE_START_EVENT: "sequence start",
yaml_SEQUENCE_END_EVENT: "sequence end",
yaml_MAPPING_START_EVENT: "mapping start",
yaml_MAPPING_END_EVENT: "mapping end",
}

func (e yaml_event_type_t) String() string {
if e < 0 || int(e) >= len(eventStrings) {
return fmt.Sprintf("unknown event %d", e)
}
return eventStrings[e]
}

// The event structure.
type yaml_event_t struct {

Expand Down

0 comments on commit 39e59aa

Please sign in to comment.