func ParseAndDecodeVarFile(hclContents string, filename string, out interface{}) (err error) {
	defer func() {
		if recovered := recover(); recovered != nil {
			err = errors.WithStackTrace(PanicWhileParsingConfig{RecoveredValue: recovered, ConfigFile: filename})
		}
	}()
	parser := hclparse.NewParser()
	file, err := parseHcl(parser, hclContents, filename)
	if err != nil {
		return err
	}
	attrs, hclDiags := file.Body.JustAttributes()
	if hclDiags != nil && hclDiags.HasErrors() {
		return hclDiags
	}
	valMap := map[string]cty.Value{}
	for name, attr := range attrs {
		val, hclDiags := attr.Expr.Value(nil)  
		if hclDiags != nil && hclDiags.HasErrors() {
			return hclDiags
		}
		valMap[name] = val
	}
	ctyVal, err := convertValuesMapToCtyVal(valMap)
	if err != nil {
		return err
	}
	typedOut, hasType := out.(*map[string]interface{})
	if hasType {
		genericMap, err := parseCtyValueToMap(ctyVal)
		if err != nil {
			return err
		}
		*typedOut = genericMap
		return nil
	}
	return gocty.FromCtyValue(ctyVal, out)
}
ParseAndDecodeVarFile uses the HCL2 parser to parse the given varfile string into an HCL file body, and then decode it
into the provided output.
package config
import (
	"path/filepath"
	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/options"
	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/gohcl"
	"github.com/hashicorp/hcl/v2/hclparse"
	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/gocty"
)
func parseHcl(parser *hclparse.Parser, hcl string, filename string) (file *hcl.File, err error) {
	defer func() {
		if recovered := recover(); recovered != nil {
			err = errors.WithStackTrace(PanicWhileParsingConfig{RecoveredValue: recovered, ConfigFile: filename})
		}
	}()
	if filepath.Ext(filename) == ".json" {
		file, parseDiagnostics := parser.ParseJSON([]byte(hcl), filename)
		if parseDiagnostics != nil && parseDiagnostics.HasErrors() {
			return nil, parseDiagnostics
		}
		return file, nil
	}
	file, parseDiagnostics := parser.ParseHCL([]byte(hcl), filename)
	if parseDiagnostics != nil && parseDiagnostics.HasErrors() {
		return nil, parseDiagnostics
	}
	return file, nil
}
func decodeHcl(
	file *hcl.File,
	filename string,
	out interface{},
	terragruntOptions *options.TerragruntOptions,
	extensions EvalContextExtensions,
) (err error) {
	defer func() {
		if recovered := recover(); recovered != nil {
			err = errors.WithStackTrace(PanicWhileParsingConfig{RecoveredValue: recovered, ConfigFile: filename})
		}
	}()
	updatedBytes, isUpdated, err := updateBareIncludeBlock(file, filename)
	if err != nil {
		return err
	}
	if isUpdated {
		file, err = parseHcl(hclparse.NewParser(), string(updatedBytes), filename)
		if err != nil {
			return err
		}
	}
	evalContext, err := CreateTerragruntEvalContext(filename, terragruntOptions, extensions)
	if err != nil {
		return err
	}
	decodeDiagnostics := gohcl.DecodeBody(file.Body, evalContext, out)
	if decodeDiagnostics != nil && decodeDiagnostics.HasErrors() {
		return decodeDiagnostics
	}
	return nil
}