Compare commits

..

6 Commits

10 changed files with 556 additions and 194 deletions
+1
View File
@@ -27,6 +27,7 @@ func TestDictParser(t *testing.T) {
/* 4 */ {`{1:"one",2:"two",3:"three"}.2`, "three", nil},
/* 5 */ {`#{1:"one",2:"two",3:"three"}`, int64(3), nil},
/* 6 */ {`{1:"one"} + {2:"two"}`, map[any]any{1: "one", 2: "two"}, nil},
/* 7 */ {`2 in {1:"one", 2:"two"}`, true, nil},
}
succeeded := 0
+135 -82
View File
@@ -22,7 +22,7 @@ Expressions calculator
toc::[]
#TODO: Work in progress (last update on 2024/05/16, 7:08 a.m.)#
#TODO: Work in progress (last update on 2024/05/17, 15:47 p.m.)#
== Expr
_Expr_ is a GO package capable of analysing, interpreting and calculating expressions.
@@ -44,7 +44,7 @@ Here are some examples of execution.
.Run `dev-expr` in REPL mode and ask for help
[source,shell]
----
# Assume the expr source directory. Type 'exit' or Ctrl+D to quit the program.
# Type 'exit' or Ctrl+D to quit the program.
[user]$ ./dev-expr
expr -- Expressions calculator v1.7.1(build 2),2024/05/16 (celestino.amoroso@portale-stac.it)
@@ -122,7 +122,7 @@ _Expr_ supports three type of numbers:
. [blue]#Integers#
. [blue]#Floats#
. [blue]#Factions# internally are stored as _pairs of_ Golang _int64_ values.
. [blue]#Factions#
In mixed operations involving integers, fractions and floats, automatic type promotion to the largest type take place.
@@ -183,7 +183,7 @@ _dec-seq_ = _see-integer-literal-syntax_
`>>>` [blue]`4.5E-3` +
[green]`0.0045` +
`>>>` [blue]`4.5E10` +
[green]`4.5e+10` +
[green]`4.5e+10`
.Arithmetic operators
@@ -207,7 +207,7 @@ _sign_ = "**+**" | "**-**" +
_num-den-spec_ = _digit-seq_ "**|**" _digit-seq_ +
_float-spec_ = _dec-seq_ "**.**" [_dec-seq_] "**(**" _dec-seq_ "**)**" +
_dec-seq_ = _see-integer-literal-syntax_ +
_digit-seq_ = _see-integer-literal-syntax_ +
_digit-seq_ = _see-integer-literal-syntax_
====
.Examples
@@ -235,12 +235,13 @@ _digit-seq_ = _see-integer-literal-syntax_ +
Fractions can be used together with integers and floats in expressions.
.Examples
`>>>` [blue]`1|2 + 5` +
[green]`11|2` +
`>>>` [blue]`4 - 1|2` +
[green]`7|2` +
`>>>` [blue]`1.0 + 1|2` +
[green]`1.5` +
[green]`1.5`
@@ -288,9 +289,10 @@ _item_ = _string-expr_ "**.**" _integer-expr_
`>>>` [blue]`\#s` [gray]_number of chars_ +
[gren]`3` +
`>>>` [blue]`#"abc"` [gray]_number of chars_ +
[green]`3` +
[green]`3`
=== Boolean
=== Booleans
Boolean data type has two values only: [blue]_true_ and [blue]_false_. Relational and boolean expressions result in boolean values.
.Relational operators
@@ -341,35 +343,42 @@ Currently, boolean operations are evaluated using _short cut evaluation_. This m
====
=== Lists
_Expr_ supports list of mixed-type values, also specified by normal expressions.
_Expr_ supports list of mixed-type values, also specified by normal expressions. Internally, _Expr_'s lists are Go arrays.
.List examples
[source,go]
----
[1, 2, 3] // List of integers
["one", "two", "three"] // List of strings
["one", 2, false, 4.1] // List of mixed-types
["one"+1, 2.0*(9-2)] // List of expressions
[ [1,"one"], [2,"two"]] // List of lists
----
.List literal syntax
====
*_list_* = _empty-list_ | _non-empty-list_ +
_empty-list_ = "**[]**" +
_non-empty-list_ = "**[**" _any-value_ {"**,**" _any-value} "**]**" +
====
.Examples
`>>>` [blue]`[1,2,3]` [gray]_// List of integers_ +
[green]`[1, 2, 3]` +
`>>>` [blue]`["one", "two", "three"]` [gray]_// List of strings_ +
[green]`["one", "two", "three"]` +
`>>>` [blue]`["one", 2, false, 4.1]` [gray]_// List of mixed-types_ +
[green]`["one", 2, false, 4.1]` +
`>>>` [blue]`["one"+1, 2.0*(9-2)]` [gray]_// List of expressions_ +
[green]`["one1", 14]` +
`>>>` [blue]`[ [1,"one"], [2,"two"]]` [gray]_// List of lists_ +
[green]`[[1, "one"], [2, "two"]]`
.List operators
[cols="^2,^2,5,4"]
|===
| Symbol | Operation | Description | Examples
| [blue]`+` | _Join_ | Joins two lists | [blue]`[1,2] + [3]` _[ [1,2,3] ]_
| [blue]`-` | _Difference_ | Left list without elements in the right list | [blue]`[1,2,3] - [2]` _[ [1,3] ]_
| [blue]`+` | _Join_ | Joins two lists | [blue]`[1,2] + [3]` -> _[1,2,3]_
| [blue]`-` | _Difference_ | Left list without elements in the right list | [blue]`[1,2,3] - [2]` -> _[1,3]_
|===
The items of array can be accessed using the dot `.` operator.
.Item access syntax
[source,bnf]
----
<item> ::= <list-expr>"."<index-expr>
----
====
_item_ = _list-expr_ "**.**" _list-expr_
====
.Items of list
`>>>` [blue]`[1,2,3].1` +
@@ -389,44 +398,73 @@ The items of array can be accessed using the dot `.` operator.
== Dictionaries
The _dictionary_ data-type is set of pairs _key/value_. It is also known as _map_ or _associative array_. Dictionary literals are sequences of pairs separated by comma `,`; sequences are enclosed between brace brackets.
.Dictionary examples
[source,go]
----
{1:"one", 2:"two"}
{"one":1, "two": 2}
{"sum":1+2+3, "prod":1*2*3}
----
=== Dictionaries
WARNING: Support for dictionaries is still ongoing.
== Variables
A variable is an identifier with an assigned value. Variables are stored in the object that implements the Go _ExprContext_ interface, e.g. _SimpleVarStore_ or _SimpleFuncStore_.
The _dictionary_, or _dict_, data-type is set of pairs _key/value_. It is also known as _map_ or _associative array_. Dictionary literals are sequences of pairs separated by comma `,`; sequences are enclosed between brace brackets.
.Dict literal syntax
====
*_dict_* = _empty-dict_ | _non-empty-dict_ +
_empty-dict_ = "**{}**" +
_non-empty-dict_ = "**{**" _key-scalar_ "**:**" _any-value_ {"**,**" _key-scalar_ "**:**" _any-value} "**}**" +
====
.Examples
[source,go]
----
a=1
x = 5.2 * (9-3)
x = 1; y = 2*x
----
`>>>` [blue]`{1:"one", 2:"two"}` +
`>>>` [blue]`{"one":1, "two": 2}` +
`>>>` [blue]`{"sum":1+2+3, "prod":1*2*3}`
== Variables
_Expr_ supports variables like most programming languages. A variable is an identifier with an assigned value. Variables are stored in _contexts_.
.Variable literal syntax
====
*_variable_* = _identifier_ "*=*" _any-value_ +
_identifier_ = _alpha_ {(_alpha_)|_dec-digit_|"*_*"} +
__alpha__ = "*a*"|"*b*"|..."*z*"|"*A*"|"*B*"|..."*Z*"
====
NOTE: The assign operator [blue]`=` returns the value assigned to the variable.
.Examples
`>>>` [blue]`a=1` +
[green]`1` +
`>>>` [blue]`a_b=1+2` +
[green]`1+2` +
`>>>` [blue]`a_b` +
[green]`3` +
`>>>` [blue]`x = 5.2 * (9-3)` [gray]_// The assigned value has the approximation error typical of the float data-type_ +
[green]`31.200000000000003` +
`>>>` [blue]`x = 1; y = 2*x` +
[green]`2` +
`>>>` [blue]`_a=2` +
[red]`Parse Error: [1:2] unexpected token "_"` +
`>>>` [blue]`1=2` +
[red]`Parse Error: assign operator ("=") must be preceded by a variable`
== Other operations
=== [blue]`;` operator
The semicolon operator [blue]`;` is an infixed pseudo-operator. It evaluates the left expression first and then the right expression. The latter is the final result.
The semicolon operator [blue]`;` is an infixed pseudo-operator. It evaluates the left expression first and then the right expression. The value of the latter is the final result.
An expression that contains [blue]`;` is called a _multi-expression_ and each component expressione is called a _sub-expression_.
IMPORTANT: Technically [blue]`;` is not treated as a real operator. It acts as a separator in lists of expressions.
TIP: [blue]`;` can be used to set some variables before the final calculation.
.Example
[source,go]
----
a=1; b=2; c=3; a+b+c // returns 6
----
`>>>` [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_.
.Example
`>>>` [blue]`2+3; b=last+10; last` +
[green]`15`
=== [blue]`but` operator
[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` returns 2, [blue]`x=2*3 but x-1` returns 5.
@@ -438,50 +476,65 @@ The assignment operator [blue]`=` is used to define variables in the evaluation
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.
.Example
[source,go]
----
a=15+1 // returns 16
----
`>>>` [blue]`a=15+1`
[green]`16`
=== Selector operator [blue]`? : ::`
The _selector operator_ is very similar to the _switch/case/default_ statement available in many programming languages.
.Syntax
[source,bnf]
----
<selector-operator> ::= <select-expression> "?" <selector-case> { ":" <selector-case> } ["::" <default-multi-expression>]
<selector-case> ::= [<match-list>] <case-value>
<match-list> ::= "["<item>{","<items>}"]"
<item> ::= <expression
<case-multi-expression> ::= "{" <multi-expression> "}"
<multi-expression> ::= <expression> {";" <expression>}
----
.Selector literal Syntax
_selector-operator_ = _select-expression_ "*?*" _selector-case_ { "*:*" _selector-case_ } ["*::*" _default-multi-expression_] +
_selector-case_ = [_match-list_] _case-value_ +
_match-list_ = "*[*" _item_ {"*,*" _items_} "*]*" +
_item_ = _expression_ +
_case-multi-expression_ = "*{*" _multi-expression_ "*}*" +
_multi-expression_ = _expression_ { "*;*" _expression_ } +
_default-multi-expression_ = _multi-expression_
In other words, the selector operator evaluates the expression (`<select-expression>`) on the left-hand side of the `?` symbol; it then compares the result obtained with the values listed in the `<match-list>`'s. If the comparision finds a match with a value in a match-list, the associated `<case-multi-expression>` is evaluted, and its result will be the final result of the selection operation.
In other words, the selector operator evaluates the _select-expression_ on the left-hand side of the [blue]`?` symbol; it then compares the result obtained with the values listed in the __match-list__'s, from left to right. If the comparision finds a match with a value in a _match-list_, the associated _case-multi-expression_ is evaluted, and its result will be the final result of the selection operation.
The match lists are optional. In that case, the position, from left to right, of the `<selector-case>` is used as match-list. Of course, that only works if the select-expression results in an integer.
The match lists are optional. In that case, the position, from left to right, of the _selector-case_ is used as _match-list_. Of course, that only works if the _select-expression_ results in an integer.
The `:` symbol (colon) is the separator of the selector-cases. Note that if the value of the select-expression does not match any match-list, an error will be issued. Therefore, it is strongly recommended to provide a default (multi-)expression introduced by the `::` symbol (double-colon). Also note that the default expression has no match-list.
The [blue]`:` symbol (colon) is the separator of the selector-cases. Note that if the value of the _select-expression_ does not match any _match-list_, an error will be issued. Therefore, it is strongly recommended to provide a default (multi-)expression introduced by the [blue]`::` symbol (double-colon). Also note that the default expression has no _match-list_.
.Examples
[source,go]
----
`>>>` [blue]`1 ? {"a"} : {"b"}`
[green]`b`
`>>>` [blue]`10 ? {"a"} : {"b"} :: {"c"}`
[green]`c'
[green]`>>>` [blue]`10 ? {"a"} :[true, 2+8] {"b"} :: {"c"}`
[green]`b`
`>>>` [blue]`10 ? {"a"} :[true, 2+8] {"b"} ::[10] {"c"}`
[red]`Parse Error: [1:34] case list in default clause`
[green]`>>>` [blue]`10 ? {"a"} :[10] {x="b" but x} :: {"c"}`
[green]`b`
`>>>` [blue]`10 ? {"a"} :[10] {x="b"; x} :: {"c"}`
[green]`b`
`>>>` [blue]`10 ? {"a"} : {"b"}`
`>>>` [blue]`1 ? {"a"} : {"b"}` +
[green]`b` +
`>>>` [blue]`10 ? {"a"} : {"b"} :: {"c"}` +
[green]`c' +
[green]`>>>` [blue]`10 ? {"a"} :[true, 2+8] {"b"} :: {"c"}` +
[green]`b` +
`>>>` [blue]`10 ? {"a"} :[true, 2+8] {"b"} ::[10] {"c"}` +
[red]`Parse Error: [1:34] case list in default clause` +
[green]`>>>` [blue]`10 ? {"a"} :[10] {x="b" but x} :: {"c"}` +
[green]`b` +
`>>>` [blue]`10 ? {"a"} :[10] {x="b"; x} :: {"c"}` +
[green]`b` +
`>>>` [blue]`10 ? {"a"} : {"b"}` +
[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 define; otherwise they return the value of the right expression.
IMPORTANT: If the left variable is defined, the right expression is not evuated at all.
The [blue]`??` do not change the status of the left variable.
The [blue]`?=` assigns the calculated value of the right expression to the left variable.
.Examples
`>>>` [blue]`var ?? (1+2)`'
[green]`3` +
`>>>` [blue]`var` +
[red]`Eval Error: undefined variable or function "var"` +
`>>>` [blue]`var ?= (1+2)` +
[green]`3` +
`>>>` [blue]`var` +
[green]`3`
NOTE: These operators have a high priority, in particular higher than the operator [blue]`=`.
== Priorities of operators
The table below shows all supported operators by decreasing priorities.
+216 -110
View File
@@ -549,31 +549,32 @@ pre.rouge .ss {
</ul>
</li>
<li><a href="#_strings">2.2. Strings</a></li>
<li><a href="#_boolean">2.3. Boolean</a></li>
<li><a href="#_booleans">2.3. Booleans</a></li>
<li><a href="#_lists">2.4. Lists</a></li>
<li><a href="#_dictionaries">2.5. Dictionaries</a></li>
</ul>
</li>
<li><a href="#_dictionaries">3. Dictionaries</a></li>
<li><a href="#_variables">4. Variables</a></li>
<li><a href="#_other_operations">5. Other operations</a>
<li><a href="#_variables">3. Variables</a></li>
<li><a href="#_other_operations">4. Other operations</a>
<ul class="sectlevel2">
<li><a href="#_operator">5.1. <code class="blue">;</code> operator</a></li>
<li><a href="#_but_operator">5.2. <code class="blue">but</code> operator</a></li>
<li><a href="#_assignment_operator">5.3. Assignment operator <code class="blue">=</code></a></li>
<li><a href="#_selector_operator">5.4. Selector operator <code class="blue">? : ::</code></a></li>
<li><a href="#_operator">4.1. <code class="blue">;</code> operator</a></li>
<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>
</ul>
</li>
<li><a href="#_priorities_of_operators">6. Priorities of operators</a></li>
<li><a href="#_functions">7. Functions</a>
<li><a href="#_priorities_of_operators">5. Priorities of operators</a></li>
<li><a href="#_functions">6. Functions</a>
<ul class="sectlevel2">
<li><a href="#_function_calls">7.1. Function calls</a></li>
<li><a href="#_function_definitions">7.2. Function definitions</a></li>
<li><a href="#_function_calls">6.1. Function calls</a></li>
<li><a href="#_function_definitions">6.2. Function definitions</a></li>
</ul>
</li>
<li><a href="#_builtins">8. Builtins</a>
<li><a href="#_builtins">7. Builtins</a>
<ul class="sectlevel2">
<li><a href="#_builtin_functions">8.1. Builtin functions</a></li>
<li><a href="#_import">8.2. <em class="blue">import()</em></a></li>
<li><a href="#_builtin_functions">7.1. Builtin functions</a></li>
<li><a href="#_import">7.2. <em class="blue">import()</em></a></li>
</ul>
</li>
</ul>
@@ -584,7 +585,7 @@ pre.rouge .ss {
<div class="sectionbody">
<!-- toc disabled -->
<div class="paragraph">
<p><mark>TODO: Work in progress (last update on 2024/05/16, 7:08 a.m.)</mark></p>
<p><mark>TODO: Work in progress (last update on 2024/05/17, 15:47 p.m.)</mark></p>
</div>
</div>
</div>
@@ -622,7 +623,7 @@ pre.rouge .ss {
<div class="listingblock">
<div class="title">Run <code>dev-expr</code> in REPL mode and ask for help</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="shell"><span class="c"># Assume the expr source directory. Type 'exit' or Ctrl+D to quit the program.</span>
<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
<span class="nb">expr</span> <span class="nt">--</span> Expressions calculator v1.7.1<span class="o">(</span>build 2<span class="o">)</span>,2024/05/16 <span class="o">(</span>celestino.amoroso@portale-stac.it<span class="o">)</span>
@@ -742,7 +743,7 @@ pre.rouge .ss {
<p><span class="blue">Floats</span></p>
</li>
<li>
<p><span class="blue">Factions</span> internally are stored as <em>pairs of</em> Golang <em>int64</em> values.</p>
<p><span class="blue">Factions</span></p>
</li>
</ol>
</div>
@@ -854,7 +855,7 @@ pre.rouge .ss {
<code>&gt;&gt;&gt;</code> <code class="blue">4.5E-3</code><br>
<code class="green">0.0045</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">4.5E10</code><br>
<code class="green">4.5e+10</code><br></p>
<code class="green">4.5e+10</code></p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Table 2. Arithmetic operators</caption>
@@ -918,7 +919,7 @@ pre.rouge .ss {
<em>num-den-spec</em> = <em>digit-seq</em> "<strong>|</strong>" <em>digit-seq</em><br>
<em>float-spec</em> = <em>dec-seq</em> "<strong>.</strong>" [<em>dec-seq</em>] "<strong>(</strong>" <em>dec-seq</em> "<strong>)</strong>"<br>
<em>dec-seq</em> = <em>see-integer-literal-syntax</em><br>
<em>digit-seq</em> = <em>see-integer-literal-syntax</em><br></p>
<em>digit-seq</em> = <em>see-integer-literal-syntax</em></p>
</div>
</div>
</div>
@@ -947,12 +948,13 @@ pre.rouge .ss {
<p>Fractions can be used together with integers and floats in expressions.</p>
</div>
<div class="paragraph">
<div class="title">Examples</div>
<p><code>&gt;&gt;&gt;</code> <code class="blue">1|2 + 5</code><br>
<code class="green">11|2</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">4 - 1|2</code><br>
<code class="green">7|2</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">1.0 + 1|2</code><br>
<code class="green">1.5</code><br></p>
<code class="green">1.5</code></p>
</div>
</div>
</div>
@@ -1030,11 +1032,11 @@ pre.rouge .ss {
<code>&gt;&gt;&gt;</code> <code class="blue">#s</code> <em class="gray">number of chars</em><br>
<code class="gren">3</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">#"abc"</code> <em class="gray">number of chars</em><br>
<code class="green">3</code><br></p>
<code class="green">3</code></p>
</div>
</div>
<div class="sect2">
<h3 id="_boolean"><a class="anchor" href="#_boolean"></a><a class="link" href="#_boolean">2.3. Boolean</a></h3>
<h3 id="_booleans"><a class="anchor" href="#_booleans"></a><a class="link" href="#_booleans">2.3. Booleans</a></h3>
<div class="paragraph">
<p>Boolean data type has two values only: <em class="blue">true</em> and <em class="blue">false</em>. Relational and boolean expressions result in boolean values.</p>
</div>
@@ -1171,18 +1173,31 @@ pre.rouge .ss {
<div class="sect2">
<h3 id="_lists"><a class="anchor" href="#_lists"></a><a class="link" href="#_lists">2.4. Lists</a></h3>
<div class="paragraph">
<p><em>Expr</em> supports list of mixed-type values, also specified by normal expressions.</p>
<p><em>Expr</em> supports list of mixed-type values, also specified by normal expressions. Internally, <em>Expr</em>'s lists are Go arrays.</p>
</div>
<div class="listingblock">
<div class="title">List examples</div>
<div class="exampleblock">
<div class="title">Example 5. List literal syntax</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="go"><span class="p">[</span><span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span><span class="p">]</span> <span class="c">// List of integers</span>
<span class="p">[</span><span class="s">"one"</span><span class="p">,</span> <span class="s">"two"</span><span class="p">,</span> <span class="s">"three"</span><span class="p">]</span> <span class="c">// List of strings</span>
<span class="p">[</span><span class="s">"one"</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="no">false</span><span class="p">,</span> <span class="m">4.1</span><span class="p">]</span> <span class="c">// List of mixed-types</span>
<span class="p">[</span><span class="s">"one"</span><span class="o">+</span><span class="m">1</span><span class="p">,</span> <span class="m">2.0</span><span class="o">*</span><span class="p">(</span><span class="m">9</span><span class="o">-</span><span class="m">2</span><span class="p">)]</span> <span class="c">// List of expressions</span>
<span class="p">[</span> <span class="p">[</span><span class="m">1</span><span class="p">,</span><span class="s">"one"</span><span class="p">],</span> <span class="p">[</span><span class="m">2</span><span class="p">,</span><span class="s">"two"</span><span class="p">]]</span> <span class="c">// List of lists</span></code></pre>
<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>
</div>
</div>
</div>
<div class="paragraph">
<div class="title">Examples</div>
<p><code>&gt;&gt;&gt;</code> <code class="blue">[1,2,3]</code> <em class="gray">// List of integers</em><br>
<code class="green">[1, 2, 3]</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">["one", "two", "three"]</code> <em class="gray">// List of strings</em><br>
<code class="green">["one", "two", "three"]</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">["one", 2, false, 4.1]</code> <em class="gray">// List of mixed-types</em><br>
<code class="green">["one", 2, false, 4.1]</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">["one"+1, 2.0*(9-2)]</code> <em class="gray">// List of expressions</em><br>
<code class="green">["one1", 14]</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">[ [1,"one"], [2,"two"]]</code> <em class="gray">// List of lists</em><br>
<code class="green">[[1, "one"], [2, "two"]]</code></p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Table 6. List operators</caption>
<colgroup>
@@ -1204,23 +1219,25 @@ pre.rouge .ss {
<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>Join</em></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Joins two lists</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">[1,2] + [3]</code> <em>[ [1,2,3] ]</em></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">[1,2] + [3]</code> &#8594; <em>[1,2,3]</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>Difference</em></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Left list without elements in the right list</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">[1,2,3] - [2]</code> <em>[ [1,3] ]</em></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">[1,2,3] - [2]</code> &#8594; <em>[1,3]</em></p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The items of array can be accessed using the dot <code>.</code> operator.</p>
</div>
<div class="listingblock">
<div class="title">Item access syntax</div>
<div class="exampleblock">
<div class="title">Example 6. Item access syntax</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="bnf">&lt;item&gt; ::= &lt;list-expr&gt;"."&lt;index-expr&gt;</code></pre>
<div class="paragraph">
<p><em>item</em> = <em>list-expr</em> "<strong>.</strong>" <em>list-expr</em></p>
</div>
</div>
</div>
<div class="paragraph">
@@ -1241,22 +1258,8 @@ pre.rouge .ss {
<code class="green">3</code></p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_dictionaries"><a class="anchor" href="#_dictionaries"></a><a class="link" href="#_dictionaries">3. Dictionaries</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <em>dictionary</em> data-type is set of pairs <em>key/value</em>. It is also known as <em>map</em> or <em>associative array</em>. Dictionary literals are sequences of pairs separated by comma <code>,</code>; sequences are enclosed between brace brackets.</p>
</div>
<div class="listingblock">
<div class="title">Dictionary examples</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="go"><span class="p">{</span><span class="m">1</span><span class="o">:</span><span class="s">"one"</span><span class="p">,</span> <span class="m">2</span><span class="o">:</span><span class="s">"two"</span><span class="p">}</span>
<span class="p">{</span><span class="s">"one"</span><span class="o">:</span><span class="m">1</span><span class="p">,</span> <span class="s">"two"</span><span class="o">:</span> <span class="m">2</span><span class="p">}</span>
<span class="p">{</span><span class="s">"sum"</span><span class="o">:</span><span class="m">1</span><span class="o">+</span><span class="m">2</span><span class="o">+</span><span class="m">3</span><span class="p">,</span> <span class="s">"prod"</span><span class="o">:</span><span class="m">1</span><span class="o">*</span><span class="m">2</span><span class="o">*</span><span class="m">3</span><span class="p">}</span></code></pre>
</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="admonitionblock warning">
<table>
<tr>
@@ -1269,31 +1272,85 @@ Support for dictionaries is still ongoing.
</tr>
</table>
</div>
<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>. Dictionary literals are sequences of pairs separated by comma <code>,</code>; sequences are enclosed between brace brackets.</p>
</div>
<div class="exampleblock">
<div class="title">Example 7. Dict literal syntax</div>
<div class="content">
<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>
</div>
</div>
</div>
<div class="paragraph">
<div class="title">Examples</div>
<p><code>&gt;&gt;&gt;</code> <code class="blue">{1:"one", 2:"two"}</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">{"one":1, "two": 2}</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">{"sum":1+2+3, "prod":1*2*3}</code></p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_variables"><a class="anchor" href="#_variables"></a><a class="link" href="#_variables">4. Variables</a></h2>
<h2 id="_variables"><a class="anchor" href="#_variables"></a><a class="link" href="#_variables">3. Variables</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>A variable is an identifier with an assigned value. Variables are stored in the object that implements the Go <em>ExprContext</em> interface, e.g. <em>SimpleVarStore</em> or <em>SimpleFuncStore</em>.</p>
<p><em>Expr</em> supports variables like most programming languages. A variable is an identifier with an assigned value. Variables are stored in <em>contexts</em>.</p>
</div>
<div class="listingblock">
<div class="title">Examples</div>
<div class="exampleblock">
<div class="title">Example 8. Variable literal syntax</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="go"><span class="n">a</span><span class="o">=</span><span class="m">1</span>
<span class="n">x</span> <span class="o">=</span> <span class="m">5.2</span> <span class="o">*</span> <span class="p">(</span><span class="m">9</span><span class="o">-</span><span class="m">3</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="m">1</span><span class="p">;</span> <span class="n">y</span> <span class="o">=</span> <span class="m">2</span><span class="o">*</span><span class="n">x</span></code></pre>
<div class="paragraph">
<p><strong><em>variable</em></strong> = <em>identifier</em> "<strong>=</strong>" <em>any-value</em><br>
<em>identifier</em> = <em>alpha</em> {(<em>alpha</em>)|<em>dec-digit</em>|"<strong>_</strong>"}<br>
<em>alpha</em> = "<strong>a</strong>"|"<strong>b</strong>"|&#8230;&#8203;"<strong>z</strong>"|"<strong>A</strong>"|"<strong>B</strong>"|&#8230;&#8203;"<strong>Z</strong>"</p>
</div>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The assign operator <code class="blue">=</code> returns the value assigned to the variable.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<div class="title">Examples</div>
<p><code>&gt;&gt;&gt;</code> <code class="blue">a=1</code><br>
<code class="green">1</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">a_b=1+2</code><br>
<code class="green">1+2</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">a_b</code><br>
<code class="green">3</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">x = 5.2 * (9-3)</code> <em class="gray">// The assigned value has the approximation error typical of the float data-type</em><br>
<code class="green">31.200000000000003</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">x = 1; y = 2*x</code><br>
<code class="green">2</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue"><em>a=2</code><br>
<code class="red">Parse Error: [1:2] unexpected token "</em>"</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">1=2</code><br>
<code class="red">Parse Error: assign operator ("=") must be preceded by a variable</code></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_other_operations"><a class="anchor" href="#_other_operations"></a><a class="link" href="#_other_operations">5. Other operations</a></h2>
<h2 id="_other_operations"><a class="anchor" href="#_other_operations"></a><a class="link" href="#_other_operations">4. Other operations</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_operator"><a class="anchor" href="#_operator"></a><a class="link" href="#_operator">5.1. <code class="blue">;</code> operator</a></h3>
<h3 id="_operator"><a class="anchor" href="#_operator"></a><a class="link" href="#_operator">4.1. <code class="blue">;</code> operator</a></h3>
<div class="paragraph">
<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 latter is the final result.</p>
<p>The semicolon operator <code class="blue">;</code> is an infixed pseudo-operator. It evaluates the left expression first and then the right expression. The value of the latter is the final result.</p>
</div>
<div 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>
</div>
<div class="admonitionblock important">
<table>
@@ -1319,15 +1376,22 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
</tr>
</table>
</div>
<div class="listingblock">
<div class="paragraph">
<div class="title">Example</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="go"><span class="n">a</span><span class="o">=</span><span class="m">1</span><span class="p">;</span> <span class="n">b</span><span class="o">=</span><span class="m">2</span><span class="p">;</span> <span class="n">c</span><span class="o">=</span><span class="m">3</span><span class="p">;</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="o">+</span><span class="n">c</span> <span class="c">// returns 6</span></code></pre>
<p><code>&gt;&gt;&gt;</code> <code class="blue">a=1; b=2; c=3; a+b+c</code><br>
<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>
</div>
<div class="paragraph">
<div class="title">Example</div>
<p><code>&gt;&gt;&gt;</code> <code class="blue">2+3; b=last+10; last</code><br>
<code class="green">15</code></p>
</div>
</div>
<div class="sect2">
<h3 id="_but_operator"><a class="anchor" href="#_but_operator"></a><a class="link" href="#_but_operator">5.2. <code class="blue">but</code> operator</a></h3>
<h3 id="_but_operator"><a class="anchor" href="#_but_operator"></a><a class="link" href="#_but_operator">4.2. <code class="blue">but</code> operator</a></h3>
<div class="paragraph">
<p><code class="blue">but</code> 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: <code class="blue">5 but 2</code> returns 2, <code class="blue">x=2*3 but x-1</code> returns 5.</p>
</div>
@@ -1336,68 +1400,110 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
</div>
</div>
<div class="sect2">
<h3 id="_assignment_operator"><a class="anchor" href="#_assignment_operator"></a><a class="link" href="#_assignment_operator">5.3. Assignment operator <code class="blue">=</code></a></h3>
<h3 id="_assignment_operator"><a class="anchor" href="#_assignment_operator"></a><a class="link" href="#_assignment_operator">4.3. Assignment operator <code class="blue">=</code></a></h3>
<div class="paragraph">
<p>The assignment operator <code class="blue">=</code> is used to define variables in the evaluation context or to change their value (see <em>ExprContext</em>).
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>
</div>
<div class="listingblock">
<div class="paragraph">
<div class="title">Example</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="go"><span class="n">a</span><span class="o">=</span><span class="m">15</span><span class="o">+</span><span class="m">1</span> <span class="c">// returns 16</span></code></pre>
</div>
<p><code>&gt;&gt;&gt;</code> <code class="blue">a=15+1</code>
<code class="green">16</code></p>
</div>
</div>
<div class="sect2">
<h3 id="_selector_operator"><a class="anchor" href="#_selector_operator"></a><a class="link" href="#_selector_operator">5.4. Selector operator <code class="blue">? : ::</code></a></h3>
<h3 id="_selector_operator"><a class="anchor" href="#_selector_operator"></a><a class="link" href="#_selector_operator">4.4. Selector operator <code class="blue">? : ::</code></a></h3>
<div class="paragraph">
<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="listingblock">
<div class="title">Syntax</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="bnf">&lt;selector-operator&gt; ::= &lt;select-expression&gt; "?" &lt;selector-case&gt; { ":" &lt;selector-case&gt; } ["::" &lt;default-multi-expression&gt;]
&lt;selector-case&gt; ::= [&lt;match-list&gt;] &lt;case-value&gt;
&lt;match-list&gt; ::= "["&lt;item&gt;{","&lt;items&gt;}"]"
&lt;item&gt; ::= &lt;expression
&lt;case-multi-expression&gt; ::= "{" &lt;multi-expression&gt; "}"
&lt;multi-expression&gt; ::= &lt;expression&gt; {";" &lt;expression&gt;}</code></pre>
</div>
<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>
<em>item</em> = <em>expression</em><br>
<em>case-multi-expression</em> = "<strong>{</strong>" <em>multi-expression</em> "<strong>}</strong>"<br>
<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 class="paragraph">
<p>In other words, the selector operator evaluates the expression (<code>&lt;select-expression&gt;</code>) on the left-hand side of the <code>?</code> symbol; it then compares the result obtained with the values listed in the <code>&lt;match-list&gt;&#8217;s. If the comparision finds a match with a value in a match-list, the associated `&lt;case-multi-expression&gt;</code> is evaluted, and its result will be the final result of the selection operation.</p>
<p>In other words, the selector operator evaluates the <em>select-expression</em> on the left-hand side of the <code class="blue">?</code> symbol; it then compares the result obtained with the values listed in the <em>match-list</em>'s, from left to right. If the comparision finds a match with a value in a <em>match-list</em>, the associated <em>case-multi-expression</em> is evaluted, and its result will be the final result of the selection operation.</p>
</div>
<div class="paragraph">
<p>The match lists are optional. In that case, the position, from left to right, of the <code>&lt;selector-case&gt;</code> is used as match-list. Of course, that only works if the select-expression results in an integer.</p>
<p>The match lists are optional. In that case, the position, from left to right, of the <em>selector-case</em> is used as <em>match-list</em>. Of course, that only works if the <em>select-expression</em> results in an integer.</p>
</div>
<div class="paragraph">
<p>The <code>:</code> symbol (colon) is the separator of the selector-cases. Note that if the value of the select-expression does not match any match-list, an error will be issued. Therefore, it is strongly recommended to provide a default (multi-)expression introduced by the <code>::</code> symbol (double-colon). Also note that the default expression has no match-list.</p>
<p>The <code class="blue">:</code> symbol (colon) is the separator of the selector-cases. Note that if the value of the <em>select-expression</em> does not match any <em>match-list</em>, an error will be issued. Therefore, it is strongly recommended to provide a default (multi-)expression introduced by the <code class="blue">::</code> symbol (double-colon). Also note that the default expression has no <em>match-list</em>.</p>
</div>
<div class="listingblock">
<div class="paragraph">
<div class="title">Examples</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="go"><span class="s">`&gt;&gt;&gt;`</span> <span class="p">[</span><span class="n">blue</span><span class="p">]</span><span class="s">`1 ? {"a"} : {"b"}`</span>
<span class="p">[</span><span class="n">green</span><span class="p">]</span><span class="s">`b`</span>
<span class="s">`&gt;&gt;&gt;`</span> <span class="p">[</span><span class="n">blue</span><span class="p">]</span><span class="s">`10 ? {"a"} : {"b"} :: {"c"}`</span>
<span class="p">[</span><span class="n">green</span><span class="p">]</span><span class="s">`c'
[green]`</span><span class="o">&gt;&gt;&gt;</span><span class="s">` [blue]`</span><span class="m">10</span> <span class="err">?</span> <span class="p">{</span><span class="s">"a"</span><span class="p">}</span> <span class="o">:</span><span class="p">[</span><span class="no">true</span><span class="p">,</span> <span class="m">2</span><span class="o">+</span><span class="m">8</span><span class="p">]</span> <span class="p">{</span><span class="s">"b"</span><span class="p">}</span> <span class="o">::</span> <span class="p">{</span><span class="s">"c"</span><span class="p">}</span><span class="s">`
[green]`</span><span class="n">b</span><span class="s">`
`</span><span class="o">&gt;&gt;&gt;</span><span class="s">` [blue]`</span><span class="m">10</span> <span class="err">?</span> <span class="p">{</span><span class="s">"a"</span><span class="p">}</span> <span class="o">:</span><span class="p">[</span><span class="no">true</span><span class="p">,</span> <span class="m">2</span><span class="o">+</span><span class="m">8</span><span class="p">]</span> <span class="p">{</span><span class="s">"b"</span><span class="p">}</span> <span class="o">::</span><span class="p">[</span><span class="m">10</span><span class="p">]</span> <span class="p">{</span><span class="s">"c"</span><span class="p">}</span><span class="s">`
[red]`</span><span class="n">Parse</span> <span class="n">Error</span><span class="o">:</span> <span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="m">34</span><span class="p">]</span> <span class="k">case</span> <span class="n">list</span> <span class="n">in</span> <span class="k">default</span> <span class="n">clause</span><span class="s">`
[green]`</span><span class="o">&gt;&gt;&gt;</span><span class="s">` [blue]`</span><span class="m">10</span> <span class="err">?</span> <span class="p">{</span><span class="s">"a"</span><span class="p">}</span> <span class="o">:</span><span class="p">[</span><span class="m">10</span><span class="p">]</span> <span class="p">{</span><span class="n">x</span><span class="o">=</span><span class="s">"b"</span> <span class="n">but</span> <span class="n">x</span><span class="p">}</span> <span class="o">::</span> <span class="p">{</span><span class="s">"c"</span><span class="p">}</span><span class="s">`
[green]`</span><span class="n">b</span><span class="s">`
`</span><span class="o">&gt;&gt;&gt;</span><span class="s">` [blue]`</span><span class="m">10</span> <span class="err">?</span> <span class="p">{</span><span class="s">"a"</span><span class="p">}</span> <span class="o">:</span><span class="p">[</span><span class="m">10</span><span class="p">]</span> <span class="p">{</span><span class="n">x</span><span class="o">=</span><span class="s">"b"</span><span class="p">;</span> <span class="n">x</span><span class="p">}</span> <span class="o">::</span> <span class="p">{</span><span class="s">"c"</span><span class="p">}</span><span class="s">`
[green]`</span><span class="n">b</span><span class="s">`
`</span><span class="o">&gt;&gt;&gt;</span><span class="s">` [blue]`</span><span class="m">10</span> <span class="err">?</span> <span class="p">{</span><span class="s">"a"</span><span class="p">}</span> <span class="o">:</span> <span class="p">{</span><span class="s">"b"</span><span class="p">}</span><span class="s">`
[red]`</span><span class="n">Eval</span> <span class="n">Error</span><span class="o">:</span> <span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">]</span> <span class="n">no</span> <span class="k">case</span> <span class="n">catches</span> <span class="n">the</span> <span class="n">value</span> <span class="p">(</span><span class="m">10</span><span class="p">)</span> <span class="n">of</span> <span class="n">the</span> <span class="n">selection</span> <span class="n">expression</span><span class="s">`
</span></code></pre>
<p><code>&gt;&gt;&gt;</code> <code class="blue">1 ? {"a"} : {"b"}</code><br>
<code class="green">b</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">10 ? {"a"} : {"b"} :: {"c"}</code><br>
<code class="green">c'<br>
[green]</code>&gt;&gt;&gt;` <code class="blue">10 ? {"a"} :[true, 2+8] {"b"} :: {"c"}</code><br>
<code class="green">b</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">10 ? {"a"} :[true, 2+8] {"b"} ::[10] {"c"}</code><br>
<code class="red">Parse Error: [1:34] case list in default clause</code><br>
<code class="green">&gt;&gt;&gt;</code> <code class="blue">10 ? {"a"} :[10] {x="b" but x} :: {"c"}</code><br>
<code class="green">b</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">10 ? {"a"} :[10] {x="b"; x} :: {"c"}</code><br>
<code class="green">b</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">10 ? {"a"} : {"b"}</code><br>
<code class="red">Eval Error: [1:3] no case catches the value (10) of the selection expression</code></p>
</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>
<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 define; otherwise they return the value of the right expression.</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 defined, the right expression is not evuated at all.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code class="blue">??</code> do not change the status of the left variable.</p>
</div>
<div class="paragraph">
<p>The <code class="blue">?=</code> assigns the calculated value of the right expression to the left variable.</p>
</div>
<div class="paragraph">
<div class="title">Examples</div>
<p><code>&gt;&gt;&gt;</code> <code class="blue">var ?? (1+2)&#8217;
[green]`3</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">var</code><br>
<code class="red">Eval Error: undefined variable or function "var"</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">var ?= (1+2)</code><br>
<code class="green">3</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">var</code><br>
<code class="green">3</code></p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
These operators have a high priority, in particular higher than the operator <code class="blue">=</code>.
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_priorities_of_operators"><a class="anchor" href="#_priorities_of_operators"></a><a class="link" href="#_priorities_of_operators">6. Priorities of operators</a></h2>
<h2 id="_priorities_of_operators"><a class="anchor" href="#_priorities_of_operators"></a><a class="link" href="#_priorities_of_operators">5. Priorities of operators</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The table below shows all supported operators by decreasing priorities.</p>
@@ -1618,7 +1724,7 @@ The value on the left side of <code class="blue">=</code> must be an identifier.
</div>
</div>
<div class="sect1">
<h2 id="_functions"><a class="anchor" href="#_functions"></a><a class="link" href="#_functions">7. Functions</a></h2>
<h2 id="_functions"><a class="anchor" href="#_functions"></a><a class="link" href="#_functions">6. Functions</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Functions in <em>Expr</em> are very similar to functions in many programming languages.</p>
@@ -1627,13 +1733,13 @@ The value on the left side of <code class="blue">=</code> must be an identifier.
<p>In <em>Expr</em> 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>
</div>
<div class="sect2">
<h3 id="_function_calls"><a class="anchor" href="#_function_calls"></a><a class="link" href="#_function_calls">7.1. Function calls</a></h3>
<h3 id="_function_calls"><a class="anchor" href="#_function_calls"></a><a class="link" href="#_function_calls">6.1. Function calls</a></h3>
<div class="paragraph">
<p><mark>TODO: function calls operations</mark></p>
</div>
</div>
<div class="sect2">
<h3 id="_function_definitions"><a class="anchor" href="#_function_definitions"></a><a class="link" href="#_function_definitions">7.2. Function definitions</a></h3>
<h3 id="_function_definitions"><a class="anchor" href="#_function_definitions"></a><a class="link" href="#_function_definitions">6.2. Function definitions</a></h3>
<div class="paragraph">
<p><mark>TODO: function definitions operations</mark></p>
</div>
@@ -1641,17 +1747,17 @@ The value on the left side of <code class="blue">=</code> must be an identifier.
</div>
</div>
<div class="sect1">
<h2 id="_builtins"><a class="anchor" href="#_builtins"></a><a class="link" href="#_builtins">8. Builtins</a></h2>
<h2 id="_builtins"><a class="anchor" href="#_builtins"></a><a class="link" href="#_builtins">7. Builtins</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p><mark>TODO: builtins</mark></p>
</div>
<div class="sect2">
<h3 id="_builtin_functions"><a class="anchor" href="#_builtin_functions"></a><a class="link" href="#_builtin_functions">8.1. Builtin functions</a></h3>
<h3 id="_builtin_functions"><a class="anchor" href="#_builtin_functions"></a><a class="link" href="#_builtin_functions">7.1. Builtin functions</a></h3>
</div>
<div class="sect2">
<h3 id="_import"><a class="anchor" href="#_import"></a><a class="link" href="#_import">8.2. <em class="blue">import()</em></a></h3>
<h3 id="_import"><a class="anchor" href="#_import"></a><a class="link" href="#_import">7.2. <em class="blue">import()</em></a></h3>
<div class="paragraph">
<p><em class="blue">import(<span class="grey">&lt;source-file&gt;</span>)</em> loads the multi-expression contained in the specified source and returns its value.</p>
</div>
@@ -1661,7 +1767,7 @@ The value on the left side of <code class="blue">=</code> must be an identifier.
</div>
<div id="footer">
<div id="footer-text">
Last updated 2024-05-16 07:10:03 +0200
Last updated 2024-05-17 15:47:29 +0200
</div>
</div>
</body>
+3 -2
View File
@@ -40,6 +40,7 @@ func TestListParser(t *testing.T) {
/* 18 */ {`["a", "b", "c"]`, newListA("a", "b", "c"), nil},
/* 19 */ {`["a", "b", "c"]`, newList([]any{"a", "b", "c"}), nil},
/* 20 */ {`#["a", "b", "c"]`, int64(3), nil},
/* 21 */ {`"b" in ["a", "b", "c"]`, true, nil},
// /* 8 */ {`[int(x)|x=csv("test.csv",1,all(),1)]`, []any{int64(10), int64(40), int64(20)}, nil},
// /* 9 */ {`sum(@[int(x)|x=csv("test.csv",1,all(),1)])`, []any{int64(10), int64(40), int64(20)}, nil},
@@ -58,8 +59,8 @@ func TestListParser(t *testing.T) {
var gotErr error
ctx := NewSimpleFuncStore()
ctx.SetVar("var1", int64(123))
ctx.SetVar("var2", "abc")
// ctx.SetVar("var1", int64(123))
// ctx.SetVar("var2", "abc")
ImportMathFuncs(ctx)
parser := NewParser(ctx)
+11
View File
@@ -6,6 +6,7 @@ package expr
import (
"fmt"
"reflect"
"strings"
)
@@ -61,6 +62,16 @@ func newList(listAny []any) (list *ListType) {
return
}
func (list *ListType) indexDeepCmp(target any) (index int) {
index = -1
for i, item := range *list {
if reflect.DeepEqual(item, target) {
index = i
break
}
}
return
}
// -------- list term
func newListTermA(args ...*term) *term {
+2
View File
@@ -4,6 +4,8 @@
// operand-fraction.go
package expr
//https://www.youmath.it/lezioni/algebra-elementare/lezioni-di-algebra-e-aritmetica-per-scuole-medie/553-dalle-frazioni-a-numeri-decimali.html
import (
"errors"
"fmt"
+46
View File
@@ -0,0 +1,46 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-in.go
package expr
//-------- in term
func newInTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRelational,
evalFunc: evalIn,
}
}
func hasKey(d map[any]any, target any) (ok bool) {
_, ok = d[target]
return
}
func evalIn(ctx ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
if IsList(rightValue) {
list, _ := rightValue.(*ListType)
v = list.indexDeepCmp(leftValue) >= 0
} else if IsDict(rightValue) {
d, _ := rightValue.(map[any]any)
v = hasKey(d, leftValue)
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
}
return
}
// init
func init() {
registerTermConstructor(SymKwIn, newInTerm)
}
+2
View File
@@ -99,6 +99,7 @@ const (
SymKwBut
SymKwFunc
SymKwBuiltin
SymKwIn
SymKwInclude
SymKwNil
)
@@ -112,6 +113,7 @@ func init() {
"BUILTIN": SymKwBuiltin,
"BUT": SymKwBut,
"FUNC": SymKwFunc,
"IN": SymKwIn,
"INCLUDE": SymKwInclude,
"NOT": SymKwNot,
"OR": SymKwOr,
+1
View File
@@ -31,6 +31,7 @@ func TestGetRoom(t *testing.T) {
t.Errorf("err: got <%v>, want <nil>", gotErr)
}
}
func TestGetChildrenCount(t *testing.T) {
tk1 := NewValueToken(0, 0, SymInteger, "100", 100)
+139
View File
@@ -0,0 +1,139 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// utils_test.go
package expr
import (
"errors"
"testing"
)
func TestIsString(t *testing.T) {
count := 0
succeeded := 0
failed := 0
count++
if !IsBool(true) {
t.Errorf("%d: IsBool(true) -> result = false, want true", count)
failed++
} else {
succeeded++
}
count++
if !IsString("abc") {
t.Errorf("%d: IsString(\"abc\") -> result = false, want true", count)
failed++
} else {
succeeded++
}
count++
if !IsInteger(int64(123)) {
t.Errorf("%d: IsInteger(123) -> result = false, want true", count)
failed++
} else {
succeeded++
}
count++
if !IsFloat(1.23) {
t.Errorf("%d: IsFloat(1.23) -> result = false, want true", count)
failed++
} else {
succeeded++
}
count++
if !IsFloat(numAsFloat(123)) {
t.Errorf("%d: IsFloat(numAsFloat(123)) -> result = false, want true", count)
failed++
} else {
succeeded++
}
count++
b, ok := toBool(true)
if !(ok && b) {
t.Errorf("%d: toBool(true) b=%v, ok=%v -> result = false, want true", count, b, ok)
failed++
} else {
succeeded++
}
count++
b, ok = toBool("abc")
if !(ok && b) {
t.Errorf("%d: toBool(\"abc\") b=%v, ok=%v -> result = false, want true", count, b, ok)
failed++
} else {
succeeded++
}
t.Logf("test count: %d, succeeded count: %d, failed count: %d", count, succeeded, failed)
}
func TestToIntOk(t *testing.T) {
source := int64(64)
wantValue := int(64)
wantErr := error(nil)
gotValue, gotErr := toInt(source, "test")
if gotErr != nil || gotValue != wantValue {
t.Errorf("toInt(%v, \"test\") gotValue=%v, gotErr=%v -> wantValue=%v, wantErr=%v",
source, gotValue, gotErr, wantValue, wantErr)
}
}
func TestToIntErr(t *testing.T) {
source := uint64(64)
wantValue := 0
wantErr := errors.New(`test expected integer, got uint64 (64)`)
gotValue, gotErr := toInt(source, "test")
if gotErr.Error() != wantErr.Error() || gotValue != wantValue {
t.Errorf("toInt(%v, \"test\") gotValue=%v, gotErr=%v -> wantValue=%v, wantErr=%v",
source, gotValue, gotErr, wantValue, wantErr)
}
}
func TestAnyInteger(t *testing.T) {
type inputType struct {
source any
wantValue int64
wantOk bool
}
section := "utils.anyInteger"
inputs := []inputType{
/* 1 */ {int8(-8), int64(-8), true},
/* 2 */ {int16(-16), int64(-16), true},
/* 3 */ {int32(-32), int64(-32), true},
/* 4 */ {int64(-64), int64(-64), true},
/* 5 */ {uint8(8), int64(8), true},
/* 6 */ {uint16(16), int64(16), true},
/* 7 */ {uint32(32), int64(32), true},
/* 8 */ {uint64(64), int64(64), true},
/* 9 */ {int(-1), int64(-1), true},
/* 10 */ {true, 0, false},
}
succeeded := 0
failed := 0
for i, input := range inputs {
gotValue, gotOk := anyInteger(input.source)
if gotOk != input.wantOk || gotValue != input.wantValue {
t.Errorf("%d: anyInteger(%v) -> gotOk = %t, wantOk = %t; gotValue = %v, wantValue = %v",
i+1, input.source, gotOk, input.wantOk, gotValue, input.wantValue)
failed++
} else {
succeeded++
}
}
t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(inputs), succeeded, failed)
}