Files
chaisql/internal/expr/logical.go
2024-02-17 17:56:41 +04:00

135 lines
2.8 KiB
Go

package expr
import (
"fmt"
"github.com/chaisql/chai/internal/environment"
"github.com/chaisql/chai/internal/sql/scanner"
"github.com/chaisql/chai/internal/types"
)
// AndOp is the And operator.
type AndOp struct {
*simpleOperator
}
// And creates an expression that evaluates a And b And returns true if both are truthy.
func And(a, b Expr) Expr {
return &AndOp{&simpleOperator{a, b, scanner.AND}}
}
func (op *AndOp) Clone() Expr {
return &AndOp{
simpleOperator: op.simpleOperator.Clone(),
}
}
// Eval implements the Expr interface. It evaluates a and b and returns true if both evaluate
// to true.
func (op *AndOp) Eval(env *environment.Environment) (types.Value, error) {
s, err := op.a.Eval(env)
if err != nil {
return FalseLiteral, err
}
isTruthy, err := types.IsTruthy(s)
if !isTruthy || err != nil {
return FalseLiteral, err
}
s, err = op.b.Eval(env)
if err != nil {
return FalseLiteral, err
}
isTruthy, err = types.IsTruthy(s)
if !isTruthy || err != nil {
return FalseLiteral, err
}
return TrueLiteral, nil
}
// OrOp is the Or operator.
type OrOp struct {
*simpleOperator
}
// Or creates an expression that first evaluates a, returns true if truthy, then evaluates b, returns true if truthy Or false if falsy.
func Or(a, b Expr) Expr {
return &OrOp{&simpleOperator{a, b, scanner.OR}}
}
func (op *OrOp) Clone() Expr {
return &OrOp{
simpleOperator: op.simpleOperator.Clone(),
}
}
// Eval implements the Expr interface. It evaluates a and b and returns true if a or b evalutate
// to true.
func (op *OrOp) Eval(env *environment.Environment) (types.Value, error) {
s, err := op.a.Eval(env)
if err != nil {
return FalseLiteral, err
}
isTruthy, err := types.IsTruthy(s)
if err != nil {
return FalseLiteral, err
}
if isTruthy {
return TrueLiteral, nil
}
s, err = op.b.Eval(env)
if err != nil {
return FalseLiteral, err
}
isTruthy, err = types.IsTruthy(s)
if err != nil {
return FalseLiteral, err
}
if isTruthy {
return TrueLiteral, nil
}
return FalseLiteral, nil
}
// NotOp is the NOT unary operator.
type NotOp struct {
*simpleOperator
}
// Not creates an expression that returns true if e is falsy.
func Not(e Expr) Expr {
return &NotOp{&simpleOperator{a: e}}
}
func (op *NotOp) Clone() Expr {
return &NotOp{
simpleOperator: op.simpleOperator.Clone(),
}
}
// Eval implements the Expr interface. It evaluates e and returns true if b is falsy
func (op *NotOp) Eval(env *environment.Environment) (types.Value, error) {
s, err := op.a.Eval(env)
if err != nil {
return FalseLiteral, err
}
isTruthy, err := types.IsTruthy(s)
if err != nil {
return FalseLiteral, err
}
if isTruthy {
return FalseLiteral, nil
}
return TrueLiteral, nil
}
// String implements the fmt.Stringer interface.
func (op *NotOp) String() string {
return fmt.Sprintf("NOT %v", op.a)
}