2020-11-03 23:48:43 +00:00
|
|
|
package yqlib
|
2020-09-17 11:58:01 +00:00
|
|
|
|
|
|
|
import (
|
2020-12-17 03:02:54 +00:00
|
|
|
"fmt"
|
2020-09-17 12:12:56 +00:00
|
|
|
"strconv"
|
2021-01-13 05:54:28 +00:00
|
|
|
"strings"
|
2020-09-17 11:58:01 +00:00
|
|
|
|
|
|
|
lex "github.com/timtadh/lexmachine"
|
|
|
|
"github.com/timtadh/lexmachine/machines"
|
|
|
|
)
|
|
|
|
|
2020-10-11 00:24:22 +00:00
|
|
|
func skip(*lex.Scanner, *machines.Match) (interface{}, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2020-09-17 11:58:01 +00:00
|
|
|
|
2021-01-11 05:46:28 +00:00
|
|
|
type tokenType uint32
|
2020-10-20 02:53:26 +00:00
|
|
|
|
|
|
|
const (
|
2021-01-11 22:55:55 +00:00
|
|
|
operationToken = 1 << iota
|
|
|
|
openBracket
|
|
|
|
closeBracket
|
|
|
|
openCollect
|
|
|
|
closeCollect
|
|
|
|
openCollectObject
|
|
|
|
closeCollectObject
|
|
|
|
traverseArrayCollect
|
2020-10-20 02:53:26 +00:00
|
|
|
)
|
|
|
|
|
2021-01-11 05:46:28 +00:00
|
|
|
type token struct {
|
|
|
|
TokenType tokenType
|
2020-11-19 05:45:05 +00:00
|
|
|
Operation *Operation
|
|
|
|
AssignOperation *Operation // e.g. tag (GetTag) op becomes AssignTag if '=' follows it
|
|
|
|
CheckForPostTraverse bool // e.g. [1]cat should really be [1].cat
|
2020-09-20 12:40:09 +00:00
|
|
|
|
2020-09-17 11:58:01 +00:00
|
|
|
}
|
|
|
|
|
2021-02-03 06:11:47 +00:00
|
|
|
func (t *token) toString(detail bool) string {
|
2021-01-11 22:55:55 +00:00
|
|
|
if t.TokenType == operationToken {
|
2021-02-03 06:11:47 +00:00
|
|
|
if detail {
|
|
|
|
return fmt.Sprintf("%v (%v)", t.Operation.toString(), t.Operation.OperationType.Precedence)
|
|
|
|
}
|
2020-10-20 04:33:20 +00:00
|
|
|
return t.Operation.toString()
|
2021-01-11 22:55:55 +00:00
|
|
|
} else if t.TokenType == openBracket {
|
2020-10-20 04:33:20 +00:00
|
|
|
return "("
|
2021-01-11 22:55:55 +00:00
|
|
|
} else if t.TokenType == closeBracket {
|
2020-10-20 04:33:20 +00:00
|
|
|
return ")"
|
2021-01-11 22:55:55 +00:00
|
|
|
} else if t.TokenType == openCollect {
|
2020-10-20 04:33:20 +00:00
|
|
|
return "["
|
2021-01-11 22:55:55 +00:00
|
|
|
} else if t.TokenType == closeCollect {
|
2020-10-20 04:33:20 +00:00
|
|
|
return "]"
|
2021-01-11 22:55:55 +00:00
|
|
|
} else if t.TokenType == openCollectObject {
|
2020-10-21 01:54:58 +00:00
|
|
|
return "{"
|
2021-01-11 22:55:55 +00:00
|
|
|
} else if t.TokenType == closeCollectObject {
|
2020-10-21 01:54:58 +00:00
|
|
|
return "}"
|
2021-01-11 22:55:55 +00:00
|
|
|
} else if t.TokenType == traverseArrayCollect {
|
2020-12-26 10:37:08 +00:00
|
|
|
return ".["
|
|
|
|
|
2020-10-20 04:33:20 +00:00
|
|
|
} else {
|
2020-11-13 03:07:11 +00:00
|
|
|
return "NFI"
|
2020-10-20 04:33:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 00:24:22 +00:00
|
|
|
func pathToken(wrapped bool) lex.Action {
|
2020-09-17 11:58:01 +00:00
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
2020-10-11 00:24:22 +00:00
|
|
|
value := string(m.Bytes)
|
2020-11-13 03:07:11 +00:00
|
|
|
value = value[1:]
|
2020-10-11 00:24:22 +00:00
|
|
|
if wrapped {
|
|
|
|
value = unwrap(value)
|
|
|
|
}
|
2020-11-22 02:50:32 +00:00
|
|
|
log.Debug("PathToken %v", value)
|
2021-01-13 05:54:28 +00:00
|
|
|
op := &Operation{OperationType: traversePathOpType, Value: value, StringValue: value, Preferences: traversePreferences{}}
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: op, CheckForPostTraverse: true}, nil
|
2020-10-19 09:05:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
func opToken(op *operationType) lex.Action {
|
2020-11-19 05:45:05 +00:00
|
|
|
return opTokenWithPrefs(op, nil, nil)
|
2020-11-06 00:23:26 +00:00
|
|
|
}
|
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
func opAssignableToken(opType *operationType, assignOpType *operationType) lex.Action {
|
2020-11-19 05:45:05 +00:00
|
|
|
return opTokenWithPrefs(opType, assignOpType, nil)
|
|
|
|
}
|
|
|
|
|
2021-01-06 09:22:50 +00:00
|
|
|
func assignOpToken(updateAssign bool) lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
|
|
log.Debug("assignOpToken %v", string(m.Bytes))
|
|
|
|
value := string(m.Bytes)
|
2021-01-11 06:13:48 +00:00
|
|
|
op := &Operation{OperationType: assignOpType, Value: assignOpType.Type, StringValue: value, UpdateAssign: updateAssign}
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: op}, nil
|
2021-01-06 09:22:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-13 05:54:28 +00:00
|
|
|
func multiplyWithPrefs() lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
|
|
prefs := multiplyPreferences{}
|
|
|
|
options := string(m.Bytes)
|
|
|
|
if strings.Contains(options, "+") {
|
|
|
|
prefs.AppendArrays = true
|
|
|
|
}
|
|
|
|
if strings.Contains(options, "?") {
|
|
|
|
prefs.TraversePrefs = traversePreferences{DontAutoCreate: true}
|
|
|
|
}
|
2021-02-18 00:16:54 +00:00
|
|
|
if strings.Contains(options, "d") {
|
|
|
|
prefs.DeepMergeArrays = true
|
|
|
|
}
|
2021-01-13 05:59:01 +00:00
|
|
|
op := &Operation{OperationType: multiplyOpType, Value: multiplyOpType.Type, StringValue: options, Preferences: prefs}
|
2021-01-13 05:54:28 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: op}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
func opTokenWithPrefs(op *operationType, assignOpType *operationType, preferences interface{}) lex.Action {
|
2020-10-11 00:24:22 +00:00
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
2020-11-22 02:50:32 +00:00
|
|
|
log.Debug("opTokenWithPrefs %v", string(m.Bytes))
|
2020-10-11 00:24:22 +00:00
|
|
|
value := string(m.Bytes)
|
2020-11-06 00:23:26 +00:00
|
|
|
op := &Operation{OperationType: op, Value: op.Type, StringValue: value, Preferences: preferences}
|
2020-11-19 05:45:05 +00:00
|
|
|
var assign *Operation
|
|
|
|
if assignOpType != nil {
|
|
|
|
assign = &Operation{OperationType: assignOpType, Value: assignOpType.Type, StringValue: value, Preferences: preferences}
|
|
|
|
}
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: op, AssignOperation: assign}, nil
|
2020-10-11 00:24:22 +00:00
|
|
|
}
|
2020-09-17 12:12:56 +00:00
|
|
|
}
|
|
|
|
|
2021-01-06 09:22:50 +00:00
|
|
|
func assignAllCommentsOp(updateAssign bool) lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
|
|
log.Debug("assignAllCommentsOp %v", string(m.Bytes))
|
|
|
|
value := string(m.Bytes)
|
|
|
|
op := &Operation{
|
2021-01-11 06:13:48 +00:00
|
|
|
OperationType: assignCommentOpType,
|
|
|
|
Value: assignCommentOpType.Type,
|
2021-01-06 09:22:50 +00:00
|
|
|
StringValue: value,
|
|
|
|
UpdateAssign: updateAssign,
|
2021-01-13 05:56:24 +00:00
|
|
|
Preferences: commentOpPreferences{LineComment: true, HeadComment: true, FootComment: true},
|
2021-01-06 09:22:50 +00:00
|
|
|
}
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: op}, nil
|
2021-01-06 09:22:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-11 05:46:28 +00:00
|
|
|
func literalToken(pType tokenType, checkForPost bool) lex.Action {
|
2020-09-17 12:12:56 +00:00
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
2021-01-11 05:46:28 +00:00
|
|
|
return &token{TokenType: pType, CheckForPostTraverse: checkForPost}, nil
|
2020-09-17 12:12:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 00:24:22 +00:00
|
|
|
func unwrap(value string) string {
|
|
|
|
return value[1 : len(value)-1]
|
|
|
|
}
|
|
|
|
|
2020-10-16 01:29:26 +00:00
|
|
|
func numberValue() lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
|
|
var numberString = string(m.Bytes)
|
|
|
|
var number, errParsingInt = strconv.ParseInt(numberString, 10, 64) // nolint
|
|
|
|
if errParsingInt != nil {
|
|
|
|
return nil, errParsingInt
|
|
|
|
}
|
2020-10-20 04:33:20 +00:00
|
|
|
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: createValueOperation(number, numberString)}, nil
|
2020-10-16 01:29:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-17 11:39:01 +00:00
|
|
|
func floatValue() lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
|
|
var numberString = string(m.Bytes)
|
|
|
|
var number, errParsingInt = strconv.ParseFloat(numberString, 64) // nolint
|
|
|
|
if errParsingInt != nil {
|
|
|
|
return nil, errParsingInt
|
|
|
|
}
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: createValueOperation(number, numberString)}, nil
|
2020-10-17 11:39:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-16 01:29:26 +00:00
|
|
|
func booleanValue(val bool) lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: createValueOperation(val, string(m.Bytes))}, nil
|
2020-10-16 01:29:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func stringValue(wrapped bool) lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
|
|
value := string(m.Bytes)
|
|
|
|
if wrapped {
|
|
|
|
value = unwrap(value)
|
|
|
|
}
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: createValueOperation(value, value)}, nil
|
2020-10-16 01:29:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-03 04:51:26 +00:00
|
|
|
func getVariableOpToken() lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
|
|
value := string(m.Bytes)
|
|
|
|
|
2021-02-15 06:31:12 +00:00
|
|
|
value = value[1:]
|
2021-02-03 04:51:26 +00:00
|
|
|
|
|
|
|
getVarOperation := createValueOperation(value, value)
|
|
|
|
getVarOperation.OperationType = getVariableOpType
|
|
|
|
|
|
|
|
return &token{TokenType: operationToken, Operation: getVarOperation, CheckForPostTraverse: true}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 00:33:39 +00:00
|
|
|
func envOp(strenv bool) lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
|
|
value := string(m.Bytes)
|
2021-01-13 06:00:53 +00:00
|
|
|
preferences := envOpPreferences{}
|
2021-01-09 00:33:39 +00:00
|
|
|
|
|
|
|
if strenv {
|
|
|
|
// strenv( )
|
2021-01-09 01:06:19 +00:00
|
|
|
value = value[7 : len(value)-1]
|
|
|
|
preferences.StringValue = true
|
|
|
|
} else {
|
2021-01-09 00:33:39 +00:00
|
|
|
//env( )
|
2021-01-09 01:06:19 +00:00
|
|
|
value = value[4 : len(value)-1]
|
|
|
|
}
|
2021-01-09 00:33:39 +00:00
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
envOperation := createValueOperation(value, value)
|
|
|
|
envOperation.OperationType = envOpType
|
2021-01-09 01:06:19 +00:00
|
|
|
envOperation.Preferences = preferences
|
2021-01-09 00:33:39 +00:00
|
|
|
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: envOperation}, nil
|
2021-01-09 00:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-20 04:40:11 +00:00
|
|
|
func nullValue() lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: createValueOperation(nil, string(m.Bytes))}, nil
|
2020-10-20 04:40:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-16 01:29:26 +00:00
|
|
|
func selfToken() lex.Action {
|
|
|
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
2021-01-11 06:13:48 +00:00
|
|
|
op := &Operation{OperationType: selfReferenceOpType}
|
2021-01-11 22:55:55 +00:00
|
|
|
return &token{TokenType: operationToken, Operation: op}, nil
|
2020-09-17 12:12:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-17 11:58:01 +00:00
|
|
|
func initLexer() (*lex.Lexer, error) {
|
|
|
|
lexer := lex.NewLexer()
|
2021-01-11 22:55:55 +00:00
|
|
|
lexer.Add([]byte(`\(`), literalToken(openBracket, false))
|
|
|
|
lexer.Add([]byte(`\)`), literalToken(closeBracket, true))
|
2020-10-11 00:24:22 +00:00
|
|
|
|
2021-01-11 22:55:55 +00:00
|
|
|
lexer.Add([]byte(`\.\[`), literalToken(traverseArrayCollect, false))
|
2021-01-13 06:00:03 +00:00
|
|
|
lexer.Add([]byte(`\.\.`), opTokenWithPrefs(recursiveDescentOpType, nil, recursiveDescentPreferences{RecurseArray: true,
|
2021-01-13 05:54:28 +00:00
|
|
|
TraversePreferences: traversePreferences{DontFollowAlias: true, IncludeMapKeys: false}}))
|
2020-12-28 00:24:42 +00:00
|
|
|
|
2021-01-13 06:00:03 +00:00
|
|
|
lexer.Add([]byte(`\.\.\.`), opTokenWithPrefs(recursiveDescentOpType, nil, recursiveDescentPreferences{RecurseArray: true,
|
2021-01-13 05:54:28 +00:00
|
|
|
TraversePreferences: traversePreferences{DontFollowAlias: true, IncludeMapKeys: true}}))
|
2020-10-11 00:24:22 +00:00
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`,`), opToken(unionOpType))
|
|
|
|
lexer.Add([]byte(`:\s*`), opToken(createMapOpType))
|
|
|
|
lexer.Add([]byte(`length`), opToken(lengthOpType))
|
|
|
|
lexer.Add([]byte(`sortKeys`), opToken(sortKeysOpType))
|
|
|
|
lexer.Add([]byte(`select`), opToken(selectOpType))
|
|
|
|
lexer.Add([]byte(`has`), opToken(hasOpType))
|
|
|
|
lexer.Add([]byte(`explode`), opToken(explodeOpType))
|
|
|
|
lexer.Add([]byte(`or`), opToken(orOpType))
|
|
|
|
lexer.Add([]byte(`and`), opToken(andOpType))
|
|
|
|
lexer.Add([]byte(`not`), opToken(notOpType))
|
2021-02-15 05:06:37 +00:00
|
|
|
lexer.Add([]byte(`ireduce`), opToken(reduceOpType))
|
2021-02-15 03:27:00 +00:00
|
|
|
lexer.Add([]byte(`;`), opToken(blockOpType))
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`\/\/`), opToken(alternativeOpType))
|
2020-11-02 00:20:38 +00:00
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`documentIndex`), opToken(getDocumentIndexOpType))
|
|
|
|
lexer.Add([]byte(`di`), opToken(getDocumentIndexOpType))
|
2021-01-14 03:25:31 +00:00
|
|
|
lexer.Add([]byte(`splitDoc`), opToken(splitDocumentOpType))
|
2020-11-06 01:11:38 +00:00
|
|
|
|
2021-01-14 03:46:50 +00:00
|
|
|
lexer.Add([]byte(`join`), opToken(joinStringOpType))
|
2021-01-14 04:05:50 +00:00
|
|
|
lexer.Add([]byte(`split`), opToken(splitStringOpType))
|
2021-01-14 04:45:07 +00:00
|
|
|
lexer.Add([]byte(`keys`), opToken(keysOpType))
|
2021-01-14 03:46:50 +00:00
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`style`), opAssignableToken(getStyleOpType, assignStyleOpType))
|
2020-11-02 00:20:38 +00:00
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`tag`), opAssignableToken(getTagOpType, assignTagOpType))
|
|
|
|
lexer.Add([]byte(`anchor`), opAssignableToken(getAnchorOpType, assignAnchorOpType))
|
|
|
|
lexer.Add([]byte(`alias`), opAssignableToken(getAliasOptype, assignAliasOpType))
|
|
|
|
lexer.Add([]byte(`filename`), opToken(getFilenameOpType))
|
|
|
|
lexer.Add([]byte(`fileIndex`), opToken(getFileIndexOpType))
|
|
|
|
lexer.Add([]byte(`fi`), opToken(getFileIndexOpType))
|
|
|
|
lexer.Add([]byte(`path`), opToken(getPathOpType))
|
2020-11-06 00:45:18 +00:00
|
|
|
|
2021-01-13 05:56:24 +00:00
|
|
|
lexer.Add([]byte(`lineComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{LineComment: true}))
|
2020-11-06 00:45:18 +00:00
|
|
|
|
2021-01-13 05:56:24 +00:00
|
|
|
lexer.Add([]byte(`headComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{HeadComment: true}))
|
2020-11-06 00:45:18 +00:00
|
|
|
|
2021-01-13 05:56:24 +00:00
|
|
|
lexer.Add([]byte(`footComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{FootComment: true}))
|
2020-11-19 05:45:05 +00:00
|
|
|
|
2021-01-06 09:22:50 +00:00
|
|
|
lexer.Add([]byte(`comments\s*=`), assignAllCommentsOp(false))
|
|
|
|
lexer.Add([]byte(`comments\s*\|=`), assignAllCommentsOp(true))
|
2020-11-06 00:23:26 +00:00
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`collect`), opToken(collectOpType))
|
2020-10-11 00:24:22 +00:00
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`\s*==\s*`), opToken(equalsOpType))
|
2021-02-04 22:54:03 +00:00
|
|
|
lexer.Add([]byte(`\s*!=\s*`), opToken(notEqualsOpType))
|
2021-01-06 09:22:50 +00:00
|
|
|
lexer.Add([]byte(`\s*=\s*`), assignOpToken(false))
|
2020-10-11 00:24:22 +00:00
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`del`), opToken(deleteChildOpType))
|
2020-10-11 00:24:22 +00:00
|
|
|
|
2021-01-06 09:22:50 +00:00
|
|
|
lexer.Add([]byte(`\s*\|=\s*`), assignOpToken(true))
|
2020-10-16 01:29:26 +00:00
|
|
|
|
2020-09-17 11:58:01 +00:00
|
|
|
lexer.Add([]byte("( |\t|\n|\r)+"), skip)
|
2020-10-11 00:24:22 +00:00
|
|
|
|
2020-10-16 01:29:26 +00:00
|
|
|
lexer.Add([]byte(`\."[^ "]+"`), pathToken(true))
|
2020-10-21 01:54:58 +00:00
|
|
|
lexer.Add([]byte(`\.[^ \}\{\:\[\],\|\.\[\(\)=]+`), pathToken(false))
|
2020-10-16 01:29:26 +00:00
|
|
|
lexer.Add([]byte(`\.`), selfToken())
|
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`\|`), opToken(pipeOpType))
|
2020-10-16 01:29:26 +00:00
|
|
|
|
2020-10-17 11:39:01 +00:00
|
|
|
lexer.Add([]byte(`-?\d+(\.\d+)`), floatValue())
|
|
|
|
lexer.Add([]byte(`-?[1-9](\.\d+)?[Ee][-+]?\d+`), floatValue())
|
|
|
|
lexer.Add([]byte(`-?\d+`), numberValue())
|
2020-10-16 01:29:26 +00:00
|
|
|
|
|
|
|
lexer.Add([]byte(`[Tt][Rr][Uu][Ee]`), booleanValue(true))
|
|
|
|
lexer.Add([]byte(`[Ff][Aa][Ll][Ss][Ee]`), booleanValue(false))
|
2020-10-11 00:24:22 +00:00
|
|
|
|
2020-10-20 04:40:11 +00:00
|
|
|
lexer.Add([]byte(`[Nn][Uu][Ll][Ll]`), nullValue())
|
|
|
|
lexer.Add([]byte(`~`), nullValue())
|
|
|
|
|
2020-12-21 21:04:08 +00:00
|
|
|
lexer.Add([]byte(`"[^"]*"`), stringValue(true))
|
2021-01-09 00:33:39 +00:00
|
|
|
lexer.Add([]byte(`strenv\([^\)]+\)`), envOp(true))
|
2021-01-09 01:06:19 +00:00
|
|
|
lexer.Add([]byte(`env\([^\)]+\)`), envOp(false))
|
2020-10-16 01:29:26 +00:00
|
|
|
|
2021-01-11 22:55:55 +00:00
|
|
|
lexer.Add([]byte(`\[`), literalToken(openCollect, false))
|
|
|
|
lexer.Add([]byte(`\]`), literalToken(closeCollect, true))
|
|
|
|
lexer.Add([]byte(`\{`), literalToken(openCollectObject, false))
|
|
|
|
lexer.Add([]byte(`\}`), literalToken(closeCollectObject, true))
|
2021-02-18 00:16:54 +00:00
|
|
|
lexer.Add([]byte(`\*[\+|\?d]*`), multiplyWithPrefs())
|
2021-01-11 06:13:48 +00:00
|
|
|
lexer.Add([]byte(`\+`), opToken(addOpType))
|
|
|
|
lexer.Add([]byte(`\+=`), opToken(addAssignOpType))
|
2021-03-24 21:12:01 +00:00
|
|
|
lexer.Add([]byte(`\-`), opToken(subtractOpType))
|
|
|
|
lexer.Add([]byte(`\-=`), opToken(subtractAssignOpType))
|
2021-02-03 04:51:26 +00:00
|
|
|
lexer.Add([]byte(`\$[a-zA-Z_-0-9]+`), getVariableOpToken())
|
|
|
|
lexer.Add([]byte(`as`), opToken(assignVariableOpType))
|
2020-10-16 01:29:26 +00:00
|
|
|
|
2021-02-25 05:47:55 +00:00
|
|
|
err := lexer.CompileNFA()
|
2020-09-17 11:58:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return lexer, nil
|
|
|
|
}
|
|
|
|
|
2021-01-12 23:18:53 +00:00
|
|
|
type expressionTokeniser interface {
|
|
|
|
Tokenise(expression string) ([]*token, error)
|
2020-09-17 11:58:01 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 23:18:53 +00:00
|
|
|
type expressionTokeniserImpl struct {
|
2020-09-17 11:58:01 +00:00
|
|
|
lexer *lex.Lexer
|
|
|
|
}
|
|
|
|
|
2021-01-12 23:18:53 +00:00
|
|
|
func newExpressionTokeniser() expressionTokeniser {
|
2020-09-17 11:58:01 +00:00
|
|
|
var lexer, err = initLexer()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2021-01-12 23:18:53 +00:00
|
|
|
return &expressionTokeniserImpl{lexer}
|
2020-09-17 11:58:01 +00:00
|
|
|
}
|
|
|
|
|
2021-01-12 23:18:53 +00:00
|
|
|
func (p *expressionTokeniserImpl) Tokenise(expression string) ([]*token, error) {
|
|
|
|
scanner, err := p.lexer.Scanner([]byte(expression))
|
2020-09-17 11:58:01 +00:00
|
|
|
|
|
|
|
if err != nil {
|
2020-12-17 03:02:54 +00:00
|
|
|
return nil, fmt.Errorf("Parsing expression: %v", err)
|
2020-09-17 11:58:01 +00:00
|
|
|
}
|
2021-01-11 05:46:28 +00:00
|
|
|
var tokens []*token
|
2020-09-17 11:58:01 +00:00
|
|
|
for tok, err, eof := scanner.Next(); !eof; tok, err, eof = scanner.Next() {
|
|
|
|
|
|
|
|
if tok != nil {
|
2021-01-11 05:46:28 +00:00
|
|
|
currentToken := tok.(*token)
|
2021-02-03 06:11:47 +00:00
|
|
|
log.Debugf("Tokenising %v", currentToken.toString(true))
|
2021-01-11 05:46:28 +00:00
|
|
|
tokens = append(tokens, currentToken)
|
2020-09-17 11:58:01 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
2020-12-17 03:02:54 +00:00
|
|
|
return nil, fmt.Errorf("Parsing expression: %v", err)
|
2020-09-17 11:58:01 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-11 05:46:28 +00:00
|
|
|
var postProcessedTokens = make([]*token, 0)
|
2020-09-24 00:52:45 +00:00
|
|
|
|
2020-11-19 05:45:05 +00:00
|
|
|
skipNextToken := false
|
2020-10-11 00:24:22 +00:00
|
|
|
|
2020-12-09 01:15:14 +00:00
|
|
|
for index := range tokens {
|
2020-11-19 05:45:05 +00:00
|
|
|
if skipNextToken {
|
|
|
|
skipNextToken = false
|
|
|
|
} else {
|
2020-12-09 01:15:14 +00:00
|
|
|
postProcessedTokens, skipNextToken = p.handleToken(tokens, index, postProcessedTokens)
|
2020-09-24 00:52:45 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-17 11:58:01 +00:00
|
|
|
|
2020-09-24 00:52:45 +00:00
|
|
|
return postProcessedTokens, nil
|
2020-09-17 11:58:01 +00:00
|
|
|
}
|
2020-12-09 01:15:14 +00:00
|
|
|
|
2021-01-12 23:18:53 +00:00
|
|
|
func (p *expressionTokeniserImpl) handleToken(tokens []*token, index int, postProcessedTokens []*token) (tokensAccum []*token, skipNextToken bool) {
|
2020-12-09 01:15:14 +00:00
|
|
|
skipNextToken = false
|
2021-01-11 05:46:28 +00:00
|
|
|
currentToken := tokens[index]
|
2020-12-09 01:15:14 +00:00
|
|
|
|
2021-01-11 22:55:55 +00:00
|
|
|
if currentToken.TokenType == traverseArrayCollect {
|
2021-01-11 05:46:28 +00:00
|
|
|
//need to put a traverse array then a collect currentToken
|
|
|
|
// do this by adding traverse then converting currentToken to collect
|
2020-12-09 01:15:14 +00:00
|
|
|
|
2021-02-03 04:51:26 +00:00
|
|
|
if index == 0 || tokens[index-1].TokenType != operationToken ||
|
|
|
|
tokens[index-1].Operation.OperationType != traversePathOpType {
|
|
|
|
op := &Operation{OperationType: selfReferenceOpType, StringValue: "SELF"}
|
|
|
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
|
|
|
}
|
|
|
|
|
2021-01-11 06:13:48 +00:00
|
|
|
op := &Operation{OperationType: traverseArrayOpType, StringValue: "TRAVERSE_ARRAY"}
|
2021-01-11 22:55:55 +00:00
|
|
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
2020-12-26 10:37:08 +00:00
|
|
|
|
2021-01-11 22:55:55 +00:00
|
|
|
currentToken = &token{TokenType: openCollect}
|
2020-12-09 01:15:14 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-11 05:46:28 +00:00
|
|
|
if index != len(tokens)-1 && currentToken.AssignOperation != nil &&
|
2021-01-11 22:55:55 +00:00
|
|
|
tokens[index+1].TokenType == operationToken &&
|
2021-01-11 06:13:48 +00:00
|
|
|
tokens[index+1].Operation.OperationType == assignOpType {
|
2021-01-11 05:46:28 +00:00
|
|
|
currentToken.Operation = currentToken.AssignOperation
|
|
|
|
currentToken.Operation.UpdateAssign = tokens[index+1].Operation.UpdateAssign
|
2020-12-09 01:15:14 +00:00
|
|
|
skipNextToken = true
|
|
|
|
}
|
|
|
|
|
2021-01-11 05:46:28 +00:00
|
|
|
postProcessedTokens = append(postProcessedTokens, currentToken)
|
2020-12-09 01:15:14 +00:00
|
|
|
|
2021-02-03 06:20:54 +00:00
|
|
|
if index != len(tokens)-1 &&
|
|
|
|
((currentToken.TokenType == openCollect && tokens[index+1].TokenType == closeCollect) ||
|
|
|
|
(currentToken.TokenType == openCollectObject && tokens[index+1].TokenType == closeCollectObject)) {
|
|
|
|
|
|
|
|
op := &Operation{OperationType: emptyOpType, StringValue: "EMPTY"}
|
|
|
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
|
|
|
}
|
|
|
|
|
2021-01-11 05:46:28 +00:00
|
|
|
if index != len(tokens)-1 && currentToken.CheckForPostTraverse &&
|
2021-01-11 22:55:55 +00:00
|
|
|
tokens[index+1].TokenType == operationToken &&
|
2021-01-11 06:13:48 +00:00
|
|
|
tokens[index+1].Operation.OperationType == traversePathOpType {
|
|
|
|
op := &Operation{OperationType: shortPipeOpType, Value: "PIPE"}
|
2021-01-11 22:55:55 +00:00
|
|
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
2020-12-09 01:15:14 +00:00
|
|
|
}
|
2021-01-11 05:46:28 +00:00
|
|
|
if index != len(tokens)-1 && currentToken.CheckForPostTraverse &&
|
2021-01-11 22:55:55 +00:00
|
|
|
tokens[index+1].TokenType == openCollect {
|
2020-12-26 10:37:08 +00:00
|
|
|
|
2021-02-03 04:51:26 +00:00
|
|
|
op := &Operation{OperationType: traverseArrayOpType}
|
2021-01-11 22:55:55 +00:00
|
|
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
2020-12-26 10:37:08 +00:00
|
|
|
}
|
2020-12-09 01:15:14 +00:00
|
|
|
return postProcessedTokens, skipNextToken
|
|
|
|
}
|