expr
expr copied to clipboard
Operator override not detecting the correct method.
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.