forked from goccmack/gocc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
errors.go
108 lines (91 loc) · 2.66 KB
/
errors.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
// Code generated by gocc; DO NOT EDIT.
package errors
import (
"fmt"
"strconv"
"strings"
"unicode"
"github.com/Desuuuu/gocc/example/errormsg/token"
)
type ErrorSymbol interface {
}
type Error struct {
Err error
ErrorToken *token.Token
ErrorSymbols []ErrorSymbol
ExpectedTokens []string
StackTop int
}
func (e *Error) String() string {
w := new(strings.Builder)
if e.Err != nil {
fmt.Fprintln(w, "Error ", e.Err)
} else {
fmt.Fprintln(w, "Error")
}
fmt.Fprintf(w, "Token: type=%d, lit=%s\n", e.ErrorToken.Type, e.ErrorToken.Lit)
fmt.Fprintf(w, "Pos: offset=%d, line=%d, column=%d\n", e.ErrorToken.Pos.Offset, e.ErrorToken.Pos.Line, e.ErrorToken.Pos.Column)
fmt.Fprint(w, "Expected one of: ")
for _, sym := range e.ExpectedTokens {
fmt.Fprint(w, string(sym), " ")
}
fmt.Fprintln(w, "ErrorSymbol:")
for _, sym := range e.ErrorSymbols {
fmt.Fprintf(w, "%v\n", sym)
}
return w.String()
}
func DescribeExpected(tokens []string) string {
switch len(tokens) {
case 0:
return "unexpected additional tokens"
case 1:
return "expected " + tokens[0]
case 2:
return "expected either " + tokens[0] + " or " + tokens[1]
case 3:
// Oxford-comma rules require more than 3 items in a list for the
// comma to appear before the 'or'
return fmt.Sprintf("expected one of %s, %s or %s", tokens[0], tokens[1], tokens[2])
default:
// Oxford-comma separated alternatives list.
tokens = append(tokens[:len(tokens)-1], "or "+tokens[len(tokens)-1])
return "expected one of " + strings.Join(tokens, ", ")
}
}
func DescribeToken(tok *token.Token) string {
switch tok.Type {
case token.INVALID:
return fmt.Sprintf("unknown/invalid token %q", tok.Lit)
case token.EOF:
return "end-of-file"
default:
return fmt.Sprintf("%q", tok.Lit)
}
}
func (e *Error) Error() string {
// identify the line and column of the error in 'gnu' style so it can be understood
// by editors and IDEs; user will need to prefix it with a filename.
text := fmt.Sprintf("%d:%d: error: ", e.ErrorToken.Pos.Line, e.ErrorToken.Pos.Column)
// See if the error token can provide us with the filename.
switch src := e.ErrorToken.Pos.Context.(type) {
case token.Sourcer:
text = src.Source() + ":" + text
}
if e.Err != nil {
// Custom error specified, e.g. by << nil, errors.New("missing newline") >>
text += e.Err.Error()
} else {
tokens := make([]string, len(e.ExpectedTokens))
for idx, token := range e.ExpectedTokens {
if !unicode.IsLetter(rune(token[0])) {
token = strconv.Quote(token)
}
tokens[idx] = token
}
text += DescribeExpected(tokens)
actual := DescribeToken(e.ErrorToken)
text += fmt.Sprintf("; got: %s", actual)
}
return text
}