Skip to content

Commit

Permalink
Tweaks.
Browse files Browse the repository at this point in the history
  • Loading branch information
fasaxc committed Dec 6, 2024
1 parent e570829 commit af153d2
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 18 deletions.
46 changes: 28 additions & 18 deletions libcalico-go/lib/selector/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ import (

const parserDebug = false

var (
sharedParserLock sync.Mutex
sharedParser = NewParser()
)

// Parse parses a string representation of a selector expression into a Selector.
func Parse(selector string) (sel Selector, err error) {
sharedParserLock.Lock()
Expand All @@ -34,18 +39,18 @@ func Parse(selector string) (sel Selector, err error) {
return sharedParser.Parse(selector)
}

var (
sharedValidatorLock sync.Mutex
sharedValidator = NewParser()
)

func Validate(selector string) (err error) {
sharedParserLock.Lock()
defer sharedParserLock.Unlock()
sharedValidatorLock.Lock()
defer sharedValidatorLock.Unlock()

return sharedParser.Validate(selector)
return sharedValidator.Validate(selector)
}

var (
sharedParserLock sync.Mutex
sharedParser = NewParser()
)

func NewParser() *Parser {
return &Parser{
tokBuf: make([]tokenizer.Token, 0, 128),
Expand All @@ -72,11 +77,16 @@ func (p *Parser) Validate(selector string) (err error) {
}

func (p *Parser) parseRoot(selector string, validateOnly bool) (sel Selector, err error) {
// Fixed size array to avoid heap allocation (for smaller selectors).
// Tokenize the input. We re-use the same shared buffer to avoid
// allocations.
tokens, err := tokenizer.AppendTokens(p.tokBuf[:0], selector)
if err != nil {
return
}
if cap(tokens) > cap(p.tokBuf) && cap(tokens) < 4096 {
// Allow buffer to grow if we're seeing large inputs.
p.tokBuf = tokens[:0]
}

if tokens[0].Kind == tokenizer.TokEOF {
if validateOnly {
Expand All @@ -89,7 +99,7 @@ func (p *Parser) parseRoot(selector string, validateOnly bool) (sel Selector, er
}

// The "||" operator has the lowest precedence so we start with that.
node, remTokens, err := parseOrExpression(tokens, validateOnly)
node, remTokens, err := p.parseOrExpression(tokens, validateOnly)
if err != nil {
return
}
Expand All @@ -105,13 +115,13 @@ func (p *Parser) parseRoot(selector string, validateOnly bool) (sel Selector, er
}

// parseOrExpression parses a one or more "&&" terms, separated by "||" operators.
func parseOrExpression(tokens []tokenizer.Token, validateOnly bool) (sel node, remTokens []tokenizer.Token, err error) {
func (p *Parser) parseOrExpression(tokens []tokenizer.Token, validateOnly bool) (sel node, remTokens []tokenizer.Token, err error) {
if parserDebug {
log.Debugf("Parsing ||s from %v", tokens)
}
// Look for the first expression.
var andNodes []node
sel, remTokens, err = parseAndExpression(tokens, validateOnly)
sel, remTokens, err = p.parseAndExpression(tokens, validateOnly)
if err != nil {
return
}
Expand All @@ -124,7 +134,7 @@ func parseOrExpression(tokens []tokenizer.Token, validateOnly bool) (sel node, r
switch remTokens[0].Kind {
case tokenizer.TokOr:
remTokens = remTokens[1:]
sel, remTokens, err = parseAndExpression(remTokens, validateOnly)
sel, remTokens, err = p.parseAndExpression(remTokens, validateOnly)
if err != nil {
return
}
Expand All @@ -147,7 +157,7 @@ func parseOrExpression(tokens []tokenizer.Token, validateOnly bool) (sel node, r
}

// parseAndExpression parses a one or more operations, separated by "&&" operators.
func parseAndExpression(
func (p *Parser) parseAndExpression(
tokens []tokenizer.Token,
validateOnly bool,
) (sel node, remTokens []tokenizer.Token, err error) {
Expand All @@ -156,7 +166,7 @@ func parseAndExpression(
}
// Look for the first operation.
var opNodes []node
sel, remTokens, err = parseOperation(tokens, validateOnly)
sel, remTokens, err = p.parseOperation(tokens, validateOnly)
if err != nil {
return
}
Expand All @@ -169,7 +179,7 @@ func parseAndExpression(
switch remTokens[0].Kind {
case tokenizer.TokAnd:
remTokens = remTokens[1:]
sel, remTokens, err = parseOperation(remTokens, validateOnly)
sel, remTokens, err = p.parseOperation(remTokens, validateOnly)
if err != nil {
return
}
Expand Down Expand Up @@ -201,7 +211,7 @@ var (

// parseOperations parses a single, possibly negated operation (i.e. ==, !=, has()).
// It also handles calling parseOrExpression recursively for parenthesized expressions.
func parseOperation(tokens []tokenizer.Token, validateOnly bool) (sel node, remTokens []tokenizer.Token, err error) {
func (p *Parser) parseOperation(tokens []tokenizer.Token, validateOnly bool) (sel node, remTokens []tokenizer.Token, err error) {
if parserDebug {
log.Debugf("Parsing op from %v", tokens)
}
Expand Down Expand Up @@ -335,7 +345,7 @@ func parseOperation(tokens []tokenizer.Token, validateOnly bool) (sel node, remT
}
case tokenizer.TokLParen:
// We hit a paren, skip past it, then recurse.
sel, remTokens, err = parseOrExpression(tokens[1:], validateOnly)
sel, remTokens, err = p.parseOrExpression(tokens[1:], validateOnly)
if err != nil {
return
}
Expand Down
2 changes: 2 additions & 0 deletions libcalico-go/lib/selector/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ var _ = Describe("Parser", func() {
BeforeEach(func() {
sel, err = parser.Parse(test.sel)
Expect(err).To(BeNil())
err = parser.Validate(test.sel)
Expect(err).To(BeNil())
})
It("should match", func() {
for _, labels := range test.expMatches {
Expand Down

0 comments on commit af153d2

Please sign in to comment.