Compare commits
9 Commits
ac5c97bfd3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d8dc2939b4 | |||
| 6e868b568d | |||
| 73e4ad7b87 | |||
| b86ce6fe62 | |||
| 38316cec0b | |||
| ee7f488ebb | |||
| 02ea20cdb5 | |||
| 20cffbddfa | |||
| 4b2b573420 |
+109
-47
@@ -1,6 +1,7 @@
|
|||||||
= Expr
|
= Expr
|
||||||
Expressions calculator
|
Expressions calculator
|
||||||
:authors: Celestino Amoroso
|
:authors: Celestino Amoroso
|
||||||
|
:email: celestino.amoroso@gmail.com
|
||||||
:docinfo: shared
|
:docinfo: shared
|
||||||
:encoding: utf-8
|
:encoding: utf-8
|
||||||
:toc: right
|
:toc: right
|
||||||
@@ -16,10 +17,11 @@ Expressions calculator
|
|||||||
:sectlinks:
|
:sectlinks:
|
||||||
:sectanchors:
|
:sectanchors:
|
||||||
:source-highlighter: rouge
|
:source-highlighter: rouge
|
||||||
// :rouge-style: ThankfulEyes
|
// :rouge-style: gruvbox
|
||||||
:rouge-style: gruvbox
|
:rouge-style: manni
|
||||||
// :rouge-style: colorful
|
:stylesdir: /home/share/s3-howto/styles
|
||||||
//:rouge-style: monokay
|
:stylesheet: adoc-colony.css
|
||||||
|
|
||||||
// Workaround to manage double-column in back-tick quotes
|
// Workaround to manage double-column in back-tick quotes
|
||||||
:2c: ::
|
:2c: ::
|
||||||
// Workaround to manage double-plus in back-tick quotes
|
// Workaround to manage double-plus in back-tick quotes
|
||||||
@@ -45,18 +47,18 @@ _Expr_ is a GO package that can analyze, interpret and calculate expressions.
|
|||||||
Expressions are texts containing sequences of operations represented by a syntax very similar to that of most programming languages. _Expr_ package provides these macro functions:
|
Expressions are texts containing sequences of operations represented by a syntax very similar to that of most programming languages. _Expr_ package provides these macro functions:
|
||||||
|
|
||||||
* *_Scanner_* -- Its input is a text. It scans expression text characters to produce a flow of logical symbol and related attributes, aka tokens.
|
* *_Scanner_* -- Its input is a text. It scans expression text characters to produce a flow of logical symbol and related attributes, aka tokens.
|
||||||
* *_Parser_* -- Parser input is the token flow coming from the scanner. It analyses the token flow verifyng if it complies with the _Expr_ syntax. If that is the case, the Parser generates the Abstract Syntax Tree (AST). This is tree data structure that represents the components of an expressions and how they are related one each other.
|
* *_Parser_* -- Parser input is the token flow coming from the scanner. It analyses the token flow verifying if it complies with the _Expr_ syntax. If that is the case, the Parser generates the Abstract Syntax Tree (AST). This is tree data structure that represents the components of an expression and how they are related to each other.
|
||||||
* *_Calculator_*. Its input is the AST. It computes the parsed expression contained in the AST and returns the result or an error.
|
* *_Calculator_*. Its input is the AST. It computes the parsed expression contained in the AST and returns the result or an error.
|
||||||
|
|
||||||
image::expression-diagram.png[]
|
image::expression-diagram.png[]
|
||||||
|
|
||||||
==== Variables
|
==== Variables
|
||||||
_Expr_ supports variables. The result of an expression can be stored in a variable and reused in other espressions by simply specifying the name of the variable as an operand.
|
_Expr_ supports variables. The result of an expression can be stored in a variable and reused in other expressions by simply specifying the name of the variable as an operand.
|
||||||
|
|
||||||
==== Multi-expression
|
==== Multi-expression
|
||||||
An input text valid for _Expr_ can contain more than an expression. Expressions are separated by [blue]`;` (semicolon). When an input contains two or more expressions it is called _multi-expression_.
|
An input text valid for _Expr_ can contain more than an expression. Expressions are separated by [blue]`;` (semicolon). When an input contains two or more expressions it is called _multi-expression_.
|
||||||
|
|
||||||
_Expr_ parses and computes each expression of a multi-espression, from the left to the right. If all expressions are computed without errors, it only returns the value of the last, the right most.
|
_Expr_ parses and computes each expression of a multi-expression, from the left to the right. If all expressions are computed without errors, it only returns the value of the last, the right most.
|
||||||
|
|
||||||
The result of each expression of a multi-expression is stored in an automatic variable named _last_. In this way, each expression can refer to the result of the previous one without the need to assign that value to a new dedicated variable.
|
The result of each expression of a multi-expression is stored in an automatic variable named _last_. In this way, each expression can refer to the result of the previous one without the need to assign that value to a new dedicated variable.
|
||||||
|
|
||||||
@@ -74,7 +76,7 @@ Imported functions are registered in the _global context_. When an expression fi
|
|||||||
===== Inspecting contexts
|
===== Inspecting contexts
|
||||||
_Expr_ provides the operator [blue]_$$_ that returns the current context. This can be used to inspect the content of the context, for example to check the value of a variable or to see which functions are currently linked to the context. This operator is primarily intended for debugging purposes.
|
_Expr_ provides the operator [blue]_$$_ that returns the current context. This can be used to inspect the content of the context, for example to check the value of a variable or to see which functions are currently linked to the context. This operator is primarily intended for debugging purposes.
|
||||||
|
|
||||||
An interactive tool could like `dev-expr` (see <<_dev-expr_test_tool>>) can be used to inspect contexts interactively.
|
An interactive tool like `ecli` (see <<_ecli_test_tool>>) can be used to inspect contexts interactively.
|
||||||
|
|
||||||
|
|
||||||
.Example: inspecting contexts
|
.Example: inspecting contexts
|
||||||
@@ -103,7 +105,7 @@ An interactive tool could like `dev-expr` (see <<_dev-expr_test_tool>>) can be u
|
|||||||
In order to inspect the global context issue the [blue]`$$ global` operation.
|
In order to inspect the global context issue the [blue]`$$ global` operation.
|
||||||
////
|
////
|
||||||
.Example: list all functions whose name starts with "str"
|
.Example: list all functions whose name starts with "str"
|
||||||
`>>>` [blue]`builtin "string` [gray]__// most function in the builtin module *string* have names starting with "str".__ +
|
`>>>` [blue]`builtin "string` [gray]__// most functions in the builtin module *string* have names starting with "str".__ +
|
||||||
[green]`1`
|
[green]`1`
|
||||||
|
|
||||||
:dollar: $
|
:dollar: $
|
||||||
@@ -123,24 +125,25 @@ In order to inspect the global context issue the [blue]`$$ global` operation.
|
|||||||
[green]`]`
|
[green]`]`
|
||||||
////
|
////
|
||||||
|
|
||||||
=== `dev-expr` test tool
|
[[sec_ecli]]
|
||||||
Before we begin to describe the syntax of _Expr_, it is worth introducing _dev-expr_ because it will be used to show many examples of expressions.
|
=== `ecli` Expression Calculator Interactive Tool
|
||||||
|
Before we begin to describe the syntax of _Expr_, it is worth introducing _ecli_, former _dev-expr_, because it will be used to show many examples of expressions.
|
||||||
|
|
||||||
`dev-expr` is a simple program that can be used to evaluate expressions interactively. As its name suggests, it was created for testing purpose. In fact, in additon to the automatic verification test suite based on the Go test framework, `dev-expr` provided an important aid for quickly testing of new features during their development.
|
`ecli` is a simple program that can be used to evaluate expressions interactively. As its name suggests, it was created for testing purpose. In fact, in addition to the automatic verification test suite based on the Go test framework, `ecli` provided an important aid for quickly testing of new features during their development.
|
||||||
|
|
||||||
`dev-expr` can work as a _REPL_, _**R**ead-**E**xecute-**P**rint-**L**oop_, or it can process expression acquired from files or standard input.
|
`ecli` can work as a _REPL_, _**R**ead-**E**xecute-**P**rint-**L**oop_, or it can process expression acquired from files or standard input.
|
||||||
|
|
||||||
The program can be downloaded from https://git.portale-stac.it/go-pkg/-/packages/generic/dev-expr/[dev-expr].
|
The program can be downloaded from https://git.portale-stac.it/go-pkg/-/packages/generic/ecli/[ecli].
|
||||||
|
|
||||||
Here are some examples of execution.
|
Here are some examples of execution.
|
||||||
|
|
||||||
.Run `dev-expr` in REPL mode and ask for help
|
.Run `ecli` in REPL mode and ask for help
|
||||||
[source,shell]
|
[source,shell]
|
||||||
----
|
----
|
||||||
# Type 'exit' or Ctrl+D to quit the program.
|
# Type 'exit' or Ctrl+D to quit the program.
|
||||||
|
|
||||||
[user]$ ./dev-expr
|
[user]$ ./ecli
|
||||||
dev-expr -- Expressions calculator v1.12.0(build 1),2024/09/14 (celestino.amoroso@portale-stac.it)
|
ecli -- Expressions calculator v1.12.0(build 1),2024/09/14 (celestino.amoroso@portale-stac.it)
|
||||||
Based on the Expr package v0.26.0
|
Based on the Expr package v0.26.0
|
||||||
Type help to get the list of available commands
|
Type help to get the list of available commands
|
||||||
See also https://git.portale-stac.it/go-pkg/expr/src/branch/main/README.adoc
|
See also https://git.portale-stac.it/go-pkg/expr/src/branch/main/README.adoc
|
||||||
@@ -176,8 +179,8 @@ dev-expr -- Expressions calculator v1.12.0(build 1),2024/09/14 (celestino.amoros
|
|||||||
.REPL examples
|
.REPL examples
|
||||||
[source,shell]
|
[source,shell]
|
||||||
----
|
----
|
||||||
[user]$ ./dev-expr
|
[user]$ ./ecli
|
||||||
dev-expr -- Expressions calculator v1.10.0(build 14),2024/06/17 (celestino.amoroso@portale-stac.it)
|
ecli -- Expressions calculator v1.10.0(build 14),2024/06/17 (celestino.amoroso@portale-stac.it)
|
||||||
Based on the Expr package v0.19.0
|
Based on the Expr package v0.19.0
|
||||||
Type help to get the list of available commands
|
Type help to get the list of available commands
|
||||||
See also https://git.portale-stac.it/go-pkg/expr/src/branch/main/README.adoc
|
See also https://git.portale-stac.it/go-pkg/expr/src/branch/main/README.adoc
|
||||||
@@ -254,7 +257,7 @@ Value range: *-9223372036854775808* to *9223372036854775807*
|
|||||||
^(1)^ The sum operator [blue]`+` also supports adding an integer number to a string. In this case, the number is converted to a string and prependend or appended to the string, e.g. `"x" + 48` results in `"x48"`.
|
^(1)^ The sum operator [blue]`+` also supports adding an integer number to a string. In this case, the number is converted to a string and prependend or appended to the string, e.g. `"x" + 48` results in `"x48"`.
|
||||||
|
|
||||||
[[note_string_repl]]
|
[[note_string_repl]]
|
||||||
^(2)^ The product operator also supports multiplying a string by an integer. In this case, the number represents homw may times the string has to be repeated in the result, e.g. `"foo" * 3` returnsn `"foofoofoo"`.
|
^(2)^ The product operator also supports multiplying a string by an integer. In this case, the number represents how many times the string has to be repeated in the result, e.g. `"foo" * 3` returns `"foofoofoo"`.
|
||||||
|
|
||||||
[[note_float_division]]
|
[[note_float_division]]
|
||||||
^(3)^ See also the _float division_ [blue]`./` below.
|
^(3)^ See also the _float division_ [blue]`./` below.
|
||||||
@@ -393,7 +396,7 @@ Some arithmetic operators also apply to strings.
|
|||||||
| [blue]`*` | _repeat_ | Make _n_ copy of a string | [blue]`"one" * 2` -> _"oneone"_
|
| [blue]`*` | _repeat_ | Make _n_ copy of a string | [blue]`"one" * 2` -> _"oneone"_
|
||||||
|===
|
|===
|
||||||
|
|
||||||
The charanters in a string can be accessed using the square `[]` operator.
|
The characters in a string can be accessed using the square `[]` operator.
|
||||||
|
|
||||||
.Item access syntax
|
.Item access syntax
|
||||||
====
|
====
|
||||||
@@ -416,7 +419,7 @@ The charanters in a string can be accessed using the square `[]` operator.
|
|||||||
[green]`"d"`
|
[green]`"d"`
|
||||||
|
|
||||||
`>>>` [blue]`#s` [gray]_// number of chars_ +
|
`>>>` [blue]`#s` [gray]_// number of chars_ +
|
||||||
[gren]`4`
|
[green]`4`
|
||||||
|
|
||||||
`>>>` [blue]`#"abc"` [gray]_// number of chars_ +
|
`>>>` [blue]`#"abc"` [gray]_// number of chars_ +
|
||||||
[green]`3`
|
[green]`3`
|
||||||
@@ -473,14 +476,14 @@ Currently, boolean operations are evaluated using _short cut evaluation_. This m
|
|||||||
----
|
----
|
||||||
2 > (a=1) or (a=8) > 0; a // <1>
|
2 > (a=1) or (a=8) > 0; a // <1>
|
||||||
----
|
----
|
||||||
<1> This multi-expression returns _1_ because in the first expression the left value of [blue]`or` is _true_ and, as a conseguence, its right value is not computed. Therefore the _a_ variable only receives the integer _1_.
|
<1> This multi-expression returns _1_ because in the first expression the left value of [blue]`or` is _true_ and, as a consequence, its right value is not computed. Therefore the _a_ variable only receives the integer _1_.
|
||||||
|
|
||||||
|
|
||||||
TIP: `dev-expr` provides the _ctrl()_ function that allows to change this behaviour.
|
TIP: `ecli` provides the _ctrl()_ function that allows to change this behaviour.
|
||||||
====
|
====
|
||||||
|
|
||||||
=== Lists
|
=== Lists
|
||||||
_Expr_ supports list of mixed-type values, also specified by normal expressions. Internally, _Expr_'s lists are Go arrays.
|
_Expr_ supports list of mixed-type values, also specified by normal expressions. Internally, _Expr_'s lists are Go slices.
|
||||||
|
|
||||||
.List literal syntax
|
.List literal syntax
|
||||||
====
|
====
|
||||||
@@ -585,7 +588,21 @@ Array's items can be accessed using the index `[]` operator.
|
|||||||
`>>>` [blue]`[1,2,3,2,4] - [2,4]` +
|
`>>>` [blue]`[1,2,3,2,4] - [2,4]` +
|
||||||
[green]`[1, 3]`
|
[green]`[1, 3]`
|
||||||
|
|
||||||
|
=== Linked Lists
|
||||||
|
Linked lists are a special kind of lists that are used to represent sequences of items that can be easily modified. They are represented as lists of two items: the first item is the value of the current node, and the second item is the next node in the list. The last node in the list has a next node that is _nil_.
|
||||||
|
|
||||||
|
Internally,Expr's linked lists hold two pointers: one to the head of the list and one to the tail of the list. This allows for efficient insertion and deletion of items at both ends of the list. Also, linked lists keep track of their size, so the number of items in a linked list can be obtained in constant time.
|
||||||
|
|
||||||
|
.Linked List literal syntax
|
||||||
|
====
|
||||||
|
*_linked-list_* = "**[<**" [_item-expr_ {"**,**" _item-expr_}] "**>]**" +
|
||||||
|
_item-expr_ = _any-value_
|
||||||
|
====
|
||||||
|
|
||||||
|
`>>>` [blue]`ls=[<1,2,3,4>]` +
|
||||||
|
[green]`[<1, 2, 3, 4>]`
|
||||||
|
|
||||||
|
#todo: to be completed#
|
||||||
|
|
||||||
=== Dictionaries
|
=== Dictionaries
|
||||||
The _dictionary_, or _dict_, data-type represents sets 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_.
|
||||||
@@ -707,7 +724,7 @@ The value of each sub-expression is stored in the automatic variable _last_.
|
|||||||
[green]`2`
|
[green]`2`
|
||||||
|
|
||||||
`>>>` [blue]`x=2*3 but x-1` +
|
`>>>` [blue]`x=2*3 but x-1` +
|
||||||
[green]`5`.
|
[green]`5`
|
||||||
|
|
||||||
[blue]`but` behavior is very similar to [blue]`;`. The only difference is that [blue]`;` is not a true operator and can't be used inside parenthesis [blue]`(` and [blue]`)`.
|
[blue]`but` behavior is very similar to [blue]`;`. The only difference is that [blue]`;` is not a true operator and can't be used inside parenthesis [blue]`(` and [blue]`)`.
|
||||||
|
|
||||||
@@ -787,7 +804,7 @@ The triple special case of the selector operator is very useful, but it only wor
|
|||||||
====
|
====
|
||||||
|
|
||||||
=== Variable default value [blue]`??`, [blue]`?=`, and [blue]`?!`
|
=== Variable default value [blue]`??`, [blue]`?=`, and [blue]`?!`
|
||||||
The left operand of the first two operators, [blue]`??` and [blue]`?=`, must be a variable. The right operatand can be any expression. They return the value of the variable if this is defined; otherwise they return the value of the right expression.
|
The left operand of the first two operators, [blue]`??` and [blue]`?=`, must be a variable. The right operand 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.
|
IMPORTANT: If the left variable is defined, the right expression is not evaluated at all.
|
||||||
|
|
||||||
@@ -795,7 +812,7 @@ The [blue]`??` operator do not change the status of the left variable.
|
|||||||
|
|
||||||
The [blue]`?=` assigns the calculated value of the right expression to the variable on the left side.
|
The [blue]`?=` assigns the calculated value of the right expression to the variable on the left side.
|
||||||
|
|
||||||
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.
|
The third one, [blue]`?!`, is the alternate operator. If the variable on the left side is not defined, it returns [blue]_nil_. Otherwise it returns the result of the expression on the right side.
|
||||||
|
|
||||||
IMPORTANT: If the variable [blue]`?!` is NOT defined, the expression is not evaluated at all.
|
IMPORTANT: If the variable [blue]`?!` is NOT defined, the expression is not evaluated at all.
|
||||||
|
|
||||||
@@ -897,7 +914,7 @@ The table below shows all supported operators by decreasing priorities.
|
|||||||
|
|
||||||
//^1^ Experimental
|
//^1^ Experimental
|
||||||
|
|
||||||
.Special assignment perators
|
.Special assignment operators
|
||||||
[cols="^2,^2,^4,^6"]
|
[cols="^2,^2,^4,^6"]
|
||||||
|===
|
|===
|
||||||
| Priority | Operator | Operation |Equivalent operation
|
| Priority | Operator | Operation |Equivalent operation
|
||||||
@@ -980,7 +997,7 @@ _param-name_ = _identifier_
|
|||||||
|
|
||||||
|
|
||||||
=== _Golang_ function definition
|
=== _Golang_ function definition
|
||||||
Description of how to define Golang functions and how to bind them to _Expr_ are topics covered in another documents that I'll write, one day, maybe.
|
Description of how to define Golang functions and how to bind them to _Expr_ are topics covered in other documents.
|
||||||
|
|
||||||
=== Function calls
|
=== Function calls
|
||||||
To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters.
|
To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters.
|
||||||
@@ -1246,7 +1263,7 @@ Returns _true_ if the value type of _<expr>_ is string, false otherwise.
|
|||||||
|
|
||||||
===== bool()
|
===== bool()
|
||||||
Syntax: `bool(<expr>) -> bool` +
|
Syntax: `bool(<expr>) -> bool` +
|
||||||
Returns a _boolean_ value consisent with the value of the expression.
|
Returns a _boolean_ value consistent with the value of the expression.
|
||||||
|
|
||||||
.Examples
|
.Examples
|
||||||
`>>>` [blue]`bool(1)` +
|
`>>>` [blue]`bool(1)` +
|
||||||
@@ -1709,6 +1726,8 @@ Returns a string obtained by converting all characters of the specified string t
|
|||||||
`>>>` [blue]`strLower("Hello, world!")` +
|
`>>>` [blue]`strLower("Hello, world!")` +
|
||||||
[green]`"hello, world!"`
|
[green]`"hello, world!"`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
== Iterators
|
== Iterators
|
||||||
Iterators are objects that can be used to traverse collections, such as lists and dictionaries. They are created by providing a _data-source_ object, the collection, in a `$(<data-source>)` expression. Once an iterator is created, it can be used to access the elements of the collection one by one.
|
Iterators are objects that can be used to traverse collections, such as lists and dictionaries. They are created by providing a _data-source_ object, the collection, in a `$(<data-source>)` expression. Once an iterator is created, it can be used to access the elements of the collection one by one.
|
||||||
|
|
||||||
@@ -1723,16 +1742,16 @@ _data-source_ = _explicit_ | _list-spec_ | _dict-spec_ | _custom-data-source_
|
|||||||
|
|
||||||
_explicit_ = _any-expr_ { "**,**" _any-expr_ }
|
_explicit_ = _any-expr_ { "**,**" _any-expr_ }
|
||||||
|
|
||||||
_list-spec_ = _list_ _range-options_ +
|
_list-spec_ = _list_ ["**,**" _range-options_] +
|
||||||
_list_ = "**[**" _any-expr_ { "**,**" _any-expr_ } "**]**" +
|
_list_ = "**[**" _any-expr_ { "**,**" _any-expr_ } "**]**" +
|
||||||
_range-options_ = [ "**,**" _start-index_ [ "**,**" _end-index_ [ "**,**" _step_ ]]] +
|
_range-options_ = _start-index_ [ "**,**" _end-index_ [ "**,**" _step_ ]] +
|
||||||
_start-index_, _end-index_, _step_ = _integer-expr_
|
_start-index_, _end-index_, _step_ = _integer-expr_
|
||||||
|
|
||||||
_dict-spec_ = _dict_ _dict-options_ +
|
_dict-spec_ = _dict_ ["**,**" _dict-options_] +
|
||||||
_dict_ = "**{**" _key-value-pair_ { "**,**" _key-value-pair_ } "**}**" +
|
_dict_ = "**{**" _key-value-pair_ { "**,**" _key-value-pair_ } "**}**" +
|
||||||
_key-value-pair_ = _scalar-value_ "**:**" _any-expr_ +
|
_key-value-pair_ = _scalar-value_ "**:**" _any-expr_ +
|
||||||
_scalar-value_ = _string_ | _number_ | _boolean_ +
|
_scalar-value_ = _string_ | _number_ | _boolean_ +
|
||||||
_dict-options_ = [ "**,**" _sort-order_ [ "**,**" _iter-mode_ ] ] +
|
_dict-options_ = _sort-order_ [ "**,**" _iter-mode_ ] +
|
||||||
_sort-order_ = _asc-order_ | _desc-order_ | _no-sort_ | _default-order_ +
|
_sort-order_ = _asc-order_ | _desc-order_ | _no-sort_ | _default-order_ +
|
||||||
_asc-order_ = "**asc**" | "**a**" +
|
_asc-order_ = "**asc**" | "**a**" +
|
||||||
_desc-order_ = "**desc**" | "**d**" +
|
_desc-order_ = "**desc**" | "**d**" +
|
||||||
@@ -1810,7 +1829,7 @@ Negative steps are also allowed. They are interpreted as reverse iteration. For
|
|||||||
The above example shows the use of the [blue]`{plusplus}` operator to get the next element of an iterator. The [blue]`{plusplus}` operator is a postfix operator that can be used with iterators. It returns the next element of the collection and updates the state of the iterator. When there are no more elements to iterate over, it returns the error [red]_Eval Error: EOF_.
|
The above example shows the use of the [blue]`{plusplus}` operator to get the next element of an iterator. The [blue]`{plusplus}` operator is a postfix operator that can be used with iterators. It returns the next element of the collection and updates the state of the iterator. When there are no more elements to iterate over, it returns the error [red]_Eval Error: EOF_.
|
||||||
|
|
||||||
|
|
||||||
After the first use of the [blue]`{plusplus}` operator, the prefixed operato [blue]`{star}` operator can be used to get the current element of the collection without updating the state of the iterator. When there are no more elements to iterate over, it returns the error [red]_Eval Error: EOF_. Same error is returned if the [blue]`{star}` operator is used before the first use of the [blue]`{plusplus}` operator.
|
After the first use of the [blue]`{plusplus}` operator, the prefixed operator [blue]`{star}` operator can be used to get the current element of the collection without updating the state of the iterator. When there are no more elements to iterate over, it returns the error [red]_Eval Error: EOF_. Same error is returned if the [blue]`{star}` operator is used before the first use of the [blue]`{plusplus}` operator.
|
||||||
|
|
||||||
.Example: using the [blue]`{star}` operator
|
.Example: using the [blue]`{star}` operator
|
||||||
`>>>` [blue]`it = $(["one", "two", "three"])` +
|
`>>>` [blue]`it = $(["one", "two", "three"])` +
|
||||||
@@ -1822,12 +1841,17 @@ After the first use of the [blue]`{plusplus}` operator, the prefixed operato [bl
|
|||||||
`>>>` [blue]`{star}it` +
|
`>>>` [blue]`{star}it` +
|
||||||
[green]`"one"`
|
[green]`"one"`
|
||||||
|
|
||||||
|
==== [blue]*`$$()`* -- Expansion special function for iterators
|
||||||
|
The [blue]`$$()` operator is a special function already seen applied to contexts. It can also be applied to iterators. When applied to an iterator, it returns a _linked list_ of all the remaining elements of the collection. The state of the iterator is updated to the end of the collection. If there are no more elements to iterate over, it returns an empty list.
|
||||||
|
|
||||||
|
#todo: examples#
|
||||||
|
|
||||||
==== Named operators
|
==== Named operators
|
||||||
Named operators are operators that are identified by a name instead of a symbol. They are implicitly defined and can be called using a special syntax. For example, the [blue]`{plusplus}` has the equivalent named operator [blue]`.next`.
|
Named operators are operators that are identified by a name instead of a symbol. They are implicitly defined and can be called using a special syntax. For example, the [blue]`{plusplus}` has the equivalent named operator [blue]`.next`.
|
||||||
|
|
||||||
.Available named operators
|
.Available named operators
|
||||||
* *_.next_*: same as [blue]`{plusplus}`.
|
* *_.next_*: same as [blue]`{plusplus}`.
|
||||||
* *_.current_*: same as [blue]`{star}`.
|
* *_.current_*: same as [blue]`{star}.`
|
||||||
* *_.reset_*: resets the state of the iterator to the initial state.
|
* *_.reset_*: resets the state of the iterator to the initial state.
|
||||||
* *_.count_*: returns the number of elements in the iterator already visited.
|
* *_.count_*: returns the number of elements in the iterator already visited.
|
||||||
* *_.index_*: returns the index of the current element in the iterator. Before the first use of the [blue]`{plusplus}` operator, it returns the error [red]_-1_.
|
* *_.index_*: returns the index of the current element in the iterator. Before the first use of the [blue]`{plusplus}` operator, it returns the error [red]_-1_.
|
||||||
@@ -1854,13 +1878,21 @@ TIP: Iterators built on custom data-sources can provide additional named operato
|
|||||||
There are also some infixed operators that can be used with iterators. They are defined as follows.
|
There are also some infixed operators that can be used with iterators. They are defined as follows.
|
||||||
|
|
||||||
* <<_cat,cat operator>>
|
* <<_cat,cat operator>>
|
||||||
* <<_diget,digest operator>>
|
* <<_digest,digest operator>>
|
||||||
* <<_filter,filter operator>>
|
* <<_filter,filter operator>>
|
||||||
* <<_groupby,groupby operator>>
|
* <<_groupby,groupby operator>>
|
||||||
* <<_map,map operator>>
|
* <<_map,map operator>>
|
||||||
//* <<_reduce,reduce operator>>: applies a binary expression cumulatively to the elements of the iterator, from left to right, to reduce the iterator to a single value.
|
//* <<_reduce,reduce operator>>: applies a binary expression cumulatively to the elements of the iterator, from left to right, to reduce the iterator to a single value.
|
||||||
//* <<_zip,zip operator>>: takes two or more iterators and returns a list of tuples, where the i-th tuple contains the i-th element from each of the input iterators.
|
//* <<_zip,zip operator>>: takes two or more iterators and returns a list of tuples, where the i-th tuple contains the i-th element from each of the input iterators.
|
||||||
|
|
||||||
|
|
||||||
|
==== Automatic variables in operators
|
||||||
|
At each iteration, the following automatic variables are available for use in the expression of the [blue]`digest`, [blue]`filter`, [blue]`groupby`, and [blue]`map` operators.
|
||||||
|
|
||||||
|
* `$_`: the current element of the iterator.
|
||||||
|
* `$__`: the index of the current element in the iterator, starting from 0.
|
||||||
|
* `$#`: the number of elements already visited in the iterator, starting from 0.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
==== [blue]`cat` operator
|
==== [blue]`cat` operator
|
||||||
@@ -1870,33 +1902,63 @@ Syntax: +
|
|||||||
[blue]`cat` operator takes two iterators or iterables and returns a new iterator that produces the elements of the first iterator followed by the elements of the second iterator.
|
[blue]`cat` operator takes two iterators or iterables and returns a new iterator that produces the elements of the first iterator followed by the elements of the second iterator.
|
||||||
|
|
||||||
.Examples
|
.Examples
|
||||||
|
#todo: examples#
|
||||||
|
|
||||||
==== [blue]`filter` operator
|
==== [blue]`filter` operator
|
||||||
Syntax: +
|
Syntax: +
|
||||||
`{4sp}<iterable> filter <expr> -> <iterator>{4sp}`
|
`{4sp}<iterable> filter <expr> -> <iterator>{4sp}`
|
||||||
|
|
||||||
[blue]`filter` applies a boolean expression to each element of the iterator and returns a list of the elements for which the expression evaluates to true.
|
[blue]`filter` applies a boolean expression to each element of the iterator and returns a new iterator that only produces the elements of the first iterator for which the expression evaluates to true.
|
||||||
|
|
||||||
|
.Examples
|
||||||
|
#todo: examples#
|
||||||
|
|
||||||
|
|
||||||
==== [blue]`groupby` operator
|
==== [blue]`groupby` operator
|
||||||
Syntax: +
|
Syntax: +
|
||||||
`{4sp}<dict> groupby <key> -> <dict>{4sp}`
|
`{4sp}<list-of-dicts> groupby <key> -> <dict>{4sp}`
|
||||||
|
|
||||||
[blue]`groupby` operator groups the elements of the iterator based on the value of a specified expression and returns a dictionary where the keys are the group values and the values are lists of the elements in each group.
|
The left side of [blue]`groupby` operator is a list ofdictionaries or an iterator over a list of dictionaries. It takes a key and returns a dictionary where the keys are the unique values of the specified key in the dictionaries and the values are lists of dictionaries that have that key value. In other words, it groups the dictionaries by the specified key value.
|
||||||
|
|
||||||
|
NOTE: Currently, keys of group are always strings. In the future, it will be possible to specify a key function to compute the keys of the groups.
|
||||||
|
|
||||||
|
.Examples
|
||||||
|
`>>>` [blue]`[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}, {"name": "Charlie", "age": 30}] groupby "age"` +
|
||||||
|
[source,yaml]
|
||||||
|
----
|
||||||
|
{
|
||||||
|
"25": [
|
||||||
|
{
|
||||||
|
"name": "Bob",
|
||||||
|
"age": 25
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"30": [
|
||||||
|
{
|
||||||
|
"name": "Alice",
|
||||||
|
"age": 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Charlie",
|
||||||
|
"age": 30
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
==== [blue]`map` operator
|
==== [blue]`map` operator
|
||||||
Syntax: +
|
Syntax: +
|
||||||
`{4sp}<iterable> map <expr> -> <list>{4sp}`
|
`{4sp}<iterable> map <expr> -> <iterator>{4sp}`
|
||||||
|
|
||||||
|
[blue]`map` operator iterates over the elements of the iterator and evaluates the expressions provided on the right side for each element. Its result is a new iterator over the computed values of the that expression. The current element of the iterator is available in the expression as the variable `$_`.
|
||||||
[blue]`map` operator iterates over the elements of the iterator and evaluates the expressions provided on the right side for each element. Its result is a list of the computed values of the that expression. The current element of the iterator is available in the expression as the variable `$_`.
|
|
||||||
|
|
||||||
.Example: using the [blue]`map` operator
|
.Example: using the [blue]`map` operator
|
||||||
`>>>` [blue]`it = $(["one", "two", "three"])` +
|
`>>>` [blue]`it = $(["one", "two", "three"])` +
|
||||||
[green]`$(#3)` +
|
[green]`$(#3)` +
|
||||||
`>>>` [blue]`it map $_ + "!"` +
|
`>>>` [blue]`excl_it = it map $_ + "!"` +
|
||||||
[green]`["one!", "two!", "three!"]`
|
[green]`$($([#3]))` +
|
||||||
|
`>>>` [blue]`$$(excl_it)` +
|
||||||
|
[green]`[<"one!", "two!", "three!">]`
|
||||||
|
|
||||||
=== Iterator over custom data-sources
|
=== Iterator over custom data-sources
|
||||||
It is possible to create iterators over custom data-sources by defining a dictionary that has the key `next` whose value is a function that returns the next element of the collection and updates the state of the iterator. The syntax for creating an iterator over a custom data-source is as follows.
|
It is possible to create iterators over custom data-sources by defining a dictionary that has the key `next` whose value is a function that returns the next element of the collection and updates the state of the iterator. The syntax for creating an iterator over a custom data-source is as follows.
|
||||||
|
|||||||
@@ -11,6 +11,15 @@ import (
|
|||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewFormalIterator(value any) (it kern.Iterator) {
|
||||||
|
if value == nil {
|
||||||
|
it = NewArrayIterator([]any{})
|
||||||
|
} else {
|
||||||
|
it = NewArrayIterator([]any{value})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func NewIterator(ctx kern.ExprContext, value any, ops []*scan.Term) (it kern.Iterator, err error) {
|
func NewIterator(ctx kern.ExprContext, value any, ops []*scan.Term) (it kern.Iterator, err error) {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return NewArrayIterator([]any{}), nil
|
return NewArrayIterator([]any{}), nil
|
||||||
|
|||||||
+2
-2
@@ -45,7 +45,7 @@ func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
ctx.SetVar("_", item)
|
ctx.SetVar("_", item)
|
||||||
ctx.SetVar("__", it.Index())
|
ctx.SetVar("__", it.Index())
|
||||||
ctx.SetVar("_#", it.Count())
|
ctx.SetVar("#", it.Count())
|
||||||
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
|
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
|
||||||
if rightValue == nil {
|
if rightValue == nil {
|
||||||
break
|
break
|
||||||
@@ -53,7 +53,7 @@ func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
lastValue = rightValue
|
lastValue = rightValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.DeleteVar("_#")
|
ctx.DeleteVar("#")
|
||||||
ctx.DeleteVar("__")
|
ctx.DeleteVar("__")
|
||||||
ctx.DeleteVar("_")
|
ctx.DeleteVar("_")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+2
-2
@@ -110,9 +110,9 @@ func (it *filterIterator) Next() (item any, err error) {
|
|||||||
for attempt, err = it.itSrc.Next(); err == nil; attempt, err = it.itSrc.Next() {
|
for attempt, err = it.itSrc.Next(); err == nil; attempt, err = it.itSrc.Next() {
|
||||||
ctx.SetVar("_", attempt)
|
ctx.SetVar("_", attempt)
|
||||||
ctx.SetVar("__", it.Index())
|
ctx.SetVar("__", it.Index())
|
||||||
ctx.SetVar("_#", it.Count())
|
ctx.SetVar("#", it.Count())
|
||||||
result, err = it.expr.Compute(ctx)
|
result, err = it.expr.Compute(ctx)
|
||||||
ctx.DeleteVar("_#")
|
ctx.DeleteVar("#")
|
||||||
ctx.DeleteVar("__")
|
ctx.DeleteVar("__")
|
||||||
ctx.DeleteVar("_")
|
ctx.DeleteVar("_")
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -62,7 +62,7 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
ctx.SetVar("_", item)
|
ctx.SetVar("_", item)
|
||||||
ctx.SetVar("__", it.Index())
|
ctx.SetVar("__", it.Index())
|
||||||
ctx.SetVar("_#", it.Count())
|
ctx.SetVar("#", it.Count())
|
||||||
|
|
||||||
var sItemKey string
|
var sItemKey string
|
||||||
|
|
||||||
@@ -71,7 +71,11 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
sItemKey = strconv.Itoa(int(it.Index()))
|
sItemKey = strconv.Itoa(int(it.Index()))
|
||||||
} else if d.HasKey(sKey) {
|
} else if d.HasKey(sKey) {
|
||||||
if keyValue, exists := d.GetItem(sKey); exists {
|
if keyValue, exists := d.GetItem(sKey); exists {
|
||||||
sItemKey = fmt.Sprintf("%v", keyValue)
|
if s, ok := keyValue.(string); ok {
|
||||||
|
sItemKey = s
|
||||||
|
} else {
|
||||||
|
sItemKey = fmt.Sprintf("%v", keyValue)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sItemKey = "_"
|
sItemKey = "_"
|
||||||
}
|
}
|
||||||
@@ -92,7 +96,7 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
ls.AppendItem(item)
|
ls.AppendItem(item)
|
||||||
values.SetItem(sItemKey, ls)
|
values.SetItem(sItemKey, ls)
|
||||||
|
|
||||||
ctx.DeleteVar("_#")
|
ctx.DeleteVar("#")
|
||||||
ctx.DeleteVar("__")
|
ctx.DeleteVar("__")
|
||||||
ctx.DeleteVar("_")
|
ctx.DeleteVar("_")
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-20
@@ -31,13 +31,11 @@ func newAppendTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prependToList(ctx kern.ExprContext, opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
|
func prependToList(opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
|
||||||
if list, ok := rightValue.(*kern.ListType); ok {
|
if list, ok := rightValue.(*kern.ListType); ok {
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
if it, ok = leftValue.(kern.Iterator); !ok {
|
if it, ok = leftValue.(kern.Iterator); !ok {
|
||||||
if it, err = NewIterator(ctx, leftValue, nil); err != nil {
|
it = NewFormalIterator(leftValue)
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ls := kern.NewLinkedList()
|
ls := kern.NewLinkedList()
|
||||||
@@ -54,12 +52,13 @@ func prependToList(ctx kern.ExprContext, opTerm *scan.Term, leftValue, rightValu
|
|||||||
newList = append(newList, item)
|
newList = append(newList, item)
|
||||||
}
|
}
|
||||||
result = &newList
|
result = &newList
|
||||||
|
} else if list, ok := rightValue.(*kern.LinkedList); ok {
|
||||||
|
var it kern.Iterator
|
||||||
|
if it, ok = leftValue.(kern.Iterator); !ok {
|
||||||
|
it = NewFormalIterator(leftValue)
|
||||||
|
}
|
||||||
|
|
||||||
// ***** EVENTUALMENTE ABILITARE LA MODIFICA DELLA VARIABILE
|
result = list.SeqPushBack(it)
|
||||||
// ***** CON UN OPERATORE SPECIFICO
|
|
||||||
// if opTerm.Children[1].Symbol() == scan.SymVariable {
|
|
||||||
// ctx.UnsafeSetVar(opTerm.Children[1].Source(), result)
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@@ -73,17 +72,15 @@ func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err = prependToList(ctx, opTerm, leftValue, rightValue)
|
v, err = prependToList(opTerm, leftValue, rightValue)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendToList(ctx kern.ExprContext, opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
|
func appendToList(opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
|
||||||
if list, ok := leftValue.(*kern.ListType); ok {
|
if list, ok := leftValue.(*kern.ListType); ok {
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
if it, ok = rightValue.(kern.Iterator); !ok {
|
if it, ok = rightValue.(kern.Iterator); !ok {
|
||||||
if it, err = NewIterator(ctx, rightValue, nil); err != nil {
|
it = NewFormalIterator(rightValue)
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ls := kern.NewLinkedList()
|
ls := kern.NewLinkedList()
|
||||||
@@ -100,12 +97,13 @@ func appendToList(ctx kern.ExprContext, opTerm *scan.Term, leftValue, rightValue
|
|||||||
newList = append(newList, node.Data())
|
newList = append(newList, node.Data())
|
||||||
}
|
}
|
||||||
result = &newList
|
result = &newList
|
||||||
|
} else if list, ok := leftValue.(*kern.LinkedList); ok {
|
||||||
|
var it kern.Iterator
|
||||||
|
if it, ok = rightValue.(kern.Iterator); !ok {
|
||||||
|
it = NewFormalIterator(rightValue)
|
||||||
|
}
|
||||||
|
|
||||||
// ***** EVENTUALMENTE ABILITARE LA MODIFICA DELLA VARIABILE
|
result = list.SeqPushBack(it)
|
||||||
// ***** CON UN OPERATORE SPECIFICO
|
|
||||||
// if opTerm.Children[0].Symbol() == scan.SymVariable {
|
|
||||||
// ctx.UnsafeSetVar(opTerm.Children[0].Source(), result)
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@@ -119,7 +117,7 @@ func evalAppend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err = appendToList(ctx, opTerm, leftValue, rightValue)
|
v, err = appendToList(opTerm, leftValue, rightValue)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -40,7 +40,7 @@ func evalRightShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if v, err = bitRightShift(opTerm, leftValue, rightValue); err != nil {
|
if v, err = bitRightShift(opTerm, leftValue, rightValue); err != nil {
|
||||||
v, err = prependToList(ctx, opTerm, leftValue, rightValue)
|
v, err = prependToList(opTerm, leftValue, rightValue)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ func evalLeftShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if v, err = bitLeftShift(opTerm, leftValue, rightValue); err != nil {
|
if v, err = bitLeftShift(opTerm, leftValue, rightValue); err != nil {
|
||||||
v, err = appendToList(ctx, opTerm, leftValue, rightValue)
|
v, err = appendToList(opTerm, leftValue, rightValue)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-9
@@ -53,15 +53,25 @@ func TestOperatorInsert(t *testing.T) {
|
|||||||
section := "Operator-Insert"
|
section := "Operator-Insert"
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`["a", "b"] << nil`, kern.NewListA("a", "b"), nil},
|
/* 1 */ {`["a", "b"] << nil`, kern.NewListA("a", "b"), nil},
|
||||||
/* 2 */ {`["a", "b"] << []`, kern.NewListA("a", "b"), nil},
|
/* 2 */ {`["a", "b"] << []`, kern.NewListA("a", "b", kern.NewListA()), nil},
|
||||||
/* 3 */ {`["a", "b"] << 3`, kern.NewListA("a", "b", int64(3)), nil},
|
/* 3 */ {`["a", "b"] << $([])`, kern.NewListA("a", "b"), nil},
|
||||||
/* 4 */ {`3 << ["a", "b"]`, nil, `[1:5] left operand '3' [integer] and right operand '["a", "b"]' [list] are not compatible with operator "<<"`},
|
/* 4 */ {`["a", "b"] << 3`, kern.NewListA("a", "b", int64(3)), nil},
|
||||||
/* 5 */ {`nil >> ["a", "b"]`, kern.NewListA("a", "b"), nil},
|
/* 5 */ {`3 << ["a", "b"]`, nil, `[1:5] left operand '3' [integer] and right operand '["a", "b"]' [list] are not compatible with operator "<<"`},
|
||||||
/* 6 */ {`[] >> ["a", "b"]`, kern.NewListA("a", "b"), nil},
|
/* 6 */ {`nil >> ["a", "b"]`, kern.NewListA("a", "b"), nil},
|
||||||
/* 7 */ {`["a", "b"] << $([1,2,3])`, kern.NewListA("a", "b", int64(1), int64(2), int64(3)), nil},
|
/* 7 */ {`[] >> ["a", "b"]`, kern.NewListA(kern.NewListA(), "a", "b"), nil},
|
||||||
/* 8 */ {`L=["a", "b"]; L << $([1,2,3])`, kern.NewListA("a", "b", int64(1), int64(2), int64(3)), nil},
|
/* 8 */ {`$([]) >> ["a", "b"]`, kern.NewListA("a", "b"), nil},
|
||||||
/* 9 */ {`L=["a", "b"]; L << $([1,2,3]); L`, kern.NewListA("a", "b"), nil},
|
/* 9 */ {`["a", "b"] << $([1,2,3])`, kern.NewListA("a", "b", int64(1), int64(2), int64(3)), nil},
|
||||||
/* 10 */ {`L << $([1,2,3])`, nil, `undefined variable or function "L"`},
|
/* 10 */ {`L=["a", "b"]; L << $([1,2,3])`, kern.NewListA("a", "b", int64(1), int64(2), int64(3)), nil},
|
||||||
|
/* 11 */ {`L=["a", "b"]; L << $([1,2,3]); L`, kern.NewListA("a", "b"), nil},
|
||||||
|
/* 12 */ {`L << $([1,2,3])`, nil, `undefined variable or function "L"`},
|
||||||
|
/* 13 */ {`[<>] << 1`, kern.NewLinkedListA(1), nil},
|
||||||
|
/* 14 */ {`[<>] << [1,2]`, kern.NewLinkedListA(kern.NewListA(int64(1), int64(2))), nil},
|
||||||
|
/* 15 */ {`[<>] << [<1,2>]`, kern.NewLinkedListA(kern.NewLinkedListA(1, 2)), nil},
|
||||||
|
/* 16 */ {`1 >> [<>]`, kern.NewLinkedListA(1), nil},
|
||||||
|
/* 17 */ {`[1,2] >> [<>]`, kern.NewLinkedListA(kern.NewListA(int64(1), int64(2))), nil},
|
||||||
|
/* 18 */ {`[<1,2>] >> [<>]`, kern.NewLinkedListA(kern.NewLinkedListA(1, 2)), nil},
|
||||||
|
/* 19 */ {`$([1,2]) >> [<>]`, kern.NewLinkedListA(1, 2), nil},
|
||||||
|
/* 20 */ {`$([<1,2>]) >> [<>]`, kern.NewLinkedListA(1, 2), nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 9)
|
// runTestSuiteSpec(t, section, inputs, 9)
|
||||||
|
|||||||
Reference in New Issue
Block a user