A small & fast dependency-free library for parsing micro expressions.

MicroExpr

A small & fast dependency-free library for parsing micro expressions.

This library was originally built for use in templating languages (e.g. for-loop variable selection, if-statement evaluation) so is minimal in what it supports by design. If you need a more full-featured expression parser, check out antonmedv/expr instead.

Features:

  • Fast, low-allocation parser and runtime
  • Simple
    • Easy to learn
    • Easy to read
    • No hiding complex branching logic in expressions
  • Intuitive, e.g. "id" + 1 => "id1"
  • Useful error messages

Usage

import "github.com/danielgtaylor/mexpr"

// Convenience for lexing/parsing/running in one step:
result, err := mexpr.Eval("a + b", map[string]interface{}{
	"a": 1,
	"b": 2,
})

// Manual method with type checking and fast AST re-use. Error handling is
// omitted for brevity.
l := mexpr.NewLexer("a + b")
p := mexpr.NewParser(l)
ast, err := mexpr.Parse()
typeExamples = map[string]interface{}{
	"a": 1,
	"b": 1,
}
err := mexpr.TypeCheck(ast, typeExamples)
interpreter := mexpr.NewInterpreter(ast)
result1, err := interpreter.Run(map[string]interface{}{
	"a": 1,
	"b": 2,
})
result2, err := interpreter.Run(map[string]interfae{}{
	"a": 150,
	"b": 30,
})

Syntax

Literals

  • strings double quoted e.g. "hello"
  • numbers e.g. 123, 2.5

Internally all numbers are treated as float64, which means fewer conversions/casts when taking arbitrary JSON/YAML inputs.

Accessing properties

foo.bar[0].value

Arithmetic operators

  • + (addition)
  • - (subtration)
  • * (multiplication)
  • / (division)
  • % (modulus)
  • ^ (power)
(1 + 2) * 3^2

Comparison operators

  • == (equal)
  • != (not equal)
  • < (less than)
  • > (greater than)
  • <= (less than or equal to)
  • >= (greater than or equal to)
100 >= 42

Logical operators

  • not (negation)
  • and
  • or
1 < 2 and 3 < 4

Non-boolean values are converted to booleans. The following result in true:

  • numbers greater than zero
  • non-empty string
  • array with at least one item
  • map with at least one key/value pair

String operators

  • Indexing, e.g. foo[0]
  • Slicing, e.g. foo[1:2]
  • .length pseudo-property, e.g. foo.length
  • + (concatenation)
  • in e.g. "f" in "foo"
  • startsWith e.g. "foo" startsWith "f"
  • endsWith e.g. "foo" endsWith "o"

Slices indexes are mandatory and inclusive. Indexes can be negative, e.g. foo[-1] selects the last item in the array.

Any value concatenated with a string will result in a string. For example "id" + 1 will result in "id1".

There is no distinction between strings, bytes, or runes. Everything is treated as a string.

Array/slice operators

  • Indexing, e.g. foo[1]
  • Slicing, e.g. foo[1:2]
  • .length pseudo-property, e.g. foo.length
  • + (concatenation)
  • in (has item), e.g. 1 in foo

Slices indexes are mandatory and inclusive. Indexes can be negative, e.g. foo[-1] selects the last item in the array.

Map operators

  • in (has key), e.g. "key" in foo

Performance

Performance compares favorably to antonmedv/expr for both Eval(...) and cached program performance, which is expected given the more limited feature set. The example expression used is non-trivial: foo.bar / 2 * (2 + 4 / 2) == 20 and "v" in baz.

$ go test -bench=. -benchmem
goos: darwin
goarch: amd64
pkg: github.com/danielgtaylor/mexpr
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkMexpr-12            	  322903	      3592 ns/op	    2576 B/op	      53 allocs/op
BenchmarkMexprCached-12      	 7066062	       166.4 ns/op	      32 B/op	       4 allocs/op
BenchmarkLibExpr-12          	  110338	      9976 ns/op	    8146 B/op	      79 allocs/op
BenchmarkLibExprCached-12    	 2816659	       432.6 ns/op	      96 B/op	       6 allocs/op

References

These were a big help in understanding how Pratt parsers work:

Similar Resources

Gene parsing package for Axie Infinity

agp Package agp is a gene parsing package for Axie Infinity. The name agp stands for "Axie Gene Parser" which decodes the hex representation of an Axi

Apr 18, 2022

Go-path - A helper package that provides utilities for parsing and using ipfs paths

go-path is a helper package that provides utilities for parsing and using ipfs paths

Jan 18, 2022

A faster RWLock primitive in Go, 2-3 times faster than RWMutex. A Go implementation of concurrency control algorithm in paper Left-Right - A Concurrency Control Technique with Wait-Free Population Oblivious Reads

