Skip to content

Provides support for evaluating arbitrary C-like artithmetic/string expressions.

License

Notifications You must be signed in to change notification settings

StrangeYear/goeval

Repository files navigation

GoEval

Provides support for evaluating arbitrary C-like artithmetic/string expressions.

How do I use it?

GoEval can evaluate expressions with parameters, arimethetic, logical, and string operations:

  • basic expression: 10 > 0
  • parameterized expression: foo > 0
  • special parameterized expression: $.["foo bar"] > 0$.["response-time"] > 0
  • nested parameterized expression: foo.bar > 0foo.bar[0] > 0foo["bar"] > 0$.["foo bar"].$.["foo baz"] > 0
  • gjson expression: $["response-time"] > 0$["data.items.0"] < 0
  • arithmetic expression: (requests_made * requests_succeeded / 100) >= 90
  • string expression: http_response_body == "service is ok"
  • float64 expression: (mem_used / total_mem) * 100
  • date comparator: date(2022-05-02) > date(2022-05-01 23:59:59)
  • date timestamp comparator: date(1651467728) > date("2022-05-01 23:59:59")
  • strlen("someReallyLongInputString") <= 16

It can easily be extended with custom functions or operators:

custom comparator: max(1,2,3) > 1

What operators and types does this support?

  • Modifiers: + - / * %
  • Comparators: > >= < <= == != =~ !~ in
  • Logical ops: || &&
  • Numeric constants, as 64-bit floating point (12345.678)
  • String constants ("foo", 'bar', baz)
  • Boolean constants: true false
  • Parenthesis to control order of evaluation ( )
  • Arrays (anything separated by , within parenthesis: [1, 2, 'foo', bar], bar is variable)
  • Prefixes: ! - ~
  • Ternary conditional: ? :
  • Null coalescence: ??

Functions

func TestFunc(t *testing.T) {
	val, err := Full(
		WithFunc("max", func(args ...any) (any, error) {
			if len(args) == 0 {
				return 0, nil
			}
			max := func(a, b float64) float64 {
				if a > b {
					return a
				}
				return b
			}
			var val float64
			val, ok := args[0].(float64)
			if !ok {
				return 0, fmt.Errorf("max() expects number arguments")
			}
			for i, arg := range args {
				if i == 0 {
					continue
				}
				arg, ok := arg.(float64)
				if !ok {
					return 0, fmt.Errorf("max() expects number arguments")
				}
				val = max(val, arg)
			}
			return val, nil
		}),
	).EvalFloat(`max(1,2,3,a)`, map[string]any{"a": float64(6)})
	if err != nil {
		t.Fatalf("Eval() error = %v", err)
	}
	t.Log(val == 6)
	// output: true
}

Benchmarks

For a very rough idea of performance, here are the results output from a benchmark run on a Mac (i9-9900K).

goos: darwin
goarch: amd64
pkg: github.com/StrangeYear/goeval
cpu: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
BenchmarkEvaluationSingle-16                 	 2371440	       508.2 ns/op
BenchmarkEvaluationNumericLiteral-16         	  979606	      1178 ns/op
BenchmarkEvaluationLiteralModifiers-16       	  604010	      1903 ns/op
BenchmarkEvaluationParameter-16              	 1344694	       885.3 ns/op
BenchmarkEvaluationParameters-16             	  712880	      1594 ns/op
BenchmarkEvaluationParametersModifiers-16    	  478978	      2434 ns/op
BenchmarkComplexExpression-16                	  143646	      8187 ns/op
BenchmarkRegexExpression-16                  	  451497	      2595 ns/op
BenchmarkFunc-16                             	  268068	      4476 ns/op
BenchmarkJSON-16                             	  460448	      2557 ns/op
BenchmarkNested-16                           	  520017	      2287 ns/op
BenchmarkSpecial-16                          	 1323009	       908.7 ns/op
PASS

About

Provides support for evaluating arbitrary C-like artithmetic/string expressions.

Resources

License

Stars

Watchers

Forks

Packages

No packages published