Compare commits
No commits in common. "8f396a35decbb6f816a2b3d445c2622129af9573" and "8ab2c28343546e5de9b525bf42c9add21be15a51" have entirely different histories.
8f396a35de
...
8ab2c28343
79
README.adoc
79
README.adoc
@ -63,37 +63,35 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := expr.NewSimpleVarStore()
|
||||
ctx.SetVar("var", 4)
|
||||
ctx.SetValue("var", int64(4))
|
||||
|
||||
source := `(3-1)*(10/5) == var`
|
||||
|
||||
r := strings.NewReader(source)
|
||||
scanner := expr.NewScanner(r, expr.DefaultTranslations())
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
fmt.Println("Error parsing the expression:", err)
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
The above program is equivalent to the following one.
|
||||
|
||||
[source,go]
|
||||
----
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.portale-stac.it/go-pkg/expr"
|
||||
@ -101,37 +99,15 @@ import (
|
||||
|
||||
func main() {
|
||||
ctx := expr.NewSimpleVarStore()
|
||||
ctx.SetVar("var", 4)
|
||||
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)
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Here is another equivalent version.
|
||||
|
||||
[source,go]
|
||||
----
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.portale-stac.it/go-pkg/expr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
source := `(3-1)*(10/5) == var`
|
||||
|
||||
if result, err := expr.EvalStringA(source, expr.Arg{"var", 4}); err == nil {
|
||||
fmt.Printf("%q -> %v [%T]\n", source, result, result)
|
||||
} else {
|
||||
fmt.Println("Error calculating the expression:", err)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
@ -236,28 +212,7 @@ Currently, boolean operations are evaluated using _short cut evaluation_. This m
|
||||
====
|
||||
|
||||
==== List
|
||||
_Expr_ supports list of mixed-type values, also specified by normal expressions.
|
||||
|
||||
.List examples
|
||||
[source,go]
|
||||
----
|
||||
[1, 2, 3] // List of integers
|
||||
["one", "two", "three"] // List of strings
|
||||
["one", 2, false, 4.1] // List of mixed-types
|
||||
["one"+1, 2.0*(9-2)] // List of expressions
|
||||
[ [1,"one"], [2,"two"]] // List of lists
|
||||
----
|
||||
|
||||
|
||||
.List operators
|
||||
[cols="^2,^2,5,4"]
|
||||
|===
|
||||
| Symbol | Operation | Description | Examples
|
||||
|
||||
| [blue]`+` | _Join_ | Joins two lists | [blue]`[1,2] + [3]` _[ [1,2,3] ]_
|
||||
|
||||
| [blue]`-` | _Difference_ | Left list without elements in the right list | [blue]`[1,2,3] - [2]` _[ [1,3] ]_
|
||||
|===
|
||||
#TODO: List operations#
|
||||
|
||||
=== Variables
|
||||
#TODO: variables#
|
||||
|
2
ast.go
2
ast.go
@ -118,7 +118,7 @@ func (self *ast) eval(ctx ExprContext, preset bool) (result any, err error) {
|
||||
if self.forest != nil {
|
||||
for _, root := range self.forest {
|
||||
if result, err = root.compute(ctx); err == nil {
|
||||
ctx.setVar(control_last_result, result)
|
||||
ctx.SetVar(control_last_result, result)
|
||||
} else {
|
||||
//err = fmt.Errorf("error in expression nr %d: %v", i+1, err)
|
||||
break
|
||||
|
@ -33,7 +33,6 @@ type ExprContext interface {
|
||||
Clone() ExprContext
|
||||
GetVar(varName string) (value any, exists bool)
|
||||
SetVar(varName string, value any)
|
||||
setVar(varName string, value any)
|
||||
EnumVars(func(name string) (accept bool)) (varNames []string)
|
||||
EnumFuncs(func(name string) (accept bool)) (funcNames []string)
|
||||
GetFuncInfo(name string) ExprFunc
|
||||
|
12
control.go
12
control.go
@ -21,23 +21,23 @@ const (
|
||||
)
|
||||
|
||||
func initDefaultVars(ctx ExprContext) {
|
||||
ctx.setVar(control_bool_shortcut, true)
|
||||
ctx.setVar(control_import_path, init_import_path)
|
||||
ctx.SetVar(control_bool_shortcut, true)
|
||||
ctx.SetVar(control_import_path, init_import_path)
|
||||
}
|
||||
|
||||
func enable(ctx ExprContext, name string) {
|
||||
if strings.HasPrefix(name, "_") {
|
||||
ctx.setVar(name, true)
|
||||
ctx.SetVar(name, true)
|
||||
} else {
|
||||
ctx.setVar("_"+name, true)
|
||||
ctx.SetVar("_"+name, true)
|
||||
}
|
||||
}
|
||||
|
||||
func disable(ctx ExprContext, name string) {
|
||||
if strings.HasPrefix(name, "_") {
|
||||
ctx.setVar(name, false)
|
||||
ctx.SetVar(name, false)
|
||||
} else {
|
||||
ctx.setVar("_"+name, false)
|
||||
ctx.SetVar("_"+name, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
30
helpers.go
30
helpers.go
@ -20,8 +20,8 @@ func EvalString(ctx ExprContext, source string) (result any, err error) {
|
||||
}
|
||||
|
||||
type Arg struct {
|
||||
Name string
|
||||
Value any
|
||||
name string
|
||||
value any
|
||||
}
|
||||
|
||||
func EvalStringA(source string, args ...Arg) (result any, err error) {
|
||||
@ -31,23 +31,23 @@ func EvalStringA(source string, args ...Arg) (result any, err error) {
|
||||
func EvalStringV(source string, args []Arg) (result any, err error) {
|
||||
ctx := NewSimpleFuncStore()
|
||||
for _, arg := range args {
|
||||
if isFunc(arg.Value) {
|
||||
if f, ok := arg.Value.(FuncTemplate); ok {
|
||||
if isFunc(arg.value) {
|
||||
if f, ok := arg.value.(FuncTemplate); ok {
|
||||
functor := &simpleFunctor{f: f}
|
||||
ctx.RegisterFunc(arg.Name, functor, 0, -1)
|
||||
ctx.RegisterFunc(arg.name, functor, 0, -1)
|
||||
} else {
|
||||
err = fmt.Errorf("invalid function specification: %q", arg.Name)
|
||||
err = fmt.Errorf("invalid function specification: %q", arg.name)
|
||||
}
|
||||
} else if integer, ok := anyInteger(arg.Value); ok {
|
||||
ctx.SetVar(arg.Name, integer)
|
||||
} else if float, ok := anyFloat(arg.Value); ok {
|
||||
ctx.SetVar(arg.Name, float)
|
||||
} else if _, ok := arg.Value.(string); ok {
|
||||
ctx.SetVar(arg.Name, arg.Value)
|
||||
} else if _, ok := arg.Value.(bool); ok {
|
||||
ctx.SetVar(arg.Name, arg.Value)
|
||||
} else if integer, ok := anyInteger(arg.value); ok {
|
||||
ctx.SetVar(arg.name, integer)
|
||||
} else if float, ok := anyFloat(arg.value); ok {
|
||||
ctx.SetVar(arg.name, float)
|
||||
} else if _, ok := arg.value.(string); ok {
|
||||
ctx.SetVar(arg.name, arg.value)
|
||||
} else if _, ok := arg.value.(bool); ok {
|
||||
ctx.SetVar(arg.name, arg.value)
|
||||
} else {
|
||||
err = fmt.Errorf("unsupported type %T specified for item %q", arg.Value, arg.Name)
|
||||
err = fmt.Errorf("unsupported type %T specified for item %q", arg.value, arg.name)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ func exportVar(ctx ExprContext, name string, value any) {
|
||||
if name[0] == '@' {
|
||||
name = name[1:]
|
||||
}
|
||||
ctx.setVar(name, value)
|
||||
ctx.SetVar(name, value)
|
||||
}
|
||||
|
||||
func exportFunc(ctx ExprContext, name string, info ExprFunc) {
|
||||
@ -89,9 +89,9 @@ type funcDefFunctor struct {
|
||||
func (functor *funcDefFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
for i, p := range functor.params {
|
||||
if i < len(args) {
|
||||
ctx.setVar(p, args[i])
|
||||
ctx.SetVar(p, args[i])
|
||||
} else {
|
||||
ctx.setVar(p, nil)
|
||||
ctx.SetVar(p, nil)
|
||||
}
|
||||
}
|
||||
result, err = functor.expr.eval(ctx, false)
|
||||
|
@ -31,7 +31,7 @@ func evalAssign(ctx ExprContext, self *term) (v any, err error) {
|
||||
if functor, ok := v.(Functor); ok {
|
||||
ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
|
||||
} else {
|
||||
ctx.setVar(leftTerm.tk.source, v)
|
||||
ctx.SetVar(leftTerm.tk.source, v)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -75,7 +75,7 @@ func evalAssignCoalesce(ctx ExprContext, self *term) (v any, err error) {
|
||||
err = errCoalesceNoFunc(self.children[1])
|
||||
} else {
|
||||
v = rightValue
|
||||
ctx.setVar(leftTerm.source(), rightValue)
|
||||
ctx.SetVar(leftTerm.source(), rightValue)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -1,8 +1,6 @@
|
||||
// simple-var-store.go
|
||||
package expr
|
||||
|
||||
import "fmt"
|
||||
|
||||
type SimpleVarStore struct {
|
||||
varStore map[string]any
|
||||
}
|
||||
@ -25,16 +23,8 @@ func (ctx *SimpleVarStore) GetVar(varName string) (v any, exists bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func (ctx *SimpleVarStore) setVar(varName string, value any) {
|
||||
ctx.varStore[varName] = value
|
||||
}
|
||||
|
||||
func (ctx *SimpleVarStore) SetVar(varName string, value any) {
|
||||
if allowedValue, ok := fromGenericAny(value); ok {
|
||||
ctx.varStore[varName] = allowedValue
|
||||
} else {
|
||||
panic(fmt.Errorf("unsupported type %T of value %v", value, value))
|
||||
}
|
||||
ctx.varStore[varName] = value
|
||||
}
|
||||
|
||||
func (ctx *SimpleVarStore) EnumVars(acceptor func(name string) (accept bool)) (varNames []string) {
|
||||
|
18
utils.go
18
utils.go
@ -73,8 +73,6 @@ func anyInteger(v any) (i int64, ok bool) {
|
||||
i = int64(intval)
|
||||
case uint16:
|
||||
i = int64(intval)
|
||||
case uint64:
|
||||
i = int64(intval)
|
||||
case uint32:
|
||||
i = int64(intval)
|
||||
case int8:
|
||||
@ -91,22 +89,6 @@ func anyInteger(v any) (i int64, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func fromGenericAny(v any) (exprAny any, ok bool) {
|
||||
if exprAny, ok = v.(bool); ok {
|
||||
return
|
||||
}
|
||||
if exprAny, ok = v.(string); ok {
|
||||
return
|
||||
}
|
||||
if exprAny, ok = anyInteger(v); ok {
|
||||
return
|
||||
}
|
||||
if exprAny, ok = anyFloat(v); ok {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func anyFloat(v any) (float float64, ok bool) {
|
||||
ok = true
|
||||
switch floatval := v.(type) {
|
||||
|
Loading…
Reference in New Issue
Block a user