github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/ast/spl/spl.peg (about)

     1  {
     2  package spl
     3  
     4  import (
     5      "regexp"
     6      "time"
     7  
     8      "github.com/siglens/siglens/pkg/ast"
     9      "github.com/siglens/siglens/pkg/segment/aggregations"
    10      "github.com/siglens/siglens/pkg/segment/query"
    11      "github.com/siglens/siglens/pkg/segment/structs"
    12      "github.com/siglens/siglens/pkg/segment/utils"
    13      log "github.com/sirupsen/logrus"
    14  )
    15  
    16  func getParseError(err error) error {
    17      switch ev := err.(type) {
    18      case errList:
    19          if pe, ok := ev[0].(*parserError); ok {
    20              return &ast.ParseError{
    21                  Inner:    pe.Inner,
    22                  Line:     pe.pos.line,
    23                  Column:   pe.pos.col,
    24                  Offset:   pe.pos.offset,
    25                  Prefix:   pe.prefix,
    26                  Expected: pe.expected,
    27              }
    28          }
    29      }
    30      return err
    31  }
    32  
    33  // Remove the first and last character of the string
    34  func removeQuotes(s any) string {
    35      str := s.(string)
    36      if len(str) < 3 {
    37          return ""
    38      }
    39  
    40      return str[1:len(str)-1]
    41  }
    42  
    43  // Check if it rename fields with similar names using a wildcard
    44  func isRegexRename(originalPattern, newPattern string) (bool, error) {
    45      oldWildcards := strings.Count(originalPattern, "*")
    46      newWildcards := strings.Count(newPattern, "*")
    47  
    48      if oldWildcards == 0 && newWildcards == 0 {
    49          return false, nil
    50      } else if oldWildcards > 0 && oldWildcards == newWildcards {
    51          return true, nil
    52      } else {
    53          return false, errors.New("Patterns do not match")
    54      }
    55  }
    56  
    57  func deMorgansLaw(node *ast.Node) {
    58      switch node.NodeType {
    59      case ast.NodeTerminal:
    60          switch node.Comparison.Op {
    61          case "=":
    62              node.Comparison.Op = "!="
    63          case "!=":
    64              node.Comparison.Op = "="
    65          case ">":
    66              node.Comparison.Op = "<="
    67          case "<":
    68              node.Comparison.Op = ">="
    69          case ">=":
    70              node.Comparison.Op = "<"
    71          case "<=":
    72              node.Comparison.Op = ">"
    73          default:
    74              log.Errorf("deMorgansLaw: unexpected node comparison op: %v", node.Comparison.Op)
    75          }
    76      case ast.NodeAnd:
    77          node.NodeType = ast.NodeOr
    78          deMorgansLaw(node.Left)
    79          deMorgansLaw(node.Right)
    80      case ast.NodeOr:
    81          node.NodeType = ast.NodeAnd
    82          deMorgansLaw(node.Left)
    83          deMorgansLaw(node.Right)
    84      default:
    85          log.Errorf("deMorgansLaw: unexpected NodeType: %v", node.NodeType)
    86      }
    87  }
    88  
    89  //Generate NumericExpr struct for eval functions
    90  func createNumericExpr(op string, leftNumericExpr *structs.NumericExpr, rightNumericExpr *structs.NumericExpr, numericExprMode structs.NumericExprMode) (*structs.NumericExpr, error) {
    91      if leftNumericExpr == nil {
    92          return nil, fmt.Errorf("expr cannot be nil")
    93      }
    94  
    95      return &structs.NumericExpr{
    96          IsTerminal: false,
    97          Op: op,
    98          Left: leftNumericExpr,
    99          Right: rightNumericExpr,
   100          NumericExprMode: numericExprMode,
   101      }, nil
   102  }
   103  
   104  func transferUint8ToString(opName interface{}) (string, error){
   105      strData, ok := opName.([]byte)
   106      if !ok {
   107          return "", fmt.Errorf("opName is not a []byte")
   108      }
   109  
   110      opNameStr := string(strData)
   111      return opNameStr, nil
   112  }
   113  
   114  func transferPCREToRE2(pattern string) string {
   115      pattern = strings.Replace(pattern, "(?<", "(?P<", -1)
   116      return pattern
   117  }
   118  
   119  func getRexColNames(pattern string) ([]string, error) {
   120      re, err := regexp.Compile(`\?<(?P<GroupName>[a-zA-Z0-9_]+)>`)
   121      if err != nil {
   122          return nil, fmt.Errorf("getRexColNames: There are some errors in the pattern: %v", err)
   123      }
   124      matches := re.FindAllStringSubmatch(pattern, -1)
   125  
   126      var rexColNames []string
   127      for _, match := range matches {
   128          rexColNames = append(rexColNames, match[1])
   129      }
   130  
   131      return rexColNames, nil
   132  }
   133  
   134  type aggregator struct {
   135      measureAgg          *structs.MeasureAggregator
   136      renameOutputField   bool
   137      outputFieldNewName  string
   138  }
   139  
   140  type singleAggTemp struct {
   141      aggregators []*aggregator
   142      SplitByClause *structs.SplitByClause
   143  }
   144  
   145  type TxnArgs struct {
   146      argOption string
   147      arguments *structs.TransactionArguments
   148  }
   149  
   150  type TimechartArgs struct {
   151      singleAggExpr *singleAggTemp
   152      // Todo: Add eval clause expr.
   153      tcOptions     *structs.TcOptions
   154  }
   155  }
   156  
   157  Start <- SPACE? initialSearch:(InitialSearchBlock) filterBlocks:(FilterBlock)* queryAggBlocks:(QueryAggergatorBlock)* SPACE? EOF {
   158      var q ast.QueryStruct
   159      q.SearchFilter = initialSearch.(*ast.Node)
   160  
   161      // Join the InitialSearchBlock with the FilterBlocks with AND nodes. For a
   162      // search like "A | B | C | D" we should generate the node structure below
   163      // so that when we run the search it evaluates A first.
   164      //
   165      //      AND
   166      //     /   \
   167      //    A     AND
   168      //         /   \
   169      //        B     AND
   170      //             /   \
   171      //            C     D
   172  
   173      filterBlocksSlice := filterBlocks.([]any)
   174      switch len(filterBlocksSlice) {
   175      case 0:
   176          q.SearchFilter = initialSearch.(*ast.Node)
   177      case 1:
   178          q.SearchFilter = &ast.Node {
   179              NodeType: ast.NodeAnd,
   180              Left: initialSearch.(*ast.Node),
   181              Right: filterBlocksSlice[0].(*ast.Node),
   182          }
   183      default: // len > 1
   184          // Iterate backwards so we build the node structure mentioned above.
   185          root := filterBlocksSlice[len(filterBlocksSlice) - 1].(*ast.Node)
   186          for i := len(filterBlocksSlice) - 2; i > -1; i-- {
   187              newRoot := &ast.Node {
   188                  NodeType: ast.NodeAnd,
   189                  Left: filterBlocksSlice[i].(*ast.Node),
   190                  Right: root,
   191              }
   192  
   193              root = newRoot
   194          }
   195  
   196          q.SearchFilter = &ast.Node {
   197              NodeType: ast.NodeAnd,
   198              Left: initialSearch.(*ast.Node),
   199              Right: root,
   200          }
   201      }
   202  
   203      if queryAggBlocks != nil {
   204          queryAggSlice := queryAggBlocks.([]any)
   205  
   206          if len(queryAggSlice) > 0 {
   207              // Chain together all QueryAggergators.
   208              q.PipeCommands = queryAggSlice[0].(*structs.QueryAggregators)
   209  
   210              // Go to the end of the first chain.
   211              curQueryAgg := q.PipeCommands
   212              for ; curQueryAgg.Next != nil; curQueryAgg = curQueryAgg.Next {}
   213  
   214              // Link the remaining chains.
   215              for i := range queryAggSlice[1:] {
   216                  queryAgg := queryAggSlice[i + 1].(*structs.QueryAggregators)
   217                  curQueryAgg.Next = queryAgg
   218  
   219                  // Go to the end of this chain.
   220                  for ; curQueryAgg.Next != nil; curQueryAgg = curQueryAgg.Next {}
   221              }
   222          }
   223      }
   224  
   225      return q, nil
   226  }
   227  
   228  InitialSearchBlock <- CMD_SEARCH? clause:ClauseLevel4 {
   229      return clause, nil
   230  }
   231  
   232  SearchBlock <- !(ALLCMD) CMD_SEARCH? clause:ClauseLevel4 {
   233      return clause, nil
   234  }
   235  
   236  FilterBlock <- PIPE block:(SearchBlock / RegexBlock) {
   237      return block, nil
   238  }
   239  
   240  // Returns *structs.QueryAggregators
   241  QueryAggergatorBlock <- block:(FieldSelectBlock / AggregatorBlock / EvalBlock / WhereBlock / HeadBlock / RexBlock / StatisticBlock / RenameBlock / TimechartBlock / TransactionBlock / DedupBlock / SortBlock) {
   242      queryAgg := block.(*structs.QueryAggregators)
   243      return queryAgg, nil
   244  }
   245  
   246  FieldSelectBlock <- PIPE CMD_FIELDS op:("-" / "+")? EMPTY_OR_SPACE fields:FieldNameList {
   247      columnsRequest := &structs.ColumnsRequest{}
   248      if op == nil || string(op.([]byte)) == "+" {
   249          columnsRequest.IncludeColumns = fields.([]string)
   250      } else {
   251          columnsRequest.ExcludeColumns = fields.([]string)
   252      }
   253  
   254      queryAggregator := &structs.QueryAggregators {
   255          PipeCommandType: structs.OutputTransformType,
   256          OutputTransforms: &structs.OutputTransforms {
   257              OutputColumns: columnsRequest,
   258          },
   259      }
   260  
   261      return queryAggregator, nil
   262  }
   263  
   264  AggregatorBlock <- PIPE CMD_STATS aggs:AggregationList byFields:(GroupbyBlock)? {
   265      aggNode := &structs.QueryAggregators{}
   266  
   267      // Extract the MeasureAggregators and check if any of the aggregation fields
   268      // need to be renamed.
   269      aggsSlice := aggs.([]*aggregator)
   270      measureAggs := make([]*structs.MeasureAggregator, len(aggsSlice))
   271      columnsRequest := &structs.ColumnsRequest{}
   272      columnsRequest.RenameAggregationColumns = make(map[string]string, 0)
   273  
   274      for i, agg := range aggsSlice {
   275          measureAggs[i] = agg.measureAgg
   276  
   277          if agg.renameOutputField {
   278              columnsRequest.RenameAggregationColumns[measureAggs[i].String()] = agg.outputFieldNewName
   279          }
   280      }
   281  
   282      // If any agg field was renamed, make a QueryAggregators for all the renames.
   283      if len(columnsRequest.RenameAggregationColumns) > 0 {
   284          renameNode := &structs.QueryAggregators {
   285              PipeCommandType: structs.OutputTransformType,
   286              OutputTransforms: &structs.OutputTransforms {
   287                  OutputColumns: columnsRequest,
   288              },
   289          }
   290  
   291          aggNode.Next = renameNode
   292      }
   293  
   294      if byFields == nil {
   295          aggNode.PipeCommandType = structs.MeasureAggsType
   296          aggNode.MeasureOperations = measureAggs
   297      } else {
   298          aggNode.PipeCommandType = structs.GroupByType
   299          aggNode.GroupByRequest = &structs.GroupByRequest {
   300              MeasureOperations: measureAggs,
   301              GroupByColumns: byFields.([]string),
   302          }
   303          aggNode.BucketLimit = query.MAX_GRP_BUCKS
   304      }
   305  
   306      return aggNode, nil
   307  }
   308  
   309  GroupbyBlock <- BY fields:FieldNameList {
   310      // Wildcard fields are not allowed. See https://docs.splunk.com/Documentation/Splunk/9.1.0/SearchReference/Stats
   311      for _, field := range fields.([]string) {
   312          if strings.Contains(field, "*") {
   313              return nil, errors.New("BY clause cannot contain fields with wildcards")
   314          }
   315      }
   316  
   317      return fields, nil
   318  }
   319  
   320  RegexBlock <- CMD_REGEX keyAndOp:(FieldName EqualityOperator)? str:QuotedString {
   321      var key, op string
   322      if keyAndOp == nil {
   323          key = "*"
   324          op = "="
   325      } else {
   326          keyAndOpSlice := keyAndOp.([]any)
   327          key = keyAndOpSlice[0].(string)
   328          op = keyAndOpSlice[1].(string)
   329      }
   330  
   331      // Remove the quotation marks.
   332      regex := str.(string)
   333      regex = regex[1:len(regex) - 1]
   334  
   335      node := &ast.Node {
   336          NodeType: ast.NodeTerminal,
   337          Comparison: ast.Comparison {
   338              Op: op,
   339              Field: key,
   340              Values: regex,
   341              ValueIsRegex: true,
   342          },
   343      }
   344  
   345      return node, nil
   346  }
   347  
   348  ClauseLevel4 <- first:ClauseLevel3 rest:((AND / SPACE) ClauseLevel3)* {
   349      if rest == nil {
   350          return first, nil
   351      }
   352  
   353      cur := first.(*ast.Node)
   354      for _, v := range rest.([]any) {
   355          parts := v.([]any)  // This will be [(AND / SPACE), ClauseLevel3].
   356          cur = &ast.Node {
   357              NodeType: ast.NodeAnd,
   358              Left: cur,
   359              Right: parts[1].(*ast.Node),
   360          }
   361      }
   362  
   363      return cur, nil
   364  }
   365  
   366  ClauseLevel3 <- first:ClauseLevel2 rest:(OR ClauseLevel2)* {
   367      if rest == nil {
   368          return first, nil
   369      }
   370  
   371      cur := first.(*ast.Node)
   372      for _, v := range rest.([]any) {
   373          parts := v.([]any)  // This will be [OR, ClauseLevel2].
   374          cur = &ast.Node {
   375              NodeType: ast.NodeOr,
   376              Left: cur,
   377              Right: parts[1].(*ast.Node),
   378          }
   379      }
   380  
   381      return cur, nil
   382  }
   383  
   384  ClauseLevel2 <- notList:NOT+ first:ClauseLevel1 {
   385      // There's an issue with how queries with AST Not nodes are run, so use
   386      // De Morgan's law to manipulate the expression.
   387      node := first.(*ast.Node)
   388      numNots := len(notList.([]any))
   389  
   390      if numNots % 2 == 1 {
   391          deMorgansLaw(node)
   392      }
   393  
   394      return node, nil
   395  } / clause:ClauseLevel1 {
   396      return clause, nil
   397  }
   398  
   399  ClauseLevel1 <- L_PAREN clause:ClauseLevel4 R_PAREN {
   400      return clause, nil
   401  } / term:SearchTerm {
   402      return term, nil
   403  }
   404  
   405  // Parsing the text of a Number as a String would succeed, so we need to try
   406  // parsing as a FieldWithNumberValue first.
   407  SearchTerm <- term:(FieldWithNumberValue / FieldWithBooleanValue / FieldWithStringValue) {
   408      return term, nil
   409  }
   410  
   411  // To be finished: add (<eval-expression>) BY <split-by-clause> ) for expr; Limit option ...
   412  TimechartBlock <- PIPE CMD_TIMECHART tcArgs:TimechartArgumentsList limitExpr:(LimitExpr)? {
   413      aggNode := &structs.QueryAggregators{}
   414  
   415      columnsRequest := &structs.ColumnsRequest{}
   416      columnsRequest.RenameAggregationColumns = make(map[string]string, 0)
   417      measureAggs := make([]*structs.MeasureAggregator, 0)
   418  
   419      timechartExpr := &structs.TimechartExpr{}
   420      byField := ""
   421  
   422      if tcArgs == nil {
   423          return nil, fmt.Errorf("spl peg: timechart: either single-agg or eval-expression by split-by-clause is required")
   424      }
   425      
   426      timechartArgs := tcArgs.(*TimechartArgs)
   427      
   428      // Todo: Should add || timechartArgs.evalExpr == nil
   429      if timechartArgs.singleAggExpr == nil {
   430          return nil, fmt.Errorf("spl peg: timechart: either single-agg or eval-expression by split-by-clause is required")
   431      }
   432  
   433      var bOptions *structs.BinOptions
   434      
   435      if timechartArgs.tcOptions != nil {
   436          if timechartArgs.tcOptions.BinOptions != nil {
   437              bOptions = timechartArgs.tcOptions.BinOptions
   438          }
   439      }
   440  
   441      if timechartArgs.singleAggExpr != nil {
   442          singleAgg := &structs.SingleAgg{}
   443          aggTemp := timechartArgs.singleAggExpr
   444  
   445          for i, agg := range aggTemp.aggregators {
   446              measureAggs = append(measureAggs, agg.measureAgg)
   447  
   448              if agg.renameOutputField {
   449                  measureAggs[i].StrEnc = agg.outputFieldNewName
   450              }
   451          }
   452  
   453          singleAgg.MeasureOperations = measureAggs
   454          timechartExpr.SingleAgg = singleAgg
   455  
   456          if aggTemp.SplitByClause != nil {
   457              byField = aggTemp.SplitByClause.Field
   458          }
   459      }
   460  
   461      // TODO: if timechartArgs.evalExpr != nil {}
   462  
   463      aggNode.PipeCommandType = structs.GroupByType
   464      aggNode.GroupByRequest = &structs.GroupByRequest{
   465          MeasureOperations: measureAggs,
   466          GroupByColumns:    []string{"timestamp"},
   467      }
   468      aggNode.BucketLimit = query.MAX_GRP_BUCKS
   469  
   470      if bOptions == nil {
   471          bOptions = &structs.BinOptions{
   472              SpanOptions: &structs.SpanOptions{
   473                  DefaultSettings: true,
   474                  SpanLength: &structs.SpanLength{
   475                      Num: 1,
   476                      TimeScalr: utils.TMMinute,
   477                  },
   478              },
   479          }
   480      }
   481  
   482      var limitExprTmp *structs.LimitExpr
   483      if limitExpr != nil {
   484          limitExprTmp = limitExpr.(*structs.LimitExpr)
   485          if len(measureAggs) > 1 {
   486              limitExprTmp.LimitScoreMode = structs.LSMByFreq
   487          }
   488      }
   489  
   490      timeBucket := aggregations.InitTimeBucket(bOptions.SpanOptions.SpanLength.Num, bOptions.SpanOptions.SpanLength.TimeScalr, byField, limitExprTmp, len(measureAggs))
   491      aggNode.TimeHistogram = timeBucket
   492  
   493      return aggNode, nil
   494  }
   495  
   496  // To be finished: <eval-expression> BY <split-by-clause>
   497  // TimechartEvalExpr <- ... BY splitByClause:(SplitByClause) {
   498  // }
   499  
   500  TimechartArgumentsList <- first:TimechartArgument rest:(SPACE TimechartArgument)* {
   501      restSlice := rest.([]any)
   502      timechartArgs := &TimechartArgs{}
   503  
   504      numArgs := 1 + len(restSlice)
   505  
   506      for i :=0; i < numArgs; i++ {
   507  
   508          var numArg interface{}
   509  
   510          if i == 0 {
   511              numArg = first
   512          } else {
   513              numArg = restSlice[i - 1].([]any)[1]
   514          }
   515  
   516          switch numArg.(type) {
   517              case *singleAggTemp:
   518                  timechartArgs.singleAggExpr = numArg.(*singleAggTemp)
   519              case *structs.TcOptions:
   520                  timechartArgs.tcOptions = numArg.(*structs.TcOptions)
   521              default:
   522                  return nil, fmt.Errorf("Spl peg: Timechart: invalid timechart argument: %v", numArg)
   523          }
   524      }
   525      
   526      return timechartArgs, nil
   527  }
   528  
   529  TimechartArgument <- tcArg:(SingleAggExpr / TcOptions) {
   530      return tcArg, nil
   531  }
   532  
   533  SingleAggExpr <- aggs:AggregationList splitByClause:SplitByClause? {
   534      singleAggExpr := &singleAggTemp {
   535          aggregators: aggs.([]*aggregator),
   536      }
   537  
   538      if splitByClause != nil {
   539          singleAggExpr.SplitByClause = splitByClause.(*structs.SplitByClause)
   540      }
   541  
   542      return singleAggExpr, nil
   543  }
   544  
   545  // Syntax: <field> (<tc-options>)... [<where-clause>]
   546  // <where-clause> to be finished
   547  SplitByClause <- BY field:FieldName {
   548      splitByClause := &structs.SplitByClause {
   549          Field: field.(string),
   550      }
   551  
   552      return splitByClause, nil
   553  }
   554  
   555  TcOptions <- option:(BinOptions / (TcOption)+) {
   556      //Default value
   557      tcOptions := &structs.TcOptions{
   558          UseNull: true,
   559          UseOther: true,
   560          NullStr: "null",
   561          OtherStr: "other",
   562      }
   563      switch option.(type) {
   564      case *structs.BinOptions:
   565          tcOptions.BinOptions = option.(*structs.BinOptions)
   566      case [][]string:
   567          optionSlice := option.([]any)
   568          for _, opt := range optionSlice {
   569              optArr := opt.([]string)
   570              switch optArr[0] {
   571                  case "usenull":
   572                      useNullBool, err := strconv.ParseBool(optArr[1])
   573                      if err != nil {
   574                          return nil, fmt.Errorf("Spl peg: Timechart: TcOptions: %v", err)
   575                      }
   576                      tcOptions.UseNull = useNullBool
   577                  case "useother":
   578                      useOtherBool, err := strconv.ParseBool(optArr[1])
   579                      if err != nil {
   580                          return nil, fmt.Errorf("Spl peg: Timechart: TcOptions: %v", err)
   581                      }
   582                      tcOptions.UseOther = useOtherBool
   583                  case "nullstr":
   584                      tcOptions.OtherStr = optArr[1]
   585                  case "otherstr":
   586                      tcOptions.OtherStr = optArr[1]
   587                  default:
   588                      return nil, fmt.Errorf("Spl peg: Timechart: TcOptions: invalid option: %v", optArr[0])
   589              }
   590          }
   591      default:
   592          return nil, fmt.Errorf("Spl peg: Timechart: Invalid tcOptions %v", option)
   593      }
   594      return tcOptions, nil
   595  }
   596  
   597  TcOption <- SPACE tcOptionCMD:TcOptionCMD EQUAL val:EvalFieldToRead {
   598      tcOptionArr := []string{tcOptionCMD.(string), val.(string)}
   599      return tcOptionArr, nil
   600  }
   601  
   602  TcOptionCMD <- option:("usenull" / "useother" / "nullstr" / "otherstr") {
   603      optionStr, err := transferUint8ToString(option)
   604      if err != nil {
   605          return nil, fmt.Errorf("Spl peg: Timechart: TcOptionCMD: %v", err)
   606      }
   607      return optionStr, nil
   608  }
   609  
   610  // To be finished: bins=<int> | minspan=<span-length> | span | <start-end>: (end=<num> | start=<num>) | aligntime=(earliest | latest | <time-specifier>)
   611  BinOptions <- spanOptions:SpanOptions {
   612      binOptions := &structs.BinOptions {
   613          SpanOptions: spanOptions.(*structs.SpanOptions),
   614      }
   615      return binOptions, nil
   616  }
   617  
   618  // To be finished: span=<log-span> | span=<span-length> | span=<snap-to-time>
   619  SpanOptions <- CMD_SPAN EQUAL spanLength:SpanLength {
   620      spanOptions := &structs.SpanOptions {
   621          SpanLength: spanLength.(*structs.SpanLength),
   622      }
   623      return spanOptions, nil
   624  }
   625  
   626  SpanLength <- intAsStr:IntegerAsString timeScale:TimeScale{
   627      num, err := strconv.Atoi(intAsStr.(string))
   628      if err != nil {
   629          return nil, fmt.Errorf("SpanLength: Invalid num (%v): %v", intAsStr.(string), err)
   630      }
   631  
   632      spanLength := &structs.SpanLength {
   633          Num: num,
   634          TimeScalr: timeScale.(utils.TimeUnit),
   635      }
   636      return spanLength, nil
   637  }
   638  
   639  TimeScale <- timeUnit:(Second / Minute / Hour / Day/ Week / Month / Quarter/ Subseconds) {
   640      return timeUnit, nil
   641  }
   642  
   643  // limit=topN keeps the N highest scoring distinct values of the split-by field
   644  LimitExpr <- SPACE "limit" EQUAL sortBy:("top" / "bottom")? EMPTY_OR_SPACE intAsStr:(IntegerAsString){
   645      num, err := strconv.Atoi(intAsStr.(string))
   646      if err != nil {
   647          return nil, fmt.Errorf("SpanLength: Invalid num (%v): %v", intAsStr.(string), err)
   648      }
   649  
   650      limitExpr := &structs.LimitExpr {
   651          IsTop: true, // Default Value
   652          Num: num,
   653      }
   654  
   655      if sortBy != nil {
   656          sortByStr, err := transferUint8ToString(sortBy)
   657          if err != nil {
   658              return nil, fmt.Errorf("Spl peg: Timechart: %v", err)
   659          }
   660          if sortByStr == "bottom" {
   661              limitExpr.IsTop = false
   662          }
   663      }
   664  
   665      return limitExpr, nil
   666  }
   667  
   668  StatisticBlock <- PIPE statisticExpr:StatisticExpr {
   669      letColReq := &structs.LetColumnsRequest {
   670          StatisticColRequest: statisticExpr.(*structs.StatisticExpr),
   671      }
   672  
   673      root := &structs.QueryAggregators {
   674          PipeCommandType: structs.OutputTransformType,
   675          OutputTransforms: &structs.OutputTransforms {
   676              LetColumns: letColReq,
   677          },
   678      }
   679  
   680      measureAgg := &structs.MeasureAggregator {
   681          MeasureCol: "*",
   682          MeasureFunc: utils.Count,
   683      }
   684  
   685      measureOperations := make([]*structs.MeasureAggregator, 1)
   686      measureOperations[0] = measureAgg
   687  
   688      groupByColumns := append(statisticExpr.(*structs.StatisticExpr).FieldList, statisticExpr.(*structs.StatisticExpr).ByClause...)
   689  
   690      aggNode := &structs.QueryAggregators{}
   691      aggNode.Next = root
   692      aggNode.PipeCommandType = structs.GroupByType
   693      aggNode.GroupByRequest = &structs.GroupByRequest {
   694          MeasureOperations: measureOperations,
   695          GroupByColumns: groupByColumns,
   696      }
   697  
   698      return aggNode, nil
   699  }
   700  
   701  StatisticExpr <- cmd:(CMD_TOP / CMD_RARE) limit:(StatisticLimit)? fieldList:(SPACE FieldNameList) byClause:(ByClause)? options:(StatisticOptions)? {
   702  
   703      statisticExpr := &structs.StatisticExpr {
   704          FieldList: fieldList.([]interface{})[1].([]string),
   705      }
   706  
   707      statisticCmd, err := transferUint8ToString(cmd)
   708      if err != nil {
   709          return nil, fmt.Errorf("Spl peg: StatisticExpr: %v", err)
   710      }
   711  
   712      if(statisticCmd == "top"){
   713          statisticExpr.StatisticFunctionMode = structs.SFMTop
   714      } else {
   715          statisticExpr.StatisticFunctionMode = structs.SFMRare
   716      }
   717  
   718      if limit != nil {
   719          statisticExpr.Limit = limit.(string)
   720      }
   721  
   722      if options != nil {
   723          statisticExpr.StatisticOptions = options.(*structs.StatisticOptions)
   724      } else {
   725          statisticExpr.StatisticOptions = &structs.StatisticOptions {
   726              ShowCount: true,
   727              CountField: "count",
   728              ShowPerc: true,
   729              PercentField: "percent",
   730              UseOther: false,
   731              OtherStr: "Other",
   732          }
   733      }
   734  
   735      if byClause != nil {
   736          statisticExpr.ByClause = byClause.([]string)
   737      }
   738  
   739      return statisticExpr, nil
   740  }
   741  
   742  // Top limit=<int> is the same as specifying top N.
   743  StatisticLimit <- SPACE number:IntegerAsString {
   744      return number.(string), nil
   745  }
   746  / SPACE "limit" EQUAL limit:(IntegerAsString) {
   747      return limit.(string), nil
   748  }
   749  
   750  // Optional arguments for top/rare functions
   751  StatisticOptions <- option:(StatisticOption)*
   752  {
   753      //Default value
   754      options := &structs.StatisticOptions {
   755          ShowCount: true,
   756          CountField: "count",
   757          ShowPerc: true,
   758          PercentField: "percent",
   759          UseOther: false,
   760          OtherStr: "other",
   761      }
   762  
   763      optionSlice := option.([]any)
   764      for _, opt := range optionSlice {
   765          optArr :=  opt.([]string)
   766          // Check for matching option types
   767          switch optArr[0] {
   768          case "showcount":
   769              showCountBool, err := strconv.ParseBool(optArr[1])
   770              if err != nil {
   771                  return nil, fmt.Errorf("Spl peg: StatisticBlock: Options: %v", err)
   772              }
   773              options.ShowCount = showCountBool
   774          case "countfield":
   775              options.CountField = optArr[1]
   776          case "showperc":
   777              showPercBool, err := strconv.ParseBool(optArr[1])
   778              if err != nil {
   779                  return nil, fmt.Errorf("Spl peg: StatisticBlock: Options: %v", err)
   780              }
   781              options.ShowPerc = showPercBool
   782          case "percentfield":
   783              options.PercentField = optArr[1]
   784          case "useother":
   785              useOtherBool, err := strconv.ParseBool(optArr[1])
   786              if err != nil {
   787                  return nil, fmt.Errorf("Spl peg: StatisticBlock: Options: %v", err)
   788              }
   789              options.UseOther = useOtherBool
   790          case "otherstr":
   791              options.OtherStr = optArr[1]
   792          default:
   793              return nil, fmt.Errorf("Spl peg: StatisticBlock: Options: invalid option")
   794          }
   795      }
   796  
   797      return options, nil
   798  }
   799  
   800  StatisticOption <- SPACE optionCMD:StatisticOptionCMD EQUAL field:EvalFieldToRead {
   801      optionArr := []string{optionCMD.(string), field.(string)}
   802      return optionArr, nil
   803  }
   804  
   805  StatisticOptionCMD <- option:("countfield" / "showcount" / "otherstr" / "useother"/ "percentfield" / "showperc") {
   806      optionStr, err := transferUint8ToString(option)
   807      if err != nil {
   808          return nil, fmt.Errorf("Spl peg: StatisticExpr: %v", err)
   809      }
   810      return optionStr, nil
   811  }
   812  
   813  ByClause <- BY fieldList:FieldNameList {
   814      return fieldList.([]string), nil
   815  }
   816  / groupByBlock:GroupbyBlock {
   817      return groupByBlock.([]string), nil
   818  }
   819  
   820  DedupBlock <- PIPE CMD_DEDUP dedupExpr:DedupExpr {
   821  
   822      letColReq := &structs.LetColumnsRequest {
   823          DedupColRequest: dedupExpr.(*structs.DedupExpr),
   824      }
   825  
   826      root := &structs.QueryAggregators {
   827          PipeCommandType: structs.OutputTransformType,
   828          OutputTransforms: &structs.OutputTransforms {
   829              LetColumns: letColReq,
   830          },
   831      }
   832  
   833      return root, nil
   834  }
   835  
   836  // Returns *structs.DedupExpr
   837  // It's not clear in the Splunk documentation whether the DedupOptions should
   838  // be before or after the field list. However, the field list probably
   839  // shouldn't be after the sortby clause.
   840  DedupExpr <- limitArr:(SPACE IntegerAsString)? options1:(DedupOptions)? fieldList:(DedupFieldList)? options2:(DedupOptions)? sortByClause:(DedupSortByClause)? {
   841      dedupExpr := &structs.DedupExpr {
   842          FieldList: fieldList.([]string),
   843          Limit: 1,
   844          DedupCombinations: make(map[string]map[int][]structs.SortValue, 0),
   845          DedupRecords: make(map[string]map[string]interface{}, 0),
   846      }
   847  
   848      if limitArr != nil {
   849          limitStr := limitArr.([]interface{})[1].(string)
   850          limit, err := strconv.ParseUint(limitStr, 10, 64)
   851          if err != nil || limit == 0 {
   852              return nil, fmt.Errorf("Invalid limit (%v): %v", limitStr, err)
   853          }
   854          dedupExpr.Limit = limit
   855      }
   856  
   857      dedupExpr.DedupOptions = &structs.DedupOptions {
   858          Consecutive: false,
   859          KeepEmpty: false,
   860          KeepEvents: false,
   861      }
   862  
   863      if options1 != nil {
   864          dedupExpr.DedupOptions = options1.(*structs.DedupOptions)
   865      }
   866      if options2 != nil {
   867          options := options2.(*structs.DedupOptions)
   868  
   869          if options.Consecutive {
   870              dedupExpr.DedupOptions.Consecutive = options.Consecutive
   871          }
   872          if options.KeepEmpty {
   873              dedupExpr.DedupOptions.KeepEmpty = options.KeepEmpty
   874          }
   875          if options.KeepEvents {
   876              dedupExpr.DedupOptions.KeepEvents = options.KeepEvents
   877          }
   878      }
   879  
   880      if sortByClause != nil {
   881          dedupExpr.DedupSortEles = sortByClause.([]*structs.SortElement)
   882  
   883          // Make the DedupSortAscending from the DedupSortEles.
   884          dedupExpr.DedupSortAscending = make([]int, len(dedupExpr.DedupSortEles))
   885          for i, ele := range dedupExpr.DedupSortEles {
   886              if ele.SortByAsc {
   887                  dedupExpr.DedupSortAscending[i] = 1
   888              } else {
   889                  dedupExpr.DedupSortAscending[i] = -1
   890              }
   891          }
   892      }
   893  
   894      return dedupExpr, nil
   895  }
   896  
   897  DedupFieldName <- !("sortby") field:FieldName {
   898      return field, nil
   899  }
   900  
   901  DedupFieldList <- SPACE first:DedupFieldName rest:(SPACE DedupFieldName !EQUAL)* {
   902      // Convert `rest` to a slice. Each element of the slice will be a 2-element
   903      // slice where the first element is " " and the second is a FieldName.
   904      restSlice := rest.([]any)
   905  
   906      numFieldNames := 1 + len(restSlice)
   907      fields := make([]string, numFieldNames)
   908      fields[0] = first.(string)
   909  
   910      for i := 1; i < numFieldNames; i++ {
   911          separatorAndField := restSlice[i - 1].([]any)
   912          fields[i] = separatorAndField[1].(string)
   913      }
   914  
   915      return fields, nil
   916  }
   917  
   918  // Optional arguments for dedup block
   919  DedupOptions <- option:(DedupOption)*
   920  {
   921      //Default value
   922      options := &structs.DedupOptions {
   923          Consecutive: false,
   924          KeepEmpty: false,
   925          KeepEvents: false,
   926      }
   927  
   928      optionSlice := option.([]any)
   929      for _, opt := range optionSlice {
   930          optArr :=  opt.([]string)
   931          // Check for matching option types
   932          switch optArr[0] {
   933          case "consecutive":
   934              consecutiveBool, err := strconv.ParseBool(optArr[1])
   935              if err != nil {
   936                  return nil, fmt.Errorf("Spl peg: DedupBlock: Options: %v", err)
   937              }
   938              options.Consecutive = consecutiveBool
   939          case "keepempty":
   940              keepEmptyBool, err := strconv.ParseBool(optArr[1])
   941              if err != nil {
   942                  return nil, fmt.Errorf("Spl peg: DedupBlock: Options: %v", err)
   943              }
   944              options.KeepEmpty = keepEmptyBool
   945          case "keepevents":
   946              keepEventsBool, err := strconv.ParseBool(optArr[1])
   947              if err != nil {
   948                  return nil, fmt.Errorf("Spl peg: DedupBlock: Options: %v", err)
   949              }
   950              options.KeepEvents = keepEventsBool
   951          default:
   952              return nil, fmt.Errorf("Spl peg: DedupBlock: Options: invalid option")
   953          }
   954      }
   955  
   956      return options, nil
   957  }
   958  
   959  DedupOption <- SPACE optionCMD:DedupOptionCMD "=" field:EvalFieldToRead {
   960      optionArr := []string{optionCMD.(string), field.(string)}
   961      return optionArr, nil
   962  }
   963  
   964  DedupOptionCMD <- option:("consecutive" / "keepempty" / "keepevents") {
   965      optionStr, err := transferUint8ToString(option)
   966      if err != nil {
   967          return nil, fmt.Errorf("Spl peg: DedupExpr: %v", err)
   968      }
   969      return optionStr, nil
   970  }
   971  
   972  DedupSortByClause <- CMD_DEDUP_SORTBY dedupSortEles:SortElements {
   973      return dedupSortEles, nil
   974  }
   975  
   976  // sortby ( - | + ) <sort-field> [(- | +) <sort_field> ...]
   977  SortElements <- first:SingleSortElement rest:(EMPTY_OR_COMMA SingleSortElement)* {
   978      restSlice := rest.([]any)
   979  
   980      length := 1 + len(restSlice)
   981      sortEles := make([]*structs.SortElement, length)
   982      sortEles[0] = first.(*structs.SortElement)
   983  
   984      for i := 1; i < length; i++ {
   985          elements := restSlice[i - 1].([]any)
   986          sortEles[i] = elements[1].(*structs.SortElement)
   987      }
   988  
   989      return sortEles, nil
   990  }
   991  
   992  SingleSortElement <- element:(SingleSortElementWithCast / SingleSortElementWithoutCast) {
   993      return element, nil
   994  }
   995  
   996  SingleSortElementWithoutCast <- sortBySymbol:("+" / "-" / "") field:FieldName {
   997      sortByAsc := true
   998  
   999      symbol := sortBySymbol.([]byte)
  1000      if(len(symbol) > 0 && symbol[0] == '-') {
  1001          sortByAsc = false
  1002      }
  1003  
  1004      return &structs.SortElement {
  1005          SortByAsc: sortByAsc,
  1006          Op: "",
  1007          Field: field.(string),
  1008      }, nil
  1009  }
  1010  
  1011  SingleSortElementWithCast <- sortBySymbol:("+" / "-" / "") op:("auto" / "str" / "ip" / "num") L_PAREN field:FieldName R_PAREN {
  1012      sortByAsc := true
  1013  
  1014      symbol := sortBySymbol.([]byte)
  1015      if(len(symbol) > 0 && symbol[0] == '-') {
  1016          sortByAsc = false
  1017      }
  1018  
  1019      opStr, err := transferUint8ToString(op)
  1020      if err != nil {
  1021          return nil, fmt.Errorf("Spl peg: singleSortElementWithCast: %v", err)
  1022      }
  1023  
  1024      return &structs.SortElement {
  1025          SortByAsc: sortByAsc,
  1026          Op: opStr,
  1027          Field: field.(string),
  1028      }, nil
  1029  }
  1030  
  1031  RenameBlock <- PIPE CMD_RENAME renameExpr:RenameExpr {
  1032      letColReq := &structs.LetColumnsRequest {
  1033          RenameColRequest: renameExpr.(*structs.RenameExpr),
  1034      }
  1035  
  1036      root := &structs.QueryAggregators {
  1037          PipeCommandType: structs.OutputTransformType,
  1038          OutputTransforms: &structs.OutputTransforms {
  1039              LetColumns: letColReq,
  1040          },
  1041      }
  1042  
  1043      return root, nil
  1044  }
  1045  
  1046  // Rename with a phrase
  1047  RenameExpr <- originalPattern:RenamePattern AS newPattern:QuotedString {
  1048      renameExpr := &structs.RenameExpr {
  1049          RenameExprMode: structs.REMPhrase,
  1050          OriginalPattern: originalPattern.(string),
  1051          NewPattern: removeQuotes(newPattern),
  1052      }
  1053  
  1054      return renameExpr, nil
  1055  }
  1056  // Rename fields with similar names using a wildcard
  1057  // Or Rename to a existing field
  1058  / originalPattern:RenamePattern AS newPattern:RenamePattern {
  1059      isRegex, err := isRegexRename(originalPattern.(string), newPattern.(string))
  1060      if err != nil {
  1061          return nil, fmt.Errorf("Spl peg: RenameExpr: %v", err)
  1062      }
  1063  
  1064      var renameExprMode structs.RenameExprMode
  1065      if isRegex {
  1066          renameExprMode = structs.REMRegex
  1067      } else {
  1068          renameExprMode = structs.REMOverride
  1069      }
  1070  
  1071      renameExpr := &structs.RenameExpr {
  1072          RenameExprMode: renameExprMode,
  1073          OriginalPattern: originalPattern.(string),
  1074          NewPattern: newPattern.(string),
  1075      }
  1076  
  1077      return renameExpr, nil
  1078  }
  1079  
  1080  RexBlock <- PIPE CMD_REX "field" EQUAL field:EvalFieldToRead SPACE str:QuotedString {
  1081      pattern := removeQuotes(str)
  1082      rexColNames, err := getRexColNames(pattern)
  1083      if err != nil {
  1084          return nil, fmt.Errorf("Spl peg: RexBlock: %v", err)
  1085      }
  1086      rexExpr := &structs.RexExpr {
  1087          FieldName: field.(string),
  1088          Pattern: transferPCREToRE2(pattern),
  1089          RexColNames: rexColNames,
  1090      }
  1091  
  1092      letColReq := &structs.LetColumnsRequest {
  1093          RexColRequest: rexExpr,
  1094      }
  1095  
  1096      root := &structs.QueryAggregators {
  1097          PipeCommandType: structs.OutputTransformType,
  1098          OutputTransforms: &structs.OutputTransforms {
  1099              LetColumns: letColReq,
  1100          },
  1101      }
  1102  
  1103      return root, nil
  1104  }
  1105  
  1106  // arguments need to be finished:
  1107  // [<count>], [desc]
  1108  SortBlock <- PIPE CMD_SORT sortByEles:SortElements {
  1109  
  1110      sortExpr := &structs.SortExpr {
  1111          SortEles: sortByEles.([]*structs.SortElement),
  1112          SortRecords: make(map[string]map[string]interface{}, 0),
  1113      }
  1114  
  1115      ascendingArr := make([]int, len(sortExpr.SortEles))
  1116      for i, ele := range sortExpr.SortEles {
  1117          if ele.SortByAsc {
  1118              ascendingArr[i] = 1
  1119          } else {
  1120              ascendingArr[i] = -1
  1121          }
  1122      }
  1123  
  1124      sortExpr.SortAscending = ascendingArr
  1125  
  1126      letColReq := &structs.LetColumnsRequest {
  1127          SortColRequest: sortExpr,
  1128      }
  1129  
  1130      root := &structs.QueryAggregators {
  1131          PipeCommandType: structs.OutputTransformType,
  1132          OutputTransforms: &structs.OutputTransforms {
  1133              LetColumns: letColReq,
  1134          },
  1135      }
  1136  
  1137      return root, nil
  1138  }
  1139  
  1140  // Returns *structs.QueryAggregators
  1141  EvalBlock <- PIPE CMD_EVAL first:SingleEval rest:(COMMA SingleEval)* {
  1142      root := &structs.QueryAggregators {
  1143          PipeCommandType: structs.OutputTransformType,
  1144          OutputTransforms: &structs.OutputTransforms {
  1145              LetColumns: first.(*structs.LetColumnsRequest),
  1146          },
  1147      }
  1148  
  1149      leafQueryAgg := root
  1150      restSlice := rest.([]any)
  1151      for i := range restSlice {
  1152          CommaSpaceAndEval := restSlice[i].([]any)
  1153          nextQueryAgg := &structs.QueryAggregators {
  1154              PipeCommandType: structs.OutputTransformType,
  1155              OutputTransforms: &structs.OutputTransforms {
  1156                  LetColumns: CommaSpaceAndEval[1].(*structs.LetColumnsRequest),
  1157              },
  1158          }
  1159  
  1160          leafQueryAgg.Next = nextQueryAgg
  1161          leafQueryAgg = leafQueryAgg.Next
  1162      }
  1163  
  1164      return root, nil
  1165  }
  1166  
  1167  // Returns *structs.LetColumnsRequest
  1168  SingleEval <- field:FieldName EQUAL expr:EvalExpression {
  1169      fieldStr := field.(string)
  1170      if strings.Contains(fieldStr, "*") {
  1171          return nil, fmt.Errorf("New fields must not contain wildcards; invalid field: %v", field)
  1172      }
  1173  
  1174      letColumnsRequest := expr.(*structs.LetColumnsRequest)
  1175      letColumnsRequest.NewColName = fieldStr
  1176  
  1177      return letColumnsRequest, nil
  1178  }
  1179  
  1180  // Returns *structs.LetColumnsRequest without the NewColName set.
  1181  EvalExpression <- value:ValueExpr {
  1182      letColReq := &structs.LetColumnsRequest {
  1183          ValueColRequest: value.(*structs.ValueExpr),
  1184      }
  1185  
  1186      return letColReq, nil
  1187  }
  1188  
  1189  ConditionExpr <- "if" L_PAREN condition:BoolExpr COMMA trueValue:ValueExpr COMMA falseValue:ValueExpr R_PAREN {
  1190  
  1191      node := &structs.ConditionExpr {
  1192          Op: "if",
  1193          BoolExpr: condition.(*structs.BoolExpr),
  1194          TrueValue: trueValue.(*structs.ValueExpr),
  1195          FalseValue: falseValue.(*structs.ValueExpr),
  1196      }
  1197  
  1198      return node, nil
  1199  }
  1200  
  1201  TextExpr <- (opName:("lower") L_PAREN stringExpr:StringExpr R_PAREN) {
  1202      opNameStr, err := transferUint8ToString(opName)
  1203      if err != nil {
  1204          return nil, fmt.Errorf("Spl peg: TextExpr: %v", err)
  1205      }
  1206      node := &structs.TextExpr {
  1207          Op: opNameStr,
  1208          Value: stringExpr.(*structs.StringExpr),
  1209          StrToRemove: "",
  1210      }
  1211  
  1212      return node, nil
  1213  }
  1214  
  1215  / (opName:("max" / "min") L_PAREN firstVal:StringExpr rest:(COMMA StringExpr)* R_PAREN )
  1216        {
  1217          opNameStr, err := transferUint8ToString(opName)
  1218          if err != nil {
  1219              return nil, fmt.Errorf("Spl peg: TextExpr: %v", err)
  1220          }
  1221          if rest == nil {
  1222              return firstVal, nil
  1223          }
  1224          restSlice := rest.([]any)
  1225          values := make([]*structs.StringExpr, 1 + len(restSlice))
  1226          values[0] = firstVal.(*structs.StringExpr)
  1227  
  1228          for i := range restSlice {
  1229              stringAtom := restSlice[i].([]any)
  1230              values[i + 1] = stringAtom[1].(*structs.StringExpr)
  1231          }
  1232          node := &structs.TextExpr {
  1233              Op: opNameStr,
  1234              MaxMinValues: values,
  1235          }
  1236          return node, nil
  1237        }
  1238  / (opName:("urldecode") L_PAREN url:StringExpr R_PAREN ){
  1239          opNameStr, err := transferUint8ToString(opName)
  1240          if err != nil {
  1241          return nil, fmt.Errorf("Spl peg: TextExpr: %v", err)
  1242      }
  1243          node := &structs.TextExpr {
  1244              Op: opNameStr,
  1245              Value: url.(*structs.StringExpr),
  1246              StrToRemove: "",
  1247          }
  1248          return node, nil
  1249      }
  1250  / (opName:("split") L_PAREN stringExpr:StringExpr COMMA delim:StringExpr R_PAREN) {
  1251      opNameStr, err := transferUint8ToString(opName)
  1252      if err != nil {
  1253          return nil, fmt.Errorf("Spl peg: TextExpr: %v", err)
  1254      }
  1255      node := &structs.TextExpr {
  1256          Op: opNameStr,
  1257          Value: stringExpr.(*structs.StringExpr),
  1258          Delimiter: delim.(*structs.StringExpr),
  1259      }
  1260      return node, nil
  1261  }
  1262  / (opName:("substr") L_PAREN stringExpr:StringExpr COMMA startIndex:NumericExpr lengthParam:(COMMA NumericExpr)? R_PAREN) {
  1263      opNameStr, err := transferUint8ToString(opName)
  1264      if err != nil {
  1265          return nil, fmt.Errorf("Spl peg: TextExpr: %v", err)
  1266      }
  1267      stringExprConverted, ok := stringExpr.(*structs.StringExpr)
  1268      if !ok {
  1269          return nil, fmt.Errorf("Spl peg: TextExpr: Failed to assert stringExpr as *structs.StringExpr")
  1270      }
  1271      startIndexConverted, ok := startIndex.(*structs.NumericExpr)
  1272      if !ok {
  1273          return nil, fmt.Errorf("Spl peg: TextExpr: Failed to assert startIndex as *structs.NumericExpr")
  1274      }
  1275    var lengthConverted *structs.NumericExpr
  1276      if lengthParam != nil {
  1277          lengthSlice, ok := lengthParam.([]interface{})
  1278          if ok && len(lengthSlice) > 1 {
  1279              length, ok := lengthSlice[1].(*structs.NumericExpr)
  1280              if ok {
  1281                  lengthConverted = length
  1282              } else {
  1283                  return nil, fmt.Errorf("Spl peg: TextExpr: Unable to assert length as *structs.NumericExpr")
  1284              }
  1285          }
  1286      }
  1287      node := &structs.TextExpr {
  1288          Op: opNameStr,
  1289          Value: stringExprConverted,
  1290          StartIndex: startIndexConverted,
  1291          LengthExpr: lengthConverted,
  1292      }
  1293      return node, nil
  1294  }
  1295  / "tostring" L_PAREN value:ValueExpr format:(COMMA StringExpr )? R_PAREN {
  1296      var formatExpr *structs.StringExpr
  1297      if format != nil {
  1298          formatSlice := format.([]interface{})
  1299          formatExpr, _ = formatSlice[1].(*structs.StringExpr)
  1300      }
  1301      return &structs.TextExpr{
  1302          IsTerminal: false,
  1303          Op:         "tostring",
  1304          Val:        value.(*structs.ValueExpr),
  1305          Format:     formatExpr,
  1306      }, nil
  1307  }
  1308  / (opName:("ltrim" / "rtrim") L_PAREN expr:(StringExpr) strToRemoveExpr:(StrToRemoveExpr)? R_PAREN) {
  1309      opNameStr, err := transferUint8ToString(opName)
  1310      if err != nil {
  1311          return nil, fmt.Errorf("Spl peg: TextExpr: %v", err)
  1312      }
  1313  
  1314      stringExpr, ok := expr.(*structs.StringExpr)
  1315      if !ok {
  1316          return nil, fmt.Errorf("Spl peg: TextExpr: Failed to assert expr as *structs.StringExpr: %v", err)
  1317      }
  1318  
  1319      strToRemove := " \t"
  1320      if strToRemoveExpr != nil {
  1321          strToRemove = strToRemoveExpr.(string)
  1322      }
  1323  
  1324      node := &structs.TextExpr {
  1325          Op: opNameStr,
  1326          Value: stringExpr,
  1327          StrToRemove: removeQuotes(strToRemove),
  1328      }
  1329  
  1330      return node, nil
  1331  }
  1332  
  1333  StrToRemoveExpr <- COMMA strToRemove:String {
  1334      return strToRemove, nil
  1335  }
  1336  
  1337  // From https://docs.splunk.com/Documentation/Splunk/9.1.0/SearchReference/Eval#Syntax
  1338  // Returns the field as a string with no quotation marks.
  1339  EvalFieldToRead <- [a-zA-Z_]+ !("(") {
  1340      return string(c.text), nil
  1341  }
  1342  / "'" field:FieldName "'" {
  1343      return field, nil
  1344  }
  1345  
  1346  // Returns *structs.QueryAggregators
  1347  WhereBlock <- PIPE CMD_WHERE condition:BoolExpr {
  1348      queryAgg := &structs.QueryAggregators {
  1349          PipeCommandType: structs.OutputTransformType,
  1350          OutputTransforms: &structs.OutputTransforms {
  1351              FilterRows: condition.(*structs.BoolExpr),
  1352          },
  1353      }
  1354  
  1355      return queryAgg, nil
  1356  }
  1357  
  1358  // Returns *structs.BoolExpr
  1359  BoolExpr <- expr:BoolExprLevel4 {
  1360      return expr, nil
  1361  }
  1362  
  1363  // Returns *structs.BoolExpr
  1364  BoolExprLevel4 <- first:BoolExprLevel3 rest:(OR BoolExprLevel3)* {
  1365      if rest == nil {
  1366          return first, nil
  1367      }
  1368  
  1369      cur := first.(*structs.BoolExpr)
  1370      for _, v := range rest.([]any) {
  1371          opAndClause := v.([]any)
  1372          cur = &structs.BoolExpr {
  1373              IsTerminal: false,
  1374              BoolOp: structs.BoolOpOr,
  1375              LeftBool: cur,
  1376              RightBool: opAndClause[1].(*structs.BoolExpr),
  1377          }
  1378      }
  1379  
  1380      return cur, nil
  1381  }
  1382  
  1383  // Returns *structs.BoolExpr
  1384  BoolExprLevel3 <- first:BoolExprLevel2 rest:(AND BoolExprLevel2)* {
  1385      if rest == nil {
  1386          return first, nil
  1387      }
  1388  
  1389      cur := first.(*structs.BoolExpr)
  1390      for _, v := range rest.([]any) {
  1391          opAndClause := v.([]any)
  1392          cur = &structs.BoolExpr {
  1393              IsTerminal: false,
  1394              BoolOp: structs.BoolOpAnd,
  1395              LeftBool: cur,
  1396              RightBool: opAndClause[1].(*structs.BoolExpr),
  1397          }
  1398      }
  1399  
  1400      return cur, nil
  1401  }
  1402  
  1403  // Returns *structs.BoolExpr
  1404  BoolExprLevel2 <- NOT L_PAREN first:BoolExprLevel1 R_PAREN {
  1405      cur := &structs.BoolExpr {
  1406          IsTerminal: false,
  1407          BoolOp: structs.BoolOpNot,
  1408          LeftBool: first.(*structs.BoolExpr),
  1409          RightBool: nil,
  1410      }
  1411  
  1412      return cur, nil
  1413  }
  1414  / first:BoolExprLevel1 {
  1415      return first, nil
  1416  }
  1417  
  1418  // Returns *structs.BoolExpr
  1419  BoolExprLevel1 <- L_PAREN first:BoolExprLevel4 R_PAREN {
  1420      return first, nil
  1421  }
  1422  / (op:("isbool" / "isint" / "isstr" / "isnull") L_PAREN value:ValueExpr R_PAREN ) {
  1423      opNameStr, err := transferUint8ToString(op)
  1424      if err != nil {
  1425          return nil, fmt.Errorf("Spl peg: BoolExpr: %v", err)
  1426      }
  1427      expr := &structs.BoolExpr {
  1428          IsTerminal: true,
  1429          LeftValue: value.(*structs.ValueExpr),
  1430          RightValue: nil,
  1431          ValueOp: opNameStr,
  1432      }
  1433      return expr, nil
  1434  }
  1435  / likeExpr: LikeExpr {
  1436      return likeExpr, nil
  1437  }
  1438  LikeExpr <- left:ValueExpr SPACE "LIKE" SPACE right:ValueExpr {
  1439      expr := &structs.BoolExpr {
  1440          IsTerminal: true,
  1441          LeftValue: left.(*structs.ValueExpr),
  1442          RightValue: right.(*structs.ValueExpr),
  1443          ValueOp: "like",
  1444      }
  1445      return expr, nil
  1446  }
  1447  / "like" L_PAREN stringr:ValueExpr COMMA pattern:ValueExpr R_PAREN {
  1448       expr := &structs.BoolExpr {
  1449           IsTerminal: true,
  1450           LeftValue: stringr.(*structs.ValueExpr),
  1451           RightValue: pattern.(*structs.ValueExpr),
  1452           ValueOp: "like",
  1453       }
  1454       return expr, nil
  1455   }
  1456  / "match" L_PAREN stringVal:ValueExpr COMMA pattern:ValueExpr R_PAREN {
  1457       expr := &structs.BoolExpr {
  1458           IsTerminal: true,
  1459           LeftValue: stringVal.(*structs.ValueExpr),
  1460           RightValue: pattern.(*structs.ValueExpr),
  1461           ValueOp: "match",
  1462       }
  1463       return expr, nil
  1464   }
  1465  / "cidrmatch" L_PAREN cidr:ValueExpr COMMA ip:ValueExpr R_PAREN {
  1466      expr := &structs.BoolExpr {
  1467          IsTerminal: true,
  1468          LeftValue: cidr.(*structs.ValueExpr),
  1469          RightValue: ip.(*structs.ValueExpr),
  1470          ValueOp: "cidrmatch",
  1471      }
  1472      return expr, nil
  1473  }
  1474  / inExpr: InExpr {
  1475      return inExpr, nil
  1476  }
  1477  / boolComparisonExpr:BoolComparisonExpr {
  1478      return boolComparisonExpr, nil
  1479  }
  1480  
  1481  BoolComparisonExpr <- left:ValueExpr op:EqualityOrInequality right:ValueExpr {
  1482      expr := &structs.BoolExpr {
  1483          IsTerminal: true,
  1484          LeftValue: left.(*structs.ValueExpr),
  1485          RightValue: right.(*structs.ValueExpr),
  1486          ValueOp: op.(string),
  1487      }
  1488  
  1489      return expr, nil
  1490  }
  1491  
  1492  
  1493  InExpr <- left:ValueExpr SPACE "in" L_PAREN valueToJudge:ValueExpr rest:(COMMA ValueExpr)* R_PAREN {
  1494      restSlice := rest.([]any)
  1495      slice := make([]*structs.ValueExpr, 1 + len(restSlice))
  1496      slice[0] = valueToJudge.(*structs.ValueExpr)
  1497  
  1498      for i := range restSlice {
  1499          valueAtom := restSlice[i].([]any)
  1500          slice[i + 1] = valueAtom[1].(*structs.ValueExpr)
  1501      }
  1502  
  1503      expr := &structs.BoolExpr {
  1504          IsTerminal: true,
  1505          LeftValue: left.(*structs.ValueExpr),
  1506          ValueList: slice,
  1507          ValueOp: "in",
  1508      }
  1509      return expr, nil
  1510  }
  1511  // For this in use case: if(in(<value>, [<list>]), "true_value", "false_value")
  1512  / "in" L_PAREN valueToJudge:ValueExpr rest:(COMMA ValueExpr)* R_PAREN {
  1513      restSlice := rest.([]any)
  1514      slice := make([]*structs.ValueExpr, len(restSlice))
  1515  
  1516      for i := range restSlice {
  1517          valueAtom := restSlice[i].([]any)
  1518          slice[i] = valueAtom[1].(*structs.ValueExpr)
  1519      }
  1520  
  1521      expr := &structs.BoolExpr {
  1522          IsTerminal: true,
  1523          LeftValue: valueToJudge.(*structs.ValueExpr),
  1524          ValueList: slice,
  1525          ValueOp: "in",
  1526      }
  1527      return expr, nil
  1528  }
  1529  
  1530  // Returns *structs.ValueExpr
  1531  //
  1532  // The order of the choices is important. In particular, we want to parse a
  1533  // single field as a VEMField type ValueExpr so that it can be evaluated to
  1534  // either a string or float as needed (if the field has float values), rather
  1535  // than parsing it as a NumericExpr or ConcatExpr and forcing it to be a float
  1536  // or string respectively.
  1537  ValueExpr <- condition:ConditionExpr {
  1538  
  1539      expr := &structs.ValueExpr {
  1540          ValueExprMode: structs.VEMConditionExpr,
  1541          ConditionExpr: condition.(*structs.ConditionExpr),
  1542      }
  1543  
  1544      return expr, nil
  1545  }
  1546  / L_PAREN (condition:ConditionExpr) R_PAREN {
  1547  
  1548      expr := &structs.ValueExpr {
  1549          ValueExprMode: structs.VEMConditionExpr,
  1550          ConditionExpr: condition.(*structs.ConditionExpr),
  1551      }
  1552  
  1553      return expr, nil
  1554  }
  1555  / numeric:NumericExpr {
  1556  
  1557      expr := &structs.ValueExpr {
  1558          ValueExprMode: structs.VEMNumericExpr,
  1559          NumericExpr: numeric.(*structs.NumericExpr),
  1560      }
  1561  
  1562      return expr, nil
  1563  }
  1564  / str:StringExpr {
  1565  
  1566      expr := &structs.ValueExpr {
  1567          ValueExprMode: structs.VEMStringExpr,
  1568          StringExpr: str.(*structs.StringExpr),
  1569      }
  1570  
  1571      return expr, nil
  1572  }
  1573  / L_PAREN (str:StringExpr) R_PAREN {
  1574  
  1575      expr := &structs.ValueExpr {
  1576          ValueExprMode: structs.VEMStringExpr,
  1577          StringExpr: str.(*structs.StringExpr),
  1578      }
  1579  
  1580      return expr, nil
  1581  }
  1582  / L_PAREN boolean:BoolExpr R_PAREN {
  1583  
  1584      expr := &structs.ValueExpr{
  1585          ValueExprMode: structs.VEMBooleanExpr,
  1586          BooleanExpr: boolean.(*structs.BoolExpr),
  1587      }
  1588  
  1589      return expr, nil
  1590  }
  1591  
  1592  StringExpr <- text:TextExpr !(EVAL_CONCAT) {
  1593      expr := &structs.StringExpr {
  1594          StringExprMode: structs.SEMTextExpr,
  1595          TextExpr: text.(*structs.TextExpr),
  1596      }
  1597  
  1598      return expr, nil
  1599  }
  1600  / str:QuotedString !(EVAL_CONCAT) {
  1601      expr := &structs.StringExpr {
  1602          StringExprMode: structs.SEMRawString,
  1603          RawString: removeQuotes(str),
  1604      }
  1605  
  1606      return expr, nil
  1607  }
  1608  / field:EvalFieldToRead !(OpPlus / OpMinus / OpMul / OpDiv / EVAL_CONCAT / "(") {
  1609      expr := &structs.StringExpr {
  1610          StringExprMode: structs.SEMField,
  1611          FieldName: field.(string),
  1612      }
  1613  
  1614      return expr, nil
  1615  }
  1616  / concat:ConcatExpr {
  1617      expr := &structs.StringExpr {
  1618          StringExprMode: structs.SEMConcatExpr,
  1619          ConcatExpr: concat.(*structs.ConcatExpr),
  1620      }
  1621  
  1622      return expr, nil
  1623  }
  1624  
  1625  // Returns *structs.ConcatExpr
  1626  ConcatExpr <- first:ConcatAtom rest:(EVAL_CONCAT ConcatAtom)* !(OpPlus / OpMinus / OpMul / OpDiv / "(") {
  1627      restSlice := rest.([]any)
  1628      slice := make([]*structs.ConcatAtom, 1 + len(restSlice))
  1629      slice[0] = first.(*structs.ConcatAtom)
  1630  
  1631      for i := range restSlice {
  1632          concatAndAtom := restSlice[i].([]any)
  1633          slice[i + 1] = concatAndAtom[1].(*structs.ConcatAtom)
  1634      }
  1635  
  1636      expr := &structs.ConcatExpr {
  1637          Atoms: slice,
  1638      }
  1639  
  1640      return expr, nil
  1641  }
  1642  
  1643  // Returns *structs.ConcatAtom
  1644  ConcatAtom <- text:TextExpr {
  1645      atom := &structs.ConcatAtom {
  1646          IsField: false,
  1647          Value: "",
  1648          TextExpr: text.(*structs.TextExpr),
  1649      }
  1650  
  1651      return atom, nil
  1652  }
  1653  / str:QuotedString {
  1654      atom := &structs.ConcatAtom {
  1655          IsField: false,
  1656          Value: removeQuotes(str),
  1657      }
  1658  
  1659      return atom, nil
  1660  }
  1661  / number:NumberAsString {
  1662      atom := &structs.ConcatAtom {
  1663          IsField: false,
  1664          Value: number.(string),
  1665      }
  1666  
  1667      return atom, nil
  1668  }
  1669  / field:EvalFieldToRead {
  1670      atom := &structs.ConcatAtom {
  1671          IsField: true,
  1672          Value: field.(string),
  1673      }
  1674  
  1675      return atom, nil
  1676  }
  1677  
  1678  // Returns *structs.NumericExpr
  1679  NumericExpr <- expr:NumericExprLevel3 !(EVAL_CONCAT / "\"" ) {
  1680      return expr, nil
  1681  }
  1682  
  1683  // Returns *structs.NumericExpr
  1684  NumericExprLevel3 <- first:NumericExprLevel2 rest:((OpPlus / OpMinus) NumericExprLevel2)* {
  1685      if rest == nil {
  1686          return first, nil
  1687      }
  1688  
  1689      cur := first.(*structs.NumericExpr)
  1690      for _, v := range rest.([]any) {
  1691          opAndClause := v.([]any)
  1692          cur = &structs.NumericExpr {
  1693              IsTerminal: false,
  1694              Op: opAndClause[0].(string),
  1695              Left: cur,
  1696              Right: opAndClause[1].(*structs.NumericExpr),
  1697              NumericExprMode: structs.NEMNumericExpr,
  1698          }
  1699      }
  1700  
  1701      return cur, nil
  1702  }
  1703  
  1704  // Returns *structs.NumericExpr
  1705  NumericExprLevel2 <- first:NumericExprLevel1 rest:((OpMul / OpDiv) NumericExprLevel1)* {
  1706      if rest == nil {
  1707          return first, nil
  1708      }
  1709  
  1710      cur := first.(*structs.NumericExpr)
  1711      for _, v := range rest.([]any) {
  1712          opAndClause := v.([]any)
  1713          cur = &structs.NumericExpr {
  1714              IsTerminal: false,
  1715              Op: opAndClause[0].(string),
  1716              Left: cur,
  1717              Right: opAndClause[1].(*structs.NumericExpr),
  1718              NumericExprMode: structs.NEMNumericExpr,
  1719          }
  1720      }
  1721  
  1722      return cur, nil
  1723  }
  1724  
  1725  RoundPrecisionExpr <- COMMA expr:NumericExprLevel3 {
  1726      rightNumericExpr, ok := expr.(*structs.NumericExpr)
  1727      if !ok {
  1728          return nil, fmt.Errorf("Failed to assert expr as *structs.NumericExpr")
  1729      }
  1730  
  1731      return rightNumericExpr, nil
  1732  }
  1733  
  1734  // Returns *structs.NumericExpr
  1735  NumericExprLevel1 <- L_PAREN expr:NumericExprLevel3 R_PAREN {
  1736      return expr, nil
  1737  }
  1738  / numericEvalExpr: NumericEvalExpr {
  1739      return numericEvalExpr, nil
  1740  }
  1741  / field:EvalFieldToRead {
  1742      expr := &structs.NumericExpr {
  1743          IsTerminal: true,
  1744          ValueIsField: true,
  1745          Value: field.(string),
  1746          NumericExprMode: structs.NEMNumberField,
  1747      }
  1748  
  1749      return expr, nil
  1750  }
  1751  / number:NumberAsString {
  1752      expr := &structs.NumericExpr {
  1753          IsTerminal: true,
  1754          ValueIsField: false,
  1755          Value: number.(string),
  1756          NumericExprMode: structs.NEMNumber,
  1757      }
  1758  
  1759      return expr, nil
  1760  }
  1761  
  1762  //Currently involves abs, ceil, round, sqrt
  1763  NumericEvalExpr <- (opName:("abs" / "ceil" / "sqrt"/ "exact"/ "exp") L_PAREN expr:(NumericExprLevel3) R_PAREN) {
  1764      leftNumericExpr, ok := expr.(*structs.NumericExpr)
  1765      if !ok {
  1766          return nil, fmt.Errorf("Failed to assert expr as *structs.NumericExpr")
  1767      }
  1768  
  1769      //transfer []uint8 to string
  1770      strData, ok := opName.([]byte)
  1771      if !ok {
  1772          return nil, fmt.Errorf("opName is not a []byte")
  1773      }
  1774  
  1775      opNameStr := string(strData)
  1776      node, err := createNumericExpr(opNameStr, leftNumericExpr, nil, structs.NEMNumericExpr)
  1777      if err != nil {
  1778          return nil, err
  1779      }
  1780  
  1781      return node, nil
  1782  }
  1783  / roundExpr:"round" L_PAREN expr:(NumericExprLevel3) roundPrecision:(RoundPrecisionExpr)? R_PAREN {
  1784      leftNumericExpr, ok := expr.(*structs.NumericExpr)
  1785      if !ok {
  1786          return nil, fmt.Errorf("Failed to assert expr as *structs.NumericExpr")
  1787      }
  1788  
  1789      var rightNumericExpr *structs.NumericExpr
  1790      if roundPrecision != nil {
  1791          rightNumericExpr, ok = roundPrecision.(*structs.NumericExpr)
  1792          if !ok {
  1793              return nil, fmt.Errorf("Failed to assert roundPrecision as *structs.NumericExpr")
  1794          }
  1795      }
  1796  
  1797      node, err := createNumericExpr("round", leftNumericExpr, rightNumericExpr, structs.NEMNumericExpr)
  1798      if err != nil {
  1799          return nil, err
  1800      }
  1801  
  1802      return node, nil
  1803  }
  1804  / "now" "()" {
  1805      return &structs.NumericExpr{
  1806          IsTerminal: true,
  1807          Op:         "now",
  1808      }, nil
  1809  }
  1810  / "tonumber" L_PAREN stringExpr:StringExpr baseExpr:(COMMA NumericExprLevel3)? R_PAREN {
  1811      stringExprConverted, ok := stringExpr.(*structs.StringExpr)
  1812      if !ok {
  1813          return nil, fmt.Errorf("Failed to assert stringExpr as *structs.StringExpr")
  1814      }
  1815  
  1816      var baseExprConverted *structs.NumericExpr
  1817      if baseExpr != nil {
  1818          baseSlice, ok := baseExpr.([]interface{})
  1819          if ok && len(baseSlice) > 1 {
  1820              if base, ok := baseSlice[1].(*structs.NumericExpr); ok {
  1821                  baseExprConverted = base
  1822              } else {
  1823                  return nil, fmt.Errorf("Failed to assert base as *structs.NumericExpr")
  1824              }
  1825          }
  1826      }
  1827  
  1828      node := &structs.NumericExpr {
  1829          IsTerminal: false,
  1830          Op: "tonumber",
  1831          Left: nil,
  1832          Right: baseExprConverted,
  1833          Val: stringExprConverted,
  1834          NumericExprMode: structs.NEMNumericExpr,
  1835      }
  1836      return node, nil
  1837  }
  1838  / lenExpr: "len" L_PAREN expr:LenExpr R_PAREN {
  1839      return expr, nil
  1840  }
  1841  
  1842  LenExpr <- str:QuotedString !(EVAL_CONCAT) {
  1843  
  1844      leftNumericExpr := &structs.NumericExpr{
  1845          IsTerminal: true,
  1846          ValueIsField: false,
  1847          Value: str.(string),
  1848          NumericExprMode: structs.NEMLenString,
  1849      }
  1850  
  1851      node, err := createNumericExpr("len", leftNumericExpr, nil, structs.NEMLenString)
  1852      if err != nil {
  1853          return nil, err
  1854      }
  1855  
  1856      return node, nil
  1857  }
  1858  / field:EvalFieldToRead !(OpPlus / OpMinus / OpMul / OpDiv / EVAL_CONCAT / "(") {
  1859  
  1860      leftNumericExpr := &structs.NumericExpr{
  1861          IsTerminal: true,
  1862          ValueIsField: true,
  1863          Value: field.(string),
  1864          NumericExprMode: structs.NEMLenField,
  1865      }
  1866  
  1867      node, err := createNumericExpr("len", leftNumericExpr, nil, structs.NEMLenField)
  1868      if err != nil {
  1869          return nil, err
  1870      }
  1871  
  1872      return node, nil
  1873  }
  1874  
  1875  // Returns *structs.QueryAggregators
  1876  HeadBlock <- PIPE CMD_HEAD ("limit" EQUAL)? intAsStr:IntegerAsString {
  1877      limit, err := strconv.ParseUint(intAsStr.(string), 10, 64)
  1878      if err != nil {
  1879          return nil, fmt.Errorf("Invalid limit (%v): %v", intAsStr.(string), err)
  1880      }
  1881  
  1882      queryAgg := &structs.QueryAggregators {
  1883          PipeCommandType: structs.OutputTransformType,
  1884          OutputTransforms: &structs.OutputTransforms {
  1885              MaxRows: limit,
  1886          },
  1887      }
  1888  
  1889      return queryAgg, nil
  1890  }
  1891  / PIPE CMD_HEAD_NO_SPACE {
  1892      queryAgg := &structs.QueryAggregators {
  1893          PipeCommandType: structs.OutputTransformType,
  1894          OutputTransforms: &structs.OutputTransforms {
  1895              MaxRows: uint64(10), // From https://docs.splunk.com/Documentation/Splunk/9.1.0/SearchReference/Head
  1896          },
  1897      }
  1898  
  1899      return queryAgg, nil
  1900  }
  1901  
  1902  // Parses one or more AggFunctions separated by a comma and space.
  1903  // Returns a slice containing all the AggFunctions.
  1904  AggregationList <- first:Aggregator rest:((COMMA / SPACE) Aggregator)* {
  1905      // Convert `rest` to a slice. Each element of the slice will be a 2-element
  1906      // slice where the first element is ", " and the second is an Aggregator.
  1907      restSlice := rest.([]any)
  1908  
  1909      numAggs := 1 + len(restSlice)
  1910      aggsSlice := make([]*aggregator, numAggs)
  1911      aggsSlice[0] = first.(*aggregator)
  1912  
  1913      for i := 1; i < numAggs; i++ {
  1914          separatorAndAgg := restSlice[i - 1].([]any)
  1915          aggsSlice[i] = separatorAndAgg[1].(*aggregator)
  1916      }
  1917  
  1918      return aggsSlice, nil
  1919  }
  1920  
  1921  Aggregator <- aggFunc:AggFunction asField:AsField? {
  1922      agg := &aggregator{}
  1923      agg.measureAgg = aggFunc.(*structs.MeasureAggregator)
  1924  
  1925      if asField != nil {
  1926          agg.renameOutputField = true
  1927          agg.outputFieldNewName = asField.(string)
  1928      }
  1929  
  1930      return agg, nil
  1931  }
  1932  
  1933  // For evaluation statements inside aggregate functions:
  1934  // 1. min, max, sum, avg, and range can only evaluate boolComparisonExpr, as they need to compute the field value inside the expression. There should be only one field.
  1935  // 2. count can evaluate boolExpr because it does not care about the field value inside the expression. It only cares about whether the current row should be counted or not.
  1936  // 3. distinctCount and values can evaluate valueExpr because they just need to find out the distinct values of the result of the expression. As for the type of the expression result, it is not important.
  1937  AggFunction <- agg:(AggCount / AggDistinctCount / AggAvg / AggMin / AggMax / AggRange / AggSum / AggValues) {
  1938      return agg, nil
  1939  }
  1940  
  1941  AsField <- AS field: (FieldName / String) {
  1942      fieldStr := field.(string)
  1943  
  1944      if strings.Contains(fieldStr, "*") {
  1945          return nil, errors.New("The field specified in `AS` cannot contain wildcards")
  1946      }
  1947      
  1948      if fieldStr[0] == '"' && fieldStr[len(fieldStr)-1] == '"' {
  1949          fieldStr = fieldStr[1 : len(fieldStr)-1]
  1950      }
  1951  
  1952      return fieldStr, nil
  1953  }
  1954  
  1955  AggCount <- ("count" / "c") L_PAREN "eval" boolExpr:BoolExpr R_PAREN {
  1956      valueExpr := &structs.ValueExpr {
  1957          ValueExprMode: structs.VEMBooleanExpr,
  1958          BooleanExpr: boolExpr.(*structs.BoolExpr),
  1959      }
  1960  
  1961      agg := &structs.MeasureAggregator {
  1962          MeasureCol: "",
  1963          MeasureFunc: utils.Count,
  1964          StrEnc: string(c.text),
  1965          ValueColRequest: valueExpr,
  1966      }
  1967  
  1968      return agg, nil
  1969  }
  1970  / ("count" / "c") L_PAREN field:FieldName R_PAREN {
  1971      agg := &structs.MeasureAggregator {
  1972          MeasureCol: field.(string),
  1973          MeasureFunc: utils.Count,
  1974      }
  1975  
  1976      return agg, nil
  1977  } / ("count" / "c") {
  1978      agg := &structs.MeasureAggregator {
  1979          MeasureCol: "*",
  1980          MeasureFunc: utils.Count,
  1981      }
  1982  
  1983      return agg, nil
  1984  }
  1985  
  1986  AggDistinctCount <- ("distinct_count" / "dc") L_PAREN "eval" valueExpr:ValueExpr R_PAREN {
  1987      agg := &structs.MeasureAggregator {
  1988          MeasureCol: "",
  1989          MeasureFunc: utils.Cardinality,
  1990          StrEnc: string(c.text),
  1991          ValueColRequest: valueExpr.(*structs.ValueExpr),
  1992      }
  1993  
  1994      return agg, nil
  1995  }
  1996  / ("distinct_count" / "dc") L_PAREN field:FieldName R_PAREN {
  1997      agg := &structs.MeasureAggregator {
  1998          MeasureCol: field.(string),
  1999          MeasureFunc: utils.Cardinality,
  2000      }
  2001  
  2002      return agg, nil
  2003  }
  2004  
  2005  AggAvg <- "avg" L_PAREN "eval" L_PAREN boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN {
  2006      valueExpr := &structs.ValueExpr {
  2007          ValueExprMode: structs.VEMBooleanExpr,
  2008          BooleanExpr: boolComparisonExpr.(*structs.BoolExpr),
  2009      }
  2010  
  2011      agg := &structs.MeasureAggregator {
  2012          MeasureCol: "",
  2013          MeasureFunc: utils.Avg,
  2014          StrEnc: string(c.text),
  2015          ValueColRequest: valueExpr,
  2016      }
  2017  
  2018      return agg, nil
  2019  }
  2020  / "avg" L_PAREN field:FieldName R_PAREN {
  2021      agg := &structs.MeasureAggregator {
  2022          MeasureCol: field.(string),
  2023          MeasureFunc: utils.Avg,
  2024      }
  2025  
  2026      return agg, nil
  2027  }
  2028  
  2029  AggMin <- "min" L_PAREN "eval" L_PAREN boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN {
  2030      valueExpr := &structs.ValueExpr {
  2031          ValueExprMode: structs.VEMBooleanExpr,
  2032          BooleanExpr: boolComparisonExpr.(*structs.BoolExpr),
  2033      }
  2034  
  2035      agg := &structs.MeasureAggregator {
  2036          MeasureCol: "",
  2037          MeasureFunc: utils.Min,
  2038          StrEnc: string(c.text),
  2039          ValueColRequest: valueExpr,
  2040      }
  2041  
  2042      return agg, nil
  2043  }
  2044  / "min" L_PAREN field:FieldName R_PAREN {
  2045      agg := &structs.MeasureAggregator {
  2046          MeasureCol: field.(string),
  2047          MeasureFunc: utils.Min,
  2048      }
  2049  
  2050      return agg, nil
  2051  }
  2052  
  2053  AggMax <- "max" L_PAREN "eval" L_PAREN  boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN {
  2054      valueExpr := &structs.ValueExpr {
  2055          ValueExprMode: structs.VEMBooleanExpr,
  2056          BooleanExpr: boolComparisonExpr.(*structs.BoolExpr),
  2057      }
  2058  
  2059      agg := &structs.MeasureAggregator {
  2060          MeasureCol: "",
  2061          MeasureFunc: utils.Max,
  2062          StrEnc: string(c.text),
  2063          ValueColRequest: valueExpr,
  2064      }
  2065  
  2066      return agg, nil
  2067  }
  2068  / "max" L_PAREN field:FieldName R_PAREN {
  2069      agg := &structs.MeasureAggregator {
  2070          MeasureCol: field.(string),
  2071          MeasureFunc: utils.Max,
  2072      }
  2073  
  2074      return agg, nil
  2075  }
  2076  
  2077  AggRange <- "range" L_PAREN "eval" L_PAREN boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN {
  2078      valueExpr := &structs.ValueExpr {
  2079          ValueExprMode: structs.VEMBooleanExpr,
  2080          BooleanExpr: boolComparisonExpr.(*structs.BoolExpr),
  2081      }
  2082  
  2083      agg := &structs.MeasureAggregator {
  2084          MeasureCol: "",
  2085          MeasureFunc: utils.Range,
  2086          StrEnc: string(c.text),
  2087          ValueColRequest: valueExpr,
  2088      }
  2089  
  2090      return agg, nil
  2091  }
  2092  / "range" L_PAREN field:FieldName R_PAREN {
  2093      agg := &structs.MeasureAggregator {
  2094          MeasureCol: field.(string),
  2095          MeasureFunc: utils.Range,
  2096      }
  2097  
  2098      return agg, nil
  2099  }
  2100  
  2101  AggSum <- "sum" L_PAREN "eval" L_PAREN boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN {
  2102      valueExpr := &structs.ValueExpr {
  2103          ValueExprMode: structs.VEMBooleanExpr,
  2104          BooleanExpr: boolComparisonExpr.(*structs.BoolExpr),
  2105      }
  2106  
  2107      agg := &structs.MeasureAggregator {
  2108          MeasureCol: "",
  2109          MeasureFunc: utils.Sum,
  2110          StrEnc: string(c.text),
  2111          ValueColRequest: valueExpr,
  2112      }
  2113  
  2114      return agg, nil
  2115  }
  2116  / "sum" L_PAREN field:FieldName R_PAREN {
  2117      agg := &structs.MeasureAggregator {
  2118          MeasureCol: field.(string),
  2119          MeasureFunc: utils.Sum,
  2120      }
  2121  
  2122      return agg, nil
  2123  }
  2124  
  2125  AggValues <- "values" L_PAREN "eval" valueExpr:ValueExpr R_PAREN {
  2126      agg := &structs.MeasureAggregator {
  2127          MeasureCol: "",
  2128          MeasureFunc: utils.Values,
  2129          StrEnc: string(c.text),
  2130          ValueColRequest: valueExpr.(*structs.ValueExpr),
  2131      }
  2132  
  2133      return agg, nil
  2134  }
  2135  / "values" L_PAREN field:FieldName R_PAREN {
  2136      agg := &structs.MeasureAggregator {
  2137          MeasureCol: field.(string),
  2138          MeasureFunc: utils.Values,
  2139      }
  2140  
  2141      return agg, nil
  2142  }
  2143  
  2144  FieldWithNumberValue <- keyValuePair:(NamedFieldWithNumberValue / UnnamedFieldWithNumberValue) {
  2145      return keyValuePair, nil
  2146  }
  2147  
  2148  NamedFieldWithNumberValue <- key:FieldName op:(EqualityOperator / InequalityOperator) value:Number {
  2149      node := &ast.Node{
  2150          NodeType: ast.NodeTerminal,
  2151          Comparison:ast.Comparison{
  2152              Op: op.(string),
  2153              Field: key.(string),
  2154              Values: value,
  2155          },
  2156      }
  2157  
  2158      return node, nil
  2159  }
  2160  
  2161  UnnamedFieldWithNumberValue <- value:Number {
  2162      node := &ast.Node{
  2163          NodeType: ast.NodeTerminal,
  2164          Comparison:ast.Comparison{
  2165              Op: "=",
  2166              Field: "*",
  2167              Values: value,
  2168          },
  2169      }
  2170  
  2171      return node, nil
  2172  }
  2173  
  2174  FieldWithBooleanValue <- key:FieldName op:EqualityOperator value:Boolean {
  2175      node := &ast.Node{
  2176          NodeType: ast.NodeTerminal,
  2177          Comparison:ast.Comparison{
  2178              Op: op.(string),
  2179              Field: key.(string),
  2180              Values: value,
  2181          },
  2182      }
  2183  
  2184      return node, nil
  2185  }
  2186  
  2187  FieldWithStringValue <- keyValuePair:(NamedFieldWithStringValue / UnnamedFieldWithStringValue) {
  2188      return keyValuePair, nil
  2189  }
  2190  
  2191  NamedFieldWithStringValue <- key:FieldName op:EqualityOperator value:String {
  2192      node := &ast.Node{
  2193          NodeType: ast.NodeTerminal,
  2194          Comparison:ast.Comparison{
  2195              Op: op.(string),
  2196              Field: key.(string),
  2197              Values: value,
  2198          },
  2199      }
  2200      return node, nil
  2201  }
  2202  
  2203  UnnamedFieldWithStringValue <- value:String {
  2204      node := &ast.Node{
  2205          NodeType: ast.NodeTerminal,
  2206          Comparison:ast.Comparison{
  2207              Op: "=",
  2208              Field: "*",
  2209              Values: value,
  2210          },
  2211      }
  2212      return node, nil
  2213  }
  2214  
  2215  // Parses one or more FieldNames separated by a comma and space.
  2216  // Returns a slice containing all the FieldNames.
  2217  FieldNameList <- first:FieldName rest:(COMMA FieldName)* {
  2218      // Convert `rest` to a slice. Each element of the slice will be a 2-element
  2219      // slice where the first element is ", " and the second is a FieldName.
  2220      restSlice := rest.([]any)
  2221  
  2222      numFieldNames := 1 + len(restSlice)
  2223      fields := make([]string, numFieldNames)
  2224      fields[0] = first.(string)
  2225  
  2226      for i := 1; i < numFieldNames; i++ {
  2227          separatorAndField := restSlice[i - 1].([]any)
  2228          fields[i] = separatorAndField[1].(string)
  2229      }
  2230  
  2231      return fields, nil
  2232  }
  2233  
  2234  // From https://docs.splunk.com/Documentation/Splunk/7.3.1/Knowledge/Aboutregularexpressionswithfieldextractions
  2235  // This allows wildcards in a FieldName, but wildcard fields are not allowed in
  2236  // some places; those rules should check whether the field has a wildcard.
  2237  FieldName <- [a-zA-Z0-9:*][a-zA-Z0-9:_.*]* {
  2238      return string(c.text), nil
  2239  }
  2240  
  2241  String <- str:(QuotedString / UnquotedString) {
  2242      return str, nil
  2243  }
  2244  
  2245  QuotedString <- '"' [^"]* '"' {
  2246      // The returned string has quotes as the first and last character.
  2247      return string(c.text), nil
  2248  }
  2249  
  2250  Boolean <- ("true" / "false") {
  2251      boolValue, _ := strconv.ParseBool(string(c.text))
  2252      return boolValue, nil
  2253  }
  2254  
  2255  UnquotedString <- ("*" / (!(MAJOR_BREAK / "|" / EOF) .))+ {
  2256      // Return the string wrapped in quotes.
  2257      str := "\"" + string(c.text) + "\""
  2258      return str, nil
  2259  }
  2260  
  2261  //Can recognize fieldName or Regex Pattern for Rename Block
  2262  RenamePattern <- [a-zA-Z0-9_*]+ {
  2263      return string(c.text), nil
  2264  }
  2265  
  2266  Number <- number:NumberAsString {
  2267      return json.Number(number.(string)), nil
  2268  }
  2269  
  2270  // If a number isn't followed by a space, ")", comma, or EOF, we probably want
  2271  // to fail and parse it as a string instead.
  2272  NumberAsString <- number:(FloatAsString / IntegerAsString) &(SPACE / "|" / ")" / "," / EOF) {
  2273      return number, nil
  2274  }
  2275  
  2276  // Allow leading zeros, a "+" before the number, and a decimal point before
  2277  // the first digit.
  2278  FloatAsString <- [-+]? [0-9]* "." [0-9]+ {
  2279      return string(c.text), nil
  2280  }
  2281  
  2282  // Allow leading zeros and a "+" before the number.
  2283  IntegerAsString <- [-+]? [0-9]+ {
  2284      return string(c.text), nil
  2285  }
  2286  
  2287  EqualityOperator <- EMPTY_OR_SPACE op:("=" / "!=") EMPTY_OR_SPACE {
  2288      opStr, err := transferUint8ToString(op)
  2289      if err != nil {
  2290          return nil, fmt.Errorf("Spl peg: EqualityOperator: %v", err)
  2291      }
  2292      return opStr, nil
  2293  }
  2294  
  2295  InequalityOperator <- EMPTY_OR_SPACE op:("<=" / "<" / ">=" / ">") EMPTY_OR_SPACE {
  2296      opStr, err := transferUint8ToString(op)
  2297      if err != nil {
  2298          return nil, fmt.Errorf("Spl peg: InequalityOperator: %v", err)
  2299      }
  2300      return opStr, nil
  2301  }
  2302  
  2303  EqualityOrInequality <- op:EqualityOperator {
  2304      return op, nil
  2305  }
  2306  / op:InequalityOperator {
  2307      return op, nil
  2308  }
  2309  
  2310  OpPlus <- EMPTY_OR_SPACE "+" EMPTY_OR_SPACE {
  2311      return "+", nil
  2312  }
  2313  
  2314  OpMinus <- EMPTY_OR_SPACE "-" EMPTY_OR_SPACE {
  2315      return "-", nil
  2316  }
  2317  
  2318  OpMul <- EMPTY_OR_SPACE "*" EMPTY_OR_SPACE {
  2319      return "*", nil
  2320  }
  2321  
  2322  OpDiv <- EMPTY_OR_SPACE "/" EMPTY_OR_SPACE {
  2323      return "/", nil
  2324  }
  2325  
  2326  // Add Empty space here
  2327  Second <- ("seconds" / "second" / "secs" / "sec" / "s") {
  2328      return utils.TMSecond, nil
  2329  }
  2330  
  2331  Minute <- ("minutes" / "minute" / "mins" / "min" / "m") {
  2332      return utils.TMMinute, nil
  2333  }
  2334  
  2335  Hour <- ("hours" / "hour" / "hrs" / "hr" / "h") {
  2336      return utils.TMHour, nil
  2337  }
  2338  
  2339  Day <- ("days" / "day" / "d") {
  2340      return utils.TMDay, nil
  2341  }
  2342  
  2343  Week <- ("weeks" / "week" / "w") {
  2344      return utils.TMWeek, nil
  2345  }
  2346  
  2347  Month <- ("months" / "month" / "mon") {
  2348      return utils.TMMonth, nil
  2349  }
  2350  
  2351  Quarter <- ("quarters" / "quarter" / "qtrs" / "qtr" / "q") {
  2352      return utils.TMQuarter, nil
  2353  }
  2354  
  2355  // Might not has effect for 'us', because smallest time unit for timestamp in siglens is ms
  2356  Subseconds <- ("us" / "ms" / "cs" / "ds") {
  2357      timeUnit, err := utils.ConvertSubseconds(string(c.text))
  2358      if err != nil {
  2359          return nil, fmt.Errorf("Spl peg: Subseconds: %v", err)
  2360      }
  2361      return timeUnit, nil
  2362  }
  2363  
  2364  // Returns *structs.QueryAggregators
  2365  TransactionBlock <- PIPE CMD_TRANSACTION txnOptions:TransactionOptions {
  2366      queryAgg := &structs.QueryAggregators{
  2367          PipeCommandType: structs.TransactionType,
  2368          TransactionArguments: txnOptions.(*structs.TransactionArguments),
  2369      }
  2370      return queryAgg, nil
  2371  }
  2372  
  2373  // The TransactionDefinitionOptionsList will consist of all the Transaction Options
  2374  TransactionOptions <- txnOptions:TransactionDefinitionOptionsList?  {
  2375  
  2376      transactionRequest := &structs.TransactionArguments{}
  2377       
  2378      if txnOptions != nil {
  2379          txnArgs := txnOptions.(*TxnArgs).arguments
  2380          transactionRequest.Fields = txnArgs.Fields
  2381          transactionRequest.StartsWith = txnArgs.StartsWith
  2382          transactionRequest.EndsWith = txnArgs.EndsWith
  2383      }
  2384  
  2385      return transactionRequest, nil
  2386  }
  2387  
  2388  
  2389  TransactionDefinitionOptionsList <- first:TransactionDefinitionOption rest:(SPACE TransactionDefinitionOption)* {
  2390  
  2391      restSlice := rest.([]any)
  2392      txnArgs := &TxnArgs{
  2393          argOption: "txn-definition",
  2394          arguments: &structs.TransactionArguments{},
  2395      }
  2396  
  2397      numArgs := 1 + len(restSlice)
  2398  
  2399      for i := 0; i < numArgs; i++ {
  2400          var txnArg *TxnArgs
  2401          if i == 0 {
  2402              txnArg = first.(*TxnArgs)
  2403          } else {
  2404              separatorAndArg := restSlice[i - 1].([]any)
  2405              txnArg = separatorAndArg[1].(*TxnArgs)
  2406          }
  2407          argOption := txnArg.argOption
  2408  
  2409          switch argOption {
  2410              case "fields":
  2411                  txnArgs.arguments.Fields = txnArg.arguments.Fields
  2412              case "startswith": 
  2413                  txnArgs.arguments.StartsWith = txnArg.arguments.StartsWith
  2414              case "endswith":
  2415                  txnArgs.arguments.EndsWith = txnArg.arguments.EndsWith
  2416              default: 
  2417                  return nil, fmt.Errorf("Not a Valid Transaction Argument option")
  2418          }
  2419      }
  2420  
  2421      return txnArgs, nil
  2422  }
  2423  
  2424  TransactionDefinitionOption <- option:(SpaceSeparatedFieldNameList / StartsWithOption / EndsWithOption) {
  2425      return option, nil
  2426  }
  2427  
  2428  // Parses one or more FieldNames separate by a space
  2429  // Returns a slice containing all the FieldNames
  2430  SpaceSeparatedFieldNameList <- first:FieldName !(EQUAL) rest:(SPACE FieldName !(EQUAL))* {
  2431      var fields []string
  2432      fields = append(fields, first.(string))
  2433      for _, r := range rest.([]any) {
  2434          // Extracting the field name from the tuple (SPACE, FieldName)
  2435          fields = append(fields, r.([]any)[1].(string))
  2436      }
  2437  
  2438      txnArg := &TxnArgs{
  2439          argOption: "fields",
  2440          arguments: &structs.TransactionArguments{
  2441              Fields: fields,
  2442          },
  2443      }
  2444  
  2445      return txnArg, nil
  2446  }
  2447  
  2448  StartsWithOption <- "startswith" EQUAL strExpr:TransactionFilterString {
  2449      txnArg := &TxnArgs{
  2450          argOption: "startswith",
  2451          arguments: &structs.TransactionArguments{
  2452              StartsWith: strExpr.(*structs.FilterStringExpr),
  2453          }, 
  2454      }
  2455      return txnArg, nil
  2456  }
  2457  
  2458  EndsWithOption <- "endswith" EQUAL strExpr:TransactionFilterString {
  2459      txnArg := &TxnArgs{
  2460          argOption: "endswith",
  2461          arguments: &structs.TransactionArguments{
  2462              EndsWith: strExpr.(*structs.FilterStringExpr),
  2463          },
  2464      }
  2465      return txnArg, nil
  2466  }
  2467  
  2468  // Returns structs.FilterStringExpr
  2469  TransactionFilterString <- strExpr:(TransactionQuotedString / TransactionEval / TransactionSearch) {
  2470      return strExpr, nil
  2471  }
  2472  
  2473  TransactionQuotedString <- str:(TransactionQuotedStringValue / TransactionQuotedStringSearchExpr) {
  2474      return str, nil
  2475  }
  2476  
  2477  TransactionQuotedStringSearchExpr <- '"' searchClause:ClauseLevel4 '"' {
  2478      filterStrExpr := &structs.FilterStringExpr{
  2479         SearchNode: searchClause.(*ast.Node),
  2480      }
  2481  
  2482      return filterStrExpr, nil
  2483  }
  2484  
  2485  QuotedStringNoOp <- '"' [^" !(OR / AND)]*  '"' {
  2486      // The returned string has quotes as the first and last character.
  2487      return string(c.text), nil
  2488  }
  2489  
  2490  TransactionQuotedStringValue <- str:QuotedStringNoOp {
  2491      filterStrExpr := &structs.FilterStringExpr{
  2492         StringValue: removeQuotes(str.(string)),
  2493      }
  2494  
  2495      return filterStrExpr, nil
  2496  }
  2497  
  2498  TransactionSearch <- expr:ClauseLevel1 {
  2499      
  2500      filterStrExpr := &structs.FilterStringExpr{
  2501         SearchNode: expr.(*ast.Node),
  2502      }
  2503  
  2504      return filterStrExpr, nil
  2505  }
  2506  
  2507  // eval(<bool-expression>)
  2508  TransactionEval <- "eval" EMPTY_OR_SPACE L_PAREN condition:BoolExpr R_PAREN {
  2509      filterStrExpr := &structs.FilterStringExpr{
  2510          EvalBoolExpr: condition.(*structs.BoolExpr),
  2511      }
  2512  
  2513      return filterStrExpr, nil
  2514  }
  2515  
  2516  
  2517  // All cmd expect CMD_SEARCH
  2518  ALLCMD <- (CMD_REGEX / CMD_STATS / CMD_FIELDS / CMD_WHERE / CMD_HEAD_NO_SPACE / CMD_HEAD / CMD_EVAL / CMD_REX / CMD_TOP / CMD_RARE / CMD_RENAME / CMD_TIMECHART / CMD_TRANSACTION / CMD_DEDUP / CMD_SORT)
  2519  CMD_SEARCH <- "search" SPACE
  2520  CMD_REGEX <- "regex" SPACE
  2521  CMD_STATS <- "stats" SPACE
  2522  CMD_FIELDS <- "fields" SPACE
  2523  CMD_WHERE <- "where" SPACE
  2524  CMD_HEAD_NO_SPACE <- "head"
  2525  CMD_HEAD <- CMD_HEAD_NO_SPACE SPACE
  2526  CMD_EVAL <- "eval" SPACE
  2527  CMD_REX <- "rex" SPACE
  2528  CMD_SORT <- "sort" SPACE
  2529  CMD_TOP <- "top"
  2530  CMD_RARE <- "rare"
  2531  CMD_RENAME <- "rename" SPACE
  2532  CMD_TIMECHART <- "timechart" SPACE
  2533  CMD_SPAN <- "span"
  2534  CMD_TRANSACTION <- "transaction" SPACE
  2535  CMD_DEDUP <- "dedup"
  2536  CMD_DEDUP_SORTBY <- SPACE "sortby" SPACE
  2537  EVAL_CONCAT <- SPACE? "." SPACE?
  2538  
  2539  // Major and Minor breaks from https://docs.splunk.com/Documentation/Splunk/9.0.4/Admin/Segmentersconf
  2540  MAJOR_BREAK <- [[\]<>(){}|!;,'"*\n\r \t&?+] / "%21" / "%26" /
  2541                 "%2526" / "%3B" / "%7C" / "%20" / "%2B" / "%3D" / "--" /
  2542                 "%2520" / "%5D" / "%5B" / "%3A" / "%0A" / "%2C" / "%28" / "%29"
  2543  MINOR_BREAK <- [/:=@.$#%_] / "-" / "\\"
  2544  
  2545  // https://community.splunk.com/t5/Splunk-Search/are-search-language-keywords-case-sensitive/m-p/9106
  2546  // has some information about case sensitivity.
  2547  NOT <- "NOT" SPACE
  2548  OR <- SPACE "OR" SPACE
  2549  AND <- SPACE "AND" SPACE
  2550  PIPE <- EMPTY_OR_SPACE "|" EMPTY_OR_SPACE
  2551  AS <- SPACE "AS"i SPACE // Case insensitive
  2552  BY <- SPACE "BY"i SPACE // Case insensitive
  2553  
  2554  EQUAL <- EMPTY_OR_SPACE "=" EMPTY_OR_SPACE
  2555  COMMA <- EMPTY_OR_SPACE "," EMPTY_OR_SPACE
  2556  L_PAREN <- "(" EMPTY_OR_SPACE
  2557  R_PAREN <- EMPTY_OR_SPACE ")"
  2558  
  2559  EOF <- !.
  2560  SPACE <- (" "? COMMENT " "?) / " "+
  2561  COMMENT <- "```" (!("```") .)* "```"
  2562  EMPTY_OR_SPACE  <- SPACE / ""
  2563  EMPTY_OR_COMMA  <- COMMA / EMPTY_OR_SPACE