postfix with traverse op

This commit is contained in:
Mike Farah 2020-09-24 13:20:02 +10:00
parent 95bc1e1599
commit c2159d9861
3 changed files with 61 additions and 47 deletions

View File

@ -21,31 +21,28 @@ type OperationType uint32
const ( const (
None OperationType = 1 << iota None OperationType = 1 << iota
Traverse
Or Or
And And
Equals Equals
EqualsSelf
) )
type PathElement struct { type PathElement struct {
PathElementType PathElementType PathElementType PathElementType
OperationType OperationType OperationType OperationType
Value interface{} Value interface{}
ChildElements [][]*PathElement
Finished bool Finished bool
} }
// debugging purposes only // debugging purposes only
func (p *PathElement) toString() string { func (p *PathElement) toString() string {
var result string = `Type: ` var result string = ``
switch p.PathElementType { switch p.PathElementType {
case PathKey: case PathKey:
result = result + fmt.Sprintf("PathKey - %v", p.Value) result = result + fmt.Sprintf("PathKey - '%v'\n", p.Value)
for _, next := range p.ChildElements[0] {
result = result + fmt.Sprintf(".%v", next.Value)
}
result = result + "\n"
case ArrayIndex: case ArrayIndex:
result = result + fmt.Sprintf("ArrayIndex - %v\n", p.Value) result = result + fmt.Sprintf("ArrayIndex - '%v'\n", p.Value)
case Operation: case Operation:
result = result + "Operation - " result = result + "Operation - "
switch p.OperationType { switch p.OperationType {
@ -55,7 +52,12 @@ func (p *PathElement) toString() string {
result = result + "AND\n" result = result + "AND\n"
case Equals: case Equals:
result = result + "EQUALS\n" result = result + "EQUALS\n"
case EqualsSelf:
result = result + "EQUALS SELF\n"
case Traverse:
result = result + "TRAVERSE\n"
} }
} }
return result return result
} }
@ -76,11 +78,16 @@ func initMaps() {
precedenceMap[TokenIds["EQUALS_OPERATOR"]] = 30 precedenceMap[TokenIds["EQUALS_OPERATOR"]] = 30
operationTypeMapper[TokenIds["EQUALS_OPERATOR"]] = Equals 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 { func createOperationPathElement(opToken *lex.Token) PathElement {
var childElements = make([][]*PathElement, 2) var pathElement = PathElement{PathElementType: Operation, OperationType: operationTypeMapper[opToken.Type]}
var pathElement = PathElement{PathElementType: Operation, OperationType: operationTypeMapper[opToken.Type], ChildElements: childElements}
return pathElement return pathElement
} }
@ -119,22 +126,15 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*lex.Token) ([]*PathEleme
for _, token := range tokens { for _, token := range tokens {
switch token.Type { switch token.Type {
case TokenIds["PATH_KEY"]: // handle splats and array appends here too 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}
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) result = append(result, &pathElement)
}
case TokenIds["("]: case TokenIds["("]:
opStack = append(opStack, token) opStack = append(opStack, token)
finishPathKey(result) 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] var currentPrecedence = precedenceMap[token.Type]
// pop off higher precedent operators onto the result // 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) opStack, result = popOpToResult(opStack, result)
} }
// add this operator to the opStack // add this operator to the opStack

View File

@ -25,9 +25,9 @@ func testExpression(expression string) (string, error) {
return formatted, nil return formatted, nil
} }
func TestPostFixSimple(t *testing.T) { func TestPostFixSimpleExample(t *testing.T) {
var infix = "a" 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) test.AssertResultComplex(t, expectedOutput, actual)
} }
func TestPostFixSimplePath(t *testing.T) { func TestPostFixSimplePathExample(t *testing.T) {
var infix = "apples.bananas*.cat" 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) test.AssertResultComplex(t, expectedOutput, actual)
} }
func TestPostFixOr(t *testing.T) { func TestPostFixOrExample(t *testing.T) {
var infix = "a OR b" 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) test.AssertResultComplex(t, expectedOutput, actual)
} }
func TestPostFixOrWithEquals(t *testing.T) { func TestPostFixOrWithEqualsExample(t *testing.T) {
var infix = "a==thing OR b==thongs" 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) 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 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
-------- --------
` `

View File

@ -25,8 +25,6 @@ func initTokens() {
")", ")",
} }
Tokens = []string{ Tokens = []string{
"BEGIN_SUB_EXPRESSION",
"END_SUB_EXPRESSION",
"OR_OPERATOR", "OR_OPERATOR",
"AND_OPERATOR", "AND_OPERATOR",
"EQUALS_OPERATOR", "EQUALS_OPERATOR",