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:
2026-07-27 16:01:52 +02:00
parent 07aecfc4e7
commit 8e596d5979
63 changed files with 1125 additions and 755 deletions
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
+103
View File
@@ -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)
}
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
+6 -5
View File
@@ -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)
}
+5 -4
View File
@@ -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
View File
@@ -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)
}
-88
View File
@@ -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
View File
@@ -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)
}
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
+118 -110
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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() {
+6 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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))
}
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+9 -1
View File
@@ -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{}
}
+68
View File
@@ -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
// }
+74
View File
@@ -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{})