expr

package module
v1.4.1 Latest Latest
Warning

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

Go to latest
Published: Jan 1, 2024 License: Apache-2.0 Imports: 10 Imported by: 0

README

expr

GitHub Workflow Status Go Dev Reference CodeCov Go Report Card

Expr is a simple, lightweight and performant programming toolkit for evaluating basic mathematical expression and boolean expression. The resulting value is one of these following primitive types: string, boolean, numerical (complex, float, integer).

Supported Numerical Notations

- Binary (base-2)       : 0b1011
- Octal (base-8)        : 0o13 or 013
- Decimal (base-10)     : 11
- Hexadecimal (base-16) : 0xB 
- Scientific            : 11e0

Expression Examples

"1 + 1"             -> 2
"1.0 / 2"           -> 0.5
"2 < 2 + 2"         -> true
"true && !false"    -> true
"4 << 10"           -> 4096
"0b0100 << 0b1010"  -> 4096 (0b1000000000000)
"0x4 << 0xA"        -> 4096 (0x1000)
"0o4 << 0o12"       -> 4096 (0o10000)
"0b1000 | 0b1001"   -> 9 (0b1001)
"(2+1i) + (2+2i)"   -> (4+3i)
"0x4 << 0xA > 1024" -> true

Usage

Bind

For binding variables into expr string, see Bind

Explain

For explaining step-by-step operations, see Explain

Any

  • Any parses the given expr string into any type it returns as a result. e.g:
    • "1 < 2" -> true
    • "true || false" -> true
    • "2 + 2" -> 4
    • "4 << 10" -> 4906
    • "2.2 + 2" -> 4.2
    • "(2+1i) + (2+2i)" -> (4+3i)
    • ""abc" == "abc"" -> true
    • ""abc"" -> "abc"
  • Supported operators:
    • Comparison: [==, !=, <, <=, >, >=]
    • Logical: [&&, ||, !]
    • Arithmetic: [+, -, *, /, %] (% operator does not work for complex number)
    • Bitwise: [&, |, ^, &^, <<, >>] (only work for integer values)
    str := "(2+1i) + (2+2i)"
    v, err := expr.Any(str)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%v", v) // (4+3i)

Boolean

  • Bool parses the given expr string into boolean as a result. e.g:
    • "1 < 2" -> true
    • "1 > 2" -> false
    • "true || false" -> true
    • "true && !false" -> true
  • Arithmetic operation are supported. e.g:
    • "1 + 2 > 1" -> true
    • "(1 * 10) > -2" -> true
  • Supported operators:
    • Comparison: [==, !=, <, <=, >, >=]
    • Logical: [&&, ||, !]
    • Arithmetic: [+, -, *, /, %] (% operator does not work for complex number)
    • Bitwise: [&, |, ^, &^, <<, >>] (only work for integer values)
    str := "((1 < 2 && 3 > 4) || 1 == 1) && 4 < 5"
    v, err := expr.Bool(str)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%t", v) // true

Complex128

  • Complex128 parses the given expr string into complex128 as a result. e.g:
    • "(2+1i) + (2+2i)" -> (4+3i)
    • "(2.2+1i) + 2" -> (4.2+1i)
    • "2 + 2" -> (4+0i)
  • Supported operators:
    • Arithmetic: [+, -, *, /]
    str := "(2+1i) + (2+2i)"
    v, err := expr.Complex128(str)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%f", v) // (4+3i)

Float64

  • Float64 parses the given expr string into float64 as a result. e.g:
    • "2 + 2" -> 4
    • "2.2 + 2" -> 4.2
    • "10 * -5 + (-5.5)" -> -55.5
    • "10.0 % 2.6" -> 2.2
  • Supported operators:
    • Arithmetic: [+, -, *, /, %]
    str := "((2 * 2) * (8 + 2) * 2) + 2.56789"
    v, err := expr.Float64(str)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%f", v) // 82.56789

Int64

  • Int64 parses the given expr string into int64 as a result. e.g:
    • "2 + 2" -> 4
    • "2.2 + 2" -> 4
    • "10 + ((-5 * -10) / -10) - 2" -> 3
  • Supported operators:
    • Arithmetic: [+, -, *, /, %]
    • Bitwise: [&, |, ^, &^, <<, >>]
    str := "((2 * 2) * (8 + 2) * 2) + 2.56789"
    v, err := expr.Int64(str)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%d", v) // 82

Int64Strict

  • Int64Strict is shorthand for Int64(str) but when x / y and y == 0, it will return ErrIntegerDividedByZero
    str := "12 + 24 - 10/0"
    v, err := expr.Int64Strict(str)
    if err != nil {
        // err == ErrIntegerDividedByZero
    }
    fmt.Printf("%d", v) // 0

