several changes:
1. moved scan/symbol.go to new package sym and adapted all files that reference Symbol type and its values. 2. new type interval defined by begin, end and step values. 3. replaced operator-range.go with operator-interval.go. 4. replaced range operator begin:end with begin..end..step. 5. new implementation of sub-collection extraction based on new interval literal.
This commit is contained in:
+2
-1
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
func importFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||
@@ -47,7 +48,7 @@ func doImport(ctx kern.ExprContext, name string, dirList []string, it kern.Itera
|
||||
var expr *scan.Ast
|
||||
scanner := scan.NewScanner(file, scan.DefaultTranslations())
|
||||
parser := NewParser()
|
||||
if expr, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, scan.SymEos); err == nil {
|
||||
if expr, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, sym.SymEos); err == nil {
|
||||
result, err = expr.Eval(ctx)
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -6,6 +6,8 @@ package kern
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
type Term interface {
|
||||
@@ -17,8 +19,12 @@ type Term interface {
|
||||
GetChildSource(index int) string
|
||||
GetLeftChild() (c Term)
|
||||
GetRightChild() (c Term)
|
||||
Symbol() (symbol sym.Symbol)
|
||||
IsSymbol(symbol sym.Symbol) bool
|
||||
IsOneOf(symbols ...sym.Symbol) bool
|
||||
IsAssign() bool
|
||||
IsVar() bool
|
||||
SetSymbol(symbol sym.Symbol)
|
||||
Compute(ctx ExprContext) (result any, err error)
|
||||
EvalInfix(ctx ExprContext) (leftValue, rightValue any, err error)
|
||||
Errorf(template string, args ...any) (err error)
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||
@@ -15,7 +16,7 @@ import (
|
||||
// -------- dict term
|
||||
func newDictTerm(args map[any]*scan.Term) *scan.Term {
|
||||
return &scan.Term{
|
||||
Tk: *scan.NewValueToken(0, 0, scan.SymDict, "{}", args),
|
||||
Tk: *scan.NewValueToken(0, 0, sym.SymDict, "{}", args),
|
||||
Parent: nil,
|
||||
Children: nil,
|
||||
Position: scan.PosLeaf,
|
||||
|
||||
+2
-1
@@ -9,11 +9,12 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
// -------- expr term
|
||||
func newExprTerm(root *scan.Term) *scan.Term {
|
||||
tk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), scan.SymExpression, root.Source(), root)
|
||||
tk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), sym.SymExpression, root.Source(), root)
|
||||
return &scan.Term{
|
||||
Tk: *tk,
|
||||
Parent: nil,
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
@@ -18,7 +19,7 @@ import (
|
||||
// -------- iterator term
|
||||
|
||||
func newIteratorTerm(tk *scan.Token, args []*scan.Term) *scan.Term {
|
||||
tk.Sym = scan.SymIterator
|
||||
tk.Sym = sym.SymIterator
|
||||
return &scan.Term{
|
||||
Tk: *tk,
|
||||
Parent: nil,
|
||||
|
||||
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
)
|
||||
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
|
||||
func newLinkedListTerm(row, col int, args []*scan.Term) *scan.Term {
|
||||
return &scan.Term{
|
||||
Tk: *scan.NewValueToken(row, col, scan.SymLinkedList, "[<>]", args),
|
||||
Tk: *scan.NewValueToken(row, col, sym.SymLinkedList, "[<>]", args),
|
||||
Parent: nil,
|
||||
Children: nil,
|
||||
Position: scan.PosLeaf,
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
)
|
||||
|
||||
@@ -17,7 +18,7 @@ func newListTermA(args ...*scan.Term) *scan.Term {
|
||||
|
||||
func newListTerm(row, col int, args []*scan.Term) *scan.Term {
|
||||
return &scan.Term{
|
||||
Tk: *scan.NewValueToken(row, col, scan.SymList, "[]", args),
|
||||
Tk: *scan.NewValueToken(row, col, sym.SymList, "[]", args),
|
||||
Parent: nil,
|
||||
Children: nil,
|
||||
Position: scan.PosLeaf,
|
||||
|
||||
+8
-7
@@ -7,13 +7,14 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||
)
|
||||
|
||||
// -------- literal term
|
||||
func newLiteralTerm(tk *scan.Token) *scan.Term {
|
||||
|
||||
if tk.Sym == scan.SymFraction {
|
||||
if tk.Sym == sym.SymFraction {
|
||||
if v, isString := tk.Value.(string); isString {
|
||||
var err error
|
||||
if tk.Value, err = fract.MakeGeneratingFraction(v); err != nil {
|
||||
@@ -40,10 +41,10 @@ func evalLiteral(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymString, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(scan.SymInteger, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(scan.SymFloat, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(scan.SymFraction, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(scan.SymBool, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(scan.SymKwNil, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(sym.SymString, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(sym.SymInteger, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(sym.SymFloat, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(sym.SymFraction, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(sym.SymBool, newLiteralTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwNil, newLiteralTerm)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
// -------- selector case term
|
||||
@@ -32,7 +33,7 @@ func (sc *selectorCase) String() string {
|
||||
}
|
||||
|
||||
func newSelectorCaseTerm(row, col int, filterList *scan.Term, caseExpr kern.Expr) *scan.Term {
|
||||
tk := scan.NewValueToken(row, col, scan.SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr})
|
||||
tk := scan.NewValueToken(row, col, sym.SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr})
|
||||
return &scan.Term{
|
||||
Tk: *tk,
|
||||
Parent: nil,
|
||||
|
||||
+3
-2
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
// -------- variable term
|
||||
@@ -21,7 +22,7 @@ func newVarTerm(tk *scan.Token) *scan.Term {
|
||||
Priority: scan.PriValue,
|
||||
EvalFunc: evalVar,
|
||||
}
|
||||
t.Tk.Sym = scan.SymVariable
|
||||
t.Tk.Sym = sym.SymVariable
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -41,5 +42,5 @@ func evalVar(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymIdentifier, newVarTerm)
|
||||
scan.RegisterTermConstructor(sym.SymIdentifier, newVarTerm)
|
||||
}
|
||||
|
||||
+30
-29
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
@@ -87,7 +88,7 @@ func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *sca
|
||||
}
|
||||
|
||||
func assignValue(ctx kern.ExprContext, leftTerm *scan.Term, v any, deepCopy bool) (err error) {
|
||||
if leftTerm.Symbol() == scan.SymIndex {
|
||||
if leftTerm.Symbol() == sym.SymIndex {
|
||||
err = assignCollectionItem(ctx, leftTerm.Children[0], leftTerm.Children[1], v)
|
||||
} else {
|
||||
if deepCopy {
|
||||
@@ -118,7 +119,7 @@ func evalAssignDictItem(ctx kern.ExprContext, dotTerm *scan.Term, valueTerm kern
|
||||
|
||||
dotRightTerm := dotTerm.Children[1]
|
||||
dotRightSym := dotRightTerm.Symbol()
|
||||
if dotRightSym == scan.SymVariable || dotRightSym == scan.SymString {
|
||||
if dotRightSym == sym.SymVariable || dotRightSym == sym.SymString {
|
||||
dotKey = util.UnquoteString(dotRightTerm.Source())
|
||||
} else if dotKey, err = dotRightTerm.Compute(ctx); err != nil {
|
||||
return
|
||||
@@ -139,9 +140,9 @@ func generalEvalAssign(ctx kern.ExprContext, opTerm *scan.Term, deepCopy bool) (
|
||||
|
||||
leftTerm := opTerm.Children[0]
|
||||
leftSym := leftTerm.Symbol()
|
||||
if leftSym == scan.SymDot {
|
||||
if leftSym == sym.SymDot {
|
||||
return evalAssignDictItem(ctx, opTerm.Children[0], opTerm.GetChild(1))
|
||||
} else if leftSym != scan.SymVariable && leftSym != scan.SymIndex {
|
||||
} else if leftSym != sym.SymVariable && leftSym != sym.SymIndex {
|
||||
err = leftTerm.Tk.Errorf("left operand of %q must be a variable or a collection's item", opTerm.Tk.Source())
|
||||
return
|
||||
}
|
||||
@@ -150,7 +151,7 @@ func generalEvalAssign(ctx kern.ExprContext, opTerm *scan.Term, deepCopy bool) (
|
||||
|
||||
if v, err = rightChild.Compute(ctx); err == nil {
|
||||
if functor, ok := v.(kern.Functor); ok {
|
||||
if leftSym == scan.SymVariable {
|
||||
if leftSym == sym.SymVariable {
|
||||
if info := functor.GetFunc(); info != nil {
|
||||
ctx.RegisterFunc(leftTerm.Source(), info.Functor(), info.ReturnType(), info.Params())
|
||||
} else if funcDef, ok := functor.(*exprFunctor); ok {
|
||||
@@ -221,7 +222,7 @@ func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *s
|
||||
}
|
||||
|
||||
func getAssignValue(ctx kern.ExprContext, leftTerm *scan.Term) (value any, err error) {
|
||||
if leftTerm.Symbol() == scan.SymIndex {
|
||||
if leftTerm.Symbol() == sym.SymIndex {
|
||||
value, err = getCollectionItemValue(ctx, leftTerm.Children[0], leftTerm.Children[1])
|
||||
} else {
|
||||
value, _ = ctx.GetVar(leftTerm.Source())
|
||||
@@ -237,7 +238,7 @@ func evalOpAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
leftTerm := opTerm.Children[0]
|
||||
leftSym := leftTerm.Symbol()
|
||||
if leftSym != scan.SymVariable && leftSym != scan.SymIndex {
|
||||
if leftSym != sym.SymVariable && leftSym != sym.SymIndex {
|
||||
err = leftTerm.Tk.Errorf("left operand of %q must be a variable or a collection's item", opTerm.Tk.Source())
|
||||
return
|
||||
}
|
||||
@@ -247,25 +248,25 @@ func evalOpAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
if rightValue, err = rightChild.Compute(ctx); err == nil {
|
||||
if leftValue, err = getAssignValue(ctx, leftTerm); err == nil {
|
||||
switch opTerm.Symbol() {
|
||||
case scan.SymPlusEqual:
|
||||
case sym.SymPlusEqual:
|
||||
v, err = sumValues(opTerm, leftValue, rightValue)
|
||||
case scan.SymMinusEqual:
|
||||
case sym.SymMinusEqual:
|
||||
v, err = diffValues(opTerm, leftValue, rightValue)
|
||||
case scan.SymStarEqual:
|
||||
case sym.SymStarEqual:
|
||||
v, err = mulValues(opTerm, leftValue, rightValue)
|
||||
case scan.SymSlashEqual:
|
||||
case sym.SymSlashEqual:
|
||||
v, err = divValues(opTerm, leftValue, rightValue)
|
||||
case scan.SymPercEqual:
|
||||
case sym.SymPercEqual:
|
||||
v, err = remainderValues(opTerm, leftValue, rightValue)
|
||||
case scan.SymAmpersandEqual:
|
||||
case sym.SymAmpersandEqual:
|
||||
v, err = bitwiseAnd(opTerm, leftValue, rightValue)
|
||||
case scan.SymVertBarEqual:
|
||||
case sym.SymVertBarEqual:
|
||||
v, err = bitwiseOr(opTerm, leftValue, rightValue)
|
||||
case scan.SymCaretEqual:
|
||||
case sym.SymCaretEqual:
|
||||
v, err = bitwiseXor(opTerm, leftValue, rightValue)
|
||||
case scan.SymDoubleLessEqual:
|
||||
case sym.SymDoubleLessEqual:
|
||||
v, err = bitLeftShift(opTerm, leftValue, rightValue)
|
||||
case scan.SymDoubleGreaterEqual:
|
||||
case sym.SymDoubleGreaterEqual:
|
||||
v, err = bitRightShift(opTerm, leftValue, rightValue)
|
||||
default:
|
||||
err = opTerm.Errorf("unsupported assign operator %q", opTerm.Source())
|
||||
@@ -280,16 +281,16 @@ func evalOpAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymEqual, newAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymColonEqual, newDeepCopyAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymPlusEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymMinusEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymStarEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymSlashEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymPercEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymDoubleLessEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymDoubleGreaterEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymAmpersandEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymVertBarEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymCaretEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymEqual, newAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymColonEqual, newDeepCopyAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymPlusEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymMinusEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymStarEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymSlashEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymPercEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleLessEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleGreaterEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymAmpersandEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymVertBarEqual, newOpAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymCaretEqual, newOpAssignTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
@@ -63,5 +64,5 @@ func evalAt(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwAt, newAtTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwAt, newAtTerm)
|
||||
}
|
||||
|
||||
+5
-4
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
)
|
||||
|
||||
@@ -153,8 +154,8 @@ func evalBitwiseXor(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error)
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymTilde, newBitwiseNotTerm)
|
||||
scan.RegisterTermConstructor(scan.SymAmpersand, newBitwiseAndTerm)
|
||||
scan.RegisterTermConstructor(scan.SymVertBar, newBitwiseOrTerm)
|
||||
scan.RegisterTermConstructor(scan.SymCaret, newBitwiseXorTerm)
|
||||
scan.RegisterTermConstructor(sym.SymTilde, newBitwiseNotTerm)
|
||||
scan.RegisterTermConstructor(sym.SymAmpersand, newBitwiseAndTerm)
|
||||
scan.RegisterTermConstructor(sym.SymVertBar, newBitwiseOrTerm)
|
||||
scan.RegisterTermConstructor(sym.SymCaret, newBitwiseXorTerm)
|
||||
}
|
||||
|
||||
+4
-3
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||
)
|
||||
|
||||
@@ -176,7 +177,7 @@ func evalOrWithShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err error
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymNot, newNotTerm)
|
||||
scan.RegisterTermConstructor(scan.SymAnd, newAndTerm)
|
||||
scan.RegisterTermConstructor(scan.SymOr, newOrTerm)
|
||||
scan.RegisterTermConstructor(sym.SymNot, newNotTerm)
|
||||
scan.RegisterTermConstructor(sym.SymAnd, newAndTerm)
|
||||
scan.RegisterTermConstructor(sym.SymOr, newOrTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||
)
|
||||
|
||||
@@ -66,5 +67,5 @@ func evalBuiltin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwBuiltin, newBuiltinTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwBuiltin, newBuiltinTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
//-------- but term
|
||||
@@ -28,5 +29,5 @@ func evalBut(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwBut, newButTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwBut, newButTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
//-------- cat term
|
||||
@@ -147,5 +148,5 @@ func (it *catIterator) CallOperation(name string, args map[string]any) (v any, e
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwCat, newCatTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwCat, newCatTerm)
|
||||
}
|
||||
|
||||
+3
-2
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
)
|
||||
|
||||
@@ -30,7 +31,7 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
|
||||
|
||||
if len(opTerm.Children) == 0 {
|
||||
sourceCtx = ctx
|
||||
} else if opTerm.Children[0].Symbol() == scan.SymVariable && opTerm.Children[0].Source() == "global" {
|
||||
} else if opTerm.Children[0].Symbol() == sym.SymVariable && opTerm.Children[0].Source() == "global" {
|
||||
sourceCtx = ctx.GetGlobal()
|
||||
} else if childValue, err = opTerm.EvalPrefix(ctx); err == nil {
|
||||
if dc, ok := childValue.(*dataCursor); ok {
|
||||
@@ -66,5 +67,5 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymDoubleDollar, newContextTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleDollar, newContextTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
//-------- export all term
|
||||
@@ -28,5 +29,5 @@ func evalExportAll(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymDoubleAt, newExportAllTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleAt, newExportAllTerm)
|
||||
}
|
||||
|
||||
+7
-6
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
//-------- default term
|
||||
@@ -29,7 +30,7 @@ func evalDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
}
|
||||
|
||||
leftTerm := opTerm.Children[0]
|
||||
if leftTerm.Tk.Sym != scan.SymVariable {
|
||||
if leftTerm.Tk.Sym != sym.SymVariable {
|
||||
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
||||
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
|
||||
return
|
||||
@@ -63,7 +64,7 @@ func evalAlternate(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
}
|
||||
|
||||
leftTerm := opTerm.Children[0]
|
||||
if leftTerm.Tk.Sym != scan.SymVariable {
|
||||
if leftTerm.Tk.Sym != sym.SymVariable {
|
||||
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
||||
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
|
||||
return
|
||||
@@ -99,7 +100,7 @@ func evalAssignDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err erro
|
||||
}
|
||||
|
||||
leftTerm := opTerm.Children[0]
|
||||
if leftTerm.Tk.Sym != scan.SymVariable {
|
||||
if leftTerm.Tk.Sym != sym.SymVariable {
|
||||
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
||||
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
|
||||
return
|
||||
@@ -123,7 +124,7 @@ func evalAssignDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err erro
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymDoubleQuestion, newDefaultTerm)
|
||||
scan.RegisterTermConstructor(scan.SymQuestionEqual, newDefaultAssignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymQuestionExclam, newAlternateTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleQuestion, newDefaultTerm)
|
||||
scan.RegisterTermConstructor(sym.SymQuestionEqual, newDefaultAssignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymQuestionExclam, newAlternateTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
//-------- digest term
|
||||
@@ -70,5 +71,5 @@ func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwDigest, newDigestTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwDigest, newDigestTerm)
|
||||
}
|
||||
|
||||
+4
-3
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/util"
|
||||
)
|
||||
@@ -36,7 +37,7 @@ func evalDot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
switch unboxedValue := leftValue.(type) {
|
||||
case kern.ExtIterator:
|
||||
if indexTerm.Symbol() == scan.SymVariable /*|| indexTerm.Tk.Sym == scan.SymString */ {
|
||||
if indexTerm.Symbol() == sym.SymVariable /*|| indexTerm.Tk.Sym == sym.SymString */ {
|
||||
opName := indexTerm.Source()
|
||||
if unboxedValue.HasOperation(opName) {
|
||||
v, err = unboxedValue.CallOperation(opName, map[string]any{})
|
||||
@@ -61,7 +62,7 @@ func dotGetDictItemValue(ctx kern.ExprContext, d *dict.DictType, rightTerm *scan
|
||||
var ok bool
|
||||
var rightValue any
|
||||
s := rightTerm.Symbol()
|
||||
if s == scan.SymVariable || s == scan.SymString {
|
||||
if s == sym.SymVariable || s == sym.SymString {
|
||||
// src := rightTerm.Source()
|
||||
// if len(src) > 1 && src[0] == '"' && src[len(src)-1] == '"' {
|
||||
// src = src[1 : len(src)-1]
|
||||
@@ -87,5 +88,5 @@ func errDictKeyNotFound(term *scan.Term, key any) error {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymDot, newDotTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDot, newDotTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
)
|
||||
|
||||
@@ -49,5 +50,5 @@ func evalFact(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymExclamation, newFactTerm)
|
||||
scan.RegisterTermConstructor(sym.SymExclamation, newFactTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||
)
|
||||
|
||||
@@ -164,5 +165,5 @@ func (it *filterIterator) CallOperation(name string, args map[string]any) (v any
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwFilter, newFilterTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwFilter, newFilterTerm)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||
)
|
||||
|
||||
@@ -72,5 +73,5 @@ func evalFraction(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
// init
|
||||
func init() {
|
||||
// registerTermConstructor(SymVertBar, newFractionTerm)
|
||||
scan.RegisterTermConstructor(scan.SymColon, newFractionTerm)
|
||||
scan.RegisterTermConstructor(sym.SymColon, newFractionTerm)
|
||||
}
|
||||
|
||||
+3
-2
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||
@@ -51,7 +52,7 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
}
|
||||
|
||||
rightTk := opTerm.Children[1].Tk
|
||||
if rightTk.IsSymbol(scan.SymVariable) && rightTk.Source() == "__" {
|
||||
if rightTk.IsSymbol(sym.SymVariable) && rightTk.Source() == "__" {
|
||||
keyByIndex = true
|
||||
} else if rightValue, err = opTerm.Children[1].Compute(ctx); err != nil {
|
||||
return
|
||||
@@ -112,5 +113,5 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwGroupBy, newGroupByTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwGroupBy, newGroupByTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
@@ -53,5 +54,5 @@ func evalIn(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwIn, newInTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwIn, newInTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||
)
|
||||
@@ -63,5 +64,5 @@ func evalInclude(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwInclude, newIncludeTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwInclude, newIncludeTerm)
|
||||
}
|
||||
|
||||
+151
-67
@@ -5,11 +5,15 @@
|
||||
package expr
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/interval"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
)
|
||||
|
||||
@@ -29,7 +33,7 @@ func verifyKey(indexList *array.ArrayType) (index any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func verifyIndex(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int64) (index int64, err error) {
|
||||
func verifyIndex(indexTerm kern.Term, indexList *array.ArrayType, maxValue int64) (index int64, err error) {
|
||||
var v int64
|
||||
|
||||
if v, err = types.ToGoInt64((*indexList)[0], "index expression"); err == nil {
|
||||
@@ -45,28 +49,28 @@ func verifyIndex(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int6
|
||||
return
|
||||
}
|
||||
|
||||
func verifyRange(indexTerm *scan.Term, indexList *array.ArrayType, maxValue int64) (startIndex, endIndex int64, err error) {
|
||||
v, _ := ((*indexList)[0]).(*intPair)
|
||||
startIndex = v.a
|
||||
endIndex = v.b
|
||||
if endIndex == kern.ConstLastIndex {
|
||||
endIndex = int64(maxValue)
|
||||
}
|
||||
if startIndex < 0 && startIndex >= -maxValue {
|
||||
startIndex = int64(maxValue) + startIndex
|
||||
}
|
||||
if endIndex < 0 && endIndex >= -maxValue {
|
||||
endIndex = int64(maxValue) + endIndex
|
||||
}
|
||||
if startIndex < 0 || startIndex > maxValue {
|
||||
err = indexTerm.Errorf("range start-index %d is out of bounds", startIndex)
|
||||
} else if endIndex < 0 || endIndex > maxValue {
|
||||
err = indexTerm.Errorf("range end-index %d is out of bounds", endIndex)
|
||||
} else if startIndex > endIndex {
|
||||
err = indexTerm.Errorf("range start-index %d must not be greater than end-index %d", startIndex, endIndex)
|
||||
}
|
||||
return
|
||||
}
|
||||
// func verifyInterval(indexTerm kern.Term, indexList *array.ArrayType, maxValue int64) (startIndex, endIndex int64, err error) {
|
||||
// v, _ := ((*indexList)[0]).(*interval.IntervalType)
|
||||
// startIndex = v.Begin()
|
||||
// endIndex = v.End()
|
||||
// if endIndex == kern.ConstLastIndex {
|
||||
// endIndex = int64(maxValue)
|
||||
// }
|
||||
// if startIndex < 0 && startIndex >= -maxValue {
|
||||
// startIndex = int64(maxValue) + startIndex
|
||||
// }
|
||||
// if endIndex < 0 && endIndex >= -maxValue {
|
||||
// endIndex = int64(maxValue) + endIndex
|
||||
// }
|
||||
// if startIndex < 0 || startIndex > maxValue {
|
||||
// err = indexTerm.Errorf("%s start-index %d is out of bounds", interval.TypeName, startIndex)
|
||||
// } else if endIndex < 0 || endIndex > maxValue {
|
||||
// err = indexTerm.Errorf("%s end-index %d is out of bounds", interval.TypeName, endIndex)
|
||||
// } else if startIndex > endIndex {
|
||||
// err = indexTerm.Errorf("%s start-index %d must not be greater than end-index %d", interval.TypeName, startIndex, endIndex)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
var leftValue, rightValue any
|
||||
@@ -87,48 +91,9 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
}
|
||||
|
||||
if types.IsInteger((*indexList)[0]) {
|
||||
switch unboxedValue := leftValue.(type) {
|
||||
case *array.ArrayType:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(len(*unboxedValue))); err == nil {
|
||||
v = (*unboxedValue)[index]
|
||||
}
|
||||
case *list.LinkedList:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(unboxedValue.Len())); err == nil {
|
||||
v, err = unboxedValue.At(index)
|
||||
}
|
||||
case string:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(len(unboxedValue))); err == nil {
|
||||
v = string(unboxedValue[index])
|
||||
}
|
||||
case *dict.DictType:
|
||||
v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue)
|
||||
default:
|
||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
} else if isIntPair((*indexList)[0]) {
|
||||
switch unboxedValue := leftValue.(type) {
|
||||
case *array.ArrayType:
|
||||
var start, end int64
|
||||
if start, end, err = verifyRange(indexTerm, indexList, int64(len(*unboxedValue))); err == nil {
|
||||
sublist := array.ArrayType((*unboxedValue)[start:end])
|
||||
v = &sublist
|
||||
}
|
||||
case *list.LinkedList:
|
||||
var start, end int64
|
||||
if start, end, err = verifyRange(indexTerm, indexList, int64(unboxedValue.Len())); err == nil {
|
||||
v = unboxedValue.Sub(start, end)
|
||||
}
|
||||
case string:
|
||||
var start, end int64
|
||||
if start, end, err = verifyRange(indexTerm, indexList, int64(len(unboxedValue))); err == nil {
|
||||
v = unboxedValue[start:end]
|
||||
}
|
||||
default:
|
||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
v, err = collectionItemByIndex(opTerm, leftValue, rightValue, indexList)
|
||||
} else if interval.IsInterval((*indexList)[0]) {
|
||||
v, err = subCollectionByIndex(opTerm, leftValue, rightValue, indexList)
|
||||
} else if dict.IsDict(leftValue) {
|
||||
d := leftValue.(*dict.DictType)
|
||||
v, err = getDictItem(d, indexTerm, indexList, rightValue)
|
||||
@@ -139,7 +104,126 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func getDictItem(d *dict.DictType, indexTerm *scan.Term, indexList *array.ArrayType, rightValue any) (v any, err error) {
|
||||
func collectionItemByIndex(opTerm kern.Term, leftValue, rightValue any, indexList *array.ArrayType) (v any, err error) {
|
||||
indexTerm := opTerm.GetChild(1)
|
||||
switch unboxedValue := leftValue.(type) {
|
||||
case *array.ArrayType:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(len(*unboxedValue))); err == nil {
|
||||
v = (*unboxedValue)[index]
|
||||
}
|
||||
case *list.LinkedList:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(unboxedValue.Len())); err == nil {
|
||||
v, err = unboxedValue.At(index)
|
||||
}
|
||||
case string:
|
||||
var index int64
|
||||
if index, err = verifyIndex(indexTerm, indexList, int64(len(unboxedValue))); err == nil {
|
||||
v = string(unboxedValue[index])
|
||||
}
|
||||
case *dict.DictType:
|
||||
v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue)
|
||||
default:
|
||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func subCollectionByIndex(opTerm kern.Term, leftValue, rightValue any, indexList *array.ArrayType) (v any, err error) {
|
||||
triple := (*indexList)[0].(*interval.IntervalType)
|
||||
switch unboxedValue := leftValue.(type) {
|
||||
case *array.ArrayType:
|
||||
v = intervalSubArray(unboxedValue, triple)
|
||||
case *list.LinkedList:
|
||||
v = intervalSubLinkedList(unboxedValue, triple)
|
||||
case string:
|
||||
v = intervalSubString(unboxedValue, triple)
|
||||
default:
|
||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fixInterval(p *interval.IntervalType, maxLength int) (b, e, s int) {
|
||||
b, e, s = p.ToIntTriple()
|
||||
if b < 0 {
|
||||
b = maxLength + b
|
||||
}
|
||||
if e < 0 {
|
||||
e = maxLength + e //+ 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func intervalSubString(source string, p *interval.IntervalType) (result string) {
|
||||
b, e, s := fixInterval(p, len(source))
|
||||
if b <= e {
|
||||
e = min(e, len(source))
|
||||
if s == 1 {
|
||||
result = source[b:e]
|
||||
} else {
|
||||
var sb strings.Builder
|
||||
for i := b; i < e; i += s {
|
||||
sb.WriteByte(source[i])
|
||||
}
|
||||
result = sb.String()
|
||||
}
|
||||
} else {
|
||||
var sb strings.Builder
|
||||
for i := b; i >= e; i -= s {
|
||||
sb.WriteByte(source[i])
|
||||
}
|
||||
result = sb.String()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func intervalSubArray(source *array.ArrayType, p *interval.IntervalType) (result *array.ArrayType) {
|
||||
var a array.ArrayType
|
||||
b, e, s := fixInterval(p, len(*source))
|
||||
if b <= e {
|
||||
e = min(e, len(*source))
|
||||
if s == 1 {
|
||||
a = (*source)[b:e]
|
||||
} else {
|
||||
size := (e-b)/s + 1
|
||||
a = make(array.ArrayType, 0, size)
|
||||
for i := b; i < e; i += s {
|
||||
a = append(a, (*source)[i])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
size := (b-e)/s + 1
|
||||
a = make(array.ArrayType, 0, size)
|
||||
for i := b; i > e; i -= s {
|
||||
a = append(a, (*source)[i])
|
||||
}
|
||||
}
|
||||
result = &a
|
||||
return
|
||||
}
|
||||
|
||||
func intervalSubLinkedList(source *list.LinkedList, p *interval.IntervalType) (result *list.LinkedList) {
|
||||
b, e, s := fixInterval(p, source.Len())
|
||||
revert := b > e
|
||||
if revert {
|
||||
b, e = e, b
|
||||
source = source.Revert()
|
||||
}
|
||||
e = min(e, source.Len())
|
||||
if s == 1 {
|
||||
result = source.Sub(int64(b), int64(e))
|
||||
} else {
|
||||
result = source.SubStep(int64(b), int64(e), int64(s))
|
||||
}
|
||||
if revert {
|
||||
source = source.Revert()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getDictItem(d *dict.DictType, indexTerm kern.Term, indexList *array.ArrayType, rightValue any) (v any, err error) {
|
||||
var ok bool
|
||||
var indexValue any
|
||||
|
||||
@@ -153,5 +237,5 @@ func getDictItem(d *dict.DictType, indexTerm *scan.Term, indexList *array.ArrayT
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymIndex, newIndexTerm)
|
||||
scan.RegisterTermConstructor(sym.SymIndex, newIndexTerm)
|
||||
}
|
||||
|
||||
+3
-2
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
)
|
||||
@@ -134,6 +135,6 @@ func evalAppend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymPlusGreater, newPrependTerm)
|
||||
scan.RegisterTermConstructor(scan.SymLessPlus, newAppendTerm)
|
||||
scan.RegisterTermConstructor(sym.SymPlusGreater, newPrependTerm)
|
||||
scan.RegisterTermConstructor(sym.SymLessPlus, newAppendTerm)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// operator-interval.go
|
||||
package expr
|
||||
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
"git.portale-stac.it/go-pkg/expr/types/interval"
|
||||
)
|
||||
|
||||
// -------- interval term
|
||||
|
||||
func newIntervalTerm(tk *scan.Token) (inst *scan.Term) {
|
||||
return &scan.Term{
|
||||
Tk: *tk,
|
||||
Children: make([]*scan.Term, 0, 2),
|
||||
Position: scan.PosInfix,
|
||||
Priority: scan.PriInterval,
|
||||
EvalFunc: evalInterval,
|
||||
}
|
||||
}
|
||||
|
||||
func changeColonToInterval(t *scan.Term) {
|
||||
if t.IsSymbol(sym.SymDoubleDot) {
|
||||
t.SetSymbol(sym.SymInterval)
|
||||
t.EvalFunc = evalInterval
|
||||
if child := t.GetLeftChild(); child != nil && child.IsSymbol(sym.SymDoubleDot) {
|
||||
child.SetSymbol(sym.SymInterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func evalInterval(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
var begin, end int64
|
||||
|
||||
step := int64(1)
|
||||
switch opTerm.GetChildCount() {
|
||||
case 0:
|
||||
begin = 0
|
||||
end = int64(kern.ConstLastIndex)
|
||||
case 1:
|
||||
var leftValue any
|
||||
if leftValue, err = opTerm.GetChild(0).Compute(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
if begin, err = checkIntervalComponent(opTerm, leftValue); err != nil {
|
||||
return
|
||||
}
|
||||
end = int64(kern.ConstLastIndex)
|
||||
default:
|
||||
var beginValue, endValue, stepValue any
|
||||
subTerm := opTerm.GetLeftChild()
|
||||
if subTerm.IsOneOf(sym.SymInterval, sym.SymDoubleDot) {
|
||||
if beginValue, endValue, err = subTerm.EvalInfix(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
if stepValue, err = opTerm.GetRightChild().Compute(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
step, err = checkIntervalComponent(opTerm.GetRightChild(), stepValue)
|
||||
} else if beginValue, endValue, err = opTerm.EvalInfix(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
if begin, err = checkIntervalComponent(opTerm, beginValue); err != nil {
|
||||
return
|
||||
}
|
||||
if end, err = checkIntervalComponent(opTerm, endValue); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if step <= 0 {
|
||||
err = opTerm.Errorf("invalid %s specification: step must be positive", interval.TypeName)
|
||||
} else {
|
||||
v = interval.NewInterval(begin, end, step)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkIntervalComponent(t kern.Term, value any) (component int64, err error) {
|
||||
if component, err = types.ToGoInt64(value, "%s expression"); err != nil {
|
||||
err = t.Errorf(err.Error(), interval.TypeName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func errIntervalInvalidSpecification(t kern.Term) error {
|
||||
return t.Errorf("invalid %s specification", interval.TypeName)
|
||||
}
|
||||
|
||||
func errIntervalUnexpectedExpression(t *scan.Term) error {
|
||||
return t.Errorf("unexpected %s expression", interval.TypeName)
|
||||
}
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(sym.SymInterval, newIntervalTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleDot, newIntervalTerm)
|
||||
}
|
||||
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
//-------- iter value term
|
||||
@@ -39,5 +40,5 @@ func evalIterValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
// init
|
||||
func init() {
|
||||
// registerTermConstructor(SymOpenClosedRound, newIterValueTerm)
|
||||
scan.RegisterTermConstructor(scan.SymDereference, newIterValueTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDereference, newIterValueTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
@@ -53,5 +54,5 @@ func evalLength(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymHash, newLengthTerm)
|
||||
scan.RegisterTermConstructor(sym.SymHash, newLengthTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
//-------- map term
|
||||
@@ -50,5 +51,5 @@ func evalMap(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwMap, newMapTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwMap, newMapTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
//-------- plugin term
|
||||
@@ -37,5 +38,5 @@ func evalPlugin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwPlugin, newPluginTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwPlugin, newPluginTerm)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
)
|
||||
|
||||
@@ -32,7 +33,7 @@ func evalPostInc(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
var namePrefix string
|
||||
v, err = it.Next()
|
||||
|
||||
if opTerm.Children[0].Symbol() == scan.SymVariable {
|
||||
if opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||
namePrefix = opTerm.Children[0].Source()
|
||||
}
|
||||
ctx.UnsafeSetVar(namePrefix+"_index", it.Index())
|
||||
@@ -50,7 +51,7 @@ func evalPostInc(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
ctx.UnsafeSetVar(namePrefix+"_value", v1)
|
||||
}
|
||||
}
|
||||
} else if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
|
||||
} else if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||
v = childValue
|
||||
i, _ := childValue.(int64)
|
||||
ctx.SetVar(opTerm.Children[0].Source(), i+1)
|
||||
@@ -80,7 +81,7 @@ func evalPostDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
/* if it, ok := childValue.(Iterator); ok {
|
||||
v, err = it.Next()
|
||||
} else */if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
|
||||
} else */if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||
v = childValue
|
||||
i, _ := childValue.(int64)
|
||||
ctx.SetVar(opTerm.Children[0].Source(), i-1)
|
||||
@@ -92,6 +93,6 @@ func evalPostDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymDoublePlus, newPostIncTerm)
|
||||
scan.RegisterTermConstructor(scan.SymDoubleMinus, newPostDecTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoublePlus, newPostIncTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleMinus, newPostDecTerm)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
)
|
||||
|
||||
@@ -28,7 +29,7 @@ func evalPreInc(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
|
||||
if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||
i := childValue.(int64) + 1
|
||||
ctx.SetVar(opTerm.Children[0].Source(), i)
|
||||
v = i
|
||||
@@ -57,7 +58,7 @@ func evalPreDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
|
||||
if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||
i := childValue.(int64) - 1
|
||||
ctx.SetVar(opTerm.Children[0].Source(), i)
|
||||
v = i
|
||||
@@ -69,6 +70,6 @@ func evalPreDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymPreInc, newPreIncTerm)
|
||||
scan.RegisterTermConstructor(scan.SymPreDec, newPreDecTerm)
|
||||
scan.RegisterTermConstructor(sym.SymPreInc, newPreIncTerm)
|
||||
scan.RegisterTermConstructor(sym.SymPreDec, newPreDecTerm)
|
||||
}
|
||||
|
||||
+5
-4
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||
@@ -201,8 +202,8 @@ func evalRemainder(ctx kern.ExprContext, remainderTerm *scan.Term) (v any, err e
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymStar, newMultiplyTerm)
|
||||
scan.RegisterTermConstructor(scan.SymSlash, newDivideTerm)
|
||||
scan.RegisterTermConstructor(scan.SymDotSlash, newDivideAsFloatTerm)
|
||||
scan.RegisterTermConstructor(scan.SymPercent, newRemainderTerm)
|
||||
scan.RegisterTermConstructor(sym.SymStar, newMultiplyTerm)
|
||||
scan.RegisterTermConstructor(sym.SymSlash, newDivideTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDotSlash, newDivideAsFloatTerm)
|
||||
scan.RegisterTermConstructor(sym.SymPercent, newRemainderTerm)
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// operator-range.go
|
||||
package expr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
)
|
||||
|
||||
// -------- range term
|
||||
type intPair struct {
|
||||
a, b int64
|
||||
}
|
||||
|
||||
func (p *intPair) TypeName() string {
|
||||
return kern.TypeIntPair
|
||||
}
|
||||
|
||||
func (p *intPair) ToString(opt kern.FmtOpt) string {
|
||||
return fmt.Sprintf("(%d, %d)", p.a, p.b)
|
||||
}
|
||||
|
||||
func isIntPair(v any) bool {
|
||||
_, ok := v.(*intPair)
|
||||
return ok
|
||||
}
|
||||
|
||||
func newRangeTerm(tk *scan.Token) (inst *scan.Term) {
|
||||
return &scan.Term{
|
||||
Tk: *tk,
|
||||
Children: make([]*scan.Term, 0, 2),
|
||||
Position: scan.PosInfix,
|
||||
Priority: scan.PriRange,
|
||||
EvalFunc: evalRange,
|
||||
}
|
||||
}
|
||||
|
||||
func changeColonToRange(t *scan.Term) {
|
||||
if t.Tk.IsSymbol(scan.SymColon) {
|
||||
t.Tk.Sym = scan.SymRange
|
||||
t.EvalFunc = evalRange
|
||||
}
|
||||
}
|
||||
|
||||
func evalRange(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
var leftValue, rightValue any
|
||||
|
||||
if len(opTerm.Children) == 0 {
|
||||
leftValue = int64(0)
|
||||
rightValue = int64(-1)
|
||||
} else if len(opTerm.Children) == 1 {
|
||||
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
rightValue = int64(kern.ConstLastIndex)
|
||||
} else if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
if !(types.IsInteger(leftValue) && types.IsInteger(rightValue)) {
|
||||
// err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||
err = errRangeInvalidSpecification(opTerm)
|
||||
return
|
||||
}
|
||||
|
||||
startIndex, _ := leftValue.(int64)
|
||||
endIndex, _ := rightValue.(int64)
|
||||
|
||||
v = &intPair{startIndex, endIndex}
|
||||
return
|
||||
}
|
||||
|
||||
func errRangeInvalidSpecification(t *scan.Term) error {
|
||||
return t.Errorf("invalid range specification")
|
||||
}
|
||||
|
||||
func errRangeUnexpectedExpression(t *scan.Term) error {
|
||||
return t.Errorf("unexpected range expression")
|
||||
}
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymRange, newRangeTerm)
|
||||
}
|
||||
+7
-6
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||
@@ -224,10 +225,10 @@ func evalGreaterEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymDoubleEqual, newEqualTerm)
|
||||
scan.RegisterTermConstructor(scan.SymNotEqual, newNotEqualTerm)
|
||||
scan.RegisterTermConstructor(scan.SymLess, newLessTerm)
|
||||
scan.RegisterTermConstructor(scan.SymLessOrEqual, newLessEqualTerm)
|
||||
scan.RegisterTermConstructor(scan.SymGreater, newGreaterTerm)
|
||||
scan.RegisterTermConstructor(scan.SymGreaterOrEqual, newGreaterEqualTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleEqual, newEqualTerm)
|
||||
scan.RegisterTermConstructor(sym.SymNotEqual, newNotEqualTerm)
|
||||
scan.RegisterTermConstructor(sym.SymLess, newLessTerm)
|
||||
scan.RegisterTermConstructor(sym.SymLessOrEqual, newLessEqualTerm)
|
||||
scan.RegisterTermConstructor(sym.SymGreater, newGreaterTerm)
|
||||
scan.RegisterTermConstructor(sym.SymGreaterOrEqual, newGreaterEqualTerm)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
//-------- selector term
|
||||
@@ -82,5 +83,5 @@ func evalSelector(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymSelector, newSelectorTerm)
|
||||
scan.RegisterTermConstructor(sym.SymSelector, newSelectorTerm)
|
||||
}
|
||||
|
||||
+3
-2
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
)
|
||||
|
||||
@@ -82,6 +83,6 @@ func evalLeftShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymDoubleGreater, newRightShiftTerm)
|
||||
scan.RegisterTermConstructor(scan.SymDoubleLess, newLeftShiftTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleGreater, newRightShiftTerm)
|
||||
scan.RegisterTermConstructor(sym.SymDoubleLess, newLeftShiftTerm)
|
||||
}
|
||||
|
||||
+5
-4
@@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||
)
|
||||
@@ -41,14 +42,14 @@ func evalSign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
}
|
||||
|
||||
if float.IsFloat(rightValue) {
|
||||
if opTerm.Tk.Sym == scan.SymChangeSign {
|
||||
if opTerm.Tk.Sym == sym.SymChangeSign {
|
||||
f, _ := rightValue.(float64)
|
||||
v = -f
|
||||
} else {
|
||||
v = rightValue
|
||||
}
|
||||
} else if types.IsInteger(rightValue) {
|
||||
if opTerm.Tk.Sym == scan.SymChangeSign {
|
||||
if opTerm.Tk.Sym == sym.SymChangeSign {
|
||||
i, _ := rightValue.(int64)
|
||||
v = -i
|
||||
} else {
|
||||
@@ -62,6 +63,6 @@ func evalSign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymUnchangeSign, newPlusSignTerm)
|
||||
scan.RegisterTermConstructor(scan.SymChangeSign, newMinusSignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymUnchangeSign, newPlusSignTerm)
|
||||
scan.RegisterTermConstructor(sym.SymChangeSign, newMinusSignTerm)
|
||||
}
|
||||
|
||||
+3
-2
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
@@ -139,6 +140,6 @@ func evalMinus(ctx kern.ExprContext, minusTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymPlus, newPlusTerm)
|
||||
scan.RegisterTermConstructor(scan.SymMinus, newMinusTerm)
|
||||
scan.RegisterTermConstructor(sym.SymPlus, newPlusTerm)
|
||||
scan.RegisterTermConstructor(sym.SymMinus, newMinusTerm)
|
||||
}
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
)
|
||||
|
||||
@@ -71,5 +72,5 @@ func evalUnset(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
scan.RegisterTermConstructor(scan.SymKwUnset, newUnsetTerm)
|
||||
scan.RegisterTermConstructor(sym.SymKwUnset, newUnsetTerm)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"slices"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
@@ -58,7 +59,7 @@ func NewParser() (p *parser) {
|
||||
}
|
||||
|
||||
func (parser *parser) Next(scanner *scan.Scanner) (tk *scan.Token) {
|
||||
for tk = scanner.Next(); tk.IsSymbol(scan.SymComment); tk = scanner.Next() {
|
||||
for tk = scanner.Next(); tk.IsSymbol(sym.SymComment); tk = scanner.Next() {
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -66,10 +67,10 @@ func (parser *parser) Next(scanner *scan.Scanner) (tk *scan.Token) {
|
||||
func (parser *parser) parseFuncCall(scanner *scan.Scanner, ctx parserContext, tk *scan.Token) (tree *scan.Term, err error) {
|
||||
args := make([]*scan.Term, 0, 10)
|
||||
itemExpected := false
|
||||
lastSym := scan.SymUnknown
|
||||
for lastSym != scan.SymClosedRound && lastSym != scan.SymEos {
|
||||
lastSym := sym.SymUnknown
|
||||
for lastSym != sym.SymClosedRound && lastSym != sym.SymEos {
|
||||
var subTree *scan.Ast
|
||||
if subTree, err = parser.parseItem(scanner, ctx, scan.SymComma, scan.SymClosedRound); err != nil {
|
||||
if subTree, err = parser.parseItem(scanner, ctx, sym.SymComma, sym.SymClosedRound); err != nil {
|
||||
break
|
||||
}
|
||||
prev := scanner.Previous()
|
||||
@@ -80,11 +81,11 @@ func (parser *parser) parseFuncCall(scanner *scan.Scanner, ctx parserContext, tk
|
||||
break
|
||||
}
|
||||
|
||||
itemExpected = prev.Sym == scan.SymComma
|
||||
itemExpected = prev.Sym == sym.SymComma
|
||||
lastSym = scanner.Previous().Sym
|
||||
}
|
||||
if err == nil {
|
||||
if lastSym != scan.SymClosedRound {
|
||||
if lastSym != sym.SymClosedRound {
|
||||
err = errors.New("unterminated arguments list")
|
||||
} else {
|
||||
tree = newFuncCallTerm(tk, args)
|
||||
@@ -97,13 +98,13 @@ func (parser *parser) parseFuncDef(scanner *scan.Scanner) (tree *scan.Term, err
|
||||
// Example: "add = func(x,y) {x+y}
|
||||
var body *scan.Ast
|
||||
args := make([]*scan.Term, 0)
|
||||
lastSym := scan.SymUnknown
|
||||
lastSym := sym.SymUnknown
|
||||
defaultParamsStarted := false
|
||||
itemExpected := false
|
||||
tk := scanner.Previous()
|
||||
for lastSym != scan.SymClosedRound && lastSym != scan.SymEos {
|
||||
for lastSym != sym.SymClosedRound && lastSym != sym.SymEos {
|
||||
tk = parser.Next(scanner)
|
||||
if tk.IsSymbol(scan.SymIdentifier) {
|
||||
if tk.IsSymbol(sym.SymIdentifier) {
|
||||
param := scan.NewTerm(tk)
|
||||
if len(args) > 0 {
|
||||
if pos := paramAlreadyDefined(args, param); pos > 0 {
|
||||
@@ -113,10 +114,10 @@ func (parser *parser) parseFuncDef(scanner *scan.Scanner) (tree *scan.Term, err
|
||||
}
|
||||
args = append(args, param)
|
||||
tk = parser.Next(scanner)
|
||||
if tk.Sym == scan.SymEqual {
|
||||
if tk.Sym == sym.SymEqual {
|
||||
var paramExpr *scan.Ast
|
||||
defaultParamsStarted = true
|
||||
if paramExpr, err = parser.parseItem(scanner, parserNoFlags, scan.SymComma, scan.SymClosedRound); err != nil {
|
||||
if paramExpr, err = parser.parseItem(scanner, parserNoFlags, sym.SymComma, sym.SymClosedRound); err != nil {
|
||||
break
|
||||
}
|
||||
param.ForceChild(paramExpr.Root())
|
||||
@@ -130,25 +131,25 @@ func (parser *parser) parseFuncDef(scanner *scan.Scanner) (tree *scan.Term, err
|
||||
break
|
||||
}
|
||||
lastSym = scanner.Previous().Sym
|
||||
itemExpected = lastSym == scan.SymComma
|
||||
itemExpected = lastSym == sym.SymComma
|
||||
}
|
||||
|
||||
if err == nil && lastSym != scan.SymClosedRound {
|
||||
if err == nil && lastSym != sym.SymClosedRound {
|
||||
err = tk.ErrorExpectedGot(")")
|
||||
}
|
||||
if err == nil {
|
||||
tk = parser.Next(scanner)
|
||||
if tk.IsSymbol(scan.SymOpenBrace) {
|
||||
body, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, scan.SymClosedBrace)
|
||||
if tk.IsSymbol(sym.SymOpenBrace) {
|
||||
body, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, sym.SymClosedBrace)
|
||||
} else {
|
||||
err = tk.ErrorExpectedGot("{")
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if scanner.Previous().Sym != scan.SymClosedBrace {
|
||||
if scanner.Previous().Sym != sym.SymClosedBrace {
|
||||
err = scanner.Previous().ErrorExpectedGot("}")
|
||||
} else {
|
||||
tk = scanner.MakeValueToken(scan.SymExpression, "", body)
|
||||
tk = scanner.MakeValueToken(sym.SymExpression, "", body)
|
||||
tree = newFuncDefTerm(tk, args)
|
||||
}
|
||||
}
|
||||
@@ -165,40 +166,40 @@ func paramAlreadyDefined(args []*scan.Term, param *scan.Term) (position int) {
|
||||
return
|
||||
}
|
||||
|
||||
func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSym scan.Symbol) (listTerm *scan.Term, err error) {
|
||||
func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSym sym.Symbol) (listTerm *scan.Term, err error) {
|
||||
r, c := scanner.LastPos()
|
||||
args := make([]*scan.Term, 0)
|
||||
lastSym := scan.SymUnknown
|
||||
lastSym := sym.SymUnknown
|
||||
itemExpected := false
|
||||
itemCtx := remFlags(ctx, allowIndex)
|
||||
for lastSym != termSym && lastSym != scan.SymEos {
|
||||
zeroRequired := scanner.Current().Sym == scan.SymColon
|
||||
for lastSym != termSym && lastSym != sym.SymEos {
|
||||
// zeroRequired := scanner.Current().Sym == sym.SymDoubleDot
|
||||
var itemTree *scan.Ast
|
||||
if itemTree, err = parser.parseItem(scanner, itemCtx, scan.SymComma, termSym); err == nil {
|
||||
if itemTree, err = parser.parseItem(scanner, itemCtx, sym.SymComma, termSym); err == nil {
|
||||
root := itemTree.Root()
|
||||
if root != nil {
|
||||
if hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymColon {
|
||||
changeColonToRange(root)
|
||||
if hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymDoubleDot {
|
||||
changeColonToInterval(root)
|
||||
}
|
||||
if !hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymRange {
|
||||
if !hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymInterval {
|
||||
// err = root.Errorf("unexpected range expression")
|
||||
err = errRangeUnexpectedExpression(root)
|
||||
err = errIntervalUnexpectedExpression(root)
|
||||
break
|
||||
}
|
||||
args = append(args, root)
|
||||
if hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymRange && zeroRequired { //len(root.children) == 0 {
|
||||
if len(root.Children) == 1 {
|
||||
root.Children = append(root.Children, root.Children[0])
|
||||
} else if len(root.Children) > 1 {
|
||||
// err = root.Errorf("invalid range specification")
|
||||
err = errRangeInvalidSpecification(root)
|
||||
break
|
||||
}
|
||||
zeroTk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), scan.SymInteger, "0", int64(0))
|
||||
zeroTerm := scan.NewTerm(zeroTk)
|
||||
zeroTerm.SetParent(root)
|
||||
root.Children[0] = zeroTerm
|
||||
}
|
||||
// if hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymInterval && zeroRequired { //len(root.children) == 0 {
|
||||
// if len(root.Children) == 1 {
|
||||
// root.Children = append(root.Children, root.Children[0])
|
||||
// } else if len(root.Children) > 1 {
|
||||
// // err = root.Errorf("invalid range specification")
|
||||
// err = errIntervalInvalidSpecification(root)
|
||||
// break
|
||||
// }
|
||||
// zeroTk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), sym.SymInteger, "0", int64(0))
|
||||
// zeroTerm := scan.NewTerm(zeroTk)
|
||||
// zeroTerm.SetParent(root)
|
||||
// root.Children[0] = zeroTerm
|
||||
// }
|
||||
} else if itemExpected {
|
||||
prev := scanner.Previous()
|
||||
err = prev.ErrorExpectedGot("list-item")
|
||||
@@ -208,16 +209,16 @@ func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSy
|
||||
break
|
||||
}
|
||||
lastSym = scanner.Previous().Sym
|
||||
if itemExpected = lastSym == scan.SymComma; itemExpected {
|
||||
if itemExpected = lastSym == sym.SymComma; itemExpected {
|
||||
remFlags(ctx, allowIndex)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if lastSym != termSym {
|
||||
err = scanner.Previous().ErrorExpectedGot("]")
|
||||
} else if termSym == scan.SymClosedSquare {
|
||||
} else if termSym == sym.SymClosedSquare {
|
||||
listTerm = newListTerm(r, c, args)
|
||||
} else if termSym == scan.SymGreaterClosedSquare {
|
||||
} else if termSym == sym.SymGreaterClosedSquare {
|
||||
listTerm = newLinkedListTerm(r, c, args)
|
||||
} else {
|
||||
err = fmt.Errorf("[%d:%d] unknown list type", r, c)
|
||||
@@ -229,11 +230,11 @@ func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSy
|
||||
func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (subtree *scan.Term, err error) {
|
||||
tk := scanner.Previous()
|
||||
args := make([]*scan.Term, 0)
|
||||
lastSym := scan.SymUnknown
|
||||
lastSym := sym.SymUnknown
|
||||
itemExpected := false
|
||||
for lastSym != scan.SymClosedRound && lastSym != scan.SymEos {
|
||||
for lastSym != sym.SymClosedRound && lastSym != sym.SymEos {
|
||||
var subTree *scan.Ast
|
||||
if subTree, err = parser.parseItem(scanner, ctx, scan.SymComma, scan.SymClosedRound); err == nil {
|
||||
if subTree, err = parser.parseItem(scanner, ctx, sym.SymComma, sym.SymClosedRound); err == nil {
|
||||
if subTree.Root() != nil {
|
||||
args = append(args, subTree.Root())
|
||||
} else if itemExpected {
|
||||
@@ -245,10 +246,10 @@ func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (su
|
||||
break
|
||||
}
|
||||
lastSym = scanner.Previous().Sym
|
||||
itemExpected = lastSym == scan.SymComma
|
||||
itemExpected = lastSym == sym.SymComma
|
||||
}
|
||||
if err == nil {
|
||||
if lastSym != scan.SymClosedRound {
|
||||
if lastSym != sym.SymClosedRound {
|
||||
err = scanner.Previous().ErrorExpectedGot(")")
|
||||
} else {
|
||||
subtree = newIteratorTerm(tk, args)
|
||||
@@ -259,16 +260,16 @@ func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (su
|
||||
|
||||
// func (parser *parser) parseDictKey(scanner *scan.Scanner) (key any, err error) {
|
||||
// tk := parser.Next(scanner)
|
||||
// if tk.Sym == scan.SymError {
|
||||
// if tk.Sym == sym.SymError {
|
||||
// err = tk.Error()
|
||||
// return
|
||||
// }
|
||||
// if tk.Sym == scan.SymClosedBrace || tk.Sym == scan.SymEos {
|
||||
// if tk.Sym == sym.SymClosedBrace || tk.Sym == sym.SymEos {
|
||||
// return
|
||||
// }
|
||||
// if tk.Sym == scan.SymInteger || tk.Sym == scan.SymString || tk.Sym == scan.SymIdentifier {
|
||||
// if tk.Sym == sym.SymInteger || tk.Sym == sym.SymString || tk.Sym == sym.SymIdentifier {
|
||||
// tkSep := parser.Next(scanner)
|
||||
// if tkSep.Sym != scan.SymColon {
|
||||
// if tkSep.Sym != sym.SymColon {
|
||||
// err = tkSep.ErrorExpectedGot(":")
|
||||
// } else {
|
||||
// key = tk.Value
|
||||
@@ -281,15 +282,15 @@ func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (su
|
||||
|
||||
func (parser *parser) parseDictKey(scanner *scan.Scanner) (key *scan.Term, err error) {
|
||||
var keyTree *scan.Ast
|
||||
if keyTree, err = parser.parseItem(scanner, parserNoFlags, scan.SymColon, scan.SymClosedBrace); err == nil {
|
||||
if keyTree, err = parser.parseItem(scanner, parserNoFlags, sym.SymColon, sym.SymClosedBrace); err == nil {
|
||||
key = keyTree.Root()
|
||||
tkSep := scanner.Previous()
|
||||
sym := tkSep.Sym
|
||||
if sym == scan.SymClosedBrace || sym == scan.SymEos {
|
||||
symbol := tkSep.Sym
|
||||
if symbol == sym.SymClosedBrace || symbol == sym.SymEos {
|
||||
if key != nil {
|
||||
err = tkSep.ErrorExpectedGot(":")
|
||||
}
|
||||
} else if sym != scan.SymColon {
|
||||
} else if symbol != sym.SymColon {
|
||||
err = tkSep.ErrorExpectedGot(":")
|
||||
}
|
||||
}
|
||||
@@ -298,9 +299,9 @@ func (parser *parser) parseDictKey(scanner *scan.Scanner) (key *scan.Term, err e
|
||||
|
||||
func (parser *parser) parseDictionary(scanner *scan.Scanner, ctx parserContext) (subtree *scan.Term, err error) {
|
||||
args := make(map[any]*scan.Term, 0)
|
||||
lastSym := scan.SymUnknown
|
||||
lastSym := sym.SymUnknown
|
||||
itemExpected := false
|
||||
for lastSym != scan.SymClosedBrace && lastSym != scan.SymEos {
|
||||
for lastSym != sym.SymClosedBrace && lastSym != sym.SymEos {
|
||||
var valueTree *scan.Ast
|
||||
var key any
|
||||
if key, err = parser.parseDictKey(scanner); err != nil {
|
||||
@@ -313,7 +314,7 @@ func (parser *parser) parseDictionary(scanner *scan.Scanner, ctx parserContext)
|
||||
}
|
||||
break
|
||||
}
|
||||
if valueTree, err = parser.parseItem(scanner, ctx, scan.SymComma, scan.SymClosedBrace); err == nil {
|
||||
if valueTree, err = parser.parseItem(scanner, ctx, sym.SymComma, sym.SymClosedBrace); err == nil {
|
||||
if valueTree.Root() != nil {
|
||||
args[key] = valueTree.Root()
|
||||
} else /*if key != nil*/ {
|
||||
@@ -325,10 +326,10 @@ func (parser *parser) parseDictionary(scanner *scan.Scanner, ctx parserContext)
|
||||
break
|
||||
}
|
||||
lastSym = scanner.Previous().Sym
|
||||
itemExpected = lastSym == scan.SymComma
|
||||
itemExpected = lastSym == sym.SymComma
|
||||
}
|
||||
if err == nil {
|
||||
if lastSym != scan.SymClosedBrace {
|
||||
if lastSym != sym.SymClosedBrace {
|
||||
err = scanner.Previous().ErrorExpectedGot("}")
|
||||
} else {
|
||||
subtree = newDictTerm(args)
|
||||
@@ -344,12 +345,12 @@ func (parser *parser) parseSelectorCase(scanner *scan.Scanner, ctx parserContext
|
||||
tk := parser.Next(scanner)
|
||||
startRow := tk.Row()
|
||||
startCol := tk.Col()
|
||||
if tk.Sym == scan.SymOpenSquare {
|
||||
if tk.Sym == sym.SymOpenSquare {
|
||||
if defaultCase {
|
||||
err = tk.Errorf("case list in default clause")
|
||||
return
|
||||
}
|
||||
if filterList, err = parser.parseList(scanner, remFlags(ctx, allowIndex), scan.SymClosedSquare); err != nil {
|
||||
if filterList, err = parser.parseList(scanner, remFlags(ctx, allowIndex), sym.SymClosedSquare); err != nil {
|
||||
return
|
||||
}
|
||||
tk = parser.Next(scanner)
|
||||
@@ -359,8 +360,8 @@ func (parser *parser) parseSelectorCase(scanner *scan.Scanner, ctx parserContext
|
||||
filterList = newListTerm(startRow, startCol, make([]*scan.Term, 0))
|
||||
}
|
||||
|
||||
if tk.Sym == scan.SymOpenBrace {
|
||||
if caseExpr, err = parser.parseGeneral(scanner, ctx|allowMultiExpr, scan.SymClosedBrace); err != nil {
|
||||
if tk.Sym == sym.SymOpenBrace {
|
||||
if caseExpr, err = parser.parseGeneral(scanner, ctx|allowMultiExpr, sym.SymClosedBrace); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -390,7 +391,7 @@ func (parser *parser) parseSelector(scanner *scan.Scanner, tree *scan.Ast, ctx p
|
||||
var caseTerm *scan.Term
|
||||
|
||||
ctx = remFlags(ctx, allowIndex)
|
||||
tk := scanner.MakeToken(scan.SymSelector, '?')
|
||||
tk := scanner.MakeToken(sym.SymSelector, '?')
|
||||
if selectorTerm, err = tree.AddToken(tk); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -401,11 +402,11 @@ func (parser *parser) parseSelector(scanner *scan.Scanner, tree *scan.Ast, ctx p
|
||||
return
|
||||
}
|
||||
|
||||
func (parser *parser) parseItem(scanner *scan.Scanner, ctx parserContext, termSymbols ...scan.Symbol) (tree *scan.Ast, err error) {
|
||||
func (parser *parser) parseItem(scanner *scan.Scanner, ctx parserContext, termSymbols ...sym.Symbol) (tree *scan.Ast, err error) {
|
||||
return parser.parseGeneral(scanner, ctx|allowVarRef, termSymbols...)
|
||||
}
|
||||
|
||||
func (parser *parser) Parse(scanner *scan.Scanner, termSymbols ...scan.Symbol) (tree *scan.Ast, err error) {
|
||||
func (parser *parser) Parse(scanner *scan.Scanner, termSymbols ...sym.Symbol) (tree *scan.Ast, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if errVal, ok := r.(error); ok {
|
||||
@@ -415,23 +416,23 @@ func (parser *parser) Parse(scanner *scan.Scanner, termSymbols ...scan.Symbol) (
|
||||
}
|
||||
}
|
||||
}()
|
||||
termSymbols = append(termSymbols, scan.SymEos)
|
||||
termSymbols = append(termSymbols, sym.SymEos)
|
||||
return parser.parseGeneral(scanner, allowMultiExpr, termSymbols...)
|
||||
}
|
||||
|
||||
func couldBeACollection(t *scan.Term) bool {
|
||||
var sym = scan.SymUnknown
|
||||
var symbol = sym.SymUnknown
|
||||
if t != nil {
|
||||
sym = t.Symbol()
|
||||
symbol = t.Symbol()
|
||||
}
|
||||
// return sym == scan.SymList || sym == scan.SymString || sym == scan.SymDict || sym == scan.SymExpression || sym == scan.SymVariable
|
||||
return slices.Contains([]scan.Symbol{scan.SymList, scan.SymLinkedList, scan.SymString, scan.SymDict, scan.SymExpression, scan.SymVariable, scan.SymIndex}, sym)
|
||||
// return sym == sym.SymList || sym == sym.SymString || sym == sym.SymDict || sym == sym.SymExpression || sym == sym.SymVariable
|
||||
return slices.Contains([]sym.Symbol{sym.SymList, sym.SymLinkedList, sym.SymString, sym.SymDict, sym.SymExpression, sym.SymVariable, sym.SymIndex}, symbol)
|
||||
}
|
||||
|
||||
func listSubTree(tree *scan.Ast, listTerm *scan.Term, allowIndeces bool) (root *scan.Term, err error) {
|
||||
var tk *scan.Token
|
||||
if allowIndeces {
|
||||
tk = scan.NewToken(listTerm.Tk.Row(), listTerm.Tk.Col(), scan.SymIndex, listTerm.Source())
|
||||
tk = scan.NewToken(listTerm.Tk.Row(), listTerm.Tk.Col(), sym.SymIndex, listTerm.Source())
|
||||
root = scan.NewTerm(tk)
|
||||
if err = tree.AddTerm(root); err == nil {
|
||||
err = tree.AddTerm(listTerm)
|
||||
@@ -445,22 +446,22 @@ func listSubTree(tree *scan.Ast, listTerm *scan.Term, allowIndeces bool) (root *
|
||||
|
||||
func changePrefix(tk *scan.Token) {
|
||||
switch tk.Sym {
|
||||
case scan.SymMinus:
|
||||
tk.SetSymbol(scan.SymChangeSign)
|
||||
case scan.SymPlus:
|
||||
tk.SetSymbol(scan.SymUnchangeSign)
|
||||
case scan.SymStar:
|
||||
tk.SetSymbol(scan.SymDereference)
|
||||
case scan.SymExclamation:
|
||||
tk.SetSymbol(scan.SymNot)
|
||||
case scan.SymDoublePlus:
|
||||
tk.SetSymbol(scan.SymPreInc)
|
||||
case scan.SymDoubleMinus:
|
||||
tk.SetSymbol(scan.SymPreDec)
|
||||
case sym.SymMinus:
|
||||
tk.SetSymbol(sym.SymChangeSign)
|
||||
case sym.SymPlus:
|
||||
tk.SetSymbol(sym.SymUnchangeSign)
|
||||
case sym.SymStar:
|
||||
tk.SetSymbol(sym.SymDereference)
|
||||
case sym.SymExclamation:
|
||||
tk.SetSymbol(sym.SymNot)
|
||||
case sym.SymDoublePlus:
|
||||
tk.SetSymbol(sym.SymPreInc)
|
||||
case sym.SymDoubleMinus:
|
||||
tk.SetSymbol(sym.SymPreDec)
|
||||
}
|
||||
}
|
||||
|
||||
func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, termSymbols ...scan.Symbol) (tree *scan.Ast, err error) {
|
||||
func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, termSymbols ...sym.Symbol) (tree *scan.Ast, err error) {
|
||||
var selectorTerm *scan.Term = nil
|
||||
var currentTerm *scan.Term = nil
|
||||
var tk *scan.Token
|
||||
@@ -473,7 +474,7 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
||||
// continue
|
||||
// }
|
||||
|
||||
if tk.Sym == scan.SymSemiColon {
|
||||
if tk.Sym == sym.SymSemiColon {
|
||||
if hasFlag(ctx, allowMultiExpr) {
|
||||
tree.ToForest()
|
||||
firstToken = true
|
||||
@@ -493,9 +494,9 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
||||
}
|
||||
|
||||
switch tk.Sym {
|
||||
case scan.SymOpenRound:
|
||||
case sym.SymOpenRound:
|
||||
var subTree *scan.Ast
|
||||
if subTree, err = parser.parseGeneral(scanner, ctx, scan.SymClosedRound); err == nil {
|
||||
if subTree, err = parser.parseGeneral(scanner, ctx, sym.SymClosedRound); err == nil {
|
||||
if subTree.Root() == nil {
|
||||
err = tk.ErrorExpectedGotString("expression", "()")
|
||||
} else {
|
||||
@@ -504,26 +505,26 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
||||
currentTerm = exprTerm
|
||||
}
|
||||
}
|
||||
case scan.SymFuncCall:
|
||||
case sym.SymFuncCall:
|
||||
var funcCallTerm *scan.Term
|
||||
if funcCallTerm, err = parser.parseFuncCall(scanner, ctx, tk); err == nil {
|
||||
err = tree.AddTerm(funcCallTerm)
|
||||
currentTerm = funcCallTerm
|
||||
}
|
||||
case scan.SymOpenSquare:
|
||||
case sym.SymOpenSquare:
|
||||
var listTerm *scan.Term
|
||||
newCtx := addFlagsCond(addFlags(ctx, squareContext), allowIndex, couldBeACollection(currentTerm))
|
||||
if listTerm, err = parser.parseList(scanner, newCtx, scan.SymClosedSquare); err == nil {
|
||||
if listTerm, err = parser.parseList(scanner, newCtx, sym.SymClosedSquare); err == nil {
|
||||
currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex))
|
||||
}
|
||||
case scan.SymOpenSquareLess:
|
||||
case sym.SymOpenSquareLess:
|
||||
var listTerm *scan.Term
|
||||
newCtx := addFlagsCond(addFlags(ctx, listContext), allowIndex, false)
|
||||
if listTerm, err = parser.parseList(scanner, newCtx, scan.SymGreaterClosedSquare); err == nil {
|
||||
if listTerm, err = parser.parseList(scanner, newCtx, sym.SymGreaterClosedSquare); err == nil {
|
||||
currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex))
|
||||
}
|
||||
case scan.SymOpenBrace:
|
||||
if currentTerm != nil && currentTerm.Symbol() == scan.SymColon {
|
||||
case sym.SymOpenBrace:
|
||||
if currentTerm != nil && currentTerm.Symbol() == sym.SymColon {
|
||||
err = currentTerm.Errorf(`selector-case outside of a selector context`)
|
||||
} else {
|
||||
var mapTerm *scan.Term
|
||||
@@ -532,54 +533,61 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
||||
currentTerm = mapTerm
|
||||
}
|
||||
}
|
||||
case scan.SymEqual, scan.SymPlusEqual, scan.SymMinusEqual, scan.SymStarEqual, scan.SymSlashEqual, scan.SymPercEqual, scan.SymAmpersandEqual, scan.SymVertBarEqual, scan.SymDoubleLessEqual, scan.SymDoubleGreaterEqual, scan.SymCaretEqual:
|
||||
case sym.SymEqual, sym.SymPlusEqual, sym.SymMinusEqual, sym.SymStarEqual, sym.SymSlashEqual, sym.SymPercEqual, sym.SymAmpersandEqual, sym.SymVertBarEqual, sym.SymDoubleLessEqual, sym.SymDoubleGreaterEqual, sym.SymCaretEqual:
|
||||
currentTerm, err = tree.AddToken(tk)
|
||||
firstToken = true
|
||||
case scan.SymFuncDef:
|
||||
case sym.SymFuncDef:
|
||||
var funcDefTerm *scan.Term
|
||||
if funcDefTerm, err = parser.parseFuncDef(scanner); err == nil {
|
||||
err = tree.AddTerm(funcDefTerm)
|
||||
currentTerm = funcDefTerm
|
||||
}
|
||||
case scan.SymDollarRound:
|
||||
case sym.SymDollarRound:
|
||||
var iterDefTerm *scan.Term
|
||||
if iterDefTerm, err = parser.parseIterDef(scanner, ctx); err == nil {
|
||||
err = tree.AddTerm(iterDefTerm)
|
||||
currentTerm = iterDefTerm
|
||||
}
|
||||
case scan.SymIdentifier:
|
||||
case sym.SymIdentifier:
|
||||
if tk.Source()[0] == '@' && !hasFlag(ctx, allowVarRef) {
|
||||
err = tk.Errorf("variable references are not allowed in top level expressions: %q", tk.Source())
|
||||
} else {
|
||||
currentTerm, err = tree.AddToken(tk)
|
||||
}
|
||||
case scan.SymQuestion:
|
||||
case sym.SymQuestion:
|
||||
if selectorTerm, err = parser.parseSelector(scanner, tree, ctx); err == nil {
|
||||
currentTerm = selectorTerm
|
||||
addFlags(ctx, selectorContext)
|
||||
}
|
||||
case scan.SymColon, scan.SymDoubleColon:
|
||||
case sym.SymColon, sym.SymDoubleColon:
|
||||
var caseTerm *scan.Term
|
||||
if selectorTerm != nil {
|
||||
if caseTerm, err = parser.parseSelectorCase(scanner, ctx, tk.Sym == scan.SymDoubleColon); err == nil {
|
||||
if caseTerm, err = parser.parseSelectorCase(scanner, ctx, tk.Sym == sym.SymDoubleColon); err == nil {
|
||||
addSelectorCase(selectorTerm, caseTerm)
|
||||
currentTerm = caseTerm
|
||||
if tk.Sym == scan.SymDoubleColon {
|
||||
if tk.Sym == sym.SymDoubleColon {
|
||||
selectorTerm = nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// err = tk.Errorf("colon outside a selector context")
|
||||
currentTerm, err = tree.AddToken(tk)
|
||||
if tk.IsOneOfA(scan.SymColon, scan.SymRange) {
|
||||
// Colon outside a selector term acts like a separator
|
||||
firstToken = true
|
||||
}
|
||||
// Colon outside a selector term acts like a separator
|
||||
firstToken = tk.IsOneOfA(sym.SymColon, sym.SymInterval)
|
||||
}
|
||||
case sym.SymDoubleDot:
|
||||
currentTerm, err = tree.AddToken(tk)
|
||||
if currentTerm.GetLeftChild() == nil {
|
||||
zeroTk := scan.NewValueToken(tk.Row(), tk.Col(), sym.SymInteger, "0", int64(0))
|
||||
tree.AddToken(zeroTk)
|
||||
}
|
||||
// Double dot acts like a separator
|
||||
firstToken = tk.IsOneOfA(sym.SymDoubleDot, sym.SymInterval)
|
||||
default:
|
||||
currentTerm, err = tree.AddToken(tk)
|
||||
}
|
||||
|
||||
if currentTerm != nil && currentTerm.Tk.Sym != scan.SymSelector && currentTerm.Parent != nil && currentTerm.Parent.Tk.Sym != scan.SymSelector {
|
||||
if currentTerm != nil && currentTerm.Tk.Sym != sym.SymSelector && currentTerm.Parent != nil && currentTerm.Parent.Tk.Sym != sym.SymSelector {
|
||||
selectorTerm = nil
|
||||
remFlags(ctx, selectorContext)
|
||||
}
|
||||
@@ -589,7 +597,7 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
||||
if err == nil {
|
||||
if !tk.IsOneOf(termSymbols) {
|
||||
var symDesc string
|
||||
if tk.IsSymbol(scan.SymError) {
|
||||
if tk.IsSymbol(sym.SymError) {
|
||||
symDesc = tk.ErrorText()
|
||||
} else {
|
||||
symDesc = scan.SymToString(tk.Sym)
|
||||
|
||||
+154
-127
@@ -12,20 +12,23 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/util"
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
current *Token
|
||||
prev *Token
|
||||
stage *Token
|
||||
stream *bufio.Reader
|
||||
row int
|
||||
column int
|
||||
translations map[Symbol]Symbol
|
||||
current *Token
|
||||
prev *Token
|
||||
stage *Token
|
||||
stream *bufio.Reader
|
||||
row int
|
||||
column int
|
||||
translations map[sym.Symbol]sym.Symbol
|
||||
unreadByte byte
|
||||
prevRowLength int
|
||||
}
|
||||
|
||||
func NewScanner(s io.Reader, translations map[Symbol]Symbol) (inst *Scanner) {
|
||||
func NewScanner(s io.Reader, translations map[sym.Symbol]sym.Symbol) (inst *Scanner) {
|
||||
inst = &Scanner{
|
||||
stream: bufio.NewReader(s),
|
||||
row: 1,
|
||||
@@ -36,15 +39,15 @@ func NewScanner(s io.Reader, translations map[Symbol]Symbol) (inst *Scanner) {
|
||||
return inst
|
||||
}
|
||||
|
||||
func DefaultTranslations() map[Symbol]Symbol {
|
||||
return map[Symbol]Symbol{
|
||||
SymDoubleAmpersand: SymAnd,
|
||||
SymKwAnd: SymAnd,
|
||||
SymDoubleVertBar: SymOr,
|
||||
SymKwOr: SymOr,
|
||||
// SymTilde: SymNot,
|
||||
SymKwNot: SymNot,
|
||||
SymLessGreater: SymNotEqual,
|
||||
func DefaultTranslations() map[sym.Symbol]sym.Symbol {
|
||||
return map[sym.Symbol]sym.Symbol{
|
||||
sym.SymDoubleAmpersand: sym.SymAnd,
|
||||
sym.SymKwAnd: sym.SymAnd,
|
||||
sym.SymDoubleVertBar: sym.SymOr,
|
||||
sym.SymKwOr: sym.SymOr,
|
||||
sym.SymKwNot: sym.SymNot,
|
||||
sym.SymLessGreater: sym.SymNotEqual,
|
||||
// SymTilde: sym.SymNot,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,9 +59,25 @@ func (scanner *Scanner) Current() *Token {
|
||||
return scanner.current
|
||||
}
|
||||
|
||||
func (scanner *Scanner) setUnreadChar(ch byte) {
|
||||
scanner.column--
|
||||
if scanner.column == 0 {
|
||||
scanner.column = scanner.prevRowLength
|
||||
scanner.row--
|
||||
}
|
||||
scanner.unreadByte = ch
|
||||
}
|
||||
|
||||
func (scanner *Scanner) readChar() (ch byte, err error) {
|
||||
if ch, err = scanner.stream.ReadByte(); err == nil {
|
||||
if scanner.unreadByte != 0 {
|
||||
ch = scanner.unreadByte
|
||||
scanner.unreadByte = 0
|
||||
} else {
|
||||
ch, err = scanner.stream.ReadByte()
|
||||
}
|
||||
if err == nil {
|
||||
if ch == '\n' {
|
||||
scanner.prevRowLength = scanner.column
|
||||
scanner.row++
|
||||
scanner.column = 0
|
||||
} else {
|
||||
@@ -127,237 +146,237 @@ func (scanner *Scanner) fetchNextToken() (tk *Token) {
|
||||
switch ch {
|
||||
case '+':
|
||||
if next, _ := scanner.peek(); next == '+' {
|
||||
tk = scanner.moveOn(SymDoublePlus, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoublePlus, ch, next)
|
||||
} else if next == '=' {
|
||||
tk = scanner.moveOn(SymPlusEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymPlusEqual, ch, next)
|
||||
} else if next == '>' {
|
||||
tk = scanner.moveOn(SymPlusGreater, ch, next)
|
||||
tk = scanner.moveOn(sym.SymPlusGreater, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymPlus, ch)
|
||||
tk = scanner.MakeToken(sym.SymPlus, ch)
|
||||
}
|
||||
case '-':
|
||||
if next, _ := scanner.peek(); next == '-' {
|
||||
tk = scanner.moveOn(SymDoubleMinus, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoubleMinus, ch, next)
|
||||
} else if next == '=' {
|
||||
tk = scanner.moveOn(SymMinusEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymMinusEqual, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymMinus, ch)
|
||||
tk = scanner.MakeToken(sym.SymMinus, ch)
|
||||
}
|
||||
case '*':
|
||||
if next, _ := scanner.peek(); next == '*' {
|
||||
tk = scanner.moveOn(SymDoubleStar, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoubleStar, ch, next)
|
||||
// } else if next == '/' {
|
||||
// tk = self.moveOn(SymClosedComment, ch, next)
|
||||
} else if next, _ = scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymStarEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymStarEqual, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymStar, ch)
|
||||
tk = scanner.MakeToken(sym.SymStar, ch)
|
||||
}
|
||||
case '/':
|
||||
if next, _ := scanner.peek(); next == '*' {
|
||||
scanner.readChar()
|
||||
tk = scanner.fetchBlockComment()
|
||||
} else if next, _ = scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymSlashEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymSlashEqual, ch, next)
|
||||
} else if next == '/' {
|
||||
scanner.readChar()
|
||||
tk = scanner.fetchOnLineComment()
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymSlash, ch)
|
||||
tk = scanner.MakeToken(sym.SymSlash, ch)
|
||||
}
|
||||
case '\\':
|
||||
if escape {
|
||||
tk = scanner.MakeToken(SymBackSlash, ch)
|
||||
tk = scanner.MakeToken(sym.SymBackSlash, ch)
|
||||
escape = false
|
||||
} else {
|
||||
escape = true
|
||||
}
|
||||
case '|':
|
||||
if next, _ := scanner.peek(); next == '|' {
|
||||
tk = scanner.moveOn(SymDoubleVertBar, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoubleVertBar, ch, next)
|
||||
} else if next, _ = scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymVertBarEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymVertBarEqual, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymVertBar, ch)
|
||||
tk = scanner.MakeToken(sym.SymVertBar, ch)
|
||||
}
|
||||
case ',':
|
||||
tk = scanner.MakeToken(SymComma, ch)
|
||||
tk = scanner.MakeToken(sym.SymComma, ch)
|
||||
case '^':
|
||||
if next, _ := scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymCaretEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymCaretEqual, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymCaret, ch)
|
||||
tk = scanner.MakeToken(sym.SymCaret, ch)
|
||||
}
|
||||
case ':':
|
||||
if next, _ := scanner.peek(); next == ':' {
|
||||
tk = scanner.moveOn(SymDoubleColon, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoubleColon, ch, next)
|
||||
} else if next == '=' {
|
||||
tk = scanner.moveOn(SymColonEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymColonEqual, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymColon, ch)
|
||||
tk = scanner.MakeToken(sym.SymColon, ch)
|
||||
}
|
||||
case ';':
|
||||
tk = scanner.MakeToken(SymSemiColon, ch)
|
||||
tk = scanner.MakeToken(sym.SymSemiColon, ch)
|
||||
case '.':
|
||||
//if next, _ := self.peek(); next >= '0' && next <= '9' {
|
||||
// tk = self.parseNumber(ch)
|
||||
//} else if next == '/' {
|
||||
if next, _ := scanner.peek(); next == '/' {
|
||||
tk = scanner.moveOn(SymDotSlash, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDotSlash, ch, next)
|
||||
} else if next == '.' {
|
||||
tk = scanner.moveOn(sym.SymDoubleDot, ch, next)
|
||||
// TODO: this section needs verification
|
||||
if next1, _ := scanner.peek(); next1 == '.' {
|
||||
tk = scanner.moveOn(SymTripleDot, ch, next, next1)
|
||||
} else {
|
||||
tk = scanner.moveOn(SymDoubleDot, ch, next)
|
||||
tk = scanner.moveOn(sym.SymTripleDot, next, next1)
|
||||
}
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymDot, ch)
|
||||
tk = scanner.MakeToken(sym.SymDot, ch)
|
||||
}
|
||||
case '\'':
|
||||
if escape {
|
||||
tk = scanner.MakeToken(SymQuote, ch)
|
||||
tk = scanner.MakeToken(sym.SymQuote, ch)
|
||||
escape = false
|
||||
} else {
|
||||
tk = scanner.fetchString(ch, true)
|
||||
}
|
||||
case '"':
|
||||
if escape {
|
||||
tk = scanner.MakeToken(SymDoubleQuote, ch)
|
||||
tk = scanner.MakeToken(sym.SymDoubleQuote, ch)
|
||||
escape = false
|
||||
} else {
|
||||
tk = scanner.fetchString(ch, true)
|
||||
}
|
||||
case '`':
|
||||
tk = scanner.MakeToken(SymBackTick, ch)
|
||||
tk = scanner.MakeToken(sym.SymBackTick, ch)
|
||||
case '!':
|
||||
if next, _ := scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymNotEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymNotEqual, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymExclamation, ch)
|
||||
tk = scanner.MakeToken(sym.SymExclamation, ch)
|
||||
}
|
||||
case '?':
|
||||
if next, _ := scanner.peek(); next == '?' {
|
||||
tk = scanner.moveOn(SymDoubleQuestion, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoubleQuestion, ch, next)
|
||||
} else if next == '=' {
|
||||
tk = scanner.moveOn(SymQuestionEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymQuestionEqual, ch, next)
|
||||
} else if next == '!' {
|
||||
tk = scanner.moveOn(SymQuestionExclam, ch, next)
|
||||
tk = scanner.moveOn(sym.SymQuestionExclam, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymQuestion, ch)
|
||||
tk = scanner.MakeToken(sym.SymQuestion, ch)
|
||||
}
|
||||
case '&':
|
||||
if next, _ := scanner.peek(); next == '&' {
|
||||
tk = scanner.moveOn(SymDoubleAmpersand, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoubleAmpersand, ch, next)
|
||||
} else if next, _ = scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymAmpersandEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymAmpersandEqual, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymAmpersand, ch)
|
||||
tk = scanner.MakeToken(sym.SymAmpersand, ch)
|
||||
}
|
||||
case '%':
|
||||
if next, _ := scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymPercEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymPercEqual, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymPercent, ch)
|
||||
tk = scanner.MakeToken(sym.SymPercent, ch)
|
||||
}
|
||||
case '#':
|
||||
tk = scanner.MakeToken(SymHash, ch)
|
||||
tk = scanner.MakeToken(sym.SymHash, ch)
|
||||
case '@':
|
||||
if next, _ := scanner.peek(); (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') {
|
||||
scanner.readChar()
|
||||
if tk = scanner.fetchIdentifier(next); tk.Sym == SymIdentifier {
|
||||
if tk = scanner.fetchIdentifier(next); tk.Sym == sym.SymIdentifier {
|
||||
//tk.Sym = SymIdRef
|
||||
tk.source = "@" + tk.source
|
||||
} else {
|
||||
tk = scanner.makeErrorToken(fmt.Errorf("invalid variable reference %q", tk.source))
|
||||
}
|
||||
} else if next == '@' {
|
||||
tk = scanner.moveOn(SymDoubleAt, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoubleAt, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymAt, ch)
|
||||
tk = scanner.MakeToken(sym.SymAt, ch)
|
||||
}
|
||||
case '_':
|
||||
tk = scanner.MakeToken(SymUndescore, ch)
|
||||
tk = scanner.MakeToken(sym.SymUndescore, ch)
|
||||
case '=':
|
||||
if next, _ := scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymDoubleEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoubleEqual, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymEqual, ch)
|
||||
tk = scanner.MakeToken(sym.SymEqual, ch)
|
||||
}
|
||||
case '<':
|
||||
if next, _ := scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymLessOrEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymLessOrEqual, ch, next)
|
||||
} else if next == '<' {
|
||||
scanner.readChar()
|
||||
next2, _ := scanner.readChar()
|
||||
scanner.unreadChar()
|
||||
if next2 == '=' {
|
||||
tk = scanner.moveOn(SymDoubleLessEqual, ch, next, next2)
|
||||
tk = scanner.moveOn(sym.SymDoubleLessEqual, ch, next, next2)
|
||||
} else {
|
||||
tk = scanner.accept(SymDoubleLess, ch, next)
|
||||
tk = scanner.accept(sym.SymDoubleLess, ch, next)
|
||||
}
|
||||
} else if next == '>' {
|
||||
tk = scanner.moveOn(SymLessGreater, ch, next)
|
||||
tk = scanner.moveOn(sym.SymLessGreater, ch, next)
|
||||
} else if next == '+' {
|
||||
tk = scanner.moveOn(SymLessPlus, ch, next)
|
||||
tk = scanner.moveOn(sym.SymLessPlus, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymLess, ch)
|
||||
tk = scanner.MakeToken(sym.SymLess, ch)
|
||||
}
|
||||
case '>':
|
||||
if next, _ := scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymGreaterOrEqual, ch, next)
|
||||
tk = scanner.moveOn(sym.SymGreaterOrEqual, ch, next)
|
||||
} else if next == '>' {
|
||||
scanner.readChar()
|
||||
next2, _ := scanner.readChar()
|
||||
scanner.unreadChar()
|
||||
if next2 == '=' {
|
||||
tk = scanner.moveOn(SymDoubleGreaterEqual, ch, next, next2)
|
||||
tk = scanner.moveOn(sym.SymDoubleGreaterEqual, ch, next, next2)
|
||||
} else {
|
||||
tk = scanner.accept(SymDoubleGreater, ch, next)
|
||||
tk = scanner.accept(sym.SymDoubleGreater, ch, next)
|
||||
}
|
||||
} else if next == ']' {
|
||||
tk = scanner.moveOn(SymGreaterClosedSquare, ch, next)
|
||||
tk = scanner.moveOn(sym.SymGreaterClosedSquare, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymGreater, ch)
|
||||
tk = scanner.MakeToken(sym.SymGreater, ch)
|
||||
}
|
||||
case '$':
|
||||
if next, _ := scanner.peek(); next == '(' {
|
||||
tk = scanner.moveOn(SymDollarRound, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDollarRound, ch, next)
|
||||
tk.source += ")"
|
||||
} else if next == '$' {
|
||||
tk = scanner.moveOn(SymDoubleDollar, ch, next)
|
||||
tk = scanner.moveOn(sym.SymDoubleDollar, ch, next)
|
||||
} else if next == '{' {
|
||||
scanner.readChar()
|
||||
if tk = scanner.fetchString('}', false); tk != nil {
|
||||
tk.Sym = SymIdentifier
|
||||
tk.Sym = sym.SymIdentifier
|
||||
}
|
||||
} else if next == '_' || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') {
|
||||
scanner.readChar()
|
||||
tk = scanner.fetchIdentifier(next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymDollar, ch)
|
||||
tk = scanner.MakeToken(sym.SymDollar, ch)
|
||||
}
|
||||
case '(':
|
||||
// if next, _ := scanner.peek(); next == ')' {
|
||||
// tk = scanner.moveOn(SymOpenClosedRound, ch, next)
|
||||
// } else {
|
||||
tk = scanner.MakeToken(SymOpenRound, ch)
|
||||
tk = scanner.MakeToken(sym.SymOpenRound, ch)
|
||||
// }
|
||||
case ')':
|
||||
tk = scanner.MakeToken(SymClosedRound, ch)
|
||||
tk = scanner.MakeToken(sym.SymClosedRound, ch)
|
||||
case '[':
|
||||
if next, _ := scanner.peek(); next == '<' {
|
||||
tk = scanner.moveOn(SymOpenSquareLess, ch, next)
|
||||
tk = scanner.moveOn(sym.SymOpenSquareLess, ch, next)
|
||||
} else {
|
||||
tk = scanner.MakeToken(SymOpenSquare, ch)
|
||||
tk = scanner.MakeToken(sym.SymOpenSquare, ch)
|
||||
}
|
||||
case ']':
|
||||
tk = scanner.MakeToken(SymClosedSquare, ch)
|
||||
tk = scanner.MakeToken(sym.SymClosedSquare, ch)
|
||||
case '{':
|
||||
tk = scanner.MakeToken(SymOpenBrace, ch)
|
||||
tk = scanner.MakeToken(sym.SymOpenBrace, ch)
|
||||
case '}':
|
||||
tk = scanner.MakeToken(SymClosedBrace, ch)
|
||||
tk = scanner.MakeToken(sym.SymClosedBrace, ch)
|
||||
case '~':
|
||||
tk = scanner.MakeToken(SymTilde, ch)
|
||||
tk = scanner.MakeToken(sym.SymTilde, ch)
|
||||
case 0:
|
||||
if escape {
|
||||
tk = scanner.makeErrorToken(errors.New("incomplete escape sequence"))
|
||||
@@ -365,9 +384,9 @@ func (scanner *Scanner) fetchNextToken() (tk *Token) {
|
||||
escape = false
|
||||
default:
|
||||
if /*ch == '_' ||*/ (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') {
|
||||
if tk = scanner.fetchIdentifier(ch); tk.Sym == SymKwFunc {
|
||||
if tk = scanner.fetchIdentifier(ch); tk.Sym == sym.SymKwFunc {
|
||||
if next, _ := scanner.peek(); next == '(' {
|
||||
tk = scanner.moveOn(SymFuncDef, ch, next)
|
||||
tk = scanner.moveOn(sym.SymFuncDef, ch, next)
|
||||
}
|
||||
}
|
||||
} else if ch >= '0' && ch <= '9' {
|
||||
@@ -415,19 +434,20 @@ func (scanner *Scanner) initBase(currentFirstCh byte) (firstCh byte, numBase int
|
||||
numBase = 10
|
||||
|
||||
if ch, err = scanner.peek(); err == nil {
|
||||
if ch == 'b' || ch == 'B' {
|
||||
switch ch {
|
||||
case 'b', 'B':
|
||||
numBase = 2
|
||||
digitType = "binary"
|
||||
scanner.readChar()
|
||||
digitFunc = isBinaryDigit
|
||||
firstCh, err = scanner.readChar()
|
||||
} else if ch == 'o' || ch == 'O' {
|
||||
case 'o', 'O':
|
||||
numBase = 8
|
||||
digitType = "octal"
|
||||
scanner.readChar()
|
||||
digitFunc = isOctalDigit
|
||||
firstCh, err = scanner.readChar()
|
||||
} else if ch == 'x' || ch == 'X' {
|
||||
case 'x', 'X':
|
||||
numBase = 16
|
||||
digitType = "hex"
|
||||
scanner.readChar()
|
||||
@@ -449,7 +469,7 @@ func (scanner *Scanner) initBase(currentFirstCh byte) (firstCh byte, numBase int
|
||||
func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
||||
var err error
|
||||
var ch byte
|
||||
var sym Symbol = SymInteger
|
||||
var symbol sym.Symbol = sym.SymInteger
|
||||
var sb strings.Builder
|
||||
var isDigit func(byte) bool = isDecimalDigit
|
||||
var numBase = 10
|
||||
@@ -463,18 +483,24 @@ func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
||||
|
||||
if numBase == 10 {
|
||||
if err == nil && ch == '.' {
|
||||
sym = SymFloat
|
||||
sb.WriteByte(ch)
|
||||
ch, err = scanner.readChar()
|
||||
if ch >= '0' && ch <= '9' {
|
||||
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = scanner.readChar() {
|
||||
sb.WriteByte(ch)
|
||||
if next, _ := scanner.peek(); next == '.' {
|
||||
// do nothing, this is an interval operator
|
||||
scanner.setUnreadChar('.')
|
||||
} else {
|
||||
symbol = sym.SymFloat
|
||||
sb.WriteByte(ch)
|
||||
ch, err = scanner.readChar()
|
||||
if ch >= '0' && ch <= '9' {
|
||||
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = scanner.readChar() {
|
||||
sb.WriteByte(ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if ch == 'e' || ch == 'E' {
|
||||
sym = SymFloat
|
||||
switch ch {
|
||||
case 'e', 'E':
|
||||
symbol = sym.SymFloat
|
||||
sb.WriteByte(ch)
|
||||
if ch, err = scanner.readChar(); err == nil {
|
||||
if ch == '+' || ch == '-' {
|
||||
@@ -489,8 +515,8 @@ func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
||||
err = fmt.Errorf("[%d:%d] expected integer exponent, got %c", scanner.row, scanner.column, ch)
|
||||
}
|
||||
}
|
||||
} else if ch == '(' {
|
||||
sym = SymFraction
|
||||
case '(':
|
||||
symbol = sym.SymFraction
|
||||
sb.WriteByte(ch)
|
||||
ch, err = scanner.readChar()
|
||||
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = scanner.readChar() {
|
||||
@@ -514,15 +540,16 @@ func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
||||
var value any
|
||||
_ = scanner.sync(err) // TODO: Check this function
|
||||
txt := sb.String()
|
||||
if sym == SymFloat {
|
||||
switch symbol {
|
||||
case sym.SymFloat:
|
||||
value, err = strconv.ParseFloat(txt, 64)
|
||||
} else if sym == SymFraction {
|
||||
case sym.SymFraction:
|
||||
// value, err = kern.MakeGeneratingFraction(txt)
|
||||
value = txt
|
||||
} else {
|
||||
default:
|
||||
value, err = strconv.ParseInt(txt, numBase, 64)
|
||||
}
|
||||
tk = scanner.MakeValueToken(sym, txt, value)
|
||||
tk = scanner.MakeValueToken(symbol, txt, value)
|
||||
// if err == nil {
|
||||
// tk = scanner.MakeValueToken(sym, txt, value)
|
||||
// } else {
|
||||
@@ -546,17 +573,17 @@ func (scanner *Scanner) fetchIdentifier(firstCh byte) (tk *Token) {
|
||||
} else {
|
||||
txt := sb.String()
|
||||
uptxt := strings.ToUpper(txt)
|
||||
if sym, ok := keywords[uptxt]; ok {
|
||||
tk = scanner.makeKeywordToken(sym, uptxt)
|
||||
if symbol, ok := sym.Keywords[uptxt]; ok {
|
||||
tk = scanner.makeKeywordToken(symbol, uptxt)
|
||||
} else if uptxt == `TRUE` {
|
||||
tk = scanner.MakeValueToken(SymBool, txt, true)
|
||||
tk = scanner.MakeValueToken(sym.SymBool, txt, true)
|
||||
} else if uptxt == `FALSE` {
|
||||
tk = scanner.MakeValueToken(SymBool, txt, false)
|
||||
tk = scanner.MakeValueToken(sym.SymBool, txt, false)
|
||||
} else if ch, _ := scanner.peek(); ch == '(' {
|
||||
scanner.readChar()
|
||||
tk = scanner.MakeValueToken(SymFuncCall, txt+"(", txt)
|
||||
tk = scanner.MakeValueToken(sym.SymFuncCall, txt+"(", txt)
|
||||
} else {
|
||||
tk = scanner.MakeValueToken(SymIdentifier, txt, txt)
|
||||
tk = scanner.MakeValueToken(sym.SymIdentifier, txt, txt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,14 +604,14 @@ func (scanner *Scanner) fetchIdentifier(firstCh byte) (tk *Token) {
|
||||
}
|
||||
|
||||
func (scanner *Scanner) fetchBlockComment() *Token {
|
||||
return scanner.fetchUntil(SymComment, false, '*', '/')
|
||||
return scanner.fetchUntil(sym.SymComment, false, '*', '/')
|
||||
}
|
||||
|
||||
func (scanner *Scanner) fetchOnLineComment() *Token {
|
||||
return scanner.fetchUntil(SymComment, true, '\n')
|
||||
return scanner.fetchUntil(sym.SymComment, true, '\n')
|
||||
}
|
||||
|
||||
func (scanner *Scanner) fetchUntil(sym Symbol, allowEos bool, endings ...byte) (tk *Token) {
|
||||
func (scanner *Scanner) fetchUntil(sym sym.Symbol, allowEos bool, endings ...byte) (tk *Token) {
|
||||
var err error
|
||||
var ch byte
|
||||
var sb strings.Builder
|
||||
@@ -653,9 +680,9 @@ func (scanner *Scanner) fetchString(termCh byte, addQuote bool) (tk *Token) {
|
||||
} else {
|
||||
txt := sb.String()
|
||||
if addQuote {
|
||||
tk = scanner.MakeValueToken(SymString, `"`+txt+`"`, txt)
|
||||
tk = scanner.MakeValueToken(sym.SymString, `"`+txt+`"`, txt)
|
||||
} else {
|
||||
tk = scanner.MakeValueToken(SymString, txt, txt)
|
||||
tk = scanner.MakeValueToken(sym.SymString, txt, txt)
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -677,7 +704,7 @@ func (scanner *Scanner) skipBlanks() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (scanner *Scanner) translate(sym Symbol) Symbol {
|
||||
func (scanner *Scanner) translate(sym sym.Symbol) sym.Symbol {
|
||||
if scanner.translations != nil {
|
||||
if translatedSym, ok := scanner.translations[sym]; ok {
|
||||
return translatedSym
|
||||
@@ -686,7 +713,7 @@ func (scanner *Scanner) translate(sym Symbol) Symbol {
|
||||
return sym
|
||||
}
|
||||
|
||||
func (scanner *Scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
|
||||
func (scanner *Scanner) moveOn(sym sym.Symbol, chars ...byte) (tk *Token) {
|
||||
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
|
||||
// for i := 1; i < len(chars); i++ {
|
||||
if len(chars) > 1 {
|
||||
@@ -696,22 +723,22 @@ func (scanner *Scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
|
||||
return
|
||||
}
|
||||
|
||||
func (scanner *Scanner) accept(sym Symbol, chars ...byte) (tk *Token) {
|
||||
func (scanner *Scanner) accept(sym sym.Symbol, chars ...byte) (tk *Token) {
|
||||
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
|
||||
return
|
||||
}
|
||||
|
||||
func (scanner *Scanner) MakeToken(sym Symbol, chars ...byte) (tk *Token) {
|
||||
func (scanner *Scanner) MakeToken(sym sym.Symbol, chars ...byte) (tk *Token) {
|
||||
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
|
||||
return
|
||||
}
|
||||
|
||||
func (scanner *Scanner) makeKeywordToken(sym Symbol, upperCaseKeyword string) (tk *Token) {
|
||||
func (scanner *Scanner) makeKeywordToken(sym sym.Symbol, upperCaseKeyword string) (tk *Token) {
|
||||
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), upperCaseKeyword)
|
||||
return
|
||||
}
|
||||
|
||||
func (scanner *Scanner) MakeValueToken(sym Symbol, source string, value any) (tk *Token) {
|
||||
func (scanner *Scanner) MakeValueToken(sym sym.Symbol, source string, value any) (tk *Token) {
|
||||
tk = NewValueToken(scanner.row, scanner.column, scanner.translate(sym), source, value)
|
||||
return
|
||||
}
|
||||
|
||||
+132
-130
@@ -1,14 +1,16 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// Symbol.go
|
||||
// symbol-map.go
|
||||
package scan
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
var symbolMap map[Symbol]symbolSpec
|
||||
var symbolMap map[sym.Symbol]symbolSpec
|
||||
|
||||
type SymbolClass int16
|
||||
|
||||
@@ -31,139 +33,139 @@ type symbolSpec struct {
|
||||
|
||||
func init() {
|
||||
|
||||
symbolMap = map[Symbol]symbolSpec{
|
||||
SymUnknown: {"<unknown>", SymClassOther, PosLeaf}, // -1: Unknown symbol
|
||||
SymNone: {"<null>", SymClassOther, PosLeaf}, // 0: Null value for variable of type symbol
|
||||
SymError: {"<error>", SymClassOther, PosLeaf}, // 1: Error reading from stream
|
||||
SymEos: {"<eos>", SymClassOther, PosLeaf}, // 2: End of stream
|
||||
SymMinus: {"-", SymClassOperator, PosInfix}, // 3: '-'
|
||||
SymMinusEqual: {"-=", SymClassOperator, PosInfix}, // 4: '-='
|
||||
SymDoubleMinus: {"--", SymClassOperator, PosPostfix}, // 5: '--'
|
||||
SymPlus: {"+", SymClassOperator, PosInfix}, // 6: '+'
|
||||
SymPlusEqual: {"+=", SymClassOperator, PosInfix}, // 7: '+='
|
||||
SymDoublePlus: {"++", SymClassOperator, PosPostfix}, // 8: '++'
|
||||
SymStar: {"*", SymClassOperator, PosInfix}, // 9: '*'
|
||||
SymDoubleStar: {"**", SymClassOperator, PosInfix}, // 10: '**'
|
||||
SymSlash: {"/", SymClassOperator, PosInfix}, // 11: '/'
|
||||
SymBackSlash: {"\\", SymClassOperator, PosLeaf}, // 12: '\'
|
||||
SymVertBar: {"|", SymClassOperator, PosInfix}, // 13: '|'
|
||||
SymDoubleVertBar: {"||", SymClassOperator, PosInfix}, // 14: '||'
|
||||
SymComma: {",", SymClassOperator, PosInfix}, // 15: ','
|
||||
SymColon: {":", SymClassOperator, PosInfix}, // 16: ':'
|
||||
SymSemiColon: {";", SymClassOperator, PosInfix}, // 17: ';'
|
||||
SymDot: {".", SymClassOperator, PosInfix}, // 18: '.'
|
||||
SymDotSlash: {"./", SymClassOperator, PosInfix}, // 19: './'
|
||||
SymQuote: {"'", SymClassDelimiter, PosLeaf}, // 20: '\''
|
||||
SymDoubleQuote: {"\"", SymClassDelimiter, PosLeaf}, // 21: '"'
|
||||
SymBackTick: {"`", SymClassDelimiter, PosLeaf}, // 22: '`'
|
||||
SymExclamation: {"!", SymClassOperator, PosPostfix}, // 23: '!'
|
||||
SymQuestion: {"?", SymClassOperator, PosInfix}, // 24: '?'
|
||||
SymAmpersand: {"&", SymClassOperator, PosInfix}, // 25: '&'
|
||||
SymDoubleAmpersand: {"&&", SymClassOperator, PosInfix}, // 26: '&&'
|
||||
SymPercent: {"%", SymClassOperator, PosInfix}, // 27: '%'
|
||||
SymAt: {"@", SymClassOperator, PosPrefix}, // 28: '@'
|
||||
SymUndescore: {"_", SymClassIdentifier, PosLeaf}, // 29: '_'
|
||||
SymEqual: {"=", SymClassOperator, PosInfix}, // 30: '='
|
||||
SymColonEqual: {":=", SymClassOperator, PosInfix}, // 31: ':='
|
||||
SymDoubleEqual: {"==", SymClassOperator, PosInfix}, // 32: '=='
|
||||
SymLess: {"<", SymClassOperator, PosInfix}, // 33: '<'
|
||||
SymLessOrEqual: {"<=", SymClassOperator, PosInfix}, // 34: '<='
|
||||
SymGreater: {">", SymClassOperator, PosInfix}, // 35: '>'
|
||||
SymGreaterOrEqual: {">=", SymClassOperator, PosInfix}, // 36: '>='
|
||||
SymLessGreater: {"<>", SymClassOperator, PosInfix}, // 37: '<>'
|
||||
SymNotEqual: {"!=", SymClassOperator, PosInfix}, // 38: '!='
|
||||
SymDollar: {"$", SymClassOperator, PosPrefix}, // 39: '$'
|
||||
SymHash: {"#", SymClassOperator, PosPrefix}, // 40: '#'
|
||||
SymOpenRound: {"(", SymClassParenthesis, PosPrefix}, // 41: '('
|
||||
SymClosedRound: {")", SymClassParenthesis, PosPostfix}, // 42: ')'
|
||||
SymOpenSquare: {"[", SymClassParenthesis, PosPrefix}, // 43: '['
|
||||
SymClosedSquare: {"]", SymClassParenthesis, PosPostfix}, // 44: ']'
|
||||
SymOpenBrace: {"{", SymClassParenthesis, PosPrefix}, // 45: '{'
|
||||
SymClosedBrace: {"}", SymClassParenthesis, PosPostfix}, // 46: '}'
|
||||
SymTilde: {"~", SymClassOperator, PosPrefix}, // 47: '~'
|
||||
SymDoubleQuestion: {"??", SymClassOperator, PosInfix}, // 48: '??'
|
||||
SymQuestionEqual: {"?=", SymClassOperator, PosInfix}, // 49: '?='
|
||||
SymQuestionExclam: {"?!", SymClassOperator, PosInfix}, // 50: '?!'
|
||||
SymDoubleAt: {"@@", SymClassCommand, PosLeaf}, // 51: '@@'
|
||||
SymDoubleColon: {"::", SymClassOperator, PosInfix}, // 52: '::'
|
||||
SymDoubleGreater: {">>", SymClassOperator, PosInfix}, // 53: '>>'
|
||||
SymDoubleLess: {"<<", SymClassOperator, PosInfix}, // 54: '<<'
|
||||
SymCaret: {"^", SymClassOperator, PosInfix}, // 55: '^'
|
||||
SymDollarRound: {"$(", SymClassOperator, PosPrefix}, // 56: '$('
|
||||
SymOpenClosedRound: {"()", SymClassOperator, PosPostfix}, // 57: '()'
|
||||
SymDoubleDollar: {"$$", SymClassCommand, PosLeaf}, // 58: '$$'
|
||||
SymDoubleDot: {"..", SymClassOperator, PosInfix}, // 59: '..'
|
||||
SymTripleDot: {"...", SymClassOperator, PosPostfix}, // 60: '...'
|
||||
SymStarEqual: {"*=", SymClassOperator, PosInfix}, // 61: '*='
|
||||
SymSlashEqual: {"/=", SymClassOperator, PosInfix}, // 62: '/='
|
||||
SymPercEqual: {"%=", SymClassOperator, PosInfix}, // 63: '%='
|
||||
SymDoubleLessEqual: {"<<=", SymClassOperator, PosInfix}, // 64: '<<='
|
||||
SymDoubleGreaterEqual: {">>=", SymClassOperator, PosInfix}, // 65: '>>='
|
||||
SymAmpersandEqual: {"&=", SymClassOperator, PosInfix}, // 66: '&='
|
||||
SymVertBarEqual: {"|=", SymClassOperator, PosInfix}, // 67: '|='
|
||||
SymCaretEqual: {"^=", SymClassOperator, PosInfix}, // 68: '^='
|
||||
SymPlusGreater: {"+>", SymClassOperator, PosInfix}, // 69: '+>'
|
||||
SymLessPlus: {"<+", SymClassOperator, PosInfix}, // 70: '<+'
|
||||
SymPreInc: {"++", SymClassOperator, PosPrefix}, // 71: '++'
|
||||
SymPreDec: {"--", SymClassOperator, PosPrefix}, // 72: '--'
|
||||
SymOpenSquareLess: {"[<", SymClassOperator, PosPrefix}, // 97: '[<'
|
||||
SymGreaterClosedSquare: {">]", SymClassOperator, PosPostfix}, // 98: '>]'
|
||||
// SymChangeSign
|
||||
// SymUnchangeSign
|
||||
// SymIdentifier
|
||||
// SymBool
|
||||
// SymInteger
|
||||
// SymVariable
|
||||
// SymFloat
|
||||
// SymFraction
|
||||
// SymString
|
||||
// SymIterator
|
||||
// SymOr: "or",
|
||||
// SymAnd: "and",
|
||||
// SymNot: "not",
|
||||
// SymComment
|
||||
// SymFuncCall
|
||||
// SymFuncDef
|
||||
// SymList
|
||||
// SymLinkedList
|
||||
// SymDict
|
||||
// SymIndex
|
||||
// SymExpression
|
||||
// SymSelector // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
||||
// SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
||||
// // SymOpenComment // 0: '/*'
|
||||
// // SymClosedComment // 0: '*/'
|
||||
// // SymOneLineComment // 0: '//'
|
||||
symbolMap = map[sym.Symbol]symbolSpec{
|
||||
sym.SymUnknown: {"<unknown>", SymClassOther, PosLeaf}, // -1: Unknown symbol
|
||||
sym.SymNone: {"<null>", SymClassOther, PosLeaf}, // 0: Null value for variable of type symbol
|
||||
sym.SymError: {"<error>", SymClassOther, PosLeaf}, // 1: Error reading from stream
|
||||
sym.SymEos: {"<eos>", SymClassOther, PosLeaf}, // 2: End of stream
|
||||
sym.SymMinus: {"-", SymClassOperator, PosInfix}, // 3: '-'
|
||||
sym.SymMinusEqual: {"-=", SymClassOperator, PosInfix}, // 4: '-='
|
||||
sym.SymDoubleMinus: {"--", SymClassOperator, PosPostfix}, // 5: '--'
|
||||
sym.SymPlus: {"+", SymClassOperator, PosInfix}, // 6: '+'
|
||||
sym.SymPlusEqual: {"+=", SymClassOperator, PosInfix}, // 7: '+='
|
||||
sym.SymDoublePlus: {"++", SymClassOperator, PosPostfix}, // 8: '++'
|
||||
sym.SymStar: {"*", SymClassOperator, PosInfix}, // 9: '*'
|
||||
sym.SymDoubleStar: {"**", SymClassOperator, PosInfix}, // 10: '**'
|
||||
sym.SymSlash: {"/", SymClassOperator, PosInfix}, // 11: '/'
|
||||
sym.SymBackSlash: {"\\", SymClassOperator, PosLeaf}, // 12: '\'
|
||||
sym.SymVertBar: {"|", SymClassOperator, PosInfix}, // 13: '|'
|
||||
sym.SymDoubleVertBar: {"||", SymClassOperator, PosInfix}, // 14: '||'
|
||||
sym.SymComma: {",", SymClassOperator, PosInfix}, // 15: ','
|
||||
sym.SymColon: {":", SymClassOperator, PosInfix}, // 16: ':'
|
||||
sym.SymSemiColon: {";", SymClassOperator, PosInfix}, // 17: ';'
|
||||
sym.SymDot: {".", SymClassOperator, PosInfix}, // 18: '.'
|
||||
sym.SymDotSlash: {"./", SymClassOperator, PosInfix}, // 19: './'
|
||||
sym.SymQuote: {"'", SymClassDelimiter, PosLeaf}, // 20: '\''
|
||||
sym.SymDoubleQuote: {"\"", SymClassDelimiter, PosLeaf}, // 21: '"'
|
||||
sym.SymBackTick: {"`", SymClassDelimiter, PosLeaf}, // 22: '`'
|
||||
sym.SymExclamation: {"!", SymClassOperator, PosPostfix}, // 23: '!'
|
||||
sym.SymQuestion: {"?", SymClassOperator, PosInfix}, // 24: '?'
|
||||
sym.SymAmpersand: {"&", SymClassOperator, PosInfix}, // 25: '&'
|
||||
sym.SymDoubleAmpersand: {"&&", SymClassOperator, PosInfix}, // 26: '&&'
|
||||
sym.SymPercent: {"%", SymClassOperator, PosInfix}, // 27: '%'
|
||||
sym.SymAt: {"@", SymClassOperator, PosPrefix}, // 28: '@'
|
||||
sym.SymUndescore: {"_", SymClassIdentifier, PosLeaf}, // 29: '_'
|
||||
sym.SymEqual: {"=", SymClassOperator, PosInfix}, // 30: '='
|
||||
sym.SymColonEqual: {":=", SymClassOperator, PosInfix}, // 31: ':='
|
||||
sym.SymDoubleEqual: {"==", SymClassOperator, PosInfix}, // 32: '=='
|
||||
sym.SymLess: {"<", SymClassOperator, PosInfix}, // 33: '<'
|
||||
sym.SymLessOrEqual: {"<=", SymClassOperator, PosInfix}, // 34: '<='
|
||||
sym.SymGreater: {">", SymClassOperator, PosInfix}, // 35: '>'
|
||||
sym.SymGreaterOrEqual: {">=", SymClassOperator, PosInfix}, // 36: '>='
|
||||
sym.SymLessGreater: {"<>", SymClassOperator, PosInfix}, // 37: '<>'
|
||||
sym.SymNotEqual: {"!=", SymClassOperator, PosInfix}, // 38: '!='
|
||||
sym.SymDollar: {"$", SymClassOperator, PosPrefix}, // 39: '$'
|
||||
sym.SymHash: {"#", SymClassOperator, PosPrefix}, // 40: '#'
|
||||
sym.SymOpenRound: {"(", SymClassParenthesis, PosPrefix}, // 41: '('
|
||||
sym.SymClosedRound: {")", SymClassParenthesis, PosPostfix}, // 42: ')'
|
||||
sym.SymOpenSquare: {"[", SymClassParenthesis, PosPrefix}, // 43: '['
|
||||
sym.SymClosedSquare: {"]", SymClassParenthesis, PosPostfix}, // 44: ']'
|
||||
sym.SymOpenBrace: {"{", SymClassParenthesis, PosPrefix}, // 45: '{'
|
||||
sym.SymClosedBrace: {"}", SymClassParenthesis, PosPostfix}, // 46: '}'
|
||||
sym.SymTilde: {"~", SymClassOperator, PosPrefix}, // 47: '~'
|
||||
sym.SymDoubleQuestion: {"??", SymClassOperator, PosInfix}, // 48: '??'
|
||||
sym.SymQuestionEqual: {"?=", SymClassOperator, PosInfix}, // 49: '?='
|
||||
sym.SymQuestionExclam: {"?!", SymClassOperator, PosInfix}, // 50: '?!'
|
||||
sym.SymDoubleAt: {"@@", SymClassCommand, PosLeaf}, // 51: '@@'
|
||||
sym.SymDoubleColon: {"::", SymClassOperator, PosInfix}, // 52: '::'
|
||||
sym.SymDoubleGreater: {">>", SymClassOperator, PosInfix}, // 53: '>>'
|
||||
sym.SymDoubleLess: {"<<", SymClassOperator, PosInfix}, // 54: '<<'
|
||||
sym.SymCaret: {"^", SymClassOperator, PosInfix}, // 55: '^'
|
||||
sym.SymDollarRound: {"$(", SymClassOperator, PosPrefix}, // 56: '$('
|
||||
sym.SymOpenClosedRound: {"()", SymClassOperator, PosPostfix}, // 57: '()'
|
||||
sym.SymDoubleDollar: {"$$", SymClassCommand, PosLeaf}, // 58: '$$'
|
||||
sym.SymDoubleDot: {"..", SymClassOperator, PosInfix}, // 59: '..'
|
||||
sym.SymTripleDot: {"...", SymClassOperator, PosPostfix}, // 60: '...'
|
||||
sym.SymStarEqual: {"*=", SymClassOperator, PosInfix}, // 61: '*='
|
||||
sym.SymSlashEqual: {"/=", SymClassOperator, PosInfix}, // 62: '/='
|
||||
sym.SymPercEqual: {"%=", SymClassOperator, PosInfix}, // 63: '%='
|
||||
sym.SymDoubleLessEqual: {"<<=", SymClassOperator, PosInfix}, // 64: '<<='
|
||||
sym.SymDoubleGreaterEqual: {">>=", SymClassOperator, PosInfix}, // 65: '>>='
|
||||
sym.SymAmpersandEqual: {"&=", SymClassOperator, PosInfix}, // 66: '&='
|
||||
sym.SymVertBarEqual: {"|=", SymClassOperator, PosInfix}, // 67: '|='
|
||||
sym.SymCaretEqual: {"^=", SymClassOperator, PosInfix}, // 68: '^='
|
||||
sym.SymPlusGreater: {"+>", SymClassOperator, PosInfix}, // 69: '+>'
|
||||
sym.SymLessPlus: {"<+", SymClassOperator, PosInfix}, // 70: '<+'
|
||||
sym.SymPreInc: {"++", SymClassOperator, PosPrefix}, // 71: '++'
|
||||
sym.SymPreDec: {"--", SymClassOperator, PosPrefix}, // 72: '--'
|
||||
sym.SymOpenSquareLess: {"[<", SymClassOperator, PosPrefix}, // 97: '[<'
|
||||
sym.SymGreaterClosedSquare: {">]", SymClassOperator, PosPostfix}, // 98: '>]'
|
||||
// sym.SymChangeSign
|
||||
// sym.SymUnchangeSign
|
||||
// sym.SymIdentifier
|
||||
// sym.SymBool
|
||||
// sym.SymInteger
|
||||
// sym.SymVariable
|
||||
// sym.SymFloat
|
||||
// sym.SymFraction
|
||||
// sym.SymString
|
||||
// sym.SymIterator
|
||||
// sym.SymOr: "or",
|
||||
// sym.SymAnd: "and",
|
||||
// sym.SymNot: "not",
|
||||
// sym.SymComment
|
||||
// sym.SymFuncCall
|
||||
// sym.SymFuncDef
|
||||
// sym.SymList
|
||||
// sym.SymLinkedList
|
||||
// sym.SymDict
|
||||
// sym.SymIndex
|
||||
// sym.SymExpression
|
||||
// sym.SymSelector // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
||||
// sym.SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
||||
// // sym.SymOpenComment // 0: '/*'
|
||||
// // sym.SymClosedComment // 0: '*/'
|
||||
// // sym.SymOneLineComment // 0: '//'
|
||||
// keywordBase
|
||||
SymKwAnd: {"and", SymClassOperator, PosInfix},
|
||||
SymKwNot: {"not", SymClassOperator, PosInfix},
|
||||
SymKwOr: {"or", SymClassOperator, PosInfix},
|
||||
SymKwBut: {"but", SymClassOperator, PosInfix},
|
||||
SymKwMap: {"map", SymClassOperator, PosInfix},
|
||||
SymKwFilter: {"filter", SymClassOperator, PosInfix},
|
||||
SymKwDigest: {"digest", SymClassOperator, PosInfix},
|
||||
SymKwCat: {"cat", SymClassOperator, PosInfix},
|
||||
SymKwJoin: {"join", SymClassOperator, PosInfix},
|
||||
SymKwGroupBy: {"groupby", SymClassOperator, PosInfix},
|
||||
SymKwFunc: {"func(", SymClassDeclaration, PosPrefix},
|
||||
SymKwBuiltin: {"builtin", SymClassOperator, PosPrefix},
|
||||
SymKwPlugin: {"plugin", SymClassOperator, PosPrefix},
|
||||
SymKwIn: {"in", SymClassOperator, PosInfix},
|
||||
SymKwAt: {"at", SymClassOperator, PosInfix},
|
||||
SymKwInclude: {"include", SymClassOperator, PosPrefix},
|
||||
SymKwNil: {"nil", SymClassValue, PosLeaf},
|
||||
SymKwUnset: {"unset", SymClassOperator, PosPrefix},
|
||||
sym.SymKwAnd: {"and", SymClassOperator, PosInfix},
|
||||
sym.SymKwNot: {"not", SymClassOperator, PosInfix},
|
||||
sym.SymKwOr: {"or", SymClassOperator, PosInfix},
|
||||
sym.SymKwBut: {"but", SymClassOperator, PosInfix},
|
||||
sym.SymKwMap: {"map", SymClassOperator, PosInfix},
|
||||
sym.SymKwFilter: {"filter", SymClassOperator, PosInfix},
|
||||
sym.SymKwDigest: {"digest", SymClassOperator, PosInfix},
|
||||
sym.SymKwCat: {"cat", SymClassOperator, PosInfix},
|
||||
sym.SymKwJoin: {"join", SymClassOperator, PosInfix},
|
||||
sym.SymKwGroupBy: {"groupby", SymClassOperator, PosInfix},
|
||||
sym.SymKwFunc: {"func(", SymClassDeclaration, PosPrefix},
|
||||
sym.SymKwBuiltin: {"builtin", SymClassOperator, PosPrefix},
|
||||
sym.SymKwPlugin: {"plugin", SymClassOperator, PosPrefix},
|
||||
sym.SymKwIn: {"in", SymClassOperator, PosInfix},
|
||||
sym.SymKwAt: {"at", SymClassOperator, PosInfix},
|
||||
sym.SymKwInclude: {"include", SymClassOperator, PosPrefix},
|
||||
sym.SymKwNil: {"nil", SymClassValue, PosLeaf},
|
||||
sym.SymKwUnset: {"unset", SymClassOperator, PosPrefix},
|
||||
}
|
||||
}
|
||||
|
||||
func SymToString(sym Symbol) string {
|
||||
func SymToString(sym sym.Symbol) string {
|
||||
if s, ok := symbolMap[sym]; ok {
|
||||
return s.repr
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func SymListToString(symList []Symbol, quote bool) string {
|
||||
func SymListToString(symList []sym.Symbol, quote bool) string {
|
||||
var sb strings.Builder
|
||||
if len(symList) == 0 {
|
||||
sb.WriteString("<nothing>")
|
||||
@@ -186,13 +188,13 @@ func SymListToString(symList []Symbol, quote bool) string {
|
||||
}
|
||||
|
||||
func StringEndsWithOperator(s string) bool {
|
||||
return endingOperator(s) != SymNone
|
||||
return endingOperator(s) != sym.SymNone
|
||||
}
|
||||
|
||||
func endingOperator(s string) (sym Symbol) {
|
||||
func endingOperator(s string) (resultSym sym.Symbol) {
|
||||
var matchLength = 0
|
||||
var repr string
|
||||
sym = SymNone
|
||||
resultSym = sym.SymNone
|
||||
lower := strings.TrimRight(strings.ToLower(s), " \t")
|
||||
for symbol, spec := range symbolMap {
|
||||
if len(spec.repr) > matchLength || repr == spec.repr {
|
||||
@@ -200,9 +202,9 @@ func endingOperator(s string) (sym Symbol) {
|
||||
if isNotEndingSymbol(spec) && repr != spec.repr {
|
||||
repr = spec.repr
|
||||
matchLength = len(spec.repr)
|
||||
sym = symbol
|
||||
resultSym = symbol
|
||||
} else {
|
||||
sym = SymNone
|
||||
resultSym = sym.SymNone
|
||||
break
|
||||
// matchLength = 0
|
||||
}
|
||||
|
||||
+44
-42
@@ -9,57 +9,59 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
func TestScanner(t *testing.T) {
|
||||
type inputType struct {
|
||||
source string
|
||||
wantSym Symbol
|
||||
wantSym sym.Symbol
|
||||
wantValue any
|
||||
wantErr error
|
||||
}
|
||||
|
||||
inputs := []inputType{
|
||||
/* 1 */ {`123`, SymInteger, int64(123), nil},
|
||||
/* 2 */ {"=", SymEqual, nil, nil},
|
||||
/* 3 */ {`--`, SymDoubleMinus, nil, nil},
|
||||
/* 4 */ {`++`, SymDoublePlus, nil, nil},
|
||||
/* 5 */ {`**`, SymDoubleStar, nil, nil},
|
||||
/* 6 */ {`&&`, SymDoubleAmpersand, nil, nil},
|
||||
/* 7 */ {`||`, SymDoubleVertBar, nil, nil},
|
||||
/* 8 */ {`NOT`, SymKwNot, nil, nil},
|
||||
/* 9 */ {`AND`, SymKwAnd, nil, nil},
|
||||
/* 10 */ {`or`, SymKwOr, nil, nil},
|
||||
/* 11 */ {`+=`, SymPlusEqual, nil, nil},
|
||||
/* 12 */ {`-=`, SymMinusEqual, nil, nil},
|
||||
/* 13 */ {`|`, SymVertBar, nil, nil},
|
||||
/* 14 */ {`:`, SymColon, nil, nil},
|
||||
/* 15 */ {`;`, SymSemiColon, nil, nil},
|
||||
/* 16 */ {`.`, SymDot, nil, nil},
|
||||
/* 17 */ {`0.5`, SymFloat, float64(0.5), nil},
|
||||
/* 18 */ {`\\`, SymBackSlash, nil, nil},
|
||||
/* 19 */ {"`", SymBackTick, nil, nil},
|
||||
/* 20 */ {"?", SymQuestion, nil, nil},
|
||||
/* 21 */ {"&", SymAmpersand, nil, nil},
|
||||
/* 22 */ {"@", SymAt, nil, nil},
|
||||
/* 23 */ {`#`, SymHash, nil, nil},
|
||||
/* 24 */ {`%`, SymPercent, nil, nil},
|
||||
/* 25 */ {`\'`, SymQuote, nil, nil},
|
||||
/* 26 */ {`\"`, SymDoubleQuote, nil, nil},
|
||||
/* 27 */ {`_`, SymUndescore, nil, nil},
|
||||
/* 28 */ {`<>`, SymLessGreater, nil, nil},
|
||||
/* 29 */ {`[`, SymOpenSquare, nil, nil},
|
||||
/* 30 */ {`]`, SymClosedSquare, nil, nil},
|
||||
/* 31 */ {`{`, SymOpenBrace, nil, nil},
|
||||
/* 32 */ {`}`, SymClosedBrace, nil, nil},
|
||||
/* 33 */ {`(`, SymOpenRound, nil, nil},
|
||||
/* 34 */ {`)`, SymClosedRound, nil, nil},
|
||||
/* 35 */ {`1E+2`, SymFloat, float64(100), nil},
|
||||
/* 36 */ {`1E+x`, SymError, errors.New("[1:5] expected integer exponent, got x"), nil},
|
||||
/* 37 */ {`$`, SymDollar, nil, nil},
|
||||
/* 38 */ {`\`, SymError, errors.New("incomplete escape sequence"), nil},
|
||||
/* 39 */ {`"string"`, SymString, "string", nil},
|
||||
/* 40 */ {`identifier`, SymIdentifier, "identifier", nil},
|
||||
/* 1 */ {`123`, sym.SymInteger, int64(123), nil},
|
||||
/* 2 */ {"=", sym.SymEqual, nil, nil},
|
||||
/* 3 */ {`--`, sym.SymDoubleMinus, nil, nil},
|
||||
/* 4 */ {`++`, sym.SymDoublePlus, nil, nil},
|
||||
/* 5 */ {`**`, sym.SymDoubleStar, nil, nil},
|
||||
/* 6 */ {`&&`, sym.SymDoubleAmpersand, nil, nil},
|
||||
/* 7 */ {`||`, sym.SymDoubleVertBar, nil, nil},
|
||||
/* 8 */ {`NOT`, sym.SymKwNot, nil, nil},
|
||||
/* 9 */ {`AND`, sym.SymKwAnd, nil, nil},
|
||||
/* 10 */ {`or`, sym.SymKwOr, nil, nil},
|
||||
/* 11 */ {`+=`, sym.SymPlusEqual, nil, nil},
|
||||
/* 12 */ {`-=`, sym.SymMinusEqual, nil, nil},
|
||||
/* 13 */ {`|`, sym.SymVertBar, nil, nil},
|
||||
/* 14 */ {`:`, sym.SymColon, nil, nil},
|
||||
/* 15 */ {`;`, sym.SymSemiColon, nil, nil},
|
||||
/* 16 */ {`.`, sym.SymDot, nil, nil},
|
||||
/* 17 */ {`0.5`, sym.SymFloat, float64(0.5), nil},
|
||||
/* 18 */ {`\\`, sym.SymBackSlash, nil, nil},
|
||||
/* 19 */ {"`", sym.SymBackTick, nil, nil},
|
||||
/* 20 */ {"?", sym.SymQuestion, nil, nil},
|
||||
/* 21 */ {"&", sym.SymAmpersand, nil, nil},
|
||||
/* 22 */ {"@", sym.SymAt, nil, nil},
|
||||
/* 23 */ {`#`, sym.SymHash, nil, nil},
|
||||
/* 24 */ {`%`, sym.SymPercent, nil, nil},
|
||||
/* 25 */ {`\'`, sym.SymQuote, nil, nil},
|
||||
/* 26 */ {`\"`, sym.SymDoubleQuote, nil, nil},
|
||||
/* 27 */ {`_`, sym.SymUndescore, nil, nil},
|
||||
/* 28 */ {`<>`, sym.SymLessGreater, nil, nil},
|
||||
/* 29 */ {`[`, sym.SymOpenSquare, nil, nil},
|
||||
/* 30 */ {`]`, sym.SymClosedSquare, nil, nil},
|
||||
/* 31 */ {`{`, sym.SymOpenBrace, nil, nil},
|
||||
/* 32 */ {`}`, sym.SymClosedBrace, nil, nil},
|
||||
/* 33 */ {`(`, sym.SymOpenRound, nil, nil},
|
||||
/* 34 */ {`)`, sym.SymClosedRound, nil, nil},
|
||||
/* 35 */ {`1E+2`, sym.SymFloat, float64(100), nil},
|
||||
/* 36 */ {`1E+x`, sym.SymError, errors.New("[1:5] expected integer exponent, got x"), nil},
|
||||
/* 37 */ {`$`, sym.SymDollar, nil, nil},
|
||||
/* 38 */ {`\`, sym.SymError, errors.New("incomplete escape sequence"), nil},
|
||||
/* 39 */ {`"string"`, sym.SymString, "string", nil},
|
||||
/* 40 */ {`identifier`, sym.SymIdentifier, "identifier", nil},
|
||||
}
|
||||
|
||||
for i, input := range inputs {
|
||||
@@ -79,7 +81,7 @@ func TestScanner(t *testing.T) {
|
||||
t.Errorf("%d: %q -> got = (nil), want %v (value %v [%T])", i+1, input.source, input.wantSym, input.wantValue, input.wantValue)
|
||||
// } else if tk.Sym != input.wantSym || tk.Value != input.wantValue {
|
||||
} else if tk.Sym != input.wantSym || !reflect.DeepEqual(tk.Value, input.wantValue) {
|
||||
if tk.Sym == SymError && input.wantSym == tk.Sym {
|
||||
if tk.Sym == sym.SymError && input.wantSym == tk.Sym {
|
||||
if tkErr, tkOk := tk.Value.(error); tkOk {
|
||||
if inputErr, inputOk := input.wantValue.(error); inputOk {
|
||||
if tkErr.Error() != inputErr.Error() {
|
||||
|
||||
@@ -4,17 +4,19 @@
|
||||
// term-constructor-registry.go
|
||||
package scan
|
||||
|
||||
import "git.portale-stac.it/go-pkg/expr/sym"
|
||||
|
||||
const initialRegistryCapacity = 10
|
||||
|
||||
type termContructor func(tk *Token) *Term
|
||||
|
||||
var constructorRegistry map[Symbol]termContructor = nil
|
||||
var constructorRegistry map[sym.Symbol]termContructor = nil
|
||||
|
||||
func RegisterTermConstructor(sym Symbol, constructor termContructor) {
|
||||
func RegisterTermConstructor(symmbol sym.Symbol, constructor termContructor) {
|
||||
if constructorRegistry == nil {
|
||||
constructorRegistry = make(map[Symbol]termContructor, initialRegistryCapacity)
|
||||
constructorRegistry = make(map[sym.Symbol]termContructor, initialRegistryCapacity)
|
||||
}
|
||||
constructorRegistry[sym] = constructor
|
||||
constructorRegistry[symmbol] = constructor
|
||||
}
|
||||
|
||||
func NewTerm(tk *Token) (inst *Term) {
|
||||
|
||||
+17
-4
@@ -8,13 +8,14 @@ import (
|
||||
"strings"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
type TermPriority uint32
|
||||
|
||||
const (
|
||||
PriNone TermPriority = iota
|
||||
PriRange
|
||||
PriInterval
|
||||
PriBut
|
||||
PriAssign
|
||||
PriIterOp // map, filter, digest, etc
|
||||
@@ -160,7 +161,7 @@ func (t *Term) SetParent(parent *Term) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Term) Symbol() Symbol {
|
||||
func (t *Term) Symbol() sym.Symbol {
|
||||
return t.Tk.Sym
|
||||
}
|
||||
|
||||
@@ -200,12 +201,24 @@ func (t *Term) GetRightChild() (c kern.Term) {
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Term) IsSymbol(symbol sym.Symbol) bool {
|
||||
return t.Symbol() == symbol
|
||||
}
|
||||
|
||||
func (t *Term) IsOneOf(symbols ...sym.Symbol) bool {
|
||||
return t.Tk.IsOneOf(symbols)
|
||||
}
|
||||
|
||||
func (t *Term) IsAssign() bool {
|
||||
return t.Symbol() == SymEqual
|
||||
return t.Symbol() == sym.SymEqual
|
||||
}
|
||||
|
||||
func (t *Term) IsVar() bool {
|
||||
return t.Symbol() == SymVariable
|
||||
return t.Symbol() == sym.SymVariable
|
||||
}
|
||||
|
||||
func (t *Term) SetSymbol(symbol sym.Symbol) {
|
||||
t.Tk.SetSymbol(symbol)
|
||||
}
|
||||
|
||||
// func (t *Term) IsFunc() bool {
|
||||
|
||||
+24
-22
@@ -8,12 +8,14 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
row int
|
||||
col int
|
||||
Sym Symbol
|
||||
Sym sym.Symbol
|
||||
source string
|
||||
Value any
|
||||
}
|
||||
@@ -36,19 +38,19 @@ func (tk *Token) String() string {
|
||||
return tk.source
|
||||
}
|
||||
|
||||
func NewToken(row, col int, sym Symbol, source string) *Token {
|
||||
return &Token{row: row, col: col, Sym: sym, source: source}
|
||||
func NewToken(row, col int, symbol sym.Symbol, source string) *Token {
|
||||
return &Token{row: row, col: col, Sym: symbol, source: source}
|
||||
}
|
||||
|
||||
func NewValueToken(row, col int, sym Symbol, source string, value any) *Token {
|
||||
return &Token{row: row, col: col, Sym: sym, source: source, Value: value}
|
||||
func NewValueToken(row, col int, symbol sym.Symbol, source string, value any) *Token {
|
||||
return &Token{row: row, col: col, Sym: symbol, source: source, Value: value}
|
||||
}
|
||||
|
||||
func NewErrorToken(row, col int, err error) *Token {
|
||||
if err == io.EOF {
|
||||
return NewToken(row, col, SymEos, "<EOF>")
|
||||
return NewToken(row, col, sym.SymEos, "<EOF>")
|
||||
}
|
||||
return NewValueToken(row, col, SymError, fmt.Sprintf("[%d:%d]", row, col), err)
|
||||
return NewValueToken(row, col, sym.SymError, fmt.Sprintf("[%d:%d]", row, col), err)
|
||||
}
|
||||
|
||||
func (tk *Token) Source() string {
|
||||
@@ -68,31 +70,31 @@ func (tk *Token) Clone() (c *Token) {
|
||||
}
|
||||
|
||||
func (tk *Token) IsEos() bool {
|
||||
return tk.Sym == SymEos
|
||||
return tk.Sym == sym.SymEos
|
||||
}
|
||||
|
||||
func (tk *Token) IsError() bool {
|
||||
return tk.Sym == SymError
|
||||
return tk.Sym == sym.SymError
|
||||
}
|
||||
|
||||
func (tk *Token) IsTerm(termSymbols []Symbol) bool {
|
||||
return tk.IsEos() || tk.IsError() || tk.IsOneOf(termSymbols)
|
||||
func (tk *Token) IsTerm(symbols []sym.Symbol) bool {
|
||||
return tk.IsEos() || tk.IsError() || tk.IsOneOf(symbols)
|
||||
}
|
||||
|
||||
func (tk *Token) IsOneOf(termSymbols []Symbol) bool {
|
||||
return termSymbols != nil && slices.Index(termSymbols, tk.Sym) >= 0
|
||||
func (tk *Token) IsOneOf(symbols []sym.Symbol) bool {
|
||||
return symbols != nil && slices.Index(symbols, tk.Sym) >= 0
|
||||
}
|
||||
|
||||
func (tk *Token) IsOneOfA(termSymbols ...Symbol) bool {
|
||||
return slices.Index(termSymbols, tk.Sym) >= 0
|
||||
func (tk *Token) IsOneOfA(symbols ...sym.Symbol) bool {
|
||||
return slices.Index(symbols, tk.Sym) >= 0
|
||||
}
|
||||
|
||||
func (tk *Token) IsSymbol(sym Symbol) bool {
|
||||
return tk.Sym == sym
|
||||
func (tk *Token) IsSymbol(symbol sym.Symbol) bool {
|
||||
return tk.Sym == symbol
|
||||
}
|
||||
|
||||
func (tk *Token) SetSymbol(sym Symbol) {
|
||||
tk.Sym = sym
|
||||
func (tk *Token) SetSymbol(symbol sym.Symbol) {
|
||||
tk.Sym = symbol
|
||||
}
|
||||
|
||||
func (tk *Token) Errorf(template string, args ...any) (err error) {
|
||||
@@ -101,7 +103,7 @@ func (tk *Token) Errorf(template string, args ...any) (err error) {
|
||||
}
|
||||
|
||||
func (tk *Token) Error() (err error) {
|
||||
if tk.Sym == SymError {
|
||||
if tk.Sym == sym.SymError {
|
||||
if msg, ok := tk.Value.(error); ok {
|
||||
err = fmt.Errorf("[%d:%d] %v", tk.row, tk.col, msg)
|
||||
}
|
||||
@@ -110,7 +112,7 @@ func (tk *Token) Error() (err error) {
|
||||
}
|
||||
|
||||
func (tk *Token) ErrorText() (err string) {
|
||||
if tk.Sym == SymError {
|
||||
if tk.Sym == sym.SymError {
|
||||
if msg, ok := tk.Value.(error); ok {
|
||||
err = msg.Error()
|
||||
}
|
||||
@@ -137,6 +139,6 @@ func (tk *Token) ErrorExpectedGotStringWithPrefix(prefix, symbol, got string) (e
|
||||
return
|
||||
}
|
||||
|
||||
func (tk *Token) ErrorExpectedOneOfGot(expected ...Symbol) (err error) {
|
||||
func (tk *Token) ErrorExpectedOneOfGot(expected ...sym.Symbol) (err error) {
|
||||
return tk.ErrorExpectedGotStringWithPrefix("expected one of ", SymListToString(expected, true), SymToString(tk.Sym))
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// All rights reserved.
|
||||
|
||||
// symbol.go
|
||||
package scan
|
||||
package sym
|
||||
|
||||
type Symbol int16
|
||||
|
||||
@@ -101,7 +101,7 @@ const (
|
||||
SymList // 90: list
|
||||
SymDict // 91: dict
|
||||
SymIndex // 92: index
|
||||
SymRange // 93: range [index : index]
|
||||
SymInterval // 93: range [index : index]
|
||||
SymExpression // 94: expression
|
||||
SymSelector // 95: selector <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
||||
SymSelectorCase // 96: <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
||||
@@ -134,11 +134,11 @@ const (
|
||||
SymKwUnset
|
||||
)
|
||||
|
||||
var keywords map[string]Symbol
|
||||
var Keywords map[string]Symbol
|
||||
|
||||
func init() {
|
||||
//keywords = make(map[string]Symbol)
|
||||
keywords = map[string]Symbol{
|
||||
Keywords = map[string]Symbol{
|
||||
"AND": SymKwAnd,
|
||||
"BUILTIN": SymKwBuiltin,
|
||||
"PLUGIN": SymKwPlugin,
|
||||
+11
-17
@@ -39,23 +39,17 @@ func TestArray(t *testing.T) {
|
||||
/* 23 */ {`a=[1,2]; (a)<+3; a`, array.NewArrayA(int64(1), int64(2)), nil},
|
||||
/* 24 */ {`["a","b","c","d"][1]`, "b", nil},
|
||||
/* 25 */ {`["a","b","c","d"][1,1]`, nil, `[1:19] one index only is allowed`},
|
||||
/* 26 */ {`[0,1,2,3,4][:]`, array.NewArrayA(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`},
|
||||
/* 28 */ {`but +> ["a", "b", "c"]`, nil, `[1:6] infix operator "+>" requires two non-nil operands, got 0`},
|
||||
/* 29 */ {`a=[1,2]; a<+3`, array.NewArrayA(int64(1), int64(2), int64(3)), nil},
|
||||
/* 30 */ {`a=[1,2]; 5+>a`, array.NewArrayA(int64(5), int64(1), int64(2)), nil},
|
||||
/* 31 */ {`L=[1,2]; L[0]=9; L`, array.NewArrayA(int64(9), int64(2)), nil},
|
||||
/* 32 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`},
|
||||
/* 33 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [array]`},
|
||||
/* 34 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`},
|
||||
/* 35 */ {`[0,1,2,3,4][2:3]`, array.NewArrayA(int64(2)), nil},
|
||||
/* 36 */ {`[0,1,2,3,4][3:-1]`, array.NewArrayA(int64(3)), nil},
|
||||
/* 37 */ {`[0,1,2,3,4][-3:-1]`, array.NewArrayA(int64(2), int64(3)), nil},
|
||||
/* 38 */ {`[0,1,2,3,4][0:]`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
|
||||
/* 39 */ {`2 IN [1,2,3]`, true, nil},
|
||||
/* 40 */ {`2 AT [1,2,3]`, int64(1), nil},
|
||||
/* 41 */ {`4 AT [1,2,3]`, int64(-1), nil},
|
||||
// /* 44 */ {`[0,1,2,3,4][2:3]`, kern.NewListA(int64(20)), nil},
|
||||
/* 26 */ {`["a", "b", "c"] <+ ;`, nil, `[1:18] infix operator "<+" requires two non-nil operands, got 1`},
|
||||
/* 27 */ {`but +> ["a", "b", "c"]`, nil, `[1:6] infix operator "+>" requires two non-nil operands, got 0`},
|
||||
/* 28 */ {`a=[1,2]; a<+3`, array.NewArrayA(int64(1), int64(2), int64(3)), nil},
|
||||
/* 29 */ {`a=[1,2]; 5+>a`, array.NewArrayA(int64(5), int64(1), int64(2)), nil},
|
||||
/* 30 */ {`L=[1,2]; L[0]=9; L`, array.NewArrayA(int64(9), int64(2)), nil},
|
||||
/* 31 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`},
|
||||
/* 32 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [array]`},
|
||||
/* 33 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`},
|
||||
/* 34 */ {`2 IN [1,2,3]`, true, nil},
|
||||
/* 35 */ {`2 AT [1,2,3]`, int64(1), nil},
|
||||
/* 36 */ {`4 AT [1,2,3]`, int64(-1), nil},
|
||||
}
|
||||
|
||||
// t.Setenv("EXPR_PATH", ".")
|
||||
|
||||
+9
-8
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
func TestAstString(t *testing.T) {
|
||||
@@ -19,9 +20,9 @@ func TestAstString(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAddTokensGood(t *testing.T) {
|
||||
tk1 := scan.NewValueToken(0, 0, scan.SymInteger, "100", 100)
|
||||
tk2 := scan.NewToken(0, 0, scan.SymPlus, "+")
|
||||
tk3 := scan.NewValueToken(0, 0, scan.SymInteger, "50", 500)
|
||||
tk1 := scan.NewValueToken(0, 0, sym.SymInteger, "100", 100)
|
||||
tk2 := scan.NewToken(0, 0, sym.SymPlus, "+")
|
||||
tk3 := scan.NewValueToken(0, 0, sym.SymInteger, "50", 500)
|
||||
|
||||
tree := scan.NewAst()
|
||||
if gotErr := tree.AddTokens(tk1, tk2, tk3); gotErr != nil {
|
||||
@@ -30,10 +31,10 @@ func TestAddTokensGood(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAddTokensBad(t *testing.T) {
|
||||
tk0 := scan.NewValueToken(0, 0, scan.SymInteger, "200", 200)
|
||||
tk1 := scan.NewValueToken(0, 0, scan.SymInteger, "100", 100)
|
||||
tk2 := scan.NewToken(0, 0, scan.SymPlus, "+")
|
||||
tk3 := scan.NewValueToken(0, 0, scan.SymInteger, "50", 500)
|
||||
tk0 := scan.NewValueToken(0, 0, sym.SymInteger, "200", 200)
|
||||
tk1 := scan.NewValueToken(0, 0, sym.SymInteger, "100", 100)
|
||||
tk2 := scan.NewToken(0, 0, sym.SymPlus, "+")
|
||||
tk3 := scan.NewValueToken(0, 0, sym.SymInteger, "50", 500)
|
||||
|
||||
wantErr := errors.New(`[0:0] two adjacent operators: "200" and "100"`)
|
||||
|
||||
@@ -44,7 +45,7 @@ func TestAddTokensBad(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAddUnknownTokens(t *testing.T) {
|
||||
tk0 := scan.NewToken(0, 0, scan.SymPercent, "%")
|
||||
tk0 := scan.NewToken(0, 0, sym.SymPercent, "%")
|
||||
|
||||
wantErr := errors.New(`unexpected token "%"`)
|
||||
|
||||
|
||||
+3
-2
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
)
|
||||
@@ -109,7 +110,7 @@ func TestDictToStringMultiLine(t *testing.T) {
|
||||
"first": 1
|
||||
}`
|
||||
args := map[any]any{
|
||||
"first": newLiteralTerm(scan.NewValueToken(0, 0, scan.SymInteger, "1", 1)),
|
||||
"first": newLiteralTerm(scan.NewValueToken(0, 0, sym.SymInteger, "1", 1)),
|
||||
}
|
||||
dict := dict.NewDict(args)
|
||||
got := dict.ToString(kern.MultiLine)
|
||||
@@ -131,7 +132,7 @@ func TestDictToString(t *testing.T) {
|
||||
section := "dict-ToString-SL"
|
||||
want := `{"first": 1}`
|
||||
args := map[any]any{
|
||||
"first": newLiteralTerm(scan.NewValueToken(0, 0, scan.SymInteger, "1", 1)),
|
||||
"first": newLiteralTerm(scan.NewValueToken(0, 0, sym.SymInteger, "1", 1)),
|
||||
}
|
||||
dict := dict.NewDict(args)
|
||||
got := dict.ToString(0)
|
||||
|
||||
+29
-9
@@ -8,23 +8,43 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
)
|
||||
|
||||
func TestCollections(t *testing.T) {
|
||||
section := "Index"
|
||||
inputs := []inputType{
|
||||
/* 1 */ {`"abcdef"[1:3]`, "bc", nil},
|
||||
/* 2 */ {`"abcdef"[:3]`, "abc", nil},
|
||||
/* 3 */ {`"abcdef"[1:]`, "bcdef", nil},
|
||||
/* 4 */ {`"abcdef"[:]`, "abcdef", nil},
|
||||
/* 5 */ {`"abcdef"[1:2:3]`, nil, `[1:14] invalid range specification`},
|
||||
/* 6 */ {`"abcdef"[((1>0)?{1}:{0}):3]`, "bc", nil},
|
||||
/* 7 */ {`"abcdef"[[0,1][0]:1]`, "a", nil},
|
||||
/* 8 */ {`[0,1,2,3,4][:]`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
|
||||
/* 1 */ {`"abcdef"[1..3]`, "bc", nil},
|
||||
/* 2 */ {`"abcdef"[..3]`, "abc", nil},
|
||||
/* 3 */ {`"abcdef"[1..]`, "bcdef", nil},
|
||||
/* 4 */ {`"abcdef"[..]`, "abcdef", nil},
|
||||
/* 5 */ {`"abcdef"[1..2..3]`, `b`, nil},
|
||||
/* 6 */ {`"abcdef"[((1>0)?{1}:{0})..3]`, "bc", nil},
|
||||
/* 7 */ {`"abcdef"[[0,1][0]..1]`, "a", nil},
|
||||
/* 8 */ {`"abcdef"[..1]`, "a", nil},
|
||||
/* 9 */ {`"abcdef"[..-1]`, "abcde", nil},
|
||||
/* 10 */ {`"abcdef"[..-1..2]`, "ace", nil},
|
||||
/* 11 */ {`"abcdef"[-3..-1..2]`, "d", nil},
|
||||
/* 12 */ {`"abcdef"[3..0]`, "dcba", nil},
|
||||
/* 13 */ {`"abcdef"[-1..0..2]`, "fdb", nil},
|
||||
/* 14 */ {`[0,1,2,3,4][..]`, array.NewIntArrayA(0, 1, 2, 3, 4), nil},
|
||||
/* 15 */ {`[0,1,2,3,4][2..3]`, array.NewIntArrayA(2), nil},
|
||||
/* 16 */ {`[0,1,2,3,4][3..-1]`, array.NewIntArrayA(3), nil},
|
||||
/* 17 */ {`[0,1,2,3,4][-3..-1]`, array.NewIntArrayA(2, 3), nil},
|
||||
/* 18 */ {`[0,1,2,3,4][0..]`, array.NewIntArrayA(0, 1, 2, 3, 4), nil},
|
||||
/* 19 */ {`[0,1,2,3,4][0..-1..2]`, array.NewIntArrayA(0, 2), nil},
|
||||
/* 20 */ {`[0,1,2,3,4][-1..0..2]`, array.NewIntArrayA(4, 2), nil},
|
||||
/* 21 */ {`[<0,1,2,3,4>][..]`, list.NewLinkedListA(0, 1, 2, 3, 4), nil},
|
||||
/* 22 */ {`[<0,1,2,3,4>][2..3]`, list.NewLinkedListA(2), nil},
|
||||
/* 23 */ {`[<0,1,2,3,4>][3..-1]`, list.NewLinkedListA(3), nil},
|
||||
/* 24 */ {`[<0,1,2,3,4>][-3..-1]`, list.NewLinkedListA(2, 3), nil},
|
||||
/* 25 */ {`[<0,1,2,3,4>][0..]`, list.NewLinkedListA(0, 1, 2, 3, 4), nil},
|
||||
/* 26 */ {`[<0,1,2,3,4>][0..-1..2]`, list.NewLinkedListA(0, 2), nil},
|
||||
/* 27 */ {`[<0,1,2,3,4>][-1..0..2]`, list.NewLinkedListA(4, 2), nil},
|
||||
}
|
||||
|
||||
t.Setenv("EXPR_PATH", ".")
|
||||
|
||||
// runTestSuiteSpec(t, section, inputs, 5)
|
||||
// RunTestSuiteSpec(t, section, inputs, 27)
|
||||
RunTestSuite(t, section, inputs)
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ func TestLinkedListParser(t *testing.T) {
|
||||
/* 2 */ {`it=$([<1,2,3>]); it++`, int64(1), nil},
|
||||
/* 3 */ {`it=$([<1,2,3>]); #($$(it))`, int64(3), nil},
|
||||
/* 4 */ {`[<1,2,3>][0]`, int64(1), nil},
|
||||
/* 5 */ {`[<1,2,3>][0:2]`, list.NewLinkedListA(1, 2), nil},
|
||||
/* 5 */ {`[<1,2,3>][0..2]`, list.NewLinkedListA(1, 2), nil},
|
||||
/* 6 */ {`[<1>] + [<2,3>]`, list.NewLinkedListA(1, 2, 3), nil},
|
||||
/* 7 */ {`L=[<1>] + [<2,3>]; L[0]=100; L`, list.NewLinkedListA(100, 2, 3), nil},
|
||||
/* 8 */ {`builtin "base"; L=[<1>]; isList(L)`, true, nil},
|
||||
|
||||
+6
-5
@@ -8,12 +8,13 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
tk1 := scan.NewValueToken(0, 0, scan.SymInteger, "100", 100)
|
||||
tk2 := scan.NewToken(0, 0, scan.SymPlus, "+")
|
||||
tk3 := scan.NewValueToken(0, 0, scan.SymInteger, "50", 500)
|
||||
tk1 := scan.NewValueToken(0, 0, sym.SymInteger, "100", 100)
|
||||
tk2 := scan.NewToken(0, 0, sym.SymPlus, "+")
|
||||
tk3 := scan.NewValueToken(0, 0, sym.SymInteger, "50", 500)
|
||||
|
||||
tree := scan.NewAst()
|
||||
if gotErr := tree.AddTokens(tk1, tk2, tk3); gotErr == nil {
|
||||
@@ -24,7 +25,7 @@ func TestString(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetRoom(t *testing.T) {
|
||||
tk1 := scan.NewValueToken(0, 0, scan.SymInteger, "100", 100)
|
||||
tk1 := scan.NewValueToken(0, 0, sym.SymInteger, "100", 100)
|
||||
|
||||
tree := scan.NewAst()
|
||||
if gotErr := tree.AddTokens(tk1); gotErr == nil {
|
||||
@@ -35,7 +36,7 @@ func TestGetRoom(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetChildrenCount(t *testing.T) {
|
||||
tk1 := scan.NewValueToken(0, 0, scan.SymInteger, "100", 100)
|
||||
tk1 := scan.NewValueToken(0, 0, sym.SymInteger, "100", 100)
|
||||
|
||||
tree := scan.NewAst()
|
||||
if gotErr := tree.AddTokens(tk1); gotErr == nil {
|
||||
|
||||
+4
-3
@@ -9,19 +9,20 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/scan"
|
||||
"git.portale-stac.it/go-pkg/expr/sym"
|
||||
)
|
||||
|
||||
func TestDevString(t *testing.T) {
|
||||
type inputType struct {
|
||||
source string
|
||||
sym scan.Symbol
|
||||
sym sym.Symbol
|
||||
value any
|
||||
wantResult string
|
||||
}
|
||||
|
||||
inputs := []inputType{
|
||||
/* 1 */ {"100", scan.SymInteger, 100, fmt.Sprintf(`[%d]"100"{100}`, scan.SymInteger)},
|
||||
/* 2 */ {"+", scan.SymPlus, nil, fmt.Sprintf(`[%d]"+"{}`, scan.SymPlus)},
|
||||
/* 1 */ {"100", sym.SymInteger, 100, fmt.Sprintf(`[%d]"100"{100}`, sym.SymInteger)},
|
||||
/* 2 */ {"+", sym.SymPlus, nil, fmt.Sprintf(`[%d]"+"{}`, sym.SymPlus)},
|
||||
}
|
||||
|
||||
for i, input := range inputs {
|
||||
|
||||
@@ -18,7 +18,15 @@ func IsArray(v any) (ok bool) {
|
||||
return ok
|
||||
}
|
||||
|
||||
func NewArrayA(listAny ...any) (list *ArrayType) {
|
||||
func NewIntArrayA(listInt ...int) (aRef *ArrayType) {
|
||||
a := make(ArrayType, len(listInt))
|
||||
for i, v := range listInt {
|
||||
a[i] = int64(v)
|
||||
}
|
||||
return &a
|
||||
}
|
||||
|
||||
func NewArrayA(listAny ...any) (aRef *ArrayType) {
|
||||
if listAny == nil {
|
||||
listAny = []any{}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// interval.go
|
||||
package interval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
)
|
||||
|
||||
const TypeName = "interval"
|
||||
|
||||
type IntervalType struct {
|
||||
begin, end, step int64
|
||||
}
|
||||
|
||||
func NewInterval(begin, end, step int64) *IntervalType {
|
||||
return &IntervalType{
|
||||
begin: begin,
|
||||
end: end,
|
||||
step: step,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *IntervalType) Begin() int64 {
|
||||
return p.begin
|
||||
}
|
||||
|
||||
func (p *IntervalType) End() int64 {
|
||||
return p.end
|
||||
}
|
||||
|
||||
func (p *IntervalType) Step() int64 {
|
||||
return p.step
|
||||
}
|
||||
|
||||
func IsInterval(v any) (ok bool) {
|
||||
_, ok = v.(*IntervalType)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (p *IntervalType) TypeName() string {
|
||||
return TypeName
|
||||
}
|
||||
|
||||
func (p *IntervalType) ToString(opt kern.FmtOpt) string {
|
||||
return fmt.Sprintf("%d..%d..%d", p.begin, p.end, p.step)
|
||||
}
|
||||
|
||||
func (p *IntervalType) String() string {
|
||||
return p.ToString(0)
|
||||
}
|
||||
|
||||
func (p *IntervalType) ToIntTriple() (b, e, s int) {
|
||||
b = int(p.begin)
|
||||
e = int(p.end)
|
||||
s = int(p.step)
|
||||
return
|
||||
}
|
||||
|
||||
// func (b *bool) EqualTo(other kern.Equaler) (equal bool) {
|
||||
// if otherBool, ok := other.(*bool); ok {
|
||||
// equal = b == otherBool
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
@@ -19,6 +19,14 @@ func (node *ListNode) Next() *ListNode {
|
||||
return node.next
|
||||
}
|
||||
|
||||
func (node *ListNode) MoveOn(steps int64) *ListNode {
|
||||
n := node
|
||||
for i := int64(0); n != nil && i < steps; i++ {
|
||||
n = n.Next()
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (self *ListNode) Data() any {
|
||||
return self.data
|
||||
}
|
||||
@@ -42,6 +50,29 @@ func (ls *LinkedList) Empty() bool {
|
||||
return ls.count == 0
|
||||
}
|
||||
|
||||
func (ls *LinkedList) PushNodeFront(node *ListNode) *ListNode {
|
||||
node.next = ls.first
|
||||
ls.first = node
|
||||
if ls.last == nil {
|
||||
ls.last = ls.first
|
||||
}
|
||||
ls.count++
|
||||
return node
|
||||
}
|
||||
|
||||
func (ls *LinkedList) PushNodeBack(node *ListNode) *ListNode {
|
||||
node.next = nil
|
||||
if ls.last != nil {
|
||||
ls.last.next = node
|
||||
}
|
||||
ls.last = node
|
||||
if ls.first == nil {
|
||||
ls.first = node
|
||||
}
|
||||
ls.count++
|
||||
return node
|
||||
}
|
||||
|
||||
func (ls *LinkedList) PushFront(data any) *ListNode {
|
||||
ls.first = &ListNode{data, ls.first}
|
||||
if ls.last == nil {
|
||||
@@ -231,6 +262,36 @@ func (ls *LinkedList) Sub(start, end int64) (subList *LinkedList) {
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) SubStep(start, end, step int64) (subList *LinkedList) {
|
||||
subList = NewLinkedList()
|
||||
if node, err := ls.NodeAt(start); err == nil {
|
||||
for i := start; i < end && node != nil; i += step {
|
||||
subList.PushBack(node.data)
|
||||
node = node.MoveOn(step)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// func (ls *LinkedList) SubStep(start, end, step int64) (subList *LinkedList) {
|
||||
// subList = NewLinkedList()
|
||||
// if node, err := ls.NodeAt(start); err == nil {
|
||||
// forward := step > 0
|
||||
// if !forward {
|
||||
// step = -step
|
||||
// }
|
||||
// for i := start; i < end && node != nil; i += step {
|
||||
// if forward {
|
||||
// subList.PushBack(node.data)
|
||||
// } else {
|
||||
// subList.PushFront(node.data)
|
||||
// }
|
||||
// node = node.MoveOn(step)
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// type TraverseOperator func(index int, elem interface{}, userData interface{}) (err error)
|
||||
|
||||
// func (self *LinkedList) Traverse(op TraverseOperator, user_data interface{}) (err error) {
|
||||
@@ -279,6 +340,19 @@ func (ls *LinkedList) FindNext(eqFunc EqualFunc, startNode *ListNode) (targetNod
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) Revert() (rls *LinkedList) {
|
||||
var next *ListNode
|
||||
node := ls.first
|
||||
ls.count = 0
|
||||
ls.first = nil
|
||||
ls.last = nil
|
||||
for ; node != nil; node = next {
|
||||
next = node.next
|
||||
ls.PushNodeFront(node)
|
||||
}
|
||||
return ls
|
||||
}
|
||||
|
||||
// type DataFeeder func(user_data interface{}) interface{}
|
||||
// type NodeObserver func(node *ListNode, index int, userData interface{})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user