zclparse: ParseZCL and ParseZCLFile methods

These are the top-level interface to parsing configuration files in the
native zcl syntax, similarly to the existing methods for parsing other
syntaxes.
This commit is contained in:
Martin Atkins 2017-05-30 08:03:38 -07:00
parent e953e1c18a
commit 9348014b2d
3 changed files with 53 additions and 4 deletions

View File

@ -143,7 +143,7 @@ func TestParseConfig(t *testing.T) {
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
got, diags := ParseConfig([]byte(test.input), "", zcl.Pos{Byte: 0, Line: 1, Column: 1})
file, diags := ParseConfig([]byte(test.input), "", zcl.Pos{Byte: 0, Line: 1, Column: 1})
if len(diags) != test.diagCount {
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.diagCount)
for _, diag := range diags {
@ -151,6 +151,8 @@ func TestParseConfig(t *testing.T) {
}
}
got := file.Body
if !reflect.DeepEqual(got, test.want) {
diff := prettyConfig.Compare(test.want, got)
t.Errorf("wrong result\ninput: %s\ndiff: %s", test.input, diff)

View File

@ -5,14 +5,24 @@ import (
)
// ParseConfig parses the given buffer as a whole zcl config file, returning
// a Body representing its contents. If HasErrors called on the returned
// a *zcl.File representing its contents. If HasErrors called on the returned
// diagnostics returns true, the returned body is likely to be incomplete
// and should therefore be used with care.
func ParseConfig(src []byte, filename string, start zcl.Pos) (*Body, zcl.Diagnostics) {
//
// The body in the returned file has dynamic type *zclsyntax.Body, so callers
// may freely type-assert this to get access to the full zclsyntax API in
// situations where detailed access is required. However, most common use-cases
// should be served using the zcl.Body interface to ensure compatibility with
// other configurationg syntaxes, such as JSON.
func ParseConfig(src []byte, filename string, start zcl.Pos) (*zcl.File, zcl.Diagnostics) {
tokens := LexConfig(src, filename, start)
peeker := newPeeker(tokens, false)
parser := &parser{peeker: peeker}
return parser.ParseBody(TokenEOF)
body, diags := parser.ParseBody(TokenEOF)
return &zcl.File{
Body: body,
Bytes: src,
}, diags
}
// ParseExpression parses the given buffer as a standalone zcl expression,

View File

@ -1,9 +1,13 @@
package zclparse
import (
"fmt"
"io/ioutil"
"github.com/zclconf/go-zcl/zcl"
"github.com/zclconf/go-zcl/zcl/hclhil"
"github.com/zclconf/go-zcl/zcl/json"
"github.com/zclconf/go-zcl/zcl/zclsyntax"
)
// NOTE: This is the public interface for parsing. The actual parsers are
@ -24,6 +28,39 @@ type Parser struct {
files map[string]*zcl.File
}
// ParseZCL parses the given buffer (which is assumed to have been loaded from
// the given filename) as a native-syntax configuration file and returns the
// zcl.File object representing it.
func (p *Parser) ParseZCL(src []byte, filename string) (*zcl.File, zcl.Diagnostics) {
if existing := p.files[filename]; existing != nil {
return existing, nil
}
return zclsyntax.ParseConfig(src, filename, zcl.Pos{Byte: 0, Line: 1, Column: 1})
}
// ParseZCLFile reads the given filename and parses it as a native-syntax zcl
// configuration file. An error diagnostic is returned if the given file
// cannot be read.
func (p *Parser) ParseZCLFile(filename string) (*zcl.File, zcl.Diagnostics) {
if existing := p.files[filename]; existing != nil {
return existing, nil
}
src, err := ioutil.ReadFile(filename)
if err != nil {
return nil, zcl.Diagnostics{
{
Severity: zcl.DiagError,
Summary: "Failed to read file",
Detail: fmt.Sprintf("The configuration file %q could not be read.", filename),
},
}
}
return p.ParseZCL(src, filename)
}
// ParseJSON parses the given JSON buffer (which is assumed to have been loaded
// from the given filename) and returns the zcl.File object representing it.
func (p *Parser) ParseJSON(src []byte, filename string) (*zcl.File, zcl.Diagnostics) {