diff options
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/parser_traversal.go')
-rw-r--r-- | vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/parser_traversal.go | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/parser_traversal.go b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/parser_traversal.go new file mode 100644 index 0000000..2ff3ed6 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/parser_traversal.go | |||
@@ -0,0 +1,159 @@ | |||
1 | package hclsyntax | ||
2 | |||
3 | import ( | ||
4 | "github.com/hashicorp/hcl2/hcl" | ||
5 | "github.com/zclconf/go-cty/cty" | ||
6 | ) | ||
7 | |||
8 | // ParseTraversalAbs parses an absolute traversal that is assumed to consume | ||
9 | // all of the remaining tokens in the peeker. The usual parser recovery | ||
10 | // behavior is not supported here because traversals are not expected to | ||
11 | // be parsed as part of a larger program. | ||
12 | func (p *parser) ParseTraversalAbs() (hcl.Traversal, hcl.Diagnostics) { | ||
13 | var ret hcl.Traversal | ||
14 | var diags hcl.Diagnostics | ||
15 | |||
16 | // Absolute traversal must always begin with a variable name | ||
17 | varTok := p.Read() | ||
18 | if varTok.Type != TokenIdent { | ||
19 | diags = append(diags, &hcl.Diagnostic{ | ||
20 | Severity: hcl.DiagError, | ||
21 | Summary: "Variable name required", | ||
22 | Detail: "Must begin with a variable name.", | ||
23 | Subject: &varTok.Range, | ||
24 | }) | ||
25 | return ret, diags | ||
26 | } | ||
27 | |||
28 | varName := string(varTok.Bytes) | ||
29 | ret = append(ret, hcl.TraverseRoot{ | ||
30 | Name: varName, | ||
31 | SrcRange: varTok.Range, | ||
32 | }) | ||
33 | |||
34 | for { | ||
35 | next := p.Peek() | ||
36 | |||
37 | if next.Type == TokenEOF { | ||
38 | return ret, diags | ||
39 | } | ||
40 | |||
41 | switch next.Type { | ||
42 | case TokenDot: | ||
43 | // Attribute access | ||
44 | dot := p.Read() // eat dot | ||
45 | nameTok := p.Read() | ||
46 | if nameTok.Type != TokenIdent { | ||
47 | if nameTok.Type == TokenStar { | ||
48 | diags = append(diags, &hcl.Diagnostic{ | ||
49 | Severity: hcl.DiagError, | ||
50 | Summary: "Attribute name required", | ||
51 | Detail: "Splat expressions (.*) may not be used here.", | ||
52 | Subject: &nameTok.Range, | ||
53 | Context: hcl.RangeBetween(varTok.Range, nameTok.Range).Ptr(), | ||
54 | }) | ||
55 | } else { | ||
56 | diags = append(diags, &hcl.Diagnostic{ | ||
57 | Severity: hcl.DiagError, | ||
58 | Summary: "Attribute name required", | ||
59 | Detail: "Dot must be followed by attribute name.", | ||
60 | Subject: &nameTok.Range, | ||
61 | Context: hcl.RangeBetween(varTok.Range, nameTok.Range).Ptr(), | ||
62 | }) | ||
63 | } | ||
64 | return ret, diags | ||
65 | } | ||
66 | |||
67 | attrName := string(nameTok.Bytes) | ||
68 | ret = append(ret, hcl.TraverseAttr{ | ||
69 | Name: attrName, | ||
70 | SrcRange: hcl.RangeBetween(dot.Range, nameTok.Range), | ||
71 | }) | ||
72 | case TokenOBrack: | ||
73 | // Index | ||
74 | open := p.Read() // eat open bracket | ||
75 | next := p.Peek() | ||
76 | |||
77 | switch next.Type { | ||
78 | case TokenNumberLit: | ||
79 | tok := p.Read() // eat number | ||
80 | numVal, numDiags := p.numberLitValue(tok) | ||
81 | diags = append(diags, numDiags...) | ||
82 | |||
83 | close := p.Read() | ||
84 | if close.Type != TokenCBrack { | ||
85 | diags = append(diags, &hcl.Diagnostic{ | ||
86 | Severity: hcl.DiagError, | ||
87 | Summary: "Unclosed index brackets", | ||
88 | Detail: "Index key must be followed by a closing bracket.", | ||
89 | Subject: &close.Range, | ||
90 | Context: hcl.RangeBetween(open.Range, close.Range).Ptr(), | ||
91 | }) | ||
92 | } | ||
93 | |||
94 | ret = append(ret, hcl.TraverseIndex{ | ||
95 | Key: numVal, | ||
96 | SrcRange: hcl.RangeBetween(open.Range, close.Range), | ||
97 | }) | ||
98 | |||
99 | if diags.HasErrors() { | ||
100 | return ret, diags | ||
101 | } | ||
102 | |||
103 | case TokenOQuote: | ||
104 | str, _, strDiags := p.parseQuotedStringLiteral() | ||
105 | diags = append(diags, strDiags...) | ||
106 | |||
107 | close := p.Read() | ||
108 | if close.Type != TokenCBrack { | ||
109 | diags = append(diags, &hcl.Diagnostic{ | ||
110 | Severity: hcl.DiagError, | ||
111 | Summary: "Unclosed index brackets", | ||
112 | Detail: "Index key must be followed by a closing bracket.", | ||
113 | Subject: &close.Range, | ||
114 | Context: hcl.RangeBetween(open.Range, close.Range).Ptr(), | ||
115 | }) | ||
116 | } | ||
117 | |||
118 | ret = append(ret, hcl.TraverseIndex{ | ||
119 | Key: cty.StringVal(str), | ||
120 | SrcRange: hcl.RangeBetween(open.Range, close.Range), | ||
121 | }) | ||
122 | |||
123 | if diags.HasErrors() { | ||
124 | return ret, diags | ||
125 | } | ||
126 | |||
127 | default: | ||
128 | if next.Type == TokenStar { | ||
129 | diags = append(diags, &hcl.Diagnostic{ | ||
130 | Severity: hcl.DiagError, | ||
131 | Summary: "Attribute name required", | ||
132 | Detail: "Splat expressions ([*]) may not be used here.", | ||
133 | Subject: &next.Range, | ||
134 | Context: hcl.RangeBetween(varTok.Range, next.Range).Ptr(), | ||
135 | }) | ||
136 | } else { | ||
137 | diags = append(diags, &hcl.Diagnostic{ | ||
138 | Severity: hcl.DiagError, | ||
139 | Summary: "Index value required", | ||
140 | Detail: "Index brackets must contain either a literal number or a literal string.", | ||
141 | Subject: &next.Range, | ||
142 | Context: hcl.RangeBetween(varTok.Range, next.Range).Ptr(), | ||
143 | }) | ||
144 | } | ||
145 | return ret, diags | ||
146 | } | ||
147 | |||
148 | default: | ||
149 | diags = append(diags, &hcl.Diagnostic{ | ||
150 | Severity: hcl.DiagError, | ||
151 | Summary: "Invalid character", | ||
152 | Detail: "Expected an attribute access or an index operator.", | ||
153 | Subject: &next.Range, | ||
154 | Context: hcl.RangeBetween(varTok.Range, next.Range).Ptr(), | ||
155 | }) | ||
156 | return ret, diags | ||
157 | } | ||
158 | } | ||
159 | } | ||