Fix golint errors and export all returnable types

This commit is contained in:
Vladimir Hodakov 2019-10-19 01:17:00 +04:00
parent 3ab215ed63
commit ca047193ee
Signed by: Vladimir Hodakov
GPG Key ID: 673980B6882F82C6
10 changed files with 135 additions and 98 deletions

View File

@ -1,10 +1,10 @@
package jsonpath
const (
BadStructure = "Bad Structure"
NoMoreResults = "No more results"
UnexpectedToken = "Unexpected token in evaluation"
AbruptTokenStreamEnd = "Token reader is not sending anymore tokens"
BadStructure = "bad structure"
NoMoreResults = "no more results"
UnexpectedToken = "unexpected token in evaluation"
AbruptTokenStreamEnd = "token reader is not sending anymore tokens"
)
var (

31
eval.go
View File

@ -49,7 +49,7 @@ func newEvaluation(tr tokenReader, paths ...*Path) *Eval {
location: *newStack(),
levelStack: *newIntStack(),
state: evalRoot,
queries: make(map[string]*query, 0),
queries: make(map[string]*query),
prevIndex: -1,
nextKey: nil,
copyValues: true, // depends on which lexer is used
@ -61,7 +61,7 @@ func newEvaluation(tr tokenReader, paths ...*Path) *Eval {
}
// Determine whether to copy emitted item values ([]byte) from lexer
switch tr.(type) {
case *readerLexer:
case *ReaderLexer:
e.copyValues = true
default:
e.copyValues = false
@ -100,6 +100,7 @@ func (e *Eval) Iterate() (*Results, bool) {
for str, query := range e.queries {
anyRunning = true
query.state = query.state(query, e, t)
if query.state == nil {
delete(e.queries, str)
}
@ -144,8 +145,8 @@ func (e *Eval) Next() (*Result, bool) {
} else {
break
}
}
return nil, false
}
@ -163,9 +164,12 @@ func (q *query) trySpillOver() {
if err != nil {
q.errors = append(q.errors, err)
}
if exprRes {
next, ok := q.buckets.peek()
var spillover *Results
if !ok {
// fmt.Println("Spilling over into end queue")
spillover = q.resultQueue
@ -174,6 +178,7 @@ func (q *query) trySpillOver() {
nextBucket := next.(exprBucket)
spillover = nextBucket.results
}
for {
v := bucket.results.Pop()
if v != nil {
@ -191,7 +196,7 @@ func pathMatchOp(q *query, e *Eval, i *Item) queryStateFn {
curLocation := e.location.len() - 1
if q.loc() > curLocation {
q.pos -= 1
q.pos--
q.trySpillOver()
} else if q.loc() <= curLocation {
if q.loc() == curLocation-1 {
@ -218,7 +223,6 @@ func pathMatchOp(q *query, e *Eval, i *Item) queryStateFn {
q.buckets.push(bucket)
}
}
}
}
}
@ -228,15 +232,17 @@ func pathMatchOp(q *query, e *Eval, i *Item) queryStateFn {
q.firstType = i.typ
q.buffer.Write(i.val)
}
q.valLoc = *e.location.clone()
return pathEndValue
}
if q.loc() < -1 {
return nil
} else {
return pathMatchOp
}
return pathMatchOp
}
func pathEndValue(q *query, e *Eval, i *Item) queryStateFn {
@ -278,14 +284,16 @@ func pathEndValue(q *query, e *Eval, i *Item) queryStateFn {
q.valLoc = *newStack()
q.buffer.Truncate(0)
q.pos -= 1
q.pos--
return pathMatchOp
}
return pathEndValue
}
func (b *exprBucket) evaluate() (bool, error) {
values := make(map[string]Item)
for _, q := range b.queries {
result := q.resultQueue.Pop()
if result != nil {
@ -293,6 +301,7 @@ func (b *exprBucket) evaluate() (bool, error) {
if err != nil {
return false, err
}
i := Item{
typ: t,
val: result.Value,
@ -305,11 +314,13 @@ func (b *exprBucket) evaluate() (bool, error) {
if err != nil {
return false, err
}
res_bool, ok := res.(bool)
resBool, ok := res.(bool)
if !ok {
return false, fmt.Errorf(exprErrorFinalValueNotBool, res)
}
return res_bool, nil
return resBool, nil
}
func itemMatchOperator(loc interface{}, op *operator) bool {

View File

@ -18,6 +18,7 @@ func evalRoot(e *Eval, i *Item) evalStateFn {
default:
e.Error = errors.New(UnexpectedToken)
}
return nil
}
@ -25,12 +26,16 @@ func evalObjectAfterOpen(e *Eval, i *Item) evalStateFn {
switch i.typ {
case jsonKey:
c := i.val[1 : len(i.val)-1]
if e.copyValues {
d := make([]byte, len(c))
copy(d, c)
c = d
}
e.nextKey = c
return evalObjectColon
case jsonBraceRight:
return rightBraceOrBracket(e)
@ -39,6 +44,7 @@ func evalObjectAfterOpen(e *Eval, i *Item) evalStateFn {
default:
e.Error = errors.New(UnexpectedToken)
}
return nil
}
@ -72,11 +78,13 @@ func evalObjectValue(e *Eval, i *Item) evalStateFn {
default:
e.Error = errors.New(UnexpectedToken)
}
return nil
}
func evalObjectAfterValue(e *Eval, i *Item) evalStateFn {
e.location.pop()
switch i.typ {
case jsonComma:
return evalObjectAfterOpen
@ -87,6 +95,7 @@ func evalObjectAfterValue(e *Eval, i *Item) evalStateFn {
default:
e.Error = errors.New(UnexpectedToken)
}
return nil
}
@ -96,14 +105,15 @@ func rightBraceOrBracket(e *Eval) evalStateFn {
lowerTyp, ok := e.levelStack.peek()
if !ok {
return evalRootEnd
} else {
switch lowerTyp {
case jsonBraceLeft:
return evalObjectAfterValue
case jsonBracketLeft:
return evalArrayAfterValue
}
}
switch lowerTyp {
case jsonBraceLeft:
return evalObjectAfterValue
case jsonBracketLeft:
return evalArrayAfterValue
}
return nil
}

View File

@ -9,13 +9,13 @@ import (
)
const (
exprErrorMismatchedParens = "Mismatched parentheses"
exprErrorBadExpression = "Bad Expression"
exprErrorFinalValueNotBool = "Expression evaluated to a non-bool: %v"
exprErrorNotEnoughOperands = "Not enough operands for operation %q"
exprErrorValueNotFound = "Value for %q not found"
exprErrorBadValue = "Bad value %q for type %q"
exprErrorPathValueNotScalar = "Path value must be scalar value"
exprErrorMismatchedParens = "mismatched parentheses"
exprErrorBadExpression = "bad expression"
exprErrorFinalValueNotBool = "expression evaluated to a non-bool: %v"
exprErrorNotEnoughOperands = "not enough operands for operation %q"
exprErrorValueNotFound = "value for %q not found"
exprErrorBadValue = "bad value %q for type %q"
exprErrorPathValueNotScalar = "path value must be scalar value"
)
type exprErrorBadTypeComparison struct {
@ -141,15 +141,16 @@ func evaluatePostFix(postFixItems []Item, pathValues map[string]Item) (interface
if !ok {
return false, fmt.Errorf(exprErrorValueNotFound, string(item.val))
}
switch i.typ {
case jsonNull:
s.push(nil)
case jsonNumber:
val_float, err := strconv.ParseFloat(string(i.val), 64)
valFloat, err := strconv.ParseFloat(string(i.val), 64)
if err != nil {
return false, fmt.Errorf(exprErrorBadValue, string(item.val), jsonTokenNames[jsonNumber])
}
s.push(val_float)
s.push(valFloat)
case jsonKey, jsonString:
s.push(i.val)
default:
@ -173,14 +174,15 @@ func evaluatePostFix(postFixItems []Item, pathValues map[string]Item) (interface
if !ok {
return false, fmt.Errorf(exprErrorNotEnoughOperands, exprTokenNames[item.typ])
}
switch p.(type) {
case nil:
err := take2Null(s, item.typ)
if err != nil {
return false, err
} else {
s.push(true)
}
s.push(true)
case bool:
a, b, err := take2Bool(s, item.typ)
if err != nil {
@ -205,14 +207,15 @@ func evaluatePostFix(postFixItems []Item, pathValues map[string]Item) (interface
if !ok {
return false, fmt.Errorf(exprErrorNotEnoughOperands, exprTokenNames[item.typ])
}
switch p.(type) {
case nil:
err := take2Null(s, item.typ)
if err != nil {
return true, err
} else {
s.push(false)
}
s.push(false)
case bool:
a, b, err := take2Bool(s, item.typ)
if err != nil {
@ -363,9 +366,9 @@ func take1Bool(s *stack, op int) (bool, error) {
}
func take2Bool(s *stack, op int) (bool, bool, error) {
a, a_err := take1Bool(s, op)
b, b_err := take1Bool(s, op)
return a, b, firstError(a_err, b_err)
a, aErr := take1Bool(s, op)
b, bErr := take1Bool(s, op)
return a, b, firstError(aErr, bErr)
}
func take1Float(s *stack, op int) (float64, error) {
@ -383,9 +386,9 @@ func take1Float(s *stack, op int) (float64, error) {
}
func take2Float(s *stack, op int) (float64, float64, error) {
a, a_err := take1Float(s, op)
b, b_err := take1Float(s, op)
return a, b, firstError(a_err, b_err)
a, aErr := take1Float(s, op)
b, bErr := take1Float(s, op)
return a, b, firstError(aErr, bErr)
}
func take1ByteSlice(s *stack, op int) ([]byte, error) {
@ -403,9 +406,9 @@ func take1ByteSlice(s *stack, op int) ([]byte, error) {
}
func take2ByteSlice(s *stack, op int) ([]byte, []byte, error) {
a, a_err := take1ByteSlice(s, op)
b, b_err := take1ByteSlice(s, op)
return a, b, firstError(a_err, b_err)
a, aErr := take1ByteSlice(s, op)
b, bErr := take1ByteSlice(s, op)
return a, b, firstError(aErr, bErr)
}
func take1Null(s *stack, op int) error {
@ -422,7 +425,7 @@ func take1Null(s *stack, op int) error {
}
func take2Null(s *stack, op int) error {
a_err := take1Null(s, op)
b_err := take1Null(s, op)
return firstError(a_err, b_err)
aErr := take1Null(s, op)
bErr := take1Null(s, op)
return firstError(aErr, bErr)
}

View File

@ -149,9 +149,9 @@ func TestExpressions(t *testing.T) {
items := readerToArray(lexer)
// trim EOF
items = items[0 : len(items)-1]
items_post, err := infixToPostFix(items)
itemsPost, err := infixToPostFix(items)
if as.NoError(err, "Could not transform to postfix\nTest: %q", test.input) {
val, err := evaluatePostFix(items_post, test.fields)
val, err := evaluatePostFix(itemsPost, test.fields)
if as.NoError(err, "Could not evaluate postfix\nTest Input: %q\nTest Values:%q\nError:%q", test.input, test.fields, err) {
as.EqualValues(test.expectedValue, val, "\nTest: %q\nActual: %v \nExpected %v\n", test.input, val, test.expectedValue)
}
@ -165,8 +165,8 @@ var exprErrorTests = []struct {
expectedErrorSubstring string
}{
{"@a == @b", map[string]Item{"@a": genValue(`"one"`, jsonString), "@b": genValue("3.4", jsonNumber)}, "cannot be compared"},
{")(", nil, "Mismatched parentheses"},
{")123", nil, "Mismatched parentheses"},
{")(", nil, "mismatched parentheses"},
{")123", nil, "mismatched parentheses"},
{"20 == null", nil, "cannot be compared"},
{`"toronto" == null`, nil, "cannot be compared"},
{`false == 20`, nil, "cannot be compared"},
@ -175,9 +175,9 @@ var exprErrorTests = []struct {
{`"toronto" != null`, nil, "cannot be compared"},
{`false != 20`, nil, "cannot be compared"},
{`"nick" != 20`, nil, "cannot be compared"},
{``, nil, "Bad Expression"},
{`==`, nil, "Bad Expression"},
{`!=`, nil, "Not enough operands"},
{``, nil, "bad expression"},
{`==`, nil, "bad expression"},
{`!=`, nil, "not enough operands"},
{`!23`, nil, "cannot be compared"},
{`"nick" || true`, nil, "cannot be compared"},
@ -210,13 +210,13 @@ func TestBadExpressions(t *testing.T) {
items := readerToArray(lexer)
// trim EOF
items = items[0 : len(items)-1]
items_post, err := infixToPostFix(items)
itemsPost, err := infixToPostFix(items)
if err != nil {
as.True(strings.Contains(err.Error(), test.expectedErrorSubstring), "Test Input: %q\nError %q does not contain %q", test.input, err.Error(), test.expectedErrorSubstring)
continue
}
if as.NoError(err, "Could not transform to postfix\nTest: %q", test.input) {
_, err := evaluatePostFix(items_post, test.fields)
_, err := evaluatePostFix(itemsPost, test.fields)
if as.Error(err, "Could not evaluate postfix\nTest Input: %q\nTest Values:%q\nError:%s", test.input, test.fields, err) {
as.True(strings.Contains(err.Error(), test.expectedErrorSubstring), "Test Input: %q\nError %s does not contain %q", test.input, err.Error(), test.expectedErrorSubstring)
}

View File

@ -134,9 +134,9 @@ func stateJSONAfterValue(l lexer, state *intStack) stateFn {
case jsonBracketLeft:
return stateJSONValue
case noValue:
return l.errorf("Found %#U outside of array or object", cur)
return l.errorf("found %#U outside of array or object", cur)
default:
return l.errorf("Unexpected character in lexer stack: %#U", cur)
return l.errorf("unexpected character in lexer stack: %#U", cur)
}
case '}':
l.emit(jsonBraceRight)
@ -145,7 +145,7 @@ func stateJSONAfterValue(l lexer, state *intStack) stateFn {
case jsonBraceLeft:
return stateJSONAfterValue
case jsonBracketLeft:
return l.errorf("Unexpected %#U in array", cur)
return l.errorf("unexpected %#U in array", cur)
case noValue:
return stateJSONAfterRoot
}
@ -154,7 +154,7 @@ func stateJSONAfterValue(l lexer, state *intStack) stateFn {
state.pop()
switch topVal {
case jsonBraceLeft:
return l.errorf("Unexpected %#U in object", cur)
return l.errorf("unexpected %#U in object", cur)
case jsonBracketLeft:
return stateJSONAfterValue
case noValue:
@ -164,11 +164,11 @@ func stateJSONAfterValue(l lexer, state *intStack) stateFn {
if state.len() == 0 {
l.emit(jsonEOF)
return nil
} else {
return l.errorf("Unexpected EOF instead of value")
}
return l.errorf("unexpected EOF instead of value")
default:
return l.errorf("Unexpected character after json value token: %#U", cur)
return l.errorf("unexpected character after json value token: %#U", cur)
}
return nil
}

View File

@ -8,7 +8,7 @@ import (
"io"
)
type readerLexer struct {
type ReaderLexer struct {
lex
bufInput *bufio.Reader
input io.Reader
@ -17,8 +17,8 @@ type readerLexer struct {
lexeme *bytes.Buffer
}
func NewReaderLexer(rr io.Reader, initial stateFn) *readerLexer {
l := readerLexer{
func NewReaderLexer(rr io.Reader, initial stateFn) *ReaderLexer {
l := ReaderLexer{
input: rr,
bufInput: bufio.NewReader(rr),
nextByte: noValue,
@ -28,7 +28,7 @@ func NewReaderLexer(rr io.Reader, initial stateFn) *readerLexer {
return &l
}
func (l *readerLexer) take() int {
func (l *ReaderLexer) take() int {
if l.nextByte == noValue {
l.peek()
}
@ -39,10 +39,10 @@ func (l *readerLexer) take() int {
return nr
}
func (l *readerLexer) takeString() error {
func (l *ReaderLexer) takeString() error {
cur := l.take()
if cur != '"' {
return fmt.Errorf("Expected \" as start of string instead of %#U", cur)
return fmt.Errorf("expected \" as start of string instead of %#U", cur)
}
var previous byte
@ -50,7 +50,7 @@ looper:
for {
curByte, err := l.bufInput.ReadByte()
if err == io.EOF {
return errors.New("Unexpected EOF in string")
return errors.New("unexpected EOF in string")
}
l.lexeme.WriteByte(curByte)
@ -60,7 +60,7 @@ looper:
} else {
curByte, err = l.bufInput.ReadByte()
if err == io.EOF {
return errors.New("Unexpected EOF in string")
return errors.New("unexpected EOF in string")
}
l.lexeme.WriteByte(curByte)
}
@ -71,7 +71,7 @@ looper:
return nil
}
func (l *readerLexer) peek() int {
func (l *ReaderLexer) peek() int {
if l.nextByte != noValue {
return l.nextByte
}
@ -86,7 +86,7 @@ func (l *readerLexer) peek() int {
return l.nextByte
}
func (l *readerLexer) emit(t int) {
func (l *ReaderLexer) emit(t int) {
l.setItem(t, l.pos, l.lexeme.Bytes())
l.pos += Pos(l.lexeme.Len())
l.hasItem = true
@ -117,18 +117,18 @@ func (l *readerLexer) emit(t int) {
}
}
func (l *readerLexer) setItem(typ int, pos Pos, val []byte) {
func (l *ReaderLexer) setItem(typ int, pos Pos, val []byte) {
l.item.typ = typ
l.item.pos = pos
l.item.val = val
}
func (l *readerLexer) ignore() {
func (l *ReaderLexer) ignore() {
l.pos += Pos(l.lexeme.Len())
l.lexeme.Reset()
}
func (l *readerLexer) next() (*Item, bool) {
func (l *ReaderLexer) next() (*Item, bool) {
l.lexeme.Reset()
for {
if l.currentStateFn == nil {
@ -145,14 +145,14 @@ func (l *readerLexer) next() (*Item, bool) {
return &l.item, false
}
func (l *readerLexer) errorf(format string, args ...interface{}) stateFn {
func (l *ReaderLexer) errorf(format string, args ...interface{}) stateFn {
l.setItem(lexError, l.pos, []byte(fmt.Sprintf(format, args...)))
l.lexeme.Truncate(0)
l.hasItem = true
return nil
}
func (l *readerLexer) reset() {
func (l *ReaderLexer) reset() {
l.bufInput.Reset(l.input)
l.lexeme.Reset()
l.nextByte = noValue

View File

@ -5,31 +5,31 @@ import (
"fmt"
)
type sliceLexer struct {
type SliceLexer struct {
lex
input []byte // the []byte being scanned.
start Pos // start position of this Item.
pos Pos // current position in the input
}
func NewSliceLexer(input []byte, initial stateFn) *sliceLexer {
l := &sliceLexer{
func NewSliceLexer(input []byte, initial stateFn) *SliceLexer {
l := &SliceLexer{
lex: newLex(initial),
input: input,
}
return l
}
func (l *sliceLexer) take() int {
func (l *SliceLexer) take() int {
if int(l.pos) >= len(l.input) {
return eof
}
r := int(l.input[l.pos])
l.pos += 1
l.pos++
return r
}
func (l *sliceLexer) takeString() error {
func (l *SliceLexer) takeString() error {
curPos := l.pos
inputLen := len(l.input)
@ -67,14 +67,14 @@ looper:
return nil
}
func (l *sliceLexer) peek() int {
func (l *SliceLexer) peek() int {
if int(l.pos) >= len(l.input) {
return eof
}
return int(l.input[l.pos])
}
func (l *sliceLexer) emit(t int) {
func (l *SliceLexer) emit(t int) {
l.setItem(t, l.start, l.input[l.start:l.pos])
l.hasItem = true
@ -91,17 +91,17 @@ func (l *sliceLexer) emit(t int) {
l.start = l.pos
}
func (l *sliceLexer) setItem(typ int, pos Pos, val []byte) {
func (l *SliceLexer) setItem(typ int, pos Pos, val []byte) {
l.item.typ = typ
l.item.pos = pos
l.item.val = val
}
func (l *sliceLexer) ignore() {
func (l *SliceLexer) ignore() {
l.start = l.pos
}
func (l *sliceLexer) next() (*Item, bool) {
func (l *SliceLexer) next() (*Item, bool) {
for {
if l.currentStateFn == nil {
break
@ -117,14 +117,14 @@ func (l *sliceLexer) next() (*Item, bool) {
return &l.item, false
}
func (l *sliceLexer) errorf(format string, args ...interface{}) stateFn {
func (l *SliceLexer) errorf(format string, args ...interface{}) stateFn {
l.setItem(lexError, l.start, []byte(fmt.Sprintf(format, args...)))
l.start = l.pos
l.hasItem = true
return nil
}
func (l *sliceLexer) reset() {
func (l *SliceLexer) reset() {
l.start = 0
l.pos = 0
l.lex = newLex(l.initialState)

27
path.go
View File

@ -33,6 +33,7 @@ type operator struct {
whereClause []Item
}
// nolint:gocognit
func genIndexKey(tr tokenReader) (*operator, error) {
k := &operator{}
var t *Item
@ -63,34 +64,36 @@ func genIndexKey(tr tokenReader) (*operator, error) {
if t, ok = tr.next(); !ok {
return nil, errors.New("Expected number or *, but got none")
}
switch t.typ {
case pathIndexRange:
if t, ok = tr.next(); !ok {
return nil, errors.New("Expected number or *, but got none")
return nil, errors.New("expected number or *, but got none")
}
switch t.typ {
case pathIndex:
v, err := strconv.Atoi(string(t.val))
if err != nil {
return nil, fmt.Errorf("Could not parse %q into int64", t.val)
return nil, fmt.Errorf("could not parse %q into int64", t.val)
}
k.indexEnd = v - 1
k.hasIndexEnd = true
if t, ok = tr.next(); !ok || t.typ != pathBracketRight {
return nil, errors.New("Expected ], but got none")
return nil, errors.New("expected ], but got none")
}
case pathBracketRight:
k.hasIndexEnd = false
default:
return nil, fmt.Errorf("Unexpected value within brackets after index: %q", t.val)
return nil, fmt.Errorf("unexpected value within brackets after index: %q", t.val)
}
k.typ = opTypeIndexRange
case pathBracketRight:
k.typ = opTypeIndex
default:
return nil, fmt.Errorf("Unexpected value within brackets after index: %q", t.val)
return nil, fmt.Errorf("unexpected value within brackets after index: %q", t.val)
}
case pathKey:
k.keyStrings = map[string]struct{}{
@ -99,10 +102,10 @@ func genIndexKey(tr tokenReader) (*operator, error) {
k.typ = opTypeName
if t, ok = tr.next(); !ok || t.typ != pathBracketRight {
return nil, errors.New("Expected ], but got none")
return nil, errors.New("expected ], but got none")
}
default:
return nil, fmt.Errorf("Unexpected value within brackets: %q", t.val)
return nil, fmt.Errorf("unexpected value within brackets: %q", t.val)
}
return k, nil
@ -166,21 +169,26 @@ func tokensToOperators(tr tokenReader) (*Path, error) {
return nil, errors.New("Unexpected root node after start")
}
continue
case pathCurrent:
if len(q.operators) != 0 {
return nil, errors.New("Unexpected current node after start")
}
continue
case pathPeriod:
continue
case pathBracketLeft:
k, err := genIndexKey(tr)
if err != nil {
return nil, err
}
q.operators = append(q.operators, k)
case pathKey:
keyName := p.val
if len(p.val) == 0 {
return nil, fmt.Errorf("Key length is zero at %d", p.pos)
}
@ -196,11 +204,15 @@ func tokensToOperators(tr tokenReader) (*Path, error) {
},
},
)
case pathWildcard:
q.operators = append(q.operators, &operator{typ: opTypeNameWild})
case pathValue:
q.captureEndValue = true
case pathWhere:
case pathExpression:
if len(q.operators) == 0 {
return nil, errors.New("Cannot add where clause on last key")
@ -210,6 +222,7 @@ func tokensToOperators(tr tokenReader) (*Path, error) {
return nil, errors.New("Expression on last key already set")
}
last.whereClauseBytes = p.val
case pathError:
return q, errors.New(string(p.val))
}

View File

@ -9,7 +9,7 @@ type Results struct {
func newResults() *Results {
return &Results{
nodes: make([]*Result, 3, 3),
nodes: make([]*Result, 3),
}
}