fasteval

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

README

fasteval

Go Reference

fasteval evaluates expressions and renders raw string templates in Go. It supports native Go numeric types, typed generic results, collection values, ordinary Go functions, and a fast path for plain template identifiers.

The module requires Go 1.26.0 or newer.

go get go.dw1.io/fasteval

Documentation

Expressions

Call Compile once, then use Expression.Eval concurrently:

expression, err := fasteval.Compile("requests >= 100 && success / requests >= 0.9")
if err != nil {
	return err
}

value, err := expression.Eval(ctx, map[string]any{
	"requests": 100.0,
	"success":  95.0,
})

Use CompileAs[T] when the result shape is known, then evaluate the returned program with Program.Eval:

type Result struct {
	Name   string `json:"name"`
	Scores []int8 `json:"scores"`
}

program, err := fasteval.CompileAs[Result](
	"{'name': name, 'scores': [1, 2, 3]}",
)
result, err := program.Eval(ctx, map[string]any{"name": "Ada"})

Typed conversion is recursive and lossless. It rejects integer truncation, floating-point precision loss, and implicit string-to-number conversion. Explicit numeric conversion functions can parse strings.

Functions and lazy variables

Registered functions can be fixed or variadic. They return a value, optionally followed by an error. A leading context.Context is injected and does not count toward the expression's arity.

Create a Compiler with NewCompiler and register functions with WithFunction:

compiler, err := fasteval.NewCompiler(
	fasteval.WithFunction("isAdult", func(age int) bool { return age >= 18 }),
)
expression, err := compiler.Compile("filter(ages, isAdult)")

Expressions can also call exported methods and Go function values from the variables map or resolver. Templates with custom functions must use Compiler.CompileTemplate; package-level CompileTemplate uses the default builtin-only compiler.

WithResolver supplies a lazy fallback after direct map lookup. Its found result distinguishes an explicit nil value from an unknown variable.

Builtin names are reserved and cannot be registered again. Function calls and higher-order arguments resolve through a separate callable namespace, while a data variable with the same name remains available elsewhere. Compilers and compiled artifacts are immutable and safe for concurrent use. The package has no hidden compile cache or mutable global function registry.

Templates

Every template tag contains an expression. Plain identifiers use a direct lookup and formatting path.

template, err := fasteval.CompileTemplate(
	"Hello {{name}}: {{score >= 80 ? 'pass' : 'fail'}}",
)
rendered, err := template.Render(ctx, map[string]any{
	"name":  "Ada",
	"score": 90,
})

The default delimiters are {{ and }}. Use WithDelimiters to set any distinct, non-empty pair. An end delimiter inside a quoted string or nested expression construct does not close the tag.

Template.Execute streams to an io.Writer. Template.Render returns a string. If an expression, formatter, or write fails, both methods return the output completed before the error.

Template output is raw. The package does not know whether the destination is HTML, SQL, a shell command, or another interpreter. Apply the correct context-specific encoder before using untrusted values in those contexts.

Language

The language provides these operator groups:

  • arithmetic: +, -, *, /, %, and **
  • bitwise: &, |, ^, ~, <<, and >>
  • comparison: ==, !=, >, >=, <, <=, =~, !~, and in
  • logical and conditional: !, &&, ||, ??, and ? :

