exprcls

package module
v0.0.0-...-380d646 Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2025 License: MIT Imports: 5 Imported by: 0

README

expr-cls

expr-cls is a minimal, experimental implementation of a high-performance string expression compiler and runtime for Go.
The core idea is to build expressions as chains of strictly-typed Go closures (functions), rather than interpreting bytecode on a virtual machine.
This architecture enables extremely fast compilation and execution, zero allocations during evaluation, and a flexible, extensible environment system.


Key Concepts

Environment:
At compile time, you define an environment describing:

  • Supported unary and binary operators for the parser (not implemented yet; currently a fixed set is used).
  • Complex constructs for the parser (e.g., ternary operator, arbitrary typed literals; planned).
  • Overload registrations for unary and binary operators.
  • Overload registrations for functions.
  • Constant registrations.
  • Variable type registrations.
  • Variable source type registrations (struct fields as variables).

Extensibility:
You can create separate packages with ready-made environments for domain-specific tasks (e.g., matrices, complex numbers, statistics, geospatial, etc). See example for a current example of environment definition and usage.

Performance:
Expressions compile and execute extremely quickly at runtime.
Compiled expressions are strictly typed.


Usage

package example_test

import (
	"fmt"

	exprcls "github.com/guamoko995/expr-cls"

	// Using the example environment
	_ "github.com/guamoko995/expr-cls/tests/example/def_env"
)

// CompileAndCalcExample demonstrates how to compile and evaluate expressions
// using the expr-cls package.
func Example() {
	// Define a data structure containing input variables for our expression.
	type InputData struct {
		A int
		B int
	}

	// Parse and compile the expression "3 + A * B".
	prog, err := exprcls.Compile[InputData, float64]("3 + A * -B + sin(pi/2)")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	// Provide input data for evaluating the expression.
	input := InputData{A: 7, B: 10}

	// Evaluate the expression using the provided input data.
	result := prog(input)

	// Print the computed result.
	fmt.Println(result)

	// Output: -66
}

Features

  • Struct fields as variables in expressions (via registration).
  • Operator overloading for custom types (operator set is fixed by parser, not extendable yet).
  • Function overloading and custom function registration.
  • Constant registration.
  • Strict typing of compiled expressions.
  • Extremely fast compilation and evaluation (see benchmarks below).
  • MVP: Some features and built-ins from original expr-lang/expr are disabled or not implemented.

Benchmarks

You can find the benchmark source in tests/benchmarks.

Compilation Speed

Measures the time and resource usage to compile an expression (benchmark code):

goos: linux
goarch: amd64
pkg: github.com/guamoko995/expr-cls/tests/benchmarks
cpu: AMD Ryzen 5 5600H with Radeon Graphics         
BenchmarkCompile/expr-cls-12         	  661381	      1802 ns/op	    1344 B/op	      31 allocs/op
BenchmarkCompile/expr-12             	  107227	     10928 ns/op	   10351 B/op	      76 allocs/op
BenchmarkCompile/cel-go-12           	   33639	     36255 ns/op	   24404 B/op	     355 allocs/op
PASS
ok  	github.com/guamoko995/expr-cls/tests/benchmarks	3.591s

expr-cls compiles more than 6x faster and with 8x less memory allocation than expr-lang/expr.


Evaluation Speed

Measures the time and resource usage to repeatedly evaluate a compiled expression (benchmark code):

expression: "X+(6.0*Y)"
params:
	X=3
	Y=5
expr-cls result: 33
expr result: 33
cel-go result: 33

goos: linux
goarch: amd64
pkg: github.com/guamoko995/expr-cls/tests/benchmarks
cpu: AMD Ryzen 5 5600H with Radeon Graphics         
BenchmarkСalc/expr-cls-12          	132511530	         9.015 ns/op	       0 B/op	       0 allocs/op
BenchmarkСalc/expr-12              	 6529965	       172.0 ns/op	     136 B/op	       6 allocs/op
BenchmarkСalc/cel-go-12            	 4484371	       267.9 ns/op	     368 B/op	       6 allocs/op
PASS
ok  	github.com/guamoko995/expr-cls/tests/benchmarks	3.529s

expr-cls evaluates expressions ~18x faster and with zero allocations.


Architecture

  • Parsing: Expressions are parsed into AST nodes. The set of operators/constructs is currently fixed.
  • Environment: Holds operator/function/constant/variable builders. Easily extended. See example for practical setup.
  • Building: AST is compiled into a closure chain (Go functions), not bytecode.
  • Evaluation: The compiled closure chain receives strictly-typed input (struct) and returns strictly-typed output.

Extending expr-cls

To see how to register types, constants, functions, and operator overloads, refer to the example.


Limitations and Roadmap

  • Only struct variable sources supported (for now).
  • Operators cannot be extended (only overloaded).
  • Some complex constructs (e.g. ternary operator, custom literals) are planned but not implemented.
  • Error handling and reporting are minimal.
  • More tests and environments are planned.
  • Parser extensibility: declarative operator/construct definition is a future goal.

This README summarizes the ideas and experimental architecture of expr-cls.
Feedback and contributions are welcome.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Compile

func Compile[srcT, outT any](input string, ops ...Option) (func(srcT) outT, error)

Compile parses and compiles given input expression to bytecode program.

func RegisterBinary

func RegisterBinary(token string, registrator ...registrators.Binary) error

func RegisterConst

func RegisterConst(token string, registrator ...registrators.Const) error

func RegisterFunc

func RegisterFunc(token string, registrator ...registrators.Func) error

func RegisterUnary

func RegisterUnary(token string, registrator ...registrators.Unary) error

func RegisterVarSource

func RegisterVarSource(registrator ...registrators.VarSourse)

func RegisterVarType

func RegisterVarType(registrator ...registrators.VariableType)

Types

type Env

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

func NewEnv

func NewEnv() Env

type Option

type Option func(c *conf.Config)

Option for configuring config.

func MaxNodes

func MaxNodes(n uint) Option

MaxNodes sets the maximum number of nodes allowed in the expression. By default, the maximum number of nodes is conf.DefaultMaxNodes. If MaxNodes is set to 0, the node budget check is disabled.

func WithEnv

func WithEnv(Env Env) Option

Directories

Path Synopsis
env
internal
difflib
Package difflib is a partial port of Python difflib module.
Package difflib is a partial port of Python difflib module.
spew
Package spew implements a deep pretty printer for Go data structures to aid in debugging.
Package spew implements a deep pretty printer for Go data structures to aid in debugging.
testify/assert
Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
testify/assert/internal/unsafetests
This package exists just to isolate tests that reference the unsafe package.
This package exists just to isolate tests that reference the unsafe package.
testify/require
Package require implements the same assertions as the `assert` package but stops test execution when a test fails.
Package require implements the same assertions as the `assert` package but stops test execution when a test fails.
tests

Jump to

Keyboard shortcuts

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