Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/river/token/file.go
4096 views
1
package token
2
3
import (
4
"fmt"
5
"sort"
6
"strconv"
7
)
8
9
// NoPos is the zero value for Pos. It has no file or line information
10
// associated with it, and NoPos.Valid is false.
11
var NoPos = Pos{}
12
13
// Pos is a compact representation of a position within a file. It can be
14
// converted into a Position for a more convenient, but larger, representation.
15
type Pos struct {
16
file *File
17
off int
18
}
19
20
// String returns the string form of the Pos (the offset).
21
func (p Pos) String() string { return strconv.Itoa(p.off) }
22
23
// File returns the file used by the Pos. This will be nil for invalid
24
// positions.
25
func (p Pos) File() *File { return p.file }
26
27
// Position converts the Pos into a Position.
28
func (p Pos) Position() Position { return p.file.PositionFor(p) }
29
30
// Add creates a new Pos relative to p.
31
func (p Pos) Add(n int) Pos {
32
return Pos{
33
file: p.file,
34
off: p.off + n,
35
}
36
}
37
38
// Offset returns the byte offset associated with Pos.
39
func (p Pos) Offset() int { return p.off }
40
41
// Valid reports whether the Pos is valid.
42
func (p Pos) Valid() bool { return p != NoPos }
43
44
// Position holds full position information for a location within an individual
45
// file.
46
type Position struct {
47
Filename string // Filename (if any)
48
Offset int // Byte offset (starting at 0)
49
Line int // Line number (starting at 1)
50
Column int // Offset from start of line (starting at 1)
51
}
52
53
// Valid reports whether the position is valid. Valid positions must have a
54
// Line value greater than 0.
55
func (pos *Position) Valid() bool { return pos.Line > 0 }
56
57
// String returns a string in one of the following forms:
58
//
59
// file:line:column Valid position with file name
60
// file:line Valid position with file name but no column
61
// line:column Valid position with no file name
62
// line Valid position with no file name or column
63
// file Invalid position with file name
64
// - Invalid position with no file name
65
func (pos Position) String() string {
66
s := pos.Filename
67
68
if pos.Valid() {
69
if s != "" {
70
s += ":"
71
}
72
s += fmt.Sprintf("%d", pos.Line)
73
if pos.Column != 0 {
74
s += fmt.Sprintf(":%d", pos.Column)
75
}
76
}
77
78
if s == "" {
79
s = "-"
80
}
81
return s
82
}
83
84
// File holds position information for a specific file.
85
type File struct {
86
filename string
87
lines []int // Byte offset of each line number (first element is always 0).
88
}
89
90
// NewFile creates a new File for storing position information.
91
func NewFile(filename string) *File {
92
return &File{
93
filename: filename,
94
lines: []int{0},
95
}
96
}
97
98
// Pos returns a Pos given a byte offset. Pos panics if off is < 0.
99
func (f *File) Pos(off int) Pos {
100
if off < 0 {
101
panic("Pos: illegal offset")
102
}
103
return Pos{file: f, off: off}
104
}
105
106
// Name returns the name of the file.
107
func (f *File) Name() string { return f.filename }
108
109
// AddLine tracks a new line from a byte offset. The line offset must be larger
110
// than the offset for the previous line, otherwise the line offset is ignored.
111
func (f *File) AddLine(offset int) {
112
lines := len(f.lines)
113
if f.lines[lines-1] < offset {
114
f.lines = append(f.lines, offset)
115
}
116
}
117
118
// PositionFor returns a Position from an offset.
119
func (f *File) PositionFor(p Pos) Position {
120
if p == NoPos {
121
return Position{}
122
}
123
124
// Search through our line offsets to find the line/column info. The else
125
// case should never happen here, but if it does, Position.Valid will return
126
// false.
127
var line, column int
128
if i := searchInts(f.lines, p.off); i >= 0 {
129
line, column = i+1, p.off-f.lines[i]+1
130
}
131
132
return Position{
133
Filename: f.filename,
134
Offset: p.off,
135
Line: line,
136
Column: column,
137
}
138
}
139
140
func searchInts(a []int, x int) int {
141
return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1
142
}
143
144