# Getting Started

**Expr** is a simple, fast and extensible expression language for Go. It is
designed to be easy to use and integrate into your Go application. Let's delve
deeper into its core features:

- **Memory safe** - Designed to prevent vulnerabilities like buffer overflows and memory leaks.
- **Type safe** - Enforces strict type rules, aligning with Go's type system.
- **Terminating** - Ensures every expression evaluation cannot loop indefinitely.
- **Side effects free** - Evaluations won't modify global states or variables.

Let's start with a simple example:

```go
program, err := expr.Compile(`2 + 2`)
if err != nil {
    panic(err)
}

output, err := expr.Run(program, nil)
if err != nil {
    panic(err)
}

fmt.Print(output) // 4
```

Expr compiles the expression `2 + 2` into a bytecode program. Then we run
the program and get the output.

:::tip
In performance-critical applications, you can reuse the compiled program. Compiled programs are safe for concurrent use.
**Compile once** and run **multiple** times.
:::

The `expr.Compile` function returns a `*vm.Program` and an error. The `expr.Run` function takes a program and an
environment. The environment is a map of variables that can be used in the expression. In this example, we use `nil` as
an environment because we don't need any variables.


Now let's pass some variables to the expression:

```go
env := map[string]any{
    "foo": 100,
    "bar": 200,
}

program, err := expr.Compile(`foo + bar`, expr.Env(env))
if err != nil {
    panic(err)
}

output, err := expr.Run(program, env)
if err != nil {
    panic(err)
}

fmt.Print(output) // 300
```

Why do we need to pass the environment to the `expr.Compile` function? Expr can be used as a type-safe language. 
Expr can infer the type of the expression and check it against the environment. 

Here is an example:

```go
env := map[string]any{
    "name": "Anton",
    "age": 35,
}

program, err := expr.Compile(`name + age`, expr.Env(env))
if err != nil {
    // highlight-next-line
    panic(err) // Will panic with "invalid operation: string + int"
}
```

Expr can work with any Go types:

```go
env := map[string]any{
    "greet":   "Hello, %v!",
    "names":   []string{"world", "you"},
    "sprintf": fmt.Sprintf,
}

program, err := expr.Compile(`sprintf(greet, names[0])`, expr.Env(env))
if err != nil {
    panic(err)
}

output, err := expr.Run(program, env)
if err != nil {
    panic(err)
}

fmt.Print(output) // Hello, world!
```

Also, Expr can use a struct as an environment. Here is an example:

```go
type Env struct {
    Posts []Post `expr:"posts"`
}

func (Env) Format(t time.Time) string { // Methods defined on the struct become functions. 
    return t.Format(time.RFC822) 
}

type Post struct {
    Body string
    Date time.Time
}

func main() {
    code := `map(posts, Format(.Date) + ": " + .Body)`
    
    program, err := expr.Compile(code, expr.Env(Env{})) // Pass the struct as an environment.
    if err != nil {
        panic(err)
    }

    env := Env{
        Posts: []Post{
            {"Oh My God!", time.Now()}, 
            {"How you doin?", time.Now()}, 
            {"Could I be wearing any more clothes?", time.Now()},
        },
    }

    output, err := expr.Run(program, env)
    if err != nil {
        panic(err)
    }

    fmt.Print(output)
}
```

The compiled program can be reused between runs.

```go
type Env struct {
    X int
    Y int
}

program, err := expr.Compile(`X + Y`, expr.Env(Env{}))
if err != nil {
    panic(err)
}

output, err := expr.Run(program, Env{1, 2})
if err != nil {
    panic(err)
}

fmt.Print(output) // 3

output, err = expr.Run(program, Env{3, 4})
if err != nil {
    panic(err)
}

fmt.Print(output) // 7
```

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