Int

  • Int is shorthand for Int64(str) with its result will be converted into int.
    str := "1 + 10"
    v, err := expr.Int(str)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%d", v) // 11

License

Expr is released under Apache Licence 2.0

Documentation

Overview

Package expr is the core of this library, it contains implementation to parse and evaluate mathematical and boolean expression.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnsupportedOperator is error unsupported operator
	ErrUnsupportedOperator = errors.New("unsupported operator")
	// ErrUnaryOperation occurs when unary operation failed
	ErrUnaryOperation = errors.New("unary operation")
	// ErrArithmeticOperation occurs when either x or y is not int or float
	ErrArithmeticOperation = errors.New("arithmetic operation")
	// ErrIntegerDividedByZero occurs when x/y and y equals to 0 and AllowIntDivByZero == false (default).
	// Go does not allow integer to be divided by zero by default.
	ErrIntegerDividedByZero = errors.New("integer divided by zero")
	// ErrInvalidBitwiseOperation occurs when neither x nor y is an int
	ErrBitwiseOperation = errors.New("bitwise operation")
	// ErrBitwiseOperation occurs when either x or y is boolean and given operator is neither '==' nor '!='
	ErrComparisonOperation = errors.New("comparison operation")
	// ErrLogicalOperation occurs when either x or y is not boolean
	ErrLogicalOperation = errors.New("logical operation")
	// ErrValueTypeMismatch occurs when the result of expr evaluation is not match with desired type
	ErrValueTypeMismatch = errors.New("returned value's type is not match with desired type")
)

Functions

func Any added in v1.2.0

func Any(str string) (interface{}, error)

Any parses the given expr string into any type it returns as a result. e.g:

  • "1 < 2" -> true
  • "true || false" -> true
  • "2 + 2" -> 4
  • "4 << 10" -> 4906
  • "2.2 + 2" -> 4.2
  • "(2+1i) + (2+2i)" -> (4+3i)
  • ""abc" == "abc"" -> true
  • ""abc"" -> "abc"

- Supported operators:

  • Comparison: [==, !=, <, <=, >, >=]
  • Logical: [&&, ||, !]
  • Arithmetic: [+, -, *, /, %] (% operator does not work for complex number)
  • Bitwise: [&, |, ^, &^, <<, >>] (only work for integer values)
Example
package main

import (
	"fmt"

	"github.com/muktihari/expr"
)

func main() {
	values := []string{
		"1 + 2 + 3 + 4 + 5",
		"(2 + 2) * 4 / 4",
		"((2 + 2) * 4 / 4) * 10.5 + 4.234567",
		"((2 + 2) * 4 / 4) * 10.7 + 4.234567 * (50 + 50)",
		"(10+5i) + (10+7i)",
		"(2+3i) - (2+2i)",
		"(2+2i) * (2+2i)",
		"(2+2i) / (2+2i)",
		"4 % 2",
		"1 + 1 + (4 == 2)",
		"(1 + 1",
	}

	for _, value := range values {
		v, err := expr.Any(value)
		fmt.Println(v, err)
	}

}
Output:

15 <nil>
4 <nil>
46.234567 <nil>
466.2567 <nil>
(20+12i) <nil>
(0+1i) <nil>
(0+8i) <nil>
(1+0i) <nil>
0 <nil>
<nil> result of "(4 == 2)" is "false" which is not a number [pos: 10]: arithmetic operation
<nil> 1:7: expected ')', found newline

func Bool

func Bool(str string) (bool, error)

Bool parses the given expr string into boolean as a result. e.g:

  • "1 < 2" -> true
  • "1 > 2" -> false
  • "true || false" -> true
  • "true && !false" -> true

- Arithmetic operation are supported. e.g:

  • "1 + 2 > 1" -> true
  • "(1 * 10) > -2" -> true

- Supported operators:

  • Comparison: [==, !=, <, <=, >, >=]
  • Logical: [&&, ||, !]
  • Arithmetic: [+, -, *, /, %] (% operator does not work for complex number)
  • Bitwise: [&, |, ^, &^, <<, >>] (only work for integer values)
Example
package main

import (
	"fmt"

	"github.com/muktihari/expr"
)

func main() {
	values := []string{
		"1 < 2 && 3 < 4 && ( 1==1 || 12 > 4)",
		"\"expr\" == \"expr\" && \"Expr\" != \"expr\"",
		"\"expr\" == \"expr\" && \"Expr\" == \"expr\"",
		"(\"expr\" == \"expr\" && \"Expr\" == \"expr\") || 1 ==1 ",
		"(\"expr\" == \"expr\" && \"Expr\" == \"expr\") || true == true ",
		"(\"expr\" == \"expr\" && \"Expr\" == \"expr\") || true == false ",
		"1 + 2 > 1 * 2",
		"1 + 2 < (2 + 2) * 10",
		"1 < 1 <",
		"-1 > -10",
		"true",
		"!false",
		"!false || false",
	}

	for _, value := range values {
		v, err := expr.Bool(value)
		fmt.Println(v, err)
	}

}
Output:

