mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 09:05:18 +00:00
137 lines
3.3 KiB
Go
137 lines
3.3 KiB
Go
// Copyright 2023 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
|
// of this source code is governed by a BSD-style license that can be found in
|
|
// the LICENSE file.
|
|
|
|
package dsl
|
|
|
|
import (
|
|
"fmt"
|
|
"go/token"
|
|
"strconv"
|
|
"strings"
|
|
"sync/atomic"
|
|
|
|
"github.com/cockroachdb/errors"
|
|
)
|
|
|
|
// Predicate encodes conditional logic that yields a boolean.
|
|
type Predicate[E any] interface {
|
|
Evaluate(E) bool
|
|
String() string
|
|
}
|
|
|
|
// Not returns a Predicate that negates the provided predicate.
|
|
func Not[E any](p Predicate[E]) Predicate[E] { return not[E]{Predicate: p} }
|
|
|
|
// And returns a Predicate that evaluates to true if all its operands evaluate
|
|
// to true.
|
|
func And[E any](preds ...Predicate[E]) Predicate[E] { return and[E](preds) }
|
|
|
|
// Or returns a Predicate that evaluates to true if any of its operands evaluate
|
|
// true.
|
|
func Or[E any](preds ...Predicate[E]) Predicate[E] { return or[E](preds) }
|
|
|
|
// OnIndex returns a Predicate that evaluates to true on its N-th call.
|
|
func OnIndex[E any](n int32) *Index[E] {
|
|
p := new(Index[E])
|
|
p.Int32.Store(n)
|
|
return p
|
|
}
|
|
|
|
// Index is a Predicate that evaluates to true only on its N-th invocation.
|
|
type Index[E any] struct {
|
|
atomic.Int32
|
|
}
|
|
|
|
// String implements fmt.Stringer.
|
|
func (p *Index[E]) String() string {
|
|
return fmt.Sprintf("(OnIndex %d)", p.Int32.Load())
|
|
}
|
|
|
|
// Evaluate implements Predicate.
|
|
func (p *Index[E]) Evaluate(E) bool { return p.Int32.Add(-1) == -1 }
|
|
|
|
type not[E any] struct {
|
|
Predicate[E]
|
|
}
|
|
|
|
func (p not[E]) String() string { return fmt.Sprintf("(Not %s)", p.Predicate.String()) }
|
|
func (p not[E]) Evaluate(e E) bool { return !p.Predicate.Evaluate(e) }
|
|
|
|
type and[E any] []Predicate[E]
|
|
|
|
func (p and[E]) String() string {
|
|
var sb strings.Builder
|
|
sb.WriteString("(And")
|
|
for i := 0; i < len(p); i++ {
|
|
sb.WriteRune(' ')
|
|
sb.WriteString(p[i].String())
|
|
}
|
|
sb.WriteRune(')')
|
|
return sb.String()
|
|
}
|
|
|
|
func (p and[E]) Evaluate(e E) bool {
|
|
ok := true
|
|
for i := range p {
|
|
ok = ok && p[i].Evaluate(e)
|
|
}
|
|
return ok
|
|
}
|
|
|
|
type or[E any] []Predicate[E]
|
|
|
|
func (p or[E]) String() string {
|
|
var sb strings.Builder
|
|
sb.WriteString("(Or")
|
|
for i := 0; i < len(p); i++ {
|
|
sb.WriteRune(' ')
|
|
sb.WriteString(p[i].String())
|
|
}
|
|
sb.WriteRune(')')
|
|
return sb.String()
|
|
}
|
|
|
|
func (p or[E]) Evaluate(e E) bool {
|
|
ok := false
|
|
for i := range p {
|
|
ok = ok || p[i].Evaluate(e)
|
|
}
|
|
return ok
|
|
}
|
|
|
|
func parseNot[E any](p *Parser[Predicate[E]], s *Scanner) Predicate[E] {
|
|
preds := parseVariadicPredicate(p, s)
|
|
if len(preds) != 1 {
|
|
panic(errors.Newf("dsl: not accepts exactly 1 argument, given %d", len(preds)))
|
|
}
|
|
return not[E]{Predicate: preds[0]}
|
|
}
|
|
|
|
func parseAnd[E any](p *Parser[Predicate[E]], s *Scanner) Predicate[E] {
|
|
return And[E](parseVariadicPredicate[E](p, s)...)
|
|
}
|
|
|
|
func parseOr[E any](p *Parser[Predicate[E]], s *Scanner) Predicate[E] {
|
|
return Or[E](parseVariadicPredicate[E](p, s)...)
|
|
}
|
|
|
|
func parseOnIndex[E any](p *Parser[Predicate[E]], s *Scanner) Predicate[E] {
|
|
i, err := strconv.ParseInt(s.Consume(token.INT).Lit, 10, 32)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
s.Consume(token.RPAREN)
|
|
return OnIndex[E](int32(i))
|
|
}
|
|
|
|
func parseVariadicPredicate[E any](p *Parser[Predicate[E]], s *Scanner) (ret []Predicate[E]) {
|
|
tok := s.Scan()
|
|
for tok.Kind == token.LPAREN || tok.Kind == token.IDENT {
|
|
ret = append(ret, p.ParseFromPos(s, tok))
|
|
tok = s.Scan()
|
|
}
|
|
assertTok(tok, token.RPAREN)
|
|
return ret
|
|
}
|