expr/README.adoc

5.5 KiB
Raw Blame History

Expr

1. Expr

Expr is a GO package capable of analysing, interpreting and calculating expressions.

Examples taken from parser_test.go
`1.0 / 2`                      // 0.5
`435 + 105 * 2 - 1`            // 644
`4 == (3-1)*(10/5)`            // true
`"uno" * (2+1)`                // `unounouno`
`2+3 but 5*2`                  // 10 (1)
`add(add(1+4),3+2,5*(3-2))`    // 15 (2)
`a=5; b=2; add(a, b*3)`        // 11 (3)
`two=func(){2}; two()`         // 2  (4)
`double=func(x){2*x}; a=4+1; two=func() {2}; (double(3+a) + 1) * two()`  // 34
`import("./test-funcs.expr"); (double(3+a) + 1) * two()`  // 34 (5)
`[1,2,"hello"]`                // Mixed types list
`[1,2]+[3]`                    // append list, result: [1,2,3]
`add([1,[2,2],3,2])`           // Deep list sum, result: 10 (2)
`[a=1,b=2,c=3] but a+b+c`      // 6
1 but operator.
2 The add() function definition may be changed in the future.
3 Multiple expression. Only the last expression value will returned.
4 Simple function definition: two() returns 2.
5 import() function imports expressions from the specified files. See file test-funcs.expr.

1.1. Usage

import (
	"fmt"
	"strings"

	"git.portale-stac.it/go-pkg/expr"
)

func main() {
	ctx := expr.NewSimpleVarStore()
	ctx.SetValue("var", int64(4))

	source := `(3-1)*(10/5) == var`

    r := strings.NewReader(source)
    scanner := expr.NewScanner(r, DefaultTranslations())
	parser := expr.NewParser(ctx)

	if ast, err := parser.parse(scanner); err == nil {
		if result, err := ast.eval(ctx); err == nil {
            fmt.Printf("%q -> %v [%T]\n", source, result, result)
        } else {
            fmt.Println("Error calculating the expression:", err)
        }
	} else {
        fmt.Println("Error parsing the expression:", err)
    }
}

The above program is equivalent to the following one.

import (
	"fmt"
	"git.portale-stac.it/go-pkg/expr"
)

func main() {
	ctx := expr.NewSimpleVarStore()
	ctx.SetValue("var", int64(4))

	source := `(3-1)*(10/5) == var`

    if result, err := expr.evalString(ctx, source); err == nil {
        fmt.Printf("%q -> %v [%T]\n", source, result, result)
    } else {
        fmt.Println("Error calculating the expression:", err)
    }
}

1.2. Data types

Expr supports numerical, string, relational, boolean expressions, and mixed-type lists.

1.2.1. Numbers

Numbers can be integers (GO int64) and float (GO float64). In mixed operations involving integers and floats, integers are automatically promoted to floats.

Table 1. Arithmetic operators
Symbol Operation Description Examples

+ / -

change sign

Change the sign of values

-1 [-1], -(+2) [-2]

+

sum

Add two values

-1 + 2 [1], 4 + 0.5 [4.5]

-

subtracion

Subtract the right value from the left one

3 - 1 [2], 4 - 0.5 [3.5]

*

product

Multiply two values

-1 * 2 [-2], 4 * 0.5 [2.0]

/

Division

Divide the left value by the right one

-1 / 2 [0], 1.0 / 2 [0.5]

./

Float division

Force float division

-1 ./ 2 [-0.5]

%

Modulo

Remainder of the integer division

5 % 2 [1]

1.2.2. String

Strings are character sequences enclosed between two double quote ". Example: "Im a string".

Some arithmetic operators can also be used with strings.

1.2.3. Boolean

Boolean data type has two values only: true and false. Relational and Boolean expressions produce a Boolean values.

Table 2. Relational operators
Symbol Operation Description Examples

==

Equal

True if the left value is equal to the right one

5 == 2 [false], "a" == "a" [true]

!=

Not Equal

True if the left value is NOT equal to the right one

5 != 2 [true], "a" != "a" [false]

<

Less

True if the left value is less than the right one

5 < 2 [false], "a" < "b" [true]

<=

Less or Equal

True if the left value is less than or equal to the right one

5 <= 2 [false], "b" <= "b" [true]

>

Greater

True if the left value is greater than the right one

5 > 2 [true], "a" < "b" [false]

>=

Greater or Equal

True if the left value is greater than or equal to the right one

5 >= 2 [true], "b" <= "b" [true]

Table 3. Boolean operators
Symbol Operation Description Examples

NOT

Not

True if the right value is false

NOT true [false], NOT (2 < 1) [true]

AND / &&

And

True if both left and right values are true

false && true [false], "a" < "b" AND NOT (2 < 1) [true]

OR / ||

Or

True if at least one of the left and right values integers true

false or true [true], "a" == "b" OR (2 == 1) [false]