true <nil>
true <nil>
false <nil>
true <nil>
true <nil>
false <nil>
true <nil>
true <nil>
false 1:8: expected operand, found 'EOF'
true <nil>
true <nil>
true <nil>
true <nil>

func Complex128 added in v1.2.0

func Complex128(str string) (complex128, error)

Complex128 parses the given expr string into complex128 as a result. e.g:

  • "(2+1i) + (2+2i)" -> (4+3i)
  • "(2.2+1i) + 2" -> (4.2+1i)
  • "2 + 2" -> (4+0i)

- Supported operators:

  • Arithmetic: [+, -, *, /]
Example
package main

import (
	"fmt"

	"github.com/muktihari/expr"
)

func main() {
	values := []string{
		"1 + 2 + 3 + 4 + 5",
		"(2 + 2) * 4 / 4",
		"((2 + 2) * 4 / 4) * 10.5 + 4.234567",
		"((2 + 2) * 4 / 4) * 10.7 + 4.234567 * (50 + 50)",
		"(10+5i) + (10+7i)",
		"(2+3i) - (2+2i)",
		"(2+2i) * (2+2i)",
		"(2+2i) / (2+2i)",
		"4 % 2",
		"1 + 1 + (4 == 2)",
		"(1 + 1",
	}

	for _, value := range values {
		v, err := expr.Complex128(value)
		fmt.Println(v, err)
	}

}
Output:

(15+0i) <nil>
(4+0i) <nil>
(46.234567+0i) <nil>
(466.2567+0i) <nil>
(20+12i) <nil>
(0+1i) <nil>
(0+8i) <nil>
(1+0i) <nil>
(0+0i) operator "%" is not supported to do arithmetic on complex number [pos: 3]: arithmetic operation
(0+0i) result of "(4 == 2)" is "false" which is not a number [pos: 10]: arithmetic operation
(0+0i) 1:7: expected ')', found newline

func Float64

func Float64(str string) (float64, error)

Float64 parses the given expr string into float64 as a result. e.g:

  • "2 + 2" -> 4
  • "2.2 + 2" -> 4.2
  • "10 * -5 + (-5.5)" -> -55.5
  • "10.0 % 2.6" -> 2.2

- Supported operators:

  • Arithmetic: [+, -, *, /, %]
Example
package main

import (
	"fmt"

	"github.com/muktihari/expr"
)

func main() {
	values := []string{
		"1 + 2 + 3 + 4 + 5",
		"(2 + 2) * 4 / 4",
		"((2 + 2) * 4 / 4) * 10",
		"((2 + 2) * 4 / 4) * 10 + 2",
		"((2 + 2) * 4 / 4) * 10 + 2 - 2",
		"((2 + 2) * 4 / 4) * 10 + 4.234567",
		"((2 + 2) * 4 / 4) * 10.5 + 4.234567",
		"((2 + 2) * 4 / 4) * 10.7 + 4.234567 * (50 + 50)",
		"4 % 2",
		"1 + 1 + (4 == 2)",
		"(1 + 1",
	}

	for _, value := range values {
		v, err := expr.Float64(value)
		fmt.Println(v, err)
	}

}
Output:

15 <nil>
4 <nil>
40 <nil>
42 <nil>
40 <nil>
44.234567 <nil>
46.234567 <nil>
466.2567 <nil>
0 <nil>
0 result of "(4 == 2)" is "false" which is not a number [pos: 10]: arithmetic operation
0 1:7: expected ')', found newline

func Int

func Int(str string) (int, error)

Int is shorthand for Int64(str) with its result will be converted into int.

Example
package main

import (
	"fmt"

	"github.com/muktihari/expr"
)

func main() {
	values := []string{
		"1 + 2 + 3 + 4 + 5",
		"(2 + 2) * 4 / 4",
		"(2 + 2) - 2 * 2",
	}

	for _, value := range values {
		v, err := expr.Int64(value)
		fmt.Println(v, err)
	}

}
Output:

15 <nil>
4 <nil>
0 <nil>

func Int64 added in v1.2.0

func Int64(str string) (int64, error)

- Int64 parses the given expr string into int64 as a result. e.g:

  • "2 + 2" -> 4
  • "2.2 + 2" -> 4
  • "10 + ((-5 * -10) / -10) - 2" -> 3

- Supported operators:

  • Arithmetic: [+, -, *, /, %]
  • Bitwise: [&, |, ^, &^, <<, >>]
Example
package main

import (
	"fmt"

	"github.com/muktihari/expr"
)

