diff --git a/json.go b/json.go index 96c50e2..8976c49 100644 --- a/json.go +++ b/json.go @@ -3,6 +3,8 @@ package main import ( "fmt" "strconv" + "strings" + "unicode/utf8" ) type jsonParser struct { @@ -49,6 +51,9 @@ func (p *jsonParser) next() { } else { p.lastChar = 0 } + if p.lastChar == '\n' { + p.lineNumber++ + } p.sourceTail.writeByte(p.lastChar) } @@ -357,5 +362,20 @@ func (p *jsonParser) skipComment() { } func (p *jsonParser) errorSnippet(message string) error { - return fmt.Errorf("%s on node %d.\n%s\n", message, p.lineNumber, p.sourceTail.string()) + lines := strings.Split(p.sourceTail.string(), "\n") + lastLineLen := utf8.RuneCountInString(lines[len(lines)-1]) + pointer := strings.Repeat(".", lastLineLen-1) + "^" + lines = append(lines, pointer) + + paddedLines := make([]string, len(lines)) + for i, line := range lines { + paddedLines[i] = " " + line + } + + return fmt.Errorf( + "%s on line %d.\n\n%s\n\n", + message, + p.lineNumber, + strings.Join(paddedLines, "\n"), + ) } diff --git a/ring.go b/ring.go index 70d1255..86f4b63 100644 --- a/ring.go +++ b/ring.go @@ -1,32 +1,49 @@ package main +import ( + "strings" +) + type ring struct { - buf [100]byte + buf [70]byte start, end int } func (r *ring) writeByte(b byte) { - if b == '\n' { - r.end = 0 - r.start = r.end - return - } r.buf[r.end] = b - r.end++ - if r.end >= len(r.buf) { - r.end = 0 - } + r.end = (r.end + 1) % len(r.buf) + if r.end == r.start { - r.start++ - if r.start >= len(r.buf) { - r.start = 0 - } + r.start = (r.start + 1) % len(r.buf) } } func (r *ring) string() string { - if r.start < r.end { - return string(r.buf[r.start:r.end]) + var lines []byte + newlineCount := 0 + + for i := r.end - 1; ; i-- { + if i < 0 { + i = len(r.buf) - 1 + } + + if r.buf[i] == '\n' { + newlineCount++ + if newlineCount == 2 { + break + } + } + + lines = append(lines, r.buf[i]) + + if i == r.start { + break + } } - return string(r.buf[r.start:]) + string(r.buf[:r.end]) + + for i, j := 0, len(lines)-1; i < j; i, j = i+1, j-1 { + lines[i], lines[j] = lines[j], lines[i] + } + + return strings.TrimRight(string(lines), "\t \n") }