mirror of
https://github.com/chaisql/chai.git
synced 2025-10-05 15:46:55 +08:00
215 lines
4.1 KiB
Go
215 lines
4.1 KiB
Go
package expr
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/chaisql/chai/internal/environment"
|
|
"github.com/chaisql/chai/internal/types"
|
|
)
|
|
|
|
var (
|
|
TrueLiteral = types.NewBoolValue(true)
|
|
FalseLiteral = types.NewBoolValue(false)
|
|
NullLiteral = types.NewNullValue()
|
|
)
|
|
|
|
// An Expr evaluates to a value.
|
|
type Expr interface {
|
|
Eval(*environment.Environment) (types.Value, error)
|
|
String() string
|
|
}
|
|
|
|
type isEqualer interface {
|
|
IsEqual(Expr) bool
|
|
}
|
|
|
|
// Equal reports whether a and b are equal by first calling IsEqual
|
|
// if they have an IsEqual method with this signature:
|
|
//
|
|
// IsEqual(Expr) bool
|
|
//
|
|
// If not, it returns whether a and b values are equal.
|
|
func Equal(a, b Expr) bool {
|
|
if aa, ok := a.(isEqualer); ok {
|
|
return aa.IsEqual(b)
|
|
}
|
|
|
|
if bb, ok := b.(isEqualer); ok {
|
|
return bb.IsEqual(a)
|
|
}
|
|
|
|
return a == b
|
|
}
|
|
|
|
// Parentheses is a special expression which turns
|
|
// any sub-expression as unary.
|
|
// It hides the underlying operator, if any, from the parser
|
|
// so that it doesn't get reordered by precedence.
|
|
type Parentheses struct {
|
|
E Expr
|
|
}
|
|
|
|
// Eval calls the underlying expression Eval method.
|
|
func (p Parentheses) Eval(env *environment.Environment) (types.Value, error) {
|
|
return p.E.Eval(env)
|
|
}
|
|
|
|
// IsEqual compares this expression with the other expression and returns
|
|
// true if they are equal.
|
|
func (p Parentheses) IsEqual(other Expr) bool {
|
|
if other == nil {
|
|
return false
|
|
}
|
|
|
|
o, ok := other.(Parentheses)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
return Equal(p.E, o.E)
|
|
}
|
|
|
|
func (p Parentheses) String() string {
|
|
return fmt.Sprintf("(%v)", p.E)
|
|
}
|
|
|
|
func invertBoolResult(f func(env *environment.Environment) (types.Value, error)) func(env *environment.Environment) (types.Value, error) {
|
|
return func(env *environment.Environment) (types.Value, error) {
|
|
v, err := f(env)
|
|
|
|
if err != nil {
|
|
return v, err
|
|
}
|
|
if v == TrueLiteral {
|
|
return FalseLiteral, nil
|
|
}
|
|
if v == FalseLiteral {
|
|
return TrueLiteral, nil
|
|
}
|
|
return v, nil
|
|
}
|
|
}
|
|
|
|
// NamedExpr is an expression with a name.
|
|
type NamedExpr struct {
|
|
Expr
|
|
|
|
ExprName string
|
|
}
|
|
|
|
// Name returns ExprName.
|
|
func (e *NamedExpr) Name() string {
|
|
return e.ExprName
|
|
}
|
|
|
|
func (e *NamedExpr) String() string {
|
|
return fmt.Sprintf("%s", e.Expr)
|
|
}
|
|
|
|
// A Function is an expression whose evaluation calls a function previously defined.
|
|
type Function interface {
|
|
Expr
|
|
|
|
// Params returns the list of parameters this function has received.
|
|
Params() []Expr
|
|
}
|
|
|
|
// An Aggregator is an expression that aggregates objects into one result.
|
|
type Aggregator interface {
|
|
Expr
|
|
|
|
Aggregate(env *environment.Environment) error
|
|
}
|
|
|
|
// An AggregatorBuilder is a type that can create aggregators.
|
|
type AggregatorBuilder interface {
|
|
Expr
|
|
|
|
Aggregator() Aggregator
|
|
}
|
|
|
|
func Walk(e Expr, fn func(Expr) bool) bool {
|
|
if e == nil {
|
|
return true
|
|
}
|
|
if !fn(e) {
|
|
return false
|
|
}
|
|
|
|
switch t := e.(type) {
|
|
case Operator:
|
|
if !Walk(t.LeftHand(), fn) {
|
|
return false
|
|
}
|
|
if !Walk(t.RightHand(), fn) {
|
|
return false
|
|
}
|
|
case *NamedExpr:
|
|
return Walk(t.Expr, fn)
|
|
case Function:
|
|
for _, p := range t.Params() {
|
|
if !Walk(p, fn) {
|
|
return false
|
|
}
|
|
}
|
|
case LiteralExprList:
|
|
for _, e := range t {
|
|
if !Walk(e, fn) {
|
|
return false
|
|
}
|
|
}
|
|
case *KVPairs:
|
|
for _, e := range t.Pairs {
|
|
if !Walk(e.V, fn) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
type NextValueFor struct {
|
|
SeqName string
|
|
}
|
|
|
|
// Eval calls the underlying expression Eval method.
|
|
func (n NextValueFor) Eval(env *environment.Environment) (types.Value, error) {
|
|
tx := env.GetTx()
|
|
|
|
if tx == nil {
|
|
return NullLiteral, fmt.Errorf(`NEXT VALUE FOR cannot be evaluated`)
|
|
}
|
|
|
|
seq, err := tx.Catalog.GetSequence(n.SeqName)
|
|
if err != nil {
|
|
return NullLiteral, err
|
|
}
|
|
|
|
i, err := seq.Next(tx)
|
|
if err != nil {
|
|
return NullLiteral, err
|
|
}
|
|
|
|
return types.NewIntegerValue(i), nil
|
|
}
|
|
|
|
// IsEqual compares this expression with the other expression and returns
|
|
// true if they are equal.
|
|
func (n NextValueFor) IsEqual(other Expr) bool {
|
|
if other == nil {
|
|
return false
|
|
}
|
|
|
|
o, ok := other.(NextValueFor)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
return o.SeqName == n.SeqName
|
|
}
|
|
|
|
func (n NextValueFor) String() string {
|
|
return fmt.Sprintf("NEXT VALUE FOR %s", n.SeqName)
|
|
}
|