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  }