forked from MontFerret/ferret
-
Notifications
You must be signed in to change notification settings - Fork 0
/
logical.go
113 lines (88 loc) · 2.33 KB
/
logical.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package operators
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
)
type (
LogicalOperatorType int
LogicalOperator struct {
*baseOperator
value LogicalOperatorType
}
)
const (
LogicalOperatorTypeAnd LogicalOperatorType = 0
LogicalOperatorTypeOr LogicalOperatorType = 1
LogicalOperatorTypeNot LogicalOperatorType = 2
)
var logicalOperators = map[string]LogicalOperatorType{
"&&": LogicalOperatorTypeAnd,
"AND": LogicalOperatorTypeAnd,
"||": LogicalOperatorTypeOr,
"OR": LogicalOperatorTypeOr,
"NOT": LogicalOperatorTypeNot,
}
func NewLogicalOperator(
src core.SourceMap,
left core.Expression,
right core.Expression,
operator string,
) (*LogicalOperator, error) {
op, exists := logicalOperators[operator]
if !exists {
return nil, core.Error(core.ErrInvalidArgument, "operator")
}
return &LogicalOperator{
&baseOperator{
src,
left,
right,
},
op,
}, nil
}
func (operator *LogicalOperator) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) {
if operator.value == LogicalOperatorTypeNot {
val, err := operator.right.Exec(ctx, scope)
if err != nil {
return values.None, core.SourceError(operator.src, err)
}
return Not(val, values.None), nil
}
left, err := operator.left.Exec(ctx, scope)
if err != nil {
return values.None, core.SourceError(operator.src, err)
}
leftBool := values.ToBoolean(left)
if operator.value == LogicalOperatorTypeAnd && leftBool == values.False {
if left.Type() == core.BooleanType {
return values.False, nil
}
return left, nil
}
if operator.value == LogicalOperatorTypeOr && leftBool == values.True {
return left, nil
}
right, err := operator.right.Exec(ctx, scope)
if err != nil {
return values.None, core.SourceError(operator.src, err)
}
return right, nil
}
func (operator *LogicalOperator) Eval(_ context.Context, left, right core.Value) (core.Value, error) {
if operator.value == LogicalOperatorTypeNot {
return Not(right, values.None), nil
}
leftBool := values.ToBoolean(left)
if operator.value == LogicalOperatorTypeAnd && leftBool == values.False {
if left.Type() == core.BooleanType {
return values.False, nil
}
return left, nil
}
if operator.value == LogicalOperatorTypeOr && leftBool == values.True {
return left, nil
}
return right, nil
}