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