Skip to content

Checker infinit looping when using patcher/value and operator overloading #637

Description

@rrb3942

I'm adding support for "github.com/shopspring/decimal" to my project that makes use of "expr/patcher/value" and ran into an issue where cpu usage spikes to 100% and expr gets stuck compiling the expression when I try to introduce operator support.

trace.txt

From the trace it seems like it is getting stuck in the checker for some reason.

Here is an example program that can recreate the problem.

package main
import (
"fmt""log""net/http"
_ "net/http/pprof""github.com/expr-lang/expr""github.com/expr-lang/expr/patcher/value""github.com/expr-lang/expr/vm""github.com/shopspring/decimal"
)
typemyIntstruct {
Intint
}
func (v*myInt) AsInt() int {
returnv.Int
}
func (v*myInt) AsAny() any {
returnv.Int
}
functoDecimal(valany) (decimal.Decimal, error) {
switchv:=val.(type) {
caseint:
returndecimal.NewFromInt(int64(v)), nilcaseint32:
returndecimal.NewFromInt32(v), nilcaseint64:
returndecimal.NewFromInt(v), nilcasefloat32:
returndecimal.NewFromFloat32(v), nilcasefloat64:
returndecimal.NewFromFloat(v), nilcasestring:
d, err:=decimal.NewFromString(v)
iferr!=nil {
return decimal.Decimal{}, err
}
returnd, nilcase decimal.Decimal:
returnv, nildefault:
return decimal.Decimal{}, fmt.Errorf("Unhandled type for rounding (type: %T)", v)
}
}
funcExampleAnyValuer() {
env:=make(map[string]any)
//using a plain int here also works fine//env["ValueOne"] = 1//But value types are brokenenv["ValueOne"] =&myInt{1}
env["ValueTwo"] =&myInt{2}
fmt.Println("Compiling")
//this is fine//program, err := expr.Compile("decimal(1) * decimal(2)",//these are broken//program, err := expr.Compile("decimal(ValueOne) * decimal(ValueTwo)",program, err:=expr.Compile("decimal(ValueOne) * decimal(2)",
expr.Env(env),
value.ValueGetter,
expr.Function(
"decimal",
func(params...any) (any, error) {
returntoDecimal(params[0])
},
new(func(int) decimal.Decimal),
new(func(int32) decimal.Decimal),
new(func(int64) decimal.Decimal),
new(func(float32) decimal.Decimal),
new(func(float64) decimal.Decimal),
new(func(string) decimal.Decimal),
),
expr.Function(
"_decimalMul",
func(params...any) (any, error) {
returnparams[0].(decimal.Decimal).Mul(params[1].(decimal.Decimal)), nil
},
new(func(decimal.Decimal, decimal.Decimal) decimal.Decimal),
),
expr.Operator("*", "_decimalMul"),
)
iferr!=nil {
panic(err)
}
fmt.Println("Running")
out, err:=vm.Run(program, env)
iferr!=nil {
panic(err)
}
fmt.Println(out)
}
funcmain() {
gofunc() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
ExampleAnyValuer()
}

If there is any additional information that would help just let me know.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions