aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/token.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/token.go')
-rw-r--r--vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/token.go272
1 files changed, 272 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/token.go b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/token.go
new file mode 100644
index 0000000..bcaa15f
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/token.go
@@ -0,0 +1,272 @@
1package hclsyntax
2
3import (
4 "fmt"
5
6 "github.com/apparentlymart/go-textseg/textseg"
7 "github.com/hashicorp/hcl2/hcl"
8)
9
10// Token represents a sequence of bytes from some HCL code that has been
11// tagged with a type and its range within the source file.
12type Token struct {
13 Type TokenType
14 Bytes []byte
15 Range hcl.Range
16}
17
18// Tokens is a slice of Token.
19type Tokens []Token
20
21// TokenType is an enumeration used for the Type field on Token.
22type TokenType rune
23
24const (
25 // Single-character tokens are represented by their own character, for
26 // convenience in producing these within the scanner. However, the values
27 // are otherwise arbitrary and just intended to be mnemonic for humans
28 // who might see them in debug output.
29
30 TokenOBrace TokenType = '{'
31 TokenCBrace TokenType = '}'
32 TokenOBrack TokenType = '['
33 TokenCBrack TokenType = ']'
34 TokenOParen TokenType = '('
35 TokenCParen TokenType = ')'
36 TokenOQuote TokenType = '«'
37 TokenCQuote TokenType = '»'
38 TokenOHeredoc TokenType = 'H'
39 TokenCHeredoc TokenType = 'h'
40
41 TokenStar TokenType = '*'
42 TokenSlash TokenType = '/'
43 TokenPlus TokenType = '+'
44 TokenMinus TokenType = '-'
45 TokenPercent TokenType = '%'
46
47 TokenEqual TokenType = '='
48 TokenEqualOp TokenType = '≔'
49 TokenNotEqual TokenType = '≠'
50 TokenLessThan TokenType = '<'
51 TokenLessThanEq TokenType = '≤'
52 TokenGreaterThan TokenType = '>'
53 TokenGreaterThanEq TokenType = '≥'
54
55 TokenAnd TokenType = '∧'
56 TokenOr TokenType = '∨'
57 TokenBang TokenType = '!'
58
59 TokenDot TokenType = '.'
60 TokenComma TokenType = ','
61
62 TokenEllipsis TokenType = '…'
63 TokenFatArrow TokenType = '⇒'
64
65 TokenQuestion TokenType = '?'
66 TokenColon TokenType = ':'
67
68 TokenTemplateInterp TokenType = '∫'
69 TokenTemplateControl TokenType = 'λ'
70 TokenTemplateSeqEnd TokenType = '∎'
71
72 TokenQuotedLit TokenType = 'Q' // might contain backslash escapes
73 TokenStringLit TokenType = 'S' // cannot contain backslash escapes
74 TokenNumberLit TokenType = 'N'
75 TokenIdent TokenType = 'I'
76
77 TokenComment TokenType = 'C'
78
79 TokenNewline TokenType = '\n'
80 TokenEOF TokenType = '␄'
81
82 // The rest are not used in the language but recognized by the scanner so
83 // we can generate good diagnostics in the parser when users try to write
84 // things that might work in other languages they are familiar with, or
85 // simply make incorrect assumptions about the HCL language.
86
87 TokenBitwiseAnd TokenType = '&'
88 TokenBitwiseOr TokenType = '|'
89 TokenBitwiseNot TokenType = '~'
90 TokenBitwiseXor TokenType = '^'
91 TokenStarStar TokenType = '➚'
92 TokenBacktick TokenType = '`'
93 TokenSemicolon TokenType = ';'
94 TokenTabs TokenType = '␉'
95 TokenInvalid TokenType = '�'
96 TokenBadUTF8 TokenType = '💩'
97
98 // TokenNil is a placeholder for when a token is required but none is
99 // available, e.g. when reporting errors. The scanner will never produce
100 // this as part of a token stream.
101 TokenNil TokenType = '\x00'
102)
103
104func (t TokenType) GoString() string {
105 return fmt.Sprintf("hclsyntax.%s", t.String())
106}
107
108type scanMode int
109
110const (
111 scanNormal scanMode = iota
112 scanTemplate
113 scanIdentOnly
114)
115
116type tokenAccum struct {
117 Filename string
118 Bytes []byte
119 Pos hcl.Pos
120 Tokens []Token
121}
122
123func (f *tokenAccum) emitToken(ty TokenType, startOfs, endOfs int) {
124 // Walk through our buffer to figure out how much we need to adjust
125 // the start pos to get our end pos.
126
127 start := f.Pos
128 start.Column += startOfs - f.Pos.Byte // Safe because only ASCII spaces can be in the offset
129 start.Byte = startOfs
130
131 end := start
132 end.Byte = endOfs
133 b := f.Bytes[startOfs:endOfs]
134 for len(b) > 0 {
135 advance, seq, _ := textseg.ScanGraphemeClusters(b, true)
136 if (len(seq) == 1 && seq[0] == '\n') || (len(seq) == 2 && seq[0] == '\r' && seq[1] == '\n') {
137 end.Line++
138 end.Column = 1
139 } else {
140 end.Column++
141 }
142 b = b[advance:]
143 }
144
145 f.Pos = end
146
147 f.Tokens = append(f.Tokens, Token{
148 Type: ty,
149 Bytes: f.Bytes[startOfs:endOfs],
150 Range: hcl.Range{
151 Filename: f.Filename,
152 Start: start,
153 End: end,
154 },
155 })
156}
157
158type heredocInProgress struct {
159 Marker []byte
160 StartOfLine bool
161}
162
163// checkInvalidTokens does a simple pass across the given tokens and generates
164// diagnostics for tokens that should _never_ appear in HCL source. This
165// is intended to avoid the need for the parser to have special support
166// for them all over.
167//
168// Returns a diagnostics with no errors if everything seems acceptable.
169// Otherwise, returns zero or more error diagnostics, though tries to limit
170// repetition of the same information.
171func checkInvalidTokens(tokens Tokens) hcl.Diagnostics {
172 var diags hcl.Diagnostics
173
174 toldBitwise := 0
175 toldExponent := 0
176 toldBacktick := 0
177 toldSemicolon := 0
178 toldTabs := 0
179 toldBadUTF8 := 0
180
181 for _, tok := range tokens {
182 switch tok.Type {
183 case TokenBitwiseAnd, TokenBitwiseOr, TokenBitwiseXor, TokenBitwiseNot:
184 if toldBitwise < 4 {
185 var suggestion string
186 switch tok.Type {
187 case TokenBitwiseAnd:
188 suggestion = " Did you mean boolean AND (\"&&\")?"
189 case TokenBitwiseOr:
190 suggestion = " Did you mean boolean OR (\"&&\")?"
191 case TokenBitwiseNot:
192 suggestion = " Did you mean boolean NOT (\"!\")?"
193 }
194
195 diags = append(diags, &hcl.Diagnostic{
196 Severity: hcl.DiagError,
197 Summary: "Unsupported operator",
198 Detail: fmt.Sprintf("Bitwise operators are not supported.%s", suggestion),
199 Subject: &tok.Range,
200 })
201 toldBitwise++
202 }
203 case TokenStarStar:
204 if toldExponent < 1 {
205 diags = append(diags, &hcl.Diagnostic{
206 Severity: hcl.DiagError,
207 Summary: "Unsupported operator",
208 Detail: "\"**\" is not a supported operator. Exponentiation is not supported as an operator.",
209 Subject: &tok.Range,
210 })
211
212 toldExponent++
213 }
214 case TokenBacktick:
215 // Only report for alternating (even) backticks, so we won't report both start and ends of the same
216 // backtick-quoted string.
217 if toldExponent < 4 && (toldExponent%2) == 0 {
218 diags = append(diags, &hcl.Diagnostic{
219 Severity: hcl.DiagError,
220 Summary: "Invalid character",
221 Detail: "The \"`\" character is not valid. To create a multi-line string, use the \"heredoc\" syntax, like \"<<EOT\".",
222 Subject: &tok.Range,
223 })
224
225 toldBacktick++
226 }
227 case TokenSemicolon:
228 if toldSemicolon < 1 {
229 diags = append(diags, &hcl.Diagnostic{
230 Severity: hcl.DiagError,
231 Summary: "Invalid character",
232 Detail: "The \";\" character is not valid. Use newlines to separate attributes and blocks, and commas to separate items in collection values.",
233 Subject: &tok.Range,
234 })
235
236 toldSemicolon++
237 }
238 case TokenTabs:
239 if toldTabs < 1 {
240 diags = append(diags, &hcl.Diagnostic{
241 Severity: hcl.DiagError,
242 Summary: "Invalid character",
243 Detail: "Tab characters may not be used. The recommended indentation style is two spaces per indent.",
244 Subject: &tok.Range,
245 })
246
247 toldTabs++
248 }
249 case TokenBadUTF8:
250 if toldBadUTF8 < 1 {
251 diags = append(diags, &hcl.Diagnostic{
252 Severity: hcl.DiagError,
253 Summary: "Invalid character encoding",
254 Detail: "All input files must be UTF-8 encoded. Ensure that UTF-8 encoding is selected in your editor.",
255 Subject: &tok.Range,
256 })
257
258 toldBadUTF8++
259 }
260 case TokenInvalid:
261 diags = append(diags, &hcl.Diagnostic{
262 Severity: hcl.DiagError,
263 Summary: "Invalid character",
264 Detail: "This character is not used within the language.",
265 Subject: &tok.Range,
266 })
267
268 toldTabs++
269 }
270 }
271 return diags
272}