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