Compare commits
3 Commits
v0.3.0
...
95605232ab
| Author | SHA1 | Date | |
|---|---|---|---|
| 95605232ab | |||
| 8f396a35de | |||
| bd323efedf |
+47
-8
@@ -68,7 +68,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx := expr.NewSimpleVarStore()
|
ctx := expr.NewSimpleVarStore()
|
||||||
ctx.SetVar("var", int64(4))
|
ctx.SetVar("var", 4)
|
||||||
|
|
||||||
source := `(3-1)*(10/5) == var`
|
source := `(3-1)*(10/5) == var`
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx := expr.NewSimpleVarStore()
|
ctx := expr.NewSimpleVarStore()
|
||||||
ctx.SetVar("var", int64(4))
|
ctx.SetVar("var", 4)
|
||||||
|
|
||||||
source := `(3-1)*(10/5) == var`
|
source := `(3-1)*(10/5) == var`
|
||||||
|
|
||||||
@@ -121,14 +121,13 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr"
|
"git.portale-stac.it/go-pkg/expr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
source := `(3-1)*(10/5) == var`
|
source := `(3-1)*(10/5) == var`
|
||||||
|
|
||||||
if result, err := expr.EvalStringA(source, expr.Arg{"var", int64(4)}); err == nil {
|
if result, err := expr.EvalStringA(source, expr.Arg{"var", 4}); err == nil {
|
||||||
fmt.Printf("%q -> %v [%T]\n", source, result, result)
|
fmt.Printf("%q -> %v [%T]\n", source, result, result)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Error calculating the expression:", err)
|
fmt.Println("Error calculating the expression:", err)
|
||||||
@@ -136,6 +135,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
=== Concepts and terminology
|
||||||
|
#TODO#
|
||||||
|
|
||||||
=== Data types
|
=== Data types
|
||||||
_Expr_ supports numerical, string, relational, boolean expressions, and mixed-type lists.
|
_Expr_ supports numerical, string, relational, boolean expressions, and mixed-type lists.
|
||||||
|
|
||||||
@@ -237,10 +239,39 @@ Currently, boolean operations are evaluated using _short cut evaluation_. This m
|
|||||||
====
|
====
|
||||||
|
|
||||||
==== List
|
==== List
|
||||||
#TODO: List operations#
|
_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] ]_
|
||||||
|
|===
|
||||||
|
|
||||||
=== Variables
|
=== Variables
|
||||||
#TODO: variables#
|
A variable is an identifier with an assigned value. Variables are stored in the object that implements the _ExprContext_ interface.
|
||||||
|
|
||||||
|
.Examples
|
||||||
|
[source,go]
|
||||||
|
----
|
||||||
|
a=1
|
||||||
|
x = 5.2 * (9-3)
|
||||||
|
x = 1; y = 2*x
|
||||||
|
----
|
||||||
|
|
||||||
=== Other operations
|
=== Other operations
|
||||||
|
|
||||||
@@ -326,12 +357,15 @@ The table below shows all supported operators by decreasing priorities.
|
|||||||
.2+|*AND*| [blue]`and` | _Infix_ | _and_ | _boolean_ "and" _boolean_ -> _boolean_
|
.2+|*AND*| [blue]`and` | _Infix_ | _and_ | _boolean_ "and" _boolean_ -> _boolean_
|
||||||
| [blue]`&&` | _Infix_ | _and_ | _boolean_ "&&" _boolean_ -> _boolean_
|
| [blue]`&&` | _Infix_ | _and_ | _boolean_ "&&" _boolean_ -> _boolean_
|
||||||
.2+|*OR*| [blue]`or` | _Infix_ | _or_ | _boolean_ "or" _boolean_ -> _boolean_
|
.2+|*OR*| [blue]`or` | _Infix_ | _or_ | _boolean_ "or" _boolean_ -> _boolean_
|
||||||
| [blue]`||` | _Infix_ | _or_ | _boolean_ "||" _boolean_ -> _boolean_
|
| [blue]`\|\|` | _Infix_ | _or_ | _boolean_ "\|\|" _boolean_ -> _boolean_
|
||||||
.1+|*ASSIGN*| [blue]`=` | _Infix_ | _assignment_ | _identifier_ "=" _any_ -> _any_
|
.1+|*ASSIGN*| [blue]`=` | _Infix_ | _assignment_ | _identifier_ "=" _any_ -> _any_
|
||||||
.1+|*BUT*| [blue]`but` | _Infix_ | _but_ | _any_ "but" _any_ -> _any_
|
.1+|*BUT*| [blue]`but` | _Infix_ | _but_ | _any_ "but" _any_ -> _any_
|
||||||
|===
|
|===
|
||||||
|
|
||||||
=== Functions
|
=== Functions
|
||||||
|
Functions in _Expr_ are very similar to functions in many programming languages.
|
||||||
|
|
||||||
|
In _Expr_ functions compute values in a local context (scope) that do not make effects on the calling context. This is the normal behavior. Using the reference operator [blue]`@` it is possibile to export local definition to the calling context.
|
||||||
|
|
||||||
==== Function calls
|
==== Function calls
|
||||||
#TODO: function calls operations#
|
#TODO: function calls operations#
|
||||||
@@ -339,8 +373,13 @@ The table below shows all supported operators by decreasing priorities.
|
|||||||
==== Function definitions
|
==== Function definitions
|
||||||
#TODO: function definitions operations#
|
#TODO: function definitions operations#
|
||||||
|
|
||||||
==== Builtins
|
=== Builtins
|
||||||
#TODO: builtins#
|
#TODO: builtins#
|
||||||
|
|
||||||
|
==== Builtin functions
|
||||||
|
|
||||||
|
==== [blue]_import()_
|
||||||
|
[blue]_import([grey]#<source-file>#)_ loads the multi-expression contained in the specified source and returns its value.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ func (self *ast) eval(ctx ExprContext, preset bool) (result any, err error) {
|
|||||||
if self.forest != nil {
|
if self.forest != nil {
|
||||||
for _, root := range self.forest {
|
for _, root := range self.forest {
|
||||||
if result, err = root.compute(ctx); err == nil {
|
if result, err = root.compute(ctx); err == nil {
|
||||||
ctx.SetVar(control_last_result, result)
|
ctx.setVar(control_last_result, result)
|
||||||
} else {
|
} else {
|
||||||
//err = fmt.Errorf("error in expression nr %d: %v", i+1, err)
|
//err = fmt.Errorf("error in expression nr %d: %v", i+1, err)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type ExprContext interface {
|
|||||||
Clone() ExprContext
|
Clone() ExprContext
|
||||||
GetVar(varName string) (value any, exists bool)
|
GetVar(varName string) (value any, exists bool)
|
||||||
SetVar(varName string, value any)
|
SetVar(varName string, value any)
|
||||||
|
setVar(varName string, value any)
|
||||||
EnumVars(func(name string) (accept bool)) (varNames []string)
|
EnumVars(func(name string) (accept bool)) (varNames []string)
|
||||||
EnumFuncs(func(name string) (accept bool)) (funcNames []string)
|
EnumFuncs(func(name string) (accept bool)) (funcNames []string)
|
||||||
GetFuncInfo(name string) ExprFunc
|
GetFuncInfo(name string) ExprFunc
|
||||||
|
|||||||
+6
-6
@@ -21,23 +21,23 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func initDefaultVars(ctx ExprContext) {
|
func initDefaultVars(ctx ExprContext) {
|
||||||
ctx.SetVar(control_bool_shortcut, true)
|
ctx.setVar(control_bool_shortcut, true)
|
||||||
ctx.SetVar(control_import_path, init_import_path)
|
ctx.setVar(control_import_path, init_import_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func enable(ctx ExprContext, name string) {
|
func enable(ctx ExprContext, name string) {
|
||||||
if strings.HasPrefix(name, "_") {
|
if strings.HasPrefix(name, "_") {
|
||||||
ctx.SetVar(name, true)
|
ctx.setVar(name, true)
|
||||||
} else {
|
} else {
|
||||||
ctx.SetVar("_"+name, true)
|
ctx.setVar("_"+name, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func disable(ctx ExprContext, name string) {
|
func disable(ctx ExprContext, name string) {
|
||||||
if strings.HasPrefix(name, "_") {
|
if strings.HasPrefix(name, "_") {
|
||||||
ctx.SetVar(name, false)
|
ctx.setVar(name, false)
|
||||||
} else {
|
} else {
|
||||||
ctx.SetVar("_"+name, false)
|
ctx.setVar("_"+name, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -57,7 +57,7 @@ func exportVar(ctx ExprContext, name string, value any) {
|
|||||||
if name[0] == '@' {
|
if name[0] == '@' {
|
||||||
name = name[1:]
|
name = name[1:]
|
||||||
}
|
}
|
||||||
ctx.SetVar(name, value)
|
ctx.setVar(name, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportFunc(ctx ExprContext, name string, info ExprFunc) {
|
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) {
|
func (functor *funcDefFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||||
for i, p := range functor.params {
|
for i, p := range functor.params {
|
||||||
if i < len(args) {
|
if i < len(args) {
|
||||||
ctx.SetVar(p, args[i])
|
ctx.setVar(p, args[i])
|
||||||
} else {
|
} else {
|
||||||
ctx.SetVar(p, nil)
|
ctx.setVar(p, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result, err = functor.expr.eval(ctx, false)
|
result, err = functor.expr.eval(ctx, false)
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ func evalAssign(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
if functor, ok := v.(Functor); ok {
|
if functor, ok := v.(Functor); ok {
|
||||||
ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
|
ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
|
||||||
} else {
|
} else {
|
||||||
ctx.SetVar(leftTerm.tk.source, v)
|
ctx.setVar(leftTerm.tk.source, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ func evalAssignCoalesce(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
err = errCoalesceNoFunc(self.children[1])
|
err = errCoalesceNoFunc(self.children[1])
|
||||||
} else {
|
} else {
|
||||||
v = rightValue
|
v = rightValue
|
||||||
ctx.SetVar(leftTerm.source(), rightValue)
|
ctx.setVar(leftTerm.source(), rightValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
+11
-1
@@ -1,6 +1,8 @@
|
|||||||
// simple-var-store.go
|
// simple-var-store.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
type SimpleVarStore struct {
|
type SimpleVarStore struct {
|
||||||
varStore map[string]any
|
varStore map[string]any
|
||||||
}
|
}
|
||||||
@@ -23,10 +25,18 @@ func (ctx *SimpleVarStore) GetVar(varName string) (v any, exists bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *SimpleVarStore) SetVar(varName string, value any) {
|
func (ctx *SimpleVarStore) setVar(varName string, value any) {
|
||||||
ctx.varStore[varName] = value
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *SimpleVarStore) EnumVars(acceptor func(name string) (accept bool)) (varNames []string) {
|
func (ctx *SimpleVarStore) EnumVars(acceptor func(name string) (accept bool)) (varNames []string) {
|
||||||
varNames = make([]string, 0)
|
varNames = make([]string, 0)
|
||||||
for name := range ctx.varStore {
|
for name := range ctx.varStore {
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ func anyInteger(v any) (i int64, ok bool) {
|
|||||||
i = int64(intval)
|
i = int64(intval)
|
||||||
case uint16:
|
case uint16:
|
||||||
i = int64(intval)
|
i = int64(intval)
|
||||||
|
case uint64:
|
||||||
|
i = int64(intval)
|
||||||
case uint32:
|
case uint32:
|
||||||
i = int64(intval)
|
i = int64(intval)
|
||||||
case int8:
|
case int8:
|
||||||
@@ -89,6 +91,22 @@ func anyInteger(v any) (i int64, ok bool) {
|
|||||||
return
|
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) {
|
func anyFloat(v any) (float float64, ok bool) {
|
||||||
ok = true
|
ok = true
|
||||||
switch floatval := v.(type) {
|
switch floatval := v.(type) {
|
||||||
|
|||||||
Reference in New Issue
Block a user