diff --git a/pkg/yqlib/path_postfix.go b/pkg/yqlib/path_postfix.go index 9a036c62..50eddd03 100644 --- a/pkg/yqlib/path_postfix.go +++ b/pkg/yqlib/path_postfix.go @@ -21,31 +21,28 @@ type OperationType uint32 const ( None OperationType = 1 << iota + Traverse Or And Equals + EqualsSelf ) type PathElement struct { PathElementType PathElementType OperationType OperationType Value interface{} - ChildElements [][]*PathElement Finished bool } // debugging purposes only func (p *PathElement) toString() string { - var result string = `Type: ` + var result string = `` switch p.PathElementType { case PathKey: - result = result + fmt.Sprintf("PathKey - %v", p.Value) - for _, next := range p.ChildElements[0] { - result = result + fmt.Sprintf(".%v", next.Value) - } - result = result + "\n" + result = result + fmt.Sprintf("PathKey - '%v'\n", p.Value) case ArrayIndex: - result = result + fmt.Sprintf("ArrayIndex - %v\n", p.Value) + result = result + fmt.Sprintf("ArrayIndex - '%v'\n", p.Value) case Operation: result = result + "Operation - " switch p.OperationType { @@ -55,7 +52,12 @@ func (p *PathElement) toString() string { result = result + "AND\n" case Equals: result = result + "EQUALS\n" + case EqualsSelf: + result = result + "EQUALS SELF\n" + case Traverse: + result = result + "TRAVERSE\n" } + } return result } @@ -76,11 +78,16 @@ func initMaps() { precedenceMap[TokenIds["EQUALS_OPERATOR"]] = 30 operationTypeMapper[TokenIds["EQUALS_OPERATOR"]] = Equals + + precedenceMap[TokenIds["EQUALS_SELF_OPERATOR"]] = 30 + operationTypeMapper[TokenIds["EQUALS_SELF_OPERATOR"]] = EqualsSelf + + precedenceMap[TokenIds["TRAVERSE_OPERATOR"]] = 40 + operationTypeMapper[TokenIds["TRAVERSE_OPERATOR"]] = Traverse } func createOperationPathElement(opToken *lex.Token) PathElement { - var childElements = make([][]*PathElement, 2) - var pathElement = PathElement{PathElementType: Operation, OperationType: operationTypeMapper[opToken.Type], ChildElements: childElements} + var pathElement = PathElement{PathElementType: Operation, OperationType: operationTypeMapper[opToken.Type]} return pathElement } @@ -119,22 +126,15 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*lex.Token) ([]*PathEleme for _, token := range tokens { switch token.Type { case TokenIds["PATH_KEY"]: // handle splats and array appends here too - var emptyArray = [][]*PathElement{make([]*PathElement, 0)} - var pathElement = PathElement{PathElementType: PathKey, Value: token.Value, ChildElements: emptyArray} - - if len(result) > 0 && result[len(result)-1].PathElementType == PathKey && !result[len(result)-1].Finished { - var lastElement = result[len(result)-1] - lastElement.ChildElements[0] = append(lastElement.ChildElements[0], &pathElement) - } else { - result = append(result, &pathElement) - } + var pathElement = PathElement{PathElementType: PathKey, Value: token.Value} + result = append(result, &pathElement) case TokenIds["("]: opStack = append(opStack, token) finishPathKey(result) - case TokenIds["OR_OPERATOR"], TokenIds["AND_OPERATOR"], TokenIds["EQUALS_OPERATOR"]: + case TokenIds["OR_OPERATOR"], TokenIds["AND_OPERATOR"], TokenIds["EQUALS_OPERATOR"], TokenIds["EQUALS_SELF_OPERATOR"], TokenIds["TRAVERSE_OPERATOR"]: var currentPrecedence = precedenceMap[token.Type] // pop off higher precedent operators onto the result - for len(opStack) > 0 && precedenceMap[opStack[len(opStack)-1].Type] > currentPrecedence { + for len(opStack) > 0 && precedenceMap[opStack[len(opStack)-1].Type] >= currentPrecedence { opStack, result = popOpToResult(opStack, result) } // add this operator to the opStack diff --git a/pkg/yqlib/path_postfix_test.go b/pkg/yqlib/path_postfix_test.go index d3c6d729..39ab7b7a 100644 --- a/pkg/yqlib/path_postfix_test.go +++ b/pkg/yqlib/path_postfix_test.go @@ -25,9 +25,9 @@ func testExpression(expression string) (string, error) { return formatted, nil } -func TestPostFixSimple(t *testing.T) { +func TestPostFixSimpleExample(t *testing.T) { var infix = "a" - var expectedOutput = `Type: PathKey - a + var expectedOutput = `PathKey - 'a' -------- ` @@ -39,9 +39,17 @@ func TestPostFixSimple(t *testing.T) { test.AssertResultComplex(t, expectedOutput, actual) } -func TestPostFixSimplePath(t *testing.T) { +func TestPostFixSimplePathExample(t *testing.T) { var infix = "apples.bananas*.cat" - var expectedOutput = `Type: PathKey - apples.bananas*.cat + var expectedOutput = `PathKey - 'apples' +-------- +PathKey - 'bananas*' +-------- +Operation - TRAVERSE +-------- +PathKey - 'cat' +-------- +Operation - TRAVERSE -------- ` @@ -53,13 +61,13 @@ func TestPostFixSimplePath(t *testing.T) { test.AssertResultComplex(t, expectedOutput, actual) } -func TestPostFixOr(t *testing.T) { +func TestPostFixOrExample(t *testing.T) { var infix = "a OR b" - var expectedOutput = `Type: PathKey - a + var expectedOutput = `PathKey - 'a' -------- -Type: PathKey - b +PathKey - 'b' -------- -Type: Operation - OR +Operation - OR -------- ` @@ -71,21 +79,21 @@ Type: Operation - OR test.AssertResultComplex(t, expectedOutput, actual) } -func TestPostFixOrWithEquals(t *testing.T) { +func TestPostFixOrWithEqualsExample(t *testing.T) { var infix = "a==thing OR b==thongs" - var expectedOutput = `Type: PathKey - a + var expectedOutput = `PathKey - 'a' -------- -Type: PathKey - thing +PathKey - 'thing' -------- -Type: Operation - EQUALS +Operation - EQUALS -------- -Type: PathKey - b +PathKey - 'b' -------- -Type: PathKey - thongs +PathKey - 'thongs' -------- -Type: Operation - EQUALS +Operation - EQUALS -------- -Type: Operation - OR +Operation - OR -------- ` @@ -97,21 +105,29 @@ Type: Operation - OR test.AssertResultComplex(t, expectedOutput, actual) } -func TestPostFixOrWithEqualsPath(t *testing.T) { +func TestPostFixOrWithEqualsPathExample(t *testing.T) { var infix = "apples.monkeys==thing OR bogs.bobos==thongs" - var expectedOutput = `Type: PathKey - apples.monkeys + var expectedOutput = `PathKey - 'apples' -------- -Type: PathKey - thing +PathKey - 'monkeys' -------- -Type: Operation - EQUALS +Operation - TRAVERSE -------- -Type: PathKey - bogs.bobos +PathKey - 'thing' -------- -Type: PathKey - thongs +Operation - EQUALS -------- -Type: Operation - EQUALS +PathKey - 'bogs' -------- -Type: Operation - OR +PathKey - 'bobos' +-------- +Operation - TRAVERSE +-------- +PathKey - 'thongs' +-------- +Operation - EQUALS +-------- +Operation - OR -------- ` diff --git a/pkg/yqlib/path_tokeniser.go b/pkg/yqlib/path_tokeniser.go index ab2da6cd..d7e22932 100644 --- a/pkg/yqlib/path_tokeniser.go +++ b/pkg/yqlib/path_tokeniser.go @@ -25,8 +25,6 @@ func initTokens() { ")", } Tokens = []string{ - "BEGIN_SUB_EXPRESSION", - "END_SUB_EXPRESSION", "OR_OPERATOR", "AND_OPERATOR", "EQUALS_OPERATOR",