Giter Club home page Giter Club logo

gval's Issues

Variables beginning with a number

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?

Keywords

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

Move `parseIf` operator in `base`

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

Return the error when error is returned by a function

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?

Allow variables to overload functoins

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.

Undefined attributes key returns error

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)

Panic when provided using struct object with null pointer field

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

Error when Not Adding Space for New Operator

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!

eval `nil > 1` returns true

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.

Allow dashes in identfiers

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.

Add option to override functions to parse string/float/bool

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

Force fail when a parameter is missing.

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?

Handle decimal/money arithmetic

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.

Error callback instead of terminating error in JSON

Hi and thanks for this greate piece of software! :)

We're using it to do sensor mapping:

  • i.e fetch sensor data as a single HTTP request
  • map those sensors into our own sensor model.

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 :)

unable to get value

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 

how to parse complex json with jsonpath?

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

Date evaluation

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

Issues with uint64 when using in expression

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...)

functions inside expression are evaluated in coroutine and on panic are not recovered thus crashing whole application

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.

go func() {

and
go func() {

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.

How to define a language which allows to create varaiables?

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:

  1. Found a new variable named 'a' and it's value is Evaluate("1+2"). Register "a" and it's value 3 to the parameter map which will be used to eval next line.
  2. Found a new variable named 'b' and it's value is Evaluate("a * 0.1", map[string]interface{}{"a":3}).
  3. Finally Evaluate("a + b", map[string]interface{}{"a": 3, "b":0.3}).

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?

Passing a context to the custom functions

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.:

  • To get an entire parameters, not only arguments selected for the function (say, count all elements in []interface{});
  • If the string is the argument, check in context, that this type should be 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

Struct methods do not accept func arguments

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>

No error even for invalid expression

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>

lazy evaluation

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

Without space after && leading error

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.

getting list of parsed variables before expression is evaluated for validation

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"?

Guidance; abusing gval to set keys

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)?

Evaluating strings with backslashes raises parsing errors

Env

This is on github.com/PaesslerAG/gval v1.2.1

Issue

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>

Conclusion

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

feature request: add metadata in evaluable

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

Unable to define and look up array

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.

Feature Request: high order functions (collection)

What is it?

Some special functions like filter, map, exists, all.

For example:

["project1/text.txt", "project2/text.txt"].exists(t => t.startsWith("project1"))
; => true

Why?

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.

Unable to accept an array as input to custom function

`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?

How to get rendered expressions

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.

How to create a language with nested parameter support?

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())?

600+k png file is checked in

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?

Extending variable() to support custom selectors on value

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.

Case Mismatch: Able to create Evaluable but actual evaluate fails

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.

Parsing errors are not user-friendly

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 "+"

Export parseIf

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.

Result line/column information

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?

evaluate with operator in value not expected

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

Better language granularity

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.