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 { for _, test := range tests {
t.Run(test.input, func(t *testing.T) { 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 { if len(diags) != test.diagCount {
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.diagCount) t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.diagCount)
for _, diag := range diags { for _, diag := range diags {
@ -151,6 +151,8 @@ func TestParseConfig(t *testing.T) {
} }
} }
got := file.Body
if !reflect.DeepEqual(got, test.want) { if !reflect.DeepEqual(got, test.want) {
diff := prettyConfig.Compare(test.want, got) diff := prettyConfig.Compare(test.want, got)
t.Errorf("wrong result\ninput: %s\ndiff: %s", test.input, diff) 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 // 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 // diagnostics returns true, the returned body is likely to be incomplete
// and should therefore be used with care. // 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) tokens := LexConfig(src, filename, start)
peeker := newPeeker(tokens, false) peeker := newPeeker(tokens, false)
parser := &parser{peeker: peeker} 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, // ParseExpression parses the given buffer as a standalone zcl expression,

View File

@ -1,9 +1,13 @@
package zclparse package zclparse
import ( import (
"fmt"
"io/ioutil"
"github.com/zclconf/go-zcl/zcl" "github.com/zclconf/go-zcl/zcl"
"github.com/zclconf/go-zcl/zcl/hclhil" "github.com/zclconf/go-zcl/zcl/hclhil"
"github.com/zclconf/go-zcl/zcl/json" "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 // NOTE: This is the public interface for parsing. The actual parsers are
@ -24,6 +28,39 @@ type Parser struct {
files map[string]*zcl.File 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 // 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. // from the given filename) and returns the zcl.File object representing it.
func (p *Parser) ParseJSON(src []byte, filename string) (*zcl.File, zcl.Diagnostics) { func (p *Parser) ParseJSON(src []byte, filename string) (*zcl.File, zcl.Diagnostics) {