Files
ziti/controller/storage/ast/node_expr.go
2024-11-19 11:27:20 -05:00

620 lines
14 KiB
Go

/*
Copyright NetFoundry, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ast
import (
"fmt"
"github.com/michaelquigley/pfxlog"
"github.com/pkg/errors"
"strings"
)
// NotExprNode implements logical NOT on a wrapped boolean expression
type NotExprNode struct {
expr BoolNode
}
func (node *NotExprNode) Accept(visitor Visitor) {
visitor.VisitNotExprNodeStart(node)
node.expr.Accept(visitor)
visitor.VisitNotExprNodeEnd(node)
}
func (node *NotExprNode) String() string {
return fmt.Sprintf("not (%v)", node.expr)
}
func (node *NotExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *NotExprNode) EvalBool(s Symbols) bool {
val := node.expr.EvalBool(s)
return !val
}
func (node *NotExprNode) TypeTransformBool(s SymbolTypes) (BoolNode, error) {
return node, transformBools(s, &node.expr)
}
func (node *NotExprNode) IsConst() bool {
return node.expr.IsConst()
}
func NewAndExprNode(left, right BoolNode) *AndExprNode {
return &AndExprNode{
left: left,
right: right,
}
}
// AndExprNode implements logical AND on two wrapped boolean expressions
type AndExprNode struct {
left BoolNode
right BoolNode
}
func (node *AndExprNode) Accept(visitor Visitor) {
visitor.VisitAndExprNodeStart(node)
node.left.Accept(visitor)
node.right.Accept(visitor)
visitor.VisitAndExprNodeEnd(node)
}
func (node *AndExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *AndExprNode) TypeTransformBool(s SymbolTypes) (BoolNode, error) {
return node, transformBools(s, &node.left, &node.right)
}
func (node *AndExprNode) EvalBool(s Symbols) bool {
if !node.left.EvalBool(s) {
return false
}
return node.right.EvalBool(s)
}
func (node *AndExprNode) String() string {
return fmt.Sprintf("%v && %v", node.left, node.right)
}
func (node *AndExprNode) IsConst() bool {
return false
}
// OrExprNode implements logical OR on two wrapped boolean expressions
type OrExprNode struct {
left BoolNode
right BoolNode
}
func (node *OrExprNode) Accept(visitor Visitor) {
visitor.VisitOrExprNodeStart(node)
node.left.Accept(visitor)
node.right.Accept(visitor)
visitor.VisitOrExprNodeEnd(node)
}
func (node *OrExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *OrExprNode) TypeTransformBool(s SymbolTypes) (BoolNode, error) {
return node, transformBools(s, &node.left, &node.right)
}
func (node *OrExprNode) EvalBool(s Symbols) bool {
leftResult := node.left.EvalBool(s)
if leftResult {
return true
}
return node.right.EvalBool(s)
}
func (node *OrExprNode) String() string {
return fmt.Sprintf("%v || %v", node.left, node.right)
}
func (node *OrExprNode) IsConst() bool {
return false
}
type SeekOptimizableBoolNode interface {
IsSeekable() bool
EvalBoolWithSeek(s Symbols, cursor TypeSeekableSetCursor) bool
}
type BinaryBoolExprNode struct {
left BoolNode
right BoolNode
op BinaryOp
}
func (node *BinaryBoolExprNode) Accept(visitor Visitor) {
visitor.VisitBinaryBoolExprNodeStart(node)
node.left.Accept(visitor)
node.right.Accept(visitor)
visitor.VisitBinaryBoolExprNodeEnd(node)
}
func (*BinaryBoolExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *BinaryBoolExprNode) EvalBool(s Symbols) bool {
leftResult := node.left.EvalBool(s)
rightResult := node.right.EvalBool(s)
switch node.op {
case BinaryOpEQ:
return leftResult == rightResult
case BinaryOpNEQ:
return leftResult != rightResult
}
pfxlog.Logger().Errorf("unhandled boolean binary expression type %v", node.op)
return false
}
func (node *BinaryBoolExprNode) String() string {
return fmt.Sprintf("%v %v %v", node.left, binaryOpNames[node.op], node.right)
}
func (node *BinaryBoolExprNode) IsConst() bool {
return false
}
type BinaryDatetimeExprNode struct {
left DatetimeNode
right DatetimeNode
op BinaryOp
}
func (node *BinaryDatetimeExprNode) Accept(visitor Visitor) {
visitor.VisitBinaryDatetimeExprNodeStart(node)
node.left.Accept(visitor)
node.right.Accept(visitor)
visitor.VisitBinaryDatetimeExprNodeEnd(node)
}
func (*BinaryDatetimeExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *BinaryDatetimeExprNode) EvalBool(s Symbols) bool {
leftResult := node.left.EvalDatetime(s)
rightResult := node.right.EvalDatetime(s)
if leftResult == nil || rightResult == nil {
if node.op == BinaryOpNEQ {
return leftResult != rightResult
}
return false
}
switch node.op {
case BinaryOpEQ:
return leftResult.Equal(*rightResult)
case BinaryOpNEQ:
return !leftResult.Equal(*rightResult)
case BinaryOpLT:
return leftResult.Before(*rightResult)
case BinaryOpLTE:
return !leftResult.After(*rightResult)
case BinaryOpGT:
return leftResult.After(*rightResult)
case BinaryOpGTE:
return !leftResult.Before(*rightResult)
}
pfxlog.Logger().Errorf("unhandled datetime binary expression type %v", node.op)
return false
}
func (node *BinaryDatetimeExprNode) String() string {
return fmt.Sprintf("%v %v %v", node.left, binaryOpNames[node.op], node.right)
}
func (node *BinaryDatetimeExprNode) IsConst() bool {
return false
}
type BinaryFloat64ExprNode struct {
left Float64Node
right Float64Node
op BinaryOp
}
func (node *BinaryFloat64ExprNode) Accept(visitor Visitor) {
visitor.VisitBinaryFloat64ExprNodeStart(node)
node.left.Accept(visitor)
node.right.Accept(visitor)
visitor.VisitBinaryFloat64ExprNodeEnd(node)
}
func (node *BinaryFloat64ExprNode) GetType() NodeType {
return NodeTypeFloat64
}
func (node *BinaryFloat64ExprNode) EvalBool(s Symbols) bool {
leftResult := node.left.EvalFloat64(s)
rightResult := node.right.EvalFloat64(s)
if leftResult == nil || rightResult == nil {
if node.op == BinaryOpNEQ {
return leftResult != rightResult
}
return false
}
switch node.op {
case BinaryOpEQ:
return *leftResult == *rightResult
case BinaryOpNEQ:
return *leftResult != *rightResult
case BinaryOpLT:
return *leftResult < *rightResult
case BinaryOpLTE:
return *leftResult <= *rightResult
case BinaryOpGT:
return *leftResult > *rightResult
case BinaryOpGTE:
return *leftResult >= *rightResult
}
pfxlog.Logger().Errorf("unhandled float64 binary expression type %v", node.op)
return false
}
func (node *BinaryFloat64ExprNode) String() string {
return fmt.Sprintf("%v %v %v", node.left, binaryOpNames[node.op], node.right)
}
func (node *BinaryFloat64ExprNode) IsConst() bool {
return false
}
type BinaryInt64ExprNode struct {
left Int64Node
right Int64Node
op BinaryOp
}
func (node *BinaryInt64ExprNode) Accept(visitor Visitor) {
visitor.VisitBinaryInt64ExprNodeStart(node)
node.left.Accept(visitor)
node.right.Accept(visitor)
visitor.VisitBinaryInt64ExprNodeEnd(node)
}
func (node *BinaryInt64ExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *BinaryInt64ExprNode) EvalBool(s Symbols) bool {
leftResult := node.left.EvalInt64(s)
rightResult := node.right.EvalInt64(s)
if leftResult == nil || rightResult == nil {
if node.op == BinaryOpNEQ {
return leftResult != rightResult
}
return false
}
switch node.op {
case BinaryOpEQ:
return *leftResult == *rightResult
case BinaryOpNEQ:
return *leftResult != *rightResult
case BinaryOpLT:
return *leftResult < *rightResult
case BinaryOpLTE:
return *leftResult <= *rightResult
case BinaryOpGT:
return *leftResult > *rightResult
case BinaryOpGTE:
return *leftResult >= *rightResult
}
pfxlog.Logger().Errorf("unhandled int64 binary expression type %v", node.op)
return false
}
func (node *BinaryInt64ExprNode) String() string {
return fmt.Sprintf("%v %v %v", node.left, binaryOpNames[node.op], node.right)
}
func (node *BinaryInt64ExprNode) IsConst() bool {
return false
}
type BinaryStringExprNode struct {
left StringNode
right StringNode
op BinaryOp
}
func (node *BinaryStringExprNode) Accept(visitor Visitor) {
visitor.VisitBinaryStringExprNodeStart(node)
node.left.Accept(visitor)
node.right.Accept(visitor)
visitor.VisitBinaryStringExprNodeEnd(node)
}
func (*BinaryStringExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *BinaryStringExprNode) IsSeekable() bool {
return (node.op == BinaryOpEQ || node.op == BinaryOpNEQ) &&
(node.left.IsConst() || node.right.IsConst())
}
func (node *BinaryStringExprNode) EvalBoolWithSeek(s Symbols, cursor TypeSeekableSetCursor) bool {
if rightResult := node.right.EvalString(s); rightResult != nil {
cursor.SeekToString(*rightResult)
if cursor.IsValid() {
return node.EvalBool(s)
}
}
return false
}
func (node *BinaryStringExprNode) EvalBool(s Symbols) bool {
leftResult := node.left.EvalString(s)
rightResult := node.right.EvalString(s)
if leftResult == nil || rightResult == nil {
if node.op == BinaryOpNEQ {
return leftResult != rightResult
}
if node.op == BinaryOpNotContains || node.op == BinaryOpNotIContains {
return true
}
return false
}
switch node.op {
case BinaryOpEQ:
return *leftResult == *rightResult
case BinaryOpNEQ:
return *leftResult != *rightResult
case BinaryOpLT:
return *leftResult < *rightResult
case BinaryOpLTE:
return *leftResult <= *rightResult
case BinaryOpGT:
return *leftResult > *rightResult
case BinaryOpGTE:
return *leftResult >= *rightResult
case BinaryOpContains:
return strings.Contains(*leftResult, *rightResult)
case BinaryOpNotContains:
return !strings.Contains(*leftResult, *rightResult)
}
pfxlog.Logger().Errorf("unhandled string binary expression type %v", node.op)
return false
}
func (node *BinaryStringExprNode) String() string {
return fmt.Sprintf("%v %v %v", node.left, binaryOpNames[node.op], node.right)
}
func (node *BinaryStringExprNode) IsConst() bool {
return false
}
type IsNilExprNode struct {
symbol SymbolNode
op BinaryOp
}
func (node *IsNilExprNode) Accept(visitor Visitor) {
visitor.VisitIsNilExprNodeStart(node)
node.symbol.Accept(visitor)
visitor.VisitIsNilExprNodeEnd(node)
}
func (*IsNilExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *IsNilExprNode) EvalBool(s Symbols) bool {
isNil := s.IsNil(node.symbol.Symbol())
switch node.op {
case BinaryOpEQ:
return isNil
case BinaryOpNEQ:
return !isNil
}
pfxlog.Logger().Errorf("unhandled binary expression type %v", node)
return true
}
func (node *IsNilExprNode) String() string {
return fmt.Sprintf("%v %v null", node.symbol, binaryOpNames[node.op])
}
func (node *IsNilExprNode) IsConst() bool {
return false
}
func NewInt64BetweenOp(nodes []Int64Node) (*Int64BetweenExprNode, error) {
if len(nodes) != 3 {
return nil, errors.Errorf("incorrect number of values provided to Int64BetweenExprNode: %v", len(nodes))
}
return &Int64BetweenExprNode{
left: nodes[0],
lower: nodes[1],
upper: nodes[2],
}, nil
}
type Int64BetweenExprNode struct {
left Int64Node
lower Int64Node
upper Int64Node
}
func (node *Int64BetweenExprNode) Accept(visitor Visitor) {
visitor.VisitInt64BetweenExprNodeStart(node)
node.left.Accept(visitor)
node.lower.Accept(visitor)
node.upper.Accept(visitor)
visitor.VisitInt64BetweenExprNodeEnd(node)
}
func (*Int64BetweenExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *Int64BetweenExprNode) EvalBool(s Symbols) bool {
leftResult := node.left.EvalInt64(s)
if leftResult == nil {
return false
}
lowerResult := node.lower.EvalInt64(s)
if lowerResult == nil {
return false
}
upperResult := node.upper.EvalInt64(s)
if upperResult == nil {
return false
}
return *leftResult >= *lowerResult && *leftResult < *upperResult
}
func (node *Int64BetweenExprNode) String() string {
return fmt.Sprintf("%v between %v and %v", node.left, node.lower, node.upper)
}
func (node *Int64BetweenExprNode) IsConst() bool {
return false
}
func NewFloat64BetweenOp(nodes []Float64Node) (*Float64BetweenExprNode, error) {
if len(nodes) != 3 {
return nil, errors.Errorf("incorrect number of values provided to Float64BetweenExprNode: %v", len(nodes))
}
return &Float64BetweenExprNode{
left: nodes[0],
lower: nodes[1],
upper: nodes[2],
}, nil
}
type Float64BetweenExprNode struct {
left Float64Node
lower Float64Node
upper Float64Node
}
func (node *Float64BetweenExprNode) Accept(visitor Visitor) {
visitor.VisitFloat64BetweenExprNodeStart(node)
node.left.Accept(visitor)
node.lower.Accept(visitor)
node.upper.Accept(visitor)
visitor.VisitFloat64BetweenExprNodeEnd(node)
}
func (*Float64BetweenExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *Float64BetweenExprNode) EvalBool(s Symbols) bool {
leftResult := node.left.EvalFloat64(s)
if leftResult == nil {
return false
}
lowerResult := node.lower.EvalFloat64(s)
if lowerResult == nil {
return false
}
upperResult := node.upper.EvalFloat64(s)
if upperResult == nil {
return false
}
return *leftResult >= *lowerResult && *leftResult < *upperResult
}
func (node *Float64BetweenExprNode) String() string {
return fmt.Sprintf("%v between %v and %v", node.left, node.lower, node.upper)
}
func (node *Float64BetweenExprNode) IsConst() bool {
return false
}
type DatetimeBetweenExprNode struct {
left DatetimeNode
lower DatetimeNode
upper DatetimeNode
}
func (node *DatetimeBetweenExprNode) Accept(visitor Visitor) {
visitor.VisitDatetimeBetweenExprNodeStart(node)
node.left.Accept(visitor)
node.lower.Accept(visitor)
node.upper.Accept(visitor)
visitor.VisitDatetimeBetweenExprNodeEnd(node)
}
func (*DatetimeBetweenExprNode) GetType() NodeType {
return NodeTypeBool
}
func (node *DatetimeBetweenExprNode) EvalBool(s Symbols) bool {
leftResult := node.left.EvalDatetime(s)
if leftResult == nil {
return false
}
lowerResult := node.lower.EvalDatetime(s)
if lowerResult == nil {
return false
}
upperResult := node.upper.EvalDatetime(s)
if upperResult == nil {
return false
}
return (leftResult.Equal(*lowerResult) || leftResult.After(*lowerResult)) && leftResult.Before(*upperResult)
}
func (node *DatetimeBetweenExprNode) String() string {
return fmt.Sprintf("%v between %v and %v", node.left, node.lower, node.upper)
}
func (node *DatetimeBetweenExprNode) IsConst() bool {
return false
}