mirror of
https://github.com/chaisql/chai.git
synced 2025-10-05 23:57:01 +08:00
133 lines
2.5 KiB
Go
133 lines
2.5 KiB
Go
package expr
|
|
|
|
import (
|
|
"github.com/genjidb/genji/document"
|
|
"github.com/genjidb/genji/internal/stringutil"
|
|
)
|
|
|
|
var (
|
|
trueLitteral = document.NewBoolValue(true)
|
|
falseLitteral = document.NewBoolValue(false)
|
|
nullLitteral = document.NewNullValue()
|
|
)
|
|
|
|
// An Expr evaluates to a value.
|
|
type Expr interface {
|
|
Eval(*Environment) (document.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) (document.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 stringutil.Sprintf("(%v)", p.E)
|
|
}
|
|
|
|
func invertBoolResult(f func(env *Environment) (document.Value, error)) func(env *Environment) (document.Value, error) {
|
|
return func(env *Environment) (document.Value, error) {
|
|
v, err := f(env)
|
|
|
|
if err != nil {
|
|
return v, err
|
|
}
|
|
if v == trueLitteral {
|
|
return falseLitteral, nil
|
|
}
|
|
if v == falseLitteral {
|
|
return trueLitteral, 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 stringutil.Sprintf("%s", e.Expr)
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|