mirror of
https://github.com/chaisql/chai.git
synced 2025-10-05 23:57:01 +08:00
135 lines
2.8 KiB
Go
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)
|
|
}
|