func main() {
	values := []string{
		"1 + 2 + 3 + 4 + 5",
		"(2 + 2) * 4 / 4",
		"((2 + 2) * 4 / 4) * 10",
		"((2 + 2) * 4 / 4) * 10 + 2",
		"((2 + 2) * 4 / 4) * 10 + 2 - 2",
		"((2 + 2) * 4 / 4) * 10 + 4.234567",
		"((2 + 2) * 4 / 4) * 10.5 + 4.234567",
		"((2 + 2) * 4 / 4) * 10.7 + 4.234567 * (50 + 50)",
		"15 % 4",
		"1 + 1 + (4 == 2)",
		"(1 * 2))",
	}

	for _, value := range values {
		v, err := expr.Int64(value)
		fmt.Println(v, err)
	}

}
Output:

15 <nil>
4 <nil>
40 <nil>
42 <nil>
40 <nil>
44 <nil>
44 <nil>
440 <nil>
3 <nil>
0 result of "(4 == 2)" is "false" which is not a number [pos: 10]: arithmetic operation
0 1:8: expected 'EOF', found ')'

func Int64Strict added in v1.2.0

func Int64Strict(str string) (int64, error)

Int64Strict is shorthand for Int64(str) but when x / y and y == 0, it will return ErrIntegerDividedByZero

Example
package main

import (
	"fmt"

	"github.com/muktihari/expr"
)

func main() {
	values := []string{
		"(2 + 2) * 4 / 4",
		"(2 + 2) - 2 / 0",
	}

	for _, value := range values {
		v, err := expr.Int64Strict(value)
		fmt.Println(v, err)
	}

}
Output:

4 <nil>
0 could not divide x with zero y, allowIntegerDividedByZero == false [pos: 15]: integer divided by zero

Types

type Kind added in v1.2.0

type Kind byte

Kind of value (value's type)

const (
	KindIllegal Kind = iota
	KindBoolean      // true false

	KindInt   // 12345
	KindFloat // 123.45
	KindImag  // 123.45i

	KindString // "abc" 'abc' `abc`
)

func (Kind) String added in v1.2.0

func (k Kind) String() string

type NumericType added in v1.2.0

type NumericType byte

NumericType determines what type of number represented in the expr string

const (
	NumericTypeAuto    NumericType = iota // [1 * 2 = 2]       [1 * 2.5 = 2.5]
	NumericTypeComplex                    // [1 * 2 = 2+0i]    [1 * (2+2i) = (2+2i)]    [(1+2i) * (2+2i) = (-2+6i)]
	NumericTypeFloat                      // [1 * 2 = 2.0]     [1 * 2.5 = 2.5]
	NumericTypeInt                        // [1 * 2 = 2,]      [1 * 2.5 = 2]
)

type Option added in v1.2.0

type Option interface {
	// contains filtered or unexported methods
}

func WithAllowIntegerDividedByZero added in v1.2.0

func WithAllowIntegerDividedByZero(v bool) Option

func WithNumericType added in v1.2.0

func WithNumericType(v NumericType) Option

type SyntaxError added in v1.2.0

type SyntaxError struct {
	Msg string
	Pos int
	Err error
}

SyntaxError is syntax error

func (SyntaxError) Error added in v1.2.0

func (e SyntaxError) Error() string

func (SyntaxError) Unwrap added in v1.2.0

func (e SyntaxError) Unwrap() error

type Visitor added in v1.2.0

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

Visitor satisfies ast.Visitor interface.

func NewVisitor added in v1.2.0

func NewVisitor(opts ...Option) *Visitor

NewVisitor create new Visitor. If Option is not specified, these following default options will be set:

  • allowIntegerDividedByZero: true
  • numericType: NumericTypeAuto

func (*Visitor) Err added in v1.2.0

func (v *Visitor) Err() error

Err returns visitor's error

func (*Visitor) Kind added in v1.2.0

func (v *Visitor) Kind() Kind

Kind returns visitor's kind

func (*Visitor) Value added in v1.2.0

func (v *Visitor) Value() string

Value returns visitor's value in string

func (*Visitor) ValueAny added in v1.4.0

func (v *Visitor) ValueAny() interface{}

ValueAny returns visitor's value interface{}

func (*Visitor) Visit added in v1.2.0

func (v *Visitor) Visit(node ast.Node) ast.Visitor

Directories

Path Synopsis
Package bind is an helper to bind variable values into the string expression.
Package bind is an helper to bind variable values into the string expression.
exp
Package exp contains experimental projects.
Package exp contains experimental projects.
explain
Package explain is a standalone package aimed to explain step by step operation in expr.
Package explain is a standalone package aimed to explain step by step operation in expr.
internal
conv
Package conv contains converter function(s)
Package conv contains converter function(s)

Jump to

Keyboard shortcuts

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