Skip to content

Commit

Permalink
fix the charm library's terminal error handling
Browse files Browse the repository at this point in the history
doesn't affect tell, but tapestry is using charm for some manual string parsing.
- exit ParseEof when using charm.Finished()
- wrap Endpoint errors instead of embedding the reason as a string
- changes for staticcheck
  • Loading branch information
ionous committed May 16, 2024
1 parent dd2b97a commit 2bfc064
Show file tree
Hide file tree
Showing 8 changed files with 30 additions and 36 deletions.
26 changes: 12 additions & 14 deletions charm/charmParse.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@ func innerParse(first State, in io.RuneReader) (ret State, err error) {
for i := 0; ; i++ {
if r, _, e := in.ReadRune(); e != nil {
if e != io.EOF {
err = errors.Join(e, EndpointError{errContext(r, in), i, try, e.Error()})
err = errors.Join(e, EndpointError{r, in, i, try})
}
break
} else {
if next := try.NewRune(r); next == nil {
// no states left to parse remaining input
err = EndpointError{errContext(r, in), i, try, "unhandled rune"}
e := errors.New("unhandled rune")
err = errors.Join(e, EndpointError{r, in, i, try})
break
} else if es, ok := next.(Terminal); ok {
err = EndpointError{errContext(r, in), i, try, es.err.Error()}
err = errors.Join(es.err, EndpointError{r, in, i, try})
break
} else {
try = next
Expand Down Expand Up @@ -72,11 +73,8 @@ func ParseEof(str string, first State) (err error) {
err = e
} else if last != nil {
if fini := last.NewRune(Eof); fini != nil {
if es, ok := fini.(Terminal); ok && es.err != nil {
err = fmt.Errorf("%s handling eof for %q", es.err, str)
} else {
// and if we are passing eof, shouldnt the states check for it and return nil?
// err = EndpointError{str, len(str), fini}
if es, ok := fini.(Terminal); !ok || !es.Finished() {
err = fmt.Errorf("%s at eof for %q", es.err, str)
}
}
}
Expand All @@ -85,10 +83,10 @@ func ParseEof(str string, first State) (err error) {

// ended before the whole input was parsed.
type EndpointError struct {
str string
end int
last State
reason string
r rune
in io.RuneReader
end int
last State
}

// index of the failure point in the input
Expand All @@ -97,6 +95,6 @@ func (e EndpointError) End() int {
}

func (e EndpointError) Error() (ret string) {
return fmt.Sprintf("%s %q (%q ended at index %d)",
e.reason, e.str, StateName(e.last), e.end)
sink := errContext(e.r, e.in)
return fmt.Sprintf("%q (%q ended at index %d)", sink, StateName(e.last), e.end)
}
5 changes: 3 additions & 2 deletions charm/charmRequires_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ func TestRequires(t *testing.T) {

// index of the fail point, or -1 if success is expected
count := func(failPoint int, str string, style State) (err error) {
var ep EndpointError
if e := ParseEof(str, style); e == nil && failPoint != -1 {
err = errors.New("unexpected success")
} else if n, ok := e.(EndpointError); !ok {
} else if !errors.As(e, &ep) {
err = e
} else if at := n.End(); at != failPoint {
} else if at := ep.End(); at != failPoint {
// 0 means okay, -1 incomplete, >0 the one-index of the failure point.
err = fmt.Errorf("%s len: %d", str, at)
}
Expand Down
4 changes: 2 additions & 2 deletions charmed/charmedHeader.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (h *headCount) update(q rune, report headerNotifier) (err error) {
} else if prev, width := h.token, h.width; t == prev {
h.width++
} else if prev == headerRedirect && width != 3 {
err = customTagError
err = errCustomTag
} else {
h.token, h.width = t, 1
if prev != headerSpaces {
Expand All @@ -70,7 +70,7 @@ func (h *headCount) update(q rune, report headerNotifier) (err error) {
return
}

var customTagError = errors.New("custom closing tags require exactly three redirect markers ('<<<')")
var errCustomTag = errors.New("custom closing tags require exactly three redirect markers ('<<<')")

// determine which header type, if any, the passed rune belongs to
// ( false if its some classifiable rune )
Expand Down
5 changes: 2 additions & 3 deletions charmed/charmedNum.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ func (*NumParser) String() string {
return "Numbers"
}


// fix: this is currently less of a number parser, and more a number validator.
func (p *NumParser) accept(q rune, s charm.State) charm.State {
p.runes.WriteRune(q)
Expand All @@ -46,7 +45,7 @@ func (p *NumParser) GetNumber() (ret any, err error) {
case modeFloat:
ret = fromFloat(s)
default:
err = fmt.Errorf("unknown number: '%v' is %v.", s, p.mode)
err = fmt.Errorf("unknown number: '%v' is %v", s, p.mode)
}
return
}
Expand All @@ -61,7 +60,7 @@ func (p *NumParser) GetFloat() (ret float64, err error) {
case modeFloat:
ret = fromFloat(s)
default:
err = fmt.Errorf("unknown number: '%v' is %v.", s, p.mode)
err = fmt.Errorf("unknown number: '%v' is %v", s, p.mode)
}
return
}
Expand Down
6 changes: 4 additions & 2 deletions charmed/charmedNum_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package charmed

import (
"errors"
"math"
"testing"

Expand Down Expand Up @@ -85,10 +86,11 @@ func TestNum(t *testing.T) {
t.Fatal("expected success", e)
break
} else if test.endpoint > 0 {
if c, ok := e.(charm.EndpointError); !ok {
var ep charm.EndpointError
if !errors.As(e, &ep) {
t.Fatal("unexpected error", e)
break
} else if c.End() != test.endpoint-1 {
} else if ep.End() != test.endpoint-1 {
t.Fatal("mismatched endpoint at", e)
break
}
Expand Down
2 changes: 1 addition & 1 deletion decode/decodeArray.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func (d *Decoder) waitForSep(at token.Pos, tokenType token.Type, val any) (err e
d.state = d.waitForEl
}
default:
err = errors.New("expected an array separator, or array close.")
err = errors.New("expected an array separator or array close")
}
}
return
Expand Down
12 changes: 3 additions & 9 deletions encode/encodeMap.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func keyTransform(v r.Value) (ret string) {
return
}

func (m *MapTransform) makeMapping(src r.Value) (retIt Iterator, err error) {
func (m *MapTransform) makeMapping(src r.Value) (Iterator, error) {
keyLess := m.keyLess
if keyLess == nil {
keyLess = func(a, b string) bool { return a < b }
Expand All @@ -62,16 +62,10 @@ func (m *MapTransform) makeMapping(src r.Value) (retIt Iterator, err error) {
mk = mapKeys{str: str, val: keys, keyLess: keyLess}
sort.Sort(&mk)
}
if err == nil {
retIt = &mapIter{src: src, mapKeys: mk}
}
return
//
return &mapIter{src: src, mapKeys: mk}, nil
}

// not quite sure how to turn string into an interface without something like this. ugh.
var anyBlank = [1]any{""}
var blank = r.ValueOf(anyBlank).Index(0)

type mapIter struct {
src r.Value // the native map
mapKeys mapKeys
Expand Down
6 changes: 3 additions & 3 deletions token/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (n *tokenizer) wordDecoder() charm.State {
} else if terminal(sign) {
// sign is mostly superset of bool; (except for the eof/eol cases)
// if it dies and boolean didnt just succeed; they're both dead.
ret = charm.Error(wordyError)
ret = charm.Error(errWordy)
}
return
})
Expand All @@ -169,7 +169,7 @@ func (n *tokenizer) decodeSignature() charm.State {
if sign = sign.NewRune(q); sign == nil {
ret = n.notifyRune(q, Key, sig.String())
} else if terminal(sign) {
ret = charm.Error(wordyError)
ret = charm.Error(errWordy)
}
return
})
Expand Down Expand Up @@ -248,7 +248,7 @@ const (
boolTrue // true
)

var wordyError = errors.New("couldn't read words. strings should be quoted, booleans should be 'true' or 'false', and map keys should start with a letter and end with a colon.")
var errWordy = errors.New("couldn't read words. strings should be quoted, booleans should be 'true' or 'false', and map keys should start with a letter and end with a colon")

// is the next state an error?
func terminal(next charm.State) (okay bool) {
Expand Down

0 comments on commit 2bfc064

Please sign in to comment.