diff options
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcl/pos.go')
-rw-r--r-- | vendor/github.com/hashicorp/hcl2/hcl/pos.go | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/hcl/pos.go b/vendor/github.com/hashicorp/hcl2/hcl/pos.go new file mode 100644 index 0000000..1a4b329 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl2/hcl/pos.go | |||
@@ -0,0 +1,262 @@ | |||
1 | package hcl | ||
2 | |||
3 | import "fmt" | ||
4 | |||
5 | // Pos represents a single position in a source file, by addressing the | ||
6 | // start byte of a unicode character encoded in UTF-8. | ||
7 | // | ||
8 | // Pos is generally used only in the context of a Range, which then defines | ||
9 | // which source file the position is within. | ||
10 | type Pos struct { | ||
11 | // Line is the source code line where this position points. Lines are | ||
12 | // counted starting at 1 and incremented for each newline character | ||
13 | // encountered. | ||
14 | Line int | ||
15 | |||
16 | // Column is the source code column where this position points, in | ||
17 | // unicode characters, with counting starting at 1. | ||
18 | // | ||
19 | // Column counts characters as they appear visually, so for example a | ||
20 | // latin letter with a combining diacritic mark counts as one character. | ||
21 | // This is intended for rendering visual markers against source code in | ||
22 | // contexts where these diacritics would be rendered in a single character | ||
23 | // cell. Technically speaking, Column is counting grapheme clusters as | ||
24 | // used in unicode normalization. | ||
25 | Column int | ||
26 | |||
27 | // Byte is the byte offset into the file where the indicated character | ||
28 | // begins. This is a zero-based offset to the first byte of the first | ||
29 | // UTF-8 codepoint sequence in the character, and thus gives a position | ||
30 | // that can be resolved _without_ awareness of Unicode characters. | ||
31 | Byte int | ||
32 | } | ||
33 | |||
34 | // Range represents a span of characters between two positions in a source | ||
35 | // file. | ||
36 | // | ||
37 | // This struct is usually used by value in types that represent AST nodes, | ||
38 | // but by pointer in types that refer to the positions of other objects, | ||
39 | // such as in diagnostics. | ||
40 | type Range struct { | ||
41 | // Filename is the name of the file into which this range's positions | ||
42 | // point. | ||
43 | Filename string | ||
44 | |||
45 | // Start and End represent the bounds of this range. Start is inclusive | ||
46 | // and End is exclusive. | ||
47 | Start, End Pos | ||
48 | } | ||
49 | |||
50 | // RangeBetween returns a new range that spans from the beginning of the | ||
51 | // start range to the end of the end range. | ||
52 | // | ||
53 | // The result is meaningless if the two ranges do not belong to the same | ||
54 | // source file or if the end range appears before the start range. | ||
55 | func RangeBetween(start, end Range) Range { | ||
56 | return Range{ | ||
57 | Filename: start.Filename, | ||
58 | Start: start.Start, | ||
59 | End: end.End, | ||
60 | } | ||
61 | } | ||
62 | |||
63 | // RangeOver returns a new range that covers both of the given ranges and | ||
64 | // possibly additional content between them if the two ranges do not overlap. | ||
65 | // | ||
66 | // If either range is empty then it is ignored. The result is empty if both | ||
67 | // given ranges are empty. | ||
68 | // | ||
69 | // The result is meaningless if the two ranges to not belong to the same | ||
70 | // source file. | ||
71 | func RangeOver(a, b Range) Range { | ||
72 | if a.Empty() { | ||
73 | return b | ||
74 | } | ||
75 | if b.Empty() { | ||
76 | return a | ||
77 | } | ||
78 | |||
79 | var start, end Pos | ||
80 | if a.Start.Byte < b.Start.Byte { | ||
81 | start = a.Start | ||
82 | } else { | ||
83 | start = b.Start | ||
84 | } | ||
85 | if a.End.Byte > b.End.Byte { | ||
86 | end = a.End | ||
87 | } else { | ||
88 | end = b.End | ||
89 | } | ||
90 | return Range{ | ||
91 | Filename: a.Filename, | ||
92 | Start: start, | ||
93 | End: end, | ||
94 | } | ||
95 | } | ||
96 | |||
97 | // ContainsOffset returns true if and only if the given byte offset is within | ||
98 | // the receiving Range. | ||
99 | func (r Range) ContainsOffset(offset int) bool { | ||
100 | return offset >= r.Start.Byte && offset < r.End.Byte | ||
101 | } | ||
102 | |||
103 | // Ptr returns a pointer to a copy of the receiver. This is a convenience when | ||
104 | // ranges in places where pointers are required, such as in Diagnostic, but | ||
105 | // the range in question is returned from a method. Go would otherwise not | ||
106 | // allow one to take the address of a function call. | ||
107 | func (r Range) Ptr() *Range { | ||
108 | return &r | ||
109 | } | ||
110 | |||
111 | // String returns a compact string representation of the receiver. | ||
112 | // Callers should generally prefer to present a range more visually, | ||
113 | // e.g. via markers directly on the relevant portion of source code. | ||
114 | func (r Range) String() string { | ||
115 | if r.Start.Line == r.End.Line { | ||
116 | return fmt.Sprintf( | ||
117 | "%s:%d,%d-%d", | ||
118 | r.Filename, | ||
119 | r.Start.Line, r.Start.Column, | ||
120 | r.End.Column, | ||
121 | ) | ||
122 | } else { | ||
123 | return fmt.Sprintf( | ||
124 | "%s:%d,%d-%d,%d", | ||
125 | r.Filename, | ||
126 | r.Start.Line, r.Start.Column, | ||
127 | r.End.Line, r.End.Column, | ||
128 | ) | ||
129 | } | ||
130 | } | ||
131 | |||
132 | func (r Range) Empty() bool { | ||
133 | return r.Start.Byte == r.End.Byte | ||
134 | } | ||
135 | |||
136 | // CanSliceBytes returns true if SliceBytes could return an accurate | ||
137 | // sub-slice of the given slice. | ||
138 | // | ||
139 | // This effectively tests whether the start and end offsets of the range | ||
140 | // are within the bounds of the slice, and thus whether SliceBytes can be | ||
141 | // trusted to produce an accurate start and end position within that slice. | ||
142 | func (r Range) CanSliceBytes(b []byte) bool { | ||
143 | switch { | ||
144 | case r.Start.Byte < 0 || r.Start.Byte > len(b): | ||
145 | return false | ||
146 | case r.End.Byte < 0 || r.End.Byte > len(b): | ||
147 | return false | ||
148 | case r.End.Byte < r.Start.Byte: | ||
149 | return false | ||
150 | default: | ||
151 | return true | ||
152 | } | ||
153 | } | ||
154 | |||
155 | // SliceBytes returns a sub-slice of the given slice that is covered by the | ||
156 | // receiving range, assuming that the given slice is the source code of the | ||
157 | // file indicated by r.Filename. | ||
158 | // | ||
159 | // If the receiver refers to any byte offsets that are outside of the slice | ||
160 | // then the result is constrained to the overlapping portion only, to avoid | ||
161 | // a panic. Use CanSliceBytes to determine if the result is guaranteed to | ||
162 | // be an accurate span of the requested range. | ||
163 | func (r Range) SliceBytes(b []byte) []byte { | ||
164 | start := r.Start.Byte | ||
165 | end := r.End.Byte | ||
166 | if start < 0 { | ||
167 | start = 0 | ||
168 | } else if start > len(b) { | ||
169 | start = len(b) | ||
170 | } | ||
171 | if end < 0 { | ||
172 | end = 0 | ||
173 | } else if end > len(b) { | ||
174 | end = len(b) | ||
175 | } | ||
176 | if end < start { | ||
177 | end = start | ||
178 | } | ||
179 | return b[start:end] | ||
180 | } | ||
181 | |||
182 | // Overlaps returns true if the receiver and the other given range share any | ||
183 | // characters in common. | ||
184 | func (r Range) Overlaps(other Range) bool { | ||
185 | switch { | ||
186 | case r.Filename != other.Filename: | ||
187 | // If the ranges are in different files then they can't possibly overlap | ||
188 | return false | ||
189 | case r.Empty() || other.Empty(): | ||
190 | // Empty ranges can never overlap | ||
191 | return false | ||
192 | case r.ContainsOffset(other.Start.Byte) || r.ContainsOffset(other.End.Byte): | ||
193 | return true | ||
194 | case other.ContainsOffset(r.Start.Byte) || other.ContainsOffset(r.End.Byte): | ||
195 | return true | ||
196 | default: | ||
197 | return false | ||
198 | } | ||
199 | } | ||
200 | |||
201 | // Overlap finds a range that is either identical to or a sub-range of both | ||
202 | // the receiver and the other given range. It returns an empty range | ||
203 | // within the receiver if there is no overlap between the two ranges. | ||
204 | // | ||
205 | // A non-empty result is either identical to or a subset of the receiver. | ||
206 | func (r Range) Overlap(other Range) Range { | ||
207 | if !r.Overlaps(other) { | ||
208 | // Start == End indicates an empty range | ||
209 | return Range{ | ||
210 | Filename: r.Filename, | ||
211 | Start: r.Start, | ||
212 | End: r.Start, | ||
213 | } | ||
214 | } | ||
215 | |||
216 | var start, end Pos | ||
217 | if r.Start.Byte > other.Start.Byte { | ||
218 | start = r.Start | ||
219 | } else { | ||
220 | start = other.Start | ||
221 | } | ||
222 | if r.End.Byte < other.End.Byte { | ||
223 | end = r.End | ||
224 | } else { | ||
225 | end = other.End | ||
226 | } | ||
227 | |||
228 | return Range{ | ||
229 | Filename: r.Filename, | ||
230 | Start: start, | ||
231 | End: end, | ||
232 | } | ||
233 | } | ||
234 | |||
235 | // PartitionAround finds the portion of the given range that overlaps with | ||
236 | // the reciever and returns three ranges: the portion of the reciever that | ||
237 | // precedes the overlap, the overlap itself, and then the portion of the | ||
238 | // reciever that comes after the overlap. | ||
239 | // | ||
240 | // If the two ranges do not overlap then all three returned ranges are empty. | ||
241 | // | ||
242 | // If the given range aligns with or extends beyond either extent of the | ||
243 | // reciever then the corresponding outer range will be empty. | ||
244 | func (r Range) PartitionAround(other Range) (before, overlap, after Range) { | ||
245 | overlap = r.Overlap(other) | ||
246 | if overlap.Empty() { | ||
247 | return overlap, overlap, overlap | ||
248 | } | ||
249 | |||
250 | before = Range{ | ||
251 | Filename: r.Filename, | ||
252 | Start: r.Start, | ||
253 | End: overlap.Start, | ||
254 | } | ||
255 | after = Range{ | ||
256 | Filename: r.Filename, | ||
257 | Start: overlap.End, | ||
258 | End: r.End, | ||
259 | } | ||
260 | |||
261 | return before, overlap, after | ||
262 | } | ||