-
-
Notifications
You must be signed in to change notification settings - Fork 96
/
error.go
124 lines (112 loc) · 3.01 KB
/
error.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package compiler
import (
"fmt"
"math"
"strings"
"github.com/antlr/antlr4/runtime/Go/antlr"
"github.com/logrusorgru/aurora"
)
type CompileError struct {
StartL, StartC int
EndL, EndC int
Msg string
}
type CompileErrorList struct {
Errors []CompileError
Source string
}
func (c *CompileErrorList) Error() string {
source := strings.ReplaceAll(c.Source, "\t", " ")
lines := strings.SplitAfter(strings.ReplaceAll(source, "\r\n", "\n"), "\n")
lines[len(lines)-1] += "\n"
txtBarGood := aurora.Blue("|")
s := ""
for _, e := range c.Errors {
lnPad := int(math.Log10(float64(e.EndL))) + 1 // line number padding
// error indicator
s += fmt.Sprintf("%v error:%v:%v\n", aurora.Red("-->"), e.StartL, e.StartC)
// initial empty line
s += fmt.Sprintf("%v %v\n", strings.Repeat(" ", lnPad), txtBarGood)
// offending lines
for l := e.StartL; l <= e.EndL; l++ { // "print fail"
line := lines[l-1]
before := ""
after := ""
start := 0
if l == e.StartL {
before = line[:e.StartC]
line = line[e.StartC:]
start = e.StartC
}
if l == e.EndL {
idx := e.EndC - start + 1
if idx >= len(line) { // because newline was erased
idx = len(line) - 1
}
after = line[idx:]
line = line[:idx]
}
s += aurora.Red(fmt.Sprintf("%0*d | ", lnPad, l)).String()
s += fmt.Sprintf("%v%v%v",
aurora.BrightBlack(before), line, aurora.BrightBlack(after))
}
// message
start := strings.IndexFunc(lines[e.EndL-1], func(r rune) bool {
return r != ' '
})
span := e.EndC - start + 1
if e.StartL == e.EndL {
start = e.StartC
span = e.EndC - e.StartC
}
if span == 0 {
span = 1
}
s += fmt.Sprintf("%v %v %v%v %v\n",
strings.Repeat(" ", lnPad),
txtBarGood,
strings.Repeat(" ", start),
aurora.Red(strings.Repeat("^", span)),
e.Msg)
}
return s
}
type ErrorListener struct {
*antlr.DefaultErrorListener
Errors []CompileError
}
func (l *ErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, startL, startC int, msg string, e antlr.RecognitionException) {
length := 1
if token, ok := offendingSymbol.(antlr.Token); ok {
length = len(token.GetText())
}
endL := startL
endC := startC + length - 1 // -1 so that end character is inside the offending token
l.Errors = append(l.Errors, CompileError{
StartL: startL,
StartC: startC,
EndL: endL,
EndC: endC,
Msg: msg,
})
}
func LogicError(c antlr.ParserRuleContext, err error) *CompileError {
endC := c.GetStop().GetColumn() + len(c.GetStop().GetText())
return &CompileError{
StartL: c.GetStart().GetLine(),
StartC: c.GetStart().GetColumn(),
EndL: c.GetStop().GetLine(),
EndC: endC,
Msg: err.Error(),
}
}
const InternalErrorMsg = "internal compiler error, please report to the issue tracker"
func InternalError(c antlr.ParserRuleContext) *CompileError {
return &CompileError{
StartL: c.GetStart().GetLine(),
StartC: c.GetStart().GetColumn(),
EndL: c.GetStop().GetLine(),
EndC: c.GetStop().GetColumn(),
Msg: InternalErrorMsg,
}
}