From 2799afc14b83368a66ba2ce23da8a79f7ada52c2 Mon Sep 17 00:00:00 2001 From: Drew Wells Date: Mon, 29 Feb 2016 22:44:10 -0600 Subject: [PATCH] adds std encoding API fixes #4 The std encoding format is Unmarshal([]byte, interface{}) error. This naturally lends itself well to being passed readfile or exhausted reader/buffer. --- decoder.go | 11 +++++++++++ decoder_test.go | 10 ++++++++++ lex.go | 17 ++++++++++++----- lex_test.go | 2 +- parse.go | 28 ++++++++++++++++++++++------ 5 files changed, 56 insertions(+), 12 deletions(-) diff --git a/decoder.go b/decoder.go index 3d6b762..6b01859 100644 --- a/decoder.go +++ b/decoder.go @@ -21,6 +21,17 @@ var ( nodeType reflect.Type = findNodeType() ) +// Unmarshal accepts a byte slice as input and writes the +// data to the value pointed to by v. +func Unmarshal(bs []byte, v interface{}) error { + root, err := parse(bs) + if err != nil { + return err + } + + return DecodeObject(v, root) +} + // Decode reads the given input and decodes it into the structure // given by `out`. func Decode(out interface{}, in string) error { diff --git a/decoder_test.go b/decoder_test.go index 8ab8596..73bc4ee 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -291,6 +291,16 @@ func TestDecode_interface(t *testing.T) { if !reflect.DeepEqual(out, tc.Out) { t.Fatalf("Input: %s. Actual, Expected.\n\n%#v\n\n%#v", tc.File, out, tc.Out) } + + var v interface{} + err = Unmarshal(d, &v) + if (err != nil) != tc.Err { + t.Fatalf("Input: %s\n\nError: %s", tc.File, err) + } + + if !reflect.DeepEqual(v, tc.Out) { + t.Fatalf("Input: %s. Actual, Expected.\n\n%#v\n\n%#v", tc.File, out, tc.Out) + } } } diff --git a/lex.go b/lex.go index 2e38ecb..d9993c2 100644 --- a/lex.go +++ b/lex.go @@ -2,6 +2,7 @@ package hcl import ( "unicode" + "unicode/utf8" ) type lexModeValue byte @@ -14,17 +15,23 @@ const ( // lexMode returns whether we're going to be parsing in JSON // mode or HCL mode. -func lexMode(v string) lexModeValue { - for _, r := range v { +func lexMode(v []byte) lexModeValue { + var ( + r rune + w int + offset int + ) + + for { + r, w = utf8.DecodeRune(v[offset:]) + offset += w if unicode.IsSpace(r) { continue } - if r == '{' { return lexModeJson - } else { - return lexModeHcl } + break } return lexModeHcl diff --git a/lex_test.go b/lex_test.go index f7ee378..8062764 100644 --- a/lex_test.go +++ b/lex_test.go @@ -28,7 +28,7 @@ func TestLexMode(t *testing.T) { } for i, tc := range cases { - actual := lexMode(tc.Input) + actual := lexMode([]byte(tc.Input)) if actual != tc.Mode { t.Fatalf("%d: %#v", i, actual) diff --git a/parse.go b/parse.go index d0719c2..1fca53c 100644 --- a/parse.go +++ b/parse.go @@ -8,16 +8,32 @@ import ( jsonParser "github.com/hashicorp/hcl/json/parser" ) -// Parse parses the given input and returns the root object. +// ParseBytes accepts as input byte slice and returns ast tree. // -// The input format can be either HCL or JSON. -func Parse(input string) (*ast.File, error) { - switch lexMode(input) { +// Input can be either JSON or HCL +func ParseBytes(in []byte) (*ast.File, error) { + return parse(in) +} + +// ParseString accepts input as a string and returns ast tree. +func ParseString(input string) (*ast.File, error) { + return parse([]byte(input)) +} + +func parse(in []byte) (*ast.File, error) { + switch lexMode(in) { case lexModeHcl: - return hclParser.Parse([]byte(input)) + return hclParser.Parse(in) case lexModeJson: - return jsonParser.Parse([]byte(input)) + return jsonParser.Parse(in) } return nil, fmt.Errorf("unknown config format") } + +// Parse parses the given input and returns the root object. +// +// The input format can be either HCL or JSON. +func Parse(input string) (*ast.File, error) { + return parse([]byte(input)) +}