Compare commits

...

7 Commits

11 changed files with 116 additions and 60 deletions
+2 -15
View File
@@ -23,22 +23,9 @@ func TestDictParser(t *testing.T) {
inputs := []inputType{
/* 1 */ {`{}`, map[any]any{}, nil},
/* 2 */ {`{123}`, nil, errors.New(`[1:6] expected ":", got "}"`)},
/* 3 */ {`{1:"one",2:"two",3:"three"}`, map[int64]any{int64(1):"one", int64(2):"two", int64(3):"three"}, nil},
/* 3 */ {`{1:"one",2:"two",3:"three"}`, map[int64]any{int64(1): "one", int64(2): "two", int64(3): "three"}, nil},
/* 4 */ {`{1:"one",2:"two",3:"three"}.2`, "three", nil},
// /* 3 */ {`[1,2,"hello"]`, []any{int64(1), int64(2), "hello"}, nil},
// /* 4 */ {`[1+2, not true, "hello"]`, []any{int64(3), false, "hello"}, nil},
// /* 5 */ {`[1,2]+[3]`, []any{int64(1), int64(2), int64(3)}, nil},
// /* 6 */ {`[1,4,3,2]-[3]`, []any{int64(1), int64(4), int64(2)}, nil},
// /* 7 */ {`add([1,4,3,2])`, int64(10), nil},
// /* 8 */ {`add([1,[2,2],3,2])`, int64(10), nil},
// /* 9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil},
// /* 10 */ {`add([1,"hello"])`, nil, errors.New(`add(): param nr 2 (2 in 1) has wrong type string, number expected`)},
// /* 11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil},
// /* 12 */ {`[1,2,3] << 2+2`, []any{int64(1), int64(2), int64(3), int64(4)}, nil},
// /* 13 */ {`2-1 >> [2,3]`, []any{int64(1), int64(2), int64(3)}, nil},
// /* 14 */ {`[1,2,3].1`, int64(2), nil},
// /* 15 */ {`ls=[1,2,3] but ls.1`, int64(2), nil},
// /* 16 */ {`ls=[1,2,3] but ls.(-1)`, int64(3), nil},
/* 5 */ {`#{1:"one",2:"two",3:"three"}`, int64(3), nil},
}
succeeded := 0
+9 -8
View File
@@ -22,17 +22,23 @@ Expressions calculator
toc::[]
#TODO: Work in progress (last update on 2024/05/09, 07:17 am)#
#TODO: Work in progress (last update on 2024/05/10, 06:52 a.m.)#
== Expr
_Expr_ is a GO package capable of analysing, interpreting and calculating expressions.
=== Concepts and terminology
#TODO#
image::expression-diagram.png[]
=== `dev-expr` test tool
`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, beyond in additon to the automatic test suite based on the Go test framework, `dev-expr` provides an important aid for quickly testing of new features during their development.
It cat work as a REPL, *R*ead-*E*xecute-*P*rint-*L*oop, or it can process expression acquired from files or standard input.
It cat work as a _REPL_, _**R**ead-**E**xecute-**P**rint-**L**oop_, or it can process expression acquired from files or standard input.
The program can be downloaded from https://git.portale-stac.it/go-pkg/-/packages/generic/dev-expr/[dev-expr].
The program in located in the _tools_ directory.
Here are some examples of execution.
.Run `dev-expr` in REPL mode and ask for help
@@ -103,11 +109,6 @@ Here are some examples of execution.
<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.
=== Concepts and terminology
#TODO#
image::expression-diagram.png[]
== Data types
_Expr_ supports numerical, string, relational, boolean expressions, and mixed-type lists.
+52 -23
View File
@@ -535,8 +535,8 @@ pre.rouge .ss {
<ul class="sectlevel1">
<li><a href="#_expr">1. Expr</a>
<ul class="sectlevel2">
<li><a href="#_dev_expr_test_tool">1.1. <code>dev-expr</code> test tool</a></li>
<li><a href="#_concepts_and_terminology">1.2. Concepts and terminology</a></li>
<li><a href="#_concepts_and_terminology">1.1. Concepts and terminology</a></li>
<li><a href="#_dev_expr_test_tool">1.2. <code>dev-expr</code> test tool</a></li>
</ul>
</li>
<li><a href="#_data_types">2. Data types</a>
@@ -545,7 +545,7 @@ pre.rouge .ss {
<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="#_list">2.5. List</a></li>
<li><a href="#_lists">2.5. Lists</a></li>
</ul>
</li>
<li><a href="#_dictionaries">3. Dictionaries</a></li>
@@ -579,7 +579,7 @@ pre.rouge .ss {
<div class="sectionbody">
<!-- toc disabled -->
<div class="paragraph">
<p><mark>TODO: Work in progress (last update on 2024/05/09, 07:17 am)</mark></p>
<p><mark>TODO: Work in progress (last update on 2024/05/10, 06:52 a.m.)</mark></p>
</div>
</div>
</div>
@@ -590,16 +590,29 @@ pre.rouge .ss {
<p><em>Expr</em> is a GO package capable of analysing, interpreting and calculating expressions.</p>
</div>
<div class="sect2">
<h3 id="_dev_expr_test_tool"><a class="anchor" href="#_dev_expr_test_tool"></a><a class="link" href="#_dev_expr_test_tool">1.1. <code>dev-expr</code> test tool</a></h3>
<h3 id="_concepts_and_terminology"><a class="anchor" href="#_concepts_and_terminology"></a><a class="link" href="#_concepts_and_terminology">1.1. Concepts and terminology</a></h3>
<div class="paragraph">
<p><mark>TODO</mark></p>
</div>
<div class="imageblock">
<div class="content">
<img src="expression-diagram.png" alt="expression diagram">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_dev_expr_test_tool"><a class="anchor" href="#_dev_expr_test_tool"></a><a class="link" href="#_dev_expr_test_tool">1.2. <code>dev-expr</code> test tool</a></h3>
<div class="paragraph">
<p><code>dev-expr</code> is a simple program that can be used to evaluate expressions interactively. As its name suggests, it was created for testing purpose. In fact, beyond in additon to the automatic test suite based on the Go test framework, <code>dev-expr</code> provides an important aid for quickly testing of new features during their development.</p>
</div>
<div class="paragraph">
<p>It cat work as a REPL, *R*ead-*E*xecute-*P*rint-*L*oop, or it can process expression acquired from files or standard input.</p>
<p>It cat work as a <em>REPL</em>, <em><strong>R</strong>ead-<strong>E</strong>xecute-<strong>P</strong>rint-<strong>L</strong>oop</em>, or it can process expression acquired from files or standard input.</p>
</div>
<div class="paragraph">
<p>The program in located in the <em>tools</em> directory.
Here are some examples of execution.</p>
<p>The program can be downloaded from <a href="https://git.portale-stac.it/go-pkg/-/packages/generic/dev-expr/">dev-expr</a>.</p>
</div>
<div class="paragraph">
<p>Here are some examples of execution.</p>
</div>
<div class="listingblock">
<div class="title">Run <code>dev-expr</code> in REPL mode and ask for help</div>
@@ -697,17 +710,6 @@ Here are some examples of execution.</p>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_concepts_and_terminology"><a class="anchor" href="#_concepts_and_terminology"></a><a class="link" href="#_concepts_and_terminology">1.2. Concepts and terminology</a></h3>
<div class="paragraph">
<p><mark>TODO</mark></p>
</div>
<div class="imageblock">
<div class="content">
<img src="expression-diagram.png" alt="expression diagram">
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
@@ -791,14 +793,14 @@ Here are some examples of execution.</p>
<div class="sect2">
<h3 id="_fractions"><a class="anchor" href="#_fractions"></a><a class="link" href="#_fractions">2.2. Fractions</a></h3>
<div class="paragraph">
<p><em>Expr</em> also suports fractions. Fraction literals are made with tow integers separated by a vertical bar <code>|</code>.</p>
<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="paragraph">
<div class="title">Examples</div>
<p><code>&gt;&gt;&gt;</code> <code class="blue">1 | 2</code><br>
<code class="green">1|2</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">4|6</code><br>
<code class="green">2|3</code> <em class="gray">Fractions are always reduced to theri lowest terms</em><br>
<code class="green">2|3</code> <em class="gray">Fractions are always reduced to their lowest terms</em><br>
<code>&gt;&gt;&gt;</code> <code class="blue">1|2 + 2|3</code><br>
<code class="green">7|6</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">1|2 * 2|3</code><br>
@@ -1003,7 +1005,7 @@ Here are some examples of execution.</p>
</div>
</div>
<div class="sect2">
<h3 id="_list"><a class="anchor" href="#_list"></a><a class="link" href="#_list">2.5. List</a></h3>
<h3 id="_lists"><a class="anchor" href="#_lists"></a><a class="link" href="#_lists">2.5. Lists</a></h3>
<div class="paragraph">
<p><em>Expr</em> supports list of mixed-type values, also specified by normal expressions.</p>
</div>
@@ -1048,6 +1050,33 @@ Here are some examples of execution.</p>
</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="content">
<pre class="rouge highlight"><code data-lang="bnf">&lt;item&gt; ::= &lt;list-expr&gt;"."&lt;index-expr&gt;</code></pre>
</div>
</div>
<div class="listingblock">
<div class="title">Items of list</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,2,3].1`</span>
<span class="p">[</span><span class="n">green</span><span class="p">]</span><span class="s">`2`</span>
<span class="s">`&gt;&gt;&gt;`</span> <span class="p">[</span><span class="n">blue</span><span class="p">]</span><span class="s">`list=[1,2,3]; list.1`</span>
<span class="p">[</span><span class="n">green</span><span class="p">]</span><span class="s">`2`</span>
<span class="s">`&gt;&gt;&gt;`</span> <span class="p">[</span><span class="n">blue</span><span class="p">]</span><span class="s">`["one","two","three"].1`</span>
<span class="p">[</span><span class="n">green</span><span class="p">]</span><span class="s">`two`</span>
<span class="s">`&gt;&gt;&gt;`</span> <span class="p">[</span><span class="n">blue</span><span class="p">]</span><span class="s">`list=["one","two","three"]; list.(2-1)`</span>
<span class="p">[</span><span class="n">green</span><span class="p">]</span><span class="s">`two`</span>
<span class="s">`&gt;&gt;&gt;`</span> <span class="p">[</span><span class="n">blue</span><span class="p">]</span><span class="s">`list.(-1)`</span>
<span class="p">[</span><span class="n">green</span><span class="p">]</span><span class="s">`three`</span>
<span class="s">`&gt;&gt;&gt;`</span> <span class="p">[</span><span class="n">blue</span><span class="p">]</span><span class="s">`list.(-1)`</span>
<span class="p">[</span><span class="n">green</span><span class="p">]</span><span class="s">`three`</span>
<span class="s">`&gt;&gt;&gt;`</span> <span class="p">[</span><span class="n">blue</span><span class="p">]</span><span class="s">`list.(10)`</span></code></pre>
</div>
</div>
</div>
</div>
</div>
@@ -1461,7 +1490,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-09 07:18:01 +0200
Last updated 2024-05-10 06:38:03 +0200
</div>
</div>
</body>
+6 -1
View File
@@ -43,6 +43,11 @@ func isFractionFunc(ctx ExprContext, name string, args []any) (result any, err e
return
}
func isRationalFunc(ctx ExprContext, name string, args []any) (result any, err error) {
result = IsRational(args[0])
return
}
func isListFunc(ctx ExprContext, name string, args []any) (result any, err error) {
result = IsList(args[0])
return
@@ -53,7 +58,6 @@ func isDictionaryFunc(ctx ExprContext, name string, args []any) (result any, err
return
}
func intFunc(ctx ExprContext, name string, args []any) (result any, err error) {
if len(args) == 1 {
switch v := args[0].(type) {
@@ -93,6 +97,7 @@ func ImportBuiltinsFuncs(ctx ExprContext) {
ctx.RegisterFunc("isString", &simpleFunctor{f: isStringFunc}, 1, 1)
ctx.RegisterFunc("isFraction", &simpleFunctor{f: isFractionFunc}, 1, 1)
ctx.RegisterFunc("isFract", &simpleFunctor{f: isFractionFunc}, 1, 1)
ctx.RegisterFunc("isRational", &simpleFunctor{f: isRationalFunc}, 1, 1)
ctx.RegisterFunc("isList", &simpleFunctor{f: isListFunc}, 1, 1)
ctx.RegisterFunc("isDictionary", &simpleFunctor{f: isDictionaryFunc}, 1, 1)
ctx.RegisterFunc("isDict", &simpleFunctor{f: isDictionaryFunc}, 1, 1)
+8 -6
View File
@@ -57,12 +57,14 @@ func TestFuncs(t *testing.T) {
/* 44 */ {`builtin "string"; splitStr("one-two-three", "-", )`, newListA("one", "two", "three"), nil},
/* 45 */ {`isInt(2+1)`, true, nil},
/* 46 */ {`isInt(3.1)`, false, nil},
/* 46 */ {`isFloat(3.1)`, true, nil},
/* 47 */ {`isString("3.1")`, true, nil},
/* 48 */ {`isString("3" + 1)`, true, nil},
/* 49 */ {`isList(["3", 1])`, true, nil},
/* 50 */ {`isDict({"a":"3", "b":1})`, true, nil},
/* 51 */ {`isFract(3|1)`, true, nil},
/* 47 */ {`isFloat(3.1)`, true, nil},
/* 48 */ {`isString("3.1")`, true, nil},
/* 49 */ {`isString("3" + 1)`, true, nil},
/* 50 */ {`isList(["3", 1])`, true, nil},
/* 51 */ {`isDict({"a":"3", "b":1})`, true, nil},
/* 52 */ {`isFract(1|3)`, true, nil},
/* 53 */ {`isFract(3|1)`, false, nil},
/* 54 */ {`isRational(3|1)`, true, nil},
}
t.Setenv("EXPR_PATH", ".")
+1
View File
@@ -39,6 +39,7 @@ func TestListParser(t *testing.T) {
/* 17 */ {`list=["one","two","three"]; list.10`, nil, errors.New(`[1:36] index 10 out of bounds`)},
/* 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},
// /* 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},
+1 -1
View File
@@ -57,7 +57,7 @@ func evalDot(ctx ExprContext, self *term) (v any, err error) {
case string:
var index int
if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil {
v = unboxedValue[index]
v = string(unboxedValue[index])
}
case map[any]any:
var ok bool
+5 -2
View File
@@ -24,11 +24,14 @@ func evalLength(ctx ExprContext, self *term) (v any, err error) {
}
if IsList(childValue) {
list, _ := childValue.([]any)
v = int64(len(list))
ls, _ := childValue.(*ListType)
v = int64(len(*ls))
} else if IsString(childValue) {
s, _ := childValue.(string)
v = int64(len(s))
} else if IsDict(childValue) {
m, _ := childValue.(map[any]any)
v = int64(len(m))
} else if it, ok := childValue.(Iterator); ok {
if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(countName) {
count, _ := extIt.CallOperation(countName, nil)
+4 -4
View File
@@ -35,10 +35,10 @@ func TestGeneralParser(t *testing.T) {
/* 14 */ {`not true`, false, nil},
/* 15 */ {`true and false`, false, nil},
/* 16 */ {`true or false`, true, nil},
/* 17 */ {`"uno" + "due"`, `unodue`, nil},
/* 18 */ {`"uno" + 2`, `uno2`, nil},
/* 19 */ {`"uno" + (2+1)`, `uno3`, nil},
/* 20 */ {`"uno" * (2+1)`, `unounouno`, nil},
/* *17 */ {`"uno" + "due"`, `unodue`, nil},
/* *18 */ {`"uno" + 2`, `uno2`, nil},
/* *19 */ {`"uno" + (2+1)`, `uno3`, nil},
/* *20 */ {`"uno" * (2+1)`, `unounouno`, nil},
/* 21 */ {"1", int64(1), nil},
/* 22 */ {"1.5", float64(1.5), nil},
/* 23 */ {"1.5*2", float64(3.0), nil},
+21
View File
@@ -0,0 +1,21 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// strings_test.go
package expr
import (
"testing"
)
func TestStringsParser(t *testing.T) {
inputs := []inputType{
/* 1 */ {`"uno" + "due"`, `unodue`, nil},
/* 2 */ {`"uno" + 2`, `uno2`, nil},
/* 3 */ {`"uno" + (2+1)`, `uno3`, nil},
/* 4 */ {`"uno" * (2+1)`, `unounouno`, nil},
/* 5 */ {`"abc".1`, `b`, nil},
/* 5 */ {`#"abc"`, int64(3), nil},
}
parserTest(t, "String", inputs)
}
+7
View File
@@ -44,6 +44,13 @@ func IsFract(v any) (ok bool) {
return ok
}
func IsRational(v any) (ok bool) {
if _, ok = v.(*fraction); !ok {
_, ok = v.(int64)
}
return ok
}
func IsNumber(v any) (ok bool) {
return IsFloat(v) || IsInteger(v)
}