/
locations.go
105 lines (90 loc) · 2.85 KB
/
locations.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
97
98
99
100
101
102
103
104
105
// Copyright (c) 2019 Kevin L. Mitchell
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
package common
import (
"fmt"
"strings"
)
// FilePos specifies a position within a given file.
type FilePos struct {
L int // The line number of the position
C int // The column number of the position
}
// Location specifies the exact range of locations of some entity.
type Location struct {
File string // The name of the file
B FilePos // The beginning of the range
E FilePos // The end of the range
}
// Advance advances a location in place. The current range end
// becomes the range beginning, and the range end is the sum of the
// new range beginning and the provided offset.
func (l *Location) Advance(offset FilePos) {
// Begin by advancing the beginning
l.B = l.E
// Now advance the ending; if L is incremented, C will be
// reset to 1
if offset.L > 0 {
l.E.L += offset.L
l.E.C = 1
}
l.E.C += offset.C
}
// AdvanceTab advances a location in place, as if by a tab character.
// The argument indicates the size of a tab stop.
func (l *Location) AdvanceTab(tabstop int) {
l.Advance(FilePos{C: 1 + tabstop - l.E.C%tabstop})
}
// Thru creates a new Location that ranges from the beginning of this
// location to the beginning of another Location.
func (l Location) Thru(other Location) Location {
// Location can't range across files
if l.File != other.File {
panic(ErrSplitEntity)
}
// Create and return the new location
return Location{
File: l.File,
B: l.B,
E: other.B,
}
}
// ThruEnd is similar to Thru, except that it creates a new Location
// that ranges from the beginning of this location to the ending of
// another Location.
func (l Location) ThruEnd(other Location) Location {
// Location can't range across files
if l.File != other.File {
panic(ErrSplitEntity)
}
// Create and return the new location
return Location{
File: l.File,
B: l.B,
E: other.E,
}
}
// String constructs a string representation of the location.
func (l Location) String() string {
text := strings.Builder{}
// Add the beginning to the location
text.WriteString(fmt.Sprintf("%s:%d:%d", l.File, l.B.L, l.B.C))
// Is it split across lines or wider than one column?
if l.B.L != l.E.L {
text.WriteString(fmt.Sprintf("-%d:%d", l.E.L, l.E.C))
} else if l.E.C-l.B.C > 1 {
text.WriteString(fmt.Sprintf("-%d", l.E.C))
}
return text.String()
}