2020-10-08 23:59:03 +00:00
|
|
|
package treeops
|
2020-09-20 12:40:09 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2020-10-17 11:10:47 +00:00
|
|
|
|
|
|
|
"gopkg.in/op/go-logging.v1"
|
2020-09-20 12:40:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type PathPostFixer interface {
|
2020-10-11 00:24:22 +00:00
|
|
|
ConvertToPostfix([]*Token) ([]*PathElement, error)
|
2020-09-20 12:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type pathPostFixer struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewPathPostFixer() PathPostFixer {
|
|
|
|
return &pathPostFixer{}
|
|
|
|
}
|
|
|
|
|
2020-10-11 00:24:22 +00:00
|
|
|
func popOpToResult(opStack []*Token, result []*PathElement) ([]*Token, []*PathElement) {
|
2020-10-20 02:53:26 +00:00
|
|
|
var newOp *Token
|
|
|
|
opStack, newOp = opStack[0:len(opStack)-1], opStack[len(opStack)-1]
|
|
|
|
var pathElement = PathElement{OperationType: newOp.OperationType, Value: newOp.Value, StringValue: newOp.StringValue}
|
|
|
|
|
|
|
|
if newOp.OperationType == ValueOp {
|
|
|
|
var candidateNode = BuildCandidateNodeFrom(newOp)
|
|
|
|
pathElement.CandidateNode = candidateNode
|
|
|
|
}
|
|
|
|
|
2020-09-20 12:40:09 +00:00
|
|
|
return opStack, append(result, &pathElement)
|
|
|
|
}
|
|
|
|
|
2020-10-11 00:24:22 +00:00
|
|
|
func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*PathElement, error) {
|
2020-09-20 12:40:09 +00:00
|
|
|
var result []*PathElement
|
|
|
|
// surround the whole thing with quotes
|
2020-10-20 02:53:26 +00:00
|
|
|
var opStack = []*Token{&Token{TokenType: OpenBracket, Value: "("}}
|
|
|
|
var tokens = append(infixTokens, &Token{TokenType: CloseBracket, Value: ")"})
|
2020-09-20 12:40:09 +00:00
|
|
|
|
|
|
|
for _, token := range tokens {
|
2020-10-16 01:29:26 +00:00
|
|
|
log.Debugf("postfix processing token %v", token.Value)
|
2020-10-20 02:53:26 +00:00
|
|
|
switch token.TokenType {
|
2020-10-16 01:29:26 +00:00
|
|
|
case OpenBracket, OpenCollect:
|
2020-09-20 12:40:09 +00:00
|
|
|
opStack = append(opStack, token)
|
2020-10-16 01:29:26 +00:00
|
|
|
case CloseCollect:
|
2020-10-20 02:53:26 +00:00
|
|
|
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != OpenCollect {
|
2020-10-16 01:29:26 +00:00
|
|
|
opStack, result = popOpToResult(opStack, result)
|
|
|
|
}
|
|
|
|
if len(opStack) == 0 {
|
|
|
|
return nil, errors.New("Bad path expression, got close collect brackets without matching opening bracket")
|
|
|
|
}
|
2020-10-17 11:10:47 +00:00
|
|
|
// now we should have [] as the last element on the opStack, get rid of it
|
2020-10-16 01:29:26 +00:00
|
|
|
opStack = opStack[0 : len(opStack)-1]
|
|
|
|
//and append a collect to the opStack
|
2020-10-20 02:53:26 +00:00
|
|
|
opStack = append(opStack, &Token{TokenType: Operation, OperationType: Pipe})
|
|
|
|
opStack = append(opStack, &Token{TokenType: Operation, OperationType: Collect})
|
2020-10-11 00:24:22 +00:00
|
|
|
case CloseBracket:
|
2020-10-20 02:53:26 +00:00
|
|
|
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != OpenBracket {
|
2020-09-20 12:40:09 +00:00
|
|
|
opStack, result = popOpToResult(opStack, result)
|
|
|
|
}
|
|
|
|
if len(opStack) == 0 {
|
|
|
|
return nil, errors.New("Bad path expression, got close brackets without matching opening bracket")
|
|
|
|
}
|
|
|
|
// now we should have ( as the last element on the opStack, get rid of it
|
|
|
|
opStack = opStack[0 : len(opStack)-1]
|
2020-10-11 00:24:22 +00:00
|
|
|
|
2020-10-10 04:24:37 +00:00
|
|
|
default:
|
2020-10-11 23:44:33 +00:00
|
|
|
var currentPrecedence = token.OperationType.Precedence
|
2020-10-10 04:24:37 +00:00
|
|
|
// pop off higher precedent operators onto the result
|
2020-10-11 23:44:33 +00:00
|
|
|
for len(opStack) > 0 && opStack[len(opStack)-1].OperationType.Precedence >= currentPrecedence {
|
2020-10-10 04:24:37 +00:00
|
|
|
opStack, result = popOpToResult(opStack, result)
|
|
|
|
}
|
|
|
|
// add this operator to the opStack
|
|
|
|
opStack = append(opStack, token)
|
2020-09-20 12:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-10-17 11:10:47 +00:00
|
|
|
|
|
|
|
if log.IsEnabledFor(logging.DEBUG) {
|
|
|
|
log.Debugf("PostFix Result:")
|
|
|
|
for _, token := range result {
|
|
|
|
log.Debugf("> %v", token.toString())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-20 12:40:09 +00:00
|
|
|
return result, nil
|
|
|
|
}
|