diff --git a/pkg/yqlib/path_tokeniser.go b/pkg/yqlib/path_tokeniser.go index a51d026..a3d64e6 100644 --- a/pkg/yqlib/path_tokeniser.go +++ b/pkg/yqlib/path_tokeniser.go @@ -1,6 +1,7 @@ package yqlib import ( + "fmt" "strconv" lex "github.com/timtadh/lexmachine" @@ -288,7 +289,7 @@ func (p *pathTokeniser) Tokenise(path string) ([]*Token, error) { scanner, err := p.lexer.Scanner([]byte(path)) if err != nil { - return nil, err + return nil, fmt.Errorf("Parsing expression: %v", err) } var tokens []*Token for tok, err, eof := scanner.Next(); !eof; tok, err, eof = scanner.Next() { @@ -299,7 +300,7 @@ func (p *pathTokeniser) Tokenise(path string) ([]*Token, error) { tokens = append(tokens, token) } if err != nil { - return nil, err + return nil, fmt.Errorf("Parsing expression: %v", err) } } var postProcessedTokens = make([]*Token, 0) diff --git a/pkg/yqlib/path_tree.go b/pkg/yqlib/path_tree.go index 3cb5ada..a9d1ea0 100644 --- a/pkg/yqlib/path_tree.go +++ b/pkg/yqlib/path_tree.go @@ -1,6 +1,9 @@ package yqlib -import "fmt" +import ( + "fmt" + "strings" +) var myPathTokeniser = NewPathTokeniser() var myPathPostfixer = NewPathPostFixer() @@ -49,10 +52,16 @@ func (p *pathTreeCreator) CreatePathTree(postFixPath []*Operation) (*PathTreeNod if Operation.OperationType.NumArgs > 0 { numArgs := Operation.OperationType.NumArgs if numArgs == 1 { + if len(stack) < 1 { + return nil, fmt.Errorf("'%v' expects 1 arg but received none", strings.TrimSpace(Operation.StringValue)) + } remaining, rhs := stack[:len(stack)-1], stack[len(stack)-1] newNode.Rhs = rhs stack = remaining } else if numArgs == 2 { + if len(stack) < 2 { + return nil, fmt.Errorf("'%v' expects 2 args but there is %v", strings.TrimSpace(Operation.StringValue), len(stack)) + } remaining, lhs, rhs := stack[:len(stack)-2], stack[len(stack)-2], stack[len(stack)-1] newNode.Lhs = lhs newNode.Rhs = rhs diff --git a/pkg/yqlib/path_tree_test.go b/pkg/yqlib/path_tree_test.go new file mode 100644 index 0000000..bd5d618 --- /dev/null +++ b/pkg/yqlib/path_tree_test.go @@ -0,0 +1,37 @@ +package yqlib + +import ( + "testing" + + "github.com/mikefarah/yq/v4/test" +) + +func TestPathTreeNoArgsForTwoArgOp(t *testing.T) { + _, err := treeCreator.ParsePath("=") + test.AssertResultComplex(t, "'=' expects 2 args but there is 0", err.Error()) +} + +func TestPathTreeOneLhsArgsForTwoArgOp(t *testing.T) { + _, err := treeCreator.ParsePath(".a =") + test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error()) +} + +func TestPathTreeOneRhsArgsForTwoArgOp(t *testing.T) { + _, err := treeCreator.ParsePath("= .a") + test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error()) +} + +func TestPathTreeTwoArgsForTwoArgOp(t *testing.T) { + _, err := treeCreator.ParsePath(".a = .b") + test.AssertResultComplex(t, nil, err) +} + +func TestPathTreeNoArgsForOneArgOp(t *testing.T) { + _, err := treeCreator.ParsePath("explode") + test.AssertResultComplex(t, "'explode' expects 1 arg but received none", err.Error()) +} + +func TestPathTreeOneArgForOneArgOp(t *testing.T) { + _, err := treeCreator.ParsePath("explode(.)") + test.AssertResultComplex(t, nil, err) +}