Skip to content

Commit 0f99b19

Browse files
committedMar 17, 2025··
Update docs
1 parent 8419ba4 commit 0f99b19

6 files changed

+69
-35
lines changed
 

‎docs/configuration.md

+14-15
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ Usually, the return type of expression is anything. But we can instruct type che
66
expression.
77
For example, in filter expressions, we expect the return type to be a boolean.
88

9-
```go
9+
```go
1010
program, err := expr.Compile(code, expr.AsBool())
1111
if err != nil {
12-
panic(err)
12+
panic(err)
1313
}
1414

1515
output, err := expr.Run(program, env)
1616
if err != nil {
17-
panic(err)
17+
panic(err)
1818
}
1919

2020
ok := output.(bool) // It is safe to assert the output to bool, if the expression is type checked as bool.
@@ -82,6 +82,9 @@ Function `expr.WithContext()` takes the name of context variable. The context va
8282
```go
8383
env := map[string]any{
8484
"ctx": context.Background(),
85+
"customFunc": func(ctx context.Context, a int) int {
86+
return a
87+
},
8588
}
8689

8790
program, err := expr.Compile(code, expr.Env(env), expr.WithContext("ctx"))
@@ -116,20 +119,16 @@ fib(12+12) // will be transformed to 267914296 during the compilation
116119
fib(x) // will **not** be transformed and will be evaluated at runtime
117120
```
118121

119-
## Options
122+
## Timezone
120123

121-
Compiler options can be defined as an array:
124+
By default, the timezone is set to `time.Local`. We can change the timezone via the [`Timezone`](https://pkg.go.dev/github.com/expr-lang/expr#Timezone) option.
122125

123126
```go
124-
options := []expr.Option{
125-
expr.Env(Env{})
126-
expr.AsInt(),
127-
expr.WarnOnAny(),
128-
expr.WithContext("ctx"),
129-
expr.ConstExpr("fib"),
130-
}
131-
132-
program, err := expr.Compile(code, options...)
127+
program, err := expr.Compile(code, expr.Timezone(time.UTC))
133128
```
134129

135-
Full list of available options can be found in the [pkg.go.dev](https://pkg.go.dev/github.com/expr-lang/expr#Option) documentation.
130+
The timezone is used for the following functions:
131+
```expr
132+
date("2024-11-23 12:00:00") // parses the date in the specified timezone
133+
now() // returns the current time in the specified timezone
134+
```

‎docs/environment.md

+18-2
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,28 @@ is the value's type.
8484
env := map[string]any{
8585
"object": map[string]any{
8686
"field": 42,
87-
},
87+
},
88+
"struct": struct {
89+
Field int `expr:"field"`
90+
}{42},
8891
}
8992
```
9093

9194
Expr will infer the type of the `object` variable as `map[string]any`.
95+
Accessing fields of the `object` and `struct` variables will return the following results.
9296

93-
By default, Expr will return an error if unknown variables are used in the expression.
97+
```expr
98+
object.field // 42
99+
object.unknown // nil (no error)
100+
101+
struct.field // 42
102+
struct.unknown // error (unknown field)
103+
104+
foobar // error (unknown variable)
105+
```
94106

107+
:::note
108+
The `foobar` variable is not defined in the environment.
109+
By default, Expr will return an error if unknown variables are used in the expression.
95110
You can disable this behavior by passing [`AllowUndefinedVariables`](https://pkg.go.dev/github.com/expr-lang/expr#AllowUndefinedVariables) option to the compiler.
111+
:::

‎docs/functions.md

+3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ atoi := expr.Function(
4949
func(params ...any) (any, error) {
5050
return strconv.Atoi(params[0].(string))
5151
},
52+
// highlight-next-line
5253
new(func(string) int),
5354
)
5455
```
@@ -80,7 +81,9 @@ toInt := expr.Function(
8081
}
8182
return nil, fmt.Errorf("invalid type")
8283
},
84+
// highlight-start
8385
new(func(float64) int),
8486
new(func(string) int),
87+
// highlight-end
8588
)
8689
```

‎docs/getting-started.md

+6-10
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ env := map[string]any{
7272

7373
program, err := expr.Compile(`name + age`, expr.Env(env))
7474
if err != nil {
75+
// highlight-next-line
7576
panic(err) // Will panic with "invalid operation: string + int"
7677
}
7778
```
@@ -85,9 +86,7 @@ env := map[string]any{
8586
"sprintf": fmt.Sprintf,
8687
}
8788

