Compare commits

..

18 Commits

Author SHA1 Message Date
camoroso 760c1ee6da New bitwise XOR operator specified by symbol ^ (caret). Iterator dereference is now done by prefixed * (star) 2025-01-03 07:33:17 +01:00
camoroso 5ab6876ea1 term.go: new priority priDereference 2025-01-03 07:28:30 +01:00
camoroso 6268abda8c token.go: new member function Token.SetSymbol() 2025-01-03 07:27:49 +01:00
camoroso d25bd325b7 symbol-map.go: improved detection of incomplete operations 2025-01-03 06:32:55 +01:00
camoroso 01c04feea5 Doc: bitwise operators in the main operator table and special assignment operators table 2025-01-03 05:43:50 +01:00
camoroso 6fc689c46c Added a test to the context type 2025-01-03 05:40:24 +01:00
camoroso eccb0c4dc9 Added new special operators like &= and <<=.
Also made a litle change to scanner function moveOn(): now it moves on
the last char passed and only if there are more than one chars.
2024-12-29 19:26:02 +01:00
camoroso e43823740f Doc: added string splitter operator '/' 2024-12-28 19:22:26 +01:00
camoroso 526982a564 new string operator '/' 2024-12-28 19:16:45 +01:00
camoroso 252514943e parser.go: fix currentItem after parse a subexpr 2024-12-28 19:16:03 +01:00
camoroso 32686fac62 term.go: new member function errDivisionByZero() 2024-12-28 19:14:34 +01:00
camoroso 52a627c747 Edited according to preious commit 2024-12-28 09:28:12 +01:00
camoroso d91e7eb979 The list operator '<<' (append) and '>>' (prepend) have been replaced
with the new operators '<+' and '+>' respectively.
'<<' and '>>' are now used only for left and right binary shit
respectively. Further, their priority has been increased moving them to
a higher priority than that of the assignment operator.
2024-12-28 09:17:27 +01:00
camoroso cca3b76baa solved a number of problems highlighted by the syntax analyzer 2024-12-27 07:46:11 +01:00
camoroso 24e31997fc context-helpers.go: export functions no longer export control flags 2024-12-27 07:22:28 +01:00
camoroso 646710e180 builtin-base.go: new eval() function 2024-12-27 07:14:26 +01:00
camoroso b38327b841 t_builtin-string_test.go: corrected an undefinite article 2024-12-27 07:14:01 +01:00
camoroso fd912b2eb1 common-errors.go: undefinte article selection in error messages 2024-12-27 07:13:03 +01:00
33 changed files with 862 additions and 403 deletions
+29
View File
@@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"math" "math"
"strconv" "strconv"
"strings"
) )
const ( const (
@@ -188,6 +189,30 @@ func fractFunc(ctx ExprContext, name string, args map[string]any) (result any, e
// return // return
// } // }
func evalFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
if source, ok := args[ParamSource].(string); ok {
var expr Expr
parser := NewParser()
if ctx == nil {
ctx = NewSimpleStore()
}
r := strings.NewReader(source)
scanner := NewScanner(r, DefaultTranslations())
if expr, err = parser.Parse(scanner); err == nil {
CtrlEnable(ctx, control_export_all)
result, err = expr.Eval(ctx)
}
} else {
err = ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource])
}
return
}
//// import
func ImportBuiltinsFuncs(ctx ExprContext) { func ImportBuiltinsFuncs(ctx ExprContext) {
anyParams := []ExprFuncParam{ anyParams := []ExprFuncParam{
NewFuncParam(ParamValue), NewFuncParam(ParamValue),
@@ -211,6 +236,10 @@ func ImportBuiltinsFuncs(ctx ExprContext) {
NewFuncParam(ParamValue), NewFuncParam(ParamValue),
NewFuncParamFlagDef(ParamDenominator, PfDefault, int64(1)), NewFuncParamFlagDef(ParamDenominator, PfDefault, int64(1)),
}) })
ctx.RegisterFunc("eval", NewGolangFunctor(evalFunc), TypeAny, []ExprFuncParam{
NewFuncParam(ParamSource),
})
} }
func init() { func init() {
+18 -1
View File
@@ -55,8 +55,25 @@ func ErrInvalidParameterValue(funcName, paramName string, paramValue any) error
return fmt.Errorf("%s(): invalid value %s (%v) for parameter %q", funcName, TypeName(paramValue), paramValue, paramName) return fmt.Errorf("%s(): invalid value %s (%v) for parameter %q", funcName, TypeName(paramValue), paramValue, paramName)
} }
func undefArticle(s string) (article string) {
if len(s) > 0 && strings.Contains("aeiou", s[0:1]) {
article = "an"
} else {
article = "a"
}
return
}
func prependUndefArticle(s string) (result string) {
return undefArticle(s) + " " + s
}
func ErrWrongParamType(funcName, paramName, paramType string, paramValue any) error { func ErrWrongParamType(funcName, paramName, paramType string, paramValue any) error {
return fmt.Errorf("%s(): the %q parameter must be a %s, got a %s (%v)", funcName, paramName, paramType, TypeName(paramValue), paramValue) var artWantType, artGotType string
gotType := TypeName(paramValue)
artGotType = prependUndefArticle(gotType)
artWantType = prependUndefArticle(paramType)
return fmt.Errorf("%s(): the %q parameter must be %s, got %s (%v)", funcName, paramName, artWantType, artGotType, paramValue)
} }
func ErrUnknownParam(funcName, paramName string) error { func ErrUnknownParam(funcName, paramName string) error {
+1 -1
View File
@@ -29,7 +29,7 @@ func exportObjects(destCtx, sourceCtx ExprContext) {
exportAll := CtrlIsEnabled(sourceCtx, control_export_all) exportAll := CtrlIsEnabled(sourceCtx, control_export_all)
// fmt.Printf("Exporting from sourceCtx [%p] to destCtx [%p] -- exportAll=%t\n", sourceCtx, destCtx, exportAll) // fmt.Printf("Exporting from sourceCtx [%p] to destCtx [%p] -- exportAll=%t\n", sourceCtx, destCtx, exportAll)
// Export variables // Export variables
for _, refName := range sourceCtx.EnumVars(func(name string) bool { return exportAll || name[0] == '@' }) { for _, refName := range sourceCtx.EnumVars(func(name string) bool { return (exportAll || name[0] == '@') && !(name[0] == '_') }) {
// fmt.Printf("\tExporting %q\n", refName) // fmt.Printf("\tExporting %q\n", refName)
refValue, _ := sourceCtx.GetVar(refName) refValue, _ := sourceCtx.GetVar(refName)
exportVar(destCtx, refName, refValue) exportVar(destCtx, refName, refValue)
+1 -1
View File
@@ -33,7 +33,7 @@ func NewDict(dictAny map[any]any) (dict *DictType) {
} }
func newDict(dictAny map[any]*term) (dict *DictType) { func newDict(dictAny map[any]*term) (dict *DictType) {
// TODO Change wi a call to NewDict() // TODO Change with a call to NewDict()
var d DictType var d DictType
if dictAny != nil { if dictAny != nil {
d = make(DictType, len(dictAny)) d = make(DictType, len(dictAny))
+53 -15
View File
@@ -439,8 +439,8 @@ _non-empty-list_ = "**[**" _any-value_ {"**,**" _any-value_} "**]**" +
| [blue]`+` | _Join_ | Joins two lists | [blue]`[1,2] + [3]` -> _[1,2,3]_ | [blue]`+` | _Join_ | Joins two lists | [blue]`[1,2] + [3]` -> _[1,2,3]_
| [blue]`-` | _Difference_ | Left list without elements in the right list | [blue]`[1,2,3] - [2]` -> _[1,3]_ | [blue]`-` | _Difference_ | Left list without elements in the right list | [blue]`[1,2,3] - [2]` -> _[1,3]_
| [blue]`>>` | _Front insertion_ | Insert an item in front | [blue]`0 >> [1,2]` -> _[0,1,2]_ | [blue]`+>` | _Front insertion_ | Insert an item in front | [blue]`0 +> [1,2]` -> _[0,1,2]_
| [blue]`<<` | _Back insertion_ | Insert an item at end | [blue]`[1,2] << 3` -> _[1,2,3]_ | [blue]`<+` | _Back insertion_ | Insert an item at end | [blue]`[1,2] <+ 3` -> _[1,2,3]_
| [blue]`[]` | _Item at index_ | Item at given position | [blue]`[1,2,3][1]` -> _2_ | [blue]`[]` | _Item at index_ | Item at given position | [blue]`[1,2,3][1]` -> _2_
| [blue]`in` | _Item in list_ | True if item is in list | [blue]`2 in [1,2,3]` -> _true_ + | [blue]`in` | _Item in list_ | True if item is in list | [blue]`2 in [1,2,3]` -> _true_ +
[blue]`6 in [1,2,3]` -> _false_ [blue]`6 in [1,2,3]` -> _false_
@@ -735,9 +735,9 @@ NOTE: These operators have a high priority, in particular higher than the operat
The table below shows all supported operators by decreasing priorities. The table below shows all supported operators by decreasing priorities.
.Operators priorities .Operators priorities
[cols="^2,^2,^2,^5,^6"] [cols="^3,^2,^2,^5,^6"]
|=== |===
| Priority | Operators | Position | Operation | Operands and results | Priority | Operator | Position | Operation | Operands and results
.2+|*ITEM*| [blue]`[`...`]` | _Postfix_ | _List item_| _list_ `[` _integer_ `]` -> _any_ .2+|*ITEM*| [blue]`[`...`]` | _Postfix_ | _List item_| _list_ `[` _integer_ `]` -> _any_
| [blue]`[`...`]` | _Postfix_ | _Dict item_ | _dict_ `[` _any_ `]` -> _any_ | [blue]`[`...`]` | _Postfix_ | _Dict item_ | _dict_ `[` _any_ `]` -> _any_
@@ -751,13 +751,17 @@ The table below shows all supported operators by decreasing priorities.
.3+|*SIGN*| [blue]`+`, [blue]`-` | _Prefix_ | _Change-sign_| (`+`\|`-`) _number_ -> _number_ .3+|*SIGN*| [blue]`+`, [blue]`-` | _Prefix_ | _Change-sign_| (`+`\|`-`) _number_ -> _number_
| [blue]`#` | _Prefix_ | _Lenght-of_ | `#` _collection_ -> _integer_ | [blue]`#` | _Prefix_ | _Lenght-of_ | `#` _collection_ -> _integer_
| [blue]`#` | _Prefix_ | _Size-of_ | `#` _iterator_ -> _integer_ | [blue]`#` | _Prefix_ | _Size-of_ | `#` _iterator_ -> _integer_
.2+|*BIT SHIFT*| [blue]`<<` | _Infix_ | _Left-Shift_ | _integer_ `<<` _integer_ -> _integer_
| [blue]`>>` | _Infix_ | _Right-Shift_ | _integer_ `>>` _iterator_ -> _integer_
.2+|*SELECT*| [blue]`? : ::` | _Multi-Infix_ | _Case-Selector_ | _any-expr_ `?` _case-list_ _case-expr_ `:` _case-list_ _case-expr_ ... `::` _default-expr_ -> _any_ .2+|*SELECT*| [blue]`? : ::` | _Multi-Infix_ | _Case-Selector_ | _any-expr_ `?` _case-list_ _case-expr_ `:` _case-list_ _case-expr_ ... `::` _default-expr_ -> _any_
| [blue]`? : ::` | _Multi-Infix_ | _Index-Selector_ | _int-expr_ `?` _case-expr_ `:` _case-expr_ ... `::` _default-expr_ -> _any_ | [blue]`? : ::` | _Multi-Infix_ | _Index-Selector_ | _int-expr_ `?` _case-expr_ `:` _case-expr_ ... `::` _default-expr_ -> _any_
.1+|*FRACT*| [blue]`:` | _Infix_ | _Fraction_ | _integer_ `:` _integer_ -> _fraction_ .1+|*FRACT*| [blue]`:` | _Infix_ | _Fraction_ | _integer_ `:` _integer_ -> _fraction_
.5+|*PROD*| [blue]`*` | _Infix_ | _Product_ | _number_ `*` _number_ -> _number_ .7+|*PROD*| [blue]`*` | _Infix_ | _Product_ | _number_ `*` _number_ -> _number_
| [blue]`*` | _Infix_ | _String-repeat_ | _string_ `*` _integer_ -> _string_ | [blue]`*` | _Infix_ | _String-repeat_ | _string_ `*` _integer_ -> _string_
| [blue]`/` | _Infix_ | _Division_ | _number_ `/` _number_ -> _number_ | [blue]`/` | _Infix_ | _Division_ | _number_ `/` _number_ -> _number_
| [blue]`./` | _Infix_ | _Float-division_ | __number__ `./` _number_ -> _float_ | [blue]`./` | _Infix_ | _Float-division_ | __number__ `./` _number_ -> _float_
| [blue]`/` | _Infix_ | _Split_ | _string_ `/` _string_ -> _list_
| [blue]`/` | _Infix_ | _Split_ | _string_ `/` integer -> _list_
| [blue]`%` | _Infix_ | _Integer-remainder_ | _integer_ `%` _integer_ -> _integer_ | [blue]`%` | _Infix_ | _Integer-remainder_ | _integer_ `%` _integer_ -> _integer_
.6+|*SUM*| [blue]`+` | _Infix_ | _Sum_ | _number_ `+` _number_ -> _number_ .6+|*SUM*| [blue]`+` | _Infix_ | _Sum_ | _number_ `+` _number_ -> _number_
| [blue]`+` | _Infix_ | _String-concat_ | (_string_\|_number_) `+` (_string_\|_number_) -> _string_ | [blue]`+` | _Infix_ | _String-concat_ | (_string_\|_number_) `+` (_string_\|_number_) -> _string_
@@ -765,9 +769,9 @@ The table below shows all supported operators by decreasing priorities.
| [blue]`+` | _Infix_ | _Dict-join_ | _dict_ `+` _dict_ -> _dict_ | [blue]`+` | _Infix_ | _Dict-join_ | _dict_ `+` _dict_ -> _dict_
| [blue]`-` | _Infix_ | _Subtraction_ | _number_ `-` _number_ -> _number_ | [blue]`-` | _Infix_ | _Subtraction_ | _number_ `-` _number_ -> _number_
| [blue]`-` | _Infix_ | _List-difference_ | _list_ `-` _list_ -> _list_ | [blue]`-` | _Infix_ | _List-difference_ | _list_ `-` _list_ -> _list_
.3+|*BINARY*| [blue]`&` | _Infix_ | _Binary And_ | _number_ `&` _number_ -> _number_ .1+|*BITWISE NOT*| [blue]`~` | _Prefix_ | _Binary Not_ | `~` _number_ -> _number_
| [blue]`\|` | _Infix_ | _Binary Or_ | _number_ `\|` _number_ -> _number_ .1+|*BITWISE AND*| [blue]`&` | _Infix_ | _Binary And_ | _number_ `&` _number_ -> _number_
| [blue]`~` | _Prefix_ | _Binary Not_ | `~` _number_ -> _number_ .1+|*BITWISE OR*| [blue]`\|` | _Infix_ | _Binary Or_ | _number_ `\|` _number_ -> _number_
.8+|*RELATION*| [blue]`<` | _Infix_ | _Less_ | _comparable_ `<` _comparable_ -> _boolean_ .8+|*RELATION*| [blue]`<` | _Infix_ | _Less_ | _comparable_ `<` _comparable_ -> _boolean_
| [blue]`\<=` | _Infix_ | _less-equal_ | _comparable_ `\<=` _comparable_ -> _boolean_ | [blue]`\<=` | _Infix_ | _less-equal_ | _comparable_ `\<=` _comparable_ -> _boolean_
| [blue]`>` | _Infix_ | _Greater_ | _comparable_ `>` _comparable_ -> _boolean_ | [blue]`>` | _Infix_ | _Greater_ | _comparable_ `>` _comparable_ -> _boolean_
@@ -776,20 +780,54 @@ The table below shows all supported operators by decreasing priorities.
| [blue]`!=` | _Infix_ | _Not-equal_ | _comparable_ `!=` _comparable_ -> _boolean_ | [blue]`!=` | _Infix_ | _Not-equal_ | _comparable_ `!=` _comparable_ -> _boolean_
| [blue]`in` | _Infix_ | _Member-of-list_ | _any_ `in` _list_ -> _boolean_ | [blue]`in` | _Infix_ | _Member-of-list_ | _any_ `in` _list_ -> _boolean_
| [blue]`in` | _Infix_ | _Key-of-dict_ | _any_ `in` _dict_ -> _boolean_ | [blue]`in` | _Infix_ | _Key-of-dict_ | _any_ `in` _dict_ -> _boolean_
.1+|*NOT*| [blue]`not` | _Prefix_ | _Not_ | `not` _boolean_ -> _boolean_ .1+|*LOGIC NOT*| [blue]`not` | _Prefix_ | _Not_ | `not` _boolean_ -> _boolean_
.2+|*AND*| [blue]`and` | _Infix_ | _And_ | _boolean_ `and` _boolean_ -> _boolean_ .2+|*LOGIC AND*| [blue]`and` | _Infix_ | _And_ | _boolean_ `and` _boolean_ -> _boolean_
| [blue]`&&` | _Infix_ | _And_ | _boolean_ `&&` _boolean_ -> _boolean_ | [blue]`&&` | _Infix_ | _And_ | _boolean_ `&&` _boolean_ -> _boolean_
.2+|*OR*| [blue]`or` | _Infix_ | _Or_ | _boolean_ `or` _boolean_ -> _boolean_ .2+|*LOGIC OR*| [blue]`or` | _Infix_ | _Or_ | _boolean_ `or` _boolean_ -> _boolean_
| [blue]`\|\|` | _Infix_ | _Or_ | _boolean_ `\|\|` _boolean_ -> _boolean_ | [blue]`\|\|` | _Infix_ | _Or_ | _boolean_ `\|\|` _boolean_ -> _boolean_
.3+|*ASSIGN*| [blue]`=` | _Infix_ | _Assignment_ | _identifier_ `=` _any_ -> _any_ .2+|*INSERT*| [blue]`+>` | _Infix_ | _Prepend_ | _any_ `+>` _list_ -> _list_
| [blue]`>>` | _Infix_ | _Front-insert_ | _any_ `>>` _list_ -> _list_ | [blue]`<+` | _Infix_ | _Append_ | _list_ `<+` _any_ -> _list_
| [blue]`<<` | _Infix_ | _Back-insert_ | _list_ `<<` _any_ -> _list_ .2+|*ASSIGN*| [blue]`=` | _Infix_ | _Assignment_ | _identifier_ `=` _any_ -> _any_
4+| _See also the special assignment operators table below_
.1+|*BUT*| [blue]`but` | _Infix_ | _But_ | _any_ `but` _any_ -> _any_ .1+|*BUT*| [blue]`but` | _Infix_ | _But_ | _any_ `but` _any_ -> _any_
.1+|*RANGE*| [blue]`:` | _Infix_ | _Index-range_ | _integer_ `:` _integer_ -> _integer-pair_ .1+|*RANGE*| [blue]`:` | _Infix_ | _Index-range_ | _integer_ `:` _integer_ -> _integer-pair_
|=== |===
//^1^ Experimental //^1^ Experimental
.Special assignment perators
[cols="^2,^2,^4,^6"]
|===
| Priority | Operator | Operation |Equivalent operation
.9+|*ASSIGN*| [blue]`+=` | _Sum & Assign_ | _var_ `\+=` _expr_ +
short for +
_var_ `=` _value-of-var_ `+` _expr_
| [blue]`-=` | _Subtract & Assign_ | _var_ `-=` _expr_ +
short for +
_var_ `=` _value-of-var_ `-` _expr_
| [blue]`*=` | _Multiply & Assign_ | _var_ `\*=` _expr_ +
short for +
_var_ `=` _value-of-var_ `*` _expr_
| [blue]`/=` | _Divide & Assign_ | _var_ `/=` _expr_ +
short for +
_var_ `=` _value-of-var_ `/` _expr_
| [blue]`%=` | _Remainder & Assign_ | _var_ `%=` _expr_ +
short for +
_var_ `=` _value-of-var_ `%` _expr_
| [blue]`&=` | _Bitwise and & Assign_ | _var_ `&=` _expr_ +
short for +
_var_ `=` _value-of-var_ `&` _expr_
| [blue]`\|=` | _Bitwise or & Assign_ | _var_ `\|=` _expr_ +
short for +
_var_ `=` _value-of-var_ `\|` _expr_
| [blue]`<\<=` | _Left shift & Assign_ | _var_ `<\<=` _expr_ +
short for +
_var_ `=` _value-of-var_ `<<` _expr_
| [blue]`>>=` | _Right shift & Assign_ | _var_ `>>=` _expr_ +
short for +
_var_ `=` _value-of-var_ `>>` _expr_
|===
== Functions == Functions
Functions in _Expr_ are very similar to functions available in many programming languages. Currently, _Expr_ supports two types of function, _expr-functions_ and _go-functions_. Functions in _Expr_ are very similar to functions available in many programming languages. Currently, _Expr_ supports two types of function, _expr-functions_ and _go-functions_.
@@ -840,7 +878,7 @@ _param-name_ = _identifier_
=== _Golang_ function definition === _Golang_ function definition
Description of how to define Golan functions and how to bind them to _Expr_ are topics treated in another document that I'll write, one day, maybe. Description of how to define Golang functions and how to bind them to _Expr_ are topics covered in another document that I'll write, one day, maybe.
=== Function calls === Function calls
To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters. To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters.
+148 -34
View File
@@ -1380,16 +1380,16 @@ dev-expr <span class="nt">--</span> Expressions calculator v1.10.0<span class="o
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">[1,2,3] - [2]</code> &#8594; <em>[1,3]</em></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">[1,2,3] - [2]</code> &#8594; <em>[1,3]</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&gt;&gt;</code></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">+&gt;</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Front insertion</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Front insertion</em></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Insert an item in front</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Insert an item in front</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">0 &gt;&gt; [1,2]</code> &#8594; <em>[0,1,2]</em></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">0 +&gt; [1,2]</code> &#8594; <em>[0,1,2]</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&lt;&lt;</code></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&lt;+</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Back insertion</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Back insertion</em></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Insert an item at end</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Insert an item at end</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">[1,2] &lt;&lt; 3</code> &#8594; <em>[1,2,3]</em></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock"><code class="blue">[1,2] &lt;+ 3</code> &#8594; <em>[1,2,3]</em></p></td>
</tr> </tr>
<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"><code class="blue">[]</code></p></td>
@@ -1900,16 +1900,16 @@ These operators have a high priority, in particular higher than the operator <co
<table class="tableblock frame-all grid-all stretch"> <table class="tableblock frame-all grid-all stretch">
<caption class="title">Table 8. Operators priorities</caption> <caption class="title">Table 8. Operators priorities</caption>
<colgroup> <colgroup>
<col style="width: 11.7647%;"> <col style="width: 16.6666%;">
<col style="width: 11.7647%;"> <col style="width: 11.1111%;">
<col style="width: 11.7647%;"> <col style="width: 11.1111%;">
<col style="width: 29.4117%;"> <col style="width: 27.7777%;">
<col style="width: 35.2942%;"> <col style="width: 33.3335%;">
</colgroup> </colgroup>
<thead> <thead>
<tr> <tr>
<th class="tableblock halign-center valign-top">Priority</th> <th class="tableblock halign-center valign-top">Priority</th>
<th class="tableblock halign-center valign-top">Operators</th> <th class="tableblock halign-center valign-top">Operator</th>
<th class="tableblock halign-center valign-top">Position</th> <th class="tableblock halign-center valign-top">Position</th>
<th class="tableblock halign-center valign-top">Operation</th> <th class="tableblock halign-center valign-top">Operation</th>
<th class="tableblock halign-center valign-top">Operands and results</th> <th class="tableblock halign-center valign-top">Operands and results</th>
@@ -1988,6 +1988,19 @@ These operators have a high priority, in particular higher than the operator <co
<td class="tableblock halign-center valign-top"><p class="tableblock"><code>#</code> <em>iterator</em> &#8594; <em>integer</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><code>#</code> <em>iterator</em> &#8594; <em>integer</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>BIT SHIFT</strong></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&lt;&lt;</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Left-Shift</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>integer</em> <code>&lt;&lt;</code> <em>integer</em> &#8594; <em>integer</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&gt;&gt;</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Right-Shift</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>integer</em> <code>&gt;&gt;</code> <em>iterator</em> &#8594; <em>integer</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>SELECT</strong></p></td> <td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>SELECT</strong></p></td>
<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"><code class="blue">? : ::</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Multi-Infix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Multi-Infix</em></p></td>
@@ -2008,7 +2021,7 @@ These operators have a high priority, in particular higher than the operator <co
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>integer</em> <code>:</code> <em>integer</em> &#8594; <em>fraction</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>integer</em> <code>:</code> <em>integer</em> &#8594; <em>fraction</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top" rowspan="5"><p class="tableblock"><strong>PROD</strong></p></td> <td class="tableblock halign-center valign-top" rowspan="7"><p class="tableblock"><strong>PROD</strong></p></td>
<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"><code class="blue">*</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Product</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Product</em></p></td>
@@ -2033,6 +2046,18 @@ These operators have a high priority, in particular higher than the operator <co
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>number</em> <code>./</code> <em>number</em> &#8594; <em>float</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>number</em> <code>./</code> <em>number</em> &#8594; <em>float</em></p></td>
</tr> </tr>
<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>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Split</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>string</em> <code>/</code> <em>string</em> &#8594; <em>list</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>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Split</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>string</em> <code>/</code> integer &#8594; <em>list</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"><code class="blue">%</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Integer-remainder</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Integer-remainder</em></p></td>
@@ -2076,25 +2101,27 @@ These operators have a high priority, in particular higher than the operator <co
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>list</em> <code>-</code> <em>list</em> &#8594; <em>list</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>list</em> <code>-</code> <em>list</em> &#8594; <em>list</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top" rowspan="3"><p class="tableblock"><strong>BINARY</strong></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><strong>BITWISE NOT</strong></p></td>
<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>Prefix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Binary Not</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code>~</code> <em>number</em> &#8594; <em>number</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>BITWISE AND</strong></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&amp;</code></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&amp;</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Binary And</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Binary And</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>number</em> <code>&amp;</code> <em>number</em> &#8594; <em>number</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>number</em> <code>&amp;</code> <em>number</em> &#8594; <em>number</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>BITWISE OR</strong></p></td>
<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"><code class="blue">|</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Binary Or</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Binary Or</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>number</em> <code>|</code> <em>number</em> &#8594; <em>number</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>number</em> <code>|</code> <em>number</em> &#8594; <em>number</em></p></td>
</tr> </tr>
<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>Prefix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Binary Not</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code>~</code> <em>number</em> &#8594; <em>number</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top" rowspan="8"><p class="tableblock"><strong>RELATION</strong></p></td> <td class="tableblock halign-center valign-top" rowspan="8"><p class="tableblock"><strong>RELATION</strong></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&lt;</code></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&lt;</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
@@ -2144,14 +2171,14 @@ These operators have a high priority, in particular higher than the operator <co
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>any</em> <code>in</code> <em>dict</em> &#8594; <em>boolean</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>any</em> <code>in</code> <em>dict</em> &#8594; <em>boolean</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>NOT</strong></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><strong>LOGIC NOT</strong></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">not</code></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">not</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Prefix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Prefix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Not</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Not</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code>not</code> <em>boolean</em> &#8594; <em>boolean</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><code>not</code> <em>boolean</em> &#8594; <em>boolean</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>AND</strong></p></td> <td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>LOGIC AND</strong></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">and</code></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">and</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>And</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>And</em></p></td>
@@ -2164,7 +2191,7 @@ These operators have a high priority, in particular higher than the operator <co
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>boolean</em> <code>&amp;&amp;</code> <em>boolean</em> &#8594; <em>boolean</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>boolean</em> <code>&amp;&amp;</code> <em>boolean</em> &#8594; <em>boolean</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>OR</strong></p></td> <td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>LOGIC OR</strong></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">or</code></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">or</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Or</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Or</em></p></td>
@@ -2177,23 +2204,27 @@ These operators have a high priority, in particular higher than the operator <co
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>boolean</em> <code>||</code> <em>boolean</em> &#8594; <em>boolean</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>boolean</em> <code>||</code> <em>boolean</em> &#8594; <em>boolean</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top" rowspan="3"><p class="tableblock"><strong>ASSIGN</strong></p></td> <td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>INSERT</strong></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">+&gt;</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Prepend</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>any</em> <code>+&gt;</code> <em>list</em> &#8594; <em>list</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&lt;+</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Append</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>list</em> <code>&lt;+</code> <em>any</em> &#8594; <em>list</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>ASSIGN</strong></p></td>
<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"><code class="blue">=</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Assignment</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>Assignment</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>identifier</em> <code>=</code> <em>any</em> &#8594; <em>any</em></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><em>identifier</em> <code>=</code> <em>any</em> &#8594; <em>any</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&gt;&gt;</code></p></td> <td class="tableblock halign-center valign-top" colspan="4"><p class="tableblock"><em>See also the special assignment operators table below</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Front-insert</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>any</em> <code>&gt;&gt;</code> <em>list</em> &#8594; <em>list</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&lt;&lt;</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Back-insert</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>list</em> <code>&lt;&lt;</code> <em>any</em> &#8594; <em>list</em></p></td>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>BUT</strong></p></td> <td class="tableblock halign-center valign-top"><p class="tableblock"><strong>BUT</strong></p></td>
@@ -2211,6 +2242,89 @@ These operators have a high priority, in particular higher than the operator <co
</tr> </tr>
</tbody> </tbody>
</table> </table>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Table 9. Special assignment perators</caption>
<colgroup>
<col style="width: 14.2857%;">
<col style="width: 14.2857%;">
<col style="width: 28.5714%;">
<col style="width: 42.8572%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-center valign-top">Priority</th>
<th class="tableblock halign-center valign-top">Operator</th>
<th class="tableblock halign-center valign-top">Operation</th>
<th class="tableblock halign-center valign-top">Equivalent operation</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-center valign-top" rowspan="9"><p class="tableblock"><strong>ASSIGN</strong></p></td>
<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 &amp; Assign</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>var</em> <code>+=</code> <em>expr</em> <br>
short for<br>
<em>var</em> <code>=</code> <em>value-of-var</em> <code>+</code> <em>expr</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>Subtract &amp; Assign</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>var</em> <code>-=</code> <em>expr</em> <br>
short for<br>
<em>var</em> <code>=</code> <em>value-of-var</em> <code>-</code> <em>expr</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>Multiply &amp; Assign</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>var</em> <code>*=</code> <em>expr</em> <br>
short for<br>
<em>var</em> <code>=</code> <em>value-of-var</em> <code>*</code> <em>expr</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>Divide &amp; Assign</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>var</em> <code>/=</code> <em>expr</em> <br>
short for<br>
<em>var</em> <code>=</code> <em>value-of-var</em> <code>/</code> <em>expr</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>Remainder &amp; Assign</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>var</em> <code>%=</code> <em>expr</em> <br>
short for<br>
<em>var</em> <code>=</code> <em>value-of-var</em> <code>%</code> <em>expr</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&amp;=</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Bitwise and &amp; Assign</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>var</em> <code>&amp;=</code> <em>expr</em> <br>
short for<br>
<em>var</em> <code>=</code> <em>value-of-var</em> <code>&amp;</code> <em>expr</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>Bitwise or &amp; Assign</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>var</em> <code>|=</code> <em>expr</em> <br>
short for<br>
<em>var</em> <code>=</code> <em>value-of-var</em> <code>|</code> <em>expr</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&lt;&lt;=</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Left shift &amp; Assign</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>var</em> <code>&lt;&lt;=</code> <em>expr</em> <br>
short for<br>
<em>var</em> <code>=</code> <em>value-of-var</em> <code>&lt;&lt;</code> <em>expr</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">&gt;&gt;=</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Right shift &amp; Assign</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>var</em> <code>&gt;&gt;=</code> <em>expr</em> <br>
short for<br>
<em>var</em> <code>=</code> <em>value-of-var</em> <code>&gt;&gt;</code> <em>expr</em></p></td>
</tr>
</tbody>
</table>
</div> </div>
</div> </div>
<div class="sect1"> <div class="sect1">
@@ -2282,7 +2396,7 @@ These operators have a high priority, in particular higher than the operator <co
<div class="sect2"> <div class="sect2">
<h3 id="_golang_function_definition"><a class="anchor" href="#_golang_function_definition"></a><a class="link" href="#_golang_function_definition">6.2. <em>Golang</em> function definition</a></h3> <h3 id="_golang_function_definition"><a class="anchor" href="#_golang_function_definition"></a><a class="link" href="#_golang_function_definition">6.2. <em>Golang</em> function definition</a></h3>
<div class="paragraph"> <div class="paragraph">
<p>Description of how to define Golan functions and how to bind them to <em>Expr</em> are topics treated in another document that I&#8217;ll write, one day, maybe.</p> <p>Description of how to define Golang functions and how to bind them to <em>Expr</em> are topics covered in another document that I&#8217;ll write, one day, maybe.</p>
</div> </div>
</div> </div>
<div class="sect2"> <div class="sect2">
@@ -2461,7 +2575,7 @@ g(@p):any{}`
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2024-12-23 07:20:48 +0100 Last updated 2025-01-03 05:42:18 +0100
</div> </div>
</div> </div>
</body> </body>
+10 -8
View File
@@ -126,34 +126,36 @@ func (f *FractionType) ToString(opt FmtOpt) string {
if opt&MultiLine == 0 { if opt&MultiLine == 0 {
sb.WriteString(fmt.Sprintf("%d:%d", f.num, f.den)) sb.WriteString(fmt.Sprintf("%d:%d", f.num, f.den))
} else { } else {
var s, num string var sign, num string
if f.num < 0 && opt&TTY == 0 { if f.num < 0 && opt&TTY == 0 {
num = strconv.FormatInt(-f.num, 10) num = strconv.FormatInt(-f.num, 10)
s = "-" sign = "-"
} else { } else {
num = strconv.FormatInt(f.num, 10) num = strconv.FormatInt(f.num, 10)
} }
den := strconv.FormatInt(f.den, 10) den := strconv.FormatInt(f.den, 10)
size := max(len(num), len(den)) size := max(len(num), len(den))
if opt&TTY != 0 { if opt&TTY != 0 {
sb.WriteString(fmt.Sprintf("\x1b[4m%[1]*s\x1b[0m\n", -size, fmt.Sprintf("%[1]*s", (size+len(num))/2, s+num))) sNum := fmt.Sprintf("\x1b[4m%[1]*s\x1b[0m\n", -size, fmt.Sprintf("%[1]*s", (size+len(num))/2, sign+num))
sb.WriteString(sNum)
} else { } else {
if len(s) > 0 { if len(sign) > 0 {
sb.WriteString(" ") sb.WriteString(" ")
} }
sb.WriteString(fmt.Sprintf("%[1]*s", -size, fmt.Sprintf("%[1]*s", (size+len(num))/2, num))) sb.WriteString(fmt.Sprintf("%[1]*s", -size, fmt.Sprintf("%[1]*s", (size+len(num))/2, num)))
sb.WriteByte('\n') sb.WriteByte('\n')
if len(s) > 0 { if len(sign) > 0 {
sb.WriteString(s) sb.WriteString(sign)
sb.WriteByte(' ') sb.WriteByte(' ')
} }
sb.WriteString(strings.Repeat("-", size)) sb.WriteString(strings.Repeat("-", size))
sb.WriteByte('\n') sb.WriteByte('\n')
if len(s) > 0 { if len(sign) > 0 {
sb.WriteString(" ") sb.WriteString(" ")
} }
} }
sb.WriteString(fmt.Sprintf("%[1]*s", -size, fmt.Sprintf("%[1]*s", (size+len(den))/2, den))) sDen := fmt.Sprintf("%[1]*s", size, fmt.Sprintf("%[1]*s", (size+len(den))/2, den))
sb.WriteString(sDen)
} }
return sb.String() return sb.String()
+4 -4
View File
@@ -5,7 +5,7 @@
package expr package expr
import ( import (
"errors" // "errors"
"fmt" "fmt"
) )
@@ -43,6 +43,6 @@ func errNoOperation(name string) error {
return fmt.Errorf("no %s() function defined in the data-source", name) return fmt.Errorf("no %s() function defined in the data-source", name)
} }
func errInvalidDataSource() error { // func errInvalidDataSource() error {
return errors.New("invalid data-source") // return errors.New("invalid data-source")
} // }
+16
View File
@@ -183,6 +183,16 @@ func evalOpAssign(ctx ExprContext, opTerm *term) (v any, err error) {
v, err = divValues(opTerm, leftValue, rightValue) v, err = divValues(opTerm, leftValue, rightValue)
case SymPercEqual: case SymPercEqual:
v, err = remainderValues(opTerm, leftValue, rightValue) v, err = remainderValues(opTerm, leftValue, rightValue)
case SymAmpersandEqual:
v, err = bitwiseAnd(opTerm, leftValue, rightValue)
case SymVertBarEqual:
v, err = bitwiseOr(opTerm, leftValue, rightValue)
case SymCaretEqual:
v, err = bitwiseXor(opTerm, leftValue, rightValue)
case SymDoubleLessEqual:
v, err = bitLeftShift(opTerm, leftValue, rightValue)
case SymDoubleGreaterEqual:
v, err = bitRightShift(opTerm, leftValue, rightValue)
default: default:
err = opTerm.Errorf("unsupported assign operator %q", opTerm.source()) err = opTerm.Errorf("unsupported assign operator %q", opTerm.source())
} }
@@ -201,4 +211,10 @@ func init() {
registerTermConstructor(SymMinusEqual, newOpAssignTerm) registerTermConstructor(SymMinusEqual, newOpAssignTerm)
registerTermConstructor(SymStarEqual, newOpAssignTerm) registerTermConstructor(SymStarEqual, newOpAssignTerm)
registerTermConstructor(SymSlashEqual, newOpAssignTerm) registerTermConstructor(SymSlashEqual, newOpAssignTerm)
registerTermConstructor(SymPercEqual, newOpAssignTerm)
registerTermConstructor(SymDoubleLessEqual, newOpAssignTerm)
registerTermConstructor(SymDoubleGreaterEqual, newOpAssignTerm)
registerTermConstructor(SymAmpersandEqual, newOpAssignTerm)
registerTermConstructor(SymVertBarEqual, newOpAssignTerm)
registerTermConstructor(SymCaretEqual, newOpAssignTerm)
} }
-104
View File
@@ -1,104 +0,0 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-binary.go
package expr
//-------- NOT term
func newBinNotTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priBinary,
evalFunc: evalBinaryNot,
}
}
func evalBinaryNot(ctx ExprContext, opTerm *term) (v any, err error) {
var value any
if value, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if IsInteger(value) {
i, _ := value.(int64)
v = ^i
} else {
err = opTerm.errIncompatibleType(value)
}
return
}
//-------- Binary AND term
func newBinAndTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBinary,
evalFunc: evalBinaryAnd,
}
}
func evalBinaryAnd(ctx ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
var leftInt, rightInt int64
var lok, rok bool
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt & rightInt
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
}
return
}
//-------- Binary OR term
func newBinOrTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBinary,
evalFunc: evalBinaryOr,
}
}
func evalBinaryOr(ctx ExprContext, self *term) (v any, err error) {
var leftValue, rightValue any
var leftInt, rightInt int64
var lok, rok bool
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
return
}
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt | rightInt
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
}
return
}
// init
func init() {
registerTermConstructor(SymTilde, newBinNotTerm)
registerTermConstructor(SymAmpersand, newBinAndTerm)
registerTermConstructor(SymVertBar, newBinOrTerm)
}
+154
View File
@@ -0,0 +1,154 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-bitwise.go
package expr
//-------- Bitwise NOT term
func newBitwiseNotTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priBitwiseNot,
evalFunc: evalBitwiseNot,
}
}
func evalBitwiseNot(ctx ExprContext, opTerm *term) (v any, err error) {
var value any
if value, err = opTerm.evalPrefix(ctx); err != nil {
return
}
if IsInteger(value) {
i, _ := value.(int64)
v = ^i
} else {
err = opTerm.errIncompatibleType(value)
}
return
}
//-------- Bitwise AND term
func newBitwiseAndTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseAnd,
evalFunc: evalBitwiseAnd,
}
}
func bitwiseAnd(opTerm *term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt & rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseAnd(ctx ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitwiseAnd(opTerm, leftValue, rightValue)
return
}
//-------- Bitwise OR term
func newBitwiseOrTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseOr,
evalFunc: evalBitwiseOr,
}
}
func bitwiseOr(opTerm *term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt | rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseOr(ctx ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitwiseOr(opTerm, leftValue, rightValue)
return
}
//-------- Bitwise XOR term
func newBitwiseXorTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseOr,
evalFunc: evalBitwiseXor,
}
}
func bitwiseXor(opTerm *term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt ^ rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseXor(ctx ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitwiseXor(opTerm, leftValue, rightValue)
return
}
// init
func init() {
registerTermConstructor(SymTilde, newBitwiseNotTerm)
registerTermConstructor(SymAmpersand, newBitwiseAndTerm)
registerTermConstructor(SymVertBar, newBitwiseOrTerm)
registerTermConstructor(SymCaret, newBitwiseXorTerm)
}
+1 -1
View File
@@ -20,7 +20,7 @@ func evalContextValue(ctx ExprContext, opTerm *term) (v any, err error) {
var childValue any var childValue any
var sourceCtx ExprContext var sourceCtx ExprContext
if opTerm.children == nil || len(opTerm.children) == 0 { if len(opTerm.children) == 0 {
sourceCtx = ctx sourceCtx = ctx
} else if opTerm.children[0].symbol() == SymVariable && opTerm.children[0].source() == "global" { } else if opTerm.children[0].symbol() == SymVariable && opTerm.children[0].source() == "global" {
sourceCtx = globalCtx sourceCtx = globalCtx
+1 -2
View File
@@ -7,7 +7,6 @@ package expr
//https://www.youmath.it/lezioni/algebra-elementare/lezioni-di-algebra-e-aritmetica-per-scuole-medie/553-dalle-frazioni-a-numeri-decimali.html //https://www.youmath.it/lezioni/algebra-elementare/lezioni-di-algebra-e-aritmetica-per-scuole-medie/553-dalle-frazioni-a-numeri-decimali.html
import ( import (
"errors"
"fmt" "fmt"
) )
@@ -41,7 +40,7 @@ func evalFraction(ctx ExprContext, opTerm *term) (v any, err error) {
return return
} }
if den == 0 { if den == 0 {
err = errors.New("division by zero") err = opTerm.errDivisionByZero()
return return
} }
+8 -16
View File
@@ -4,15 +4,15 @@
// operator-insert.go // operator-insert.go
package expr package expr
//-------- insert term //-------- prepend term
func newInsertTerm(tk *Token) (inst *term) { func newPrependTerm(tk *Token) (inst *term) {
return &term{ return &term{
tk: *tk, tk: *tk,
children: make([]*term, 0, 2), children: make([]*term, 0, 2),
position: posInfix, position: posInfix,
priority: priAssign, priority: priInsert,
evalFunc: evalInsert, evalFunc: evalPrepend,
} }
} }
@@ -21,12 +21,12 @@ func newAppendTerm(tk *Token) (inst *term) {
tk: *tk, tk: *tk,
children: make([]*term, 0, 2), children: make([]*term, 0, 2),
position: posInfix, position: posInfix,
priority: priAssign, priority: priInsert,
evalFunc: evalAppend, evalFunc: evalAppend,
} }
} }
func evalInsert(ctx ExprContext, opTerm *term) (v any, err error) { func evalPrepend(ctx ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
@@ -40,10 +40,6 @@ func evalInsert(ctx ExprContext, opTerm *term) (v any, err error) {
if opTerm.children[1].symbol() == SymVariable { if opTerm.children[1].symbol() == SymVariable {
ctx.UnsafeSetVar(opTerm.children[1].source(), v) ctx.UnsafeSetVar(opTerm.children[1].source(), v)
} }
} else if IsInteger(leftValue) && IsInteger(rightValue) {
leftInt := leftValue.(int64)
rightInt := rightValue.(int64)
v = leftInt >> rightInt
} else { } else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue) err = opTerm.errIncompatibleTypes(leftValue, rightValue)
} }
@@ -64,10 +60,6 @@ func evalAppend(ctx ExprContext, opTerm *term) (v any, err error) {
if opTerm.children[0].symbol() == SymVariable { if opTerm.children[0].symbol() == SymVariable {
ctx.UnsafeSetVar(opTerm.children[0].source(), v) ctx.UnsafeSetVar(opTerm.children[0].source(), v)
} }
} else if IsInteger(leftValue) && IsInteger(rightValue) {
leftInt := leftValue.(int64)
rightInt := rightValue.(int64)
v = leftInt << rightInt
} else { } else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue) err = opTerm.errIncompatibleTypes(leftValue, rightValue)
} }
@@ -94,6 +86,6 @@ func evalAppend(ctx ExprContext, opTerm *term) (v any, err error) {
// init // init
func init() { func init() {
registerTermConstructor(SymInsert, newInsertTerm) registerTermConstructor(SymPlusGreater, newPrependTerm)
registerTermConstructor(SymAppend, newAppendTerm) registerTermConstructor(SymLessPlus, newAppendTerm)
} }
+3 -3
View File
@@ -11,7 +11,7 @@ func newIterValueTerm(tk *Token) (inst *term) {
tk: *tk, tk: *tk,
children: make([]*term, 0, 1), children: make([]*term, 0, 1),
position: posPrefix, position: posPrefix,
priority: priIterValue, priority: priDereference,
evalFunc: evalIterValue, evalFunc: evalIterValue,
} }
} }
@@ -33,6 +33,6 @@ func evalIterValue(ctx ExprContext, opTerm *term) (v any, err error) {
// init // init
func init() { func init() {
// registerTermConstructor(SymOpenClosedRound, newIterValueTerm) // registerTermConstructor(SymOpenClosedRound, newIterValueTerm)
registerTermConstructor(SymCaret, newIterValueTerm) registerTermConstructor(SymDereference, newIterValueTerm)
} }
+29 -5
View File
@@ -5,7 +5,6 @@
package expr package expr
import ( import (
"errors"
"strings" "strings"
) )
@@ -69,7 +68,7 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
if IsFloat(leftValue) || IsFloat(rightValue) { if IsFloat(leftValue) || IsFloat(rightValue) {
d := numAsFloat(rightValue) d := numAsFloat(rightValue)
if d == 0.0 { if d == 0.0 {
err = errors.New("division by zero") err = opTerm.errDivisionByZero()
} else { } else {
v = numAsFloat(leftValue) / d v = numAsFloat(leftValue) / d
} }
@@ -78,11 +77,36 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
} else { } else {
leftInt, _ := leftValue.(int64) leftInt, _ := leftValue.(int64)
if rightInt, _ := rightValue.(int64); rightInt == 0 { if rightInt, _ := rightValue.(int64); rightInt == 0 {
err = errors.New("division by zero") err = opTerm.errDivisionByZero()
} else { } else {
v = leftInt / rightInt v = leftInt / rightInt
} }
} }
} else if IsString(leftValue) && IsString(rightValue) {
source := leftValue.(string)
sep := rightValue.(string)
v = ListFromStrings(strings.Split(source, sep))
} else if IsString(leftValue) && IsInteger(rightValue) {
source := leftValue.(string)
partSize := int(rightValue.(int64))
if partSize == 0 {
err = opTerm.errDivisionByZero()
} else {
partCount := len(source) / partSize
remainder := len(source) % partSize
listSize := partCount
if remainder > 0 {
listSize++
}
parts := make([]any, 0, listSize)
for i := 0; i < partCount; i++ {
parts = append(parts, source[i*partSize:(i+1)*partSize])
}
if remainder > 0 {
parts = append(parts, source[len(source)-remainder:])
}
v = newList(parts)
}
} else { } else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue) err = opTerm.errIncompatibleTypes(leftValue, rightValue)
} }
@@ -121,7 +145,7 @@ func evalDivideAsFloat(ctx ExprContext, floatDivTerm *term) (v any, err error) {
if isNumOrFract(leftValue) && isNumOrFract(rightValue) { if isNumOrFract(leftValue) && isNumOrFract(rightValue) {
d := numAsFloat(rightValue) d := numAsFloat(rightValue)
if d == 0.0 { if d == 0.0 {
err = errors.New("division by zero") err = floatDivTerm.errDivisionByZero()
} else { } else {
v = numAsFloat(leftValue) / d v = numAsFloat(leftValue) / d
} }
@@ -146,7 +170,7 @@ func remainderValues(opTerm *term, leftValue, rightValue any) (v any, err error)
if IsInteger(leftValue) && IsInteger(rightValue) { if IsInteger(leftValue) && IsInteger(rightValue) {
rightInt, _ := rightValue.(int64) rightInt, _ := rightValue.(int64)
if rightInt == 0 { if rightInt == 0 {
err = errors.New("division by zero") err = opTerm.errDivisionByZero()
} else { } else {
leftInt, _ := leftValue.(int64) leftInt, _ := leftValue.(int64)
v = leftInt % rightInt v = leftInt % rightInt
+77
View File
@@ -0,0 +1,77 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-shift.go
package expr
//-------- bit right shift term
func newRightShiftTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBinShift,
evalFunc: evalRightShift,
}
}
func bitRightShift(opTerm *term, leftValue, rightValue any) (v any, err error) {
if IsInteger(leftValue) && IsInteger(rightValue) {
leftInt := leftValue.(int64)
rightInt := rightValue.(int64)
v = leftInt >> rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalRightShift(ctx ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitRightShift(opTerm, leftValue, rightValue)
return
}
func newLeftShiftTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBinShift,
evalFunc: evalLeftShift,
}
}
func bitLeftShift(opTerm *term, leftValue, rightValue any) (v any, err error) {
if IsInteger(leftValue) && IsInteger(rightValue) {
leftInt := leftValue.(int64)
rightInt := rightValue.(int64)
v = leftInt << rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalLeftShift(ctx ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitLeftShift(opTerm, leftValue, rightValue)
return
}
// init
func init() {
registerTermConstructor(SymDoubleGreater, newRightShiftTerm)
registerTermConstructor(SymDoubleLess, newLeftShiftTerm)
}
+11 -9
View File
@@ -441,8 +441,10 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
tk.Sym = SymChangeSign tk.Sym = SymChangeSign
} else if tk.Sym == SymPlus { } else if tk.Sym == SymPlus {
tk.Sym = SymUnchangeSign tk.Sym = SymUnchangeSign
} else if tk.IsSymbol(SymStar) {
tk.SetSymbol(SymDereference)
} else if tk.IsSymbol(SymExclamation) { } else if tk.IsSymbol(SymExclamation) {
err = tk.Errorf("postfix opertor %q requires an operand on its left", tk) err = tk.Errorf("postfix opertor %q requires an operand on its left side", tk)
break break
} }
firstToken = false firstToken = false
@@ -452,9 +454,12 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
case SymOpenRound: case SymOpenRound:
var subTree *ast var subTree *ast
if subTree, err = parser.parseGeneral(scanner, ctx, SymClosedRound); err == nil { if subTree, err = parser.parseGeneral(scanner, ctx, SymClosedRound); err == nil {
subTree.root.priority = priValue exprTerm := newExprTerm(subTree.root)
err = tree.addTerm(newExprTerm(subTree.root)) err = tree.addTerm(exprTerm)
currentTerm = subTree.root currentTerm = exprTerm
// subTree.root.priority = priValue
// err = tree.addTerm(newExprTerm(subTree.root))
// currentTerm = subTree.root
} }
case SymFuncCall: case SymFuncCall:
var funcCallTerm *term var funcCallTerm *term
@@ -478,7 +483,7 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
currentTerm = mapTerm currentTerm = mapTerm
} }
} }
case SymEqual, SymPlusEqual, SymMinusEqual, SymStarEqual, SymSlashEqual, SymPercEqual: case SymEqual, SymPlusEqual, SymMinusEqual, SymStarEqual, SymSlashEqual, SymPercEqual, SymAmpersandEqual, SymVertBarEqual, SymDoubleLessEqual, SymDoubleGreaterEqual, SymCaretEqual:
currentTerm, err = tree.addToken(tk) currentTerm, err = tree.addToken(tk)
firstToken = true firstToken = true
case SymFuncDef: case SymFuncDef:
@@ -515,15 +520,12 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
} }
} }
} else { } else {
// if hasFlag(ctx, allowIndex) {
// tk.Sym = SymRange
// }
currentTerm, err = tree.addToken(tk) currentTerm, err = tree.addToken(tk)
}
if tk.IsOneOfA(SymColon, SymRange) { if tk.IsOneOfA(SymColon, SymRange) {
// Colon outside a selector term acts like a separator // Colon outside a selector term acts like a separator
firstToken = true firstToken = true
} }
}
default: default:
currentTerm, err = tree.addToken(tk) currentTerm, err = tree.addToken(tk)
} }
+41 -4
View File
@@ -124,6 +124,8 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
tk = scanner.moveOn(SymDoublePlus, ch, next) tk = scanner.moveOn(SymDoublePlus, ch, next)
} else if next == '=' { } else if next == '=' {
tk = scanner.moveOn(SymPlusEqual, ch, next) tk = scanner.moveOn(SymPlusEqual, ch, next)
} else if next == '>' {
tk = scanner.moveOn(SymPlusGreater, ch, next)
} else { } else {
tk = scanner.makeToken(SymPlus, ch) tk = scanner.makeToken(SymPlus, ch)
} }
@@ -167,13 +169,19 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
case '|': case '|':
if next, _ := scanner.peek(); next == '|' { if next, _ := scanner.peek(); next == '|' {
tk = scanner.moveOn(SymDoubleVertBar, ch, next) tk = scanner.moveOn(SymDoubleVertBar, ch, next)
} else if next, _ = scanner.peek(); next == '=' {
tk = scanner.moveOn(SymVertBarEqual, ch, next)
} else { } else {
tk = scanner.makeToken(SymVertBar, ch) tk = scanner.makeToken(SymVertBar, ch)
} }
case ',': case ',':
tk = scanner.makeToken(SymComma, ch) tk = scanner.makeToken(SymComma, ch)
case '^': case '^':
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymCaretEqual, ch, next)
} else {
tk = scanner.makeToken(SymCaret, ch) tk = scanner.makeToken(SymCaret, ch)
}
case ':': case ':':
if next, _ := scanner.peek(); next == ':' { if next, _ := scanner.peek(); next == ':' {
tk = scanner.moveOn(SymDoubleColon, ch, next) tk = scanner.moveOn(SymDoubleColon, ch, next)
@@ -232,11 +240,17 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
case '&': case '&':
if next, _ := scanner.peek(); next == '&' { if next, _ := scanner.peek(); next == '&' {
tk = scanner.moveOn(SymDoubleAmpersand, ch, next) tk = scanner.moveOn(SymDoubleAmpersand, ch, next)
} else if next, _ = scanner.peek(); next == '=' {
tk = scanner.moveOn(SymAmpersandEqual, ch, next)
} else { } else {
tk = scanner.makeToken(SymAmpersand, ch) tk = scanner.makeToken(SymAmpersand, ch)
} }
case '%': case '%':
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymPercEqual, ch, next)
} else {
tk = scanner.makeToken(SymPercent, ch) tk = scanner.makeToken(SymPercent, ch)
}
case '#': case '#':
tk = scanner.makeToken(SymHash, ch) tk = scanner.makeToken(SymHash, ch)
case '@': case '@':
@@ -265,9 +279,18 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
if next, _ := scanner.peek(); next == '=' { if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymLessOrEqual, ch, next) tk = scanner.moveOn(SymLessOrEqual, ch, next)
} else if next == '<' { } else if next == '<' {
tk = scanner.moveOn(SymAppend, ch, next) scanner.readChar()
next2, _ := scanner.readChar()
scanner.unreadChar()
if next2 == '=' {
tk = scanner.moveOn(SymDoubleLessEqual, ch, next, next2)
} else {
tk = scanner.accept(SymDoubleLess, ch, next)
}
} else if next == '>' { } else if next == '>' {
tk = scanner.moveOn(SymLessGreater, ch, next) tk = scanner.moveOn(SymLessGreater, ch, next)
} else if next == '+' {
tk = scanner.moveOn(SymLessPlus, ch, next)
} else { } else {
tk = scanner.makeToken(SymLess, ch) tk = scanner.makeToken(SymLess, ch)
} }
@@ -275,7 +298,14 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
if next, _ := scanner.peek(); next == '=' { if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymGreaterOrEqual, ch, next) tk = scanner.moveOn(SymGreaterOrEqual, ch, next)
} else if next == '>' { } else if next == '>' {
tk = scanner.moveOn(SymInsert, ch, next) scanner.readChar()
next2, _ := scanner.readChar()
scanner.unreadChar()
if next2 == '=' {
tk = scanner.moveOn(SymDoubleGreaterEqual, ch, next, next2)
} else {
tk = scanner.accept(SymDoubleGreater, ch, next)
}
} else { } else {
tk = scanner.makeToken(SymGreater, ch) tk = scanner.makeToken(SymGreater, ch)
} }
@@ -460,7 +490,7 @@ func (scanner *scanner) parseNumber(firstCh byte) (tk *Token) {
tk = scanner.makeErrorToken(err) tk = scanner.makeErrorToken(err)
} else { } else {
var value any var value any
err = scanner.sync(err) // TODO: Check this function _ = scanner.sync(err) // TODO: Check this function
txt := sb.String() txt := sb.String()
if sym == SymFloat { if sym == SymFloat {
value, err = strconv.ParseFloat(txt, 64) value, err = strconv.ParseFloat(txt, 64)
@@ -630,9 +660,16 @@ func (scanner *scanner) translate(sym Symbol) Symbol {
func (scanner *scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) { func (scanner *scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars)) tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
for i := 1; i < len(chars); i++ { // for i := 1; i < len(chars); i++ {
if len(chars) > 1 {
scanner.readChar() scanner.readChar()
} }
// }
return
}
func (scanner *scanner) accept(sym Symbol, chars ...byte) (tk *Token) {
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
return return
} }
+94 -79
View File
@@ -14,7 +14,7 @@ type symbolClass int16
const ( const (
symClassOperator symbolClass = iota symClassOperator symbolClass = iota
symClassPostOp symClassCommand
symClassIdentifier symClassIdentifier
symClassDelimiter symClassDelimiter
symClassParenthesis symClassParenthesis
@@ -26,75 +26,83 @@ const (
type symbolSpec struct { type symbolSpec struct {
repr string repr string
kind symbolClass kind symbolClass
opType termPosition
} }
func init() { func init() {
symbolMap = map[Symbol]symbolSpec{ symbolMap = map[Symbol]symbolSpec{
SymUnknown: {"<unknown>", symClassOther}, // -1: Unknown symbol SymUnknown: {"<unknown>", symClassOther, posLeaf}, // -1: Unknown symbol
SymNone: {"<null>", symClassOther}, // 0: Null value for variable of type symbol SymNone: {"<null>", symClassOther, posLeaf}, // 0: Null value for variable of type symbol
SymError: {"<error>", symClassOther}, // 1: Error reading from stream SymError: {"<error>", symClassOther, posLeaf}, // 1: Error reading from stream
SymEos: {"<eos>", symClassOther}, // 2: End of stream SymEos: {"<eos>", symClassOther, posLeaf}, // 2: End of stream
SymMinus: {"-", symClassOperator}, // 3: '-' SymMinus: {"-", symClassOperator, posInfix}, // 3: '-'
SymMinusEqual: {"-=", symClassOperator}, // 4: '-=' SymMinusEqual: {"-=", symClassOperator, posInfix}, // 4: '-='
SymDoubleMinus: {"--", symClassOperator}, // 5: '--' SymDoubleMinus: {"--", symClassOperator, posPostfix}, // 5: '--'
SymPlus: {"+", symClassOperator}, // 6: '+' SymPlus: {"+", symClassOperator, posInfix}, // 6: '+'
SymPlusEqual: {"+=", symClassOperator}, // 7: '+=' SymPlusEqual: {"+=", symClassOperator, posInfix}, // 7: '+='
SymDoublePlus: {"++", symClassOperator}, // 8: '++' SymDoublePlus: {"++", symClassOperator, posPostfix}, // 8: '++'
SymStar: {"*", symClassOperator}, // 9: '*' SymStar: {"*", symClassOperator, posInfix}, // 9: '*'
SymDoubleStar: {"**", symClassOperator}, // 10: '**' SymDoubleStar: {"**", symClassOperator, posInfix}, // 10: '**'
SymSlash: {"/", symClassOperator}, // 11: '/' SymSlash: {"/", symClassOperator, posInfix}, // 11: '/'
SymBackSlash: {"\\", symClassOperator}, // 12: '\' SymBackSlash: {"\\", symClassOperator, posLeaf}, // 12: '\'
SymVertBar: {"|", symClassOperator}, // 13: '|' SymVertBar: {"|", symClassOperator, posInfix}, // 13: '|'
SymDoubleVertBar: {"||", symClassOperator}, // 14: '||' SymDoubleVertBar: {"||", symClassOperator, posInfix}, // 14: '||'
SymComma: {",", symClassOperator}, // 15: ',' SymComma: {",", symClassOperator, posInfix}, // 15: ','
SymColon: {":", symClassOperator}, // 16: ':' SymColon: {":", symClassOperator, posInfix}, // 16: ':'
SymSemiColon: {";", symClassOperator}, // 17: ';' SymSemiColon: {";", symClassOperator, posInfix}, // 17: ';'
SymDot: {".", symClassOperator}, // 18: '.' SymDot: {".", symClassOperator, posInfix}, // 18: '.'
SymDotSlash: {"./", symClassOperator}, // 19: './' SymDotSlash: {"./", symClassOperator, posInfix}, // 19: './'
SymQuote: {"'", symClassDelimiter}, // 20: '\'' SymQuote: {"'", symClassDelimiter, posLeaf}, // 20: '\''
SymDoubleQuote: {"\"", symClassDelimiter}, // 21: '"' SymDoubleQuote: {"\"", symClassDelimiter, posLeaf}, // 21: '"'
SymBackTick: {"`", symClassOperator}, // 22: '`' SymBackTick: {"`", symClassDelimiter, posLeaf}, // 22: '`'
SymExclamation: {"!", symClassPostOp}, // 23: '!' SymExclamation: {"!", symClassOperator, posPostfix}, // 23: '!'
SymQuestion: {"?", symClassOperator}, // 24: '?' SymQuestion: {"?", symClassOperator, posInfix}, // 24: '?'
SymAmpersand: {"&", symClassOperator}, // 25: '&' SymAmpersand: {"&", symClassOperator, posInfix}, // 25: '&'
SymDoubleAmpersand: {"&&", symClassOperator}, // 26: '&&' SymDoubleAmpersand: {"&&", symClassOperator, posInfix}, // 26: '&&'
SymPercent: {"%", symClassOperator}, // 27: '%' SymPercent: {"%", symClassOperator, posInfix}, // 27: '%'
SymAt: {"@", symClassOperator}, // 28: '@' SymAt: {"@", symClassOperator, posPrefix}, // 28: '@'
SymUndescore: {"_", symClassOperator}, // 29: '_' SymUndescore: {"_", symClassIdentifier, posLeaf}, // 29: '_'
SymEqual: {"=", symClassOperator}, // 30: '=' SymEqual: {"=", symClassOperator, posInfix}, // 30: '='
SymDoubleEqual: {"==", symClassOperator}, // 31: '==' SymDoubleEqual: {"==", symClassOperator, posInfix}, // 31: '=='
SymLess: {"<", symClassOperator}, // 32: '<' SymLess: {"<", symClassOperator, posInfix}, // 32: '<'
SymLessOrEqual: {"<=", symClassOperator}, // 33: '<=' SymLessOrEqual: {"<=", symClassOperator, posInfix}, // 33: '<='
SymGreater: {">", symClassOperator}, // 34: '>' SymGreater: {">", symClassOperator, posInfix}, // 34: '>'
SymGreaterOrEqual: {">=", symClassOperator}, // 35: '>=' SymGreaterOrEqual: {">=", symClassOperator, posInfix}, // 35: '>='
SymLessGreater: {"<>", symClassOperator}, // 36: '<>' SymLessGreater: {"<>", symClassOperator, posInfix}, // 36: '<>'
SymNotEqual: {"!=", symClassOperator}, // 37: '!=' SymNotEqual: {"!=", symClassOperator, posInfix}, // 37: '!='
SymDollar: {"$", symClassOperator}, // 38: '$' SymDollar: {"$", symClassOperator, posPrefix}, // 38: '$'
SymHash: {"#", symClassOperator}, // 39: '#' SymHash: {"#", symClassOperator, posPrefix}, // 39: '#'
SymOpenRound: {"(", symClassParenthesis}, // 40: '(' SymOpenRound: {"(", symClassParenthesis, posPrefix}, // 40: '('
SymClosedRound: {")", symClassParenthesis}, // 41: ')' SymClosedRound: {")", symClassParenthesis, posPostfix}, // 41: ')'
SymOpenSquare: {"[", symClassParenthesis}, // 42: '[' SymOpenSquare: {"[", symClassParenthesis, posPrefix}, // 42: '['
SymClosedSquare: {"]", symClassParenthesis}, // 43: ']' SymClosedSquare: {"]", symClassParenthesis, posPostfix}, // 43: ']'
SymOpenBrace: {"{", symClassParenthesis}, // 44: '{' SymOpenBrace: {"{", symClassParenthesis, posPrefix}, // 44: '{'
SymClosedBrace: {"}", symClassParenthesis}, // 45: '}' SymClosedBrace: {"}", symClassParenthesis, posPostfix}, // 45: '}'
SymTilde: {"~", symClassOperator}, // 46: '~' SymTilde: {"~", symClassOperator, posPrefix}, // 46: '~'
SymDoubleQuestion: {"??", symClassOperator}, // 47: '??' SymDoubleQuestion: {"??", symClassOperator, posInfix}, // 47: '??'
SymQuestionEqual: {"?=", symClassOperator}, // 48: '?=' SymQuestionEqual: {"?=", symClassOperator, posInfix}, // 48: '?='
SymQuestionExclam: {"?!", symClassOperator}, // 49: '?!' SymQuestionExclam: {"?!", symClassOperator, posInfix}, // 49: '?!'
SymDoubleAt: {"@@", symClassOperator}, // 50: '@@' SymDoubleAt: {"@@", symClassCommand, posLeaf}, // 50: '@@'
SymDoubleColon: {"::", symClassOperator}, // 51: '::' SymDoubleColon: {"::", symClassOperator, posInfix}, // 51: '::'
SymInsert: {">>", symClassOperator}, // 52: '>>' SymDoubleGreater: {">>", symClassOperator, posInfix}, // 52: '>>'
SymAppend: {"<<", symClassOperator}, // 53: '<<' SymDoubleLess: {"<<", symClassOperator, posInfix}, // 53: '<<'
SymCaret: {"^", symClassOperator}, // 54: '^' SymCaret: {"^", symClassOperator, posInfix}, // 54: '^'
SymDollarRound: {"$(", symClassOperator}, // 55: '$(' SymDollarRound: {"$(", symClassOperator, posPrefix}, // 55: '$('
SymOpenClosedRound: {"()", symClassPostOp}, // 56: '()' SymOpenClosedRound: {"()", symClassOperator, posPostfix}, // 56: '()'
SymDoubleDollar: {"$$", symClassOperator}, // 57: '$$' SymDoubleDollar: {"$$", symClassCommand, posLeaf}, // 57: '$$'
SymDoubleDot: {"..", symClassOperator}, // 58: '..' SymDoubleDot: {"..", symClassOperator, posInfix}, // 58: '..'
SymTripleDot: {"...", symClassOperator}, // 59: '...' SymTripleDot: {"...", symClassOperator, posPostfix}, // 59: '...'
SymStarEqual: {"*=", symClassOperator}, // 60: '*=' SymStarEqual: {"*=", symClassOperator, posInfix}, // 60: '*='
SymSlashEqual: {"/=", symClassOperator}, // 61: '/=' SymSlashEqual: {"/=", symClassOperator, posInfix}, // 61: '/='
SymPercEqual: {"%=", symClassOperator}, // 62: '%=' SymPercEqual: {"%=", symClassOperator, posInfix}, // 62: '%='
SymDoubleLessEqual: {"<<=", symClassOperator, posInfix}, // 63: '<<='
SymDoubleGreaterEqual: {">>=", symClassOperator, posInfix}, // 64: '>>='
SymAmpersandEqual: {"&=", symClassOperator, posInfix}, // 65: '&='
SymVertBarEqual: {"|=", symClassOperator, posInfix}, // 65: '|='
SymCaretEqual: {"^=", symClassOperator, posInfix}, // 66: '^='
SymPlusGreater: {"+>", symClassOperator, posInfix}, // 67: '+>'
SymLessPlus: {"<+", symClassOperator, posInfix}, // 68: '<+'
// SymChangeSign // SymChangeSign
// SymUnchangeSign // SymUnchangeSign
// SymIdentifier // SymIdentifier
@@ -121,17 +129,17 @@ func init() {
// // SymClosedComment // 0: '*/' // // SymClosedComment // 0: '*/'
// // SymOneLineComment // 0: '//' // // SymOneLineComment // 0: '//'
// keywordBase // keywordBase
SymKwAnd: {"and", symClassOperator}, SymKwAnd: {"and", symClassOperator, posInfix},
SymKwNot: {"not", symClassOperator}, SymKwNot: {"not", symClassOperator, posInfix},
SymKwOr: {"or", symClassOperator}, SymKwOr: {"or", symClassOperator, posInfix},
SymKwBut: {"but", symClassOperator}, SymKwBut: {"but", symClassOperator, posInfix},
SymKwFunc: {"func(", symClassDeclaration}, SymKwFunc: {"func(", symClassDeclaration, posPrefix},
SymKwBuiltin: {"builtin", symClassOperator}, SymKwBuiltin: {"builtin", symClassOperator, posPrefix},
SymKwPlugin: {"plugin", symClassOperator}, SymKwPlugin: {"plugin", symClassOperator, posPrefix},
SymKwIn: {"in", symClassOperator}, SymKwIn: {"in", symClassOperator, posInfix},
SymKwInclude: {"include", symClassOperator}, SymKwInclude: {"include", symClassOperator, posPrefix},
SymKwNil: {"nil", symClassValue}, SymKwNil: {"nil", symClassValue, posLeaf},
SymKwUnset: {"unset", symClassOperator}, SymKwUnset: {"unset", symClassOperator, posPrefix},
} }
} }
@@ -169,12 +177,19 @@ func StringEndsWithOperator(s string) bool {
} }
func endingOperator(s string) (sym Symbol) { func endingOperator(s string) (sym Symbol) {
var matchLength = 0
sym = SymNone sym = SymNone
lower := strings.ToLower(s) lower := strings.TrimRight(strings.ToLower(s), " \t")
for symbol, spec := range symbolMap { for symbol, spec := range symbolMap {
if spec.kind == symClassOperator && strings.HasSuffix(lower, spec.repr) { if strings.HasSuffix(lower, spec.repr) {
if len(spec.repr) > matchLength {
matchLength = len(spec.repr)
if spec.kind == symClassOperator && (spec.opType == posInfix || spec.opType == posPrefix) {
sym = symbol sym = symbol
break } else {
sym = SymNone
}
}
} }
} }
return return
+10 -2
View File
@@ -60,8 +60,8 @@ const (
SymQuestionExclam // 49: '?!' SymQuestionExclam // 49: '?!'
SymDoubleAt // 50: '@@' SymDoubleAt // 50: '@@'
SymDoubleColon // 51: '::' SymDoubleColon // 51: '::'
SymInsert // 52: '>>' SymDoubleGreater // 52: '>>'
SymAppend // 53: '<<' SymDoubleLess // 53: '<<'
SymCaret // 54: '^' SymCaret // 54: '^'
SymDollarRound // 55: '$(' SymDollarRound // 55: '$('
SymOpenClosedRound // 56: '()' SymOpenClosedRound // 56: '()'
@@ -71,8 +71,16 @@ const (
SymStarEqual // 60: '*=' SymStarEqual // 60: '*='
SymSlashEqual // 61: '/=' SymSlashEqual // 61: '/='
SymPercEqual // 62: '%=' SymPercEqual // 62: '%='
SymDoubleLessEqual // 63: '<<='
SymDoubleGreaterEqual // 64: '>>='
SymAmpersandEqual // 65: '&='
SymVertBarEqual // 65: '|='
SymCaretEqual // 66: '^='
SymPlusGreater // 67: '+>'
SymLessPlus // 68: '<+'
SymChangeSign SymChangeSign
SymUnchangeSign SymUnchangeSign
SymDereference
SymIdentifier SymIdentifier
SymBool SymBool
SymInteger SymInteger
+2 -1
View File
@@ -56,11 +56,12 @@ func TestFuncBase(t *testing.T) {
/* 42 */ {`dec(false)`, float64(0), nil}, /* 42 */ {`dec(false)`, float64(0), nil},
/* 43 */ {`dec(1:2)`, float64(0.5), nil}, /* 43 */ {`dec(1:2)`, float64(0.5), nil},
/* 44 */ {`dec([1])`, nil, `dec(): can't convert list to float`}, /* 44 */ {`dec([1])`, nil, `dec(): can't convert list to float`},
/* 45 */ {`eval("a=3"); a`, int64(3), nil},
// /* 45 */ {`string([1])`, nil, `string(): can't convert list to string`}, // /* 45 */ {`string([1])`, nil, `string(): can't convert list to string`},
} }
t.Setenv("EXPR_PATH", ".") t.Setenv("EXPR_PATH", ".")
// runTestSuiteSpec(t, section, inputs, 30) // runTestSuiteSpec(t, section, inputs, 45)
runTestSuite(t, section, inputs) runTestSuite(t, section, inputs)
} }
+1 -1
View File
@@ -15,7 +15,7 @@ func TestFuncString(t *testing.T) {
/* 1 */ {`builtin "string"; strJoin("-", "one", "two", "three")`, "one-two-three", nil}, /* 1 */ {`builtin "string"; strJoin("-", "one", "two", "three")`, "one-two-three", nil},
/* 2 */ {`builtin "string"; strJoin("-", ["one", "two", "three"])`, "one-two-three", nil}, /* 2 */ {`builtin "string"; strJoin("-", ["one", "two", "three"])`, "one-two-three", nil},
/* 3 */ {`builtin "string"; ls= ["one", "two", "three"]; strJoin("-", ls)`, "one-two-three", nil}, /* 3 */ {`builtin "string"; ls= ["one", "two", "three"]; strJoin("-", ls)`, "one-two-three", nil},
/* 4 */ {`builtin "string"; ls= ["one", "two", "three"]; strJoin(1, ls)`, nil, `strJoin(): the "separator" parameter must be a string, got a integer (1)`}, /* 4 */ {`builtin "string"; ls= ["one", "two", "three"]; strJoin(1, ls)`, nil, `strJoin(): the "separator" parameter must be a string, got an integer (1)`},
/* 5 */ {`builtin "string"; ls= ["one", 2, "three"]; strJoin("-", ls)`, nil, `strJoin(): expected string, got integer (2)`}, /* 5 */ {`builtin "string"; ls= ["one", 2, "three"]; strJoin("-", ls)`, nil, `strJoin(): expected string, got integer (2)`},
/* 6 */ {`builtin "string"; "<"+strTrim(" bye bye ")+">"`, "<bye bye>", nil}, /* 6 */ {`builtin "string"; "<"+strTrim(" bye bye ")+">"`, "<bye bye>", nil},
/* 7 */ {`builtin "string"; strSub("0123456789", 1,2)`, "12", nil}, /* 7 */ {`builtin "string"; strSub("0123456789", 1,2)`, "12", nil},
+4 -2
View File
@@ -29,7 +29,9 @@ func TestExpr(t *testing.T) {
/* 15 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`}, /* 15 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`},
/* 16 */ {`v=[2]; a=1; v[a-=1]=5; v[0]`, int64(5), nil}, /* 16 */ {`v=[2]; a=1; v[a-=1]=5; v[0]`, int64(5), nil},
/* 17 */ {`true ? {"a"} :: {"b"}`, "a", nil}, /* 17 */ {`true ? {"a"} :: {"b"}`, "a", nil},
/* 18 */ {` /* 18 */ {`$$`, NewDict(map[any]any{"variables": NewDict(nil), "functions": NewDict(nil)}), nil},
///* 19 */ {`$$global`, NewDict(map[any]any{"variables": NewDict(nil), "functions": NewDict(nil)}), nil},
/* 19 */ {`
ds={ ds={
"init":func(@end){@current=0 but true}, "init":func(@end){@current=0 but true},
//"current":func(){current}, //"current":func(){current},
@@ -44,6 +46,6 @@ func TestExpr(t *testing.T) {
} }
// t.Setenv("EXPR_PATH", ".") // t.Setenv("EXPR_PATH", ".")
// runTestSuiteSpec(t, section, inputs, 6, 7, 8, 9) // runTestSuiteSpec(t, section, inputs, 18)
runTestSuite(t, section, inputs) runTestSuite(t, section, inputs)
} }
+4 -5
View File
@@ -25,7 +25,7 @@ func TestFractionsParser(t *testing.T) {
/* 12 */ {`builtin "math.arith"; add(1:2, 1.0, 2)`, float64(3.5), nil}, /* 12 */ {`builtin "math.arith"; add(1:2, 1.0, 2)`, float64(3.5), nil},
/* 13 */ {`builtin "math.arith"; mul(1:2, 2:3)`, newFraction(2, 6), nil}, /* 13 */ {`builtin "math.arith"; mul(1:2, 2:3)`, newFraction(2, 6), nil},
/* 14 */ {`builtin "math.arith"; mul(1:2, 1.0, 2)`, float64(1.0), nil}, /* 14 */ {`builtin "math.arith"; mul(1:2, 1.0, 2)`, float64(1.0), nil},
/* 15 */ {`1:0`, nil, `division by zero`}, /* 15 */ {`1:0`, nil, `[1:3] division by zero`},
/* 16 */ {`fract(-0.5)`, newFraction(-1, 2), nil}, /* 16 */ {`fract(-0.5)`, newFraction(-1, 2), nil},
/* 17 */ {`fract("")`, (*FractionType)(nil), `bad syntax`}, /* 17 */ {`fract("")`, (*FractionType)(nil), `bad syntax`},
/* 18 */ {`fract("-1")`, newFraction(-1, 1), nil}, /* 18 */ {`fract("-1")`, newFraction(-1, 1), nil},
@@ -34,7 +34,7 @@ func TestFractionsParser(t *testing.T) {
/* 21 */ {`fract(1,0)`, nil, `fract(): division by zero`}, /* 21 */ {`fract(1,0)`, nil, `fract(): division by zero`},
/* 22 */ {`string(1:2)`, "1:2", nil}, /* 22 */ {`string(1:2)`, "1:2", nil},
/* 23 */ {`1+1:2+0.5`, float64(2), nil}, /* 23 */ {`1+1:2+0.5`, float64(2), nil},
/* 24 */ {`1:(2-2)`, nil, `division by zero`}, /* 24 */ {`1:(2-2)`, nil, `[1:3] division by zero`},
/* 25 */ {`[0,1][1-1]:1`, newFraction(0, 1), nil}, /* 25 */ {`[0,1][1-1]:1`, newFraction(0, 1), nil},
} }
// runTestSuiteSpec(t, section, inputs, 25) // runTestSuiteSpec(t, section, inputs, 25)
@@ -59,10 +59,9 @@ func TestFractionToStringMultiline(t *testing.T) {
} }
} }
// TODO Check this test: the output string ends with a space func TestToStringMultilineTty(t *testing.T) {
func _TestToStringMultilineTty(t *testing.T) {
source := newFraction(-1, 2) source := newFraction(-1, 2)
want := "\x1b[4m-1\x1b[0m\n2" want := "\x1b[4m-1\x1b[0m\n 2"
got := source.ToString(MultiLine | TTY) got := source.ToString(MultiLine | TTY)
if got != want { if got != want {
t.Errorf(`(1,2) -> result = %#v [%T], want = %#v [%T]`, got, got, want, want) t.Errorf(`(1,2) -> result = %#v [%T], want = %#v [%T]`, got, got, want, want)
+2 -2
View File
@@ -9,10 +9,10 @@ import "testing"
func TestIteratorParser(t *testing.T) { func TestIteratorParser(t *testing.T) {
section := "Iterator" section := "Iterator"
inputs := []inputType{ inputs := []inputType{
/* 1 */ {`include "test-resources/iterator.expr"; it=$(ds,3); ^it`, int64(0), nil}, /* 1 */ {`include "test-resources/iterator.expr"; it=$(ds,3); *it`, int64(0), nil},
/* 2 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++`, int64(1), nil}, /* 2 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++`, int64(1), nil},
/* 3 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(3), nil}, /* 3 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(3), nil},
/* 4 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; it.reset; ^it`, int64(0), nil}, /* 4 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; it.reset; *it`, int64(0), nil},
/* 5 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil}, /* 5 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil},
/* 6 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil}, /* 6 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil},
/* 7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); mul(it)`, int64(12000), nil}, /* 7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); mul(it)`, int64(12000), nil},
+16 -16
View File
@@ -23,8 +23,8 @@ func TestListParser(t *testing.T) {
/* 9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil}, /* 9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil},
/* 10 */ {`add([1,"hello"])`, nil, `add(): param nr 2 (2 in 1) has wrong type string, number expected`}, /* 10 */ {`add([1,"hello"])`, nil, `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}, /* 11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil},
/* 12 */ {`[1,2,3] << 2+2`, newListA(int64(1), int64(2), int64(3), int64(4)), nil}, /* 12 */ {`[1,2,3] <+ 2+2`, newListA(int64(1), int64(2), int64(3), int64(4)), nil},
/* 13 */ {`2-1 >> [2,3]`, newListA(int64(1), int64(2), int64(3)), nil}, /* 13 */ {`2-1 +> [2,3]`, newListA(int64(1), int64(2), int64(3)), nil},
/* 14 */ {`[1,2,3][1]`, int64(2), nil}, /* 14 */ {`[1,2,3][1]`, int64(2), nil},
/* 15 */ {`ls=[1,2,3] but ls[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}, /* 16 */ {`ls=[1,2,3] but ls[-1]`, int64(3), nil},
@@ -33,25 +33,25 @@ func TestListParser(t *testing.T) {
/* 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}, /* 20 */ {`#["a", "b", "c"]`, int64(3), nil},
/* 21 */ {`"b" in ["a", "b", "c"]`, true, nil}, /* 21 */ {`"b" in ["a", "b", "c"]`, true, nil},
/* 22 */ {`a=[1,2]; (a)<<3`, newListA(int64(1), int64(2), int64(3)), nil}, /* 22 */ {`a=[1,2]; (a)<+3`, newListA(int64(1), int64(2), int64(3)), nil},
/* 23 */ {`a=[1,2]; (a)<<3; a`, newListA(int64(1), int64(2)), nil}, /* 23 */ {`a=[1,2]; (a)<+3; a`, newListA(int64(1), int64(2)), nil},
/* 24 */ {`["a","b","c","d"][1]`, "b", nil}, /* 24 */ {`["a","b","c","d"][1]`, "b", nil},
/* 25 */ {`["a","b","c","d"][1,1]`, nil, `[1:19] one index only is allowed`}, /* 25 */ {`["a","b","c","d"][1,1]`, nil, `[1:19] one index only is allowed`},
/* 26 */ {`[0,1,2,3,4][:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, /* 26 */ {`[0,1,2,3,4][:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
/* 27 */ {`["a", "b", "c"] << ;`, nil, `[1:18] infix operator "<<" requires two non-nil operands, got 1`}, /* 27 */ {`["a", "b", "c"] <+ ;`, nil, `[1:18] infix operator "<+" requires two non-nil operands, got 1`},
/* 28 */ {`2 << 3;`, int64(16), nil}, /* 28 */ {`2 << 3;`, int64(16), nil},
/* 29 */ {`but >> ["a", "b", "c"]`, nil, `[1:6] infix operator ">>" requires two non-nil operands, got 0`}, /* 29 */ {`but +> ["a", "b", "c"]`, nil, `[1:6] infix operator "+>" requires two non-nil operands, got 0`},
/* 30 */ {`2 >> 3;`, int64(0), nil}, /* 30 */ {`2 >> 3;`, int64(0), nil},
/* 31 */ {`a=[1,2]; a<<3`, newListA(int64(1), int64(2), int64(3)), nil}, /* 31 */ {`a=[1,2]; a<+3`, newListA(int64(1), int64(2), int64(3)), nil},
/* 33 */ {`a=[1,2]; 5>>a`, newListA(int64(5), int64(1), int64(2)), nil}, /* 32 */ {`a=[1,2]; 5+>a`, newListA(int64(5), int64(1), int64(2)), nil},
/* 34 */ {`L=[1,2]; L[0]=9; L`, newListA(int64(9), int64(2)), nil}, /* 33 */ {`L=[1,2]; L[0]=9; L`, newListA(int64(9), int64(2)), nil},
/* 35 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`}, /* 34 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`},
/* 36 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [list]`}, /* 35 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [list]`},
/* 37 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`}, /* 36 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`},
/* 38 */ {`[0,1,2,3,4][2:3]`, newListA(int64(2)), nil}, /* 37 */ {`[0,1,2,3,4][2:3]`, newListA(int64(2)), nil},
/* 39 */ {`[0,1,2,3,4][3:-1]`, newListA(int64(3)), nil}, /* 38 */ {`[0,1,2,3,4][3:-1]`, newListA(int64(3)), nil},
/* 40 */ {`[0,1,2,3,4][-3:-1]`, newListA(int64(2), int64(3)), nil}, /* 30 */ {`[0,1,2,3,4][-3:-1]`, newListA(int64(2), int64(3)), nil},
/* 41 */ {`[0,1,2,3,4][0:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, /* 40 */ {`[0,1,2,3,4][0:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
} }
// t.Setenv("EXPR_PATH", ".") // t.Setenv("EXPR_PATH", ".")
+18 -1
View File
@@ -14,10 +14,27 @@ func TestOperator(t *testing.T) {
/* 1 */ {`a=1; unset "a"; a`, nil, `undefined variable or function "a"`}, /* 1 */ {`a=1; unset "a"; a`, nil, `undefined variable or function "a"`},
/* 2 */ {`a=1; unset ["a", "b"]`, int64(1), nil}, /* 2 */ {`a=1; unset ["a", "b"]`, int64(1), nil},
/* 3 */ {`f=func(){3}; unset "f()"`, int64(1), nil}, /* 3 */ {`f=func(){3}; unset "f()"`, int64(1), nil},
/* 4 */ {`a=1; a<<=1+0`, int64(2), nil},
/* 5 */ {`a=2; a>>=1+0`, int64(1), nil},
/* 6 */ {`1<<1`, int64(2), nil},
/* 7 */ {`1>>1`, int64(0), nil},
/* 8 */ {`1|2`, int64(3), nil},
/* 9 */ {`a=1; a|=2`, int64(3), nil},
/* 10 */ {`3&1`, int64(1), nil},
/* 11 */ {`a=3; a&=1`, int64(1), nil},
/* 12 */ {`~1`, int64(-2), nil},
/* 13 */ {`0x10`, int64(16), nil},
/* 14 */ {`0x1X`, nil, `[1:5] two adjacent operators: "1" and "X"`},
/* 15 */ {`0o10`, int64(8), nil},
/* 16 */ {`0b10`, int64(2), nil},
/* 17 */ {`~true`, nil, `[1:2] prefix/postfix operator "~" do not support operand 'true' [bool]`},
/* 18 */ {`1^2`, int64(3), nil},
/* 19 */ {`3^2`, int64(1), nil},
/* 19 */ {`a=1; a^=2`, int64(3), nil},
} }
// t.Setenv("EXPR_PATH", ".") // t.Setenv("EXPR_PATH", ".")
//runTestSuiteSpec(t, section, inputs, 3) // runTestSuiteSpec(t, section, inputs, 4)
runTestSuite(t, section, inputs) runTestSuite(t, section, inputs)
} }
+3 -3
View File
@@ -78,8 +78,8 @@ func TestGeneralParser(t *testing.T) {
/* 64 */ {`"1.5" != `, nil, `[1:8] infix operator "!=" requires two non-nil operands, got 1`}, /* 64 */ {`"1.5" != `, nil, `[1:8] infix operator "!=" requires two non-nil operands, got 1`},
/* 65 */ {"+1.5", float64(1.5), nil}, /* 65 */ {"+1.5", float64(1.5), nil},
/* 66 */ {"+", nil, `[1:2] prefix operator "+" requires one non-nil operand`}, /* 66 */ {"+", nil, `[1:2] prefix operator "+" requires one non-nil operand`},
/* 67 */ {"4 / 0", nil, `division by zero`}, /* 67 */ {"4 / 0", nil, `[1:4] division by zero`},
/* 68 */ {"4.0 / 0", nil, `division by zero`}, /* 68 */ {"4.0 / 0", nil, `[1:6] division by zero`},
/* 69 */ {"4.0 / \n2", float64(2.0), nil}, /* 69 */ {"4.0 / \n2", float64(2.0), nil},
/* 70 */ {`123`, int64(123), nil}, /* 70 */ {`123`, int64(123), nil},
/* 71 */ {`1.`, float64(1.0), nil}, /* 71 */ {`1.`, float64(1.0), nil},
@@ -142,6 +142,6 @@ func TestGeneralParser(t *testing.T) {
} }
// t.Setenv("EXPR_PATH", ".") // t.Setenv("EXPR_PATH", ".")
//runTestSuiteSpec(t, section, inputs, 130) // runTestSuiteSpec(t, section, inputs, 114)
runTestSuite(t, section, inputs) runTestSuite(t, section, inputs)
} }
+11 -11
View File
@@ -8,18 +8,18 @@ import (
"testing" "testing"
) )
func _TestImportPlugin(t *testing.T) { // func TestImportPlugin(t *testing.T) {
t.Setenv("PLUGINS", "${HOME}/go/src/git.portale-stac.it/go") // t.Setenv("PLUGINS", "${HOME}/go/src/git.portale-stac.it/go")
t.Setenv("EXPR_PLUGIN_PATH","${PLUGINS}/expr-json-plugin:${PLUGINS}/expr-csv-plugin") // t.Setenv("EXPR_PLUGIN_PATH","${PLUGINS}/expr-json-plugin:${PLUGINS}/expr-csv-plugin")
gotCount, gotErr := importPluginFromSearchPath("json") // gotCount, gotErr := importPluginFromSearchPath("json")
if gotCount != 1 { // if gotCount != 1 {
t.Errorf("Import count: got=%d, want=1", gotCount) // t.Errorf("Import count: got=%d, want=1", gotCount)
} // }
if gotErr != nil { // if gotErr != nil {
t.Errorf("importPlugin() failed: %v", gotErr) // t.Errorf("importPlugin() failed: %v", gotErr)
} // }
} // }
func TestPluginExists(t *testing.T) { func TestPluginExists(t *testing.T) {
name := "json" name := "json"
+8 -1
View File
@@ -9,6 +9,7 @@ import (
) )
func TestStringsParser(t *testing.T) { func TestStringsParser(t *testing.T) {
section := "String"
inputs := []inputType{ inputs := []inputType{
/* 1 */ {`"uno" + "due"`, `unodue`, nil}, /* 1 */ {`"uno" + "due"`, `unodue`, nil},
/* 2 */ {`"uno" + 2`, `uno2`, nil}, /* 2 */ {`"uno" + 2`, `uno2`, nil},
@@ -16,6 +17,12 @@ func TestStringsParser(t *testing.T) {
/* 4 */ {`"uno" * (2+1)`, `unounouno`, nil}, /* 4 */ {`"uno" * (2+1)`, `unounouno`, nil},
/* 5 */ {`"abc"[1]`, `b`, nil}, /* 5 */ {`"abc"[1]`, `b`, nil},
/* 6 */ {`#"abc"`, int64(3), nil}, /* 6 */ {`#"abc"`, int64(3), nil},
/* 7 */ {`"192.168.0.240" / "."`, newListA("192", "168", "0", "240"), nil},
/* 8 */ {`("192.168.0.240" / ".")[1]`, "168", nil},
/* 9 */ {`"AF3B0Dz" / 2`, newListA("AF", "3B", "0D", "z"), nil},
/* 10 */ {`"AF3B0Dz" / 0`, nil, "[1:12] division by zero"},
} }
runTestSuite(t, "String", inputs)
// runTestSuiteSpec(t, section, inputs, 8)
runTestSuite(t, section, inputs)
} }
+10 -1
View File
@@ -15,21 +15,26 @@ const (
priRange priRange
priBut priBut
priAssign priAssign
priInsert
priOr priOr
priAnd priAnd
priNot priNot
priRelational priRelational
priBinary priBitwiseOr
priBitwiseAnd
priBitwiseNot
priSum priSum
priProduct priProduct
priFraction priFraction
priSelector priSelector
priBinShift
priSign priSign
priFact priFact
priIterValue priIterValue
priDefault priDefault
priIncDec priIncDec
priDot priDot
priDereference
priValue priValue
) )
@@ -199,6 +204,10 @@ func (term *term) errIncompatibleType(value any) error {
term.source(), value, TypeName(value)) term.source(), value, TypeName(value))
} }
func (term *term) errDivisionByZero() error {
return term.tk.Errorf("division by zero")
}
func (term *term) Errorf(template string, args ...any) (err error) { func (term *term) Errorf(template string, args ...any) (err error) {
err = term.tk.Errorf(template, args...) err = term.tk.Errorf(template, args...)
return return
+4
View File
@@ -79,6 +79,10 @@ func (tk *Token) IsSymbol(sym Symbol) bool {
return tk.Sym == sym return tk.Sym == sym
} }
func (tk *Token) SetSymbol(sym Symbol) {
tk.Sym = sym
}
func (tk *Token) Errorf(template string, args ...any) (err error) { func (tk *Token) Errorf(template string, args ...any) (err error) {
err = fmt.Errorf(fmt.Sprintf("[%d:%d] ", tk.row, tk.col)+template, args...) err = fmt.Errorf(fmt.Sprintf("[%d:%d] ", tk.row, tk.col)+template, args...)
return return