Documentation ¶
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Compile ¶ added in v1.9.0
Compile parses and compiles given input expression to bytecode program.
Example ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func main() { env := map[string]interface{}{ "foo": 1, "bar": 99, } program, err := jsexpr.Compile("foo in 1..99 and bar in 1..99", jsexpr.TypeCheck(env)) if err != nil { fmt.Printf("%v", err) return } output, err := jsexpr.Run(program, env) if err != nil { fmt.Printf("%v", err) return } fmt.Printf("%v", output) }
Output: true
func Eval ¶
Eval parses, compiles and runs given input.
Example ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func main() { output, err := jsexpr.Eval("greet + name", map[string]interface{}{ "greet": "Hello, ", "name": "world!", }) if err != nil { fmt.Printf("err: %v", err) return } fmt.Printf("%v", output) }
Output: Hello, world!
Example (Runtime_error) ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func main() { _, err := jsexpr.Eval(`map(1..3, {1 / (# - 3)})`, nil) fmt.Print(err) }
Output: runtime error: integer divide by zero (1:14) | map(1..3, {1 / (# - 3)}) | .............^
Types ¶
type Option ¶ added in v1.9.0
Option for configuring config.
func AllowUndefinedVariables ¶ added in v1.9.0
func AllowUndefinedVariables() Option
AllowUndefinedVariables allows to use undefined variables inside expressions. This can be used with expr.Env option to partially define a few variables. Note what this option is only works in map environment are used, otherwise runtime.fetch will panic as there is no way to get missing field zero value.
Example ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func main() { code := `name == nil ? "Hello, world!" : sprintf("Hello, %v!", name)` env := map[string]interface{}{ "sprintf": fmt.Sprintf, } options := []jsexpr.Option{ jsexpr.TypeCheck(env), jsexpr.AllowUndefinedVariables(), // Allow to use undefined variables. } program, err := jsexpr.Compile(code, options...) if err != nil { fmt.Printf("%v", err) return } output, err := jsexpr.Run(program, env) if err != nil { fmt.Printf("%v", err) return } fmt.Printf("%v\n", output) env["name"] = "you" // Define variables later on. output, err = jsexpr.Run(program, env) if err != nil { fmt.Printf("%v", err) return } fmt.Printf("%v\n", output) }
Output: Hello, world! Hello, you!
func AsBool ¶ added in v1.9.0
func AsBool() Option
AsBool tells the compiler to expect boolean result.
Example ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func main() { env := map[string]int{ "foo": 0, } program, err := jsexpr.Compile("foo >= 0", jsexpr.TypeCheck(env), jsexpr.AsBool()) if err != nil { fmt.Printf("%v", err) return } output, err := jsexpr.Run(program, env) if err != nil { fmt.Printf("%v", err) return } fmt.Printf("%v", output.(bool)) }
Output: true
Example (Error) ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func main() { env := map[string]interface{}{ "foo": 0, } _, err := jsexpr.Compile("foo + 42", jsexpr.TypeCheck(env), jsexpr.AsBool()) fmt.Printf("%v", err) }
Output: expected bool, but got int
func AsFloat64 ¶ added in v1.9.0
func AsFloat64() Option
AsFloat64 tells the compiler to expect float64 result.
Example ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func main() { program, err := jsexpr.Compile("42", jsexpr.AsFloat64()) if err != nil { fmt.Printf("%v", err) return } output, err := jsexpr.Run(program, nil) if err != nil { fmt.Printf("%v", err) return } fmt.Printf("%v", output.(float64)) }
Output: 42
Example (Error) ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func main() { _, err := jsexpr.Compile(`!!true`, jsexpr.AsFloat64()) fmt.Printf("%v", err) }
Output: expected float64, but got bool
func AsInt64 ¶ added in v1.9.0
func AsInt64() Option
AsInt64 tells the compiler to expect int64 result.
Example ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func main() { env := map[string]interface{}{ "rating": 5.5, } program, err := jsexpr.Compile("rating", jsexpr.TypeCheck(env), jsexpr.AsInt64()) if err != nil { fmt.Printf("%v", err) return } output, err := jsexpr.Run(program, env) if err != nil { fmt.Printf("%v", err) return } fmt.Printf("%v", output.(int64)) }
Output: 5
func ConstExpr ¶ added in v1.9.0
ConstExpr defines func expression as constant. If all argument to this function is constants, then it can be replaced by result of this func call on compile step.
Example ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" ) func fib(n int) int { if n <= 1 { return n } return fib(n-1) + fib(n-2) } func main() { code := `[fib(5), fib(3+3), fib(dyn)]` env := map[string]interface{}{ "fib": fib, "dyn": 0, } options := []jsexpr.Option{ jsexpr.TypeCheck(env), jsexpr.ConstExpr("fib"), // Mark fib func as constant expression. } program, err := jsexpr.Compile(code, options...) if err != nil { fmt.Printf("%v", err) return } // Only fib(5) and fib(6) calculated on Compile, fib(dyn) can be called at runtime. env["dyn"] = 7 output, err := jsexpr.Run(program, env) if err != nil { fmt.Printf("%v", err) return } fmt.Printf("%v\n", output) }
Output: [5 8 13]
func Operator ¶ added in v1.9.0
Operator allows to override binary operator with function.
Example ¶
package main import ( "fmt" "time" "github.com/byte-power/jsexpr" ) func main() { code := ` now() > createdAt && (now() - createdAt).hours() > 24 ` type Env struct { CreatedAt time.Time `jsexpr:"createdAt"` Now func() time.Time `jsexpr:"now"` Sub func(a, b time.Time) time.Duration `jsexpr:"sub"` After func(a, b time.Time) bool `jsexpr:"after"` } options := []jsexpr.Option{ jsexpr.TypeCheck(Env{}), jsexpr.Operator(">", "after"), jsexpr.Operator("-", "sub"), } program, err := jsexpr.Compile(code, options...) if err != nil { fmt.Printf("%v", err) return } env := Env{ CreatedAt: time.Date(2018, 7, 14, 0, 0, 0, 0, time.UTC), Now: func() time.Time { return time.Now() }, Sub: func(a, b time.Time) time.Duration { return a.Sub(b) }, After: func(a, b time.Time) bool { return a.After(b) }, } output, err := jsexpr.Run(program, env) if err != nil { fmt.Printf("%v", err) return } fmt.Printf("%v", output) }
Output: true
func Patch ¶ added in v1.9.0
Patch adds visitor to list of visitors what will be applied before compiling AST to bytecode.
Example ¶
package main import ( "fmt" "github.com/byte-power/jsexpr" "github.com/byte-power/jsexpr/ast" ) func main() { /* type patcher struct{} func (p *patcher) Enter(_ *ast.Node) {} func (p *patcher) Exit(node *ast.Node) { switch n := (*node).(type) { case *ast.PropertyNode: ast.Patch(node, &ast.FunctionNode{ Name: "get", Arguments: []ast.Node{n.Node, &ast.StringNode{Value: n.Property}}, }) } } */ program, err := jsexpr.Compile( `greet.you.world + "!"`, jsexpr.Patch(&patcher{}), ) if err != nil { fmt.Printf("%v", err) return } env := map[string]interface{}{ "greet": "Hello", "get": func(a, b string) string { return a + ", " + b }, } output, err := jsexpr.Run(program, env) if err != nil { fmt.Printf("%v", err) return } fmt.Printf("%v", output) // Output : Hello, you, world! } type patcher struct{} func (p *patcher) Enter(_ *ast.Node) {} func (p *patcher) Exit(node *ast.Node) { switch n := (*node).(type) { case *ast.PropertyNode: ast.Patch(node, &ast.FunctionNode{ Name: "get", Arguments: []ast.Node{n.Node, &ast.StringNode{Value: n.Property}}, }) } }
Output:
func TypeCheck ¶ added in v1.9.0
func TypeCheck(env interface{}) Option
Typecheck specifies expected input of env for type checks. If struct is passed, all fields will be treated as variables, as well as all fields of embedded structs and struct itself. If map is passed, all items will be treated as variables. Methods defined on this type will be available as functions.