88-
code := `sprintf(greet, names[0])`
89-
90-
program, err := expr.Compile(code, expr.Env(env))
89+
program, err := expr.Compile(`sprintf(greet, names[0])`, expr.Env(env))
9190
if err != nil {
9291
panic(err)
9392
}
@@ -100,17 +99,14 @@ if err != nil {
10099
fmt.Print(output) // Hello, world!
101100
```
102101

103-
Also, Expr can use a struct as an environment. Methods defined on the struct become functions.
104-
The struct fields can be renamed with the `expr` tag.
105-
106-
Here is an example:
102+
Also, Expr can use a struct as an environment. Here is an example:
107103

108104
```go
109105
type Env struct {
110106
Posts []Post `expr:"posts"`
111107
}
112108

113-
func (Env) Format(t time.Time) string {
109+
func (Env) Format(t time.Time) string { // Methods defined on the struct become functions.
114110
return t.Format(time.RFC822)
115111
}
116112

@@ -122,7 +118,7 @@ type Post struct {
122118
func main() {
123119
code := `map(posts, Format(.Date) + ": " + .Body)`
124120

125-
program, err := expr.Compile(code, expr.Env(Env{}))
121+
program, err := expr.Compile(code, expr.Env(Env{})) // Pass the struct as an environment.
126122
if err != nil {
127123
panic(err)
128124
}
@@ -172,7 +168,7 @@ if err != nil {
172168
fmt.Print(output) // 7
173169
```
174170

175-
:::tip
171+
:::info Eval = Compile + Run
176172
For one-off expressions, you can use the `expr.Eval` function. It compiles and runs the expression in one step.
177173
```go
178174
output, err := expr.Eval(`2 + 2`, env)

‎docs/patch.md

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Patch
22

33
Sometimes it may be necessary to modify an expression before the compilation.
4-
Expr provides a powerful mechanism to modify the expression using
5-
the [`Patch`](https://pkg.go.dev/github.com/expr-lang/expr#Patch) option.
4+
For example, you may want to replace a variable with a constant, transform an expression into a function call,
5+
or even modify the expression to use a different operator.
66

77
## Simple example
88

@@ -19,12 +19,15 @@ type FooPatcher struct{}
1919

2020
func (FooPatcher) Visit(node *ast.Node) {
2121
if n, ok := (*node).(*ast.IdentifierNode); ok && n.Value == "foo" {
22+
// highlight-next-line
2223
ast.Patch(node, &ast.IntegerNode{Value: 42})
2324
}
2425
}
2526
```
2627

27-
Now we can use the `FooPatcher` to modify the expression:
28+
We used the [ast.Patch](https://pkg.go.dev/github.com/expr-lang/expr/ast#Patch) function to replace the `foo` variable with an integer node.
29+
30+
Now we can use the `FooPatcher` to modify the expression on compilation via the [expr.Patch](https://pkg.go.dev/github.com/expr-lang/expr#Patch) option:
2831

2932
```go
3033
program, err := expr.Compile(`foo + bar`, expr.Patch(FooPatcher{}))
@@ -61,17 +64,24 @@ var decimalType = reflect.TypeOf(Decimal{})
6164

6265
func (DecimalPatcher) Visit(node *ast.Node) {
6366
if n, ok := (*node).(*ast.BinaryNode); ok && n.Operator == "+" {
67+
6468
if !n.Left.Type().AssignableTo(decimalType) {
6569
return // skip, left side is not a Decimal
6670
}
71+
6772
if !n.Right.Type().AssignableTo(decimalType) {
6873
return // skip, right side is not a Decimal
6974
}
70-
ast.Patch(node, &ast.CallNode{
75+
76+
// highlight-start
77+
callNode := &ast.CallNode{
7178
Callee: &ast.IdentifierNode{Value: "add"},
7279
Arguments: []ast.Node{n.Left, n.Right},
73-
})
74-
(*node).SetType(decimalType) // set the type, so patcher can be used multiple times
80+
}
81+
ast.Patch(node, callNode)
82+
// highlight-end
83+
84+
(*node).SetType(decimalType) // set the type, so the patcher can be applied recursively
7585
}
7686
}
7787
```
@@ -97,6 +107,7 @@ env := map[string]interface{}{
97107

98108
code := `a + b + c`
99109

110+
// highlight-next-line
100111
program, err := expr.Compile(code, expr.Env(env), expr.Patch(DecimalPatcher{}))
101112
if err != nil {
102113
panic(err)

‎docs/visitor.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# Visitor
22

3-
Expr provides an interface to traverse the AST of the expression before the compilation.
3+
Expr provides an interface to traverse the <span title="Abstract Syntax Tree" style={{borderBottom: "1px dotted currentColor"}}>AST</span> of the expression before the compilation.
44
The `Visitor` interface allows you to collect information about the expression, modify the expression, or even generate
55
a new expression.
66

77
Let's start with an [ast.Visitor](https://pkg.go.dev/github.com/expr-lang/expr/ast#Visitor) implementation which will
8-
collect all variables used in the expression:
8+
collect all variables used in the expression.
9+
10+
Visitor must implement a single method `Visit(*ast.Node)`, which will be called for each node in the AST.
911

1012
```go
1113
type Visitor struct {
@@ -30,6 +32,7 @@ if err != nil {
3032
}
3133

3234
v := &Visitor{}
35+
// highlight-next-line
3336
ast.Walk(&tree.Node, v)
3437

3538
fmt.Println(v.Identifiers) // [foo, bar]
@@ -40,6 +43,12 @@ fmt.Println(v.Identifiers) // [foo, bar]
4043
Although it is possible to access the AST of compiled program, it may be already be modified by patchers, optimizers, etc.
4144

4245
```go
46+
program, err := expr.Compile(`foo + bar`)
47+
if err != nil {
48+
panic(err)
49+
}
50+
51+
// highlight-next-line
4352
node := program.Node()
4453

4554
v := &Visitor{}

0 commit comments

Comments
 (0)
Please sign in to comment.