Skip to content
This repository was archived by the owner on Nov 21, 2023. It is now read-only.

Commit 83fdf5a

Browse files
Merge pull request #12 from goinsane/develop
v1.2.1
2 parents 53665a7 + 40581ca commit 83fdf5a

File tree

2 files changed

+63
-42
lines changed

2 files changed

+63
-42
lines changed

erf.go

Lines changed: 60 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"fmt"
88
"os"
99
"strings"
10-
"unicode"
1110
"unsafe"
1211
)
1312

@@ -21,8 +20,10 @@ type Erf struct {
2120
err error
2221
format string
2322
args []interface{}
23+
tags []string
2424
tagIndexes map[string]int
2525
pc []uintptr
26+
top int
2627
}
2728

2829
// Error is implementation of error.
@@ -38,6 +39,20 @@ func (e *Erf) Unwrap() error {
3839
return nil
3940
}
4041

42+
// UnwrapAll returns all errors using Unwrap method. The first element in the returned value is e.
43+
func (e *Erf) UnwrapAll() []error {
44+
result := make([]error, 0, 4096)
45+
for err := error(e); err != nil; {
46+
result = append(result, err)
47+
if wErr, ok := err.(WrappedError); ok {
48+
err = wErr.Unwrap()
49+
} else {
50+
err = nil
51+
}
52+
}
53+
return result
54+
}
55+
4156
// Format is implementation of fmt.Formatter.
4257
// Format lists error messages and appends StackTrace's for underlying Erf and all of wrapped Erf's,
4358
// line by line with given format.
@@ -83,12 +98,10 @@ func (e *Erf) Format(f fmt.State, verb rune) {
8398
pad, wid, prec := getPadWidPrec(f)
8499
format += fmt.Sprintf("%d.%ds", wid, prec)
85100
padding, indent := bytes.Repeat([]byte{pad}, wid), bytes.Repeat([]byte{pad}, prec)
86-
newLine := false
87-
for err := error(e); err != nil; {
88-
if newLine {
101+
for idx, err := range e.UnwrapAll() {
102+
if idx > 0 {
89103
buf.WriteRune('\n')
90104
}
91-
newLine = true
92105
if e2, ok := err.(*Erf); ok {
93106
if !f.Flag('-') {
94107
for _, line := range strings.Split(e2.Error(), "\n") {
@@ -98,30 +111,28 @@ func (e *Erf) Format(f fmt.State, verb rune) {
98111
buf.WriteRune('\n')
99112
}
100113
}
101-
buf.WriteString(fmt.Sprintf(format, e2.StackTrace()))
114+
str := fmt.Sprintf(format, e2.StackTrace())
115+
if str != "" {
116+
buf.WriteString(str)
117+
} else {
118+
buf.Write(padding)
119+
buf.WriteString("* ")
120+
}
102121
buf.WriteRune('\n')
103122
if f.Flag('+') {
104123
tags := e2.Tags()
105124
if len(tags) > 0 {
106125
buf.Write(padding)
107-
buf.WriteString("* ")
126+
buf.WriteString("+ ")
108127
for idx, tag := range tags {
109128
if idx > 0 {
110129
buf.WriteRune(' ')
111130
}
112-
v := "s"
113-
for _, r := range tag {
114-
if unicode.IsSpace(r) || r == '"' || r == '\'' {
115-
v = "q"
116-
break
117-
}
118-
}
119-
buf.WriteString(fmt.Sprintf("%"+v+"=%q", tag, fmt.Sprintf("%v", e2.Tag(tag))))
131+
buf.WriteString(fmt.Sprintf("%q=%q", tag, fmt.Sprintf("%v", e2.Tag(tag))))
120132
}
121133
buf.WriteRune('\n')
122134
}
123135
}
124-
buf.Write(padding)
125136
} else {
126137
if !f.Flag('-') {
127138
for _, line := range strings.Split(err.Error(), "\n") {
@@ -130,19 +141,16 @@ func (e *Erf) Format(f fmt.State, verb rune) {
130141
buf.WriteString(line)
131142
buf.WriteRune('\n')
132143
}
133-
buf.Write(padding)
134144
} else {
135-
newLine = false
145+
buf.Write(padding)
146+
buf.WriteString("- ")
147+
buf.WriteRune('\n')
136148
}
137149
}
150+
buf.Write(padding)
138151
if verb == 'X' {
139152
break
140153
}
141-
if wErr, ok := err.(WrappedError); ok {
142-
err = wErr.Unwrap()
143-
} else {
144-
err = nil
145-
}
146154
}
147155
default:
148156
return
@@ -189,23 +197,26 @@ func (e *Erf) Attach(tags ...string) *Erf {
189197
if e.args == nil {
190198
panic("args are not using")
191199
}
192-
if e.tagIndexes != nil {
200+
if e.tags != nil || e.tagIndexes != nil {
193201
panic("tags are already attached")
194202
}
195203
if len(tags) > len(e.args) {
196204
panic("number of tags is more than args")
197205
}
198-
tagIndexes := make(map[string]int, len(tags))
206+
t := make([]string, 0, len(tags))
207+
ti := make(map[string]int, len(tags))
199208
for index, tag := range tags {
200209
if tag == "" {
201210
continue
202211
}
203-
if _, ok := tagIndexes[tag]; ok {
212+
if _, ok := ti[tag]; ok {
204213
panic("tag already defined")
205214
}
206-
tagIndexes[tag] = index
215+
t = append(t, tag)
216+
ti[tag] = index
207217
}
208-
e.tagIndexes = tagIndexes
218+
e.tags = t
219+
e.tagIndexes = ti
209220
return e
210221
}
211222

@@ -228,32 +239,39 @@ func (e *Erf) Tag(tag string) interface{} {
228239

229240
// Tags returns all tags sequentially. It returns nil if tags are not attached.
230241
func (e *Erf) Tags() []string {
231-
if e.tagIndexes == nil {
242+
if e.tags == nil {
232243
return nil
233244
}
234-
m := make(map[int]string, len(e.tagIndexes))
235-
for tag, index := range e.tagIndexes {
236-
m[index] = tag
237-
}
238-
result := make([]string, 0, len(m))
239-
for i, j := 0, len(m); i < j; i++ {
240-
if tag, ok := m[i]; ok {
241-
result = append(result, tag)
242-
}
243-
}
245+
result := make([]string, len(e.tags))
246+
copy(result, e.tags)
244247
return result
245248
}
246249

247250
// PC returns program counters.
248251
func (e *Erf) PC() []uintptr {
249-
result := make([]uintptr, len(e.pc))
250-
copy(result, e.pc)
252+
src := e.pc[e.top:]
253+
result := make([]uintptr, len(src))
254+
copy(result, src)
251255
return result
252256
}
253257

254258
// StackTrace returns a StackTrace of Erf.
255259
func (e *Erf) StackTrace() *StackTrace {
256-
return NewStackTrace(e.pc...)
260+
return NewStackTrace(e.pc[e.top:]...)
261+
}
262+
263+
// Top sets top of program counters in Erf.
264+
// If the argument top is negative it returns just old value and doesn't set, otherwise sets and returns old value.
265+
func (e *Erf) Top(top int) int {
266+
if top < 0 {
267+
return e.top
268+
}
269+
result := e.top
270+
if top > len(e.pc) {
271+
panic("top out of range")
272+
}
273+
e.top = top
274+
return result
257275
}
258276

259277
func (e *Erf) initialize(skip int) {

stack.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ func (t *StackTrace) Len() int {
164164

165165
// Caller returns a StackCaller on the given index. It panics if index is out of range.
166166
func (t *StackTrace) Caller(index int) StackCaller {
167+
if t.Len() <= 0 {
168+
return StackCaller{}
169+
}
167170
if index < 0 || index >= t.Len() {
168171
panic("index out of range")
169172
}

0 commit comments

Comments
 (0)