expr icon indicating copy to clipboard operation
expr copied to clipboard

Operator override not detecting the correct method.

Open rajvikram opened this issue 4 years ago • 0 comments

After making some truly awesome progress implementing a scripting language, I ran into an issue where operator override does not work when using an interface that represent an IdentifierNode and a Patch() to initialize the object behind the interface. Basically I have an override for the * where I'd like to multiply an interface with a float64. Here's a simplified version of the code:

package main

import (
	"fmt"
	"github.com/antonmedv/expr"
	"github.com/antonmedv/expr/ast"
)

// 
type SomeInterface interface {
	Set(v float64)
	Get() float64
}

type SomeImpl struct{
	val float64
}
func (s *SomeImpl) Set(v float64) { s.val = v}
func (s *SomeImpl) Get() float64  {return s.val}

// Env over rides and patches
type SomeEnv struct {}

func (e *SomeEnv) InitSomeImpl(_ string) SomeInterface{
	s := &SomeImpl{1.0}
	return s
}

func (e *SomeEnv) MulSomeInterfaceByFloat64(ss SomeInterface, v float64) SomeInterface {
	s := ss.(*SomeImpl)
	s.Set(s.Get() * v)
	return s
}

func (e *SomeEnv) Enter(_ *ast.Node) {}
func (e *SomeEnv) Exit(node *ast.Node) {
	switch n := (*node).(type) {

	case (*ast.IdentifierNode):
		ast.Patch(node, &ast.FunctionNode{
			Name:      "InitSomeImpl",
			Arguments: []ast.Node{&ast.StringNode{Value: n.Value}},
		})
	}
}


func main() {
	// Multiply unit matrix by a scalar
	code := `m1 * 10.0` 	// Does not run. Gives following error.
							// panic: invalid operation: *main.TwoByTwoMatrix * float64 (1:4)
							// | m1 * 10.0
							// | ...^

	//code := `InitSomeImpl("m1") * 10.0` // Works correctly

	env := SomeEnv{}
	options := []expr.Option{
		expr.Env(&env),
		expr.Patch(&env),
		expr.Operator("*", "MulSomeInterfaceByFloat64"), // Override `*` with function.
	}

	program, err := expr.Compile(code, options...)
	if err != nil {
		panic(err)
	}

	output, err := expr.Run(program, &env)
	if err != nil {
		panic(err)
	}
	fmt.Println("Output : ", output)
}

When I try to run the expression m1 * 10.0 I get an error :

panic: invalid operation: *main.SomeImpl * float64 (1:4)
 | m1 * 10.0
 | ...^

However if I run the same expression as InitSomeImpl("m1") * 10.0, it works. Does this have something to do with the way Patch works with interfaces ? Ideally I'd not like to call InitSomeImpl in the expression.

rajvikram avatar Mar 02 '21 07:03 rajvikram