87 lines
1.9 KiB
Go
87 lines
1.9 KiB
Go
|
package zclsyntax
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/zclconf/go-cty/cty"
|
||
|
"github.com/zclconf/go-cty/cty/convert"
|
||
|
"github.com/zclconf/go-zcl/zcl"
|
||
|
)
|
||
|
|
||
|
type TemplateExpr struct {
|
||
|
Parts []Expression
|
||
|
|
||
|
SrcRange zcl.Range
|
||
|
}
|
||
|
|
||
|
func (e *TemplateExpr) walkChildNodes(w internalWalkFunc) {
|
||
|
for i, part := range e.Parts {
|
||
|
e.Parts[i] = w(part).(Expression)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *TemplateExpr) Value(ctx *zcl.EvalContext) (cty.Value, zcl.Diagnostics) {
|
||
|
buf := &bytes.Buffer{}
|
||
|
var diags zcl.Diagnostics
|
||
|
isKnown := true
|
||
|
|
||
|
for _, part := range e.Parts {
|
||
|
partVal, partDiags := part.Value(ctx)
|
||
|
diags = append(diags, partDiags...)
|
||
|
|
||
|
if partVal.IsNull() {
|
||
|
diags = append(diags, &zcl.Diagnostic{
|
||
|
Severity: zcl.DiagError,
|
||
|
Summary: "Invalid template interpolation value",
|
||
|
Detail: fmt.Sprintf(
|
||
|
"The expression result is null. Cannot include a null value in a string template.",
|
||
|
),
|
||
|
Subject: part.Range().Ptr(),
|
||
|
Context: &e.SrcRange,
|
||
|
})
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if !partVal.IsKnown() {
|
||
|
// If any part is unknown then the result as a whole must be
|
||
|
// unknown too. We'll keep on processing the rest of the parts
|
||
|
// anyway, because we want to still emit any diagnostics resulting
|
||
|
// from evaluating those.
|
||
|
isKnown = false
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
strVal, err := convert.Convert(partVal, cty.String)
|
||
|
if err != nil {
|
||
|
diags = append(diags, &zcl.Diagnostic{
|
||
|
Severity: zcl.DiagError,
|
||
|
Summary: "Invalid template interpolation value",
|
||
|
Detail: fmt.Sprintf(
|
||
|
"Cannot include the given value in a string template: %s.",
|
||
|
err.Error(),
|
||
|
),
|
||
|
Subject: part.Range().Ptr(),
|
||
|
Context: &e.SrcRange,
|
||
|
})
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
buf.WriteString(strVal.AsString())
|
||
|
}
|
||
|
|
||
|
if !isKnown {
|
||
|
return cty.UnknownVal(cty.String), diags
|
||
|
}
|
||
|
|
||
|
return cty.StringVal(buf.String()), diags
|
||
|
}
|
||
|
|
||
|
func (e *TemplateExpr) Range() zcl.Range {
|
||
|
return e.SrcRange
|
||
|
}
|
||
|
|
||
|
func (e *TemplateExpr) StartRange() zcl.Range {
|
||
|
return e.Parts[0].StartRange()
|
||
|
}
|