From 3ba8194ddb74553fa773192ed44997065b47a670 Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Wed, 15 Apr 2026 18:17:27 +0200 Subject: [PATCH] Expr.doc, a lot of fixes --- doc/Expr.adoc | 58 ++++++++++++++++++++++------------------- doc/Expr.html | 72 ++++++++++++++++++++++++++++----------------------- 2 files changed, 70 insertions(+), 60 deletions(-) diff --git a/doc/Expr.adoc b/doc/Expr.adoc index 282856e..0962bd9 100644 --- a/doc/Expr.adoc +++ b/doc/Expr.adoc @@ -20,15 +20,15 @@ Expressions calculator :rouge-style: gruvbox // :rouge-style: colorful //:rouge-style: monokay -// Work around to manage double-column in back-tick quotes +// Workaround to manage double-column in back-tick quotes :2c: :: toc::[] -#TODO: Work in progress (last update on 2024/06/21, 05:40 a.m.)# +#TODO: Work in progress (last update on 2026/04/15, 6:02 p.m.)# == Expr -_Expr_ is a GO package capable of analysing, interpreting and calculating expressions. +_Expr_ is a GO package that can analyze, interpret and calculate expressions. === Concepts and terminology @@ -42,7 +42,7 @@ Expressions are texts containing sequences of operations represented by a syntax 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. +_Expr_ supports variables. The result of an expression can be stored in a variable and reused in other espressions by simply specifying the name of the variable as an operand. ==== 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_. @@ -58,9 +58,9 @@ The expression context is analogous to the stack-frame of other programming lang Function contexts are created by cloning the calling context. More details on this topic are given later in this document. -_Expr_ creates and keeps a inner _global context_ where it stores imported functions, either from builtin or plugin modules. To perform calculations, the 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_. +_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 earlier, when a function is called, a new context is created by cloning the calling context. The created context can be called _function context_. -Imported functions are registerd in the _global context_. When an expression first calls an imported function, that function is linked to the current context; this can be the _main context_ or a _function context_. +Imported functions are registered 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. @@ -145,7 +145,7 @@ dev-expr -- Expressions calculator v1.10.0(build 14),2024/06/17 (celestino.amoro <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. +<5> Multi-expression: the same result as the previous single expression, but this time it is obtained with two separate 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. @@ -240,10 +240,11 @@ _Expr_ also supports fractions. Fraction literals are made with two integers sep .Fraction literal syntax ==== -*_fraction_* = [__sign__] (_num-den-spec_ "**:**" _float-spec_) + +*_fraction_* = [__sign__] (_num-den-spec_ | _float-spec_) + _sign_ = "**+**" | "**-**" + -_num-den-spec_ = _digit-seq_ "**|**" _digit-seq_ + -_float-spec_ = _dec-seq_ "**.**" [_dec-seq_] "**(**" _dec-seq_ "**)**" + +_num-den-spec_ = _digit-seq_ "**:**" _digit-seq_ + +_float-spec_ = _dec-seq_ "**.**" [_dec-seq_] "**(**" _repetend_ "**)**" + +_repetend_ = _dec-seq_ + _dec-seq_ = _see-integer-literal-syntax_ + _digit-seq_ = _see-integer-literal-syntax_ ==== @@ -276,6 +277,8 @@ _digit-seq_ = _see-integer-literal-syntax_ `>>>` [blue]`1:(-2)` + [green]`-1:2` +`>>>` [blue]`1.(3)` // 1.33333... + +[green]`4:3` Fractions can be used together with integers and floats in expressions. @@ -395,12 +398,13 @@ Boolean data type has two values only: [blue]_true_ and [blue]_false_. Relationa [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_. +<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. @@ -492,10 +496,10 @@ Array's items can be accessed using the index `[]` operator. [green]`3` .Examples: Element insertion -`>>>` [blue]`"first" >> list` + +`>>>` [blue]`"first" +> list` + [green]`["first", "one", "six", "three"]` -`>>>` [blue]`list << "last"` + +`>>>` [blue]`list <+ "last"` + [green]`["first", "one", "six", "three", "last"]` .Examples: Element in list @@ -509,7 +513,7 @@ Array's items can be accessed using the index `[]` operator. `>>>` [blue]`[1,2,3] + ["one", "two", "three"]` + [green]`[1, 2, 3, "one", "two", "three"]` -`>>>` [blue]`[1,2,3,4] - [2,4]` + +`>>>` [blue]`[1,2,3,2,4] - [2,4]` + [green]`[1, 3]` @@ -570,7 +574,7 @@ _Expr_, like most programming languages, supports variables. A variable is an id .Variable literal syntax ==== *_variable_* = _identifier_ "*=*" _any-value_ + -_identifier_ = _alpha_ {(_alpha_)|_dec-digit_|"*_*"} + +_identifier_ = _alpha_ {_alpha_|_dec-digit_|"*_*"} + __alpha__ = "*a*"|"*b*"|..."*z*"|"*A*"|"*B*"|..."*Z*" ==== @@ -695,7 +699,7 @@ The [blue]`:` symbol (colon) is the separator of the selector-cases. Note that i === 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. +The left operand of the 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. @@ -841,12 +845,12 @@ Functions in _Expr_ are very similar to functions available in many programming === _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. +An expr-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_ ] + +_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_ + @@ -858,7 +862,7 @@ _param-name_ = _identifier_ `>>>` [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. +^(*)^ 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)} }` + @@ -959,9 +963,9 @@ _param-name_ = _identifier_ === 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. +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 unrelated 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. +Clone variables are normal local variables. The only diffence will appear when the defining function ends, 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``_ + @@ -978,12 +982,12 @@ NOTE: The clone modifier [blue]`@` does not make a variable a reference variable 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 +`>>>` [blue]`g = func(@p) {2+@p}` + +[green]`g(@p):any{}` + +`>>>` [blue]`g(9)` + +[green]`11` + +`>>>` [blue]`p` + +[green]`9` ==== == Iterators diff --git a/doc/Expr.html b/doc/Expr.html index dffa60c..3269649 100644 --- a/doc/Expr.html +++ b/doc/Expr.html @@ -4,7 +4,7 @@ - + Expr @@ -117,7 +117,6 @@ h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title str :not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed} pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed} pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit} -pre>code{display:block} pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal} em em{font-style:normal} strong strong{font-weight:400} @@ -141,7 +140,7 @@ p a>code:hover{color:rgba(0,0,0,.9)} #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} -#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} +#header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} @@ -163,6 +162,7 @@ p a>code:hover{color:rgba(0,0,0,.9)} #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} +body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} @@ -219,6 +219,7 @@ table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} .literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8} .literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)} .listingblock>.content{position:relative} +.listingblock pre>code{display:block} .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5} .listingblock:hover code[data-lang]::before{display:block} .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5} @@ -328,7 +329,7 @@ a.image{text-decoration:none;display:inline-block} a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} -sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} +sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} @@ -605,7 +606,7 @@ pre.rouge .ss {
-

