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