= Expr Expressions calculator :authors: Celestino Amoroso :docinfo: shared :encoding: utf-8 :toc: right :toclevels: 4 //:toc-title: Indice Generale :icons: font :icon-set: fi :numbered: :data-uri: //:table-caption: Tabella //:figure-caption: Diagramma :docinfo1: :sectlinks: :sectanchors: :source-highlighter: rouge // :rouge-style: ThankfulEyes :rouge-style: gruvbox // :rouge-style: colorful //:rouge-style: monokay // Work around to manage double-column in back-tick quotes :2c: :: toc::[] #TODO: Work in progress (last update on 2024/06/21, 05:40 a.m.)# == Expr _Expr_ is a GO package capable of analysing, interpreting and calculating expressions. === Concepts and terminology 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. * *_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. * *_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[] ==== Variables _Expr_ supports variables. The result of an expression can be stored in a variable and reused in other espressions simply specifying the name of the variable as an operand. ==== 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. 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. ==== Calculation context All objects, such as variables and functions, created during the calculation of an expression are stored in a memory called _context_. The expression context is analogous to the stack-frame of other programming languages. When a function is called, a new context is allocated to store local definitions. Function contexts are created by cloning the calling context. More details on this topic are given later in this document. _Expr_ creates and keeps a inner _global context_ where it stores imported functions, either from builtin or plugin modules. To perform calculations, the user program must provide its own context; this is the _main context_. All calculations take place in this context. As mentioned eralier, when a function is called, a new context is created by cloning the calling context. The created context can be called _function context_. Imported functions are registerd in the _global context_. When an expression first calls an imported function, that function is linked to the current context; this can be the _main context_ or a _function context_. === `dev-expr` test tool 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. `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. `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. The program can be downloaded from https://git.portale-stac.it/go-pkg/-/packages/generic/dev-expr/[dev-expr]. Here are some examples of execution. .Run `dev-expr` in REPL mode and ask for help [source,shell] ---- # Type 'exit' or Ctrl+D to quit the program. [user]$ ./dev-expr dev-expr -- Expressions calculator v1.12.0(build 1),2024/09/14 (celestino.amoroso@portale-stac.it) Based on the Expr package v0.26.0 Type help to get the list of available commands See also https://git.portale-stac.it/go-pkg/expr/src/branch/main/README.adoc >>> help --- REPL commands: base -- Set the integer output base: 2, 8, 10, or 16 exit -- Exit the program help -- Show command list ml -- Enable/Disable multi-line output mods -- List builtin modules output -- Enable/Disable printing expression results. Options 'on', 'off', 'status' source -- Load a file as input tty -- Enable/Disable ansi output <1> --- Command line options: -b Import builtin modules. can be a list of module names or a glob-pattern. Use the special value 'all' or the pattern '*' to import all modules. -e Evaluate instead of standard-input -i Force REPL operation when all -e occurences have been processed -h, --help, help Show this help menu -m, --modules List all builtin modules --noout Disable printing of expression results -p Print prefix form -t Print tree form <2> -v, --version Show program version >>> ---- <1> Only available for single fraction values <2> Work in progress .REPL examples [source,shell] ---- [user]$ ./dev-expr dev-expr -- Expressions calculator v1.10.0(build 14),2024/06/17 (celestino.amoroso@portale-stac.it) Based on the Expr package v0.19.0 Type help to get the list of available commands See also https://git.portale-stac.it/go-pkg/expr/src/branch/main/README.adoc >>> 2+3 5 >>> 2+3*(4-1.5) 9.5 >>> 0xFD + 0b1 + 0o1 <1> 255 >>> 1:2 + 2:3 <2> 7:6 >>> ml <3> >>> 1:2 + 2:3 7 - 6 >>> 4+2 but 5:2+0.5 <4> 3 >>> 4+2; 5:2+0.5 <5> 3 >>> ---- <1> Number bases: 0x = _hexadecimal_, 0o = _octal_, 0b = _binary_. <2> Fractions: _numerator_ : _denominator_. <3> Activate multi-line output of fractions. <4> But operator, see <<_but_operator>>. <5> Multi-expression: the same result of the previous single expression but this it is obtained with two separated calculations. == Data types _Expr_ has its type system which is a subset of Golang's type system. It supports numerical, string, relational, boolean expressions, and mixed-type lists and maps. === Numbers _Expr_ supports three type of numbers: . [blue]#Integers# . [blue]#Floats# . [blue]#Fractions# In mixed operations involving integers, fractions and floats, automatic type promotion to the largest type is performed. ==== Integers __Expr__'s integers are a subset of the integer set. Internally they are stored as Golang _int64_ values. .Integer literal syntax ==== *_integer_* = [_sign_] _digit-seq_ + _sign_ = "**+**" | "**-**" + _digit-seq_ = _dec-seq_ | _bin-seq_ | _oct-seq_ | _hex-seq_ + _dec-seq_ = {__dec-digit__} + _dec-digit_ = "**0**"|"**1**"|...|"**9**" + _bin-seq_ = "**0b**"{__bin-digit__} + _bin-digit_ = "**0**"|"**1**" + _oct-seq_ = "**0o**"{__oct-digit__} + _oct-digit_ = "**0**"|"**1**"|...|"**7**" + _hex-seq_ = "**0x**"{__hex-digit__} + _hex-digit_ = "**0**"|"**1**"|...|"**9**"|"**a**"|...|"**z**"|"**A**"|...|"**Z**" ==== Value range: *-9223372036854775808* to *9223372036854775807* .Arithmetic operators [cols="^1,^2,6,4"] |=== | Symbol | Operation | Description | Examples | [blue]`+` | _Sum_ | Add two values | [blue]`-1 + 2` -> _1_ | [blue]`-` | _Subtraction_ | Subtract the right value from the left one | [blue]`3 - 1` -> _2_ | [blue]`*` | _Product_ | Multiply two values | [blue]`-1 * 2` -> _-2_ | [blue]`/` | _Integer division_ | Divide the left value by the right one^(*)^ | [blue]`-11 / 2` -> _-5_ | [blue]`%` | _Modulo_ | Remainder of the integer division | [blue]`5 % 2` -> _1_ |=== ^(*)^ See also the _float division_ [blue]`./` below. ==== Floats __Expr__'s floats are a subset of the rational number set. Note that they can't hold the exact value of an unlimited number; floats can only approximate them. Internally floats are stored as Golang's _float64_ values. .Float literal syntax ==== *_float_* = [_sign_] _dec-seq_ "**.**" [_dec-seq_] [("**e**"|"**E**") [_sign_] _dec-seq_] + _sign_ = "**+**" | "**-**" + _dec-seq_ = _see-integer-literal-syntax_ ==== .Examples `>>>` [blue]`1.0` + [green]`1` `>>>` [blue]`0.123` + [green]`0.123` `>>>` [blue]`4.5e+3` + [green]`4500` `>>>` [blue]`4.5E-33` + [green]`4.5e-33` `>>>` [blue]`4.5E-3` + [green]`0.0045` `>>>` [blue]`4.5E10` + [green]`4.5e+10` .Arithmetic operators [cols="^1,^2,6,4"] |=== | Symbol | Operation | Description | Examples | [blue]`+` | _Sum_ | Add two values | [blue]`4 + 0.5` -> 4.5 | [blue]`-` | _Subtraction_ | Subtract the right value from the left one | [blue]`4 - 0.5` -> 3.5 | [blue]`*` | _Product_ | Multiply two values | [blue]`4 * 0.5` -> 2.0 | [blue]`/` | _Float division_ | Divide the left value by the right one | [blue]`1.0 / 2` -> 0.5 | [blue]`./`| _Forced float division_ | Force float division | [blue]`-1 ./ 2` -> -0.5 |=== ==== Fractions _Expr_ also supports fractions. Fraction literals are made with two integers separated by a colon character `:`. .Fraction literal syntax ==== *_fraction_* = [__sign__] (_num-den-spec_ "**:**" _float-spec_) + _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_ ==== .Examples `>>>` [blue]`1 : 2` + [green]`1:2` `>>>` [blue]`4:6` [gray]_// Fractions are always reduced to their lowest terms_ + [green]`2:3` `>>>` [blue]`1:2 + 2:3` + [green]`7:6` `>>>` [blue]`1:2 * 2:3` + [green]`1:3` `>>>` [blue]`1:2 / 1:3` + [green]`3:2` `>>>` [blue]`1:2 ./ 1:3` [gray]_// Force decimal division_ + [green]`1.5` `>>>` [blue]`-1:2` + [green]`-1:2` `>>>` [blue]`1:-2` [gray]_// Invalid sign specification_ + [red]_Eval Error: [1:3] infix operator ":" requires two non-nil operands, got 1_ `>>>` [blue]`1:(-2)` + [green]`-1:2` 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` === Strings Strings are character sequences enclosed between two double quote [blue]`"`. .Examples `>>>` [blue]`"I'm a string"` + [green]`I'm a string` `>>>` [blue]`"123abc?!"` + [green]`123abc?!` `>>>` [blue]`"123\nabc"` + [green]`123` + [green]`abc` `>>>` [blue]`"123\tabc"` + [green]`123{nbsp}{nbsp}{nbsp}{nbsp}abc` Some arithmetic operators also apply to strings. .String operators [cols="^1,^2,6,4"] |=== | Symbol | Operation | Description | Examples | [blue]`+` | _concatenation_ | Join two strings or two _stringable_ values | [blue]`"one" + "two"` -> _"onetwo"_ + [blue]`"one" + 2` -> _"one2"_ | [blue]`*` | _repeat_ | Make _n_ copy of a string | [blue]`"one" * 2` -> _"oneone"_ |=== The charanters in a string can be accessed using the square `[]` operator. .Item access syntax ==== *_item_* = _string-expr_ "**[**" _integer-expr_ "**]**" ==== .Sub-string syntax ==== *_sub-string_* = _string-expr_ "**[**" _integer-expr_ "**:**" _integer-expr_ "**]**" ==== .String examples `>>>` [blue]`s="abcd"` [gray]_// assign the string to variable s_ + [green]`"abcd"` `>>>` [blue]`s[1]` [gray]_// char at position 1 (starting from 0)_ + [green]`"b"` `>>>` [blue]`s[-1]` [gray]_// char at position -1, the rightmost one_ + [green]`"d"` `>>>` [blue]`#s` [gray]_// number of chars_ + [gren]`4` `>>>` [blue]`#"abc"` [gray]_// number of chars_ + [green]`3` `>>>` [blue]`s[1:3]` [gray]_// chars from position 1 to position 3 excluded_ + [grean]`"bc"` === Booleans Boolean data type has two values only: [blue]_true_ and [blue]_false_. Relational and boolean expressions result in boolean values. .Relational operators^(*)^ [cols="^1,^2,6,4"] |=== | Symbol | Operation | Description | Examples | [blue]`==` | _Equal_ | True if the left value is equal to the right one | [blue]`5 == 2` -> _false_ + [blue]`"a" == "a"` -> _true_ | [blue]`!=` | _Not Equal_ | True if the left value is NOT equal to the right one | [blue]`5 != 2` -> _true_ + [blue]`"a" != "a"` -> _false_ | [blue]`<` | _Less_ | True if the left value is less than the right one | [blue]`5 < 2` -> _false_ + [blue]`"a" < "b"` -> _true_ | [blue]`\<=` | _Less or Equal_ | True if the left value is less than or equal to the right one | [blue]`5 \<= 2` -> _false_ + [blue]`"b" \<= "b"` -> _true_ | [blue]`>` | _Greater_ | True if the left value is greater than the right one | [blue]`5 > 2` -> _true_ + [blue]`"a" > "b"` -> _false_ | [blue]`>=` | _Greater or Equal_ | True if the left value is greater than or equal to the right one | [blue]`5 >= 2` -> _true_ + [blue]`"b" >= "b"` -> _true_ |=== ^(*)^ See also the [blue]`in` operator in the _list_ and _dictionary_ sections. .Boolean operators [cols="^2,^2,5,4"] |=== | Symbol | Operation | Description | Examples | [blue]`NOT` | _Not_ | True if the right value is false | [blue]`NOT true` -> _false_ + [blue]`NOT (2 < 1)` -> _true_ | [blue]`AND` / [blue]`&&` | _And_ | True if both left and right values are true | [blue]`false && true` -> _false_ + [blue]`"a" < "b" AND NOT (2 < 1)` -> _true_ | [blue]`OR` / [blue]`\|\|` | _Or_ | True if at least one of the left and right values integers is true| [blue]`false or true` -> _true_ + [blue]`"a" == "b" OR (2 == 1)` -> _false_ |=== [CAUTION] ==== Currently, boolean operations are evaluated using _short cut evaluation_. This means that, if the left expression of the [blue]`and` and [blue]`or` operators is sufficient to establish the result of the whole operation, the right expression would not be evaluated at all. .Example [source,go] ---- 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_. TIP: `dev-expr` provides the _ctrl()_ function that allows to change this behaviour. ==== === Lists _Expr_ supports list of mixed-type values, also specified by normal expressions. Internally, _Expr_'s lists are Go arrays. .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]`+>` | _Front insertion_ | Insert an item in front | [blue]`0 +> [1,2]` -> _[0,1,2]_ | [blue]`<+` | _Back insertion_ | Insert an item at end | [blue]`[1,2] <+ 3` -> _[1,2,3]_ | [blue]`[]` | _Item at index_ | Item at given position | [blue]`[1,2,3][1]` -> _2_ | [blue]`in` | _Item in list_ | True if item is in list | [blue]`2 in [1,2,3]` -> _true_ + [blue]`6 in [1,2,3]` -> _false_ | [blue]`#` | _Size_ | Number of items in a list | [blue]`#[1,2,3]` -> _3_ |=== Array's items can be accessed using the index `[]` operator. .Item access syntax ==== *_item_* = _list-expr_ "**[**" _integer-expr_ "**]**" ==== .Sub-array (or slice of array) syntax ==== *_slice_* = _string-expr_ "**[**" _integer-expr_ "**:**" _integer-expr_ "**]**" ==== .Examples: Getting items from lists `>>>` [blue]`[1,2,3][1]` + [green]`2` `>>>` [blue]`index=2; ["a", "b", "c", "d"][index]` + [green]`c` `>>>` [blue]`["a", "b", "c", "d"][2:]` + [green]`["c", "d"]` `>>>` [blue]`list=[1,2,3]; list[1]` + [green]`2` `>>>` [blue]`["one","two","three"][1]` + [green]`two` `>>>` [blue]`list=["one","two","three"]; list[2-1]` + [green]`two` `>>>` [blue]`list[1]="six"; list` + [green]`["one", "six", "three"]` `>>>` [blue]`list[-1]` + [green]`three` `>>>` [blue]`list[10]` + [red]`Eval Error: [1:9] index 10 out of bounds` .Example: Number of elements in a list `>>>` [blue]`#list` + [green]`3` .Examples: Element insertion `>>>` [blue]`"first" >> list` + [green]`["first", "one", "six", "three"]` `>>>` [blue]`list << "last"` + [green]`["first", "one", "six", "three", "last"]` .Examples: Element in list `>>>` [blue]`"six" in list` + [green]`true` `>>>` [blue]`"ten" in list` + [green]`false` .Examples: Concatenation and filtering `>>>` [blue]`[1,2,3] + ["one", "two", "three"]` + [green]`[1, 2, 3, "one", "two", "three"]` `>>>` [blue]`[1,2,3,4] - [2,4]` + [green]`[1, 3]` === Dictionaries The _dictionary_, or _dict_, data-type represents sets of pairs _key/value_. It is also known as _map_ or _associative array_. Dictionary literals are sequences of pairs separated by comma [blue]`,` enclosed between brace brackets. .Dict literal syntax ==== *_dict_* = _empty-dict_ | _non-empty-dict_ + _empty-dict_ = "**{}**" + _non-empty-dict_ = "**{**" _key-scalar_ "**:**" _any-value_ {"**,**" _key-scalar_ "**:**" _any-value_} "**}**" + ==== .Item access syntax ==== *_item_* = _dict-expr_ "**[**" _key-expr_ "**]**" ==== .Dict operators [cols="^2,^2,4,5"] |=== | Symbol | Operation | Description | Examples | [blue]`+` | _Join_ | Joins two dicts | [blue]`{1:"one"}+{6:"six"}` -> _{1: "one", 6: "six"}_ | [blue]`[]` | _Dict item value_ | Item value of given key | [blue]`{"one":1, "two":2}["two"]` -> _2_ | [blue]`in` | _Key in dict_ | True if key is in dict | [blue]`"one" in {"one":1, "two":2}` -> _true_ + [blue]`"six" in {"one":1, "two":2}` -> _false_ | [blue]`#` | _Size_ | Number of items in a dict | [blue]`#{1:"a",2:"b",3:"c"}` -> _3_ |=== .Examples `>>>` [blue]`{1:"one", 2:"two"}` + [green]`{1: "one", 2: "two"}` `>>>` [blue]`{"one":1, "two": 2}` + [green]`{"one": 1, "two": 2}` `>>>` [blue]`{"sum":1+2+3, "prod":1*2*3}` + [green]`{"sum": 6, "prod": 6}` `>>>` [blue]`{"one":1, "two":2}["two"]` + [green]`2` `>>>` [blue]`d={"one":1, "two":2}; d["six"]=6; d` + [green]`{"two": 2, "one": 1, "six": 6}` `>>>` [blue]`#d` + [green]`3` == Variables _Expr_, like most programming languages, supports variables. A variable is an identifier with an assigned value. Variables are stored in _contexts_. .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]`3` `>>>` [blue]`a_b` + [green]`3` `>>>` [blue]`x = 5.2 * (9-3)` [gray]_// The assigned value here has the typical approximation error of the float data-type_ + [green]`31.200000000000003` `>>>` [blue]`x = 1; y = 2*x` + [green]`2` `>>>` [blue]`\_a=2` + [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 value of the latter is the final result. .Multi-expression syntax ==== *_multi-expression_* = _expression_ {"**;**" _expression_ } ==== An expression that contains [blue]`;` is called a _multi-expression_ and each component expression is called a _sub-expression_. IMPORTANT: Technically [blue]`;` is not treated as a real operator. It acts as a separator in lists of expressions. TIP: [blue]`;` can be used to set some variables before the final calculation. .Example `>>>` [blue]`a=1; b=2; c=3; a+b+c` + [green]`6` The value of each sub-expression is stored in the automatic 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` + [green]`2` `>>>` [blue]`x=2*3 but x-1` + [green]`5`. [blue]`but` behavior is very similar to [blue]`;`. The only difference is that [blue]`;` is not a true operator and can't be used inside parenthesis [blue]`(` and [blue]`)`. === Assignment operator [blue]`=` The assignment operator [blue]`=` is used to define variables or to change their value in the evaluation context (see _ExprContext_). The value on the left side of [blue]`=` must be a variable identifier or an expression that evalutes to a variable. The value on the right side can be any expression and it becomes the result of the assignment operation. .Examples `>>>` [blue]`a=15+1` + [green]`16` `>>>` [blue]`L=[1,2,3]; L[1]=5; L` + [green]`[1, 5, 3]` === Selector operator [blue]`? : ::` The _selector operator_ is very similar to the _switch/case/default_ statement available in many programming languages. .Selector literal Syntax ==== _selector-operator_ = _select-expression_ "*?*" _selector-case_ { "*:*" _selector-case_ } ["*::*" _default-multi-expression_] + _selector-case_ = [_match-list_] _case-value_ + _match-list_ = "*[*" _item_ {"*,*" _items_} "*]*" + _item_ = _expression_ + _case-multi-expression_ = "*{*" _multi-expression_ "*}*" + _multi-expression_ = _expression_ { "*;*" _expression_ } + _default-multi-expression_ = _multi-expression_ ==== In other words, the selector operator evaluates the _select-expression_ on the left-hand side of the [blue]`?` symbol; it then compares the result obtained with the values listed in the __match-list__'s, from left to right. If the comparision finds a match with a value in a _match-list_, the associated _case-multi-expression_ is evaluted, and its result will be the final result of the selection operation. 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 [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 `>>>` [blue]`1 ? {"a"} : {"b"}` + [green]`b` `>>>` [blue]`10 ? {"a"} : {"b"} {2c} {"c"}` + [green]`c` `>>>` [blue]`10 ? {"a"} :[true, 2+8] {"b"} {2c} {"c"}` + [green]`b` `>>>` [blue]`10 ? {"a"} :[true, 2+8] {"b"} {2c} [10] {"c"}` + [red]`Parse Error: [1:34] case list in default clause` `>>>` [blue]`10 ? {"a"} :[10] {x="b" but x} {2c} {"c"}` + [green]`b` `>>>` [blue]`10 ? {"a"} :[10] {x="b"; x} {2c} {"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]`??`, [blue]`?=`, and [blue]`?!` The left operand of first two operators, [blue]`??` and [blue]`?=`, must be a variable. The right operator can be any expression. They return the value of the variable if this is defined; otherwise they return the value of the right expression. IMPORTANT: If the left variable is defined, the right expression is not evaluated at all. The [blue]`??` operator do not change the status of the left variable. The [blue]`?=` assigns the calculated value of the right expression to the left variable. The third one, [blue]`?!`, is the alternate operator. If the variable on the left size is not defined, it returns [blue]_nil_. Otherwise it returns the result of the expressione on the right side. IMPORTANT: If the left variable is NOT defined, the right expression is not evaluated at all. .Examples `>>>` [blue]`var ?? (1+2)` + [green]`3` `>>>` [blue]`var` + [red]`Eval Error: undefined variable or function "var"` `>>>` [blue]`var ?= (1+2)` + [green]`3` `>>>` [blue]`var` + [green]`3` `>>>` [blue]`x ?! 5` + [green]`nil` `>>>` [blue]`x=1; x ?! 5` + [green]`5` `>>>` [blue]`y ?! (c=5); c` + [red]`Eval Error: undefined variable or function "c"` NOTE: These operators have a high priority, in particular higher than the operator [blue]`=`. == Priorities of operators The table below shows all supported operators by decreasing priorities. .Operators priorities [cols="^3,^2,^2,^5,^6"] |=== | Priority | Operators | Position | Operation | Operands and results .2+|*ITEM*| [blue]`[`...`]` | _Postfix_ | _List item_| _list_ `[` _integer_ `]` -> _any_ | [blue]`[`...`]` | _Postfix_ | _Dict item_ | _dict_ `[` _any_ `]` -> _any_ .2+|*INC*| [blue]`++` | _Postfix_ | _Post increment_| _integer-variable_ `++` -> _integer_ | [blue]`++` | _Postfix_ | _Next item_ | _iterator_ `++` -> _any_ .3+|*DEFAULT*| [blue]`??` | _Infix_ | _Default value_| _variable_ `??` _any-expr_ -> _any_ | [blue]`?=` | _Infix_ | _Default/assign value_| _variable_ `?=` _any-expr_ -> _any_ | [blue]`?!` | _Infix_ | _Alternate value_| _variable_ `?!` _any-expr_ -> _any_ //.1+| *ITER*^1^| [blue]`()` | _Prefix_ | _Iterator value_ | `()` _iterator_ -> _any_ .1+|*FACT*| [blue]`!` | _Postfix_ | _Factorial_| _integer_ `!` -> _integer_ .3+|*SIGN*| [blue]`+`, [blue]`-` | _Prefix_ | _Change-sign_| (`+`\|`-`) _number_ -> _number_ | [blue]`#` | _Prefix_ | _Lenght-of_ | `#` _collection_ -> _integer_ | [blue]`#` | _Prefix_ | _Size-of_ | `#` _iterator_ -> _integer_ .2+|*SELECT*| [blue]`? : ::` | _Multi-Infix_ | _Case-Selector_ | _any-expr_ `?` _case-list_ _case-expr_ `:` _case-list_ _case-expr_ ... `::` _default-expr_ -> _any_ | [blue]`? : ::` | _Multi-Infix_ | _Index-Selector_ | _int-expr_ `?` _case-expr_ `:` _case-expr_ ... `::` _default-expr_ -> _any_ .1+|*FRACT*| [blue]`:` | _Infix_ | _Fraction_ | _integer_ `:` _integer_ -> _fraction_ .7+|*PROD*| [blue]`*` | _Infix_ | _Product_ | _number_ `*` _number_ -> _number_ | [blue]`*` | _Infix_ | _String-repeat_ | _string_ `*` _integer_ -> _string_ | [blue]`/` | _Infix_ | _Division_ | _number_ `/` _number_ -> _number_ | [blue]`./` | _Infix_ | _Float-division_ | __number__ `./` _number_ -> _float_ | [blue]`/` | _Infix_ | _Split_ | _string_ `/` _string_ -> _list_ | [blue]`/` | _Infix_ | _Split_ | _string_ `/` integer -> _list_ | [blue]`%` | _Infix_ | _Integer-remainder_ | _integer_ `%` _integer_ -> _integer_ .6+|*SUM*| [blue]`+` | _Infix_ | _Sum_ | _number_ `+` _number_ -> _number_ | [blue]`+` | _Infix_ | _String-concat_ | (_string_\|_number_) `+` (_string_\|_number_) -> _string_ | [blue]`+` | _Infix_ | _List-join_ | _list_ `+` _list_ -> _list_ | [blue]`+` | _Infix_ | _Dict-join_ | _dict_ `+` _dict_ -> _dict_ | [blue]`-` | _Infix_ | _Subtraction_ | _number_ `-` _number_ -> _number_ | [blue]`-` | _Infix_ | _List-difference_ | _list_ `-` _list_ -> _list_ .1+|*BINARY NOT*| [blue]`~` | _Prefix_ | _Binary Not_ | `~` _number_ -> _number_ .1+|*BINARY AND*| [blue]`&` | _Infix_ | _Binary And_ | _number_ `&` _number_ -> _number_ .1+|*BINARY OR*| [blue]`\|` | _Infix_ | _Binary Or_ | _number_ `\|` _number_ -> _number_ .8+|*RELATION*| [blue]`<` | _Infix_ | _Less_ | _comparable_ `<` _comparable_ -> _boolean_ | [blue]`\<=` | _Infix_ | _less-equal_ | _comparable_ `\<=` _comparable_ -> _boolean_ | [blue]`>` | _Infix_ | _Greater_ | _comparable_ `>` _comparable_ -> _boolean_ | [blue]`>=` | _Infix_ | _Greater-equal_ | _comparable_ `>=` _comparable_ -> _boolean_ | [blue]`==` | _Infix_ | _Equal_ | _comparable_ `==` _comparable_ -> _boolean_ | [blue]`!=` | _Infix_ | _Not-equal_ | _comparable_ `!=` _comparable_ -> _boolean_ | [blue]`in` | _Infix_ | _Member-of-list_ | _any_ `in` _list_ -> _boolean_ | [blue]`in` | _Infix_ | _Key-of-dict_ | _any_ `in` _dict_ -> _boolean_ .1+|*LOGIC NOT*| [blue]`not` | _Prefix_ | _Not_ | `not` _boolean_ -> _boolean_ .2+|*LOGIC AND*| [blue]`and` | _Infix_ | _And_ | _boolean_ `and` _boolean_ -> _boolean_ | [blue]`&&` | _Infix_ | _And_ | _boolean_ `&&` _boolean_ -> _boolean_ .2+|*LOGIC OR*| [blue]`or` | _Infix_ | _Or_ | _boolean_ `or` _boolean_ -> _boolean_ | [blue]`\|\|` | _Infix_ | _Or_ | _boolean_ `\|\|` _boolean_ -> _boolean_ .2+|*INSERT*| [blue]`+>` | _Infix_ | _Prepend_ | _any_ `+>` _list_ -> _list_ | [blue]`<+` | _Infix_ | _Append_ | _list_ `<+` _any_ -> _list_ .3+|*ASSIGN*| [blue]`=` | _Infix_ | _Assignment_ | _identifier_ `=` _any_ -> _any_ | [blue]`>>` | _Infix_ | _Front-insert_ | _any_ `>>` _list_ -> _list_ | [blue]`<<` | _Infix_ | _Back-insert_ | _list_ `<<` _any_ -> _list_ .1+|*BUT*| [blue]`but` | _Infix_ | _But_ | _any_ `but` _any_ -> _any_ .1+|*RANGE*| [blue]`:` | _Infix_ | _Index-range_ | _integer_ `:` _integer_ -> _integer-pair_ |=== //^1^ Experimental == Functions Functions in _Expr_ are very similar to functions available in many programming languages. Currently, _Expr_ supports two types of function, _expr-functions_ and _go-functions_. * _expr-functions_ are defined using _Expr_'s syntax. They can be passed as arguments to other functions and can be returned from functions. Moreover, they bind themselves to the defining context, thus becoming closures. * _go-functions_ are regular Golang functions callable from _Expr_ expressions. They are defined in Golang source files called _modules_ and compiled within the _Expr_ package. To make Golang functions available in _Expr_ contextes, it is required to activate the builtin module or to load the plugin module in which they are defined. === _Expr_ function definition A function is identified and referenced by its name. It can have zero or more parameter. _Expr_ functions also support optional parameters and passing paramters by name. .Expr's function definition syntax ==== *_function-definition_* = _identifier_ "**=**" "**func(**" [_formal-param-list_] "**)**" "**{**" _multi-expression_ "**}**" + _formal-param_list_ = _required-param-list_ [ "**,**" _optional-param-list_ ] + _required-param-list_ = _identifier_ { "**,**" _identifier_ } + _optional-param-list_ = _optional-parm_ { "**,**" _optional-param_ } + _optional-param_ = _param-name_ "**=**" _any-expr_ + _param-name_ = _identifier_ ==== .Examples `>>>` [gray]_// A simple function: it takes two parameters and returns their "sum"_**^(*)^** + `>>>` [blue]`sum = func(a, b){ a + b }` + [green]`sum(a, b):any{}` ^(\*)^ Since the plus, *+*, operator is defined for multiple data-types, the _sum()_ function can be used for any pair of that types. `>>>` [gray]_// A more complex example: recursive calculation of the n-th value of Fibonacci's sequence_ + `>>>` [blue]`fib = func(n){ n ? [0] {0}: [1] {1} :: {fib(n-1)+fib(n-2)} }` + [green]`fib(n):any{}` `>>>` [gray]_// Same function fib() but entered by splitting it over mulple text lines_ + `>>>` [blue]`fib = func(n){ \` + `\...` [blue]`{nbsp}{nbsp}n ? \` + `\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}[0] {0} : \` + `\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}[1] {1} :: \` + `\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}{ \` + `\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}{nbsp}{nbsp}fib(n-1) + fib(n-2) \` + `\...` [blue]`{nbsp}{nbsp}{nbsp}{nbsp}} \` + `\...` [blue]`}` + [green]`fib(n):any{}` `>>>` [gray]_// Required and optional parameters_ + `>>>` [blue]`measure = func(value, unit="meter"){ value + " " + unit + (value > 1) ? [true] {"s"} :: {""}}` + [green]`measure(value, unit="meter"):any{}` === _Golang_ function definition Description of how to define Golan functions and how to bind them to _Expr_ are topics treated in another document that I'll write, one day, maybe. === Function calls To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters. .Function invocation syntax ==== *_function-call_* = _identifier_ "**(**" _actual-param-list_ "**)**" + _actual-param-list_ = [_positional-params_] [_named-parameters_] + _positional-params_ = _any-value_ { "*,*" _any-value_ } + _named-params_ = _param-name_ "**=**" _any-value_ { "*,*" _param-name_ "**=**" _any-value_ } + _param-name_ = _identifier_ ==== .Examples of calling the `sum()` functions defined above `>>>` [gray]_// sum of two integers_ + `>>>` [blue]`sum(-6, 2)` + [green]`-4` + `>>>` [gray]_// same as above but passing the parameters by name_ + `>>>` [blue]`sum(a=-6, b=2)` + [green]`-4` + `>>>` [gray]_// again, but swapping parameter positions (see the diff() examples below)_ + `>>>` [blue]`sum(b=2, a=-6)` + [green]`-4` + `>>>` [gray]_// sum of a fraction and an integer_ + `>>>` [blue]`sum(3|2, 2)` + [green]`7|2` + `>>>` [gray]_// sum of two strings_ + `>>>` [blue]`sum("bye", "-bye")` + [green]`"bye-bye"` + `>>>` [gray]_// sum of two lists_ + `>>>` [blue]`sum(["one", 1], ["two", 2])` + [green]`["one", 1, "two", 2]` .Examples of calling a function with parameters passed by name `>>>` [gray]_// diff(a,b) calculates a-b_ + `>>>` [blue]`diff = func(a,b){a-b}` + [green]`diff(a, b):any{}` + `>>>` [gray]_// simple invocation_ + `>>>` [blue]`diff(10,8)` + [green]`2` + `>>>` [gray]_// swapped parameters passed by name_ + `>>>` [blue]`diff(b=8,a=10)` + [green]`2` .Examples of calling the `fib()` function defined above `>>>` [gray]_// Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ..._ + `>>>` [blue]`fib(6)` + [green]`8` + `>>>` [blue]`fib(9)` + [green]`34` .Examples of calling the `measure()` functions defined above `>>>` [gray]_// simple call_ + `>>>` [blue]`measure(10,"litre")` + [green]`"10 litres"` + `>>>` [gray]_// accept the default unit_ + `>>>` [blue]`measure(8)` + [green]`"8 meters"` + `>>>` [gray]_// without the required parameter 'value'_ + `>>>` [blue]`measure(unit="degrees"))` + [red]`Eval Error: measure(): missing params -- value` .Examples of context binding (closures) `>>>` [blue]`factory = func(n=2){ func(x){x*n} }` + [green]`factory(n=2):any{}` + `>>>` [blue]`double = factory()` + [green]`double(x):any{}` + `>>>` [blue]`triple = factory(3)` + [green]`triple(x):any{}` + `>>>` [blue]`double(5)` + [green]`10` + `>>>` [blue]`triple(5)` + [green]`15` === Function context Functions compute values in a local context (scope) that do not make effects on the calling context. This is the normal behavior. Using the _clone_ modifier [blue]`@` it is possibile to export local definition to the calling context. The clone modifier must be used as prefix to variable names and it is part of the name. E.g. [blue]`@x` is not the same as [blue]`x`; they are two different and un related variables. Clone variables are normal local variables. The only diffence will appear when the defining function terminate, just before the destruction of its local context. At that point, all local clone variables are cloned in the calling context with the same names but the [blue]`@` symbol. .Example `>>>` [blue]`f = func() { @x = 3; x = 5 }` [gray]_// f() declares two *different* local variables: ``@x`` and ``x``_ + [green]`f():any{}` + `>>>` [blue]`f()` [gray]_// The multi-expression (two) in f() is calculated and the last result is returned_ + [green]`5` + `>>>` [blue]`x` [gray]_// The `x` variable was not defined in the main context before the f() invocation. It appears in the main context by cloning the `@x` variable, local to f() after its termnation._ + [green]`3` NOTE: The clone modifier [blue]`@` does not make a variable a reference variable, as the ampersand character `&` does in languages such as C and C++. [IMPORTANT] ==== The clone modifier can also be used to declare the formal parameters of functions, because they are local variables too. .Example `>>>` [blue]`g = func(@p) {2+@p}` g(@p):any{}` `>>>` [blue]`g(9)` 11` `>>>` [blue]`p 9 ==== == Iterators #TODO: function calls operations# == Builtins #TODO: builtins# === Builtin functions === [blue]_import()_ [blue]_import([grey]##)_ loads the multi-expression contained in the specified source and returns its value. == Plugins #TODO: plugins#