From fddfb973d6d92d2a9c1e3d08ba454eacebbcc15c Mon Sep 17 00:00:00 2001 From: Alec Thomas Date: Sat, 3 Nov 2018 09:49:00 +1100 Subject: [PATCH] Clean up error handling a bit. --- kong_test.go | 9 +++++++++ model.go | 7 ++++++- scanner.go | 36 +++++++++++++++++++++++++++++++++--- tokentype_string.go | 16 ---------------- 4 files changed, 48 insertions(+), 20 deletions(-) delete mode 100644 tokentype_string.go diff --git a/kong_test.go b/kong_test.go index d8218bd..f767a03 100644 --- a/kong_test.go +++ b/kong_test.go @@ -688,3 +688,12 @@ func TestParentBindings(t *testing.T) { require.NoError(t, err) require.Equal(t, "foo", cli.Command.value) } + +func TestNumericParamErrors(t *testing.T) { + var cli struct { + Name string + } + parser := mustNew(t, &cli) + _, err := parser.Parse([]string{"--name", "-10"}) + require.EqualError(t, err, `expected string value but got "-10" (short flag)`) +} diff --git a/model.go b/model.go index 6256379..3b42e75 100644 --- a/model.go +++ b/model.go @@ -271,7 +271,12 @@ func (v *Value) IsBool() bool { func (v *Value) Parse(scan *Scanner, target reflect.Value) error { defer func() { if err := recover(); err != nil { - panic(fmt.Sprintf("mapper %T failed to apply to %s: %s", v.Mapper, v.Summary(), err)) + switch err := err.(type) { + case Error: + panic(err) + default: + panic(fmt.Sprintf("mapper %T failed to apply to %s: %s", v.Mapper, v.Summary(), err)) + } } }() err := v.Mapper.Decode(&DecodeContext{Value: v, Scan: scan}, target) diff --git a/scanner.go b/scanner.go index acab5e3..a503b41 100644 --- a/scanner.go +++ b/scanner.go @@ -5,8 +5,6 @@ import ( "strings" ) -//go:generate stringer -type=TokenType - // TokenType is the type of a token. type TokenType int @@ -21,6 +19,26 @@ const ( PositionalArgumentToken // ) +func (t TokenType) String() string { + switch t { + case UntypedToken: + return "untyped" + case EOLToken: + return "" + case FlagToken: // -- + return "long flag" + case FlagValueToken: // = + return "flag value" + case ShortFlagToken: // -[ + return "short flag remainder" + case PositionalArgumentToken: // + return "positional argument" + } + panic("unsupported type") +} + // Token created by Scanner. type Token struct { Value string @@ -58,6 +76,18 @@ func (t Token) IsAny(types ...TokenType) bool { return false } +// InferredType tries to infer the type of a token. +func (t Token) InferredType() TokenType { + if t.Type == UntypedToken { + if strings.HasPrefix(t.Value, "--") { + return FlagToken + } else if strings.HasPrefix(t.Value, "-") { + return ShortFlagToken + } + } + return t.Type +} + // IsValue returns true if token is usable as a parseable value. // // A parseable value is either a value typed token, or an untyped token NOT starting with a hyphen. @@ -113,7 +143,7 @@ func (s *Scanner) Pop() Token { func (s *Scanner) PopValue(context string) string { t := s.Pop() if !t.IsValue() { - fail("expected %s value but got %s", context, t) + fail("expected %s value but got %s (%s)", context, t, t.InferredType()) } return t.Value } diff --git a/tokentype_string.go b/tokentype_string.go deleted file mode 100644 index 7b68434..0000000 --- a/tokentype_string.go +++ /dev/null @@ -1,16 +0,0 @@ -// Code generated by "stringer -type=TokenType"; DO NOT EDIT. - -package kong - -import "strconv" - -const _TokenType_name = "UntypedTokenEOLTokenFlagTokenFlagValueTokenShortFlagTokenShortFlagTailTokenPositionalArgumentToken" - -var _TokenType_index = [...]uint8{0, 12, 20, 29, 43, 57, 75, 98} - -func (i TokenType) String() string { - if i < 0 || i >= TokenType(len(_TokenType_index)-1) { - return "TokenType(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _TokenType_name[_TokenType_index[i]:_TokenType_index[i+1]] -}