ops first class

This commit is contained in:
Mike Farah 2020-10-12 10:44:33 +11:00
parent 7c4cf72468
commit 288aec942c
6 changed files with 67 additions and 113 deletions

View File

@ -7,8 +7,7 @@ import (
)
type dataTreeNavigator struct {
leafTraverser LeafTraverser
operatorHandlers map[OperationType]OperatorHandler
leafTraverser LeafTraverser
}
type NavigationPrefs struct {
@ -21,16 +20,7 @@ type DataTreeNavigator interface {
func NewDataTreeNavigator(navigationPrefs NavigationPrefs) DataTreeNavigator {
leafTraverser := NewLeafTraverser(navigationPrefs)
operatorHandlers := make(map[OperationType]OperatorHandler)
operatorHandlers[Traverse] = TraverseOperator
operatorHandlers[Equals] = EqualsOperator
operatorHandlers[Or] = UnionOperator
operatorHandlers[And] = IntersectionOperator
operatorHandlers[Assign] = AssignOperator
operatorHandlers[DeleteChild] = DeleteChildOperator
return &dataTreeNavigator{leafTraverser, operatorHandlers}
return &dataTreeNavigator{leafTraverser}
}
func (d *dataTreeNavigator) traverse(matchMap *orderedmap.OrderedMap, pathNode *PathElement) (*orderedmap.OrderedMap, error) {
@ -79,7 +69,7 @@ func (d *dataTreeNavigator) getMatchingNodes(matchingNodes *orderedmap.OrderedMa
} else if pathNode.PathElement.PathElementType == PathKey || pathNode.PathElement.PathElementType == ArrayIndex {
return d.traverse(matchingNodes, pathNode.PathElement)
} else {
handler := d.operatorHandlers[pathNode.PathElement.OperationType]
handler := pathNode.PathElement.OperationType.Handler
if handler != nil {
return handler(d, matchingNodes, pathNode)
}

View File

@ -220,7 +220,7 @@ func TestDataTreeNavigatorDeleteViaSelf(t *testing.T) {
- sdfsd
- apple`)
path, errPath := treeCreator.ParsePath("(. .- .)")
path, errPath := treeCreator.ParsePath(". .- (. == apple)")
if errPath != nil {
t.Error(errPath)
}
@ -378,7 +378,7 @@ func TestDataTreeNavigatorSimpleAssignByFind(t *testing.T) {
nodes := readDoc(t, `a:
b: apple`)
path, errPath := treeCreator.ParsePath("(b == apple) := frog)")
path, errPath := treeCreator.ParsePath("a(. == apple) := frog")
if errPath != nil {
t.Error(errPath)
}

View File

@ -21,6 +21,57 @@ func (n *CandidateNode) getKey() string {
return fmt.Sprintf("%v - %v", n.Document, n.Path)
}
type PathElementType uint32
const (
PathKey PathElementType = 1 << iota
ArrayIndex
Operation
SelfReference
OpenBracket
CloseBracket
)
type OperationType struct {
Type string
NumArgs uint // number of arguments to the op
Precedence uint
Handler OperatorHandler
}
var None = &OperationType{Type: "NONE", NumArgs: 0, Precedence: 0}
var Traverse = &OperationType{Type: "TRAVERSE", NumArgs: 2, Precedence: 40, Handler: TraverseOperator}
var Or = &OperationType{Type: "OR", NumArgs: 2, Precedence: 10, Handler: UnionOperator}
var And = &OperationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: IntersectionOperator}
var Equals = &OperationType{Type: "EQUALS", NumArgs: 2, Precedence: 30, Handler: EqualsOperator}
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 35, Handler: AssignOperator}
var DeleteChild = &OperationType{Type: "DELETE", NumArgs: 2, Precedence: 30, Handler: DeleteChildOperator}
// var Length = &OperationType{Type: "Length", NumArgs: 2, Precedence: 35}
type PathElement struct {
PathElementType PathElementType
OperationType *OperationType
Value interface{}
StringValue string
}
// debugging purposes only
func (p *PathElement) toString() string {
var result string = ``
switch p.PathElementType {
case PathKey:
result = result + fmt.Sprintf("PathKey - '%v'\n", p.Value)
case ArrayIndex:
result = result + fmt.Sprintf("ArrayIndex - '%v'\n", p.Value)
case SelfReference:
result = result + fmt.Sprintf("SELF\n")
case Operation:
result = result + fmt.Sprintf("Operation - %v\n", p.OperationType.Type)
}
return result
}
type YqTreeLib interface {
Get(rootNode *yaml.Node, path string) ([]*CandidateNode, error)
// GetForMerge(rootNode *yaml.Node, path string, arrayMergeStrategy ArrayMergeStrategy) ([]*NodeContext, error)

View File

@ -129,7 +129,7 @@ func containsMatchingValue(matchMap *orderedmap.OrderedMap, valuePattern string)
for el := matchMap.Front(); el != nil; el = el.Next() {
node := el.Value.(*CandidateNode)
log.Debugf("-- compating %v to %v", node.Node.Value, valuePattern)
log.Debugf("-- comparing %v to %v", node.Node.Value, valuePattern)
if Match(node.Node.Value, valuePattern) {
return true
}

View File

@ -2,78 +2,8 @@ package treeops
import (
"errors"
"fmt"
)
var precedenceMap map[int]int
type PathElementType uint32
const (
PathKey PathElementType = 1 << iota
ArrayIndex
Operation
SelfReference
OpenBracket
CloseBracket
)
type OperationType uint32
const (
None OperationType = 1 << iota
Traverse
Or
And
Equals
Assign
DeleteChild
)
type PathElement struct {
PathElementType PathElementType
OperationType OperationType
Value interface{}
StringValue string
}
// debugging purposes only
func (p *PathElement) toString() string {
var result string = ``
switch p.PathElementType {
case PathKey:
result = result + fmt.Sprintf("PathKey - '%v'\n", p.Value)
case ArrayIndex:
result = result + fmt.Sprintf("ArrayIndex - '%v'\n", p.Value)
case SelfReference:
result = result + fmt.Sprintf("SELF\n")
case Operation:
result = result + "Operation - "
switch p.OperationType {
case Or:
result = result + "OR\n"
case And:
result = result + "AND\n"
case Equals:
result = result + "EQUALS\n"
case Assign:
result = result + "ASSIGN\n"
case Traverse:
result = result + "TRAVERSE\n"
case DeleteChild:
result = result + "DELETE CHILD\n"
}
}
return result
}
func createOperationPathElement(opToken *Token) PathElement {
var pathElement = PathElement{PathElementType: Operation, OperationType: opToken.OperationType}
return pathElement
}
type PathPostFixer interface {
ConvertToPostfix([]*Token) ([]*PathElement, error)
}
@ -88,15 +18,15 @@ func NewPathPostFixer() PathPostFixer {
func popOpToResult(opStack []*Token, result []*PathElement) ([]*Token, []*PathElement) {
var operatorToPushToPostFix *Token
opStack, operatorToPushToPostFix = opStack[0:len(opStack)-1], opStack[len(opStack)-1]
var pathElement = createOperationPathElement(operatorToPushToPostFix)
var pathElement = PathElement{PathElementType: Operation, OperationType: operatorToPushToPostFix.OperationType}
return opStack, append(result, &pathElement)
}
func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*PathElement, error) {
var result []*PathElement
// surround the whole thing with quotes
var opStack = []*Token{&Token{PathElementType: OpenBracket}}
var tokens = append(infixTokens, &Token{PathElementType: CloseBracket})
var opStack = []*Token{&Token{PathElementType: OpenBracket, OperationType: None}}
var tokens = append(infixTokens, &Token{PathElementType: CloseBracket, OperationType: None})
for _, token := range tokens {
switch token.PathElementType {
@ -117,9 +47,9 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*PathElement,
opStack = opStack[0 : len(opStack)-1]
default:
var currentPrecedence = p.precendenceOf(token)
var currentPrecedence = token.OperationType.Precedence
// pop off higher precedent operators onto the result
for len(opStack) > 0 && p.precendenceOf(opStack[len(opStack)-1]) >= currentPrecedence {
for len(opStack) > 0 && opStack[len(opStack)-1].OperationType.Precedence >= currentPrecedence {
opStack, result = popOpToResult(opStack, result)
}
// add this operator to the opStack
@ -128,19 +58,3 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*PathElement,
}
return result, nil
}
func (p *pathPostFixer) precendenceOf(token *Token) int {
switch token.OperationType {
case Or:
return 10
case And:
return 20
case Equals, DeleteChild:
return 30
case Assign:
return 35
case Traverse:
return 40
}
return 0
}

View File

@ -13,7 +13,7 @@ func skip(*lex.Scanner, *machines.Match) (interface{}, error) {
type Token struct {
PathElementType PathElementType
OperationType OperationType
OperationType *OperationType
Value interface{}
StringValue string
PrefixSelf bool
@ -21,7 +21,6 @@ type Token struct {
CheckForPreTraverse bool // this token can sometimes have the traverse '.' missing in frnot of it
// e.g. a[1] should really be a.[1]
CheckForPostTraverse bool // samething but for post, e.g. [1]cat should really be [1].cat
}
func pathToken(wrapped bool) lex.Action {
@ -34,7 +33,7 @@ func pathToken(wrapped bool) lex.Action {
}
}
func opToken(op OperationType, againstSelf bool) lex.Action {
func opToken(op *OperationType, againstSelf bool) lex.Action {
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
value := string(m.Bytes)
return &Token{PathElementType: Operation, OperationType: op, Value: value, StringValue: value, PrefixSelf: againstSelf}, nil
@ -43,7 +42,7 @@ func opToken(op OperationType, againstSelf bool) lex.Action {
func literalToken(pType PathElementType, literal string, checkForPre bool, checkForPost bool, againstSelf bool) lex.Action {
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
return &Token{PathElementType: pType, Value: literal, StringValue: literal, CheckForPreTraverse: checkForPre, CheckForPostTraverse: checkForPost, PrefixSelf: againstSelf}, nil
return &Token{PathElementType: pType, OperationType: None, Value: literal, StringValue: literal, CheckForPreTraverse: checkForPre, CheckForPostTraverse: checkForPost, PrefixSelf: againstSelf}, nil
}
}
@ -61,7 +60,7 @@ func arrayIndextoken(wrapped bool, checkForPre bool, checkForPost bool) lex.Acti
if errParsingInt != nil {
return nil, errParsingInt
}
return &Token{PathElementType: ArrayIndex, Value: number, StringValue: numberString, CheckForPreTraverse: checkForPre, CheckForPostTraverse: checkForPost}, nil
return &Token{PathElementType: ArrayIndex, OperationType: None, Value: number, StringValue: numberString, CheckForPreTraverse: checkForPre, CheckForPostTraverse: checkForPost}, nil
}
}
@ -130,7 +129,7 @@ func (p *pathTokeniser) Tokenise(path string) ([]*Token, error) {
if tok != nil {
token := tok.(*Token)
log.Debugf("Tokenising %v", token.Value)
log.Debugf("Tokenising %v - %v", token.Value, token.OperationType.Type)
tokens = append(tokens, token)
}
if err != nil {