TODO: Work in progress (last update on 2024/06/21, 05:40 a.m.)

+

TODO: Work in progress (last update on 2026/04/15, 6:02 p.m.)

@@ -613,7 +614,7 @@ pre.rouge .ss {

1. Expr

-

Expr is a GO package capable of analysing, interpreting and calculating expressions.

+

Expr is a GO package that can analyze, interpret and calculate expressions.

1.1. Concepts and terminology

@@ -641,7 +642,7 @@ pre.rouge .ss {

1.1.1. 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.

+

Expr supports variables. The result of an expression can be stored in a variable and reused in other espressions by simply specifying the name of the variable as an operand.

@@ -668,10 +669,10 @@ pre.rouge .ss {

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.

+

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 earlier, when a function is called, a new context is created by cloning the calling context. The created context can be called function context.

-

Imported functions are registerd in the global context. When an expression first calls an imported function, that function is linked to the current context; this can be the main context or a function context.

+

Imported functions are registered 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.

@@ -789,7 +790,7 @@ dev-expr -- Expressions calculator v1.10.05 -Multi-expression: the same result of the previous single expression but this it is obtained with two separated calculations. +Multi-expression: the same result as the previous single expression, but this time it is obtained with two separate calculations. @@ -997,10 +998,11 @@ dev-expr -- Expressions calculator v1.10.0Example 3. Fraction literal syntax
-

fraction = [sign] (num-den-spec ":" float-spec)
+

fraction = [sign] (num-den-spec | float-spec)
sign = "+" | "-"
-num-den-spec = digit-seq "|" digit-seq
-float-spec = dec-seq "." [dec-seq] "(" dec-seq ")"
+num-den-spec = digit-seq ":" digit-seq
+float-spec = dec-seq "." [dec-seq] "(" repetend ")"
+repetend = dec-seq
dec-seq = see-integer-literal-syntax
digit-seq = see-integer-literal-syntax

@@ -1044,6 +1046,10 @@ dev-expr -- Expressions calculator v1.10.0-1:2

+

>>> 1.(3) // 1.33333…​
+4:3

+
+

Fractions can be used together with integers and floats in expressions.

@@ -1281,10 +1287,10 @@ dev-expr -- Expressions calculator v1.10.0
-

Currently, boolean operations are evaluated using short cut evaluation. This means that, if the left expression of the and and or operators is sufficient to establish the result of the whole operation, the right expression would not be evaluated at all. -.Example

+

Currently, boolean operations are evaluated using short cut evaluation. This means that, if the left expression of the and and or operators is sufficient to establish the result of the whole operation, the right expression would not be evaluated at all.

+
Example
2 > (a=1) or (a=8) > 0; a (1)
@@ -1293,7 +1299,7 @@ dev-expr -- Expressions calculator v1.10.01 -This multi-expression returns 1 because in the first expression the left value of or is true and as a conseguence its right value is not computed. Therefore the a variable only receives the integer 1. +This multi-expression returns 1 because in the first expression the left value of or is true and, as a conseguence, its right value is not computed. Therefore the a variable only receives the integer 1.
@@ -1475,11 +1481,11 @@ dev-expr -- Expressions calculator v1.10.0
Examples: Element insertion
-

>>> "first" >> list
+

>>> "first" +> list
["first", "one", "six", "three"]

-

>>> list << "last"
+

>>> list <+ "last"
["first", "one", "six", "three", "last"]

@@ -1497,7 +1503,7 @@ dev-expr -- Expressions calculator v1.10.0[1, 2, 3, "one", "two", "three"]

-

>>> [1,2,3,4] - [2,4]
+

>>> [1,2,3,2,4] - [2,4]
[1, 3]

@@ -1610,7 +1616,7 @@ dev-expr -- Expressions calculator v1.10.0

variable = identifier "=" any-value
-identifier = alpha {(alpha)|dec-digit|"_"}
+identifier = alpha {alpha|dec-digit|"_"}
alpha = "a"|"b"|…​"z"|"A"|"B"|…​"Z"

@@ -1812,7 +1818,7 @@ Technically ; is not treated as a real operator. It ac

4.5. Variable default value ??, ?=, and ?!

-

The left operand of first two operators, ?? and ?=, 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.

+

The left operand of the first two operators, ?? and ?=, 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.

@@ -2370,14 +2376,14 @@ short for

6.1. 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.

+

An expr-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.

Example 14. Expr’s function definition syntax

function-definition = identifier "=" "func(" [formal-param-list] ")" "{" multi-expression "}"
-formal-param_list = required-param-list [ "," optional-param-list ]
+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
@@ -2392,7 +2398,7 @@ short for
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.

+

(*) Since the plus, +, operator is defined for multiple data-types, the sum() function can be used for any pair of that types.

>>> // A more complex example: recursive calculation of the n-th value of Fibonacci’s sequence
@@ -2510,10 +2516,10 @@ short for

6.4. 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 @ 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. @x is not the same as x; they are two different and un related variables.

+

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 @ 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. @x is not the same as x; they are two different and unrelated 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 @ symbol.

+

Clone variables are normal local variables. The only diffence will appear when the defining function ends, 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 @ symbol.

Example
@@ -2548,12 +2554,12 @@ The clone modifier @ does not make a variable a refere
Example
-

>>> g = func(@p) {2+@p} -g(@p):any{}` ->>> g(9) -11` ->>> [blue]`p -9

+

>>> g = func(@p) {2+@p}
+g(@p):any{}
+>>> g(9)
+11
+>>> p
+9

@@ -2599,7 +2605,7 @@ g(@p):any{}`