func (e *expression) AsTraversal() hcl.Traversal {
	switch v := e.src.(type) {
	case *stringVal:
		traversal, diags := hclsyntax.ParseTraversalAbs([]byte(v.Value), v.SrcRange.Filename, v.SrcRange.Start)
		if diags.HasErrors() {
			return nil
		}
		return traversal
	default:
		return nil
	}
}
Implementation for hcl.AbsTraversalForExpr.
package json
import (
	"fmt"
	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclsyntax"
	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/convert"
)
type body struct {
	val node
	hiddenAttrs map[string]struct{}
}
type expression struct {
	src node
}
func (b *body) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
	content, newBody, diags := b.PartialContent(schema)
	hiddenAttrs := newBody.(*body).hiddenAttrs
	var nameSuggestions []string
	for _, attrS := range schema.Attributes {
		if _, ok := hiddenAttrs[attrS.Name]; !ok {
			nameSuggestions = append(nameSuggestions, attrS.Name)
		}
	}
	for _, blockS := range schema.Blocks {
		nameSuggestions = append(nameSuggestions, blockS.Type)
	}
	jsonAttrs, attrDiags := b.collectDeepAttrs(b.val, nil)
	diags = append(diags, attrDiags...)
	for _, attr := range jsonAttrs {
		k := attr.Name
		if k == "//" {
			continue
		}
		if _, ok := hiddenAttrs[k]; !ok {
			suggestion := nameSuggestion(k, nameSuggestions)
			if suggestion != "" {
				suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
			}
			diags = append(diags, &hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Extraneous JSON object property",
				Detail:   fmt.Sprintf("No argument or block type is named %q.%s", k, suggestion),
				Subject:  &attr.NameRange,
				Context:  attr.Range().Ptr(),
			})
		}
	}
	return content, diags
}
func (b *body) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
	var diags hcl.Diagnostics
	jsonAttrs, attrDiags := b.collectDeepAttrs(b.val, nil)
	diags = append(diags, attrDiags...)
	usedNames := map[string]struct{}{}
	if b.hiddenAttrs != nil {
		for k := range b.hiddenAttrs {
			usedNames[k] = struct{}{}
		}
	}
	content := &hcl.BodyContent{
		Attributes: map[string]*hcl.Attribute{},
		Blocks:     nil,
		MissingItemRange: b.MissingItemRange(),
	}
	attrSchemas := map[string]hcl.AttributeSchema{}
	blockSchemas := map[string]hcl.BlockHeaderSchema{}
	for _, attrS := range schema.Attributes {
		attrSchemas[attrS.Name] = attrS
	}
	for _, blockS := range schema.Blocks {
		blockSchemas[blockS.Type] = blockS
	}
	for _, jsonAttr := range jsonAttrs {
		attrName := jsonAttr.Name
		if _, used := b.hiddenAttrs[attrName]; used {
			continue
		}
		if attrS, defined := attrSchemas[attrName]; defined {
			if existing, exists := content.Attributes[attrName]; exists {
				diags = append(diags, &hcl.Diagnostic{
					Severity: hcl.DiagError,
					Summary:  "Duplicate argument",
					Detail:   fmt.Sprintf("The argument %q was already set at %s.", attrName, existing.Range),
					Subject:  &jsonAttr.NameRange,
					Context:  jsonAttr.Range().Ptr(),
				})
				continue
			}
			content.Attributes[attrS.Name] = &hcl.Attribute{
				Name:      attrS.Name,
				Expr:      &expression{src: jsonAttr.Value},
				Range:     hcl.RangeBetween(jsonAttr.NameRange, jsonAttr.Value.Range()),
				NameRange: jsonAttr.NameRange,
			}
			usedNames[attrName] = struct{}{}
		} else if blockS, defined := blockSchemas[attrName]; defined {
			bv := jsonAttr.Value
			blockDiags := b.unpackBlock(bv, blockS.Type, &jsonAttr.NameRange, blockS.LabelNames, nil, nil, &content.Blocks)
			diags = append(diags, blockDiags...)
			usedNames[attrName] = struct{}{}
		}
	}
	for _, attrS := range schema.Attributes {
		if !attrS.Required {
			continue
		}
		if _, defined := content.Attributes[attrS.Name]; !defined {
			diags = append(diags, &hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Missing required argument",
				Detail:   fmt.Sprintf("The argument %q is required, but no definition was found.", attrS.Name),
				Subject:  b.MissingItemRange().Ptr(),
			})
		}
	}
	unusedBody := &body{
		val:         b.val,
		hiddenAttrs: usedNames,
	}
	return content, unusedBody, diags
}
func (b *body) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
	var diags hcl.Diagnostics
	attrs := make(map[string]*hcl.Attribute)
	obj, ok := b.val.(*objectVal)
	if !ok {
		diags = append(diags, &hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Incorrect JSON value type",
			Detail:   "A JSON object is required here, setting the arguments for this block.",
			Subject:  b.val.StartRange().Ptr(),
		})
		return attrs, diags
	}
	for _, jsonAttr := range obj.Attrs {
		name := jsonAttr.Name
		if name == "//" {
			continue
		}
		if _, hidden := b.hiddenAttrs[name]; hidden {
			continue
		}
		if existing, exists := attrs[name]; exists {
			diags = append(diags, &hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Duplicate attribute definition",
				Detail:   fmt.Sprintf("The argument %q was already set at %s.", name, existing.Range),
				Subject:  &jsonAttr.NameRange,
			})
			continue
		}
		attrs[name] = &hcl.Attribute{
			Name:      name,
			Expr:      &expression{src: jsonAttr.Value},
			Range:     hcl.RangeBetween(jsonAttr.NameRange, jsonAttr.Value.Range()),
			NameRange: jsonAttr.NameRange,
		}
	}
	return attrs, diags
}
func (b *body) MissingItemRange() hcl.Range {
	switch tv := b.val.(type) {
	case *objectVal:
		return tv.CloseRange
	case *arrayVal:
		return tv.OpenRange
	default:
		return tv.StartRange()
	}
}
func (b *body) unpackBlock(v node, typeName string, typeRange *hcl.Range, labelsLeft []string, labelsUsed []string, labelRanges []hcl.Range, blocks *hcl.Blocks) (diags hcl.Diagnostics) {
	if len(labelsLeft) > 0 {
		labelName := labelsLeft[0]
		jsonAttrs, attrDiags := b.collectDeepAttrs(v, &labelName)
		diags = append(diags, attrDiags...)
		if len(jsonAttrs) == 0 {
			diags = diags.Append(&hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Missing block label",
				Detail:   fmt.Sprintf("At least one object property is required, whose name represents the %s block's %s.", typeName, labelName),
				Subject:  v.StartRange().Ptr(),
			})
			return
		}
		labelsUsed := append(labelsUsed, "")
		labelRanges := append(labelRanges, hcl.Range{})
		for _, p := range jsonAttrs {
			pk := p.Name
			labelsUsed[len(labelsUsed)-1] = pk
			labelRanges[len(labelRanges)-1] = p.NameRange
			diags = append(diags, b.unpackBlock(p.Value, typeName, typeRange, labelsLeft[1:], labelsUsed, labelRanges, blocks)...)
		}
		return
	}
	labels := make([]string, len(labelsUsed))
	copy(labels, labelsUsed)
	labelR := make([]hcl.Range, len(labelRanges))
	copy(labelR, labelRanges)
	switch tv := v.(type) {
	case *nullVal:
		return
	case *objectVal:
		*blocks = append(*blocks, &hcl.Block{
			Type:   typeName,
			Labels: labels,
			Body: &body{
				val: tv,
			},
			DefRange:    tv.OpenRange,
			TypeRange:   *typeRange,
			LabelRanges: labelR,
		})
	case *arrayVal:
		for _, av := range tv.Values {
			*blocks = append(*blocks, &hcl.Block{
				Type:   typeName,
				Labels: labels,
				Body: &body{
					val: av,  
				},
				DefRange:    tv.OpenRange,
				TypeRange:   *typeRange,
				LabelRanges: labelR,
			})
		}
	default:
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Incorrect JSON value type",
			Detail:   fmt.Sprintf("Either a JSON object or a JSON array is required, representing the contents of one or more %q blocks.", typeName),
			Subject:  v.StartRange().Ptr(),
		})
	}
	return
}
func (b *body) collectDeepAttrs(v node, labelName *string) ([]*objectAttr, hcl.Diagnostics) {
	var diags hcl.Diagnostics
	var attrs []*objectAttr
	switch tv := v.(type) {
	case *nullVal:
	case *objectVal:
		attrs = append(attrs, tv.Attrs...)
	case *arrayVal:
		for _, ev := range tv.Values {
			switch tev := ev.(type) {
			case *objectVal:
				attrs = append(attrs, tev.Attrs...)
			default:
				if labelName != nil {
					diags = append(diags, &hcl.Diagnostic{
						Severity: hcl.DiagError,
						Summary:  "Incorrect JSON value type",
						Detail:   fmt.Sprintf("A JSON object is required here, to specify %s labels for this block.", *labelName),
						Subject:  ev.StartRange().Ptr(),
					})
				} else {
					diags = append(diags, &hcl.Diagnostic{
						Severity: hcl.DiagError,
						Summary:  "Incorrect JSON value type",
						Detail:   "A JSON object is required here, to define arguments and child blocks.",
						Subject:  ev.StartRange().Ptr(),
					})
				}
			}
		}
	default:
		if labelName != nil {
			diags = append(diags, &hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Incorrect JSON value type",
				Detail:   fmt.Sprintf("Either a JSON object or JSON array of objects is required here, to specify %s labels for this block.", *labelName),
				Subject:  v.StartRange().Ptr(),
			})
		} else {
			diags = append(diags, &hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Incorrect JSON value type",
				Detail:   "Either a JSON object or JSON array of objects is required here, to define arguments and child blocks.",
				Subject:  v.StartRange().Ptr(),
			})
		}
	}
	return attrs, diags
}
func (e *expression) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
	switch v := e.src.(type) {
	case *stringVal:
		if ctx != nil {
			templateSrc := v.Value
			expr, diags := hclsyntax.ParseTemplate(
				[]byte(templateSrc),
				v.SrcRange.Filename,
				hcl.Pos{
					Line: v.SrcRange.Start.Line,
					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
		}
		return cty.StringVal(v.Value), nil
	case *numberVal:
		return cty.NumberVal(v.Value), nil
	case *booleanVal:
		return cty.BoolVal(v.Value), nil
	case *arrayVal:
		var diags hcl.Diagnostics
		vals := []cty.Value{}
		for _, jsonVal := range v.Values {
			val, valDiags := (&expression{src: jsonVal}).Value(ctx)
			vals = append(vals, val)
			diags = append(diags, valDiags...)
		}
		return cty.TupleVal(vals), diags
	case *objectVal:
		var diags hcl.Diagnostics
		attrs := map[string]cty.Value{}
		attrRanges := map[string]hcl.Range{}
		known := true
		for _, jsonAttr := range v.Attrs {
			name, nameDiags := (&expression{src: &stringVal{
				Value:    jsonAttr.Name,
				SrcRange: jsonAttr.NameRange,
			}}).Value(ctx)
			valExpr := &expression{src: jsonAttr.Value}
			val, valDiags := valExpr.Value(ctx)
			diags = append(diags, nameDiags...)
			diags = append(diags, valDiags...)
			var err error
			name, err = convert.Convert(name, cty.String)
			if err != nil {
				diags = append(diags, &hcl.Diagnostic{
					Severity:    hcl.DiagError,
					Summary:     "Invalid object key expression",
					Detail:      fmt.Sprintf("Cannot use this expression as an object key: %s.", err),
					Subject:     &jsonAttr.NameRange,
					Expression:  valExpr,
					EvalContext: ctx,
				})
				continue
			}
			if name.IsNull() {
				diags = append(diags, &hcl.Diagnostic{
					Severity:    hcl.DiagError,
					Summary:     "Invalid object key expression",
					Detail:      "Cannot use null value as an object key.",
					Subject:     &jsonAttr.NameRange,
					Expression:  valExpr,
					EvalContext: ctx,
				})
				continue
			}
			if !name.IsKnown() {
				known = false
				continue
			}
			nameStr := name.AsString()
			if _, defined := attrs[nameStr]; defined {
				diags = append(diags, &hcl.Diagnostic{
					Severity:    hcl.DiagError,
					Summary:     "Duplicate object attribute",
					Detail:      fmt.Sprintf("An attribute named %q was already defined at %s.", nameStr, attrRanges[nameStr]),
					Subject:     &jsonAttr.NameRange,
					Expression:  e,
					EvalContext: ctx,
				})
				continue
			}
			attrs[nameStr] = val
			attrRanges[nameStr] = jsonAttr.NameRange
		}
		if !known {
			return cty.DynamicVal, diags
		}
		return cty.ObjectVal(attrs), diags
	case *nullVal:
		return cty.NullVal(cty.DynamicPseudoType), nil
	default:
		return cty.DynamicVal, nil
	}
}
func (e *expression) Variables() []hcl.Traversal {
	var vars []hcl.Traversal
	switch v := e.src.(type) {
	case *stringVal:
		templateSrc := v.Value
		expr, diags := hclsyntax.ParseTemplate(
			[]byte(templateSrc),
			v.SrcRange.Filename,
			hcl.Pos{
				Line: v.SrcRange.Start.Line,
				Byte:   v.SrcRange.Start.Byte + 1,
				Column: v.SrcRange.Start.Column + 1,
			},
		)
		if diags.HasErrors() {
			return vars
		}
		return expr.Variables()
	case *arrayVal:
		for _, jsonVal := range v.Values {
			vars = append(vars, (&expression{src: jsonVal}).Variables()...)
		}
	case *objectVal:
		for _, jsonAttr := range v.Attrs {
			keyExpr := &stringVal{  
				Value:    jsonAttr.Name,
				SrcRange: jsonAttr.NameRange,
			}
			vars = append(vars, (&expression{src: keyExpr}).Variables()...)
			vars = append(vars, (&expression{src: jsonAttr.Value}).Variables()...)
		}
	}
	return vars
}
func (e *expression) Range() hcl.Range {
	return e.src.Range()
}
func (e *expression) StartRange() hcl.Range {
	return e.src.StartRange()
}