9348014b2d
These are the top-level interface to parsing configuration files in the native zcl syntax, similarly to the existing methods for parsing other syntaxes.
171 lines
5.8 KiB
Go
171 lines
5.8 KiB
Go
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
|
|
// in other packages alongside this one, with this package just wrapping them
|
|
// to provide a unified interface for the caller across all supported formats.
|
|
|
|
// Parser is the main interface for parsing configuration files. As well as
|
|
// parsing files, a parser also retains a registry of all of the files it
|
|
// has parsed so that multiple attempts to parse the same file will return
|
|
// the same object and so the collected files can be used when printing
|
|
// diagnostics.
|
|
//
|
|
// Any diagnostics for parsing a file are only returned once on the first
|
|
// call to parse that file. Callers are expected to collect up diagnostics
|
|
// and present them together, so returning diagnostics for the same file
|
|
// multiple times would create a confusing result.
|
|
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) {
|
|
if existing := p.files[filename]; existing != nil {
|
|
return existing, nil
|
|
}
|
|
|
|
file, diags := json.Parse(src, filename)
|
|
p.files[filename] = file
|
|
return file, diags
|
|
}
|
|
|
|
// ParseJSONWithHIL parses the given JSON buffer (which is assumed to have been
|
|
// loaded from the given filename) and returns the zcl.File object representing
|
|
// it. Unlike ParseJSON, the strings within the file will be interpreted as
|
|
// HIL templates rather than native zcl templates.
|
|
func (p *Parser) ParseJSONWithHIL(src []byte, filename string) (*zcl.File, zcl.Diagnostics) {
|
|
if existing := p.files[filename]; existing != nil {
|
|
return existing, nil
|
|
}
|
|
|
|
file, diags := json.ParseWithHIL(src, filename)
|
|
p.files[filename] = file
|
|
return file, diags
|
|
}
|
|
|
|
// ParseJSONFile reads the given filename and parses it as JSON, similarly to
|
|
// ParseJSON. An error diagnostic is returned if the given file cannot be read.
|
|
func (p *Parser) ParseJSONFile(filename string) (*zcl.File, zcl.Diagnostics) {
|
|
if existing := p.files[filename]; existing != nil {
|
|
return existing, nil
|
|
}
|
|
|
|
file, diags := json.ParseFile(filename)
|
|
p.files[filename] = file
|
|
return file, diags
|
|
}
|
|
|
|
// ParseJSONFileWithHIL reads the given filename and parses it as JSON, similarly to
|
|
// ParseJSONWithHIL. An error diagnostic is returned if the given file cannot be read.
|
|
func (p *Parser) ParseJSONFileWithHIL(filename string) (*zcl.File, zcl.Diagnostics) {
|
|
if existing := p.files[filename]; existing != nil {
|
|
return existing, nil
|
|
}
|
|
|
|
file, diags := json.ParseFileWithHIL(filename)
|
|
p.files[filename] = file
|
|
return file, diags
|
|
}
|
|
|
|
// ParseHCLHIL parses the given buffer (which is assumed to have been loaded
|
|
// from the given filename) using the HCL and HIL parsers, and returns the
|
|
// zcl.File object representing it.
|
|
//
|
|
// This HCL/HIL parser is a compatibility interface to ease migration for
|
|
// apps that previously used HCL and HIL directly.
|
|
func (p *Parser) ParseHCLHIL(src []byte, filename string) (*zcl.File, zcl.Diagnostics) {
|
|
if existing := p.files[filename]; existing != nil {
|
|
return existing, nil
|
|
}
|
|
|
|
file, diags := hclhil.Parse(src, filename)
|
|
p.files[filename] = file
|
|
return file, diags
|
|
}
|
|
|
|
// ParseHCLHILFile reads the given filename and parses it as HCL/HIL, similarly
|
|
// to ParseHCLHIL. An error diagnostic is returned if the given file cannot be
|
|
// read.
|
|
func (p *Parser) ParseHCLHILFile(filename string) (*zcl.File, zcl.Diagnostics) {
|
|
if existing := p.files[filename]; existing != nil {
|
|
return existing, nil
|
|
}
|
|
|
|
file, diags := hclhil.ParseFile(filename)
|
|
p.files[filename] = file
|
|
return file, diags
|
|
}
|
|
|
|
// AddFile allows a caller to record in a parser a file that was parsed some
|
|
// other way, thus allowing it to be included in the registry of sources.
|
|
func (p *Parser) AddFile(filename string, file *zcl.File) {
|
|
p.files[filename] = file
|
|
}
|
|
|
|
// Sources returns a map from filenames to the raw source code that was
|
|
// read from them. This is intended to be used, for example, to print
|
|
// diagnostics with contextual information.
|
|
//
|
|
// The arrays underlying the returned slices should not be modified.
|
|
func (p *Parser) Sources() map[string][]byte {
|
|
ret := make(map[string][]byte)
|
|
for fn, f := range p.files {
|
|
ret[fn] = f.Bytes
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// Files returns a map from filenames to the File objects produced from them.
|
|
// This is intended to be used, for example, to print diagnostics with
|
|
// contextual information.
|
|
//
|
|
// The returned map and all of the objects it refers to directly or indirectly
|
|
// must not be modified.
|
|
func (p *Parser) Files() map[string]*zcl.File {
|
|
return p.files
|
|
}
|