Skip to content

Commit 5256953

Browse files
committed
Add ability to use operator overloading with methods
1 parent 9449c89 commit 5256953

File tree

4 files changed

+36
-8
lines changed

4 files changed

+36
-8
lines changed

checker/checker.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,12 @@ func (v *visitor) BinaryNode(node *ast.BinaryNode) reflect.Type {
176176
if fns, ok := v.operators[node.Operator]; ok {
177177
for _, fn := range fns {
178178
fnType := v.types[fn]
179-
180-
firstArgType := fnType.Type.In(0)
181-
secondArgType := fnType.Type.In(1)
179+
firstInIndex := 0
180+
if fnType.Method {
181+
firstInIndex = 1 // As first argument to method is receiver.
182+
}
183+
firstArgType := fnType.Type.In(firstInIndex)
184+
secondArgType := fnType.Type.In(firstInIndex + 1)
182185

183186
if l == firstArgType && r == secondArgType {
184187
return fnType.Type.Out(0)

checker/patcher.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ func (p *operatorPatcher) Exit(node *ast.Node) {
2727
rightType := binaryNode.Right.GetType()
2828
for _, fn := range fns {
2929
fnType := p.types[fn]
30-
31-
firstArgType := fnType.Type.In(0)
32-
secondArgType := fnType.Type.In(1)
30+
firstInIndex := 0
31+
if fnType.Method {
32+
firstInIndex = 1 // As first argument to method is receiver.
33+
}
34+
firstArgType := fnType.Type.In(firstInIndex)
35+
secondArgType := fnType.Type.In(firstInIndex + 1)
3336

3437
if leftType == firstArgType && rightType == secondArgType {
3538
newNode := &ast.FunctionNode{

expr_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,21 @@ func ExampleEval_marshal() {
401401
// Output: true
402402
}
403403

404+
func TestOperator_struct(t *testing.T) {
405+
env := &mockEnv{
406+
BirthDay: time.Date(2017, time.October, 23, 18, 30, 0, 0, time.UTC),
407+
}
408+
409+
code := `BirthDay == "2017-10-23"`
410+
411+
program, err := expr.Compile(code, expr.Env(&mockEnv{}), expr.Operator("==", "DateEqual"))
412+
require.NoError(t, err)
413+
414+
output, err := expr.Run(program, env)
415+
require.NoError(t, err)
416+
require.Equal(t, true, output)
417+
}
418+
404419
func TestExpr(t *testing.T) {
405420
env := &mockEnv{
406421
Any: "any",
@@ -817,6 +832,10 @@ func (*mockEnv) MapArg(m map[string]interface{}) string {
817832
return m["foo"].(string)
818833
}
819834

835+
func (*mockEnv) DateEqual(date time.Time, s string) bool {
836+
return date.Format("2006-01-02") == s
837+
}
838+
820839
type ticket struct {
821840
Price int
822841
}

internal/conf/config.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ func (c *Config) Check() error {
3636
if !ok || fnType.Type.Kind() != reflect.Func {
3737
return fmt.Errorf("function %s for %s operator does not exist in environment", fn, op)
3838
}
39-
40-
if fnType.Type.NumIn() != 2 || fnType.Type.NumOut() != 1 {
39+
requiredNumIn := 2
40+
if fnType.Method {
41+
requiredNumIn = 3 // As first argument of method is receiver.
42+
}
43+
if fnType.Type.NumIn() != requiredNumIn || fnType.Type.NumOut() != 1 {
4144
return fmt.Errorf("function %s for %s operator does not have a correct signature", fn, op)
4245
}
4346
}

0 commit comments

Comments
 (0)