func NewUnaryBooleanExpression(op OP, lE Evaluator) (Evaluator, error) {
	switch op {
	case NOT:
		return &booleanNode{
			op: op,
			lS: true,
			lE: lE,
			rS: false,
		}, nil
	default:
		return nil, errors.New("unary boolean expressions require the operation to be the following: 'not'")
	}
}
NewUnaryBooleanExpression creates a new unary boolean evaluator.
package semantic
import (
	"errors"
	"fmt"
	"strings"
	"time"
	"github.com/google/badwolf/bql/lexer"
	"github.com/google/badwolf/bql/table"
	"github.com/google/badwolf/triple/literal"
)
type Evaluator interface {
	Evaluate(r table.Row) (bool, error)
}
type AlwaysReturn struct {
	V bool
}
func (a *AlwaysReturn) Evaluate(r table.Row) (bool, error) {
	return a.V, nil
}
type OP int8
const (
	LT OP = iota
	GT
	EQ
	NOT
	AND
	OR
)
func (o OP) String() string {
	switch o {
	case LT:
		return "<"
	case GT:
		return ">"
	case EQ:
		return "="
	case NOT:
		return "not"
	case AND:
		return "and"
	case OR:
		return "or"
	default:
		return "@UNKNOWN@"
	}
}
func cellFromRow(binding string, r table.Row) (*table.Cell, error) {
	val, ok := r[binding]
	if !ok {
		return nil, fmt.Errorf("value for binding %q not found in row %v", binding, r)
	}
	return val, nil
}
func formatCell(c *table.Cell) (string, error) {
	if c.L != nil {
		return strings.TrimSpace(c.L.ToComparableString()), nil
	}
	if c.S != nil {
		formatted, err := literal.DefaultBuilder().Build(literal.Text, *c.S)
		if err != nil {
			return "", fmt.Errorf("formatCell failed, could not build a text literal from the string %q, got error: %v", *c.S, err)
		}
		return strings.TrimSpace(formatted.ToComparableString()), nil
	}
	return strings.TrimSpace(c.String()), nil
}
type evaluationNode struct {
	operation OP
	leftBinding  string
	rightBinding string
}
func (e *evaluationNode) Evaluate(r table.Row) (bool, error) {
	eval := func() (*table.Cell, *table.Cell, error) {
		leftBinding, err := cellFromRow(e.leftBinding, r)
		if err != nil {
			return nil, nil, fmt.Errorf("evaluationNode.Evaluate failed, the call for cellFromRow(%v, %v) returned error: %v", e.leftBinding, r, err)
		}
		rightBinding, err := cellFromRow(e.rightBinding, r)
		if err != nil {
			return nil, nil, fmt.Errorf("evaluationNode.Evaluate failed, the call for cellFromRow(%v, %v) returned error: %v", e.rightBinding, r, err)
		}
		return leftBinding, rightBinding, nil
	}
	leftBinding, rightBinding, err := eval()
	if err != nil {
		return false, err
	}
	var csEL, csER string
	csEL, err = formatCell(leftBinding)
	if err != nil {
		return false, fmt.Errorf("evaluationNode.Evaluate failed, the call for formatCell(%s) returned error: %v", leftBinding, err)
	}
	csER, err = formatCell(rightBinding)
	if err != nil {
		return false, fmt.Errorf("evaluationNode.Evaluate failed, the call for formatCell(%s) returned error: %v", rightBinding, err)
	}
	switch e.operation {
	case EQ:
		return csEL == csER, nil
	case LT:
		return csEL < csER, nil
	case GT:
		return csEL > csER, nil
	default:
		return false, fmt.Errorf("boolean evaluation requires a boolean operation; found %q instead", e.operation)
	}
}
type comparisonForLiteral struct {
	operation OP
	leftBinding  string
	rightLiteral string
}
func (e *comparisonForLiteral) Evaluate(r table.Row) (bool, error) {
	leftBinding, err := cellFromRow(e.leftBinding, r)
	if err != nil {
		return false, fmt.Errorf("comparisonForLiteral.Evaluate failed, the call for cellFromRow(%v, %v) returned error: %v", e.leftBinding, r, err)
	}
	if leftBinding.L == nil && leftBinding.S == nil {
		return false, nil
	}
	rightLiteral, err := literal.DefaultBuilder().Parse(e.rightLiteral)
	if err != nil {
		return false, fmt.Errorf("comparisonForLiteral.Evaluate failed, could not parse literal from the string %q, got error: %v", e.rightLiteral, err)
	}
	if leftBinding.S != nil && rightLiteral.Type() != literal.Text {
		return false, fmt.Errorf("a string binding can only be compared with a literal of type text, got literal %q instead", rightLiteral)
	}
	if leftBinding.L != nil && leftBinding.L.Type() != rightLiteral.Type() {
		return false, nil
	}
	var csEL, csER string
	csEL, err = formatCell(leftBinding)
	if err != nil {
		return false, fmt.Errorf("comparisonForLiteral.Evaluate failed, the call for formatCell(%s) returned error: %v", leftBinding, err)
	}
	csER = rightLiteral.ToComparableString()
	switch e.operation {
	case EQ:
		return csEL == csER, nil
	case LT:
		return csEL < csER, nil
	case GT:
		return csEL > csER, nil
	default:
		return false, fmt.Errorf("boolean evaluation requires a boolean operation; found %q instead", e.operation)
	}
}
type comparisonForNodeLiteral struct {
	operation OP
	leftBinding      string
	rightNodeLiteral string
}
func (e *comparisonForNodeLiteral) Evaluate(r table.Row) (bool, error) {
	leftBinding, err := cellFromRow(e.leftBinding, r)
	if err != nil {
		return false, fmt.Errorf("comparisonForNodeLiteral.Evaluate failed, the call for cellFromRow(%v, %v) returned error: %v", e.leftBinding, r, err)
	}
	if leftBinding.S != nil {
		return false, fmt.Errorf("a string binding can only be compared with a literal of type text, got literal %q instead", strings.TrimSpace(e.rightNodeLiteral))
	}
	if leftBinding.N == nil {
		return false, nil
	}
	var csEL, csER string
	csEL, err = formatCell(leftBinding)
	if err != nil {
		return false, fmt.Errorf("comparisonForNodeLiteral.Evaluate failed, the call for formatCell(%s) returned error: %v", leftBinding, err)
	}
	csER = strings.TrimSpace(e.rightNodeLiteral)
	switch e.operation {
	case EQ:
		return csEL == csER, nil
	default:
		return false, fmt.Errorf(`comparisonForNodeLiteral.Evaluate got operation %q, but it accepts only the "=" operation. For ">" and "<" think about extracting bindings with the keywords ID/TYPE and using them for comparisons`, e.operation)
	}
}
type comparisonForTimeLiteral struct {
	operation OP
	leftBinding      string
	rightTimeLiteral string
}
func (e *comparisonForTimeLiteral) Evaluate(r table.Row) (bool, error) {
	leftBinding, err := cellFromRow(e.leftBinding, r)
	if err != nil {
		return false, fmt.Errorf("comparisonForTimeLiteral.Evaluate failed, the call for cellFromRow(%v, %v) returned error: %v", e.leftBinding, r, err)
	}
	if leftBinding.S != nil {
		return false, fmt.Errorf("a string binding can only be compared with a literal of type text, got literal %q instead", strings.TrimSpace(e.rightTimeLiteral))
	}
	if leftBinding.T == nil {
		return false, nil
	}
	timeBinding := leftBinding.T
	timeLiteral, err := time.Parse(time.RFC3339Nano, strings.TrimSpace(e.rightTimeLiteral))
	if err != nil {
		return false, fmt.Errorf("comparisonForTimeLiteral.Evaluate failed, could not parse time from the string %q, got error: %v", strings.TrimSpace(e.rightTimeLiteral), err)
	}
	switch e.operation {
	case EQ:
		return timeBinding.Equal(timeLiteral), nil
	case LT:
		return timeBinding.Before(timeLiteral), nil
	case GT:
		return timeBinding.After(timeLiteral), nil
	default:
		return false, fmt.Errorf("boolean evaluation requires a boolean operation; found %q instead", e.operation)
	}
}
type comparisonForPredicateLiteral struct {
	operation OP
	leftBinding           string
	rightPredicateLiteral string
}
func (e *comparisonForPredicateLiteral) Evaluate(r table.Row) (bool, error) {
	leftBinding, err := cellFromRow(e.leftBinding, r)
	if err != nil {
		return false, fmt.Errorf("comparisonForPredicateLiteral.Evaluate failed, the call for cellFromRow(%v, %v) returned error: %v", e.leftBinding, r, err)
	}
	if leftBinding.S != nil {
		return false, fmt.Errorf("a string binding can only be compared with a literal of type text, got literal %q instead", strings.TrimSpace(e.rightPredicateLiteral))
	}
	if leftBinding.P == nil {
		return false, nil
	}
	var csEL, csER string
	csEL, err = formatCell(leftBinding)
	if err != nil {
		return false, fmt.Errorf("comparisonForPredicateLiteral.Evaluate failed, the call for formatCell(%s) returned error: %v", leftBinding, err)
	}
	csER = strings.TrimSpace(e.rightPredicateLiteral)
	switch e.operation {
	case EQ:
		return csEL == csER, nil
	default:
		return false, fmt.Errorf(`comparisonForPredicateLiteral.Evaluate got operation %q, but it accepts only the "=" operation. For ">" and "<" think about extracting bindings with the keywords ID/AT and using them for comparisons`, e.operation)
	}
}
func NewEvaluationExpression(op OP, lB, rB string) (Evaluator, error) {
	l, r := strings.TrimSpace(lB), strings.TrimSpace(rB)
	if l == "" || r == "" {
		return nil, fmt.Errorf("bindings cannot be empty; got %q, %q", l, r)
	}
	switch op {
	case EQ, LT, GT:
		return &evaluationNode{
			operation:    op,
			leftBinding:  lB,
			rightBinding: rB,
		}, nil
	default:
		return nil, errors.New("evaluation expressions require the operation to be one for the following '=', '<', '>'")
	}
}
func NewEvaluationExpressionForLiteral(op OP, lB, rL string) (Evaluator, error) {
	l, r := strings.TrimSpace(lB), strings.TrimSpace(rL)
	if l == "" || r == "" {
		return nil, fmt.Errorf("operands cannot be empty; got %q, %q", l, r)
	}
	switch op {
	case EQ, LT, GT:
		return &comparisonForLiteral{
			operation:    op,
			leftBinding:  l,
			rightLiteral: r,
		}, nil
	default:
		return nil, errors.New("evaluation expressions require the operation to be one for the following '=', '<', '>'")
	}
}
func NewEvaluationExpressionForNodeLiteral(op OP, lB, rNL string) (Evaluator, error) {
	l, r := strings.TrimSpace(lB), strings.TrimSpace(rNL)
	if l == "" || r == "" {
		return nil, fmt.Errorf("operands cannot be empty; got %q, %q", l, r)
	}
	switch op {
	case EQ, LT, GT:
		return &comparisonForNodeLiteral{
			operation:        op,
			leftBinding:      l,
			rightNodeLiteral: r,
		}, nil
	default:
		return nil, errors.New("evaluation expressions require the operation to be one for the following '=', '<', '>'")
	}
}
func NewEvaluationExpressionForTimeLiteral(op OP, lB, rTL string) (Evaluator, error) {
	l, r := strings.TrimSpace(lB), strings.TrimSpace(rTL)
	if l == "" || r == "" {
		return nil, fmt.Errorf("evaluation expression got operands %q and %q, but operands cannot be empty", l, r)
	}
	switch op {
	case EQ, LT, GT:
		return &comparisonForTimeLiteral{
			operation:        op,
			leftBinding:      l,
			rightTimeLiteral: r,
		}, nil
	default:
		return nil, errors.New("evaluation expressions require the operation to be one of the following: '=', '<', '>'")
	}
}
func NewEvaluationExpressionForPredicateLiteral(op OP, lB, rTL string) (Evaluator, error) {
	l, r := strings.TrimSpace(lB), strings.TrimSpace(rTL)
	if l == "" || r == "" {
		return nil, fmt.Errorf("evaluation expression got operands %q and %q, but operands cannot be empty", l, r)
	}
	switch op {
	case EQ, LT, GT:
		return &comparisonForPredicateLiteral{
			operation:             op,
			leftBinding:           l,
			rightPredicateLiteral: r,
		}, nil
	default:
		return nil, errors.New("evaluation expressions require the operation to be one of the following: '=', '<', '>'")
	}
}
type booleanNode struct {
	op OP
	lS bool
	lE Evaluator
	rS bool
	rE Evaluator
}
func (e *booleanNode) Evaluate(r table.Row) (bool, error) {
	evalLeft := func() (bool, error) {
		if !e.lS {
			return false, fmt.Errorf(`boolean operations require a left operator; found "(%v, %v)" instead`, e.lE, e.rE)
		}
		return e.lE.Evaluate(r)
	}
	evalRight := func() (bool, error) {
		if !e.rS {
			return false, fmt.Errorf(`boolean operations require a right operator; found "(%v, %v)" instead`, e.lE, e.rE)
		}
		return e.rE.Evaluate(r)
	}
	eL, err := evalLeft()
	if err != nil {
		return false, err
	}
	switch e.op {
	case AND:
		if !eL {
			return false, nil
		}
		return evalRight()
	case OR:
		if eL {
			return true, nil
		}
		return evalRight()
	case NOT:
		return !eL, nil
	default:
		return false, fmt.Errorf("boolean evaluation requires a boolen operation; found %q instead", e.op)
	}
}
func NewBinaryBooleanExpression(op OP, lE, rE Evaluator) (Evaluator, error) {
	switch op {
	case AND, OR:
		return &booleanNode{
			op: op,
			lS: true,
			lE: lE,
			rS: true,
			rE: rE,
		}, nil
	default:
		return nil, errors.New("binary boolean expressions require the operation to be one of the following: 'and', 'or'")
	}
}