Skip to content

Commit c223cd5

Browse files
committed
Make file package's struct marshallable
1 parent d08eedd commit c223cd5

File tree

6 files changed

+51
-46
lines changed

6 files changed

+51
-46
lines changed

internal/file/error.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ func (e *Error) Format(source *Source) string {
3131
var result = fmt.Sprintf(
3232
"%s (%d:%d)",
3333
e.Message,
34-
e.Location.Line(),
35-
e.Location.Column()+1, // add one to the 0-based column for display
34+
e.Location.Line,
35+
e.Location.Column+1, // add one to the 0-based column for display
3636
)
37-
if snippet, found := source.Snippet(e.Location.Line()); found {
37+
if snippet, found := source.Snippet(e.Location.Line); found {
3838
snippet := strings.Replace(snippet, "\t", " ", -1)
3939
srcLine := "\n | " + snippet
4040
var bytes = []byte(snippet)
4141
var indLine = "\n | "
42-
for i := 0; i < e.Location.Column() && len(bytes) > 0; i++ {
42+
for i := 0; i < e.Location.Column && len(bytes) > 0; i++ {
4343
_, sz := utf8.DecodeRune(bytes)
4444
bytes = bytes[sz:]
4545
if sz > 1 {

internal/file/errors_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import (
88
func TestErrors(t *testing.T) {
99
source := NewSource("a.b\n&&arg(missing, paren")
1010
errors := NewErrors(source)
11-
errors.ReportError(NewLocation(1, 1), "No such field")
11+
errors.ReportError(Location{Line: 1, Column: 1}, "No such field")
1212
if len(errors.GetErrors()) != 1 {
1313
t.Errorf("%s first error not recorded", t.Name())
1414
}
1515
errors.ReportError(
16-
NewLocation(2, 20),
16+
Location{Line: 2, Column: 20},
1717
"syntax error, missing paren",
1818
)
1919
if len(errors.GetErrors()) != 2 {
@@ -35,7 +35,7 @@ func TestErrors(t *testing.T) {
3535
func TestErrors_WideAndNarrowCharacters(t *testing.T) {
3636
source := NewSource("你好吗\n我b很好\n")
3737
errors := NewErrors(source)
38-
errors.ReportError(NewLocation(2, 3), "Unexpected character '好'")
38+
errors.ReportError(Location{Line: 2, Column: 3}, "Unexpected character '好'")
3939

4040
got := errors.Error()
4141
want := "Unexpected character '好' (2:4)\n" +
@@ -49,9 +49,9 @@ func TestErrors_WideAndNarrowCharacters(t *testing.T) {
4949
func TestErrors_WideAndNarrowCharacters_Emojis(t *testing.T) {
5050
source := NewSource(" '😁' in ['😁', '😑', '😦'] && in.😁")
5151
errors := NewErrors(source)
52-
errors.ReportError(NewLocation(1, 32), "syntax error: extraneous input 'in' expecting {'[', '{', '(', '.', '-', '!', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER}")
53-
errors.ReportError(NewLocation(1, 35), "syntax error: token recognition error at: '😁'")
54-
errors.ReportError(NewLocation(1, 36), "syntax error: missing IDENTIFIER at '<EOF>'")
52+
errors.ReportError(Location{Line: 1, Column: 32}, "syntax error: extraneous input 'in' expecting {'[', '{', '(', '.', '-', '!', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER}")
53+
errors.ReportError(Location{Line: 1, Column: 35}, "syntax error: token recognition error at: '😁'")
54+
errors.ReportError(Location{Line: 1, Column: 36}, "syntax error: missing IDENTIFIER at '<EOF>'")
5555
got := errors.Error()
5656
want := "syntax error: extraneous input 'in' expecting {'[', '{', '(', '.', '-', '!', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER} (1:33)\n" +
5757
" | '😁' in ['😁', '😑', '😦'] && in.😁\n" +

internal/file/location.go

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,10 @@
11
package file
22

33
type Location struct {
4-
line int
5-
column int
6-
}
7-
8-
func NewLocation(line, column int) Location {
9-
return Location{
10-
line: line,
11-
column: column,
12-
}
13-
}
14-
15-
// Line returns the 1-based line of the location.
16-
func (l Location) Line() int {
17-
return l.line
18-
}
19-
20-
// Column returns the 0-based column number of the location.
21-
func (l Location) Column() int {
22-
return l.column
4+
Line int // The 1-based line of the location.
5+
Column int // The 0-based column number of the location.
236
}
247

258
func (l Location) Empty() bool {
26-
return l.column == 0 && l.line == 0
9+
return l.Column == 0 && l.Line == 0
2710
}

internal/file/source.go

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package file
22

33
import (
4+
"encoding/json"
45
"strings"
56
"unicode/utf8"
67
)
@@ -11,18 +12,27 @@ type Source struct {
1112
}
1213

1314
func NewSource(contents string) *Source {
14-
// Compute line offsets up front as they are referred to frequently.
15-
lines := strings.Split(contents, "\n")
16-
offsets := make([]int32, len(lines))
17-
var offset int32
18-
for i, line := range lines {
19-
offset = offset + int32(utf8.RuneCountInString(line)) + 1
20-
offsets[int32(i)] = offset
15+
s := &Source{
16+
contents: []rune(contents),
2117
}
22-
return &Source{
23-
contents: []rune(contents),
24-
lineOffsets: offsets,
18+
s.updateOffsets()
19+
return s
20+
}
21+
22+
func (s *Source) MarshalJSON() ([]byte, error) {
23+
return json.Marshal(s.contents)
24+
}
25+
26+
func (s *Source) UnmarshalJSON(b []byte) error {
27+
contents := make([]rune, 0)
28+
err := json.Unmarshal(b, &contents)
29+
if err != nil {
30+
return err
2531
}
32+
33+
s.contents = contents
34+
s.updateOffsets()
35+
return nil
2636
}
2737

2838
func (s *Source) Content() string {
@@ -41,6 +51,18 @@ func (s *Source) Snippet(line int) (string, bool) {
4151
return string(s.contents[charStart:]), true
4252
}
4353

54+
// updateOffsets compute line offsets up front as they are referred to frequently.
55+
func (s *Source) updateOffsets() {
56+
lines := strings.Split(string(s.contents), "\n")
57+
offsets := make([]int32, len(lines))
58+
var offset int32
59+
for i, line := range lines {
60+
offset = offset + int32(utf8.RuneCountInString(line)) + 1
61+
offsets[int32(i)] = offset
62+
}
63+
s.lineOffsets = offsets
64+
}
65+
4466
// findLineOffset returns the offset where the (1-indexed) line begins,
4567
// or false if line doesn't exist.
4668
func (s *Source) findLineOffset(line int) (int32, bool) {

internal/file/source_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const (
88
unexpectedValue = "%s got snippet '%v', want '%v'"
99
unexpectedSnippet = "%s got snippet '%s', want '%v'"
1010
snippetNotFound = "%s snippet not found, wanted '%v'"
11-
snippetFound = "%s snippet found at line %d, wanted none"
11+
snippetFound = "%s snippet found at Line %d, wanted none"
1212
)
1313

1414
// TestStringSource_SnippetMultiline snippets of text from a multiline source.

parser/parser.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ func (p *parser) ExitClosureMemberDotExpression(ctx *gen.ClosureMemberDotExpress
407407
}
408408

409409
func (p *parser) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
410-
p.errors.ReportError(file.NewLocation(line, column), fmt.Sprintf("syntax error: %s", msg))
410+
p.errors.ReportError(file.Location{Line: line, Column: column}, fmt.Sprintf("syntax error: %s", msg))
411411
}
412412

413413
func (p *parser) ReportAmbiguity(_ antlr.Parser, _ *antlr.DFA, _, _ int, _ bool, _ *antlr.BitSet, _ antlr.ATNConfigSet) {
@@ -432,17 +432,17 @@ func unquotes(s string) string {
432432

433433
func location(ctx antlr.ParserRuleContext) file.Location {
434434
if ctx == nil {
435-
return file.NewLocation(0, 0)
435+
return file.Location{Line: 0, Column: 0}
436436
}
437437

438438
token := ctx.GetStart()
439439
if token == nil {
440-
return file.NewLocation(0, 0)
440+
return file.Location{Line: 0, Column: 0}
441441
}
442442

443-
return file.NewLocation(token.GetLine(), token.GetColumn())
443+
return file.Location{Line: token.GetLine(), Column: token.GetColumn()}
444444
}
445445

446446
func locationToken(token antlr.Token) file.Location {
447-
return file.NewLocation(token.GetLine(), token.GetColumn())
447+
return file.Location{Line: token.GetLine(), Column: token.GetColumn()}
448448
}

0 commit comments

Comments
 (0)