aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/hcl2/hcl/pos.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcl/pos.go')
-rw-r--r--vendor/github.com/hashicorp/hcl2/hcl/pos.go262
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 @@
1package hcl
2
3import "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.
10type 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.
40type 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.
55func 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.
71func 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.
99func (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.
107func (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.
114func (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
132func (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.
142func (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.
163func (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.
184func (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.
206func (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.
244func (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}