Files
chaisql/internal/expr/logical.go
Asdine El Hrychy f966172cee Introduce Value interface (#422)
This replaces the Value struct by an interface to allow us to override some
values behavior in the future.
It also introduces a new package types, which contains type definitions, comparison,
and arithmetics.
Concerning encoding, Genji now only uses on type of encoding for values. This simplifies
indexing logic as well as table access in general.
2021-07-21 22:05:44 +04:00

116 lines
2.6 KiB
Go

package expr
import (
"github.com/genjidb/genji/internal/environment"
"github.com/genjidb/genji/internal/sql/scanner"
"github.com/genjidb/genji/internal/stringutil"
"github.com/genjidb/genji/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}}
}
// 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}}
}
// 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}}
}
// 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 stringutil.Stringer interface.
func (op *NotOp) String() string {
return stringutil.Sprintf("NOT %v", op.a)
}