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