1package yqlib 2 3import ( 4 "errors" 5 6 logging "gopkg.in/op/go-logging.v1" 7) 8 9type expressionPostFixer interface { 10 ConvertToPostfix([]*token) ([]*Operation, error) 11} 12 13type expressionPostFixerImpl struct { 14} 15 16func newExpressionPostFixer() expressionPostFixer { 17 return &expressionPostFixerImpl{} 18} 19 20func popOpToResult(opStack []*token, result []*Operation) ([]*token, []*Operation) { 21 var newOp *token 22 opStack, newOp = opStack[0:len(opStack)-1], opStack[len(opStack)-1] 23 log.Debugf("popped %v from opstack to results", newOp.toString(true)) 24 return opStack, append(result, newOp.Operation) 25} 26 27func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) { 28 var result []*Operation 29 // surround the whole thing with brackets 30 var opStack = []*token{{TokenType: openBracket}} 31 var tokens = append(infixTokens, &token{TokenType: closeBracket}) 32 33 for _, currentToken := range tokens { 34 log.Debugf("postfix processing currentToken %v", currentToken.toString(true)) 35 switch currentToken.TokenType { 36 case openBracket, openCollect, openCollectObject: 37 opStack = append(opStack, currentToken) 38 log.Debugf("put %v onto the opstack", currentToken.toString(true)) 39 case closeCollect, closeCollectObject: 40 var opener tokenType = openCollect 41 var collectOperator *operationType = collectOpType 42 if currentToken.TokenType == closeCollectObject { 43 opener = openCollectObject 44 collectOperator = collectObjectOpType 45 } 46 47 for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener { 48 opStack, result = popOpToResult(opStack, result) 49 } 50 if len(opStack) == 0 { 51 return nil, errors.New("Bad path expression, got close collect brackets without matching opening bracket") 52 } 53 // now we should have [ as the last element on the opStack, get rid of it 54 opStack = opStack[0 : len(opStack)-1] 55 log.Debugf("deleteing open bracket from opstack") 56 57 //and append a collect to the opStack 58 result = append(result, &Operation{OperationType: collectOperator}) 59 log.Debugf("put collect onto the result") 60 result = append(result, &Operation{OperationType: shortPipeOpType}) 61 log.Debugf("put shortpipe onto the result") 62 63 case closeBracket: 64 for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != openBracket { 65 opStack, result = popOpToResult(opStack, result) 66 } 67 if len(opStack) == 0 { 68 return nil, errors.New("Bad path expression, got close brackets without matching opening bracket") 69 } 70 // now we should have ( as the last element on the opStack, get rid of it 71 opStack = opStack[0 : len(opStack)-1] 72 73 default: 74 var currentPrecedence = currentToken.Operation.OperationType.Precedence 75 // pop off higher precedent operators onto the result 76 for len(opStack) > 0 && 77 opStack[len(opStack)-1].TokenType == operationToken && 78 opStack[len(opStack)-1].Operation.OperationType.Precedence > currentPrecedence { 79 opStack, result = popOpToResult(opStack, result) 80 } 81 // add this operator to the opStack 82 opStack = append(opStack, currentToken) 83 log.Debugf("put %v onto the opstack", currentToken.toString(true)) 84 } 85 } 86 87 if log.IsEnabledFor(logging.DEBUG) { 88 log.Debugf("PostFix Result:") 89 for _, currentToken := range result { 90 log.Debugf("> %v", currentToken.toString()) 91 } 92 } 93 94 return result, nil 95} 96