Go Runtime
Module: github.com/xpr-lang/xpr-go · GitHub · v0.5.0
Install
bash
go get github.com/xpr-lang/xpr-goRequires Go 1.21+. Zero runtime dependencies.
API
xpr.New()
Creates a new XPR engine instance.
go
import xpr "github.com/xpr-lang/xpr-go"
engine := xpr.New()engine.Evaluate(expression string, context map[string]any) (any, error)
Evaluates an XPR expression string against an optional context map. Returns the result value or an error.
go
result, err := engine.Evaluate("1 + 2", nil)
// result → float64(3)
result, err = engine.Evaluate(
`user["name"] ?? "anonymous"`,
map[string]any{"user": map[string]any{"name": nil}},
)
// result → "anonymous"
result, err = engine.Evaluate("[1,2,3].map(x => x * 2)", nil)
// result → []any{float64(2), float64(4), float64(6)}
result, err = engine.Evaluate(
"items.filter(x => x.active).map(x => x.name)",
map[string]any{
"items": []any{
map[string]any{"name": "a", "active": true},
map[string]any{"name": "b", "active": false},
},
},
)
// result → []any{"a"}engine.AddFunction(name string, fn func(...any) (any, error))
Registers a custom function that can be called from expressions.
go
engine.AddFunction("slugify", func(args ...any) (any, error) {
s := strings.ToLower(fmt.Sprintf("%v", args[0]))
return strings.ReplaceAll(s, " ", "-"), nil
})
result, _ := engine.Evaluate(
"slugify(product.name)",
map[string]any{"product": map[string]any{"name": "Hello World"}},
)
// result → "hello-world"Type Mapping
| XPR type | Go type |
|---|---|
| number | float64 |
| string | string |
| boolean | bool |
| null | nil |
| array | []interface{} |
| object | map[string]interface{} |
| function | internal xprFunc |
Error Handling
All errors are returned as the second return value. There is no panic.
go
result, err := engine.Evaluate("1 / 0", nil)
if err != nil {
fmt.Println(err) // "division by zero"
}v0.2 Features
Let Bindings
go
result, _ := engine.Evaluate("let x = 1; let y = x + 1; y", nil)
// result → float64(2)
result, _ = engine.Evaluate("let f = (x) => x * 2; f(5)", nil)
// result → float64(10)
result, _ = engine.Evaluate(
"let items = [1,2,3,4,5]; items.filter(x => x > 2).map(x => x * 10)",
nil,
)
// result → []any{float64(30), float64(40), float64(50)}Spread Operator
go
result, _ := engine.Evaluate("[...[1,2], ...[3,4]]", nil)
// result → []any{float64(1), float64(2), float64(3), float64(4)}
result, _ = engine.Evaluate("{...defaults, ...overrides}", map[string]any{
"defaults": map[string]any{"color": "blue", "size": float64(10)},
"overrides": map[string]any{"color": "red"},
})
// result → map[string]any{"color": "red", "size": float64(10)}New Array Methods
go
engine.Evaluate("[1,2,3].includes(2)", nil) // → true
engine.Evaluate("[1,2,3].indexOf(2)", nil) // → float64(1)
engine.Evaluate("[1,2,3,4,5].slice(1, 3)", nil) // → []any{float64(2), float64(3)}
engine.Evaluate(`[1,2,3].join(", ")`, nil) // → "1, 2, 3"
engine.Evaluate("[1,2].concat([3,4])", nil) // → []any{1,2,3,4}
engine.Evaluate("[[1,2],[3,4]].flat()", nil) // → []any{1,2,3,4}
engine.Evaluate("[1,2,1,3].unique()", nil) // → []any{1,2,3}
engine.Evaluate("[1,2,3].zip([4,5,6])", nil) // → []any{[]any{1,4}, []any{2,5}, []any{3,6}}
engine.Evaluate("[1,2,3,4,5].chunk(2)", nil) // → []any{[]any{1,2}, []any{3,4}, []any{5}}
engine.Evaluate(`[1,2,3].groupBy(x => x > 1 ? "big" : "small")`, nil)
// → map[string]any{"big": []any{2,3}, "small": []any{1}}New String Methods
go
engine.Evaluate(`"hello".indexOf("ll")`, nil) // → float64(2)
engine.Evaluate(`"ab".repeat(3)`, nil) // → "ababab"
engine.Evaluate(`" hi ".trimStart()`, nil) // → "hi "
engine.Evaluate(`" hi ".trimEnd()`, nil) // → " hi"
engine.Evaluate(`"hello".charAt(1)`, nil) // → "e"
engine.Evaluate(`"42".padStart(5, "0")`, nil) // → "00042"
engine.Evaluate(`"hi".padEnd(5, ".")`, nil) // → "hi..."New Object Methods
go
engine.Evaluate(`{"b": 2, "a": 1}.entries()`, nil) // → []any{[]any{"a",1}, []any{"b",2}}
engine.Evaluate(`{"a": 1}.has("a")`, nil) // → true
engine.Evaluate(`{"a": 1}.has("b")`, nil) // → falserange() Function
go
engine.Evaluate("range(5)", nil) // → []any{0,1,2,3,4}
engine.Evaluate("range(1, 5)", nil) // → []any{1,2,3,4}
engine.Evaluate("range(0, 10, 2)", nil) // → []any{0,2,4,6,8}
engine.Evaluate("range(5, 0, -1)", nil) // → []any{5,4,3,2,1}v0.3 Features
Date/Time
Dates are epoch milliseconds (UTC only). Numbers return as float64.
go
result, _ := engine.Evaluate(`formatDate(now(), "yyyy-MM-dd")`, nil)
// → "2026-03-15"
result, _ = engine.Evaluate(`dateDiff(parseDate("2024-01-01T00:00:00Z"), now(), "days")`, nil)
// → float64(439)
result, _ = engine.Evaluate(`dateAdd(parseDate("2024-01-31T00:00:00Z"), 1, "months")`, nil)
// → float64(1709337600000)Regex Functions
go
result, _ := engine.Evaluate(`matches("hello 42", "\\d+")`, nil) // → true
result, _ = engine.Evaluate(`match("order-123", "\\d+")`, nil) // → "123"
result, _ = engine.Evaluate(`matchAll("a1b2c3", "\\d")`, nil) // → []any{"1","2","3"}
result, _ = engine.Evaluate(`replacePattern("hello world","o","0")`, nil) // → "hell0 w0rld"Negative Indexing and Spread in Calls
go
result, _ := engine.Evaluate("[1,2,3][-1]", nil) // → float64(3)
result, _ = engine.Evaluate("max(...[1, 5, 3, 2])", nil) // → float64(5)v0.4 Features
Destructuring
go
result, _ := engine.Evaluate("let {name, age} = user; name",
map[string]any{"user": map[string]any{"name": "Alice", "age": 30}})
// → "Alice"
result, _ = engine.Evaluate("let [head, ...tail] = items; tail",
map[string]any{"items": []any{1, 2, 3}})
// → []any{float64(2), float64(3)}Regex Literals
go
result, _ := engine.Evaluate(`/\d+/.test("order-123")`, nil) // → true
result, _ = engine.Evaluate(`"2024-01-15".match(/\d{4}/)`, nil) // → "2024"
result, _ = engine.Evaluate(`"hello world".replace(/o/, "0")`, nil) // → "hell0 w0rld"v0.5 Features
Math Functions and Constants
go
result, _ := engine.Evaluate("sqrt(16)", nil) // → float64(4)
result, _ = engine.Evaluate("log(E)", nil) // → float64(1)
result, _ = engine.Evaluate("pow(2, 10)", nil) // → float64(1024)
result, _ = engine.Evaluate("PI * pow(5, 2)", nil) // → float64(78.539...)
result, _ = engine.Evaluate("sign(-7)", nil) // → float64(-1)
result, _ = engine.Evaluate("trunc(3.9)", nil) // → float64(3)Type Predicates
go
result, _ := engine.Evaluate("isNumber(42)", nil) // → true
result, _ = engine.Evaluate("isArray([1,2])", nil) // → true
result, _ = engine.Evaluate("isObject([1,2])", nil) // → false
result, _ = engine.Evaluate("isNull(null)", nil) // → trueNew Array Methods
go
result, _ := engine.Evaluate("[3,null,1,null,5].compact().sortBy(x => x)", nil)
// → []any{float64(1), float64(3), float64(5)}
result, _ = engine.Evaluate("[1,2,3,4].sum()", nil) // → float64(10)
result, _ = engine.Evaluate("[1,2,3,4].avg()", nil) // → float64(2.5)
result, _ = engine.Evaluate("[3,1,2].first()", nil) // → float64(3)
result, _ = engine.Evaluate("[1,2,3].count(x => x > 1)", nil) // → float64(2)fromEntries, str.split(/regex/), Rest Parameters
go
result, _ := engine.Evaluate(`fromEntries([["a", 1], ["b", 2]])`, nil)
// → map[string]any{"a": float64(1), "b": float64(2)}
result, _ = engine.Evaluate(`"a1b2c3".split(/\d+/)`, nil)
// → []any{"a", "b", "c"}