diff --git a/pkg/yqlib/treeops/lib.go b/pkg/yqlib/treeops/lib.go index fca412fb..f30c87dc 100644 --- a/pkg/yqlib/treeops/lib.go +++ b/pkg/yqlib/treeops/lib.go @@ -15,6 +15,7 @@ type PathElementType uint32 const ( PathKey PathElementType = 1 << iota + DocumentKey Operation SelfReference OpenBracket @@ -75,6 +76,8 @@ func (p *PathElement) toString() string { switch p.PathElementType { case PathKey: result = result + fmt.Sprintf("%v", p.Value) + case DocumentKey: + result = result + fmt.Sprintf("D%v", p.Value) case SelfReference: result = result + fmt.Sprintf("SELF") case Operation: diff --git a/pkg/yqlib/treeops/operator_collect_test.go b/pkg/yqlib/treeops/operator_collect_test.go index 3fe7535c..f2de5a05 100644 --- a/pkg/yqlib/treeops/operator_collect_test.go +++ b/pkg/yqlib/treeops/operator_collect_test.go @@ -11,6 +11,12 @@ var collectOperatorScenarios = []expressionScenario{ expected: []string{ "D0, P[], (!!seq)::- cat\n", }, + }, { + document: `{}`, + expression: `[true]`, + expected: []string{ + "D0, P[], (!!seq)::- true\n", + }, }, { document: `{}`, expression: `["cat", "dog"]`, diff --git a/pkg/yqlib/treeops/operator_multilpy.go b/pkg/yqlib/treeops/operator_multilpy.go index fa919cb5..cb5c3ff0 100644 --- a/pkg/yqlib/treeops/operator_multilpy.go +++ b/pkg/yqlib/treeops/operator_multilpy.go @@ -38,7 +38,8 @@ func MultiplyOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap } func multiply(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode { + if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode || + (lhs.Node.Kind == yaml.SequenceNode && rhs.Node.Kind == yaml.SequenceNode) { var results = orderedmap.NewOrderedMap() recursiveDecent(d, results, nodeToMap(rhs)) diff --git a/pkg/yqlib/treeops/operator_multiply_test.go b/pkg/yqlib/treeops/operator_multiply_test.go index a4c89459..f9e8adb7 100644 --- a/pkg/yqlib/treeops/operator_multiply_test.go +++ b/pkg/yqlib/treeops/operator_multiply_test.go @@ -61,6 +61,12 @@ b: also: "me" `, }, + }, { + document: `{a: [1,2,3], b: [3,4,5]}`, + expression: `.a * .b`, + expected: []string{ + "D0, P[], (!!map)::{a: [3, 4, 5], b: [3, 4, 5]}\n", + }, }, } diff --git a/pkg/yqlib/treeops/path_parse_test.go b/pkg/yqlib/treeops/path_parse_test.go index b7d56213..ec8f015c 100644 --- a/pkg/yqlib/treeops/path_parse_test.go +++ b/pkg/yqlib/treeops/path_parse_test.go @@ -39,6 +39,11 @@ var pathTests = []struct { // {`."[a", ."b]"`, append(make([]interface{}, 0), "[a", "OR", "b]")}, // {`.a[]`, append(make([]interface{}, 0), "a", "PIPE", "[]")}, // {`.[].a`, append(make([]interface{}, 0), "[]", "PIPE", "a")}, + { + `d0.a`, + append(make([]interface{}, 0), int64(0), "PIPE", "a"), + append(make([]interface{}, 0), "D0", "a", "PIPE"), + }, { `.a | (.[].b == "apple")`, append(make([]interface{}, 0), "a", "PIPE", "(", "[]", "PIPE", "b", "EQUALS", "apple", ")"), @@ -52,7 +57,7 @@ var pathTests = []struct { { `[true]`, append(make([]interface{}, 0), "[", true, "]"), - append(make([]interface{}, 0), "true (bool)", "COLLECT"), + append(make([]interface{}, 0), "true (bool)", "COLLECT", "PIPE"), }, // {".animals | .==cat", append(make([]interface{}, 0), "animals", "TRAVERSE", "SELF", "EQUALS", "cat")}, diff --git a/pkg/yqlib/treeops/path_postfix.go b/pkg/yqlib/treeops/path_postfix.go index 3688dc9f..646ecadf 100644 --- a/pkg/yqlib/treeops/path_postfix.go +++ b/pkg/yqlib/treeops/path_postfix.go @@ -37,7 +37,7 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*PathElement, var candidateNode = BuildCandidateNodeFrom(token) var pathElement = PathElement{PathElementType: token.PathElementType, Value: token.Value, StringValue: token.StringValue, CandidateNode: candidateNode} result = append(result, &pathElement) - case PathKey, SelfReference: + case PathKey, SelfReference, DocumentKey: var pathElement = PathElement{PathElementType: token.PathElementType, Value: token.Value, StringValue: token.StringValue} result = append(result, &pathElement) case OpenBracket, OpenCollect: diff --git a/pkg/yqlib/treeops/path_tokeniser.go b/pkg/yqlib/treeops/path_tokeniser.go index 25a77ee7..6cc94dac 100644 --- a/pkg/yqlib/treeops/path_tokeniser.go +++ b/pkg/yqlib/treeops/path_tokeniser.go @@ -32,6 +32,18 @@ func pathToken(wrapped bool) lex.Action { } } +func documentToken() lex.Action { + return func(s *lex.Scanner, m *machines.Match) (interface{}, error) { + var numberString = string(m.Bytes) + numberString = numberString[1:len(numberString)] + var number, errParsingInt = strconv.ParseInt(numberString, 10, 64) // nolint + if errParsingInt != nil { + return nil, errParsingInt + } + return &Token{PathElementType: DocumentKey, OperationType: None, Value: number, StringValue: numberString, CheckForPostTraverse: true}, nil + } +} + func opToken(op *OperationType) lex.Action { return func(s *lex.Scanner, m *machines.Match) (interface{}, error) { value := string(m.Bytes) @@ -136,6 +148,8 @@ func initLexer() (*lex.Lexer, error) { lexer.Add([]byte("( |\t|\n|\r)+"), skip) + lexer.Add([]byte(`d[0-9]+`), documentToken()) // $0 + lexer.Add([]byte(`\."[^ "]+"`), pathToken(true)) lexer.Add([]byte(`\.[^ \[\],\|\.\[\(\)=]+`), pathToken(false)) lexer.Add([]byte(`\.`), selfToken()) diff --git a/pkg/yqlib/treeops/temp.json b/pkg/yqlib/treeops/temp.json index fd19e6d5..7d768a0b 100644 --- a/pkg/yqlib/treeops/temp.json +++ b/pkg/yqlib/treeops/temp.json @@ -1,6 +1,4 @@ { - "a": { - "b": "apple", - "c": "cactus" - } -} + "a": [1,2], + "b": [3,4] +} \ No newline at end of file