Go Left Right Concurrency A Go implementation of the left-right concurrency control algorithm in paper Left-Right - A Concurrency Control Technique w

Jan 6, 2023

Generic Free List implementation to reuse memory and avoid allocations

gofl GOFL provides a Generic Free List implementation for Go. Installation This

Oct 17, 2022

Helm plugin to reference value files packaged in dependency charts

Helm Octopus Plugin This Helm plugin allows to reference packaged value files (other than the default values.yaml). Install helm plugin install https:

Sep 23, 2021

Golang flags parser with zero dependency

flags Golang flags parser with zero dependency. Usage See simple.go for basic usage. Concept flags gives a simple way to get flag's value from argumen

Jan 16, 2022

Di - A (very) WIP Go 1.18+ generic dependency injection package based on type reflection

di A (very) WIP Go 1.18+ generic dependency injection package based on type refl

Apr 26, 2022

go-linereader: A small library for streaming lines from an io.Reader.

go-linereader: A small library for streaming lines from an io.Reader.

Oct 25, 2021

Go Small Library

Go Small Library (gosl) Copyright Gon Y. Yi 2021 Goal General No import of any library whatsoever including standard libr

Jan 12, 2022
Comments
  • fix: prevent panic on malformed slice

    fix: prevent panic on malformed slice

    Fixes a panic when slices are malformed that was found via fuzz testing CLI shorthand and makes the type checker more resilient against nested negative indexes when nested types are unavialable.

  • fix: pseudo-identifiers and unquoted strings

    fix: pseudo-identifiers and unquoted strings

    This change fixes a bug with pseudo-identifiers and unquoted strings where an expression like str.lower == abcd would return false when str is ABCD. The value tracking whether the previous item was a field selector was not being reset properly on each iteration of the loop, which is resolved with this PR.

  • feat: option to enable unquoted strings

    feat: option to enable unquoted strings

    This PR adds a feature to enable the use of unquoted strings, which is off by default. When turned on, identifiers take precedence and if an identifier is not found it gets treated as a string. For example, "foo" == foo would result in true if foo is not defined and unquoted string support is enabled.

    The options are documented in the README and several new tests related to unquoted strings are added.

  • feat: where/lower/upper, non-string map support

    feat: where/lower/upper, non-string map support

    This PR adds a number of new features without impacting performance:

    • Switch to Go 1.18+
    • where clause to filter array/slice items
    • lower and upper pseudo-properties for strings
    • Support for map[interface{}]interface{}
    • Github actions for builds
MNA - stands for mobile number assignment - a small zero external dependency golang library that is used to identify mobile number assignment in tanzania

MNA - stands for mobile number assignment - a small zero external dependency golang library that is used to identify mobile number assignment in tanzania

Nov 29, 2021
Small utility to allow simpler, quicker testing of parsing files in crowdsec

cs_parser_test Small utility to allow simpler, quicker testing of parsing files in crowdsec Usage $ sudo cs_parser_test -t syslog /var/log/mail.log N

Jul 13, 2021
A fast unused and duplicate dependency checker
A fast unused and duplicate dependency checker

Depp - A fast unused and duplicate package checker Installation npm install -g depp-installer (will try to get npm install -g depp later) Usage Just

Oct 31, 2022
Molecule is a Go library for parsing protobufs in an efficient and zero-allocation manner

Molecule Molecule is a Go library for parsing protobufs in an efficient and zero-allocation manner. The API is loosely based on this excellent Go JSON

Jan 5, 2023
A Go (golang) library for parsing and verifying versions and version constraints.

go-version is a library for parsing versions and version constraints, and verifying versions against a set of constraints. go-version can sort a collection of versions properly, handles prerelease/beta versions, can increment versions, etc.

Jan 9, 2023
A library for parsing ANSI encoded strings
 A library for parsing ANSI encoded strings

Go ANSI Parser converts strings with ANSI escape codes into a slice of structs that represent styled text

Sep 20, 2022
A utility library to do files/io/bytes processing/parsing in file-system or network.

goreader A utility library to do files/io/bytes processing/parsing in file-system or network. These features are really common to be implemented for a

Nov 1, 2021
Simple library to handle ANSI functions and parsing of color formatting strings

Emerald A basic color library for use in my Go projects, built on top of mgutz/ansi. Package ansi is a small, fast library to create ANSI colored stri

Oct 28, 2022
This library provides an ASTERIX Frame(binary data) decoding/parsing(json,xml) capabilities for Go.

GoAsterix This library provides an ASTERIX Frame(binary data) decoding/parsing(json,xml) capabilities for Go. ASTERIX ASTERIX (All Purpose Structured

Dec 13, 2022
Golang source code parsing, usage like reflect package

gotype Golang source code parsing, usage like reflect package English 简体中文 Usage API Documentation Examples License Pouch is licensed under the MIT Li

Dec 9, 2022