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{ inputs := []inputType{
/* 1 */ {`{}`, map[any]any{}, nil}, /* 1 */ {`{}`, map[any]any{}, nil},
/* 2 */ {`{123}`, nil, errors.New(`[1:6] expected ":", got "}"`)}, /* 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}, /* 4 */ {`{1:"one",2:"two",3:"three"}.2`, "three", nil},
// /* 3 */ {`[1,2,"hello"]`, []any{int64(1), int64(2), "hello"}, nil}, /* 5 */ {`#{1:"one",2:"two",3:"three"}`, int64(3), 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},
} }
succeeded := 0 succeeded := 0
+9 -8
View File
@@ -22,17 +22,23 @@ Expressions calculator
toc::[] 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
_Expr_ is a GO package capable of analysing, interpreting and calculating expressions. _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` 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. `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. Here are some examples of execution.
.Run `dev-expr` in REPL mode and ask for help .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>>. <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 of the previous single expression but this it is obtained with two separated calculations.
=== Concepts and terminology
#TODO#
image::expression-diagram.png[]
== Data types == Data types
_Expr_ supports numerical, string, relational, boolean expressions, and mixed-type lists. _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"> <ul class="sectlevel1">
<li><a href="#_expr">1. Expr</a> <li><a href="#_expr">1. Expr</a>
<ul class="sectlevel2"> <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.1. Concepts and terminology</a></li>
<li><a href="#_concepts_and_terminology">1.2. Concepts and terminology</a></li> <li><a href="#_dev_expr_test_tool">1.2. <code>dev-expr</code> test tool</a></li>
</ul> </ul>
</li> </li>
<li><a href="#_data_types">2. Data types</a> <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="#_fractions">2.2. Fractions</a></li>
<li><a href="#_strings">2.3. Strings</a></li> <li><a href="#_strings">2.3. Strings</a></li>
<li><a href="#_boolean">2.4. Boolean</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> </ul>
</li> </li>
<li><a href="#_dictionaries">3. Dictionaries</a></li> <li><a href="#_dictionaries">3. Dictionaries</a></li>
@@ -579,7 +579,7 @@ pre.rouge .ss {
<div class="sectionbody"> <div class="sectionbody">
<!-- toc disabled --> <!-- toc disabled -->
<div class="paragraph"> <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> </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> <p><em>Expr</em> is a GO package capable of analysing, interpreting and calculating expressions.</p>
</div> </div>
<div class="sect2"> <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"> <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> <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>
<div class="paragraph"> <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>
<div class="paragraph"> <div class="paragraph">
<p>The program in located in the <em>tools</em> directory. <p>The program can be downloaded from <a href="https://git.portale-stac.it/go-pkg/-/packages/generic/dev-expr/">dev-expr</a>.</p>
Here are some examples of execution.</p> </div>
<div class="paragraph">
<p>Here are some examples of execution.</p>
</div> </div>
<div class="listingblock"> <div class="listingblock">
<div class="title">Run <code>dev-expr</code> in REPL mode and ask for help</div> <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> </table>
</div> </div>
</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> </div>
<div class="sect1"> <div class="sect1">
@@ -791,14 +793,14 @@ Here are some examples of execution.</p>
<div class="sect2"> <div class="sect2">
<h3 id="_fractions"><a class="anchor" href="#_fractions"></a><a class="link" href="#_fractions">2.2. Fractions</a></h3> <h3 id="_fractions"><a class="anchor" href="#_fractions"></a><a class="link" href="#_fractions">2.2. Fractions</a></h3>
<div class="paragraph"> <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>
<div class="paragraph"> <div class="paragraph">
<div class="title">Examples</div> <div class="title">Examples</div>
<p><code>&gt;&gt;&gt;</code> <code class="blue">1 | 2</code><br> <p><code>&gt;&gt;&gt;</code> <code class="blue">1 | 2</code><br>
<code class="green">1|2</code><br> <code class="green">1|2</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">4|6</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>&gt;&gt;&gt;</code> <code class="blue">1|2 + 2|3</code><br>
<code class="green">7|6</code><br> <code class="green">7|6</code><br>
<code>&gt;&gt;&gt;</code> <code class="blue">1|2 * 2|3</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> </div>
<div class="sect2"> <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"> <div class="paragraph">
<p><em>Expr</em> supports list of mixed-type values, also specified by normal expressions.</p> <p><em>Expr</em> supports list of mixed-type values, also specified by normal expressions.</p>
</div> </div>
@@ -1048,6 +1050,33 @@ Here are some examples of execution.</p>
</tr> </tr>
</tbody> </tbody>
</table> </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> </div>
</div> </div>
@@ -1461,7 +1490,7 @@ The value on the left side of <code class="blue">=</code> must be an identifier.
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2024-05-09 07:18:01 +0200 Last updated 2024-05-10 06:38:03 +0200
</div> </div>
</div> </div>
</body> </body>
+6 -1
View File
@@ -43,6 +43,11 @@ func isFractionFunc(ctx ExprContext, name string, args []any) (result any, err e
return 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) { func isListFunc(ctx ExprContext, name string, args []any) (result any, err error) {
result = IsList(args[0]) result = IsList(args[0])
return return
@@ -53,7 +58,6 @@ func isDictionaryFunc(ctx ExprContext, name string, args []any) (result any, err
return return
} }
func intFunc(ctx ExprContext, name string, args []any) (result any, err error) { func intFunc(ctx ExprContext, name string, args []any) (result any, err error) {
if len(args) == 1 { if len(args) == 1 {
switch v := args[0].(type) { switch v := args[0].(type) {
@@ -93,6 +97,7 @@ func ImportBuiltinsFuncs(ctx ExprContext) {
ctx.RegisterFunc("isString", &simpleFunctor{f: isStringFunc}, 1, 1) ctx.RegisterFunc("isString", &simpleFunctor{f: isStringFunc}, 1, 1)
ctx.RegisterFunc("isFraction", &simpleFunctor{f: isFractionFunc}, 1, 1) ctx.RegisterFunc("isFraction", &simpleFunctor{f: isFractionFunc}, 1, 1)
ctx.RegisterFunc("isFract", &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("isList", &simpleFunctor{f: isListFunc}, 1, 1)
ctx.RegisterFunc("isDictionary", &simpleFunctor{f: isDictionaryFunc}, 1, 1) ctx.RegisterFunc("isDictionary", &simpleFunctor{f: isDictionaryFunc}, 1, 1)
ctx.RegisterFunc("isDict", &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}, /* 44 */ {`builtin "string"; splitStr("one-two-three", "-", )`, newListA("one", "two", "three"), nil},
/* 45 */ {`isInt(2+1)`, true, nil}, /* 45 */ {`isInt(2+1)`, true, nil},
/* 46 */ {`isInt(3.1)`, false, nil}, /* 46 */ {`isInt(3.1)`, false, nil},
/* 46 */ {`isFloat(3.1)`, true, nil}, /* 47 */ {`isFloat(3.1)`, true, nil},
/* 47 */ {`isString("3.1")`, true, nil}, /* 48 */ {`isString("3.1")`, true, nil},
/* 48 */ {`isString("3" + 1)`, true, nil}, /* 49 */ {`isString("3" + 1)`, true, nil},
/* 49 */ {`isList(["3", 1])`, true, nil}, /* 50 */ {`isList(["3", 1])`, true, nil},
/* 50 */ {`isDict({"a":"3", "b":1})`, true, nil}, /* 51 */ {`isDict({"a":"3", "b":1})`, true, nil},
/* 51 */ {`isFract(3|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", ".") 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`)}, /* 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}, /* 18 */ {`["a", "b", "c"]`, newListA("a", "b", "c"), nil},
/* 19 */ {`["a", "b", "c"]`, newList([]any{"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}, // /* 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}, // /* 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: case string:
var index int var index int
if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil { if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil {
v = unboxedValue[index] v = string(unboxedValue[index])
} }
case map[any]any: case map[any]any:
var ok bool var ok bool
+5 -2
View File
@@ -24,11 +24,14 @@ func evalLength(ctx ExprContext, self *term) (v any, err error) {
} }
if IsList(childValue) { if IsList(childValue) {
list, _ := childValue.([]any) ls, _ := childValue.(*ListType)
v = int64(len(list)) v = int64(len(*ls))
} else if IsString(childValue) { } else if IsString(childValue) {
s, _ := childValue.(string) s, _ := childValue.(string)
v = int64(len(s)) v = int64(len(s))
} else if IsDict(childValue) {
m, _ := childValue.(map[any]any)
v = int64(len(m))
} else if it, ok := childValue.(Iterator); ok { } else if it, ok := childValue.(Iterator); ok {
if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(countName) { if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(countName) {
count, _ := extIt.CallOperation(countName, nil) count, _ := extIt.CallOperation(countName, nil)
+4 -4
View File
@@ -35,10 +35,10 @@ func TestGeneralParser(t *testing.T) {
/* 14 */ {`not true`, false, nil}, /* 14 */ {`not true`, false, nil},
/* 15 */ {`true and false`, false, nil}, /* 15 */ {`true and false`, false, nil},
/* 16 */ {`true or false`, true, nil}, /* 16 */ {`true or false`, true, nil},
/* 17 */ {`"uno" + "due"`, `unodue`, nil}, /* *17 */ {`"uno" + "due"`, `unodue`, nil},
/* 18 */ {`"uno" + 2`, `uno2`, nil}, /* *18 */ {`"uno" + 2`, `uno2`, nil},
/* 19 */ {`"uno" + (2+1)`, `uno3`, nil}, /* *19 */ {`"uno" + (2+1)`, `uno3`, nil},
/* 20 */ {`"uno" * (2+1)`, `unounouno`, nil}, /* *20 */ {`"uno" * (2+1)`, `unounouno`, nil},
/* 21 */ {"1", int64(1), nil}, /* 21 */ {"1", int64(1), nil},
/* 22 */ {"1.5", float64(1.5), nil}, /* 22 */ {"1.5", float64(1.5), nil},
/* 23 */ {"1.5*2", float64(3.0), 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 return ok
} }
func IsRational(v any) (ok bool) {
if _, ok = v.(*fraction); !ok {
_, ok = v.(int64)
}
return ok
}
func IsNumber(v any) (ok bool) { func IsNumber(v any) (ok bool) {
return IsFloat(v) || IsInteger(v) return IsFloat(v) || IsInteger(v)
} }