Compare commits
8 Commits
v0.26.0
...
778d00677d
| Author | SHA1 | Date | |
|---|---|---|---|
| 778d00677d | |||
| ba3dbb7f02 | |||
| 7285109115 | |||
| 4755774edd | |||
| d215d837f6 | |||
| ad3c1e5a60 | |||
| d6bf5ee500 | |||
| 4b176eb868 |
@@ -6,6 +6,7 @@ package expr
|
||||
|
||||
const (
|
||||
TypeAny = "any"
|
||||
TypeNil = "nil"
|
||||
TypeBoolean = "boolean"
|
||||
TypeFloat = "float"
|
||||
TypeFraction = "fraction"
|
||||
@@ -15,6 +16,7 @@ const (
|
||||
TypeNumber = "number"
|
||||
TypePair = "pair"
|
||||
TypeString = "string"
|
||||
TypeDict = "dict"
|
||||
TypeListOf = "list-of-"
|
||||
TypeListOfStrings = "list-of-strings"
|
||||
)
|
||||
|
||||
+139
-74
@@ -6,12 +6,14 @@ package expr
|
||||
|
||||
import (
|
||||
"io"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type dataCursor struct {
|
||||
ds map[string]Functor
|
||||
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
|
||||
count int
|
||||
current any
|
||||
@@ -26,6 +28,7 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da
|
||||
dc = &dataCursor{
|
||||
ds: ds,
|
||||
initState: true,
|
||||
// cursorValid: true,
|
||||
index: -1,
|
||||
count: 0,
|
||||
current: nil,
|
||||
@@ -36,7 +39,6 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da
|
||||
cleanFunc: ds[CleanName],
|
||||
resetFunc: ds[ResetName],
|
||||
}
|
||||
//dc.Next()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -77,7 +79,7 @@ func (dc *dataCursor) String() string {
|
||||
}
|
||||
|
||||
func (dc *dataCursor) HasOperation(name string) (exists bool) {
|
||||
exists = name == IndexName
|
||||
exists = slices.Contains([]string{CleanName, ResetName, CurrentName, IndexName}, name)
|
||||
if !exists {
|
||||
f, ok := dc.ds[name]
|
||||
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) {
|
||||
if name == IndexName {
|
||||
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) {
|
||||
if functor == dc.cleanFunc {
|
||||
value, err = dc.Clean()
|
||||
} else if functor == dc.resetFunc {
|
||||
value, err = dc.Reset()
|
||||
} else {
|
||||
ctx := cloneContext(dc.ctx)
|
||||
value, err = functor.InvokeNamed(ctx, name, args)
|
||||
exportObjects(dc.ctx, ctx)
|
||||
}
|
||||
ctx := cloneContext(dc.ctx)
|
||||
value, err = functor.InvokeNamed(ctx, name, args)
|
||||
exportObjects(dc.ctx, ctx)
|
||||
} else {
|
||||
err = errNoOperation(name)
|
||||
}
|
||||
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.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
|
||||
//dc.Next()
|
||||
} else {
|
||||
err = errInvalidDataSource()
|
||||
}
|
||||
} else {
|
||||
err = errNoOperation(ResetName)
|
||||
ctx := cloneContext(dc.ctx)
|
||||
actualParams := bindActualParams(dc.resetFunc, []any{dc.resource})
|
||||
_, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams)
|
||||
exportObjects(dc.ctx, ctx)
|
||||
}
|
||||
success = err == nil
|
||||
dc.index = -1
|
||||
dc.count = 0
|
||||
dc.initState = true
|
||||
dc.current = nil
|
||||
dc.lastErr = nil
|
||||
return
|
||||
}
|
||||
|
||||
func (dc *dataCursor) Clean() (success bool, err error) {
|
||||
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)
|
||||
// dc.resource = nil
|
||||
exportObjects(dc.ctx, ctx)
|
||||
} else {
|
||||
err = errInvalidDataSource()
|
||||
}
|
||||
} else {
|
||||
err = errNoOperation(CleanName)
|
||||
ctx := cloneContext(dc.ctx)
|
||||
actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource})
|
||||
_, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams)
|
||||
exportObjects(dc.ctx, ctx)
|
||||
}
|
||||
success = err == nil
|
||||
dc.lastErr = io.EOF
|
||||
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
|
||||
dc.init()
|
||||
|
||||
@@ -191,46 +213,89 @@ func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF af
|
||||
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++
|
||||
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)
|
||||
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()
|
||||
exportObjects(dc.ctx, ctx)
|
||||
}
|
||||
dc.current = item
|
||||
if dc.lastErr != nil {
|
||||
dc.index--
|
||||
dc.Clean()
|
||||
}
|
||||
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 {
|
||||
return dc.index - 1
|
||||
}
|
||||
|
||||
+225
-78
@@ -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.
|
||||
|
||||
_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_.
|
||||
|
||||
@@ -79,20 +79,20 @@ Here are some examples of execution.
|
||||
# Type 'exit' or Ctrl+D to quit the program.
|
||||
|
||||
[user]$ ./dev-expr
|
||||
dev-expr -- Expressions calculator v1.10.0(build 14),2024/06/17 (celestino.amoroso@portale-stac.it)
|
||||
Based on the Expr package v0.19.0
|
||||
dev-expr -- Expressions calculator v1.12.0(build 1),2024/09/14 (celestino.amoroso@portale-stac.it)
|
||||
Based on the Expr package v0.26.0
|
||||
Type help to get the list of available commands
|
||||
See also https://git.portale-stac.it/go-pkg/expr/src/branch/main/README.adoc
|
||||
>>> help
|
||||
--- REPL commands:
|
||||
source -- Load a file as input
|
||||
tty -- Enable/Disable ansi output <1>
|
||||
base -- Set the integer output base: 2, 8, 10, or 16
|
||||
exit -- Exit the program
|
||||
help -- Show command list
|
||||
ml -- Enable/Disable multi-line output
|
||||
mods -- List builtin modules
|
||||
output -- Enable/Disable printing expression results. Options 'on', 'off', 'status'
|
||||
source -- Load a file as input
|
||||
tty -- Enable/Disable ansi output <1>
|
||||
|
||||
--- Command line options:
|
||||
-b <builtin> Import builtin modules.
|
||||
@@ -155,9 +155,9 @@ _Expr_ supports three type of numbers:
|
||||
|
||||
. [blue]#Integers#
|
||||
. [blue]#Floats#
|
||||
. [blue]#Factions#
|
||||
. [blue]#Fractions#
|
||||
|
||||
In mixed operations involving integers, fractions and floats, automatic type promotion to the largest type take place.
|
||||
In mixed operations involving integers, fractions and floats, automatic type promotion to the largest type is performed.
|
||||
|
||||
==== Integers
|
||||
__Expr__'s integers are a subset of the integer set. Internally they are stored as Golang _int64_ values.
|
||||
@@ -183,11 +183,11 @@ Value range: *-9223372036854775808* to *9223372036854775807*
|
||||
[cols="^1,^2,6,4"]
|
||||
|===
|
||||
| Symbol | Operation | Description | Examples
|
||||
| [blue]`+` | _sum_ | Add two values | [blue]`-1 + 2` -> 1
|
||||
| [blue]`-` | _subtraction_ | Subtract the right value from the left one | [blue]`3 - 1` -> 2
|
||||
| [blue]`*` | _product_ | Multiply two values | [blue]`-1 * 2` -> -2
|
||||
| [blue]`/` | _Division_ | Divide the left value by the right one^(*)^ | [blue]`-10 / 2` -> 5
|
||||
| [blue]`%` | _Modulo_ | Remainder of the integer division | [blue]`5 % 2` -> 1
|
||||
| [blue]`+` | _Sum_ | Add two values | [blue]`-1 + 2` -> _1_
|
||||
| [blue]`-` | _Subtraction_ | Subtract the right value from the left one | [blue]`3 - 1` -> _2_
|
||||
| [blue]`*` | _Product_ | Multiply two values | [blue]`-1 * 2` -> _-2_
|
||||
| [blue]`/` | _Integer division_ | Divide the left value by the right one^(*)^ | [blue]`-11 / 2` -> _-5_
|
||||
| [blue]`%` | _Modulo_ | Remainder of the integer division | [blue]`5 % 2` -> _1_
|
||||
|===
|
||||
|
||||
^(*)^ See also the _float division_ [blue]`./` below.
|
||||
@@ -228,11 +228,11 @@ _dec-seq_ = _see-integer-literal-syntax_
|
||||
[cols="^1,^2,6,4"]
|
||||
|===
|
||||
| Symbol | Operation | Description | Examples
|
||||
| [blue]`+` | _sum_ | Add two values | [blue]`4 + 0.5` -> 4.5
|
||||
| [blue]`-` | _subtraction_ | Subtract the right value from the left one | [blue]`4 - 0.5` -> 3.5
|
||||
| [blue]`*` | _product_ | Multiply two values | [blue]`4 * 0.5` -> 2.0
|
||||
| [blue]`/` | _Division_ | Divide the left value by the right one | [blue]`1.0 / 2` -> 0.5
|
||||
| [blue]`./`| _Float division_ | Force float division | [blue]`-1 ./ 2` -> -0.5
|
||||
| [blue]`+` | _Sum_ | Add two values | [blue]`4 + 0.5` -> 4.5
|
||||
| [blue]`-` | _Subtraction_ | Subtract the right value from the left one | [blue]`4 - 0.5` -> 3.5
|
||||
| [blue]`*` | _Product_ | Multiply two values | [blue]`4 * 0.5` -> 2.0
|
||||
| [blue]`/` | _Float division_ | Divide the left value by the right one | [blue]`1.0 / 2` -> 0.5
|
||||
| [blue]`./`| _Forced float division_ | Force float division | [blue]`-1 ./ 2` -> -0.5
|
||||
|===
|
||||
|
||||
==== Fractions
|
||||
@@ -308,7 +308,7 @@ Strings are character sequences enclosed between two double quote [blue]`"`.
|
||||
`>>>` [blue]`"123\tabc"` +
|
||||
[green]`123{nbsp}{nbsp}{nbsp}{nbsp}abc`
|
||||
|
||||
Some arithmetic operators can also be used with strings.
|
||||
Some arithmetic operators also apply to strings.
|
||||
|
||||
.String operators
|
||||
[cols="^1,^2,6,4"]
|
||||
@@ -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"_
|
||||
|===
|
||||
|
||||
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
|
||||
====
|
||||
@@ -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)_ +
|
||||
[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"`
|
||||
|
||||
`>>>` [blue]`\#s` [gray]_// number of chars_ +
|
||||
`>>>` [blue]`#s` [gray]_// number of chars_ +
|
||||
[gren]`4`
|
||||
|
||||
`>>>` [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]`"b" \<= "b"` -> _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]`"b" \<= "b"` -> _true_
|
||||
[blue]`"b" >= "b"` -> _true_
|
||||
|===
|
||||
|
||||
^(*)^ 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]`"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_
|
||||
|===
|
||||
|
||||
@@ -413,7 +413,7 @@ _Expr_ supports list of mixed-type values, also specified by normal expressions.
|
||||
====
|
||||
*_list_* = _empty-list_ | _non-empty-list_ +
|
||||
_empty-list_ = "**[]**" +
|
||||
_non-empty-list_ = "**[**" _any-value_ {"**,**" _any-value} "**]**" +
|
||||
_non-empty-list_ = "**[**" _any-value_ {"**,**" _any-value_} "**]**" +
|
||||
====
|
||||
|
||||
.Examples
|
||||
@@ -444,6 +444,7 @@ _non-empty-list_ = "**[**" _any-value_ {"**,**" _any-value} "**]**" +
|
||||
| [blue]`[]` | _Item at index_ | Item at given position | [blue]`[1,2,3][1]` -> _2_
|
||||
| [blue]`in` | _Item in list_ | True if item is in list | [blue]`2 in [1,2,3]` -> _true_ +
|
||||
[blue]`6 in [1,2,3]` -> _false_
|
||||
| [blue]`#` | _Size_ | Number of items in a list | [blue]`#[1,2,3]` -> _3_
|
||||
|===
|
||||
|
||||
Array's items can be accessed using the index `[]` operator.
|
||||
@@ -458,38 +459,63 @@ Array's items can be accessed using the index `[]` operator.
|
||||
*_slice_* = _string-expr_ "**[**" _integer-expr_ "**:**" _integer-expr_ "**]**"
|
||||
====
|
||||
|
||||
.Items of list
|
||||
`>>>` [blue]`[1,2,3].1` +
|
||||
.Examples: Getting items from lists
|
||||
`>>>` [blue]`[1,2,3][1]` +
|
||||
[green]`2`
|
||||
|
||||
`>>>` [blue]`list=[1,2,3]; list.1` +
|
||||
[green]`2`
|
||||
|
||||
`>>>` [blue]`["one","two","three"].1` +
|
||||
[green]`two`
|
||||
|
||||
`>>>` [blue]`list=["one","two","three"]; list.(2-1)` +
|
||||
[green]`two`
|
||||
|
||||
`>>>` [blue]`list.(-1)` +
|
||||
[green]`three`
|
||||
|
||||
`>>>` [blue]`list.(10)` +
|
||||
[red]`Eval Error: [1:9] index 10 out of bounds`
|
||||
|
||||
`>>>` [blue]`#list` +
|
||||
[green]`3`
|
||||
|
||||
`>>>` [blue]`index=2; ["a", "b", "c", "d"][index]` +
|
||||
[green]`c`
|
||||
|
||||
|
||||
`>>>` [blue]`["a", "b", "c", "d"][2:]` +
|
||||
[green]`["c", "d"]`
|
||||
|
||||
`>>>` [blue]`list=[1,2,3]; list[1]` +
|
||||
[green]`2`
|
||||
|
||||
`>>>` [blue]`["one","two","three"][1]` +
|
||||
[green]`two`
|
||||
|
||||
`>>>` [blue]`list=["one","two","three"]; list[2-1]` +
|
||||
[green]`two`
|
||||
|
||||
`>>>` [blue]`list[1]="six"; list` +
|
||||
[green]`["one", "six", "three"]`
|
||||
|
||||
`>>>` [blue]`list[-1]` +
|
||||
[green]`three`
|
||||
|
||||
`>>>` [blue]`list[10]` +
|
||||
[red]`Eval Error: [1:9] index 10 out of bounds`
|
||||
|
||||
.Example: Number of elements in a list
|
||||
`>>>` [blue]`#list` +
|
||||
[green]`3`
|
||||
|
||||
.Examples: Element insertion
|
||||
`>>>` [blue]`"first" >> list` +
|
||||
[green]`["first", "one", "six", "three"]`
|
||||
|
||||
`>>>` [blue]`list << "last"` +
|
||||
[green]`["first", "one", "six", "three", "last"]`
|
||||
|
||||
.Examples: Element in list
|
||||
`>>>` [blue]`"six" in list` +
|
||||
[green]`true`
|
||||
|
||||
`>>>` [blue]`"ten" in list` +
|
||||
[green]`false`
|
||||
|
||||
.Examples: Concatenation and filtering
|
||||
`>>>` [blue]`[1,2,3] + ["one", "two", "three"]` +
|
||||
[green]`[1, 2, 3, "one", "two", "three"]`
|
||||
|
||||
`>>>` [blue]`[1,2,3,4] - [2,4]` +
|
||||
[green]`[1, 3]`
|
||||
|
||||
|
||||
|
||||
=== Dictionaries
|
||||
The _dictionary_, or _dict_, data-type is set of pairs _key/value_. It is also known as _map_ or _associative array_.
|
||||
The _dictionary_, or _dict_, data-type represents sets of pairs _key/value_. It is also known as _map_ or _associative array_.
|
||||
|
||||
Dictionary literals are sequences of pairs separated by comma [blue]`,` enclosed between brace brackets.
|
||||
|
||||
@@ -497,7 +523,7 @@ Dictionary literals are sequences of pairs separated by comma [blue]`,` enclosed
|
||||
====
|
||||
*_dict_* = _empty-dict_ | _non-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_} "**}**" +
|
||||
====
|
||||
|
||||
|
||||
@@ -515,6 +541,7 @@ _non-empty-dict_ = "**{**" _key-scalar_ "**:**" _any-value_ {"**,**" _key-scalar
|
||||
| [blue]`[]` | _Dict item value_ | Item value of given key | [blue]`{"one":1, "two":2}["two"]` -> _2_
|
||||
| [blue]`in` | _Key in dict_ | True if key is in dict | [blue]`"one" in {"one":1, "two":2}` -> _true_ +
|
||||
[blue]`"six" in {"one":1, "two":2}` -> _false_
|
||||
| [blue]`#` | _Size_ | Number of items in a dict | [blue]`#{1:"a",2:"b",3:"c"}` -> _3_
|
||||
|===
|
||||
|
||||
.Examples
|
||||
@@ -533,6 +560,9 @@ _non-empty-dict_ = "**{**" _key-scalar_ "**:**" _any-value_ {"**,**" _key-scalar
|
||||
`>>>` [blue]`d={"one":1, "two":2}; d["six"]=6; d` +
|
||||
[green]`{"two": 2, "one": 1, "six": 6}`
|
||||
|
||||
`>>>` [blue]`#d` +
|
||||
[green]`3`
|
||||
|
||||
|
||||
== Variables
|
||||
_Expr_, like most programming languages, supports variables. A variable is an identifier with an assigned value. Variables are stored in _contexts_.
|
||||
@@ -551,18 +581,18 @@ NOTE: The assign operator [blue]`=` returns the value assigned to the variable.
|
||||
[green]`1`
|
||||
|
||||
`>>>` [blue]`a_b=1+2` +
|
||||
[green]`1+2`
|
||||
[green]`3`
|
||||
|
||||
`>>>` [blue]`a_b` +
|
||||
[green]`3`
|
||||
|
||||
`>>>` [blue]`x = 5.2 * (9-3)` [gray]_// The assigned value has the typical approximation error of the float data-type_ +
|
||||
`>>>` [blue]`x = 5.2 * (9-3)` [gray]_// The assigned value here has the typical approximation error of the float data-type_ +
|
||||
[green]`31.200000000000003`
|
||||
|
||||
`>>>` [blue]`x = 1; y = 2*x` +
|
||||
[green]`2`
|
||||
|
||||
`>>>` [blue]`_a=2` +
|
||||
`>>>` [blue]`\_a=2` +
|
||||
[red]`Parse Error: [1:2] unexpected token "_"`
|
||||
|
||||
`>>>` [blue]`1=2` +
|
||||
@@ -574,12 +604,12 @@ NOTE: The assign operator [blue]`=` returns the value assigned to the variable.
|
||||
=== [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.
|
||||
|
||||
.Mult-expression syntax
|
||||
.Multi-expression syntax
|
||||
====
|
||||
*_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.
|
||||
|
||||
@@ -589,7 +619,7 @@ TIP: [blue]`;` can be used to set some variables before the final calculation.
|
||||
`>>>` [blue]`a=1; b=2; c=3; a+b+c` +
|
||||
[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
|
||||
`>>>` [blue]`2+3; b=last+10; last` +
|
||||
@@ -600,9 +630,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.
|
||||
|
||||
.Examples
|
||||
[blue]`5 but 2` +
|
||||
[green]`2` +
|
||||
[blue]`x=2*3 but x-1` +
|
||||
`>>>` [blue]`5 but 2` +
|
||||
[green]`2`
|
||||
|
||||
`>>>` [blue]`x=2*3 but x-1` +
|
||||
[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]`)`.
|
||||
@@ -610,17 +641,21 @@ The value of each sub-expression is stored in the automatica variable _last_.
|
||||
=== Assignment operator [blue]`=`
|
||||
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
|
||||
`>>>` [blue]`a=15+1`
|
||||
.Examples
|
||||
`>>>` [blue]`a=15+1` +
|
||||
[green]`16`
|
||||
|
||||
`>>>` [blue]`L=[1,2,3]; L[1]=5; L` +
|
||||
[green]`[1, 5, 3]`
|
||||
|
||||
|
||||
=== Selector operator [blue]`? : ::`
|
||||
The _selector operator_ is very similar to the _switch/case/default_ statement available in many programming languages.
|
||||
|
||||
.Selector literal Syntax
|
||||
====
|
||||
_selector-operator_ = _select-expression_ "*?*" _selector-case_ { "*:*" _selector-case_ } ["*::*" _default-multi-expression_] +
|
||||
_selector-case_ = [_match-list_] _case-value_ +
|
||||
_match-list_ = "*[*" _item_ {"*,*" _items_} "*]*" +
|
||||
@@ -628,6 +663,7 @@ _item_ = _expression_ +
|
||||
_case-multi-expression_ = "*{*" _multi-expression_ "*}*" +
|
||||
_multi-expression_ = _expression_ { "*;*" _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.
|
||||
|
||||
@@ -658,8 +694,8 @@ The [blue]`:` symbol (colon) is the separator of the selector-cases. Note that i
|
||||
[red]`Eval Error: [1:3] no case catches the value (10) of the selection expression`
|
||||
|
||||
|
||||
=== Variable default value [blue]`??` and [blue]`?=`
|
||||
The left operand of these two operators must be a variable. The right operator can be any expression. They return the value of the variable if this is defined; otherwise they return the value of the right expression.
|
||||
=== Variable default value [blue]`??`, [blue]`?=`, and [blue]`?!`
|
||||
The left operand of first two operators, [blue]`??` and [blue]`?=`, must be a variable. The right operator can be any expression. They return the value of the variable if this is defined; otherwise they return the value of the right expression.
|
||||
|
||||
IMPORTANT: If the left variable is defined, the right expression is not evaluated at all.
|
||||
|
||||
@@ -667,8 +703,12 @@ 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 third one, [blue]`?!`, is the alternate operator. If the variable on the left size is not defined, it returns [blue]_nil_. Otherwise it returns the result of the expressione on the right side.
|
||||
|
||||
IMPORTANT: If the left variable is NOT defined, the right expression is not evaluated at all.
|
||||
|
||||
.Examples
|
||||
`>>>` [blue]`var ?? (1+2)`' +
|
||||
`>>>` [blue]`var ?? (1+2)` +
|
||||
[green]`3`
|
||||
|
||||
`>>>` [blue]`var` +
|
||||
@@ -677,9 +717,18 @@ The [blue]`?=` assigns the calculated value of the right expression to the left
|
||||
`>>>` [blue]`var ?= (1+2)` +
|
||||
[green]`3`
|
||||
|
||||
`>>>` [blue]`var`
|
||||
`>>>` [blue]`var` +
|
||||
[green]`3`
|
||||
|
||||
`>>>` [blue]`x ?! 5` +
|
||||
[green]`nil`
|
||||
|
||||
`>>>` [blue]`x=1; x ?! 5` +
|
||||
[green]`5`
|
||||
|
||||
`>>>` [blue]`y ?! (c=5); c` +
|
||||
[red]`Eval Error: undefined variable or function "c"`
|
||||
|
||||
NOTE: These operators have a high priority, in particular higher than the operator [blue]`=`.
|
||||
|
||||
== Priorities of operators
|
||||
@@ -694,9 +743,10 @@ The table below shows all supported operators by decreasing priorities.
|
||||
| [blue]`[`...`]` | _Postfix_ | _Dict item_ | _dict_ `[` _any_ `]` -> _any_
|
||||
.2+|*INC*| [blue]`++` | _Postfix_ | _Post increment_| _integer-variable_ `++` -> _integer_
|
||||
| [blue]`++` | _Postfix_ | _Next item_ | _iterator_ `++` -> _any_
|
||||
.2+|*DEFAULT*| [blue]`??` | _Infix_ | _Default value_| _variable_ `??` _any-expr_ -> _any_
|
||||
.3+|*DEFAULT*| [blue]`??` | _Infix_ | _Default value_| _variable_ `??` _any-expr_ -> _any_
|
||||
| [blue]`?=` | _Infix_ | _Default/assign value_| _variable_ `?=` _any-expr_ -> _any_
|
||||
.1+| *ITER*^1^| [blue]`()` | _Prefix_ | _Iterator value_ | `()` _iterator_ -> _any_
|
||||
| [blue]`?!` | _Infix_ | _Alternate value_| _variable_ `?!` _any-expr_ -> _any_
|
||||
//.1+| *ITER*^1^| [blue]`()` | _Prefix_ | _Iterator value_ | `()` _iterator_ -> _any_
|
||||
.1+|*FACT*| [blue]`!` | _Postfix_ | _Factorial_| _integer_ `!` -> _integer_
|
||||
.3+|*SIGN*| [blue]`+`, [blue]`-` | _Prefix_ | _Change-sign_| (`+`\|`-`) _number_ -> _number_
|
||||
| [blue]`#` | _Prefix_ | _Lenght-of_ | `#` _collection_ -> _integer_
|
||||
@@ -735,36 +785,133 @@ The table below shows all supported operators by decreasing priorities.
|
||||
.1+|*RANGE*| [blue]`:` | _Infix_ | _Index-range_ | _integer_ `:` _integer_ -> _integer-pair_
|
||||
|===
|
||||
|
||||
^1^ Experimental
|
||||
//^1^ Experimental
|
||||
|
||||
|
||||
== 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.
|
||||
* _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
|
||||
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 and passing paramters by name.
|
||||
|
||||
. Expr's function definition syntax
|
||||
.Expr's function definition syntax
|
||||
====
|
||||
*_function-definition_* = _identifier_ "**=**" "**func(**" [_param-list_] "**)**" "**{**" _multi-expression_ "**}**"
|
||||
_param_list_ = _required-param-list_ [ "**,**" _optional-param-list_ ]
|
||||
_required-param-list_ = _identifier_ { "**,**" _identifier_ }
|
||||
_optional-param-list_ = _optional-parm_ { "**,**" _optional-param_ }
|
||||
_optional-param_ = _identifier_ "**=**" _any-expr_
|
||||
*_function-definition_* = _identifier_ "**=**" "**func(**" [_formal-param-list_] "**)**" "**{**" _multi-expression_ "**}**" +
|
||||
_formal-param_list_ = _required-param-list_ [ "**,**" _optional-param-list_ ] +
|
||||
_required-param-list_ = _identifier_ { "**,**" _identifier_ } +
|
||||
_optional-param-list_ = _optional-parm_ { "**,**" _optional-param_ } +
|
||||
_optional-param_ = _param-name_ "**=**" _any-expr_ +
|
||||
_param-name_ = _identifier_
|
||||
====
|
||||
|
||||
.Examples
|
||||
#TODO#
|
||||
`>>>` [gray]_// A simple function: it takes two parameters and returns their "sum"_**^(*)^** +
|
||||
`>>>` [blue]`sum = func(a, b){ a + b }` +
|
||||
[green]`sum(a, b):any{}`
|
||||
|
||||
^(\*)^ Since the plus, *+*, operator is defined for multiple data-types, the _sum()_ function can be used for any pair of that types.
|
||||
|
||||
`>>>` [gray]_// A more complex example: recursive calculation of the n-th value of Fibonacci's sequence_ +
|
||||
`>>>` [blue]`fib = func(n){ n ? [0] {0}: [1] {1} :: {fib(n-1)+fib(n-2)} }` +
|
||||
[green]`fib(n):any{}`
|
||||
|
||||
|
||||
`>>>` [gray]_// Same function fib() but entered by splitting it over mulple text lines_ +
|
||||
`>>>` [blue]`fib = func(n){ \` +
|
||||
`\...` [blue]`{nbsp}{nbsp}n ? \` +
|
||||
`\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}[0] {0} : \` +
|
||||
`\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}[1] {1} :: \` +
|
||||
`\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}{ \` +
|
||||
`\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}{nbsp}{nbsp}fib(n-1) + fib(n-2) \` +
|
||||
`\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}} \` +
|
||||
`\...` [blue]`}` +
|
||||
[green]`fib(n):any{}`
|
||||
|
||||
`>>>` [gray]_// Required and optional parameters_ +
|
||||
`>>>` [blue]`measure = func(value, unit="meter"){ value + " " + unit + (value > 1) ? [true] {"s"} :: {""}}` +
|
||||
[green]`measure(value, unit="meter"):any{}`
|
||||
|
||||
|
||||
=== _Golang_ function definition
|
||||
Description of how to define Golan functions and how to bind them to _Expr_ are topics treated in another document that I'll write, one day, maybe.
|
||||
|
||||
=== Function calls
|
||||
#TODO: function calls operations#
|
||||
To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters.
|
||||
|
||||
.Function invocation syntax
|
||||
====
|
||||
*_function-call_* = _identifier_ "**(**" _actual-param-list_ "**)**" +
|
||||
_actual-param-list_ = [_positional-params_] [_named-parameters_] +
|
||||
_positional-params_ = _any-value_ { "*,*" _any-value_ } +
|
||||
_named-params_ = _param-name_ "**=**" _any-value_ { "*,*" _param-name_ "**=**" _any-value_ } +
|
||||
_param-name_ = _identifier_
|
||||
====
|
||||
|
||||
.Examples of calling the `sum()` functions defined above
|
||||
`>>>` [gray]_// sum of two integers_ +
|
||||
`>>>` [blue]`sum(-6, 2)` +
|
||||
[green]`-4` +
|
||||
`>>>` [gray]_// same as above but passing the parameters by name_ +
|
||||
`>>>` [blue]`sum(a=-6, b=2)` +
|
||||
[green]`-4` +
|
||||
`>>>` [gray]_// again, but swapping parameter positions (see the diff() examples below)_ +
|
||||
`>>>` [blue]`sum(b=2, a=-6)` +
|
||||
[green]`-4` +
|
||||
`>>>` [gray]_// sum of a fraction and an integer_ +
|
||||
`>>>` [blue]`sum(3|2, 2)` +
|
||||
[green]`7|2` +
|
||||
`>>>` [gray]_// sum of two strings_ +
|
||||
`>>>` [blue]`sum("bye", "-bye")` +
|
||||
[green]`"bye-bye"` +
|
||||
`>>>` [gray]_// sum of two lists_ +
|
||||
`>>>` [blue]`sum(["one", 1], ["two", 2])` +
|
||||
[green]`["one", 1, "two", 2]`
|
||||
|
||||
.Examples of calling a function with parameters passed by name
|
||||
`>>>` [gray]_// diff(a,b) calculates a-b_ +
|
||||
`>>>` [blue]`diff = func(a,b){a-b}` +
|
||||
[green]`diff(a, b):any{}` +
|
||||
`>>>` [gray]_// simple invocation_ +
|
||||
`>>>` [blue]`diff(10,8)` +
|
||||
[green]`2` +
|
||||
`>>>` [gray]_// swapped parameters passed by name_ +
|
||||
`>>>` [blue]`diff(b=8,a=10)` +
|
||||
[green]`2`
|
||||
|
||||
.Examples of calling the `fib()` function defined above
|
||||
`>>>` [gray]_// Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ..._ +
|
||||
`>>>` [blue]`fib(6)` +
|
||||
[green]`8` +
|
||||
`>>>` [blue]`fib(9)` +
|
||||
[green]`34`
|
||||
|
||||
.Examples of calling the `measure()` functions defined above
|
||||
`>>>` [gray]_// simple call_ +
|
||||
`>>>` [blue]`measure(10,"litre")` +
|
||||
[green]`"10 litres"` +
|
||||
`>>>` [gray]_// accept the default unit_ +
|
||||
`>>>` [blue]`measure(8)` +
|
||||
[green]`"8 meters"` +
|
||||
`>>>` [gray]_// without the required parameter 'value'_ +
|
||||
`>>>` [blue]`measure(unit="degrees"))` +
|
||||
[red]`Eval Error: measure(): missing params -- value`
|
||||
|
||||
.Examples of context binding (closures)
|
||||
`>>>` [blue]`factory = func(n=2){ func(x){x*n} }` +
|
||||
[green]`factory(n=2):any{}` +
|
||||
`>>>` [blue]`double = factory()` +
|
||||
[green]`double(x):any{}` +
|
||||
`>>>` [blue]`triple = factory(3)` +
|
||||
[green]`triple(x):any{}` +
|
||||
`>>>` [blue]`double(5)` +
|
||||
[green]`10` +
|
||||
`>>>` [blue]`triple(5)` +
|
||||
[green]`15`
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
+285
-104
@@ -567,7 +567,7 @@ pre.rouge .ss {
|
||||
<li><a href="#_but_operator">4.2. <code class="blue">but</code> operator</a></li>
|
||||
<li><a href="#_assignment_operator">4.3. Assignment operator <code class="blue">=</code></a></li>
|
||||
<li><a href="#_selector_operator">4.4. Selector operator <code class="blue">? : ::</code></a></li>
|
||||
<li><a href="#_variable_default_value_and">4.5. Variable default value <code class="blue">??</code> and <code class="blue">?=</code></a></li>
|
||||
<li><a href="#_variable_default_value_and">4.5. Variable default value <code class="blue">??</code>, <code class="blue">?=</code>, and <code class="blue">?!</code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#_priorities_of_operators">5. Priorities of operators</a></li>
|
||||
@@ -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>
|
||||
</div>
|
||||
<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 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>
|
||||
@@ -687,20 +687,20 @@ pre.rouge .ss {
|
||||
<pre class="rouge highlight"><code data-lang="shell"><span class="c"># Type 'exit' or Ctrl+D to quit the program.</span>
|
||||
|
||||
<span class="o">[</span>user]<span class="nv">$ </span>./dev-expr
|
||||
dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o">(</span>build 14<span class="o">)</span>,2024/06/17 <span class="o">(</span>celestino.amoroso@portale-stac.it<span class="o">)</span>
|
||||
Based on the Expr package v0.19.0
|
||||
dev-expr <span class="nt">--</span> Expressions calculator v1.12.0<span class="o">(</span>build 1<span class="o">)</span>,2024/09/14 <span class="o">(</span>celestino.amoroso@portale-stac.it<span class="o">)</span>
|
||||
Based on the Expr package v0.26.0
|
||||
Type <span class="nb">help </span>to get the list of available commands
|
||||
See also https://git.portale-stac.it/go-pkg/expr/src/branch/main/README.adoc
|
||||
<span class="o">>>></span> <span class="nb">help</span>
|
||||
<span class="nt">---</span> REPL commands:
|
||||
<span class="nb">source</span> <span class="nt">--</span> Load a file as input
|
||||
<span class="nb">tty</span> <span class="nt">--</span> Enable/Disable ansi output <i class="conum" data-value="1"></i><b>(1)</b>
|
||||
base <span class="nt">--</span> Set the integer output base: 2, 8, 10, or 16
|
||||
<span class="nb">exit</span> <span class="nt">--</span> Exit the program
|
||||
<span class="nb">help</span> <span class="nt">--</span> Show <span class="nb">command </span>list
|
||||
ml <span class="nt">--</span> Enable/Disable multi-line output
|
||||
mods <span class="nt">--</span> List <span class="nb">builtin </span>modules
|
||||
output <span class="nt">--</span> Enable/Disable printing expression results. Options <span class="s1">'on'</span>, <span class="s1">'off'</span>, <span class="s1">'status'</span>
|
||||
<span class="nb">source</span> <span class="nt">--</span> Load a file as input
|
||||
<span class="nb">tty</span> <span class="nt">--</span> Enable/Disable ansi output <i class="conum" data-value="1"></i><b>(1)</b>
|
||||
|
||||
<span class="nt">---</span> Command line options:
|
||||
<span class="nt">-b</span> <<span class="nb">builtin</span><span class="o">></span> Import <span class="nb">builtin </span>modules.
|
||||
@@ -805,12 +805,12 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
<p><span class="blue">Floats</span></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><span class="blue">Factions</span></p>
|
||||
<p><span class="blue">Fractions</span></p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>In mixed operations involving integers, fractions and floats, automatic type promotion to the largest type take place.</p>
|
||||
<p>In mixed operations involving integers, fractions and floats, automatic type promotion to the largest type is performed.</p>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_integers"><a class="anchor" href="#_integers"></a><a class="link" href="#_integers">2.1.1. Integers</a></h4>
|
||||
@@ -855,33 +855,33 @@ 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">+</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>sum</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Sum</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Add two values</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 + 2</code> → 1</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 + 2</code> → <em>1</em></p></td>
|
||||
</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"><em>subtraction</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Subtraction</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Subtract the right value from the left one</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">3 - 1</code> → 2</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">3 - 1</code> → <em>2</em></p></td>
|
||||
</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"><em>product</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Product</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Multiply two values</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 * 2</code> → -2</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 * 2</code> → <em>-2</em></p></td>
|
||||
</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"><em>Division</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Integer division</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Divide the left value by the right one<sup>(*)</sup></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-10 / 2</code> → 5</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-11 / 2</code> → <em>-5</em></p></td>
|
||||
</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"><em>Modulo</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Remainder of the integer division</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">5 % 2</code> → 1</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">5 % 2</code> → <em>1</em></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -946,31 +946,31 @@ 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">+</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>sum</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Sum</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Add two values</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">4 + 0.5</code> → 4.5</p></td>
|
||||
</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"><em>subtraction</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Subtraction</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Subtract the right value from the left one</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">4 - 0.5</code> → 3.5</p></td>
|
||||
</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"><em>product</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Product</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Multiply two values</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">4 * 0.5</code> → 2.0</p></td>
|
||||
</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"><em>Division</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Float division</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Divide the left value by the right one</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">1.0 / 2</code> → 0.5</p></td>
|
||||
</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"><em>Float division</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Forced float division</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Force float division</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 ./ 2</code> → -0.5</p></td>
|
||||
</tr>
|
||||
@@ -1074,7 +1074,7 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
<code class="green">123    abc</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Some arithmetic operators can also be used with strings.</p>
|
||||
<p>Some arithmetic operators also apply to strings.</p>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all stretch">
|
||||
<caption class="title">Table 3. String operators</caption>
|
||||
@@ -1109,7 +1109,7 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
</tbody>
|
||||
</table>
|
||||
<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 class="exampleblock">
|
||||
<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>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<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-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>
|
||||
<code class="blue">"a" < "b"</code> → <em>false</em></p></td>
|
||||
<code class="blue">"a" > "b"</code> → <em>false</em></p></td>
|
||||
</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"><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"><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>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1256,7 +1256,7 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
<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"><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>
|
||||
<code class="blue">"a" == "b" OR (2 == 1)</code> → <em>false</em></p></td>
|
||||
</tr>
|
||||
@@ -1314,7 +1314,7 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
<div class="paragraph">
|
||||
<p><strong><em>list</em></strong> = <em>empty-list</em> | <em>non-empty-list</em><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>
|
||||
@@ -1393,6 +1393,12 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">2 in [1,2,3]</code> → <em>true</em><br>
|
||||
<code class="blue">6 in [1,2,3]</code> → <em>false</em></p></td>
|
||||
</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"><em>Size</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Number of items in a list</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">#[1,2,3]</code> → <em>3</em></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="paragraph">
|
||||
@@ -1415,35 +1421,11 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Items of list</div>
|
||||
<p><code>>>></code> <code class="blue">[1,2,3].1</code><br>
|
||||
<div class="title">Examples: Getting items from lists</div>
|
||||
<p><code>>>></code> <code class="blue">[1,2,3][1]</code><br>
|
||||
<code class="green">2</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list=[1,2,3]; list.1</code><br>
|
||||
<code class="green">2</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">["one","two","three"].1</code><br>
|
||||
<code class="green">two</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list=["one","two","three"]; list.(2-1)</code><br>
|
||||
<code class="green">two</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list.(-1)</code><br>
|
||||
<code class="green">three</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list.(10)</code><br>
|
||||
<code class="red">Eval Error: [1:9] index 10 out of bounds</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">#list</code><br>
|
||||
<code class="green">3</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">index=2; ["a", "b", "c", "d"][index]</code><br>
|
||||
<code class="green">c</code></p>
|
||||
</div>
|
||||
@@ -1451,11 +1433,67 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
<p><code>>>></code> <code class="blue">["a", "b", "c", "d"][2:]</code><br>
|
||||
<code class="green">["c", "d"]</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list=[1,2,3]; list[1]</code><br>
|
||||
<code class="green">2</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">["one","two","three"][1]</code><br>
|
||||
<code class="green">two</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list=["one","two","three"]; list[2-1]</code><br>
|
||||
<code class="green">two</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list[1]="six"; list</code><br>
|
||||
<code class="green">["one", "six", "three"]</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list[-1]</code><br>
|
||||
<code class="green">three</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list[10]</code><br>
|
||||
<code class="red">Eval Error: [1:9] index 10 out of bounds</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Example: Number of elements in a list</div>
|
||||
<p><code>>>></code> <code class="blue">#list</code><br>
|
||||
<code class="green">3</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples: Element insertion</div>
|
||||
<p><code>>>></code> <code class="blue">"first" >> list</code><br>
|
||||
<code class="green">["first", "one", "six", "three"]</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">list << "last"</code><br>
|
||||
<code class="green">["first", "one", "six", "three", "last"]</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples: Element in list</div>
|
||||
<p><code>>>></code> <code class="blue">"six" in list</code><br>
|
||||
<code class="green">true</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">"ten" in list</code><br>
|
||||
<code class="green">false</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples: Concatenation and filtering</div>
|
||||
<p><code>>>></code> <code class="blue">[1,2,3] + ["one", "two", "three"]</code><br>
|
||||
<code class="green">[1, 2, 3, "one", "two", "three"]</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">[1,2,3,4] - [2,4]</code><br>
|
||||
<code class="green">[1, 3]</code></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_dictionaries"><a class="anchor" href="#_dictionaries"></a><a class="link" href="#_dictionaries">2.5. Dictionaries</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>The <em>dictionary</em>, or <em>dict</em>, data-type is set of pairs <em>key/value</em>. It is also known as <em>map</em> or <em>associative array</em>.</p>
|
||||
<p>The <em>dictionary</em>, or <em>dict</em>, data-type represents sets of pairs <em>key/value</em>. It is also known as <em>map</em> or <em>associative array</em>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Dictionary literals are sequences of pairs separated by comma <code class="blue">,</code> enclosed between brace brackets.</p>
|
||||
@@ -1466,7 +1504,7 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
<div class="paragraph">
|
||||
<p><strong><em>dict</em></strong> = <em>empty-dict</em> | <em>non-empty-dict</em><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>
|
||||
@@ -1514,6 +1552,12 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">"one" in {"one":1, "two":2}</code> → <em>true</em><br>
|
||||
<code class="blue">"six" in {"one":1, "two":2}</code> → <em>false</em></p></td>
|
||||
</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"><em>Size</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Number of items in a dict</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">#{1:"a",2:"b",3:"c"}</code> → <em>3</em></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="paragraph">
|
||||
@@ -1537,6 +1581,10 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
|
||||
<p><code>>>></code> <code class="blue">d={"one":1, "two":2}; d["six"]=6; d</code><br>
|
||||
<code class="green">{"two": 2, "one": 1, "six": 6}</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">#d</code><br>
|
||||
<code class="green">3</code></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1575,14 +1623,14 @@ The assign operator <code class="blue">=</code> returns the value assigned to th
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<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 class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">a_b</code><br>
|
||||
<code class="green">3</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">x = 5.2 * (9-3)</code> <em class="gray">// The assigned value has the typical approximation error of the float data-type</em><br>
|
||||
<p><code>>>></code> <code class="blue">x = 5.2 * (9-3)</code> <em class="gray">// The assigned value here has the typical approximation error of the float data-type</em><br>
|
||||
<code class="green">31.200000000000003</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
@@ -1590,8 +1638,8 @@ The assign operator <code class="blue">=</code> returns the value assigned to th
|
||||
<code class="green">2</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue"><em>a=2</code><br>
|
||||
<code class="red">Parse Error: [1:2] unexpected token "</em>"</code></p>
|
||||
<p><code>>>></code> <code class="blue">_a=2</code><br>
|
||||
<code class="red">Parse Error: [1:2] unexpected token "_"</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">1=2</code><br>
|
||||
@@ -1608,7 +1656,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>
|
||||
</div>
|
||||
<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="paragraph">
|
||||
<p><strong><em>multi-expression</em></strong> = <em>expression</em> {"<strong>;</strong>" <em>expression</em> }</p>
|
||||
@@ -1616,7 +1664,7 @@ The assign operator <code class="blue">=</code> returns the value assigned to th
|
||||
</div>
|
||||
</div>
|
||||
<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 class="admonitionblock important">
|
||||
<table>
|
||||
@@ -1648,7 +1696,7 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
|
||||
<code class="green">6</code></p>
|
||||
</div>
|
||||
<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 class="paragraph">
|
||||
<div class="title">Example</div>
|
||||
@@ -1663,9 +1711,11 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples</div>
|
||||
<p><code class="blue">5 but 2</code><br>
|
||||
<code class="green">2</code><br>
|
||||
<code class="blue">x=2*3 but x-1</code><br>
|
||||
<p><code>>>></code> <code class="blue">5 but 2</code><br>
|
||||
<code class="green">2</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">x=2*3 but x-1</code><br>
|
||||
<code class="green">5</code>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
@@ -1678,21 +1728,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>
|
||||
</div>
|
||||
<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 class="paragraph">
|
||||
<div class="title">Example</div>
|
||||
<p><code>>>></code> <code class="blue">a=15+1</code>
|
||||
<div class="title">Examples</div>
|
||||
<p><code>>>></code> <code class="blue">a=15+1</code><br>
|
||||
<code class="green">16</code></p>
|
||||
</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 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>
|
||||
<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>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="title">Example 13. Selector literal Syntax</div>
|
||||
<div class="content">
|
||||
<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>
|
||||
<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>
|
||||
@@ -1701,6 +1757,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>default-multi-expression</em> = <em>multi-expression</em></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
@@ -1741,9 +1799,9 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_variable_default_value_and"><a class="anchor" href="#_variable_default_value_and"></a><a class="link" href="#_variable_default_value_and">4.5. Variable default value <code class="blue">??</code> and <code class="blue">?=</code></a></h3>
|
||||
<h3 id="_variable_default_value_and"><a class="anchor" href="#_variable_default_value_and"></a><a class="link" href="#_variable_default_value_and">4.5. Variable default value <code class="blue">??</code>, <code class="blue">?=</code>, and <code class="blue">?!</code></a></h3>
|
||||
<div class="paragraph">
|
||||
<p>The left operand of these two operators must be a variable. The right operator can be any expression. They return the value of the variable if this is defined; otherwise they return the value of the right expression.</p>
|
||||
<p>The left operand of first two operators, <code class="blue">??</code> and <code class="blue">?=</code>, must be a variable. The right operator can be any expression. They return the value of the variable if this is defined; otherwise they return the value of the right expression.</p>
|
||||
</div>
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
@@ -1764,9 +1822,24 @@ If the left variable is defined, the right expression is not evaluated at all.
|
||||
<p>The <code class="blue">?=</code> assigns the calculated value of the right expression to the left variable.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The third one, <code class="blue">?!</code>, is the alternate operator. If the variable on the left size is not defined, it returns <em class="blue">nil</em>. Otherwise it returns the result of the expressione on the right side.</p>
|
||||
</div>
|
||||
<div class="admonitionblock important">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="icon">
|
||||
<i class="fa icon-important" title="Important"></i>
|
||||
</td>
|
||||
<td class="content">
|
||||
If the left variable is NOT defined, the right expression is not evaluated at all.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples</div>
|
||||
<p><code>>>></code> <code class="blue">var ?? (1+2)’<br>
|
||||
[green]`3</code></p>
|
||||
<p><code>>>></code> <code class="blue">var ?? (1+2)</code><br>
|
||||
<code class="green">3</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">var</code><br>
|
||||
@@ -1777,9 +1850,21 @@ If the left variable is defined, the right expression is not evaluated at all.
|
||||
<code class="green">3</code></p>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">x ?! 5</code><br>
|
||||
<code class="green">nil</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">x=1; x ?! 5</code><br>
|
||||
<code class="green">5</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <code class="blue">y ?! (c=5); c</code><br>
|
||||
<code class="red">Eval Error: undefined variable or function "c"</code></p>
|
||||
</div>
|
||||
<div class="admonitionblock note">
|
||||
<table>
|
||||
<tr>
|
||||
@@ -1847,7 +1932,7 @@ These operators have a high priority, in particular higher than the operator <co
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>iterator</em> <code>++</code> → <em>any</em></p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>DEFAULT</strong></p></td>
|
||||
<td class="tableblock halign-center valign-top" rowspan="3"><p class="tableblock"><strong>DEFAULT</strong></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>Infix</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Default value</em></p></td>
|
||||
@@ -1860,11 +1945,10 @@ These operators have a high priority, in particular higher than the operator <co
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>variable</em> <code>?=</code> <em>any-expr</em> → <em>any</em></p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>ITER</strong><sup>1</sup></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>Prefix</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Iterator value</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code>()</code> <em>iterator</em> → <em>any</em></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>Infix</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Alternate value</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>variable</em> <code>?!</code> <em>any-expr</em> → <em>any</em></p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>FACT</strong></p></td>
|
||||
@@ -2097,16 +2181,13 @@ These operators have a high priority, in particular higher than the operator <co
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="paragraph">
|
||||
<p><sup>1</sup> Experimental</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="_functions"><a class="anchor" href="#_functions"></a><a class="link" href="#_functions">6. Functions</a></h2>
|
||||
<div class="sectionbody">
|
||||
<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 class="ulist">
|
||||
<ul>
|
||||
@@ -2114,36 +2195,58 @@ 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>
|
||||
</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>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_expr_function_definition"><a class="anchor" href="#_expr_function_definition"></a><a class="link" href="#_expr_function_definition">6.1. <em>Expr</em> function definition</a></h3>
|
||||
<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>
|
||||
</div>
|
||||
<div class="olist arabic">
|
||||
<ol class="arabic">
|
||||
<li>
|
||||
<p>Expr’s function definition syntax</p>
|
||||
</li>
|
||||
</ol>
|
||||
<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 and passing paramters by name.</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="title">Example 14. Expr’s function definition syntax</div>
|
||||
<div class="content">
|
||||
<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>"
|
||||
<em>param_list</em> = <em>required-param-list</em> [ "<strong>,</strong>" <em>optional-param-list</em> ]
|
||||
<em>required-param-list</em> = <em>identifier</em> { "<strong>,</strong>" <em>identifier</em> }
|
||||
<em>optional-param-list</em> = <em>optional-parm</em> { "<strong>,</strong>" <em>optional-param</em> }
|
||||
<em>optional-param</em> = <em>identifier</em> "<strong>=</strong>" <em>any-expr</em></p>
|
||||
<p><strong><em>function-definition</em></strong> = <em>identifier</em> "<strong>=</strong>" "<strong>func(</strong>" [<em>formal-param-list</em>] "<strong>)</strong>" "<strong>{</strong>" <em>multi-expression</em> "<strong>}</strong>"<br>
|
||||
<em>formal-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> }<br>
|
||||
<em>optional-param-list</em> = <em>optional-parm</em> { "<strong>,</strong>" <em>optional-param</em> }<br>
|
||||
<em>optional-param</em> = <em>param-name</em> "<strong>=</strong>" <em>any-expr</em><br>
|
||||
<em>param-name</em> = <em>identifier</em></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples</div>
|
||||
<p><mark>TODO</mark></p>
|
||||
<p><code>>>></code> <em class="gray">// A simple function: it takes two parameters and returns their "sum"</em><strong><sup>(*)</sup></strong><br>
|
||||
<code>>>></code> <code class="blue">sum = func(a, b){ a + b }</code><br>
|
||||
<code class="green">sum(a, b):any{}</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><sup>(*)</sup> Since the plus, *+*, operator is defined for multiple data-types, the <em>sum()</em> function can be used for any pair of that types.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <em class="gray">// A more complex example: recursive calculation of the n-th value of Fibonacci’s sequence</em><br>
|
||||
<code>>>></code> <code class="blue">fib = func(n){ n ? [0] {0}: [1] {1} :: {fib(n-1)+fib(n-2)} }</code><br>
|
||||
<code class="green">fib(n):any{}</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <em class="gray">// Same function fib() but entered by splitting it over mulple text lines</em><br>
|
||||
<code>>>></code> <code class="blue">fib = func(n){ \</code><br>
|
||||
<code>...</code> <code class="blue">  n ? \</code><br>
|
||||
<code>...</code> <code class="blue">    [0] {0} : \</code><br>
|
||||
<code>...</code> <code class="blue">    [1] {1} :: \</code><br>
|
||||
<code>...</code> <code class="blue">    { \</code><br>
|
||||
<code>...</code> <code class="blue">      fib(n-1) + fib(n-2) \</code><br>
|
||||
<code>...</code> <code class="blue">    } \</code><br>
|
||||
<code>...</code> <code class="blue">}</code><br>
|
||||
<code class="green">fib(n):any{}</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>>>></code> <em class="gray">// Required and optional parameters</em><br>
|
||||
<code>>>></code> <code class="blue">measure = func(value, unit="meter"){ value + " " + unit + (value > 1) ? [true] {"s"} :: {""}}</code><br>
|
||||
<code class="green">measure(value, unit="meter"):any{}</code></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
@@ -2155,7 +2258,85 @@ These operators have a high priority, in particular higher than the operator <co
|
||||
<div class="sect2">
|
||||
<h3 id="_function_calls"><a class="anchor" href="#_function_calls"></a><a class="link" href="#_function_calls">6.3. Function calls</a></h3>
|
||||
<div class="paragraph">
|
||||
<p><mark>TODO: function calls operations</mark></p>
|
||||
<p>To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters.</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="title">Example 15. Function invocation syntax</div>
|
||||
<div class="content">
|
||||
<div class="paragraph">
|
||||
<p><strong><em>function-call</em></strong> = <em>identifier</em> "<strong>(</strong>" <em>actual-param-list</em> "<strong>)</strong>"<br>
|
||||
<em>actual-param-list</em> = [<em>positional-params</em>] [<em>named-parameters</em>]<br>
|
||||
<em>positional-params</em> = <em>any-value</em> { "<strong>,</strong>" <em>any-value</em> }<br>
|
||||
<em>named-params</em> = <em>param-name</em> "<strong>=</strong>" <em>any-value</em> { "<strong>,</strong>" <em>param-name</em> "<strong>=</strong>" <em>any-value</em> }<br>
|
||||
<em>param-name</em> = <em>identifier</em></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples of calling the <code>sum()</code> functions defined above</div>
|
||||
<p><code>>>></code> <em class="gray">// sum of two integers</em><br>
|
||||
<code>>>></code> <code class="blue">sum(-6, 2)</code><br>
|
||||
<code class="green">-4</code><br>
|
||||
<code>>>></code> <em class="gray">// same as above but passing the parameters by name</em><br>
|
||||
<code>>>></code> <code class="blue">sum(a=-6, b=2)</code><br>
|
||||
<code class="green">-4</code><br>
|
||||
<code>>>></code> <em class="gray">// again, but swapping parameter positions (see the diff() examples below)</em><br>
|
||||
<code>>>></code> <code class="blue">sum(b=2, a=-6)</code><br>
|
||||
<code class="green">-4</code><br>
|
||||
<code>>>></code> <em class="gray">// sum of a fraction and an integer</em><br>
|
||||
<code>>>></code> <code class="blue">sum(3|2, 2)</code><br>
|
||||
<code class="green">7|2</code><br>
|
||||
<code>>>></code> <em class="gray">// sum of two strings</em><br>
|
||||
<code>>>></code> <code class="blue">sum("bye", "-bye")</code><br>
|
||||
<code class="green">"bye-bye"</code><br>
|
||||
<code>>>></code> <em class="gray">// sum of two lists</em><br>
|
||||
<code>>>></code> <code class="blue">sum(["one", 1], ["two", 2])</code><br>
|
||||
<code class="green">["one", 1, "two", 2]</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples of calling a function with parameters passed by name</div>
|
||||
<p><code>>>></code> <em class="gray">// diff(a,b) calculates a-b</em><br>
|
||||
<code>>>></code> <code class="blue">diff = func(a,b){a-b}</code><br>
|
||||
<code class="green">diff(a, b):any{}</code><br>
|
||||
<code>>>></code> <em class="gray">// simple invocation</em><br>
|
||||
<code>>>></code> <code class="blue">diff(10,8)</code><br>
|
||||
<code class="green">2</code><br>
|
||||
<code>>>></code> <em class="gray">// swapped parameters passed by name</em><br>
|
||||
<code>>>></code> <code class="blue">diff(b=8,a=10)</code><br>
|
||||
<code class="green">2</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples of calling the <code>fib()</code> function defined above</div>
|
||||
<p><code>>>></code> <em class="gray">// Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …​</em><br>
|
||||
<code>>>></code> <code class="blue">fib(6)</code><br>
|
||||
<code class="green">8</code><br>
|
||||
<code>>>></code> <code class="blue">fib(9)</code><br>
|
||||
<code class="green">34</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples of calling the <code>measure()</code> functions defined above</div>
|
||||
<p><code>>>></code> <em class="gray">// simple call</em><br>
|
||||
<code>>>></code> <code class="blue">measure(10,"litre")</code><br>
|
||||
<code class="green">"10 litres"</code><br>
|
||||
<code>>>></code> <em class="gray">// accept the default unit</em><br>
|
||||
<code>>>></code> <code class="blue">measure(8)</code><br>
|
||||
<code class="green">"8 meters"</code><br>
|
||||
<code>>>></code> <em class="gray">// without the required parameter 'value'</em><br>
|
||||
<code>>>></code> <code class="blue">measure(unit="degrees"))</code><br>
|
||||
<code class="red">Eval Error: measure(): missing params — value</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples of context binding (closures)</div>
|
||||
<p><code>>>></code> <code class="blue">factory = func(n=2){ func(x){x*n} }</code><br>
|
||||
<code class="green">factory(n=2):any{}</code><br>
|
||||
<code>>>></code> <code class="blue">double = factory()</code><br>
|
||||
<code class="green">double(x):any{}</code><br>
|
||||
<code>>>></code> <code class="blue">triple = factory(3)</code><br>
|
||||
<code class="green">triple(x):any{}</code><br>
|
||||
<code>>>></code> <code class="blue">double(5)</code><br>
|
||||
<code class="green">10</code><br>
|
||||
<code>>>></code> <code class="blue">triple(5)</code><br>
|
||||
<code class="green">15</code></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>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 <code class="blue">@</code> it is possibile to export local definition to the calling context.</p>
|
||||
@@ -2200,7 +2381,7 @@ These operators have a high priority, in particular higher than the operator <co
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2024-06-21 09:06:12 +0200
|
||||
Last updated 2024-09-18 20:46:46 +0200
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
+2
-2
@@ -348,8 +348,8 @@ func CallFunctionByArgs(parentCtx ExprContext, name string, args []any) (result
|
||||
return
|
||||
}
|
||||
|
||||
func CallFunctionByParams(parentCtx ExprContext, name string, params map[string]any) (result any, err error) {
|
||||
var actualParams map[string]any
|
||||
func CallFunctionByParams(parentCtx ExprContext, name string, actualParams map[string]any) (result any, err error) {
|
||||
//var actualParams map[string]any
|
||||
if info, exists := GetFuncInfo(parentCtx, name); exists {
|
||||
functor := info.Functor()
|
||||
ctx := info.AllocContext(parentCtx)
|
||||
|
||||
@@ -33,6 +33,8 @@ type Iterator interface {
|
||||
|
||||
type ExtIterator interface {
|
||||
Iterator
|
||||
Reset() error
|
||||
Clean() error
|
||||
HasOperation(name string) bool
|
||||
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:
|
||||
v, err = it.Next()
|
||||
case ResetName:
|
||||
v, err = it.Reset()
|
||||
err = it.Reset()
|
||||
case CleanName:
|
||||
err = it.Clean()
|
||||
case IndexName:
|
||||
v = int64(it.Index())
|
||||
case CurrentName:
|
||||
@@ -147,8 +149,12 @@ func (it *ListIterator) Count() int {
|
||||
return it.count
|
||||
}
|
||||
|
||||
func (it *ListIterator) Reset() (bool, error) {
|
||||
func (it *ListIterator) Reset() (error) {
|
||||
it.index = it.start - it.step
|
||||
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 {
|
||||
var dc *dataCursor
|
||||
dcCtx := ctx.Clone()
|
||||
if initFunc, exists := ds[InitName]; exists && initFunc != nil {
|
||||
var args []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 {
|
||||
return
|
||||
}
|
||||
dcCtx := ctx.Clone()
|
||||
exportObjects(dcCtx, initCtx)
|
||||
dc = NewDataCursor(dcCtx, ds, resource)
|
||||
} else {
|
||||
dc = NewDataCursor(dcCtx, ds, nil)
|
||||
}
|
||||
|
||||
v = dc
|
||||
|
||||
@@ -417,6 +417,7 @@ func (parser *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarR
|
||||
case SymEqual:
|
||||
// if err = checkPrevSymbol(lastSym, SymIdentifier, tk); err == nil {
|
||||
currentTerm, err = tree.addToken(tk)
|
||||
firstToken = true
|
||||
// }
|
||||
case SymFuncDef:
|
||||
var funcDefTerm *term
|
||||
@@ -483,7 +484,7 @@ func (parser *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarR
|
||||
// return
|
||||
// }
|
||||
|
||||
func (parser *parser) expandOpAssign(scanner * scanner, tree *ast, tk *Token, allowVarRef bool) (t *term, err error) {
|
||||
func (parser *parser) expandOpAssign(scanner *scanner, tree *ast, tk *Token, allowVarRef bool) (t *term, err error) {
|
||||
var opSym Symbol
|
||||
var opString string
|
||||
|
||||
|
||||
+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},
|
||||
/* 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},
|
||||
/* 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},
|
||||
/* 11 */ {`it=$(1,2,3); it++; it.reset; it++`, int64(1), 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},
|
||||
/* 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},
|
||||
/* 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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user