Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4755774edd | |||
| d215d837f6 | |||
| ad3c1e5a60 | |||
| d6bf5ee500 | |||
| 4b176eb868 |
@@ -6,6 +6,7 @@ package expr
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
TypeAny = "any"
|
TypeAny = "any"
|
||||||
|
TypeNil = "nil"
|
||||||
TypeBoolean = "boolean"
|
TypeBoolean = "boolean"
|
||||||
TypeFloat = "float"
|
TypeFloat = "float"
|
||||||
TypeFraction = "fraction"
|
TypeFraction = "fraction"
|
||||||
@@ -15,6 +16,7 @@ const (
|
|||||||
TypeNumber = "number"
|
TypeNumber = "number"
|
||||||
TypePair = "pair"
|
TypePair = "pair"
|
||||||
TypeString = "string"
|
TypeString = "string"
|
||||||
|
TypeDict = "dict"
|
||||||
TypeListOf = "list-of-"
|
TypeListOf = "list-of-"
|
||||||
TypeListOfStrings = "list-of-strings"
|
TypeListOfStrings = "list-of-strings"
|
||||||
)
|
)
|
||||||
|
|||||||
+139
-74
@@ -6,12 +6,14 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dataCursor struct {
|
type dataCursor struct {
|
||||||
ds map[string]Functor
|
ds map[string]Functor
|
||||||
ctx ExprContext
|
ctx ExprContext
|
||||||
initState bool // true if no item has prodiced yet (this replace di initial Next() call in the contructor)
|
initState bool // true if no item has produced yet (this replace di initial Next() call in the contructor)
|
||||||
|
// cursorValid bool // true if resource is nil or if clean has not yet been called
|
||||||
index int
|
index int
|
||||||
count int
|
count int
|
||||||
current any
|
current any
|
||||||
@@ -26,6 +28,7 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da
|
|||||||
dc = &dataCursor{
|
dc = &dataCursor{
|
||||||
ds: ds,
|
ds: ds,
|
||||||
initState: true,
|
initState: true,
|
||||||
|
// cursorValid: true,
|
||||||
index: -1,
|
index: -1,
|
||||||
count: 0,
|
count: 0,
|
||||||
current: nil,
|
current: nil,
|
||||||
@@ -36,7 +39,6 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da
|
|||||||
cleanFunc: ds[CleanName],
|
cleanFunc: ds[CleanName],
|
||||||
resetFunc: ds[ResetName],
|
resetFunc: ds[ResetName],
|
||||||
}
|
}
|
||||||
//dc.Next()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +79,7 @@ func (dc *dataCursor) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dc *dataCursor) HasOperation(name string) (exists bool) {
|
func (dc *dataCursor) HasOperation(name string) (exists bool) {
|
||||||
exists = name == IndexName
|
exists = slices.Contains([]string{CleanName, ResetName, CurrentName, IndexName}, name)
|
||||||
if !exists {
|
if !exists {
|
||||||
f, ok := dc.ds[name]
|
f, ok := dc.ds[name]
|
||||||
exists = ok && isFunctor(f)
|
exists = ok && isFunctor(f)
|
||||||
@@ -88,63 +90,83 @@ func (dc *dataCursor) HasOperation(name string) (exists bool) {
|
|||||||
func (dc *dataCursor) CallOperation(name string, args map[string]any) (value any, err error) {
|
func (dc *dataCursor) CallOperation(name string, args map[string]any) (value any, err error) {
|
||||||
if name == IndexName {
|
if name == IndexName {
|
||||||
value = int64(dc.Index())
|
value = int64(dc.Index())
|
||||||
|
} else if name == CleanName {
|
||||||
|
err = dc.Clean()
|
||||||
|
} else if name == ResetName {
|
||||||
|
err = dc.Reset()
|
||||||
} else if functor, ok := dc.ds[name]; ok && isFunctor(functor) {
|
} else if functor, ok := dc.ds[name]; ok && isFunctor(functor) {
|
||||||
if functor == dc.cleanFunc {
|
ctx := cloneContext(dc.ctx)
|
||||||
value, err = dc.Clean()
|
value, err = functor.InvokeNamed(ctx, name, args)
|
||||||
} else if functor == dc.resetFunc {
|
exportObjects(dc.ctx, ctx)
|
||||||
value, err = dc.Reset()
|
|
||||||
} else {
|
|
||||||
ctx := cloneContext(dc.ctx)
|
|
||||||
value, err = functor.InvokeNamed(ctx, name, args)
|
|
||||||
exportObjects(dc.ctx, ctx)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
err = errNoOperation(name)
|
err = errNoOperation(name)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *dataCursor) Reset() (success bool, err error) {
|
// func (dc *dataCursor) Reset() (err error) {
|
||||||
|
// if dc.resetFunc != nil {
|
||||||
|
// if dc.resource != nil {
|
||||||
|
// ctx := cloneContext(dc.ctx)
|
||||||
|
// actualParams := bindActualParams(dc.resetFunc, []any{dc.resource})
|
||||||
|
// _, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams)
|
||||||
|
// exportObjects(dc.ctx, ctx)
|
||||||
|
// dc.index = -1
|
||||||
|
// dc.count = 0
|
||||||
|
// dc.initState = true
|
||||||
|
// dc.current = nil
|
||||||
|
// dc.lastErr = nil
|
||||||
|
// } else {
|
||||||
|
// err = errInvalidDataSource()
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// err = errNoOperation(ResetName)
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (dc *dataCursor) Reset() (err error) {
|
||||||
if dc.resetFunc != nil {
|
if dc.resetFunc != nil {
|
||||||
if dc.resource != nil {
|
ctx := cloneContext(dc.ctx)
|
||||||
ctx := cloneContext(dc.ctx)
|
actualParams := bindActualParams(dc.resetFunc, []any{dc.resource})
|
||||||
actualParams := bindActualParams(dc.resetFunc, []any{dc.resource})
|
_, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams)
|
||||||
_, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams)
|
exportObjects(dc.ctx, ctx)
|
||||||
exportObjects(dc.ctx, ctx)
|
|
||||||
dc.index = -1
|
|
||||||
dc.count = 0
|
|
||||||
dc.initState = true
|
|
||||||
dc.current = nil
|
|
||||||
dc.lastErr = nil
|
|
||||||
//dc.Next()
|
|
||||||
} else {
|
|
||||||
err = errInvalidDataSource()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = errNoOperation(ResetName)
|
|
||||||
}
|
}
|
||||||
success = err == nil
|
dc.index = -1
|
||||||
|
dc.count = 0
|
||||||
|
dc.initState = true
|
||||||
|
dc.current = nil
|
||||||
|
dc.lastErr = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *dataCursor) Clean() (success bool, err error) {
|
func (dc *dataCursor) Clean() (err error) {
|
||||||
if dc.cleanFunc != nil {
|
if dc.cleanFunc != nil {
|
||||||
if dc.resource != nil {
|
ctx := cloneContext(dc.ctx)
|
||||||
ctx := cloneContext(dc.ctx)
|
actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource})
|
||||||
actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource})
|
_, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams)
|
||||||
_, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams)
|
exportObjects(dc.ctx, ctx)
|
||||||
// dc.resource = nil
|
|
||||||
exportObjects(dc.ctx, ctx)
|
|
||||||
} else {
|
|
||||||
err = errInvalidDataSource()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = errNoOperation(CleanName)
|
|
||||||
}
|
}
|
||||||
success = err == nil
|
dc.lastErr = io.EOF
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (dc *dataCursor) Clean() (err error) {
|
||||||
|
// if dc.cleanFunc != nil {
|
||||||
|
// if dc.resource != nil {
|
||||||
|
// ctx := cloneContext(dc.ctx)
|
||||||
|
// actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource})
|
||||||
|
// _, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams)
|
||||||
|
// exportObjects(dc.ctx, ctx)
|
||||||
|
// } else {
|
||||||
|
// err = errInvalidDataSource()
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// err = errNoOperation(CleanName)
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
|
func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
|
||||||
dc.init()
|
dc.init()
|
||||||
|
|
||||||
@@ -191,46 +213,89 @@ func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF af
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
current = dc.current
|
current = dc.current
|
||||||
if dc.resource != nil {
|
filter := dc.ds[FilterName]
|
||||||
filter := dc.ds[FilterName]
|
mapper := dc.ds[MapName]
|
||||||
mapper := dc.ds[MapName]
|
var item any
|
||||||
var item any
|
for item == nil && dc.lastErr == nil {
|
||||||
for item == nil && dc.lastErr == nil {
|
ctx := cloneContext(dc.ctx)
|
||||||
ctx := cloneContext(dc.ctx)
|
dc.index++
|
||||||
dc.index++
|
|
||||||
|
|
||||||
actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, dc.index})
|
actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, dc.index})
|
||||||
if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil {
|
if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil {
|
||||||
if item == nil {
|
if item == nil {
|
||||||
dc.lastErr = io.EOF
|
dc.lastErr = io.EOF
|
||||||
} else {
|
} else {
|
||||||
accepted := true
|
accepted := true
|
||||||
if filter != nil {
|
if filter != nil {
|
||||||
if accepted, dc.lastErr = dc.checkFilter(filter, item); dc.lastErr != nil || !accepted {
|
if accepted, dc.lastErr = dc.checkFilter(filter, item); dc.lastErr != nil || !accepted {
|
||||||
item = nil
|
item = nil
|
||||||
}
|
|
||||||
}
|
|
||||||
if accepted {
|
|
||||||
dc.count++
|
|
||||||
}
|
|
||||||
if item != nil && mapper != nil {
|
|
||||||
item, dc.lastErr = dc.mapItem(mapper, item)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if accepted {
|
||||||
|
dc.count++
|
||||||
|
}
|
||||||
|
if item != nil && mapper != nil {
|
||||||
|
item, dc.lastErr = dc.mapItem(mapper, item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exportObjects(dc.ctx, ctx)
|
|
||||||
}
|
}
|
||||||
dc.current = item
|
exportObjects(dc.ctx, ctx)
|
||||||
if dc.lastErr != nil {
|
}
|
||||||
dc.index--
|
dc.current = item
|
||||||
dc.Clean()
|
if dc.lastErr != nil {
|
||||||
}
|
dc.index--
|
||||||
} else {
|
dc.Clean()
|
||||||
dc.lastErr = errInvalidDataSource()
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF after the last item
|
||||||
|
// if dc.initState {
|
||||||
|
// dc.init()
|
||||||
|
// } else if err = dc.lastErr; err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// current = dc.current
|
||||||
|
// if dc.resource != nil {
|
||||||
|
// filter := dc.ds[FilterName]
|
||||||
|
// mapper := dc.ds[MapName]
|
||||||
|
// var item any
|
||||||
|
// for item == nil && dc.lastErr == nil {
|
||||||
|
// ctx := cloneContext(dc.ctx)
|
||||||
|
// dc.index++
|
||||||
|
|
||||||
|
// actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, dc.index})
|
||||||
|
// if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil {
|
||||||
|
// if item == nil {
|
||||||
|
// dc.lastErr = io.EOF
|
||||||
|
// } else {
|
||||||
|
// accepted := true
|
||||||
|
// if filter != nil {
|
||||||
|
// if accepted, dc.lastErr = dc.checkFilter(filter, item); dc.lastErr != nil || !accepted {
|
||||||
|
// item = nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if accepted {
|
||||||
|
// dc.count++
|
||||||
|
// }
|
||||||
|
// if item != nil && mapper != nil {
|
||||||
|
// item, dc.lastErr = dc.mapItem(mapper, item)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// exportObjects(dc.ctx, ctx)
|
||||||
|
// }
|
||||||
|
// dc.current = item
|
||||||
|
// if dc.lastErr != nil {
|
||||||
|
// dc.index--
|
||||||
|
// dc.Clean()
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// dc.lastErr = errInvalidDataSource()
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
func (dc *dataCursor) Index() int {
|
func (dc *dataCursor) Index() int {
|
||||||
return dc.index - 1
|
return dc.index - 1
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-35
@@ -58,7 +58,7 @@ The expression context is analogous to the stack-frame of other programming lang
|
|||||||
|
|
||||||
Function contexts are created by cloning the calling context. More details on this topic are given later in this document.
|
Function contexts are created by cloning the calling context. More details on this topic are given later in this document.
|
||||||
|
|
||||||
_Expr_ creates and keeps a inner _global context_ where it stores imported functions, either from builtin or plugin modules. To perform calculations, the calling program must provide its own context; this is the _main context_. All calculations take place in this context. As mentioned eralier, when a function is called, a new context is created by cloning the calling context. The createt context can be called _function context_.
|
_Expr_ creates and keeps a inner _global context_ where it stores imported functions, either from builtin or plugin modules. To perform calculations, the calling program must provide its own context; this is the _main context_. All calculations take place in this context. As mentioned eralier, when a function is called, a new context is created by cloning the calling context. The created context can be called _function context_.
|
||||||
|
|
||||||
Imported functions are registerd in the _global context_. When an expression first calls an imported function, that function is linked to the current context; this can be the _main context_ or a _function context_.
|
Imported functions are registerd in the _global context_. When an expression first calls an imported function, that function is linked to the current context; this can be the _main context_ or a _function context_.
|
||||||
|
|
||||||
@@ -321,7 +321,7 @@ Some arithmetic operators can also be used with strings.
|
|||||||
| [blue]`*` | _repeat_ | Make _n_ copy of a string | [blue]`"one" * 2` -> _"oneone"_
|
| [blue]`*` | _repeat_ | Make _n_ copy of a string | [blue]`"one" * 2` -> _"oneone"_
|
||||||
|===
|
|===
|
||||||
|
|
||||||
The items of strings can be accessed using the square `[]` operator.
|
The charanters in a string can be accessed using the square `[]` operator.
|
||||||
|
|
||||||
.Item access syntax
|
.Item access syntax
|
||||||
====
|
====
|
||||||
@@ -340,10 +340,10 @@ The items of strings can be accessed using the square `[]` operator.
|
|||||||
`>>>` [blue]`s[1]` [gray]_// char at position 1 (starting from 0)_ +
|
`>>>` [blue]`s[1]` [gray]_// char at position 1 (starting from 0)_ +
|
||||||
[green]`"b"`
|
[green]`"b"`
|
||||||
|
|
||||||
`>>>` [blue]`s.[-1]` [gray]_// char at position -1, the rightmost one_ +
|
`>>>` [blue]`s[-1]` [gray]_// char at position -1, the rightmost one_ +
|
||||||
[green]`"d"`
|
[green]`"d"`
|
||||||
|
|
||||||
`>>>` [blue]`\#s` [gray]_// number of chars_ +
|
`>>>` [blue]`#s` [gray]_// number of chars_ +
|
||||||
[gren]`4`
|
[gren]`4`
|
||||||
|
|
||||||
`>>>` [blue]`#"abc"` [gray]_// number of chars_ +
|
`>>>` [blue]`#"abc"` [gray]_// number of chars_ +
|
||||||
@@ -369,9 +369,9 @@ Boolean data type has two values only: [blue]_true_ and [blue]_false_. Relationa
|
|||||||
| [blue]`\<=` | _Less or Equal_ | True if the left value is less than or equal to the right one | [blue]`5 \<= 2` -> _false_ +
|
| [blue]`\<=` | _Less or Equal_ | True if the left value is less than or equal to the right one | [blue]`5 \<= 2` -> _false_ +
|
||||||
[blue]`"b" \<= "b"` -> _true_
|
[blue]`"b" \<= "b"` -> _true_
|
||||||
| [blue]`>` | _Greater_ | True if the left value is greater than the right one | [blue]`5 > 2` -> _true_ +
|
| [blue]`>` | _Greater_ | True if the left value is greater than the right one | [blue]`5 > 2` -> _true_ +
|
||||||
[blue]`"a" < "b"` -> _false_
|
[blue]`"a" > "b"` -> _false_
|
||||||
| [blue]`>=` | _Greater or Equal_ | True if the left value is greater than or equal to the right one | [blue]`5 >= 2` -> _true_ +
|
| [blue]`>=` | _Greater or Equal_ | True if the left value is greater than or equal to the right one | [blue]`5 >= 2` -> _true_ +
|
||||||
[blue]`"b" \<= "b"` -> _true_
|
[blue]`"b" >= "b"` -> _true_
|
||||||
|===
|
|===
|
||||||
|
|
||||||
^(*)^ See also the [blue]`in` operator in the _list_ and _dictionary_ sections.
|
^(*)^ See also the [blue]`in` operator in the _list_ and _dictionary_ sections.
|
||||||
@@ -388,7 +388,7 @@ Boolean data type has two values only: [blue]_true_ and [blue]_false_. Relationa
|
|||||||
| [blue]`AND` / [blue]`&&` | _And_ | True if both left and right values are true | [blue]`false && true` -> _false_ +
|
| [blue]`AND` / [blue]`&&` | _And_ | True if both left and right values are true | [blue]`false && true` -> _false_ +
|
||||||
[blue]`"a" < "b" AND NOT (2 < 1)` -> _true_
|
[blue]`"a" < "b" AND NOT (2 < 1)` -> _true_
|
||||||
|
|
||||||
| [blue]`OR` / [blue]`\|\|` | _Or_ | True if at least one of the left and right values integers true| [blue]`false or true` -> _true_ +
|
| [blue]`OR` / [blue]`\|\|` | _Or_ | True if at least one of the left and right values integers is true| [blue]`false or true` -> _true_ +
|
||||||
[blue]`"a" == "b" OR (2 == 1)` -> _false_
|
[blue]`"a" == "b" OR (2 == 1)` -> _false_
|
||||||
|===
|
|===
|
||||||
|
|
||||||
@@ -413,7 +413,7 @@ _Expr_ supports list of mixed-type values, also specified by normal expressions.
|
|||||||
====
|
====
|
||||||
*_list_* = _empty-list_ | _non-empty-list_ +
|
*_list_* = _empty-list_ | _non-empty-list_ +
|
||||||
_empty-list_ = "**[]**" +
|
_empty-list_ = "**[]**" +
|
||||||
_non-empty-list_ = "**[**" _any-value_ {"**,**" _any-value} "**]**" +
|
_non-empty-list_ = "**[**" _any-value_ {"**,**" _any-value_} "**]**" +
|
||||||
====
|
====
|
||||||
|
|
||||||
.Examples
|
.Examples
|
||||||
@@ -459,22 +459,22 @@ Array's items can be accessed using the index `[]` operator.
|
|||||||
====
|
====
|
||||||
|
|
||||||
.Items of list
|
.Items of list
|
||||||
`>>>` [blue]`[1,2,3].1` +
|
`>>>` [blue]`[1,2,3][1]` +
|
||||||
[green]`2`
|
[green]`2`
|
||||||
|
|
||||||
`>>>` [blue]`list=[1,2,3]; list.1` +
|
`>>>` [blue]`list=[1,2,3]; list[1]` +
|
||||||
[green]`2`
|
[green]`2`
|
||||||
|
|
||||||
`>>>` [blue]`["one","two","three"].1` +
|
`>>>` [blue]`["one","two","three"][1]` +
|
||||||
[green]`two`
|
[green]`two`
|
||||||
|
|
||||||
`>>>` [blue]`list=["one","two","three"]; list.(2-1)` +
|
`>>>` [blue]`list=["one","two","three"]; list[2-1]` +
|
||||||
[green]`two`
|
[green]`two`
|
||||||
|
|
||||||
`>>>` [blue]`list.(-1)` +
|
`>>>` [blue]`list[-1]` +
|
||||||
[green]`three`
|
[green]`three`
|
||||||
|
|
||||||
`>>>` [blue]`list.(10)` +
|
`>>>` [blue]`list[10]` +
|
||||||
[red]`Eval Error: [1:9] index 10 out of bounds`
|
[red]`Eval Error: [1:9] index 10 out of bounds`
|
||||||
|
|
||||||
`>>>` [blue]`#list` +
|
`>>>` [blue]`#list` +
|
||||||
@@ -497,7 +497,7 @@ Dictionary literals are sequences of pairs separated by comma [blue]`,` enclosed
|
|||||||
====
|
====
|
||||||
*_dict_* = _empty-dict_ | _non-empty-dict_ +
|
*_dict_* = _empty-dict_ | _non-empty-dict_ +
|
||||||
_empty-dict_ = "**{}**" +
|
_empty-dict_ = "**{}**" +
|
||||||
_non-empty-dict_ = "**{**" _key-scalar_ "**:**" _any-value_ {"**,**" _key-scalar_ "**:**" _any-value} "**}**" +
|
_non-empty-dict_ = "**{**" _key-scalar_ "**:**" _any-value_ {"**,**" _key-scalar_ "**:**" _any-value_} "**}**" +
|
||||||
====
|
====
|
||||||
|
|
||||||
|
|
||||||
@@ -551,7 +551,7 @@ NOTE: The assign operator [blue]`=` returns the value assigned to the variable.
|
|||||||
[green]`1`
|
[green]`1`
|
||||||
|
|
||||||
`>>>` [blue]`a_b=1+2` +
|
`>>>` [blue]`a_b=1+2` +
|
||||||
[green]`1+2`
|
[green]`3`
|
||||||
|
|
||||||
`>>>` [blue]`a_b` +
|
`>>>` [blue]`a_b` +
|
||||||
[green]`3`
|
[green]`3`
|
||||||
@@ -562,7 +562,7 @@ NOTE: The assign operator [blue]`=` returns the value assigned to the variable.
|
|||||||
`>>>` [blue]`x = 1; y = 2*x` +
|
`>>>` [blue]`x = 1; y = 2*x` +
|
||||||
[green]`2`
|
[green]`2`
|
||||||
|
|
||||||
`>>>` [blue]`_a=2` +
|
`>>>` [blue]`\_a=2` +
|
||||||
[red]`Parse Error: [1:2] unexpected token "_"`
|
[red]`Parse Error: [1:2] unexpected token "_"`
|
||||||
|
|
||||||
`>>>` [blue]`1=2` +
|
`>>>` [blue]`1=2` +
|
||||||
@@ -574,12 +574,12 @@ NOTE: The assign operator [blue]`=` returns the value assigned to the variable.
|
|||||||
=== [blue]`;` operator
|
=== [blue]`;` operator
|
||||||
The semicolon operator [blue]`;` is an infixed pseudo-operator. It evaluates the left expression first and then the right expression. The value of the latter is the final result.
|
The semicolon operator [blue]`;` is an infixed pseudo-operator. It evaluates the left expression first and then the right expression. The value of the latter is the final result.
|
||||||
|
|
||||||
.Mult-expression syntax
|
.Multi-expression syntax
|
||||||
====
|
====
|
||||||
*_multi-expression_* = _expression_ {"**;**" _expression_ }
|
*_multi-expression_* = _expression_ {"**;**" _expression_ }
|
||||||
====
|
====
|
||||||
|
|
||||||
An expression that contains [blue]`;` is called a _multi-expression_ and each component expressione is called a _sub-expression_.
|
An expression that contains [blue]`;` is called a _multi-expression_ and each component expression is called a _sub-expression_.
|
||||||
|
|
||||||
IMPORTANT: Technically [blue]`;` is not treated as a real operator. It acts as a separator in lists of expressions.
|
IMPORTANT: Technically [blue]`;` is not treated as a real operator. It acts as a separator in lists of expressions.
|
||||||
|
|
||||||
@@ -589,7 +589,7 @@ TIP: [blue]`;` can be used to set some variables before the final calculation.
|
|||||||
`>>>` [blue]`a=1; b=2; c=3; a+b+c` +
|
`>>>` [blue]`a=1; b=2; c=3; a+b+c` +
|
||||||
[green]`6`
|
[green]`6`
|
||||||
|
|
||||||
The value of each sub-expression is stored in the automatica variable _last_.
|
The value of each sub-expression is stored in the automatic variable _last_.
|
||||||
|
|
||||||
.Example
|
.Example
|
||||||
`>>>` [blue]`2+3; b=last+10; last` +
|
`>>>` [blue]`2+3; b=last+10; last` +
|
||||||
@@ -600,9 +600,10 @@ The value of each sub-expression is stored in the automatica variable _last_.
|
|||||||
[blue]`but` is an infixed operator. Its operands can be expressions of any type. It evaluates the left expression first, then the right expression. The value of the right expression is the final result.
|
[blue]`but` is an infixed operator. Its operands can be expressions of any type. It evaluates the left expression first, then the right expression. The value of the right expression is the final result.
|
||||||
|
|
||||||
.Examples
|
.Examples
|
||||||
[blue]`5 but 2` +
|
`>>>` [blue]`5 but 2` +
|
||||||
[green]`2` +
|
[green]`2`
|
||||||
[blue]`x=2*3 but x-1` +
|
|
||||||
|
`>>>` [blue]`x=2*3 but x-1` +
|
||||||
[green]`5`.
|
[green]`5`.
|
||||||
|
|
||||||
[blue]`but` behavior is very similar to [blue]`;`. The only difference is that [blue]`;` is not a true operator and can't be used inside parenthesis [blue]`(` and [blue]`)`.
|
[blue]`but` behavior is very similar to [blue]`;`. The only difference is that [blue]`;` is not a true operator and can't be used inside parenthesis [blue]`(` and [blue]`)`.
|
||||||
@@ -610,17 +611,21 @@ The value of each sub-expression is stored in the automatica variable _last_.
|
|||||||
=== Assignment operator [blue]`=`
|
=== Assignment operator [blue]`=`
|
||||||
The assignment operator [blue]`=` is used to define variables or to change their value in the evaluation context (see _ExprContext_).
|
The assignment operator [blue]`=` is used to define variables or to change their value in the evaluation context (see _ExprContext_).
|
||||||
|
|
||||||
The value on the left side of [blue]`=` must be an identifier. The value on the right side can be any expression and it becomes the result of the assignment operation.
|
The value on the left side of [blue]`=` must be a variable identifier or an expression that evalutes to a variable. The value on the right side can be any expression and it becomes the result of the assignment operation.
|
||||||
|
|
||||||
.Example
|
.Examples
|
||||||
`>>>` [blue]`a=15+1`
|
`>>>` [blue]`a=15+1` +
|
||||||
[green]`16`
|
[green]`16`
|
||||||
|
|
||||||
|
`>>>` [blue]`L=[1,2,3]; L[1]=5; L` +
|
||||||
|
[green]`[1, 5, 3]`
|
||||||
|
|
||||||
|
|
||||||
=== Selector operator [blue]`? : ::`
|
=== Selector operator [blue]`? : ::`
|
||||||
The _selector operator_ is very similar to the _switch/case/default_ statement available in many programming languages.
|
The _selector operator_ is very similar to the _switch/case/default_ statement available in many programming languages.
|
||||||
|
|
||||||
.Selector literal Syntax
|
.Selector literal Syntax
|
||||||
|
====
|
||||||
_selector-operator_ = _select-expression_ "*?*" _selector-case_ { "*:*" _selector-case_ } ["*::*" _default-multi-expression_] +
|
_selector-operator_ = _select-expression_ "*?*" _selector-case_ { "*:*" _selector-case_ } ["*::*" _default-multi-expression_] +
|
||||||
_selector-case_ = [_match-list_] _case-value_ +
|
_selector-case_ = [_match-list_] _case-value_ +
|
||||||
_match-list_ = "*[*" _item_ {"*,*" _items_} "*]*" +
|
_match-list_ = "*[*" _item_ {"*,*" _items_} "*]*" +
|
||||||
@@ -628,6 +633,7 @@ _item_ = _expression_ +
|
|||||||
_case-multi-expression_ = "*{*" _multi-expression_ "*}*" +
|
_case-multi-expression_ = "*{*" _multi-expression_ "*}*" +
|
||||||
_multi-expression_ = _expression_ { "*;*" _expression_ } +
|
_multi-expression_ = _expression_ { "*;*" _expression_ } +
|
||||||
_default-multi-expression_ = _multi-expression_
|
_default-multi-expression_ = _multi-expression_
|
||||||
|
====
|
||||||
|
|
||||||
In other words, the selector operator evaluates the _select-expression_ on the left-hand side of the [blue]`?` symbol; it then compares the result obtained with the values listed in the __match-list__'s, from left to right. If the comparision finds a match with a value in a _match-list_, the associated _case-multi-expression_ is evaluted, and its result will be the final result of the selection operation.
|
In other words, the selector operator evaluates the _select-expression_ on the left-hand side of the [blue]`?` symbol; it then compares the result obtained with the values listed in the __match-list__'s, from left to right. If the comparision finds a match with a value in a _match-list_, the associated _case-multi-expression_ is evaluted, and its result will be the final result of the selection operation.
|
||||||
|
|
||||||
@@ -668,7 +674,7 @@ The [blue]`??` operator do not change the status of the left variable.
|
|||||||
The [blue]`?=` assigns the calculated value of the right expression to the left variable.
|
The [blue]`?=` assigns the calculated value of the right expression to the left variable.
|
||||||
|
|
||||||
.Examples
|
.Examples
|
||||||
`>>>` [blue]`var ?? (1+2)`' +
|
`>>>` [blue]`var ?? (1+2)` +
|
||||||
[green]`3`
|
[green]`3`
|
||||||
|
|
||||||
`>>>` [blue]`var` +
|
`>>>` [blue]`var` +
|
||||||
@@ -677,7 +683,7 @@ The [blue]`?=` assigns the calculated value of the right expression to the left
|
|||||||
`>>>` [blue]`var ?= (1+2)` +
|
`>>>` [blue]`var ?= (1+2)` +
|
||||||
[green]`3`
|
[green]`3`
|
||||||
|
|
||||||
`>>>` [blue]`var`
|
`>>>` [blue]`var` +
|
||||||
[green]`3`
|
[green]`3`
|
||||||
|
|
||||||
NOTE: These operators have a high priority, in particular higher than the operator [blue]`=`.
|
NOTE: These operators have a high priority, in particular higher than the operator [blue]`=`.
|
||||||
@@ -739,21 +745,21 @@ The table below shows all supported operators by decreasing priorities.
|
|||||||
|
|
||||||
|
|
||||||
== Functions
|
== Functions
|
||||||
Functions in _Expr_ are very similar to functions available in many programming languages. Actually, _Expr_ supports two types of function, _expr-functions_ and _go-functions_.
|
Functions in _Expr_ are very similar to functions available in many programming languages. Currently, _Expr_ supports two types of function, _expr-functions_ and _go-functions_.
|
||||||
|
|
||||||
* _expr-functions_ are defined using _Expr_'s syntax. They can be passed as arguments to other functions and can be returned from functions. Moreover, they bind themselves to the defining context, thus becoming closures.
|
* _expr-functions_ are defined using _Expr_'s syntax. They can be passed as arguments to other functions and can be returned from functions. Moreover, they bind themselves to the defining context, thus becoming closures.
|
||||||
* _go-functions_ are regular Golang functions callable from _Expr_ expressions. They are defined in Golang source files called _modules_ and compiled within the _Expr_ package. To make Golang functions available in _Expr_ contextes, it is required to _import_ the module in which they are defined.
|
* _go-functions_ are regular Golang functions callable from _Expr_ expressions. They are defined in Golang source files called _modules_ and compiled within the _Expr_ package. To make Golang functions available in _Expr_ contextes, it is required to activate the builtin module or to load the plugin module in which they are defined.
|
||||||
|
|
||||||
|
|
||||||
=== _Expr_ function definition
|
=== _Expr_ function definition
|
||||||
A function is identified and referenced by its name. It can have zero or more parameter. _Expr_ functions also support optional parameters.
|
A function is identified and referenced by its name. It can have zero or more parameter. _Expr_ functions also support optional parameters.
|
||||||
|
|
||||||
. Expr's function definition syntax
|
.Expr's function definition syntax
|
||||||
====
|
====
|
||||||
*_function-definition_* = _identifier_ "**=**" "**func(**" [_param-list_] "**)**" "**{**" _multi-expression_ "**}**"
|
*_function-definition_* = _identifier_ "**=**" "**func(**" [_param-list_] "**)**" "**{**" _multi-expression_ "**}**" +
|
||||||
_param_list_ = _required-param-list_ [ "**,**" _optional-param-list_ ]
|
_param_list_ = _required-param-list_ [ "**,**" _optional-param-list_ ] +
|
||||||
_required-param-list_ = _identifier_ { "**,**" _identifier_ }
|
_required-param-list_ = _identifier_ { "**,**" _identifier_ } +
|
||||||
_optional-param-list_ = _optional-parm_ { "**,**" _optional-param_ }
|
_optional-param-list_ = _optional-parm_ { "**,**" _optional-param_ } +
|
||||||
_optional-param_ = _identifier_ "**=**" _any-expr_
|
_optional-param_ = _identifier_ "**=**" _any-expr_
|
||||||
====
|
====
|
||||||
|
|
||||||
|
|||||||
+49
-45
@@ -657,7 +657,7 @@ pre.rouge .ss {
|
|||||||
<p>Function contexts are created by cloning the calling context. More details on this topic are given later in this document.</p>
|
<p>Function contexts are created by cloning the calling context. More details on this topic are given later in this document.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><em>Expr</em> creates and keeps a inner <em>global context</em> where it stores imported functions, either from builtin or plugin modules. To perform calculations, the calling program must provide its own context; this is the <em>main context</em>. All calculations take place in this context. As mentioned eralier, when a function is called, a new context is created by cloning the calling context. The createt context can be called <em>function context</em>.</p>
|
<p><em>Expr</em> creates and keeps a inner <em>global context</em> where it stores imported functions, either from builtin or plugin modules. To perform calculations, the calling program must provide its own context; this is the <em>main context</em>. All calculations take place in this context. As mentioned eralier, when a function is called, a new context is created by cloning the calling context. The created context can be called <em>function context</em>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>Imported functions are registerd in the <em>global context</em>. When an expression first calls an imported function, that function is linked to the current context; this can be the <em>main context</em> or a <em>function context</em>.</p>
|
<p>Imported functions are registerd in the <em>global context</em>. When an expression first calls an imported function, that function is linked to the current context; this can be the <em>main context</em> or a <em>function context</em>.</p>
|
||||||
@@ -1109,7 +1109,7 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>The items of strings can be accessed using the square <code>[]</code> operator.</p>
|
<p>The charanters in a string can be accessed using the square <code>[]</code> operator.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="exampleblock">
|
<div class="exampleblock">
|
||||||
<div class="title">Example 4. Item access syntax</div>
|
<div class="title">Example 4. Item access syntax</div>
|
||||||
@@ -1137,11 +1137,11 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
|||||||
<code class="green">"b"</code></p>
|
<code class="green">"b"</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">s.[-1]</code> <em class="gray">// char at position -1, the rightmost one</em><br>
|
<p><code>>>></code> <code class="blue">s[-1]</code> <em class="gray">// char at position -1, the rightmost one</em><br>
|
||||||
<code class="green">"d"</code></p>
|
<code class="green">"d"</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">\#s</code> <em class="gray">// number of chars</em><br>
|
<p><code>>>></code> <code class="blue">#s</code> <em class="gray">// number of chars</em><br>
|
||||||
<code class="gren">4</code></p>
|
<code class="gren">4</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
@@ -1208,14 +1208,14 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
|||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Greater</em></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Greater</em></p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">True if the left value is greater than the right one</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">True if the left value is greater than the right one</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">5 > 2</code> → <em>true</em><br>
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">5 > 2</code> → <em>true</em><br>
|
||||||
<code class="blue">"a" < "b"</code> → <em>false</em></p></td>
|
<code class="blue">"a" > "b"</code> → <em>false</em></p></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">>=</code></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">>=</code></p></td>
|
||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Greater or Equal</em></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Greater or Equal</em></p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">True if the left value is greater than or equal to the right one</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">True if the left value is greater than or equal to the right one</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">5 >= 2</code> → <em>true</em><br>
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">5 >= 2</code> → <em>true</em><br>
|
||||||
<code class="blue">"b" <= "b"</code> → <em>true</em></p></td>
|
<code class="blue">"b" >= "b"</code> → <em>true</em></p></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -1256,7 +1256,7 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">OR</code> / <code class="blue">||</code></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">OR</code> / <code class="blue">||</code></p></td>
|
||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Or</em></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Or</em></p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">True if at least one of the left and right values integers true</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">True if at least one of the left and right values integers is true</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">false or true</code> → <em>true</em><br>
|
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">false or true</code> → <em>true</em><br>
|
||||||
<code class="blue">"a" == "b" OR (2 == 1)</code> → <em>false</em></p></td>
|
<code class="blue">"a" == "b" OR (2 == 1)</code> → <em>false</em></p></td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -1314,7 +1314,7 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
|||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><strong><em>list</em></strong> = <em>empty-list</em> | <em>non-empty-list</em><br>
|
<p><strong><em>list</em></strong> = <em>empty-list</em> | <em>non-empty-list</em><br>
|
||||||
<em>empty-list</em> = "<strong>[]</strong>"<br>
|
<em>empty-list</em> = "<strong>[]</strong>"<br>
|
||||||
<em>non-empty-list</em> = "<strong>[</strong>" <em>any-value</em> {"<strong>,</strong>" _any-value} "<strong>]</strong>"<br></p>
|
<em>non-empty-list</em> = "<strong>[</strong>" <em>any-value</em> {"<strong>,</strong>" <em>any-value</em>} "<strong>]</strong>"<br></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1416,27 +1416,27 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
|||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<div class="title">Items of list</div>
|
<div class="title">Items of list</div>
|
||||||
<p><code>>>></code> <code class="blue">[1,2,3].1</code><br>
|
<p><code>>>></code> <code class="blue">[1,2,3][1]</code><br>
|
||||||
<code class="green">2</code></p>
|
<code class="green">2</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">list=[1,2,3]; list.1</code><br>
|
<p><code>>>></code> <code class="blue">list=[1,2,3]; list[1]</code><br>
|
||||||
<code class="green">2</code></p>
|
<code class="green">2</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">["one","two","three"].1</code><br>
|
<p><code>>>></code> <code class="blue">["one","two","three"][1]</code><br>
|
||||||
<code class="green">two</code></p>
|
<code class="green">two</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">list=["one","two","three"]; list.(2-1)</code><br>
|
<p><code>>>></code> <code class="blue">list=["one","two","three"]; list[2-1]</code><br>
|
||||||
<code class="green">two</code></p>
|
<code class="green">two</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">list.(-1)</code><br>
|
<p><code>>>></code> <code class="blue">list[-1]</code><br>
|
||||||
<code class="green">three</code></p>
|
<code class="green">three</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">list.(10)</code><br>
|
<p><code>>>></code> <code class="blue">list[10]</code><br>
|
||||||
<code class="red">Eval Error: [1:9] index 10 out of bounds</code></p>
|
<code class="red">Eval Error: [1:9] index 10 out of bounds</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
@@ -1466,7 +1466,7 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
|||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><strong><em>dict</em></strong> = <em>empty-dict</em> | <em>non-empty-dict</em><br>
|
<p><strong><em>dict</em></strong> = <em>empty-dict</em> | <em>non-empty-dict</em><br>
|
||||||
<em>empty-dict</em> = "<strong>{}</strong>"<br>
|
<em>empty-dict</em> = "<strong>{}</strong>"<br>
|
||||||
<em>non-empty-dict</em> = "<strong>{</strong>" <em>key-scalar</em> "<strong>:</strong>" <em>any-value</em> {"<strong>,</strong>" <em>key-scalar</em> "<strong>:</strong>" _any-value} "<strong>}</strong>"<br></p>
|
<em>non-empty-dict</em> = "<strong>{</strong>" <em>key-scalar</em> "<strong>:</strong>" <em>any-value</em> {"<strong>,</strong>" <em>key-scalar</em> "<strong>:</strong>" <em>any-value</em>} "<strong>}</strong>"<br></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1575,7 +1575,7 @@ The assign operator <code class="blue">=</code> returns the value assigned to th
|
|||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">a_b=1+2</code><br>
|
<p><code>>>></code> <code class="blue">a_b=1+2</code><br>
|
||||||
<code class="green">1+2</code></p>
|
<code class="green">3</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">a_b</code><br>
|
<p><code>>>></code> <code class="blue">a_b</code><br>
|
||||||
@@ -1590,8 +1590,8 @@ The assign operator <code class="blue">=</code> returns the value assigned to th
|
|||||||
<code class="green">2</code></p>
|
<code class="green">2</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue"><em>a=2</code><br>
|
<p><code>>>></code> <code class="blue">_a=2</code><br>
|
||||||
<code class="red">Parse Error: [1:2] unexpected token "</em>"</code></p>
|
<code class="red">Parse Error: [1:2] unexpected token "_"</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">1=2</code><br>
|
<p><code>>>></code> <code class="blue">1=2</code><br>
|
||||||
@@ -1608,7 +1608,7 @@ The assign operator <code class="blue">=</code> returns the value assigned to th
|
|||||||
<p>The semicolon operator <code class="blue">;</code> is an infixed pseudo-operator. It evaluates the left expression first and then the right expression. The value of the latter is the final result.</p>
|
<p>The semicolon operator <code class="blue">;</code> is an infixed pseudo-operator. It evaluates the left expression first and then the right expression. The value of the latter is the final result.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="exampleblock">
|
<div class="exampleblock">
|
||||||
<div class="title">Example 12. Mult-expression syntax</div>
|
<div class="title">Example 12. Multi-expression syntax</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><strong><em>multi-expression</em></strong> = <em>expression</em> {"<strong>;</strong>" <em>expression</em> }</p>
|
<p><strong><em>multi-expression</em></strong> = <em>expression</em> {"<strong>;</strong>" <em>expression</em> }</p>
|
||||||
@@ -1616,7 +1616,7 @@ The assign operator <code class="blue">=</code> returns the value assigned to th
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>An expression that contains <code class="blue">;</code> is called a <em>multi-expression</em> and each component expressione is called a <em>sub-expression</em>.</p>
|
<p>An expression that contains <code class="blue">;</code> is called a <em>multi-expression</em> and each component expression is called a <em>sub-expression</em>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="admonitionblock important">
|
<div class="admonitionblock important">
|
||||||
<table>
|
<table>
|
||||||
@@ -1648,7 +1648,7 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
|
|||||||
<code class="green">6</code></p>
|
<code class="green">6</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>The value of each sub-expression is stored in the automatica variable <em>last</em>.</p>
|
<p>The value of each sub-expression is stored in the automatic variable <em>last</em>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<div class="title">Example</div>
|
<div class="title">Example</div>
|
||||||
@@ -1663,9 +1663,11 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
|
|||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<div class="title">Examples</div>
|
<div class="title">Examples</div>
|
||||||
<p><code class="blue">5 but 2</code><br>
|
<p><code>>>></code> <code class="blue">5 but 2</code><br>
|
||||||
<code class="green">2</code><br>
|
<code class="green">2</code></p>
|
||||||
<code class="blue">x=2*3 but x-1</code><br>
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><code>>>></code> <code class="blue">x=2*3 but x-1</code><br>
|
||||||
<code class="green">5</code>.</p>
|
<code class="green">5</code>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
@@ -1678,21 +1680,27 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
|
|||||||
<p>The assignment operator <code class="blue">=</code> is used to define variables or to change their value in the evaluation context (see <em>ExprContext</em>).</p>
|
<p>The assignment operator <code class="blue">=</code> is used to define variables or to change their value in the evaluation context (see <em>ExprContext</em>).</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>The value on the left side of <code class="blue">=</code> must be an identifier. The value on the right side can be any expression and it becomes the result of the assignment operation.</p>
|
<p>The value on the left side of <code class="blue">=</code> must be a variable identifier or an expression that evalutes to a variable. The value on the right side can be any expression and it becomes the result of the assignment operation.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<div class="title">Example</div>
|
<div class="title">Examples</div>
|
||||||
<p><code>>>></code> <code class="blue">a=15+1</code>
|
<p><code>>>></code> <code class="blue">a=15+1</code><br>
|
||||||
<code class="green">16</code></p>
|
<code class="green">16</code></p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><code>>>></code> <code class="blue">L=[1,2,3]; L[1]=5; L</code><br>
|
||||||
|
<code class="green">[1, 5, 3]</code></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect2">
|
<div class="sect2">
|
||||||
<h3 id="_selector_operator"><a class="anchor" href="#_selector_operator"></a><a class="link" href="#_selector_operator">4.4. Selector operator <code class="blue">? : ::</code></a></h3>
|
<h3 id="_selector_operator"><a class="anchor" href="#_selector_operator"></a><a class="link" href="#_selector_operator">4.4. Selector operator <code class="blue">? : ::</code></a></h3>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>The <em>selector operator</em> is very similar to the <em>switch/case/default</em> statement available in many programming languages.</p>
|
<p>The <em>selector operator</em> is very similar to the <em>switch/case/default</em> statement available in many programming languages.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="exampleblock">
|
||||||
|
<div class="title">Example 13. Selector literal Syntax</div>
|
||||||
|
<div class="content">
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<div class="title">Selector literal Syntax</div>
|
|
||||||
<p><em>selector-operator</em> = <em>select-expression</em> "<strong>?</strong>" <em>selector-case</em> { "<strong>:</strong>" <em>selector-case</em> } ["<strong>::</strong>" <em>default-multi-expression</em>]<br>
|
<p><em>selector-operator</em> = <em>select-expression</em> "<strong>?</strong>" <em>selector-case</em> { "<strong>:</strong>" <em>selector-case</em> } ["<strong>::</strong>" <em>default-multi-expression</em>]<br>
|
||||||
<em>selector-case</em> = [<em>match-list</em>] <em>case-value</em><br>
|
<em>selector-case</em> = [<em>match-list</em>] <em>case-value</em><br>
|
||||||
<em>match-list</em> = "<strong>[</strong>" <em>item</em> {"<strong>,</strong>" <em>items</em>} "<strong>]</strong>"<br>
|
<em>match-list</em> = "<strong>[</strong>" <em>item</em> {"<strong>,</strong>" <em>items</em>} "<strong>]</strong>"<br>
|
||||||
@@ -1701,6 +1709,8 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
|
|||||||
<em>multi-expression</em> = <em>expression</em> { "<strong>;</strong>" <em>expression</em> }<br>
|
<em>multi-expression</em> = <em>expression</em> { "<strong>;</strong>" <em>expression</em> }<br>
|
||||||
<em>default-multi-expression</em> = <em>multi-expression</em></p>
|
<em>default-multi-expression</em> = <em>multi-expression</em></p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>In other words, the selector operator evaluates the <em>select-expression</em> on the left-hand side of the <code class="blue">?</code> symbol; it then compares the result obtained with the values listed in the <em>match-list</em>'s, from left to right. If the comparision finds a match with a value in a <em>match-list</em>, the associated <em>case-multi-expression</em> is evaluted, and its result will be the final result of the selection operation.</p>
|
<p>In other words, the selector operator evaluates the <em>select-expression</em> on the left-hand side of the <code class="blue">?</code> symbol; it then compares the result obtained with the values listed in the <em>match-list</em>'s, from left to right. If the comparision finds a match with a value in a <em>match-list</em>, the associated <em>case-multi-expression</em> is evaluted, and its result will be the final result of the selection operation.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -1765,8 +1775,8 @@ If the left variable is defined, the right expression is not evaluated at all.
|
|||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<div class="title">Examples</div>
|
<div class="title">Examples</div>
|
||||||
<p><code>>>></code> <code class="blue">var ?? (1+2)’<br>
|
<p><code>>>></code> <code class="blue">var ?? (1+2)</code><br>
|
||||||
[green]`3</code></p>
|
<code class="green">3</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">var</code><br>
|
<p><code>>>></code> <code class="blue">var</code><br>
|
||||||
@@ -1777,7 +1787,7 @@ If the left variable is defined, the right expression is not evaluated at all.
|
|||||||
<code class="green">3</code></p>
|
<code class="green">3</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <code class="blue">var</code>
|
<p><code>>>></code> <code class="blue">var</code><br>
|
||||||
<code class="green">3</code></p>
|
<code class="green">3</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="admonitionblock note">
|
<div class="admonitionblock note">
|
||||||
@@ -2106,7 +2116,7 @@ These operators have a high priority, in particular higher than the operator <co
|
|||||||
<h2 id="_functions"><a class="anchor" href="#_functions"></a><a class="link" href="#_functions">6. Functions</a></h2>
|
<h2 id="_functions"><a class="anchor" href="#_functions"></a><a class="link" href="#_functions">6. Functions</a></h2>
|
||||||
<div class="sectionbody">
|
<div class="sectionbody">
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>Functions in <em>Expr</em> are very similar to functions available in many programming languages. Actually, <em>Expr</em> supports two types of function, <em>expr-functions</em> and <em>go-functions</em>.</p>
|
<p>Functions in <em>Expr</em> are very similar to functions available in many programming languages. Currently, <em>Expr</em> supports two types of function, <em>expr-functions</em> and <em>go-functions</em>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="ulist">
|
<div class="ulist">
|
||||||
<ul>
|
<ul>
|
||||||
@@ -2114,7 +2124,7 @@ These operators have a high priority, in particular higher than the operator <co
|
|||||||
<p><em>expr-functions</em> are defined using <em>Expr</em>'s syntax. They can be passed as arguments to other functions and can be returned from functions. Moreover, they bind themselves to the defining context, thus becoming closures.</p>
|
<p><em>expr-functions</em> are defined using <em>Expr</em>'s syntax. They can be passed as arguments to other functions and can be returned from functions. Moreover, they bind themselves to the defining context, thus becoming closures.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><em>go-functions</em> are regular Golang functions callable from <em>Expr</em> expressions. They are defined in Golang source files called <em>modules</em> and compiled within the <em>Expr</em> package. To make Golang functions available in <em>Expr</em> contextes, it is required to <em>import</em> the module in which they are defined.</p>
|
<p><em>go-functions</em> are regular Golang functions callable from <em>Expr</em> expressions. They are defined in Golang source files called <em>modules</em> and compiled within the <em>Expr</em> package. To make Golang functions available in <em>Expr</em> contextes, it is required to activate the builtin module or to load the plugin module in which they are defined.</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -2123,20 +2133,14 @@ These operators have a high priority, in particular higher than the operator <co
|
|||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>A function is identified and referenced by its name. It can have zero or more parameter. <em>Expr</em> functions also support optional parameters.</p>
|
<p>A function is identified and referenced by its name. It can have zero or more parameter. <em>Expr</em> functions also support optional parameters.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="olist arabic">
|
|
||||||
<ol class="arabic">
|
|
||||||
<li>
|
|
||||||
<p>Expr’s function definition syntax</p>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
<div class="exampleblock">
|
<div class="exampleblock">
|
||||||
|
<div class="title">Example 14. Expr’s function definition syntax</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><strong><em>function-definition</em></strong> = <em>identifier</em> "<strong>=</strong>" "<strong>func(</strong>" [<em>param-list</em>] "<strong>)</strong>" "<strong>{</strong>" <em>multi-expression</em> "<strong>}</strong>"
|
<p><strong><em>function-definition</em></strong> = <em>identifier</em> "<strong>=</strong>" "<strong>func(</strong>" [<em>param-list</em>] "<strong>)</strong>" "<strong>{</strong>" <em>multi-expression</em> "<strong>}</strong>"<br>
|
||||||
<em>param_list</em> = <em>required-param-list</em> [ "<strong>,</strong>" <em>optional-param-list</em> ]
|
<em>param_list</em> = <em>required-param-list</em> [ "<strong>,</strong>" <em>optional-param-list</em> ]<br>
|
||||||
<em>required-param-list</em> = <em>identifier</em> { "<strong>,</strong>" <em>identifier</em> }
|
<em>required-param-list</em> = <em>identifier</em> { "<strong>,</strong>" <em>identifier</em> }<br>
|
||||||
<em>optional-param-list</em> = <em>optional-parm</em> { "<strong>,</strong>" <em>optional-param</em> }
|
<em>optional-param-list</em> = <em>optional-parm</em> { "<strong>,</strong>" <em>optional-param</em> }<br>
|
||||||
<em>optional-param</em> = <em>identifier</em> "<strong>=</strong>" <em>any-expr</em></p>
|
<em>optional-param</em> = <em>identifier</em> "<strong>=</strong>" <em>any-expr</em></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2200,7 +2204,7 @@ These operators have a high priority, in particular higher than the operator <co
|
|||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div id="footer-text">
|
<div id="footer-text">
|
||||||
Last updated 2024-06-21 09:06:12 +0200
|
Last updated 2024-09-12 06:56:30 +0200
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+2
-2
@@ -348,8 +348,8 @@ func CallFunctionByArgs(parentCtx ExprContext, name string, args []any) (result
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func CallFunctionByParams(parentCtx ExprContext, name string, params map[string]any) (result any, err error) {
|
func CallFunctionByParams(parentCtx ExprContext, name string, actualParams map[string]any) (result any, err error) {
|
||||||
var actualParams map[string]any
|
//var actualParams map[string]any
|
||||||
if info, exists := GetFuncInfo(parentCtx, name); exists {
|
if info, exists := GetFuncInfo(parentCtx, name); exists {
|
||||||
functor := info.Functor()
|
functor := info.Functor()
|
||||||
ctx := info.AllocContext(parentCtx)
|
ctx := info.AllocContext(parentCtx)
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ type Iterator interface {
|
|||||||
|
|
||||||
type ExtIterator interface {
|
type ExtIterator interface {
|
||||||
Iterator
|
Iterator
|
||||||
|
Reset() error
|
||||||
|
Clean() error
|
||||||
HasOperation(name string) bool
|
HasOperation(name string) bool
|
||||||
CallOperation(name string, args map[string]any) (value any, err error)
|
CallOperation(name string, args map[string]any) (value any, err error)
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -99,7 +99,9 @@ func (it *ListIterator) CallOperation(name string, args map[string]any) (v any,
|
|||||||
case NextName:
|
case NextName:
|
||||||
v, err = it.Next()
|
v, err = it.Next()
|
||||||
case ResetName:
|
case ResetName:
|
||||||
v, err = it.Reset()
|
err = it.Reset()
|
||||||
|
case CleanName:
|
||||||
|
err = it.Clean()
|
||||||
case IndexName:
|
case IndexName:
|
||||||
v = int64(it.Index())
|
v = int64(it.Index())
|
||||||
case CurrentName:
|
case CurrentName:
|
||||||
@@ -147,8 +149,12 @@ func (it *ListIterator) Count() int {
|
|||||||
return it.count
|
return it.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *ListIterator) Reset() (bool, error) {
|
func (it *ListIterator) Reset() (error) {
|
||||||
it.index = it.start - it.step
|
it.index = it.start - it.step
|
||||||
it.count = 0
|
it.count = 0
|
||||||
return true, nil
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *ListIterator) Clean() (error) {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -92,6 +92,7 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
|
|
||||||
if ds != nil {
|
if ds != nil {
|
||||||
var dc *dataCursor
|
var dc *dataCursor
|
||||||
|
dcCtx := ctx.Clone()
|
||||||
if initFunc, exists := ds[InitName]; exists && initFunc != nil {
|
if initFunc, exists := ds[InitName]; exists && initFunc != nil {
|
||||||
var args []any
|
var args []any
|
||||||
var resource any
|
var resource any
|
||||||
@@ -109,9 +110,10 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
if resource, err = initFunc.InvokeNamed(initCtx, InitName, actualParams); err != nil {
|
if resource, err = initFunc.InvokeNamed(initCtx, InitName, actualParams); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dcCtx := ctx.Clone()
|
|
||||||
exportObjects(dcCtx, initCtx)
|
exportObjects(dcCtx, initCtx)
|
||||||
dc = NewDataCursor(dcCtx, ds, resource)
|
dc = NewDataCursor(dcCtx, ds, resource)
|
||||||
|
} else {
|
||||||
|
dc = NewDataCursor(dcCtx, ds, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
v = dc
|
v = dc
|
||||||
|
|||||||
+4
-2
@@ -17,7 +17,7 @@ func TestIteratorParser(t *testing.T) {
|
|||||||
/* 6 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil},
|
/* 6 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil},
|
||||||
/* 7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); mul(it)`, int64(12000), nil},
|
/* 7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); mul(it)`, int64(12000), nil},
|
||||||
/* 8 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it++; it.index`, int64(0), nil},
|
/* 8 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it++; it.index`, int64(0), nil},
|
||||||
/* 9 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it.clean`, true, nil},
|
/* 9 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it.clean`, nil, nil},
|
||||||
/* 10 */ {`it=$(1,2,3); it++`, int64(1), nil},
|
/* 10 */ {`it=$(1,2,3); it++`, int64(1), nil},
|
||||||
/* 11 */ {`it=$(1,2,3); it++; it.reset; it++`, int64(1), nil},
|
/* 11 */ {`it=$(1,2,3); it++; it.reset; it++`, int64(1), nil},
|
||||||
/* 12 */ {`it=$([1,2,3,4],1); it++`, int64(2), nil},
|
/* 12 */ {`it=$([1,2,3,4],1); it++`, int64(2), nil},
|
||||||
@@ -25,8 +25,10 @@ func TestIteratorParser(t *testing.T) {
|
|||||||
/* 14 */ {`it=$([1,2,3,4],1,3,2); it++; it++;`, int64(4), nil},
|
/* 14 */ {`it=$([1,2,3,4],1,3,2); it++; it++;`, int64(4), nil},
|
||||||
/* 15 */ {`it=$([1,2,3,4],1,2,2); it++; it++;`, nil, `EOF`},
|
/* 15 */ {`it=$([1,2,3,4],1,2,2); it++; it++;`, nil, `EOF`},
|
||||||
/* 16 */ {`include "test-resources/filter.expr"; it=$(ds,10); it++`, int64(2), nil},
|
/* 16 */ {`include "test-resources/filter.expr"; it=$(ds,10); it++`, int64(2), nil},
|
||||||
|
/* 17 */ {`it=$({"next":func(){5}}); it++`, int64(5), nil},
|
||||||
|
/* 18 */ {`it=$({"next":func(){5}}); it.clean`, nil, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 11)
|
//runTestSuiteSpec(t, section, inputs, 18)
|
||||||
runTestSuite(t, section, inputs)
|
runTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user