paesslerag / gval Goto Github PK
View Code? Open in Web Editor NEWExpression evaluation in golang
License: BSD 3-Clause "New" or "Revised" License
Expression evaluation in golang
License: BSD 3-Clause "New" or "Revised" License
Hi, thanks for your work.
I found one annoying error in the execution process. When you define parameters that start with a number, then a parsing error occurs.
For example, this code will generate an error parsing error: 2_GH :1:2 - 1:5 unexpected Ident while scanning operator
resultEval, err := gval.Evaluate("2_GH", map[string]interface{}{
"2_GH": 10,
})
Can you please tell me how to fix this? Is this a bug or a feature?
Hello,
I was wondering what would be the way to handle keywords like: Now, Pi.
For now I add them as parameters in the Evaluate() function, but I was wondering if there was a more appropriate way to handle them.
Kind regards,
JClaude
Greetings,
Kudos for the awesome package!
I do think that parseIf
operator should be in base
, because it is useful in arithmetic
, but is not arithmetic
operator itself. Currently I am using .Full()
, instead of just .Arithmetic()
just because of it.
Best
When the error is returned by the function as the last value, the error is treated as it was thrown by the eval
function. Code:
package main
import (
"errors"
"fmt"
"github.com/PaesslerAG/gval"
)
func main() {
exports := map[string]interface{}{
"call": func(s string) (string, error) {
if s == "yes" {
return s + "_returned", errors.New("some error")
}
return s + "_returned", nil
},
}
res, err := gval.Evaluate(`call("yes")`, exports)
fmt.Println(res, err)
}
Will return:
<nil> can not evaluate call("yes"): some error
When you call the the evaluate with
gval.Evaluate(`call("no")`, exports)
Will return:
no_returned <nil>
When you change the error to be returned as not the last element:
package main
import (
"errors"
"fmt"
"github.com/PaesslerAG/gval"
)
func main() {
exports := map[string]interface{}{
"call": func(s string) (error, string) {
if s == "yes" {
return errors.New("some error"), s + "_returned"
}
return nil, s + "_returned"
},
}
res, err := gval.Evaluate(`call("yes")`, exports)
fmt.Println(res, err)
}
Both "yes"
and "no"
will be treated as the return values of the function.
[some error yes_returned] <nil>
[<nil> no_returned] <nil>
Any way to make the error returned by the functions treated as return values?
Is it be possible to configure a language so that variable names takes precedence over functions?
Use case: for a system that stores expressions, allow adding new functions to the language without breaking backwards-compatibility.
Exmaple: for a language with function sin
, in the expresison sin + b
-- treat sin
as variable instead of a functoin if present.
Hi,
I'm trying to create a conditional expression if a variable is nil
, but it throws an Error
instead.
parameters := make(map[string]interface)
parameters["foo"] = "bar"
expression := "fooz ?? foo"
result, err := gval.Evaluate(expression, parameters)
if err != nil {
panic(err)
}
Throw error unknown parameter fooz
when it should be bar
. I've tried to solve this problem by change return error value to a nil value from private function func variable(path ...Evaluable)
Error:
panic: reflect: call of reflect.Value.Interface on zero Value [recovered] panic: reflect: call of reflect.Value.Interface on zero Value
after quick reading, I think it has something to do with the usage of reflection, it does not check whether its valid reflect Value or not
Update - I got things working by adding custom regex to add spaces to my evaluation:
e.g. 4d2 would roll 4 "d2" dice. By adding custom logic to turn 4d2 into "4 d 2" I was able to get things working. Thanks for the support!
I am accessing a map or struct fields in expression string, and in case field is not present in map or struct and if compared like Person.Age > 30 then return true.
Reduced issue is "nil > somevalue" return true.
Currently expression "test"=="test
will be accepted as valid
I have the case that one of my identifiers contains a -
, like type-id
. The parser fails because -
is not an allowed rune in an identifier.
Example:
func main() {
vars := map[string]interface{}{"type-id": "4"}
expr := `type-id == "4"`
e, err := gval.Full().NewEvaluable(expr)
if err != nil {
return
}
value, err := e.EvalBool(context.Background(), vars)
if err != nil {
return
}
fmt.Println(value)
}
I could open a PR, but the fix is so simple: Add the condition (pos > 0 && r == '-')
to https://github.com/PaesslerAG/gval/blob/master/parser.go#L33 . The example works, I tested it even for multiple dashes. But I'm new to gval, so I might miss some cases.
Currently when defining language there is no way to override how float/string/bool are handled and to override behavior for example to be more strict for operations not to allow autocasting for example false || 1
will result in 1 being treated as boolean true or 1+'1'
resulting into 2
Scenario:
I am evaluating " a && b " with map[string]interface{}{"a":true} and i'm getting false.
If I pass to the function an alias for map[string]interface{}, like
type Values map[string]interface{}
with "a":true and without B, I get an error saying:
can not evaluate a && b: unknown parameter b
And this is exactly what we want instead of a nil in the error because we prefer an error instead of a partial evaluation; In other words, we want all the parameters before doing the evaluation.
Is there a way to force the library to fail if some parameter is missing, using a map[string]interface{}. Otherwise, is safety use an alias to map[string]interface{} to check this errors?
This library is fantastic!
The one issue I've found is that the Arithmetic is done as floating point numbers (which is fine for that use case) but this falls short when doing math involving decimals.
An example:
func TestDecimalArithmetic(t *testing.T) {
input := ArithmeticVariables{
NumberMap: map[string]float64{
"x": 12.5,
"y": -5,
},
Expression: "(x * 12.146) - y",
}
result, _ := gval.Arithmetic().Evaluate(input.Expression, input.NumberMap)
want := 156.825
if result != want {
t.Errorf("wanted %f; got %f", want, result)
t.FailNow()
}
t.Log(result)
}
This results in this output:
=== RUN TestDecimalArithmetic
arithmetic_test.go:46: wanted 156.825000; got 156.825000
--- FAIL: TestDecimalArithmetic (0.00s)
When inspecting the variable values, I can see that result
has the actual value of 156.82500000000002
.
Do you have any suggestions for what I should do, or is this even a solvable problem?
I was thinking that there could be an EvaluateDecimal
method, which instead of treating numbers as floats, would treat them as a decimal type? For decimals, I use github.com/shopspring/decimal
.
Hi and thanks for this greate piece of software! :)
We're using it to do sensor mapping:
This works great, except when for some reason we do not get one or more needed sensor data points. In this case it will error out.
Could it be possible to do a callback to an error function instead, and if that error function do return an error, it will fail, otherwise it will remove the json key or set the value to nil (or a value returned by the error function?
func OnError(c context.Context, key, expr string, e error) (val interface{], err error) {}
Example mapping document that we use (partial)
{ "tz": TZ,
"sensors": {
"IDT_O3": float64(datapoint["1!6WHH6DKH3CCVW-"].Value),
"IDT_O5": float64(datapoint["1!6WHH6DKHADPZ1N"].Value),
"AEUPS": float64(datapoint["1!6WHH6DKHICVDSS"].Value * 1000) }
}
The error function may act as a OnErrorResumeNext
or a circuit-breaker
(the latter is how it currently works).
What do you think about this? Is is hard to implement in your library, would it fit?
To maybe do other than current error handling when this or this returns an error?
p.Camouflage("object", ',', '}')
key, err := p.ParseExpression(c)
if err != nil {
return nil, err
}
Cheers,
Mario :)
i have run the following with jsonPath
package main
func main() {
v := interface{}(nil)
json.Unmarshal([]byte(`{
"foo": {
"bar": {
"val": 3
}
}
}`), &v)
value, err := jsonpath.Get("$.*.*.val", v)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for _, value := range value.([]interface{}) {
fmt.Println(value)
}
}
and this is my output
$.*.*.valmap[foo:map[bar:map[val:3]]]3
however if i run
v := interface{}(nil)
json.Unmarshal([]byte(`{
"foo": {
"bar": {
"val": 3
}
}
}`), &v)
value, err := gval.Evaluate("$.*.*.val", v, jsonpath.Language())
it returns
[]
am i using this wrong?
i would expect it to return
3
and if i run
v := interface{}(nil)
json.Unmarshal([]byte(`{
"foo": {
"bar": {
"val": 3
}
}
}`), &v)
value, err := gval.Evaluate("$.*.*.val == 3", v, jsonpath.Language())
i would expect
true
value, err := gval.Evaluate($["response-time"]+" "+$["request.method"]
,
map[string]interface{}{
"response-time": 100,
"response-time1": 110,
"request": {
"method": "GET",
"path": "/hello/2",
} //here causes syntax error: unexpected newline, expecting comma or }, how to fix it?
},
jsonpath.Language(),
)
Please check the above code when want to include nested json content, which always leads to the above specified syntax error
Hello,
First your library looks great. Thank you for sharing.
I would like to evaluate date + duration:
date(myObject.date) + 3d
I was wondering what was the best approach: adding a new language?
Cheers,
JC
Can anyone pls suggest me the way to check string contains ... For example .. string - abde contains bd should be true or any such combinations.
Hi,
Looks like gval is corrupting and returning float64 instead of uint64 when evaluating simple expression.
I'm probably missing something obvious here :)
func TestGval(t *testing.T) {
tUint64 := uint64(197830758113476796)
fmt.Printf("%d %T \n", tUint64, tUint64)
{
eval, _ := gval.Full().NewEvaluable(`a`)
rval, _ := eval(context.Background(), map[string]interface{}{"a": tUint64})
fmt.Printf("%d %T (as expected, got uint64) \n", rval, rval)
}
{
eval, _ := gval.Full().NewEvaluable(`a+0`)
rval, _ := eval(context.Background(), map[string]interface{}{"a": tUint64})
fmt.Printf("%f %T (got float, not expected...) \n", rval, rval)
}
{
eval, _ := gval.Full().NewEvaluable(`A+0`)
rval, _ := eval(context.Background(), struct{ A uint64 }{A: tUint64})
fmt.Printf("%f %T (got float, not expected...) \n", rval, rval)
}
}
Results:
=== RUN TestGval
197830758113476796 uint64
197830758113476796 uint64 (as expected, got uint64)
197830758113476800.000000 float64 (got float, not expected...)
197830758113476800.000000 float64 (got float, not expected...)
Hi Guys,
I have a requirement for the recently added DecimalArithmetic
functionality added here by @machship-mm.
However, this change is not yet published in the latest release.
@generikvault Would it be possible for you or someone else to release a new version?
Thanks!
functions inside expressions are evaluated in coroutine and on panic are not recovered thus crashing whole application. I think there should be somekind of recover as when coroutine ends with not recovered panic the whole application gets shutdown by go runtime.
Line 16 in 12d4df2
Line 39 in 12d4df2
note: why it is done in coroutine? from timeout or context cancellation perspective this makes little sense because if there is endless loop returning from expression that "timeouted" makes little difference because that endless coroutine still works on background.
The following code will panic
value,err := gval.Evaluate(`a[0] + a[2]`, map[string]interface{}{
"a":map[int]int{0:1,2:1},
})
I intend to create a new language to accept following expressions:
a = 1 + 2
b = a * 0.1
a + b
The program will eval it line-by-line, so the ideal result will be:
I'm trying to create a calculator notebook app which allows user to create new avarialbe and new functions.
I found gval.InfixEvalOperator maybe the right spot to look, but I'm stucked by getting the text value of a.
Here is the demo code
gval.InfixEvalOperator("=", func(a, b gval.Evaluable) (gval.Evaluable, error) {
return func(c context.Context, v interface{}) (interface{}, error) {
// I should get a's text value as the variable name here.
// and register global parameter map with a's text value to b's eval result.
return b.EvalString(c, v) // This is is just let me know the value of b.
}, nil
}),
Any hint?
first of all, thanks for the nice project solves my problem a lot.
here is one feature request after using this module in more scenarios of the projects, i'd like to have null safe operator
it's common that my struct is composite of primary and collect data, especially a map in the struct, so i'd like to access the field in the null safe way rather than error out
Ex.
https://www.danvega.dev/blog/2013/08/20/groovys-null-safe-operator/
Hello guys,
at the moment if we want to define a custom function, we just extend the language
gval.Evaluate(
expression,
data,
gval.Function("foo", func(args ...interface{}) (interface{}, error) {
return "bar", nil
}),
...
)
Yet we can EvaluateWithContext
, say context with value.
ctx := context.WithValue(context.Background(), "input", data)
gval.EvaluateWithContext(
ctx,
expression,
data,
gval.Function("foo", func(args ...interface{}) (interface{}, error) {
return "bar", nil
}),
...
)
Unfortunately, the context is not passed into a function itself. So maybe, we could do something like
ctx := context.WithValue(context.Background(), "input", data)
gval.EvaluateWithContext(
ctx,
expression,
data,
gval.FunctionWithContext("foo", func(ctx context.Context, args ...interface{}) (interface{}, error) {
return count(ctx.Value("input")), nil
}),
...
)
Why would one need it? E.g.:
[]interface{}
);time
, parse as time and do something.Wdyt? Or maybe there's already the way to pass some extra information into the gval function? I've tried with Init, but I apparently don't understand its concept that much.
Best regards,
sk
type Client struct{}
func (c *Client) Foo(s string) string {
return s
}
gval.Evaluate(`client.Foo("bar")`, map[string]interface{}{"client": c}) // works: does return "bar"
But
type Client struct{}
func (c *Client) Foo(s string, f func()) string {
f()
return s
}
gval.Evaluate(`client.Foo("bar", func(){})`, map[string]interface{}{"client": c}) // does not work
returns&errors.errorString{s:"parsing error: client.Foo(\"bar\", func(){})\t:1:25 - 1:26 unexpected \"{\" while scanning arguments expected \")\" or \",\""} a <nil>
In the following code:
result, err := gval.Evaluate("undefined_value == 10", map[string]interface{}{
"whatever_var": "whatever_value",
})
fmt.Println(result, err)
I expect an error to be printed, instead it is printing: false, <nil>
I am evaluating " a && b " with map[string]interface{}{"a":true} and i'm getting false in result instead of err result.
I remember that in some cases the function return the following err:
can not evaluate a && b: unknown parameter b
package main
import (
"fmt"
"github.com/PaesslerAG/gval"
)
func main() {
vars := map[string]interface{}{"name": true}
value, err := gval.Evaluate("true&&name", vars)
if err != nil {
fmt.Println(err)
}
fmt.Println(value)
value, err = gval.Evaluate("true&& name", vars)
if err != nil {
fmt.Println(err)
}
fmt.Println(value)
}
runing result:
parsing error: true&&name - 1:8 unknown operator &&n
<nil>
true
My expected result is the first expression also working fine.
I have expression vtg_ground_speed_unit > 0 ? vtg_ground_speed_knots : vtg_ground_speed_kph
.
These variables (vtg_ground_speed_unit
, vtg_ground_speed_knots
, vtg_ground_speed_kph
) can only be from fixed list (coming from configuration file). So it would be nice if would be a way to get all variables from parsed expression so they could be validated against current configuration - to see if they exist or not.
So far I have tried to create selector that captures all seen variables in "test evaluation".
Something like that:
type variableCaptor struct {
variables []string
}
func (c *variableCaptor) SelectGVal(_ context.Context, variable string) (interface{}, error) {
c.captureVariable(variable)
return 1.0, nil
}
func (c *variableCaptor) captureVariable(variable string) {
for _, v := range c.variables {
if variable == v {
return
}
}
c.variables = append(c.variables, variable)
}
func TestCaptureVariables(t *testing.T) {
var testCases = []struct {
name string
expression string
expect []string
}{
{
name: "capture 3 variables from IF",
expression: "vtg_ground_speed_unit > 0 ? vtg_ground_speed_knots : vtg_ground_speed_kph",
expect: []string{"vtg_ground_speed_unit", "vtg_ground_speed_knots", "vtg_ground_speed_kph"},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
eval, err := compile(tc.expression, gval.Full())
if !assert.NoError(t, err) {
return
}
captor := &variableCaptor{variables: make([]string, 0)}
_, err = eval.EvalBool(context.Background(), captor)
if !assert.NoError(t, err) {
return
}
assert.Equal(t, tc.expect, captor.variables)
})
}
}
but this has limitation as vtg_ground_speed_kph
will not get captured as executing all paths from expression involves knowing how to provides values for getting true/false sides.
Is there a way to traverse parsed tree without evaluation and pick all parts that are used as "variable"?
Hey folks; first up thanks for gval... it's a seriously awesome little library. Hard to believe it doesn't have more adoption!
To the point... I'm using gval in a little tool I wrote to smash up kubernetes manifests. https://github.com/mikesimons/kpatch. Please excuse the nasty code; it's prototype grade at the moment.
I've implemented an =
infix operator and it works pretty well to overwrite values that already exist.
The problem is that because I can't get the verbatim key from the left expression I'm having to set values based on a walk of the input structure and matching on reflection values. It works but it means that if the key doesn't exist no value matches and the value is not set.
To get around it I implemented a set
function but from a user experience perspective I'd really like to be able to do some.key = "value"
even if some.key
wasn't previously set.
I had a go with an InfixEvalExpression but due to the input being wrapped in an Evaluable
func I couldn't get the value out.
Any advice on a way to do this (even if it means patching gval)?
This is on github.com/PaesslerAG/gval v1.2.1
We have a custom handler for regular expressions (match(value, regex)
) where the regex can be configured from the front-end (web application).
For example, inputting match(variable, "[a-z]\d")
would be presented as (when dumping the value) "match(variable, \"[a-z]\\d\")"
(which seems correct to me), but when passed to gval, it raises parsing error: match(variable, "[a-z]\d") :1:11 - 1:20 could not parse string: invalid syntax
.
If I bypass all of the surrounding code and run it directly as so x, err := gval.Evaluate("match(variable, \"[a-z]\\d\")", map[string]any{"a": "b"})
the error is the same.
Another example would be running this x, err := gval.Evaluate("\"\\\"", map[string]any{"a": "b"})
-- same error in regards to the invalid string (parsing error: "\" :1:1 - 1:4 could not parse string: invalid syntax
).
But then, if I do this x, err := gval.Evaluate("\"apple\\banana\"", map[string]any{"a": "b"})
, it passes and outputs (when running spew.Dump(x, err)
)
(string) (len=11) "apple\banana"
(interface {}) <nil>
Am I doing something wrong with my strings, or is this a (un)intentional edge case?
If this needs more investigation I can take a look through the code and propose a fix as well, but I'd appreciate some notes on where would be a good place to start/your suspicions about what's wrong
I use this project in my job and solve a lot problems. Really appreciate for it.
But i found there are some scences that i need to get the metadata of parsed evaluable.
For example:
in our system, we allow users to configure their expression with functions and operators our language supported like a rule engine.
Apperently we want to check if user's input is valid (not syntax but business logic) but i found it is hard to get metadata by gval now, like which function does this expr use and the params pass by user.
From a legitimate point of view, this is an ability that parse module should support instead of user use init language and context to hack it.
I have read the other issues and found this problem also made other guys confused like #75
I have tried to solve it by adding wrap gval.Evaluable with a metadata, it looks fine to solve this problem. if you guys agree this request, i can work on it.
// EvaluableFunc evaluates given parameter
type EvaluableFunc func(c context.Context, parameter interface{}) (interface{}, error)
// when parse the specific token, we can pour metadata into Evaluable
type Evaluable struct {
EvaluableFunc
metadata *EvaluableMetadata
}
expect your replies. @generikvault @darh @impl
According to the readme, you can define an array in gval:
Json Arrays : [1, 2, "foo"]
And you can look up an element from an array:
Map and array elements and Struct Field can be accessed via [].
foo[0]
Then I should be able to define an array and look up an element:
[10,11,12,13][2]
I expected this to return 12
, but instead I got:
&errors.errorString{s:"parsing error: [10,11,12,13][2]\t:1:14 - 1:15 unexpected \"[\" while scanning operator"}
What I'm trying to do is let a customer define an array in a gval string, and input from their user will be used to look up an element:
["foo", "bar", ...][x]
Where "foo", "bar", ...
is written by an admin, and x
comes from an end user.
Some special functions like filter
, map
, exists
, all
.
For example:
["project1/text.txt", "project2/text.txt"].exists(t => t.startsWith("project1"))
; => true
This would simplify a lot of some operations that would require very specific custom functions.
Let me know if that's something you have thought about it.
`varsForPassing := map[string]interface{}{
"AGG311": 1,
"AGG312": 2,
"AGG313": 3,
}
function := gval.Function("max", func(args ...interface{}) (interface{}, error) {
arr := args[0].([]float64)
largest := arr[0]
for _, val := range arr {
if val > largest {
largest = val
}
}
return largest, nil
})
value, err := gval.Evaluate("max([AGG311, AGG312, AGG313]) > 1000", varsForPassing, function)
fmt.Println(value, err)`
I get the error "panic: interface conversion: interface {} is []interface {}, not []float64"
Is it not possible to define an array with variables and use a function on it?
Example:
expression: a + b > 6
args: {"a":3,"b":4}
result: 3 + 4 > 6
Because i need to show the user the calculation process of the expression rather than the direct result.
Thanks.
I need to create a language with some concrete set of rules (to obtain an ES query). I already have something like:
func getLanguage() gval.Language {
return gval.NewLanguage(
gval.InfixTextOperator("==", eqStringOp),
gval.InfixOperator("&&", andOp),
gval.InfixOperator("||", orOp),
gval.Base(),
)
}
and I evaluate it with:
var paramMap = map[string]string{
"device": "device_id",
"type": "type",
"label.id": "label.id",
"label.value": "label.value",
}
result, err := lang.Evaluate(`label.id = "my-id"`, paramMap)
How can I add nested parameter support (as it is support when calling gval.Evaluate()
)?
The file prtg-batmin-gopher.png
is over 600k and seemingly only referenced in the README. This needly increases the size of repos that end up vendoring this library. Can this file be reduced in size (it's presented as much smaller in the image tag that references it) or be remove from the repo all together?
I'm struggling to get a bit more control over how path selection is done.
I would like to expose one of my structs with prop that's internally slice of structs ({ name, value, position }
) to be accessed in more "fluent" way (record.values.foo
or record.values.bar[0]
). More info here: https://github.com/cortezaproject/corteza-server/blob/develop/compose/types/record.go#L38
Currently, I'm doing this by casting into map[string]interface{}
but I would like to avoid this because it requires keeping copies of the original data and constantly syncing and casting.
I've tried with adding an operator but I have to admit I'm lacking know-how of the internal workings of gval to make even a proof of concept. A custom function (getValue(record, name, position)
) would work but that ruins the fluentness :)
After digging more into gval, I'm thniking that a) variable
fn could be modified to get additional case that would cover a special interface interface { GvalSelect(key string) (interface{}, error) }
(I'm not 100% happy with the fn name here... ).
If you think this would be a good approach I can open a PR in next couple of days.
Hi,
I am using gval to build an excel formula parser. Repo name is efp. Check efp_test.go. You can change case in expression to see behavior.
In excel, all function names are capitalized so, I have created Functions with Capital names. Language allows creation of non-null Evaluable even when case does not match. But, when Eval* function is called on Evaluable the results are incorrect.
The function mapped to keyword is called correctly and the value returned from the function is accurate but, it seems this value is lost after evaluation. Any thoughts?
Ideally Parse should fail in this scenario so that users get feedback when expression is built improperly.
When providing expression -1==-1
parser fails with error parsing error: -1==-1 - 1:6 unknown operator ==-
Our app allows end users (not developers) to write mathematical expressions. We would like to present errors in a way that the users will understand. Unfortunately, the parser errors are very low-level and not related to the mathematical syntax.
Examples of actual and desired output:
Input:
Actual error: unexpected EOF while scanning extensions
Desired error: input is empty
Input: (
Actual error: unexpected EOF while scanning extensions
Desired error: missing right parenthesis
Input: )
Actual error: unexpected ")" while scanning extensions
Desired error: missing left parenthesis
Input: ()
Actual error: unexpected ")" while scanning extensions
Desired error: no expression inside parentheses
Input: 1+
Actual error: unexpected EOF while scanning extensions
Desired error: missing expression to the right of "+"
Input: +1
Actual error: unexpected "+" while scanning extensions
Desired error: missing expression to the left of "+"
The functions used by the full
language are not exported, which makes it hard to use them in a custom language. I got around this with //go:linkname
for now, but was wondering if it might be possible to export them similar to Parentheses()
and other language components.
Is it possible to get source location information for the returned results? I'm primarily interested in a JSON Path use-case where I can tell where in the original document the results of the query came from, e.g. a query like $..parameters[[email protected] == "query"]
gives me a bunch of parameter
objects and I'd like to know the line/col of the start of each parameter in the input file bytes. Is this something that is currently possible or something you would support in this library?
that is code:
package main
import (
"fmt"
"github.com/PaesslerAG/gval"
)
func main() {
value, err := gval.Evaluate(`foo in [100, 101]`, map[string]interface{}{
"foo": 100,
})
if err != nil {
fmt.Println(err)
}
fmt.Print(value)
}
it expect be true, but get false
Hi!
We would like to integrate gval into our platform, so that our users can write their own arithmetic expressions. However, in order to keep the language well defined, we would like to select exactly which operators to allow, in our case it would be - ( ) + - * /
and nothing more.
We could duplicate the definitions of base
and arithmetic
and strip them down, but it feels wrong to duplicate the inline code (which is library internals) outside the library, as there might be compatibility issues in the future.
Therefore we would welcome improved granularity, so that operators can be chosen on an individual basis. If you don't have time to implement it, would you accept a PR with such a change?
Best Regards,
Tom Weber
Precisely AB
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.