Values follow these rules:

  • Standard Go numeric types are preserved. Defined numeric types normalize to their underlying type at numeric-consumer and outward-result boundaries, except time.Duration. Transparent access and collection paths preserve the defined type while methods or exact map keys still need it.
  • Untyped Go-like literals adapt to their operand, function parameter, map key, or typed-result context.
  • Concrete mixed-type arithmetic requires explicit conversion. Integer arithmetic is checked for overflow and division errors.
  • Numeric equality compares different numeric types only when the comparison is exact. NaN is never equal. Complex values cannot be ordered.
  • Lists use [a, b]. Because [escaped variable] remains compatible, a singleton list requires a trailing comma: [value,].
  • Maps use {key: value} and accept any Go-comparable key. Map lookup uses exact Go key identity. Map iteration order is unspecified.
  • Strings are indexed as UTF-8 bytes. Slicing and range syntax are not part of the language.
  • Field access, map-dot access, exported methods, indexing, ?., and ?[ are supported. Optional access suppresses only a nil receiver; missing members and out-of-range indexes remain errors.
  • Only nil is a null literal. Dates and durations use functions rather than guessed string-literal formats.

See the language reference for literal syntax, exact precedence, access and call behavior, result normalization, template formatting, and fixed safety limits.

Builtins

All shipped builtins are enabled:

  • collections: all, any, one, none, map, filter, find, findIndex, findLast, findLastIndex, groupBy, count, concat, flatten, uniq, join, reduce, sum, mean, median, first, last, take, reverse, sort, and sortBy
  • maps and pairs: keys, values, toPairs, and fromPairs
  • strings: trim, trimPrefix, trimSuffix, upper, lower, split, splitAfter, replace, repeat, indexOf, lastIndexOf, hasPrefix, and hasSuffix
  • numeric: min, max, abs, ceil, floor, round, every standard Go numeric conversion, real, imag, complex, and conj
  • bitwise: bitand, bitor, bitxor, bitnand, bitnot, bitshl, bitshr, and bitushr
  • time: now, duration, date, and timezone
  • conversion and encoding: type, string, toJSON, fromJSON, toBase64, and fromBase64
  • general access: len and get

Higher-order functions accept either a registered function name or a Go function value. Inline predicates and closures are not supported.

See the builtin reference for signatures, accepted inputs, return values, and edge-case behavior.

Benchmarks

This recorded run is generated in CI with the five-engine comparison set.

benchstat
goos: linux
goarch: amd64
pkg: benchmarks
cpu: AMD EPYC 7763 64-Core Processor
                     │  fasteval   │               govaluate               │                  expr                  │                  cel                   │                 gval                  │
                     │   sec/op    │    sec/op     vs base                 │    sec/op     vs base                  │    sec/op     vs base                  │    sec/op     vs base                 │
Compile/Arithmetic-4   2.641µ ± 4%    2.182µ ± 5%   -17.38% (p=0.000 n=10)   14.395µ ± 3%   +445.04% (p=0.000 n=10)   37.546µ ± 4%  +1321.66% (p=0.000 n=10)    2.281µ ± 1%   -13.65% (p=0.000 n=10)
Compile/Variables-4    1.351µ ± 0%    2.099µ ± 1%   +55.39% (p=0.000 n=10)   15.877µ ± 2%  +1075.64% (p=0.000 n=10)   33.836µ ± 3%  +2405.44% (p=0.000 n=10)    2.937µ ± 3%  +117.44% (p=0.000 n=10)
Compile/Boolean-4      2.387µ ± 3%    3.483µ ± 0%   +45.92% (p=0.000 n=10)   17.383µ ± 1%   +628.24% (p=0.000 n=10)   53.443µ ± 2%  +2138.92% (p=0.000 n=10)    4.485µ ± 1%   +87.89% (p=0.000 n=10)
Compile/String-4       1.307µ ± 0%    2.709µ ± 1%  +107.23% (p=0.000 n=10)   16.235µ ± 1%  +1142.16% (p=0.000 n=10)   37.164µ ± 2%  +2743.46% (p=0.000 n=10)    4.142µ ± 1%  +216.91% (p=0.000 n=10)
Eval/Arithmetic-4      5.971n ± 0%   18.075n ± 0%  +202.74% (p=0.000 n=10)   46.830n ± 1%   +684.36% (p=0.000 n=10)   95.535n ± 0%  +1500.12% (p=0.000 n=10)    2.822n ± 0%   -52.74% (p=0.000 n=10)
Eval/Variables-4       91.01n ± 1%   130.65n ± 0%   +43.56% (p=0.000 n=10)   108.85n ± 1%    +19.60% (p=0.000 n=10)   197.65n ± 1%   +117.17% (p=0.000 n=10)   234.50n ± 0%  +157.66% (p=0.000 n=10)
Eval/Boolean-4         142.3n ± 1%    212.3n ± 0%   +49.19% (p=0.000 n=10)    133.3n ± 3%     -6.32% (p=0.000 n=10)    263.6n ± 0%    +85.28% (p=0.000 n=10)    354.1n ± 1%  +148.84% (p=0.000 n=10)
Eval/String-4          127.5n ± 1%    237.1n ± 0%   +85.89% (p=0.000 n=10)    130.1n ± 1%     +2.00% (p=0.000 n=10)    279.3n ± 2%   +118.97% (p=0.000 n=10)   1277.5n ± 1%  +901.57% (p=0.000 n=10)
geomean                319.9n         517.4n        +61.72%                   1.243µ        +288.56%                   2.774µ        +767.15%                   662.8n       +107.17%

                     │    fasteval    │               govaluate                │                  expr                   │                    cel                    │                  gval                   │
                     │      B/op      │     B/op      vs base                  │     B/op       vs base                  │     B/op       vs base                    │     B/op      vs base                   │
Compile/Arithmetic-4    1288.0 ± 0%       976.0 ± 0%  -24.22% (p=0.000 n=10)       9368.0 ± 0%   +627.33% (p=0.000 n=10)    16100.0 ± 0%  +1150.00% (p=0.000 n=10)      1960.0 ± 0%   +52.17% (p=0.000 n=10)
Compile/Variables-4      696.0 ± 0%       768.0 ± 0%  +10.34% (p=0.000 n=10)      10448.0 ± 0%  +1401.15% (p=0.000 n=10)    15387.0 ± 0%  +2110.78% (p=0.000 n=10)      2224.0 ± 0%  +219.54% (p=0.000 n=10)
Compile/Boolean-4      1.328Ki ± 0%     1.273Ki ± 0%   -4.12% (p=0.000 n=10)     11.023Ki ± 0%   +730.00% (p=0.000 n=10)   23.620Ki ± 0%  +1678.46% (p=0.000 n=10)     2.648Ki ± 0%   +99.41% (p=0.000 n=10)
Compile/String-4         816.0 ± 0%      1048.0 ± 0%  +28.43% (p=0.000 n=10)      11192.0 ± 0%  +1271.57% (p=0.000 n=10)    18082.0 ± 0%  +2115.93% (p=0.000 n=10)      2800.0 ± 0%  +243.14% (p=0.000 n=10)
Eval/Arithmetic-4         0.00 ± 0%        0.00 ± 0%        ~ (p=1.000 n=10) ¹      32.00 ± 0%          ? (p=0.000 n=10)       0.00 ± 0%          ~ (p=1.000 n=10) ¹      0.00 ± 0%         ~ (p=1.000 n=10) ¹
Eval/Variables-4         8.000 ± 0%       8.000 ± 0%        ~ (p=1.000 n=10) ¹     40.000 ± 0%   +400.00% (p=0.000 n=10)     24.000 ± 0%   +200.00% (p=0.000 n=10)      56.000 ± 0%  +600.00% (p=0.000 n=10)
Eval/Boolean-4           8.000 ± 0%       8.000 ± 0%        ~ (p=1.000 n=10) ¹     40.000 ± 0%   +400.00% (p=0.000 n=10)     32.000 ± 0%   +300.00% (p=0.000 n=10)      80.000 ± 0%  +900.00% (p=0.000 n=10)
Eval/String-4             0.00 ± 0%        0.00 ± 0%        ~ (p=1.000 n=10) ¹      32.00 ± 0%          ? (p=0.000 n=10)      64.00 ± 0%          ? (p=0.000 n=10)      528.00 ± 0%         ? (p=0.000 n=10)
geomean                             ²                  +0.37%                ²      614.2       ?                                         ?                        ²                 ?                       ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                     │   fasteval   │               govaluate                │                 expr                  │                    cel                    │                  gval                   │
                     │  allocs/op   │  allocs/op   vs base                   │  allocs/op   vs base                  │  allocs/op    vs base                     │  allocs/op   vs base                    │
Compile/Arithmetic-4   21.00 ± 0%      23.00 ± 0%    +9.52% (p=0.000 n=10)      47.00 ± 0%   +123.81% (p=0.000 n=10)    310.00 ± 0%   +1376.19% (p=0.000 n=10)      23.00 ± 0%     +9.52% (p=0.000 n=10)
Compile/Variables-4    6.000 ± 0%     17.000 ± 0%  +183.33% (p=0.000 n=10)     63.000 ± 0%   +950.00% (p=0.000 n=10)   289.000 ± 0%   +4716.67% (p=0.000 n=10)     35.000 ± 0%   +483.33% (p=0.000 n=10)
Compile/Boolean-4      10.00 ± 0%      29.00 ± 0%  +190.00% (p=0.000 n=10)      76.00 ± 0%   +660.00% (p=0.000 n=10)    452.00 ± 0%   +4420.00% (p=0.000 n=10)      57.00 ± 0%   +470.00% (p=0.000 n=10)
Compile/String-4       3.000 ± 0%     23.000 ± 0%  +666.67% (p=0.000 n=10)     75.000 ± 0%  +2400.00% (p=0.000 n=10)   333.000 ± 0%  +11000.00% (p=0.000 n=10)     59.000 ± 0%  +1866.67% (p=0.000 n=10)
Eval/Arithmetic-4      0.000 ± 0%      0.000 ± 0%         ~ (p=1.000 n=10) ¹    1.000 ± 0%          ? (p=0.000 n=10)     0.000 ± 0%           ~ (p=1.000 n=10) ¹    0.000 ± 0%          ~ (p=1.000 n=10) ¹
Eval/Variables-4       1.000 ± 0%      1.000 ± 0%         ~ (p=1.000 n=10) ¹    2.000 ± 0%   +100.00% (p=0.000 n=10)     3.000 ± 0%    +200.00% (p=0.000 n=10)      5.000 ± 0%   +400.00% (p=0.000 n=10)
Eval/Boolean-4         1.000 ± 0%      1.000 ± 0%         ~ (p=1.000 n=10) ¹    2.000 ± 0%   +100.00% (p=0.000 n=10)     4.000 ± 0%    +300.00% (p=0.000 n=10)      7.000 ± 0%   +600.00% (p=0.000 n=10)
Eval/String-4          0.000 ± 0%      0.000 ± 0%         ~ (p=1.000 n=10) ¹    1.000 ± 0%          ? (p=0.000 n=10)     4.000 ± 0%           ? (p=0.000 n=10)     24.000 ± 0%          ? (p=0.000 n=10)
geomean                           ²                 +69.77%                ²    9.521       ?                                        ?                         ²                ?                        ²
¹ all samples are equal
² summaries must be >0 to compute geomean
Compile
  • Execution Time (ns/op)

    Image

  • Memory Usage (B/op)

    Image

  • Allocations/op

    Image

  • Iterations

    Image

Eval
  • Execution Time (ns/op)

    Image

  • Memory Usage (B/op)

    Image

  • Allocations/op

    Image

  • Iterations

    Image

Highlights
  • Across these eight workloads: fasteval has the lowest time geomean at 319.9 ns. The nearest result is govaluate at 517.4 ns, 61.72% above the baseline.
  • Compilation: fasteval leads the Variables, Boolean, and String workloads. govaluate and gval lead Arithmetic by 17.38% and 13.65%, respectively.
  • Evaluation: fasteval leads govaluate in all four workloads. gval leads Arithmetic, expr leads Boolean by 6.32%, and fasteval leads Variables and String.
  • Memory and allocations: fasteval has the fewest compile allocations in every workload and matches govaluate's evaluation allocation counts. It uses the least compile memory for Variables and String; govaluate uses less for Arithmetic and Boolean.

These figures are a machine-specific snapshot, not a performance guarantee. See the performance guide for the benchmark method and reporting limits.

Run benchmarks yourself:

make -C benchmarks bench
make -C benchmarks benchstat

Errors and ASTs

Expression and template compilation failures return DiagnosticsError. Evaluation failures return EvalError with a stable ErrorCode, operation, source span, path, and wrapped cause when applicable. Expression.AST exposes the immutable parsed tree.

See Errors and AST inspection for errors.As examples, partial template failures, error categories, and AST traversal.

Trust and cancellation

Only trusted authors should write expressions. Exported methods, registered functions, and Go function values from variables or resolvers can have side effects. Panics from functions, methods, resolvers, builtins, and text formatters become typed evaluation errors.

Expression nesting and recursively processed values have fixed depth limits of 1,024. Exact constant-folding operations have a 1,048,576-bit size limit. There are no configurable step, collection-size, allocation, or workload budgets. Evaluation and collection loops honor context.Context; caller functions must also cooperate with cancellation. Context cancellation cannot reliably prevent one large allocation from exhausting process memory.

License

Apache License 2.0. See LICENSE and NOTICE.

Documentation

Overview

Package fasteval compiles expressions and renders raw string templates.

Its expression language covers arithmetic, comparisons, logic, collections, access, and function calls while preserving native Go numeric types. Compiled expressions and templates are immutable and safe for concurrent use.

Templates return raw text. Callers must encode values for HTML, SQL, shell commands, or any other destination before using rendered output there.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Eval

func Eval(ctx context.Context, source string, variables map[string]any, options ...EvalOption) (any, error)

Eval compiles source with the default compiler, then evaluates it.

func EvalAs

func EvalAs[T any](ctx context.Context, source string, variables map[string]any, options ...EvalOption) (T, error)

EvalAs compiles source with the default compiler and evaluates it as T.

func EvalAsWith

func EvalAsWith[T any](
	ctx context.Context,
	c *Compiler,
	source string,
	variables map[string]any,
	options ...EvalOption,
) (T, error)

EvalAsWith compiles source with c and evaluates it as T.

Types

type Compiler

type Compiler struct {
	// contains filtered or unexported fields
}

Compiler builds expressions and templates with an immutable function registry.

func NewCompiler

func NewCompiler(options ...CompilerOption) (*Compiler, error)

NewCompiler returns an immutable compiler with every builtin enabled.

func (*Compiler) Compile

func (c *Compiler) Compile(source string) (*Expression, error)

Compile builds an Expression from source with c's function registry.

func (*Compiler) CompileTemplate

func (c *Compiler) CompileTemplate(source string, options ...TemplateOption) (*Template, error)

CompileTemplate builds a Template from source with c's function registry.

Example
compiler, err := fasteval.NewCompiler(
	fasteval.WithFunction("greet", func(name string) string {
		return "Hello " + name
	}),
)
if err != nil {
	panic(err)
}

template, err := compiler.CompileTemplate("{{greet(name)}}")
if err != nil {
	panic(err)
}

value, err := template.Render(context.Background(), map[string]any{testName: testAda})
if err != nil {
	panic(err)
}

fmt.Println(value)
Output:
Hello Ada

type CompilerOption

type CompilerOption func(*compilerOptions) error

CompilerOption changes how a Compiler is built.

func WithFunction

func WithFunction(name string, function any) CompilerOption

WithFunction adds one Go function to a compiler.

func WithFunctions

func WithFunctions(functions map[string]any) CompilerOption

WithFunctions adds a map of named Go functions to a compiler.

type Diagnostic

type Diagnostic struct {
	Code     ErrorCode
	Severity Severity
	Span     Span
	Message  string
	Notes    []string
}

Diagnostic describes one compilation issue.

type DiagnosticsError

type DiagnosticsError struct {
	// contains filtered or unexported fields
}

DiagnosticsError contains one or more compilation diagnostics. Its accessors return copies instead of exposing mutable backing storage.

Example
package main

import (
	"errors"
	"fmt"

	"go.dw1.io/fasteval"
)

func main() {
	_, err := fasteval.Compile("price +")

	var diagnostics *fasteval.DiagnosticsError
	if !errors.As(err, &diagnostics) {
		panic(err)
	}

	diagnostic := diagnostics.At(0)
	fmt.Println(diagnostics.Len(), diagnostic.Code, diagnostic.Severity)
}
Output:
1 syntax error

func (*DiagnosticsError) All

func (d *DiagnosticsError) All() []Diagnostic

All returns a copy of every diagnostic in d.

func (*DiagnosticsError) At

func (d *DiagnosticsError) At(index int) Diagnostic

At returns the diagnostic at index.

func (*DiagnosticsError) Error

func (d *DiagnosticsError) Error() string

Error formats all diagnostics as a compact string.

func (*DiagnosticsError) Len

func (d *DiagnosticsError) Len() int

Len returns the number of diagnostics in d.

type ErrorCode

type ErrorCode string

ErrorCode classifies compile-time and evaluation failures. Its values are stable.

const (
	// ErrSyntax reports malformed expression or template syntax.
	ErrSyntax ErrorCode = "syntax"
	// ErrUnknownVariable reports an unresolved variable name.
	ErrUnknownVariable ErrorCode = "unknown_variable"
	// ErrType reports an operation or conversion applied to an invalid type.
	ErrType ErrorCode = "type"
	// ErrOverflow reports checked integer overflow or underflow.
	ErrOverflow ErrorCode = "overflow"
	// ErrDivisionByZero reports integer division or remainder by zero.
	ErrDivisionByZero ErrorCode = "division_by_zero"
	// ErrAccess reports invalid field, method, map, or index access.
	ErrAccess ErrorCode = "access"
	// ErrFunction reports invalid function registration or invocation.
	ErrFunction ErrorCode = "function"
	// ErrPanic reports a recovered panic from caller-controlled code.
	ErrPanic ErrorCode = "panic"
	// ErrCanceled reports evaluation canceled through context.Context.
	ErrCanceled ErrorCode = "canceled"
	// ErrFormat reports a value that a template cannot render.
	ErrFormat ErrorCode = "format"
)

type EvalError

type EvalError struct {
	// contains filtered or unexported fields
}

EvalError describes a failure during evaluation.

Example
package main

import (
	"context"
	"errors"
	"fmt"

	"go.dw1.io/fasteval"
)

func main() {
	_, err := fasteval.Eval(context.Background(), "missing", nil)

	var evaluationError *fasteval.EvalError
	if !errors.As(err, &evaluationError) {
		panic(err)
	}

	fmt.Println(evaluationError.Code(), evaluationError.Operation(), evaluationError.Path())
}
Output:
unknown_variable resolve variable missing

func (*EvalError) Code

func (e *EvalError) Code() ErrorCode

Code returns the stable error category.

func (*EvalError) Error

func (e *EvalError) Error() string

Error formats the evaluation failure.

func (*EvalError) Operation

func (e *EvalError) Operation() string

Operation returns the operation that failed.

func (*EvalError) Path

func (e *EvalError) Path() string

Path returns the related variable, accessor, or function path.

func (*EvalError) Span

func (e *EvalError) Span() Span

Span returns the source location associated with the failure.

func (*EvalError) Unwrap

func (e *EvalError) Unwrap() error

Unwrap returns the underlying cause.

type EvalOption

type EvalOption func(*evalOptions) error

EvalOption configures one evaluation call.

func WithResolver

func WithResolver(resolve ResolveFunc) EvalOption

WithResolver uses resolve after a direct variables-map miss.

Example
package main

import (
	"context"
	"fmt"

	"go.dw1.io/fasteval"
)

func main() {
	expression, err := fasteval.Compile("known + lazy")
	if err != nil {
		panic(err)
	}

	value, err := expression.Eval(
		context.Background(),
		map[string]any{"known": 40},
		fasteval.WithResolver(func(_ context.Context, name string) (any, bool, error) {
			if name == "lazy" {
				return 2, true, nil
			}

			return nil, false, nil
		}),
	)
	if err != nil {
		panic(err)
	}

	fmt.Println(value)
}
Output:
42

type Expression

type Expression struct {
	// contains filtered or unexported fields
}

Expression is an immutable compiled expression with a dynamic result.

func Compile

func Compile(source string) (*Expression, error)

Compile builds an Expression from source with the default builtin-only compiler.

Example
package main

import (
	"context"
	"fmt"

	"go.dw1.io/fasteval"
)

func main() {
	expression, err := fasteval.Compile("price * quantity >= 100")
	if err != nil {
		panic(err)
	}

	value, err := expression.Eval(context.Background(), map[string]any{
		"price":    25,
		"quantity": 4,
	})
	if err != nil {
		panic(err)
	}

	fmt.Println(value)
}
Output:
true

func (*Expression) AST

func (e *Expression) AST() *Node

AST returns the immutable root of the parsed source tree.

Example
package main

import (
	"fmt"

	"go.dw1.io/fasteval"
)

func main() {
	expression, err := fasteval.Compile("price * quantity")
	if err != nil {
		panic(err)
	}

	root := expression.AST()
	fmt.Println(root.Kind() == fasteval.NodeBinary, root.Text(), len(root.Children()))

	for _, child := range root.Children() {
		fmt.Println(child.Kind() == fasteval.NodeIdentifier, child.Text())
	}
}
Output:
true * 2
true price
true quantity

func (*Expression) Eval

func (e *Expression) Eval(ctx context.Context, variables map[string]any, options ...EvalOption) (any, error)

Eval runs e with variables and evaluation options.

func (*Expression) Source

func (e *Expression) Source() string

Source returns the expression text supplied at compile time.

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node is an immutable node in a compiled expression AST.

func (*Node) Children

func (n *Node) Children() []*Node

Children returns a copy of n's child list.

func (*Node) Kind

func (n *Node) Kind() NodeKind

Kind returns n's node category.

func (*Node) Span

func (n *Node) Span() Span

Span returns n's source span.

func (*Node) Text

func (n *Node) Text() string

Text returns the source text associated with n.

type NodeKind

type NodeKind uint8

NodeKind classifies a public AST node.

const (
	// NodeInvalid is an unavailable node.
	NodeInvalid NodeKind = iota
	// NodeLiteral is a literal value.
	NodeLiteral
	// NodeIdentifier is a variable or function name.
	NodeIdentifier
	// NodeUnary is a prefix operation.
	NodeUnary
	// NodeBinary is a binary operation.
	NodeBinary
	// NodeConditional is a ternary expression.
	NodeConditional
	// NodeCall is a function or method call.
	NodeCall
	// NodeAccess is field or map-dot access.
	NodeAccess
	// NodeIndex is an index operation.
	NodeIndex
	// NodeList is a list literal.
	NodeList
	// NodeMap is a map literal.
	NodeMap
)

type Program

type Program[T any] struct {
	// contains filtered or unexported fields
}

Program is an immutable compiled expression whose result is converted to T.

func CompileAs

func CompileAs[T any](source string) (*Program[T], error)

CompileAs compiles source and checks conversion to T during evaluation.

Example
type result struct {
	Name  string `json:"name"`
	Valid bool   `json:"valid"`
}

program, err := fasteval.CompileAs[result]("{'name': name, 'valid': score >= 80}")
if err != nil {
	panic(err)
}

value, err := program.Eval(context.Background(), map[string]any{testName: testAda, testScore: 90})
if err != nil {
	panic(err)
}

fmt.Printf("%s: %t\n", value.Name, value.Valid)
Output:
Ada: true

func CompileAsWith

func CompileAsWith[T any](c *Compiler, source string) (*Program[T], error)

CompileAsWith compiles source as T with c.

func (*Program[T]) Eval

func (p *Program[T]) Eval(ctx context.Context, variables map[string]any, options ...EvalOption) (T, error)

Eval runs p and recursively converts its result to T without loss.

type ResolveFunc

type ResolveFunc func(ctx context.Context, name string) (value any, found bool, err error)

ResolveFunc looks up a variable after a direct map miss. found distinguishes an explicit nil value from an unknown name.

type Severity

type Severity string

Severity classifies the effect of a diagnostic.

const (
	// SeverityError marks a diagnostic that prevents compilation.
	SeverityError Severity = "error"
	// SeverityWarning marks a non-fatal diagnostic.
	SeverityWarning Severity = "warning"
)

type Span

type Span struct {
	Start  int
	End    int
	Line   int
	Column int
}

Span locates a half-open byte range at a one-based source position.

type Template

type Template struct {
	// contains filtered or unexported fields
}

Template is an immutable compiled template safe for concurrent use.

func CompileTemplate

func CompileTemplate(source string, options ...TemplateOption) (*Template, error)

CompileTemplate builds a Template from source with the default builtin-only compiler.

Example
template, err := fasteval.CompileTemplate("Hello {{name}}: {{score >= 80 ? 'pass' : 'fail'}}")
if err != nil {
	panic(err)
}

value, err := template.Render(context.Background(), map[string]any{testName: testAda, testScore: 90})
if err != nil {
	panic(err)
}

fmt.Println(value)
Output:
Hello Ada: pass

func (*Template) Execute

func (t *Template) Execute(
	ctx context.Context,
	writer io.Writer,
	variables map[string]any,
	options ...EvalOption,
) (int64, error)

Execute evaluates t and writes raw output to writer. If a later expression or write fails, writer retains the bytes written before the error.

func (*Template) Render

func (t *Template) Render(ctx context.Context, variables map[string]any, options ...EvalOption) (string, error)

Render evaluates t and returns raw output. On error, it also returns the text completed before the failure.

Example (PartialOutput)
template, err := fasteval.CompileTemplate("Hello {{name}}! {{1 / zero}}")
if err != nil {
	panic(err)
}

value, err := template.Render(context.Background(), map[string]any{
	testName: testAda,
	"zero":   0,
})

var evaluationError *fasteval.EvalError
if !errors.As(err, &evaluationError) {
	panic(err)
}

fmt.Printf("%q %s\n", value, evaluationError.Code())
Output:
"Hello Ada! " division_by_zero

func (*Template) Source

func (t *Template) Source() string

Source returns the template text supplied at compile time.

type TemplateOption

type TemplateOption func(*templateOptions) error

TemplateOption changes how a template is compiled.

func WithDelimiters

func WithDelimiters(start, end string) TemplateOption

WithDelimiters replaces the default delimiters with a distinct, non-empty pair.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL