github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/jobspec2/addrs/parse_ref.go (about)

     1  package addrs
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/hcl/v2"
     7  )
     8  
     9  // Reference describes a reference to an address with source location
    10  // information.
    11  type Reference struct {
    12  	Subject     Referenceable
    13  	SourceRange hcl.Range
    14  	Remaining   hcl.Traversal
    15  }
    16  
    17  // ParseRef attempts to extract a referencable address from the prefix of the
    18  // given traversal, which must be an absolute traversal or this function
    19  // will panic.
    20  //
    21  // If no error diagnostics are returned, the returned reference includes the
    22  // address that was extracted, the source range it was extracted from, and any
    23  // remaining relative traversal that was not consumed as part of the
    24  // reference.
    25  //
    26  // If error diagnostics are returned then the Reference value is invalid and
    27  // must not be used.
    28  func ParseRef(traversal hcl.Traversal) (*Reference, hcl.Diagnostics) {
    29  	ref, diags := parseRef(traversal)
    30  
    31  	// Normalize a little to make life easier for callers.
    32  	if ref != nil {
    33  		if len(ref.Remaining) == 0 {
    34  			ref.Remaining = nil
    35  		}
    36  	}
    37  
    38  	return ref, diags
    39  }
    40  
    41  func parseRef(traversal hcl.Traversal) (*Reference, hcl.Diagnostics) {
    42  	var diags hcl.Diagnostics
    43  
    44  	root := traversal.RootName()
    45  	rootRange := traversal[0].SourceRange()
    46  
    47  	switch root {
    48  
    49  	case "var":
    50  		name, rng, remain, diags := parseSingleAttrRef(traversal)
    51  		return &Reference{
    52  			Subject:     InputVariable{Name: name},
    53  			SourceRange: rng,
    54  			Remaining:   remain,
    55  		}, diags
    56  
    57  	default:
    58  		diags = append(diags, &hcl.Diagnostic{
    59  			Severity: hcl.DiagError,
    60  			Summary:  "Unhandled reference type",
    61  			Detail:   `Currently parseRef can only parse "var" references.`,
    62  			Subject:  &rootRange,
    63  		})
    64  	}
    65  	return nil, diags
    66  }
    67  
    68  func parseSingleAttrRef(traversal hcl.Traversal) (string, hcl.Range, hcl.Traversal, hcl.Diagnostics) {
    69  	var diags hcl.Diagnostics
    70  
    71  	root := traversal.RootName()
    72  	rootRange := traversal[0].SourceRange()
    73  
    74  	if len(traversal) < 2 {
    75  		diags = append(diags, &hcl.Diagnostic{
    76  			Severity: hcl.DiagError,
    77  			Summary:  "Invalid reference",
    78  			Detail:   fmt.Sprintf("The %q object cannot be accessed directly. Instead, access one of its attributes.", root),
    79  			Subject:  &rootRange,
    80  		})
    81  		return "", hcl.Range{}, nil, diags
    82  	}
    83  	if attrTrav, ok := traversal[1].(hcl.TraverseAttr); ok {
    84  		return attrTrav.Name, hcl.RangeBetween(rootRange, attrTrav.SrcRange), traversal[2:], diags
    85  	}
    86  	diags = diags.Append(&hcl.Diagnostic{
    87  		Severity: hcl.DiagError,
    88  		Summary:  "Invalid reference",
    89  		Detail:   fmt.Sprintf("The %q object does not support this operation.", root),
    90  		Subject:  traversal[1].SourceRange().Ptr(),
    91  	})
    92  	return "", hcl.Range{}, nil, diags
    93  }