json: parse strings as zclsyntax templates

This is the same idea as our existing HIL template support, but uses the
zclsyntax template parser instead of HIL's parser.
This commit is contained in:
Martin Atkins 2017-06-12 07:25:09 -07:00
parent a0be779c9c
commit b878a4ef98
2 changed files with 102 additions and 3 deletions

View File

@ -24,6 +24,78 @@ func TestParse_nonObject(t *testing.T) {
}
}
func TestParseTemplate(t *testing.T) {
src := `{"greeting": "hello ${\"world\"}"}`
file, diags := Parse([]byte(src), "")
if len(diags) != 0 {
t.Errorf("got %d diagnostics on parse; want 0", len(diags))
for _, diag := range diags {
t.Logf("- %s", diag.Error())
}
}
if file == nil {
t.Errorf("got nil File; want actual file")
}
if file.Body == nil {
t.Fatalf("got nil Body; want actual body")
}
attrs, diags := file.Body.JustAttributes()
if len(diags) != 0 {
t.Errorf("got %d diagnostics on decode; want 0", len(diags))
for _, diag := range diags {
t.Logf("- %s", diag.Error())
}
}
val, diags := attrs["greeting"].Expr.Value(&zcl.EvalContext{})
if len(diags) != 0 {
t.Errorf("got %d diagnostics on eval; want 0", len(diags))
for _, diag := range diags {
t.Logf("- %s", diag.Error())
}
}
if !val.RawEquals(cty.StringVal("hello world")) {
t.Errorf("wrong result %#v; want %#v", val, cty.StringVal("hello world"))
}
}
func TestParseTemplateUnwrap(t *testing.T) {
src := `{"greeting": "${true}"}`
file, diags := Parse([]byte(src), "")
if len(diags) != 0 {
t.Errorf("got %d diagnostics on parse; want 0", len(diags))
for _, diag := range diags {
t.Logf("- %s", diag.Error())
}
}
if file == nil {
t.Errorf("got nil File; want actual file")
}
if file.Body == nil {
t.Fatalf("got nil Body; want actual body")
}
attrs, diags := file.Body.JustAttributes()
if len(diags) != 0 {
t.Errorf("got %d diagnostics on decode; want 0", len(diags))
for _, diag := range diags {
t.Logf("- %s", diag.Error())
}
}
val, diags := attrs["greeting"].Expr.Value(&zcl.EvalContext{})
if len(diags) != 0 {
t.Errorf("got %d diagnostics on eval; want 0", len(diags))
for _, diag := range diags {
t.Logf("- %s", diag.Error())
}
}
if !val.RawEquals(cty.True) {
t.Errorf("wrong result %#v; want %#v", val, cty.True)
}
}
func TestParseTemplateWithHIL(t *testing.T) {
src := `{"greeting": "hello ${\"world\"}"}`
file, diags := ParseWithHIL([]byte(src), "")

View File

@ -6,6 +6,7 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-zcl/zcl"
"github.com/zclconf/go-zcl/zcl/hclhil"
"github.com/zclconf/go-zcl/zcl/zclsyntax"
)
// body is the implementation of "Body" used for files processed with the JSON
@ -255,9 +256,6 @@ func (b *body) unpackBlock(v node, typeName string, typeRange *zcl.Range, labels
}
func (e *expression) Value(ctx *zcl.EvalContext) (cty.Value, zcl.Diagnostics) {
// TEMP: Since we've not yet implemented the zcl native template language
// parser, for the moment we'll support only literal values here.
switch v := e.src.(type) {
case *stringVal:
if e.useHIL && ctx != nil {
@ -281,6 +279,35 @@ func (e *expression) Value(ctx *zcl.EvalContext) (cty.Value, zcl.Diagnostics) {
return val, diags
}
if ctx != nil {
// Parse string contents as a zcl native language expression.
// We only do this if we have a context, so passing a nil context
// is how the caller specifies that interpolations are not allowed
// and that the string should just be returned verbatim.
templateSrc := v.Value
expr, diags := zclsyntax.ParseTemplate(
[]byte(templateSrc),
v.SrcRange.Filename,
// This won't produce _exactly_ the right result, since
// the zclsyntax parser can't "see" any escapes we removed
// while parsing JSON, but it's better than nothing.
zcl.Pos{
Line: v.SrcRange.Start.Line,
// skip over the opening quote mark
Byte: v.SrcRange.Start.Byte + 1,
Column: v.SrcRange.Start.Column + 1,
},
)
if diags.HasErrors() {
return cty.DynamicVal, diags
}
val, evalDiags := expr.Value(ctx)
diags = append(diags, evalDiags...)
return val, diags
}
// FIXME: Once the native zcl template language parser is implemented,
// parse string values as templates and evaluate them.
return cty.StringVal(v.Value), nil