Compare commits
8 Commits
c9db4b84e3
...
ca89931ca9
Author | SHA1 | Date | |
---|---|---|---|
ca89931ca9 | |||
d2e8aed4f7 | |||
8138cd2a80 | |||
6786666cf4 | |||
35e794701a | |||
52ef134be6 | |||
624318d84e | |||
aa1338cd51 |
@ -8,6 +8,20 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func errTooFewParams(minArgs, maxArgs, argCount int) (err error) {
|
||||
if maxArgs < 0 {
|
||||
err = fmt.Errorf("too few params -- expected %d or more, got %d", minArgs, argCount)
|
||||
} else {
|
||||
err = fmt.Errorf("too few params -- expected %d, got %d", minArgs, argCount)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func errTooMuchParams(maxArgs, argCount int) (err error) {
|
||||
err = fmt.Errorf("too much params -- expected %d, got %d", maxArgs, argCount)
|
||||
return
|
||||
}
|
||||
|
||||
// --- General errors
|
||||
|
||||
func errCantConvert(funcName string, value any, kind string) error {
|
||||
@ -24,9 +38,9 @@ func errDivisionByZero(funcName string) error {
|
||||
|
||||
// --- Parameter errors
|
||||
|
||||
func errOneParam(funcName string) error {
|
||||
return fmt.Errorf("%s() requires exactly one param", funcName)
|
||||
}
|
||||
// func errOneParam(funcName string) error {
|
||||
// return fmt.Errorf("%s() requires exactly one param", funcName)
|
||||
// }
|
||||
|
||||
func errMissingRequiredParameter(funcName, paramName string) error {
|
||||
return fmt.Errorf("%s() missing required parameter %q", funcName, paramName)
|
||||
|
@ -22,7 +22,7 @@ Expressions calculator
|
||||
|
||||
toc::[]
|
||||
|
||||
#TODO: Work in progress (last update on 2024/05/10, 06:52 a.m.)#
|
||||
#TODO: Work in progress (last update on 2024/05/15, 10:00 p.m.)#
|
||||
|
||||
== Expr
|
||||
_Expr_ is a GO package capable of analysing, interpreting and calculating expressions.
|
||||
@ -113,37 +113,84 @@ Here are some examples of execution.
|
||||
_Expr_ supports numerical, string, relational, boolean expressions, and mixed-type lists.
|
||||
|
||||
=== Numbers
|
||||
Numbers can be integers (GO int64) or float (GO float64). In mixed operations involving integers and floats, integers are automatically promoted to floats.
|
||||
_Expr_ supports three type of numbers:
|
||||
|
||||
. [blue]#Integers#
|
||||
. [blue]#Floats#
|
||||
. [blue]#Factions# internally are stored as _pairs of_ Golang _int64_ values.
|
||||
|
||||
In mixed operations involving integers, fractions and floats, automatic type promotion to the largest type take place.
|
||||
|
||||
==== 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]`+` / [blue]`-` | _change sign_ | Change the sign of values | [blue]`-1` _[-1]_ +
|
||||
[blue]`-(+2)` _[-2]_
|
||||
|
||||
| [blue]`+` | _sum_ | Add two values | [blue]`-1 + 2` _[1]_ +
|
||||
[blue]`4 + 0.5` _[4.5]_
|
||||
|
||||
| [blue]`-` | _subtraction_ | Subtract the right value from the left one | [blue]`3 - 1` _[2]_ +
|
||||
[blue]`4 - 0.5` _[3.5]_
|
||||
|
||||
| [blue]`*` | _product_ | Multiply two values | `-1 * 2` _[-2]_ +
|
||||
[blue]`4 * 0.5` _[2.0]_
|
||||
|
||||
| [blue]`/` | _Division_ | Divide the left value by the right one | [blue]`-1 / 2` _[0]_ +
|
||||
[blue]`1.0 / 2` _[0.5]_
|
||||
|
||||
| [blue]`./` | _Float division_ | Force float division | [blue]`-1 ./ 2` _[-0.5]_
|
||||
|
||||
| [blue]`%` | _Modulo_ | Remainder of the integer division | [blue]`5 % 2` _[1]_
|
||||
|
||||
| [blue]`+` | _sum_ | Add two values | [blue]`-1 + 2` -> 1
|
||||
| [blue]`-` | _subtraction_ | Subtract the right value from the left one | [blue]`3 - 1` -> 2
|
||||
| [blue]`*` | _product_ | Multiply two values | [blue]`-1 * 2` -> -2
|
||||
| [blue]`/` | _Division_ | Divide the left value by the right one^(*)^ | [blue]`-10 / 2` -> 5
|
||||
| [blue]`%` | _Modulo_ | Remainder of the integer division | [blue]`5 % 2` -> 1
|
||||
|===
|
||||
|
||||
=== Fractions
|
||||
^(*)^ 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_
|
||||
====
|
||||
|
||||
|
||||
.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]`/` | _Division_ | Divide the left value by the right one | [blue]`1.0 / 2` -> 0.5
|
||||
| [blue]`./`| _Float division_ | Force float division | [blue]`-1 ./ 2` -> -0.5
|
||||
|===
|
||||
|
||||
==== Fractions
|
||||
_Expr_ also supports fractions. Fraction literals are made with two integers separated by a vertical bar `|`.
|
||||
|
||||
.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
|
||||
// [source,go]
|
||||
// ----
|
||||
|
202
doc/Expr.html
202
doc/Expr.html
@ -541,11 +541,16 @@ pre.rouge .ss {
|
||||
</li>
|
||||
<li><a href="#_data_types">2. Data types</a>
|
||||
<ul class="sectlevel2">
|
||||
<li><a href="#_numbers">2.1. Numbers</a></li>
|
||||
<li><a href="#_fractions">2.2. Fractions</a></li>
|
||||
<li><a href="#_strings">2.3. Strings</a></li>
|
||||
<li><a href="#_boolean">2.4. Boolean</a></li>
|
||||
<li><a href="#_lists">2.5. Lists</a></li>
|
||||
<li><a href="#_numbers">2.1. Numbers</a>
|
||||
<ul class="sectlevel3">
|
||||
<li><a href="#_integers">2.1.1. Integers</a></li>
|
||||
<li><a href="#_floats">2.1.2. Floats</a></li>
|
||||
<li><a href="#_fractions">2.1.3. Fractions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#_strings">2.2. Strings</a></li>
|
||||
<li><a href="#_boolean">2.3. Boolean</a></li>
|
||||
<li><a href="#_lists">2.4. Lists</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#_dictionaries">3. Dictionaries</a></li>
|
||||
@ -579,7 +584,7 @@ pre.rouge .ss {
|
||||
<div class="sectionbody">
|
||||
<!-- toc disabled -->
|
||||
<div class="paragraph">
|
||||
<p><mark>TODO: Work in progress (last update on 2024/05/10, 06:52 a.m.)</mark></p>
|
||||
<p><mark>TODO: Work in progress (last update on 2024/05/15, 10:00 p.m.)</mark></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -721,7 +726,49 @@ pre.rouge .ss {
|
||||
<div class="sect2">
|
||||
<h3 id="_numbers"><a class="anchor" href="#_numbers"></a><a class="link" href="#_numbers">2.1. Numbers</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>Numbers can be integers (GO int64) or float (GO float64). In mixed operations involving integers and floats, integers are automatically promoted to floats.</p>
|
||||
<p><em>Expr</em> supports three type of numbers:</p>
|
||||
</div>
|
||||
<div class="olist arabic">
|
||||
<ol class="arabic">
|
||||
<li>
|
||||
<p><span class="blue">Integers</span></p>
|
||||
</li>
|
||||
<li>
|
||||
<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>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>In mixed operations involving integers, fractions and floats, automatic type promotion to the largest type take place.</p>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_integers"><a class="anchor" href="#_integers"></a><a class="link" href="#_integers">2.1.1. Integers</a></h4>
|
||||
<div class="paragraph">
|
||||
<p><em>Expr</em>'s integers are a subset of the integer set. Internally they are stored as Golang <em>int64</em> values.</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="title">Example 1. Integer literal syntax</div>
|
||||
<div class="content">
|
||||
<div class="paragraph">
|
||||
<p><strong><em>integer</em></strong> = [<em>sign</em>] <em>digit-seq</em><br>
|
||||
<em>sign</em> = "<strong>+</strong>" | "<strong>-</strong>"<br>
|
||||
<em>digit-seq</em> = <em>dec-seq</em> | <em>bin-seq</em> | <em>oct-seq</em> | <em>hex-seq</em><br>
|
||||
<em>dec-seq</em> = {<em>dec-digit</em>}<br>
|
||||
<em>dec-digit</em> = "<strong>0</strong>"|"<strong>1</strong>"|…​|"<strong>9</strong>"<br>
|
||||
<em>bin-seq</em> = "<strong>0b</strong>"{<em>bin-digit</em>}<br>
|
||||
<em>bin-digit</em> = "<strong>0</strong>"|"<strong>1</strong>"<br>
|
||||
<em>oct-seq</em> = "<strong>0o</strong>"{<em>oct-digit</em>}<br>
|
||||
<em>oct-digit</em> = "<strong>0</strong>"|"<strong>1</strong>"|…​|"<strong>7</strong>"<br>
|
||||
<em>hex-seq</em> = "<strong>0x</strong>"{<em>hex-digit</em>}<br>
|
||||
<em>hex-digit</em> = "<strong>0</strong>"|"<strong>1</strong>"|…​|"<strong>9</strong>"|"<strong>a</strong>"|…​|"<strong>z</strong>"|"<strong>A</strong>"|…​|"<strong>Z</strong>"</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Value range: <strong>-9223372036854775808</strong> to <strong>9223372036854775807</strong></p>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all stretch">
|
||||
<caption class="title">Table 1. Arithmetic operators</caption>
|
||||
@ -731,70 +778,130 @@ pre.rouge .ss {
|
||||
<col style="width: 46.1538%;">
|
||||
<col style="width: 30.7693%;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tableblock halign-center valign-top">Symbol</th>
|
||||
<th class="tableblock halign-center valign-top">Operation</th>
|
||||
<th class="tableblock halign-left valign-top">Description</th>
|
||||
<th class="tableblock halign-left valign-top">Examples</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">+</code> / <code class="blue">-</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>change sign</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Change the sign of values</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1</code> <em>[-1]</em><br>
|
||||
<code class="blue">-(+2)</code> <em>[-2]</em></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock">Symbol</p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock">Operation</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Description</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Examples</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>sum</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Add two values</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 + 2</code> <em>[1]</em><br>
|
||||
<code class="blue">4 + 0.5</code> <em>[4.5]</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 + 2</code> → 1</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">-</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>subtraction</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Subtract the right value from the left one</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">3 - 1</code> <em>[2]</em><br>
|
||||
<code class="blue">4 - 0.5</code> <em>[3.5]</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">3 - 1</code> → 2</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">*</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>product</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Multiply two values</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>-1 * 2</code> <em>[-2]</em><br>
|
||||
<code class="blue">4 * 0.5</code> <em>[2.0]</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 * 2</code> → -2</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">/</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Division</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Divide the left value by the right one</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 / 2</code> <em>[0]</em><br>
|
||||
<code class="blue">1.0 / 2</code> <em>[0.5]</em></p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">./</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Float division</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Force float division</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 ./ 2</code> <em>[-0.5]</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Divide the left value by the right one<sup>(*)</sup></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-10 / 2</code> → 5</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">%</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Modulo</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Remainder of the integer division</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">5 % 2</code> <em>[1]</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">5 % 2</code> → 1</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="paragraph">
|
||||
<p><sup>(*)</sup> See also the <em>float division</em> <code class="blue">./</code> below.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="_floats"><a class="anchor" href="#_floats"></a><a class="link" href="#_floats">2.1.2. Floats</a></h4>
|
||||
<div class="paragraph">
|
||||
<p><em>Expr</em>'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 <em>float64</em> values.</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="title">Example 2. Float literal syntax</div>
|
||||
<div class="content">
|
||||
<div class="paragraph">
|
||||
<p><strong><em>float</em></strong> = [<em>sign</em>] <em>dec-seq</em> "<strong>.</strong>" [<em>dec-seq</em>] [("<strong>e</strong>"|"<strong>E</strong>") [<em>sign</em>] <em>dec-seq</em>]<br>
|
||||
<em>sign</em> = "<strong>+</strong>" | "<strong>-</strong>"<br>
|
||||
<em>dec-seq</em> = <em>see-integer-literal-syntax</em></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all stretch">
|
||||
<caption class="title">Table 2. Arithmetic operators</caption>
|
||||
<colgroup>
|
||||
<col style="width: 7.6923%;">
|
||||
<col style="width: 15.3846%;">
|
||||
<col style="width: 46.1538%;">
|
||||
<col style="width: 30.7693%;">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock">Symbol</p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock">Operation</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Description</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Examples</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>sum</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Add two values</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">4 + 0.5</code> → 4.5</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">-</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>subtraction</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Subtract the right value from the left one</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">4 - 0.5</code> → 3.5</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">*</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>product</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Multiply two values</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">4 * 0.5</code> → 2.0</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">/</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Division</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Divide the left value by the right one</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">1.0 / 2</code> → 0.5</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">./</code></p></td>
|
||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Float division</em></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Force float division</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">-1 ./ 2</code> → -0.5</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_fractions"><a class="anchor" href="#_fractions"></a><a class="link" href="#_fractions">2.2. Fractions</a></h3>
|
||||
<div class="sect3">
|
||||
<h4 id="_fractions"><a class="anchor" href="#_fractions"></a><a class="link" href="#_fractions">2.1.3. Fractions</a></h4>
|
||||
<div class="paragraph">
|
||||
<p><em>Expr</em> also supports fractions. Fraction literals are made with two integers separated by a vertical bar <code>|</code>.</p>
|
||||
</div>
|
||||
<div class="exampleblock">
|
||||
<div class="title">Example 3. Fraction literal syntax</div>
|
||||
<div class="content">
|
||||
<div class="paragraph">
|
||||
<p><strong><em>fraction</em></strong> = [<em>sign</em>] (<em>num-den-spec</em> | <em>float-spec</em>)<br>
|
||||
<em>sign</em> = "<strong>+</strong>" | "<strong>-</strong>"<br>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<div class="title">Examples</div>
|
||||
<p><code>>>></code> <code class="blue">1 | 2</code><br>
|
||||
@ -828,8 +935,9 @@ pre.rouge .ss {
|
||||
<code class="green">1.5</code><br></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_strings"><a class="anchor" href="#_strings"></a><a class="link" href="#_strings">2.3. Strings</a></h3>
|
||||
<h3 id="_strings"><a class="anchor" href="#_strings"></a><a class="link" href="#_strings">2.2. Strings</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>Strings are character sequences enclosed between two double quote <code class="blue">"</code>. Example: <code class="blue">"I’m a string"</code>.</p>
|
||||
</div>
|
||||
@ -837,7 +945,7 @@ pre.rouge .ss {
|
||||
<p>Some arithmetic operators can also be used with strings.</p>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all stretch">
|
||||
<caption class="title">Table 2. String operators</caption>
|
||||
<caption class="title">Table 3. String operators</caption>
|
||||
<colgroup>
|
||||
<col style="width: 7.6923%;">
|
||||
<col style="width: 15.3846%;">
|
||||
@ -892,12 +1000,12 @@ pre.rouge .ss {
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_boolean"><a class="anchor" href="#_boolean"></a><a class="link" href="#_boolean">2.4. Boolean</a></h3>
|
||||
<h3 id="_boolean"><a class="anchor" href="#_boolean"></a><a class="link" href="#_boolean">2.3. Boolean</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>Boolean data type has two values only: <em>true</em> and <em>false</em>. Relational and Boolean expressions produce Boolean values.</p>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all stretch">
|
||||
<caption class="title">Table 3. Relational operators</caption>
|
||||
<caption class="title">Table 4. Relational operators</caption>
|
||||
<colgroup>
|
||||
<col style="width: 7.6923%;">
|
||||
<col style="width: 15.3846%;">
|
||||
@ -958,7 +1066,7 @@ pre.rouge .ss {
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="tableblock frame-all grid-all stretch">
|
||||
<caption class="title">Table 4. Boolean operators</caption>
|
||||
<caption class="title">Table 5. Boolean operators</caption>
|
||||
<colgroup>
|
||||
<col style="width: 15.3846%;">
|
||||
<col style="width: 15.3846%;">
|
||||
@ -1027,7 +1135,7 @@ pre.rouge .ss {
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_lists"><a class="anchor" href="#_lists"></a><a class="link" href="#_lists">2.5. Lists</a></h3>
|
||||
<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>
|
||||
</div>
|
||||
@ -1042,7 +1150,7 @@ pre.rouge .ss {
|
||||
</div>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all stretch">
|
||||
<caption class="title">Table 5. List operators</caption>
|
||||
<caption class="title">Table 6. List operators</caption>
|
||||
<colgroup>
|
||||
<col style="width: 15.3846%;">
|
||||
<col style="width: 15.3846%;">
|
||||
@ -1261,7 +1369,7 @@ The value on the left side of <code class="blue">=</code> must be an identifier.
|
||||
<p>The table below shows all supported operators by decreasing priorities.</p>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all stretch">
|
||||
<caption class="title">Table 6. Operators priorities</caption>
|
||||
<caption class="title">Table 7. Operators priorities</caption>
|
||||
<colgroup>
|
||||
<col style="width: 12.5%;">
|
||||
<col style="width: 12.5%;">
|
||||
@ -1519,7 +1627,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-11 20:13:17 +0200
|
||||
Last updated 2024-05-15 22:00:00 +0200
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -10,11 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func isNilFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
if len(args) == 1 {
|
||||
result = args[0] == nil
|
||||
} else {
|
||||
err = errOneParam(name)
|
||||
}
|
||||
result = args[0] == nil
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,9 @@ func doJoinStr(funcName string, sep string, it Iterator) (result any, err error)
|
||||
}
|
||||
|
||||
func joinStrFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
if len(args) < 1 {
|
||||
return nil, errMissingRequiredParameter(name, paramSeparator)
|
||||
}
|
||||
// if len(args) < 1 {
|
||||
// return nil, errMissingRequiredParameter(name, paramSeparator)
|
||||
// }
|
||||
if sep, ok := args[0].(string); ok {
|
||||
if len(args) == 1 {
|
||||
result = ""
|
||||
@ -62,9 +62,9 @@ func subStrFunc(ctx ExprContext, name string, args []any) (result any, err error
|
||||
var source string
|
||||
var ok bool
|
||||
|
||||
if len(args) < 1 {
|
||||
return nil, errMissingRequiredParameter(name, paramSource)
|
||||
}
|
||||
// if len(args) < 1 {
|
||||
// return nil, errMissingRequiredParameter(name, paramSource)
|
||||
// }
|
||||
if source, ok = args[0].(string); !ok {
|
||||
return nil, errWrongParamType(name, paramSource, typeString, args[0])
|
||||
}
|
||||
@ -93,9 +93,9 @@ func trimStrFunc(ctx ExprContext, name string, args []any) (result any, err erro
|
||||
var source string
|
||||
var ok bool
|
||||
|
||||
if len(args) < 1 {
|
||||
return nil, errMissingRequiredParameter(name, paramSource)
|
||||
}
|
||||
// if len(args) < 1 {
|
||||
// return nil, errMissingRequiredParameter(name, paramSource)
|
||||
// }
|
||||
if source, ok = args[0].(string); !ok {
|
||||
return nil, errWrongParamType(name, paramSource, typeString, args[0])
|
||||
}
|
||||
@ -108,9 +108,9 @@ func startsWithStrFunc(ctx ExprContext, name string, args []any) (result any, er
|
||||
var ok bool
|
||||
|
||||
result = false
|
||||
if len(args) < 1 {
|
||||
return result, errMissingRequiredParameter(name, paramSource)
|
||||
}
|
||||
// if len(args) < 1 {
|
||||
// return result, errMissingRequiredParameter(name, paramSource)
|
||||
// }
|
||||
if source, ok = args[0].(string); !ok {
|
||||
return result, errWrongParamType(name, paramSource, typeString, args[0])
|
||||
}
|
||||
@ -133,9 +133,9 @@ func endsWithStrFunc(ctx ExprContext, name string, args []any) (result any, err
|
||||
var ok bool
|
||||
|
||||
result = false
|
||||
if len(args) < 1 {
|
||||
return result, errMissingRequiredParameter(name, paramSource)
|
||||
}
|
||||
// if len(args) < 1 {
|
||||
// return result, errMissingRequiredParameter(name, paramSource)
|
||||
// }
|
||||
if source, ok = args[0].(string); !ok {
|
||||
return result, errWrongParamType(name, paramSource, typeString, args[0])
|
||||
}
|
||||
@ -159,9 +159,9 @@ func splitStrFunc(ctx ExprContext, name string, args []any) (result any, err err
|
||||
var parts []string
|
||||
var ok bool
|
||||
|
||||
if len(args) < 1 {
|
||||
return result, errMissingRequiredParameter(name, paramSource)
|
||||
}
|
||||
// if len(args) < 1 {
|
||||
// return result, errMissingRequiredParameter(name, paramSource)
|
||||
// }
|
||||
if source, ok = args[0].(string); !ok {
|
||||
return result, errWrongParamType(name, paramSource, typeString, args[0])
|
||||
}
|
||||
|
@ -76,6 +76,9 @@ func TestFuncs(t *testing.T) {
|
||||
/* 63 */ {`dec(true)`, float64(1), nil},
|
||||
/* 64 */ {`dec(true")`, nil, errors.New("[1:11] missing string termination \"")},
|
||||
/* 65 */ {`builtin "string"; joinStr("-", [1, "two", "three"])`, nil, errors.New(`joinStr() expected string, got int64 (1)`)},
|
||||
/* 65 */ {`dec()`, nil, errors.New(`too few params -- expected 1, got 0`)},
|
||||
/* 66 */ {`dec(1,2,3)`, nil, errors.New(`too much params -- expected 1, got 3`)},
|
||||
/* 67 */ {`builtin "string"; joinStr()`, nil, errors.New(`too few params -- expected 1 or more, got 0`)},
|
||||
// /* 64 */ {`string(true)`, "true", nil},
|
||||
}
|
||||
|
||||
|
@ -25,14 +25,10 @@ func newFuncCallTerm(tk *Token, args []*term) *term {
|
||||
func checkFunctionCall(ctx ExprContext, name string, params []any) (err error) {
|
||||
if info, exists, owner := GetFuncInfo(ctx, name); exists {
|
||||
if info.MinArgs() > len(params) {
|
||||
if info.MaxArgs() < 0 {
|
||||
err = fmt.Errorf("too few params -- expected %d or more, got %d", info.MinArgs(), len(params))
|
||||
} else {
|
||||
err = fmt.Errorf("too few params -- expected %d, got %d", info.MinArgs(), len(params))
|
||||
}
|
||||
err = errTooFewParams(info.MinArgs(), info.MaxArgs(), len(params))
|
||||
}
|
||||
if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(params) {
|
||||
err = fmt.Errorf("too much params -- expected %d, got %d", info.MaxArgs(), len(params))
|
||||
err = errTooMuchParams(info.MaxArgs(), len(params))
|
||||
}
|
||||
if err == nil && owner != ctx {
|
||||
ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
|
||||
|
@ -29,7 +29,7 @@ func float64ToFraction(f float64) (fract *fraction, err error) {
|
||||
var sign string
|
||||
intPart, decPart := math.Modf(f)
|
||||
if decPart < 0.0 {
|
||||
sign="-"
|
||||
sign = "-"
|
||||
intPart = -intPart
|
||||
decPart = -decPart
|
||||
}
|
||||
@ -89,11 +89,14 @@ func makeGeneratingFraction(s string) (f *fraction, err error) {
|
||||
goto exit
|
||||
}
|
||||
if s[0] == '-' {
|
||||
sign=int64(-1)
|
||||
sign = int64(-1)
|
||||
s = s[1:]
|
||||
} else if s[0] == '+' {
|
||||
s = s[1:]
|
||||
}
|
||||
if strings.HasSuffix(s, "()") {
|
||||
s = s[0 : len(s)-2]
|
||||
}
|
||||
parts = strings.SplitN(s, ".", 2)
|
||||
if num, err = strconv.ParseInt(parts[0], 10, 64); err != nil {
|
||||
return
|
||||
@ -106,7 +109,7 @@ func makeGeneratingFraction(s string) (f *fraction, err error) {
|
||||
den = 1
|
||||
dec := parts[1]
|
||||
lsd := len(dec)
|
||||
for i:=lsd-1; i>= 0 && dec[i]=='0'; i-- {
|
||||
for i := lsd - 1; i >= 0 && dec[i] == '0'; i-- {
|
||||
lsd--
|
||||
}
|
||||
for _, c := range dec[0:lsd] {
|
||||
|
@ -158,6 +158,8 @@ func TestGeneralParser(t *testing.T) {
|
||||
/* 137 */ {`builtin "os.file"`, int64(1), nil},
|
||||
/* 138 */ {`v=10; v++; v`, int64(11), nil},
|
||||
/* 139 */ {`1+1|2+0.5`, float64(2), nil},
|
||||
/* 140 */ {`1.2()`, newFraction(6, 5), nil},
|
||||
/* 141 */ {`1|(2-2)`, nil, errors.New(`division by zero`)},
|
||||
}
|
||||
|
||||
// t.Setenv("EXPR_PATH", ".")
|
||||
|
Loading…
Reference in New Issue
Block a user