github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logql/log/pattern/ast.go (about)

     1  package pattern
     2  
     3  import (
     4  	"fmt"
     5  	"unicode/utf8"
     6  )
     7  
     8  type node interface {
     9  	fmt.Stringer
    10  }
    11  
    12  type expr []node
    13  
    14  func (e expr) hasCapture() bool {
    15  	return e.captureCount() != 0
    16  }
    17  
    18  func (e expr) validate() error {
    19  	if !e.hasCapture() {
    20  		return ErrNoCapture
    21  	}
    22  	// Consecutive captures are not allowed.
    23  	for i, n := range e {
    24  		if i+1 >= len(e) {
    25  			break
    26  		}
    27  		if _, ok := n.(capture); ok {
    28  			if _, ok := e[i+1].(capture); ok {
    29  				return fmt.Errorf("found consecutive capture '%s': %w", n.String()+e[i+1].String(), ErrInvalidExpr)
    30  			}
    31  		}
    32  	}
    33  
    34  	caps := e.captures()
    35  	uniq := map[string]struct{}{}
    36  	for _, c := range caps {
    37  		if _, ok := uniq[c]; ok {
    38  			return fmt.Errorf("duplicate capture name (%s): %w", c, ErrInvalidExpr)
    39  		}
    40  		uniq[c] = struct{}{}
    41  	}
    42  	return nil
    43  }
    44  
    45  func (e expr) captures() (captures []string) {
    46  	for _, n := range e {
    47  		if c, ok := n.(capture); ok && !c.isUnamed() {
    48  			captures = append(captures, c.Name())
    49  		}
    50  	}
    51  	return
    52  }
    53  
    54  func (e expr) captureCount() (count int) {
    55  	return len(e.captures())
    56  }
    57  
    58  type capture string
    59  
    60  func (c capture) String() string {
    61  	return "<" + string(c) + ">"
    62  }
    63  
    64  func (c capture) Name() string {
    65  	return string(c)
    66  }
    67  
    68  func (c capture) isUnamed() bool {
    69  	return string(c) == underscore
    70  }
    71  
    72  type literals []byte
    73  
    74  func (l literals) String() string {
    75  	return string(l)
    76  }
    77  
    78  func runesToLiterals(rs []rune) literals {
    79  	res := make([]byte, len(rs)*utf8.UTFMax)
    80  	count := 0
    81  	for _, r := range rs {
    82  		count += utf8.EncodeRune(res[count:], r)
    83  	}
    84  	res = res[:count]
    85  	return res
    86  }