前言

Gval(Go eVALuate)支持计算任意表达式,特别是类似 Go 的表达式。

用途

Gval 可以使用参数、arimethetic、logical 和 string 运算来计算表达式:

  • 基本表达式:10 > 0
  • 参数化表达式: foo > 0
  • 嵌套参数化表达式:foo.bar > 0`
  • 算术表达式:(requests_made * requests_succeeded / 100)>= 90
  • 字符串表达式:http_response_body == "service is ok"
  • float64 表达式:(mem_used / total_mem)* 100

它可以通过自定义函数或运算符轻松扩展:

  • 自定义日期比较器: date(2014-01-02) > date(2014-01-01 23:59:59)
  • 字符串长度: strlen(“someReallyLongInputString”) <= 16

您可以解析gval.Expressions一次,并多次重复使用它们。解析是该过程的计算密集型阶段,因此,如果您打算将同一表达式用于不同的参数,只需解析一次:

遵循运算符的正常 Go 标准顺序。编写表达式时,请确保对运算符进行正确的排序,或使用括号来阐明应首先运行表达式的哪些部分。

字符串、数字和布尔值可以像在 Go 中一样使用:

(7 < “47” == true ? “hello world!\n\u263a”) + `more text`

参数

变量可以通过字符串字面来访问。如果参数是map[string]interface{}map[interface{}]interface{},它们可以用于带有字符串键的值;如果参数是struct,它们可以用于字段或方法。

  • foo > 0

括号选择器

map和数组元素以及Struct Field可以通过[]访问。

  • foo[0]
  • foo[“b” + “a” + “r”]

点选择器

一个名称只包含字母和下划线的嵌套变量可以通过点选择器访问。

  • foo.bar > 0

自定义选择器

像"response-time"这样的参数名称将被解释为响应减去时间。虽然gval不直接支持这些参数名,但你可以通过JSON Path这样的自定义扩展轻松访问它们。

  • $["response-time"]

Jsonpath也适用于访问数组元素。

字段和方法

如果你的参数中有结构体,你可以用通常的方式访问其字段和方法。

  • foo.Hello + foo.World()

如果参数是直接Hello + World()的结构,或者字段是嵌套的foo.Hello + foo.World(),它也可以工作。

这可能很方便,但要注意的是,在结构体上使用访问器会使表达式的速度比直接使用参数慢四倍左右(在你的系统上咨询基准以获得更精确的测量值)。如果有你想使用的函数,把它们定义为函数会更快(而且可能更干净)(见Evaluate部分)。这些方法不使用反射,并且被设计为快速和干净。

默认语言

默认语言是在多个子语言中定义的,如文本、算术或命题逻辑。详见Godoc。所有子语言都被合并到gval.Full中,其中包含以下元素。

  • 修饰语: + - / * & | ^ ** % » «
  • 比较器: > >= < <= == != =~ !~
  • 逻辑运算法则: || &&
  • 数字常量,作为64位浮点 (12345.678)
  • 字符串常量 (双引号: “foobar”)
  • 日期函数 ‘Date(x)’, 使用RFC3339、ISO8601、Ruby date或unix date的任何排列组合.
  • 布尔常数: true false
  • 小括号用于控制评估的顺序 ( )
  • Json数组 : [1, 2, “foo”]
  • Json对象 : {“a”:1, “b”:2, “c”:“foo”}
  • 前缀: ! - ~
  • 三元条件: ? :
  • 空值凝聚: ??

自定义

Gval是完全可定制的。每个常数、函数或运算符都可以单独定义,现有的表达式语言可以重复使用。

1
foo.Hello + foo.World()

实现自定义选择器

如果你想为选择器提供自定义逻辑,你可以在你的结构上实现SelectGVal(ctx context.Context, k string) (interface{}, error)。该函数接收路径的下一部分,可以返回任何类型的var,通过标准gval程序再次进行评估。

外部gval语言

gval的外部库列表。请随意添加你自己的库。

  • gvalstrings解析gval中的单引号字符串。
  • jsonpath 在gval中完全支持jsonpath。

性能

该库是以快速为目的建立的,但没有进行积极的分析和优化。不过,对于大多数应用来说,它是完全没有问题的。如果性能是一个问题,请确保在创建表达式语言时,所有的函数、常量和操作符都只使用一次。像gval.Evaluate("expression, const1, func1, func2, ...")这样评估一个表达式,每次调用时都会创建一个新的gval.Language,从而减缓执行速度。

该库附带了一堆基准,以衡量解析和评估表达式的性能。你可以用go test -bench=.运行它们。

对于一个非常粗略的性能概念,以下是在Dell Latitude E7470 Win 10 i5-6300U上运行的基准测试的结果。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
BenchmarkGval/const_evaluation-4                               500000000                 3.57 ns/op
BenchmarkGval/const_parsing-4                                    1000000              1144 ns/op
BenchmarkGval/single_parameter_evaluation-4                     10000000               165 ns/op
BenchmarkGval/single_parameter_parsing-4                         1000000              1648 ns/op
BenchmarkGval/parameter_evaluation-4                             5000000               352 ns/op
BenchmarkGval/parameter_parsing-4                                 500000              2773 ns/op
BenchmarkGval/common_evaluation-4                                3000000               434 ns/op
BenchmarkGval/common_parsing-4                                    300000              4419 ns/op
BenchmarkGval/complex_evaluation-4                             100000000                11.6 ns/op
BenchmarkGval/complex_parsing-4                                   100000             17936 ns/op
BenchmarkGval/literal_evaluation-4                             300000000                 3.84 ns/op
BenchmarkGval/literal_parsing-4                                   500000              2559 ns/op
BenchmarkGval/modifier_evaluation-4                            500000000                 3.54 ns/op
BenchmarkGval/modifier_parsing-4                                  500000              3755 ns/op
BenchmarkGval/regex_evaluation-4                                   50000             21347 ns/op
BenchmarkGval/regex_parsing-4                                     200000              6480 ns/op
BenchmarkGval/constant_regex_evaluation-4                        1000000              1000 ns/op
BenchmarkGval/constant_regex_parsing-4                            200000              9417 ns/op
BenchmarkGval/accessors_evaluation-4                             3000000               417 ns/op
BenchmarkGval/accessors_parsing-4                                1000000              1778 ns/op
BenchmarkGval/accessors_method_evaluation-4                      1000000              1931 ns/op
BenchmarkGval/accessors_method_parsing-4                         1000000              1729 ns/op
BenchmarkGval/accessors_method_parameter_evaluation-4            1000000              2162 ns/op
BenchmarkGval/accessors_method_parameter_parsing-4                500000              2618 ns/op
BenchmarkGval/nested_accessors_evaluation-4                      2000000               681 ns/op
BenchmarkGval/nested_accessors_parsing-4                         1000000              2115 ns/op
BenchmarkRandom-4                                                 500000              3631 ns/op
ok

概述

包gval提供了一种通用表达式语言。所有的函数、infix和前缀运算符都可以通过组合语言来替换成新的语言。

该包包含具体的表达式语言,用于文本、算术、命题逻辑等方面的常见应用。它们可以作为自定义表达式语言的基础,或者直接评估表达式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	vars := map[string]interface{}{"name": "World"}

	value, err := gval.Evaluate(`"Hello " + name + "!"`, vars)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}
1
Hello World!

func Evaluate

1
func Evaluate(expression string, parameter interface{}, opts ...Language) (interface{}, error)

用gval完整语言中的给定表达式评估给定参数

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate("foo > 0", map[string]interface{}{
		"foo": -1.,
	})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
false

Example (Accessor)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

type exampleType struct {
	Hello string
}

func (e exampleType) World() string {
	return "world"
}

func main() {

	value, err := gval.Evaluate(`foo.Hello + foo.World()`,
		map[string]interface{}{
			"foo": exampleType{Hello: "hello "},
		})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
hello world

Example (Arithmetic)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate("(requests_made * requests_succeeded / 100) >= 90",
		map[string]interface{}{
			"requests_made":      100,
			"requests_succeeded": 80,
		})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
false

Example (Array)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate("foo[0]", map[string]interface{}{
		"foo": []interface{}{-1.},
	})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
-1

Example (ComplexAccessor)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate(`foo["b" + "a" + "r"]`, map[string]interface{}{
		"foo": map[string]interface{}{"bar": -1.},
	})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
-1

Example (DateComparison)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
	"fmt"
	"time"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate("date(`2014-01-02`) > date(`2014-01-01 23:59:59`)",
		nil,
		// define Date comparison because it is not part expression language gval
		gval.InfixOperator(">", func(a, b interface{}) (interface{}, error) {
			date1, ok1 := a.(time.Time)
			date2, ok2 := b.(time.Time)

			if ok1 && ok2 {
				return date1.After(date2), nil
			}
			return nil, fmt.Errorf("unexpected operands types (%T) > (%T)", a, b)
		}),
	)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
true

Example (Encoding)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate(`(7 < "47" == true ? "hello world!\n\u263a" : "good bye\n")`+" + ` more text`",
		nil,
		gval.Function("strlen", func(args ...interface{}) (interface{}, error) {
			length := len(args[0].(string))
			return (float64)(length), nil
		}))
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
2
hello world!
more text

Example (FlatAccessor)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

type exampleType struct {
	Hello string
}

func (e exampleType) World() string {
	return "world"
}

func main() {

	value, err := gval.Evaluate(`Hello + World()`,
		exampleType{Hello: "hello "},
	)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
hello world

Example (Float64)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate("(mem_used / total_mem) * 100",
		map[string]interface{}{
			"total_mem": 1024,
			"mem_used":  512,
		})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
50

Example (Jsonpath)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
	"github.com/PaesslerAG/jsonpath"
)

func main() {

	value, err := gval.Evaluate(`$["response-time"]`,
		map[string]interface{}{
			"response-time": 100,
		},
		jsonpath.Language(),
	)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

100

Example (NestedAccessor)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

type exampleType struct {
	Hello string
}

func (e exampleType) World() string {
	return "world"
}

func main() {

	value, err := gval.Evaluate(`foo.Bar.Hello + foo.Bar.World()`,
		map[string]interface{}{
			"foo": struct{ Bar exampleType }{
				Bar: exampleType{Hello: "hello "},
			},
		})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
hello world

Example (NestedParameter)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate("foo.bar > 0", map[string]interface{}{
		"foo": map[string]interface{}{"bar": -1.},
	})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
false

Example (String)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate(`http_response_body == "service is ok"`,
		map[string]interface{}{
			"http_response_body": "service is ok",
		})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
true

Example (Strlen)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {

	value, err := gval.Evaluate(`strlen("someReallyLongInputString") <= 16`,
		nil,
		gval.Function("strlen", func(args ...interface{}) (interface{}, error) {
			length := len(args[0].(string))
			return (float64)(length), nil
		}))
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

false

func EvaluateWithContext

1
func EvaluateWithContext(c context.Context, expression string, parameter interface{}, opts ...Language) (interface{}, error)

在gval完整语言中使用上下文对给定参数和给定表达式进行评估

type Evaluable

1
type Evaluable func(c context.Context, parameter interface{}) (interface{}, error)

Evaluable评估给定的参数

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
	"context"
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {
	eval, err := gval.Full(gval.Constant("maximum_time", 52)).
		NewEvaluable("response_time <= maximum_time")
	if err != nil {
		fmt.Println(err)
	}

	for i := 50; i < 55; i++ {
		value, err := eval(context.Background(), map[string]interface{}{
			"response_time": i,
		})
		if err != nil {
			fmt.Println(err)

		}

		fmt.Println(value)
	}

}

Output:

1
2
3
4
5
true
true
true
false
false

func (Evaluable) EvalBool

1
func (e Evaluable) EvalBool(c context.Context, parameter interface{}) (bool, error)

EvalBool将给定的参数评估为一个bool。

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
	"context"
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {
	eval, err := gval.Full().NewEvaluable("1 == x")
	if err != nil {
		fmt.Println(err)
		return
	}

	value, err := eval.EvalBool(context.Background(), map[string]interface{}{"x": 1})
	if err != nil {
		fmt.Println(err)
	}

	if value {
		fmt.Print("yeah")
	}

}

Output:

1
yeah

func (Evaluable) EvalFloat64

1
func (e Evaluable) EvalFloat64(c context.Context, parameter interface{}) (float64, error)

EvalFloat64将给定的参数评估为float64

func (Evaluable) EvalInt

1
func (e Evaluable) EvalInt(c context.Context, parameter interface{}) (int, error)

EvalInt将给定参数评估为一个int

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
	"context"
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {
	eval, err := gval.Full().NewEvaluable("1 + x")
	if err != nil {
		fmt.Println(err)
		return
	}

	value, err := eval.EvalInt(context.Background(), map[string]interface{}{"x": 5})
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
6

func (Evaluable) EvalString

1
func (e Evaluable) EvalString(c context.Context, parameter interface{}) (string, error)

EvalString将给定参数评估为一个字符串

func (Evaluable) IsConst

1
func (e Evaluable) IsConst() bool

IsConst返回Evaluable是否是一个Parser.Const()值

type Evaluables

1
type Evaluables []Evaluable

Evaluables是Evaluable的一个切片。

func (Evaluables) EvalStrings

1
func (evs Evaluables) EvalStrings(c context.Context, parameter interface{}) ([]string, error)

EvalStrings将给定的参数评估为一个字符串切片

type Language

1
2
3
type Language struct {
	// contains filtered or unexported fields
}

Language 是一种表达式语言

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package main

import (
	"context"
	"fmt"

	"github.com/PaesslerAG/gval"
)

func main() {
	lang := gval.NewLanguage(gval.JSON(), gval.Arithmetic(),
		//pipe operator
		gval.PostfixOperator("|", func(c context.Context, p *gval.Parser, pre gval.Evaluable) (gval.Evaluable, error) {
			post, err := p.ParseExpression(c)
			if err != nil {
				return nil, err
			}
			return func(c context.Context, v interface{}) (interface{}, error) {
				v, err := pre(c, v)
				if err != nil {
					return nil, err
				}
				return post(c, v)
			}, nil
		}))

	eval, err := lang.NewEvaluable(`{"foobar": 50} | foobar + 100`)
	if err != nil {
		fmt.Println(err)
	}

	value, err := eval(context.Background(), nil)

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(value)

}

Output:

1
150

func Arithmetic

1
func Arithmetic() Language

Arithmetic包含基数、加(+)、减(-)、除(/)、幂(**)、负(-)和数字顺序(<=、<、>、>=)

Arithmetic运算符期待浮动64操作数。在调用不合适的输入时,它们会尝试将输入转换为float64。它们可以解析字符串并转换任何类型的int或float。

func Base

1
func Base() Language

Base包含等价(==)和不等价(!=), 符号和对变量、常量和函数的一般支持 它包含真、假、(浮点)数字、字符串(““或”)和char(")常量

func Bitmask

1
func Bitmask() Language

Bitmask包含基数、位数和(&)、位数或(|)和位数非(^)。

比特掩码运算符期待浮动64操作数。在调用不合适的输入时,它们会尝试将输入转换为float64。它们可以解析字符串并转换任何类型的int或float。

func Constant

1
func Constant(name string, value interface{}) Language

Constant返回一个具有给定常数的Language

func DefaultExtension

1
func DefaultExtension(ext func(context.Context, *Parser) (Evaluable, error)) Language

DefaultExtension是一种语言,如果没有其他前缀匹配,就会运行给定的函数。

func Full

1
func Full(extensions ...Language) Language

Full是算术、Bitmask、文本、PropositionalLogic和Json的结合。

1
2
3
4
Operator in: a in b is true iff value a is an element of array b
Operator ??: a ?? b returns a if a is not false or nil, otherwise n
Operator ?: a ? b : c returns b if bool a is true, otherwise b
Function Date: Date(a) parses string a. a must match RFC3339, ISO8601, ruby date, or unix date

func Function

1
func Function(name string, function interface{}) Language

Function返回一个具有给定功能的语言。函数对输入类型没有转换。

如果Function返回一个错误,它必须是最后一个返回参数。

如果Function有一个以上的返回参数(没有错误),它将以[]接口{}的形式返回。

func Ident

1
func Ident() Language

Ident包含对变量和函数的支持。

func InfixBoolOperator

1
func InfixBoolOperator(name string, f func(a, b bool) (interface{}, error)) Language

两个bool值的InfixBoolOperator。

func InfixEvalOperator

1
func InfixEvalOperator(name string, f func(a, b Evaluable) (Evaluable, error)) Language

InfixEvalOperator对原始操作数进行操作。因此,它不能与其他操作数类型的运算符结合。

func InfixNumberOperator

1
func InfixNumberOperator(name string, f func(a, b float64) (interface{}, error)) Language

两个数字值的InfixNumberOperator。

func InfixOperator

1
func InfixOperator(name string, f func(a, b interface{}) (interface{}, error)) Language

两个任意值的InfixOperator。

func InfixShortCircuit

1
func InfixShortCircuit(name string, f func(a interface{}) (interface{}, bool)) Language

InfixShortCircuit操作符在左操作数被评估后被调用。

func InfixTextOperator

1
func InfixTextOperator(name string, f func(a, b string) (interface{}, error)) Language

对两个文本值的InfixTextOperator。

func Init

1
func Init(ext func(context.Context, *Parser) (Evaluable, error)) Language

Init是一种不做解析的Language,但在解析开始时调用给定的函数。该函数有责任调用ParseExpression来继续解析。

这个函数可以用来定制解析器的设置,如空白或身份行为。

func JSON

1
func JSON() Language

JSON包含json对象({string:expression,…})和json数组([expression, …])。

func NewLanguage

1
func NewLanguage(bases ...Language) Language

NewLanguage返回给定的Language的组合,作为新的Language。

func Parentheses

1
func Parentheses() Language

Parentheses 包含对圆括号的支持。 .

func PostfixOperator

1
func PostfixOperator(name string, ext func(context.Context, *Parser, Evaluable) (Evaluable, error)) Language

PostfixOperator扩展了一种语言。

func Precedence

1
func Precedence(name string, operatorPrecendence uint8) Language

操作符的优先级。具有更高的operatorPrecedence的操作者被首先评估。

func PrefixExtension

1
func PrefixExtension(r rune, ext func(context.Context, *Parser) (Evaluable, error)) Language

PrefixExtension扩展了一种语言

func PrefixMetaPrefix

1
func PrefixMetaPrefix(r rune, ext func(context.Context, *Parser) (call string, alternative func() (Evaluable, error), err error)) Language

PrefixMetaPrefix chooses a Prefix to be executed

func PrefixOperator

1
func PrefixOperator(name string, e Evaluable) Language

PrefixOperator returns a Language with given prefix

func PropositionalLogic

1
func PropositionalLogic() Language

PropositionalLogic包含base、not(!)、和(&&),或者(||)和Base。

PropositionalLogic运算符期望操作数为bool。在输入不合适的情况下调用时,它们试图将输入转换为bool。0以外的数字和字符串 “TRUE “和 “true “被解释为真。0和字符串 “FALSE “和 “false “被解释为假。

func Text

1
func Text() Language

Text contains base, lexical order on strings (<=,<,>,>=), regex match (=~) and regex not match (!~)

func VariableSelector

1
func VariableSelector(selector func(path Evaluables) Evaluable) Language

VariableSelector返回一个使用给定变量选择器的语言。它必须与使用该变量选择器的语言结合。例如,gval.Base()。

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
	"context"
	"fmt"
	"strings"

	"github.com/PaesslerAG/gval"
)

func main() {
	value, err := gval.Evaluate(`hello.world`,
		"!",
		gval.VariableSelector(func(path gval.Evaluables) gval.Evaluable {
			return func(c context.Context, v interface{}) (interface{}, error) {
				keys, err := path.EvalStrings(c, v)
				if err != nil {
					return nil, err
				}
				return fmt.Sprintf("%s%s", strings.Join(keys, " "), v), nil
			}
		}),
	)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Print(value)

}

Output:

1
hello world!

func (Language) Evaluate

1
func (l Language) Evaluate(expression string, parameter interface{}) (interface{}, error)

Evaluate given parameter with given expression

func (Language) EvaluateWithContext

1
func (l Language) EvaluateWithContext(c context.Context, expression string, parameter interface{}) (interface{}, error)

Evaluate given parameter with given expression using context

func (Language) NewEvaluable

1
func (l Language) NewEvaluable(expression string) (Evaluable, error)

NewEvaluable returns an Evaluable for given expression in the specified language

type Parser

1
2
3
4
type Parser struct {
	Language
	// contains filtered or unexported fields
}

Parser parses expressions in a Language into an Evaluable

func (*Parser) Camouflage

1
func (p*Parser) Camouflage(unit string, expected ...rune)

Camouflage rewind the last Scan(). The Parser holds the camouflage error until the next Scan() Do not call Rewind() on a camouflaged Parser

func (*Parser) Const

1
func (*Parser) Const(value interface{}) Evaluable

Const Evaluable represents given constant

func (*Parser) Expected

1
func (p*Parser) Expected(unit string, expected ...rune) error

Expected returns an error signaling an unexpected Scan() result

func (*Parser) Next

1
func (p*Parser) Next() rune

Next reads and returns the next Unicode character. It returns EOF at the end of the source. Do not call Next() on a camouflaged Parser

func (*Parser) ParseExpression

1
func (p*Parser) ParseExpression(c context.Context) (eval Evaluable, err error)

ParseExpression scans an expression into an Evaluable.

func (*Parser) ParseNextExpression

1
func (p*Parser) ParseNextExpression(c context.Context) (eval Evaluable, err error)

ParseNextExpression scans the expression ignoring following operators

func (*Parser) ParseSublanguage

1
func (p*Parser) ParseSublanguage(c context.Context, l Language) (Evaluable, error)

ParseSublanguage sets the next language for this parser to parse and calls its initialization function, usually ParseExpression.

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
	"context"
	"fmt"

	"github.com/PaesslerAG/gval"
)

func parseSub(ctx context.Context, p *gval.Parser) (gval.Evaluable, error) {
	return p.ParseSublanguage(ctx, subLang)
}

var (
	superLang = gval.NewLanguage(
		gval.PrefixExtension('$', parseSub),
	)
	subLang = gval.NewLanguage(
		gval.Init(func(ctx context.Context, p *gval.Parser) (gval.Evaluable, error) { return p.Const("hello world"), nil }),
	)
)

func main() {
	value, err := superLang.Evaluate("$", nil)

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(value)

}

Output:

1
hello world

func (*Parser) Peek

1
func (p*Parser) Peek() rune

Peek returns the next Unicode character in the source without advancing the scanner. It returns EOF if the scanner’s position is at the last character of the source. Do not call Peek() on a camouflaged Parser

func (*Parser) Scan

1
func (p*Parser) Scan() rune

Scan reads the next token or Unicode character from source and returns it. It only recognizes tokens t for which the respective Mode bit (1«-t) is set. It returns scanner.EOF at the end of the source.

func (*Parser) SetIsIdentRuneFunc

1
func (p*Parser) SetIsIdentRuneFunc(fn func(ch rune, i int) bool)

SetIsIdentRuneFunc sets the function that matches ident characters in the underlying scanner.

func (*Parser) SetMode

func (p*Parser) SetMode(mode uint) SetMode sets the tokens that the underlying scanner will match.

func (*Parser) SetWhitespace

1
func (p*Parser) SetWhitespace(chars ...rune)

SetWhitespace sets the behavior of the whitespace matcher. The given characters must be less than or equal to 0x20 (’ ‘).

func (*Parser) TokenText

1
func (p*Parser) TokenText() string

TokenText returns the string corresponding to the most recently scanned token. Valid after calling Scan().

func (*Parser) Var

1
func (p*Parser) Var(path ...Evaluable) Evaluable

Var Evaluable represents value at given path. It supports with default language VariableSelector:

1
2
3
4
5
6
7
	map[interface{}]interface{},
	map[string]interface{} and
	[]interface{} and via reflect
	struct fields,
	struct methods,
	slices and
 map with int or string key.

type Selector

1
2
3
type Selector interface {
	SelectGVal(c context.Context, key string) (interface{}, error)
}

Selector allows for custom variable selection from structs

Return value is again handled with variable() until end of the given path

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
	"context"
	"fmt"

	"github.com/PaesslerAG/gval"
)

type exampleCustomSelector struct{ hidden string }

func (s *exampleCustomSelector) SelectGVal(ctx context.Context, k string) (interface{}, error) {
	if k == "hidden" {
		return s.hidden, nil
	}

	return nil, nil
}

func main() {
	lang := gval.Base()
	value, err := lang.Evaluate(
		"myStruct.hidden",
		map[string]interface{}{"myStruct": &exampleCustomSelector{hidden: "hello world"}},
	)

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(value)

}

Output:

1
hello world