From 84b255a51b7c625c3771e8686825070f11ba294c Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Sun, 17 May 2026 22:43:27 +0200 Subject: [PATCH] new type LinkedList, preliminary implementation --- builtin-base.go | 14 +++ kern/clone-value.go | 2 + kern/common-type-names.go | 1 + kern/compare.go | 4 + kern/formatter.go | 17 +++- kern/list-type.go | 38 +++----- parser.go | 27 ++++-- scan/scanner.go | 8 +- scan/symbol-map.go | 151 +++++++++++++++-------------- scan/symbol.go | 199 +++++++++++++++++++------------------- t_builtin-base_test.go | 4 +- t_list_test.go | 16 ++- 12 files changed, 273 insertions(+), 208 deletions(-) diff --git a/builtin-base.go b/builtin-base.go index 4bc243a..5cb625c 100644 --- a/builtin-base.go +++ b/builtin-base.go @@ -275,6 +275,16 @@ func charFunc(ctx kern.ExprContext, name string, args map[string]any) (result an return } +func seqFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + list := kern.NewLinkedList() + items := args[kern.ParamValue].([]any) + for _, arg := range items { + list.PushBack(arg) + } + result = list + return +} + //// import func ImportBuiltinsFuncs(ctx kern.ExprContext) { @@ -318,6 +328,10 @@ func ImportBuiltinsFuncs(ctx kern.ExprContext) { ctx.RegisterFunc("char", kern.NewGolangFunctor(charFunc), kern.TypeString, []kern.ExprFuncParam{ kern.NewFuncParam(kern.ParamValue), }) + + ctx.RegisterFunc("seq", kern.NewGolangFunctor(seqFunc), kern.TypeLinkedList, []kern.ExprFuncParam{ + kern.NewFuncParamFlag(kern.ParamValue, kern.PfRepeat), + }) } func init() { diff --git a/kern/clone-value.go b/kern/clone-value.go index 66d1ee5..5155ef9 100644 --- a/kern/clone-value.go +++ b/kern/clone-value.go @@ -21,6 +21,8 @@ func Clone(v any) (c any) { c = unboxed.Clone() case *DictType: c = unboxed.Clone() + case *LinkedList: + c = unboxed.Clone() default: c = v } diff --git a/kern/common-type-names.go b/kern/common-type-names.go index 653ebc8..0e05256 100644 --- a/kern/common-type-names.go +++ b/kern/common-type-names.go @@ -20,4 +20,5 @@ const ( TypeDict = "dict" TypeListOf = "list-of-" TypeListOfStrings = "list-of-strings" + TypeLinkedList = "linked-list" ) diff --git a/kern/compare.go b/kern/compare.go index 32c39e1..f0ccb3f 100644 --- a/kern/compare.go +++ b/kern/compare.go @@ -20,6 +20,10 @@ func Equal(value1, value2 any) (equal bool) { d1 := value1.(*DictType) d2 := value2.(*DictType) equal = d1.Equals(*d2) + } else if IsLinkedList(value1) && IsLinkedList(value2) { + ll1 := value1.(*LinkedList) + ll2 := value2.(*LinkedList) + equal = ll1.Equals(ll2) } else if IsInteger(value1) && IsInteger(value2) { equal = value1.(int64) == value2.(int64) } else if IsString(value1) && IsString(value2) { diff --git a/kern/formatter.go b/kern/formatter.go index 74e8c8d..dfbb188 100644 --- a/kern/formatter.go +++ b/kern/formatter.go @@ -4,7 +4,10 @@ // formatter.go package kern -import "fmt" +import ( + "fmt" + "strings" +) type FmtOpt uint32 // lower 16 bits hold a bit-mask, higher 16 bits hold an indentation number @@ -46,6 +49,18 @@ type Formatter interface { ToString(options FmtOpt) string } +func Format(sb *strings.Builder, item any, opt FmtOpt) { + if s, ok := item.(string); ok { + sb.WriteByte('"') + sb.WriteString(s) + sb.WriteByte('"') + } else if formatter, ok := item.(Formatter); ok { + sb.WriteString(formatter.ToString(opt)) + } else { + fmt.Fprintf(sb, "%v", item) + } +} + func GetFormatted(v any, opt FmtOpt) (text string) { if v == nil { text = "(nil)" diff --git a/kern/list-type.go b/kern/list-type.go index 7bf6c27..d461148 100644 --- a/kern/list-type.go +++ b/kern/list-type.go @@ -73,15 +73,7 @@ func (ls *ListType) ToString(opt FmtOpt) (s string) { sb.WriteString(", ") } } - if s, ok := item.(string); ok { - sb.WriteByte('"') - sb.WriteString(s) - sb.WriteByte('"') - } else if formatter, ok := item.(Formatter); ok { - sb.WriteString(formatter.ToString(innerOpt)) - } else { - sb.WriteString(fmt.Sprintf("%v", item)) - } + Format(&sb, item, innerOpt) } if flags&MultiLine != 0 { sb.WriteByte('\n') @@ -104,11 +96,11 @@ func (ls *ListType) TypeName() string { return "list" } -func (dict *ListType) Contains(t *ListType) (answer bool) { - if len(*dict) >= len(*t) { +func (ls *ListType) Contains(t *ListType) (answer bool) { + if len(*ls) >= len(*t) { answer = true for _, item := range *t { - if answer = dict.IndexDeepSameCmp(item) >= 0; !answer { + if answer = ls.IndexDeepSameCmp(item) >= 0; !answer { break } } @@ -116,10 +108,10 @@ func (dict *ListType) Contains(t *ListType) (answer bool) { return } -func (ls1 *ListType) Equals(ls2 ListType) (answer bool) { - if ls2 != nil && len(*ls1) == len(ls2) { +func (ls *ListType) Equals(ls2 ListType) (answer bool) { + if ls2 != nil && len(*ls) == len(ls2) { answer = true - for index, i1 := range *ls1 { + for index, i1 := range *ls { // if !reflect.DeepEqual(i1, ls2[index]) { // answer = false // break @@ -142,11 +134,11 @@ func (ls1 *ListType) Clone() (ls2 *ListType) { return } -func (dict *ListType) IndexDeepSameCmp(target any) (index int) { +func (ls *ListType) IndexDeepSameCmp(target any) (index int) { var eq bool var err error index = -1 - for i, item := range *dict { + for i, item := range *ls { if eq, err = deepSame(item, target, SameContent); err != nil { break } else if eq { @@ -197,15 +189,15 @@ func deepSame(a, b any, deepCmp DeepFuncTemplate) (eq bool, err error) { return } -func (dict *ListType) SetItem(index int64, value any) (err error) { - if index >= 0 && index < int64(len(*dict)) { - (*dict)[index] = value +func (ls *ListType) SetItem(index int64, value any) (err error) { + if index >= 0 && index < int64(len(*ls)) { + (*ls)[index] = value } else { - err = fmt.Errorf("index %d out of bounds (0, %d)", index, len(*dict)-1) + err = fmt.Errorf("index %d out of bounds (0, %d)", index, len(*ls)-1) } return } -func (dict *ListType) AppendItem(value any) { - *dict = append(*dict, value) +func (ls *ListType) AppendItem(value any) { + *ls = append(*ls, value) } diff --git a/parser.go b/parser.go index 69f3f64..d3fa388 100644 --- a/parser.go +++ b/parser.go @@ -6,6 +6,7 @@ package expr import ( "errors" + "fmt" "slices" "git.portale-stac.it/go-pkg/expr/scan" @@ -164,16 +165,16 @@ func paramAlreadyDefined(args []*scan.Term, param *scan.Term) (position int) { return } -func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext) (listTerm *scan.Term, err error) { +func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSym scan.Symbol) (listTerm *scan.Term, err error) { r, c := scanner.LastPos() args := make([]*scan.Term, 0) lastSym := scan.SymUnknown itemExpected := false itemCtx := remFlags(ctx, allowIndex) - for lastSym != scan.SymClosedSquare && lastSym != scan.SymEos { + for lastSym != termSym && lastSym != scan.SymEos { zeroRequired := scanner.Current().Sym == scan.SymColon var itemTree *scan.Ast - if itemTree, err = parser.parseItem(scanner, itemCtx, scan.SymComma, scan.SymClosedSquare); err == nil { + if itemTree, err = parser.parseItem(scanner, itemCtx, scan.SymComma, termSym); err == nil { root := itemTree.Root() if root != nil { if hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymColon { @@ -212,10 +213,14 @@ func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext) (listT } } if err == nil { - if lastSym != scan.SymClosedSquare { + if lastSym != termSym { err = scanner.Previous().ErrorExpectedGot("]") - } else { + } else if termSym == scan.SymClosedSquare { listTerm = newListTerm(r, c, args) + } else if termSym == scan.SymGreaterClosedSquare { + listTerm = newLinkedListTerm(r, c, args) + } else { + err = fmt.Errorf("[%d:%d] unknown list type", r, c) } } return @@ -327,7 +332,7 @@ func (parser *parser) parseSelectorCase(scanner *scan.Scanner, ctx parserContext err = tk.Errorf("case list in default clause") return } - if filterList, err = parser.parseList(scanner, remFlags(ctx, allowIndex)); err != nil { + if filterList, err = parser.parseList(scanner, remFlags(ctx, allowIndex), scan.SymClosedSquare); err != nil { return } tk = parser.Next(scanner) @@ -446,7 +451,7 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter tree = scan.NewAst() firstToken := true // lastSym := SymUnknown - for tk = parser.Next(scanner); err == nil && tk != nil && !tk.IsTerm(termSymbols); /*&& !areSymbolsOutOfCtx(tk, selectorTerm, SymColon, SymDoubleColon)*/ tk = parser.Next(scanner) { + for tk = parser.Next(scanner); err == nil && tk != nil && !tk.IsTerm(termSymbols); tk = parser.Next(scanner) { // if tk.Sym == SymComment { // continue // } @@ -491,7 +496,13 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter case scan.SymOpenSquare: var listTerm *scan.Term newCtx := addFlagsCond(addFlags(ctx, squareContext), allowIndex, couldBeACollection(currentTerm)) - if listTerm, err = parser.parseList(scanner, newCtx); err == nil { + if listTerm, err = parser.parseList(scanner, newCtx, scan.SymClosedSquare); err == nil { + currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex)) + } + case scan.SymOpenSquareLess: + var listTerm *scan.Term + newCtx := addFlagsCond(addFlags(ctx, listContext), allowIndex, false) + if listTerm, err = parser.parseList(scanner, newCtx, scan.SymGreaterClosedSquare); err == nil { currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex)) } case scan.SymOpenBrace: diff --git a/scan/scanner.go b/scan/scanner.go index 89d9d87..4ddde62 100644 --- a/scan/scanner.go +++ b/scan/scanner.go @@ -315,6 +315,8 @@ func (scanner *Scanner) fetchNextToken() (tk *Token) { } else { tk = scanner.accept(SymDoubleGreater, ch, next) } + } else if next == ']' { + tk = scanner.moveOn(SymGreaterClosedSquare, ch, next) } else { tk = scanner.MakeToken(SymGreater, ch) } @@ -344,7 +346,11 @@ func (scanner *Scanner) fetchNextToken() (tk *Token) { case ')': tk = scanner.MakeToken(SymClosedRound, ch) case '[': - tk = scanner.MakeToken(SymOpenSquare, ch) + if next, _ := scanner.peek(); next == '<' { + tk = scanner.moveOn(SymOpenSquareLess, ch, next) + } else { + tk = scanner.MakeToken(SymOpenSquare, ch) + } case ']': tk = scanner.MakeToken(SymClosedSquare, ch) case '{': diff --git a/scan/symbol-map.go b/scan/symbol-map.go index ff89794..760669a 100644 --- a/scan/symbol-map.go +++ b/scan/symbol-map.go @@ -32,80 +32,82 @@ 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: '--' + 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 @@ -123,6 +125,7 @@ func init() { // SymFuncCall // SymFuncDef // SymList + // SymLinkedList // SymDict // SymIndex // SymExpression diff --git a/scan/symbol.go b/scan/symbol.go index 18691b3..ce175db 100644 --- a/scan/symbol.go +++ b/scan/symbol.go @@ -7,104 +7,107 @@ package scan type Symbol int16 const ( - SymUnknown Symbol = iota - 1 // -1: Unknown symbol - SymNone // 0: Null value for variable of type symbol - SymError // 1: Error reading from stream - SymEos // 2: End of stream - SymMinus // 3: '-' - SymMinusEqual // 4: '-=' - SymDoubleMinus // 5: '--' - SymPlus // 6: '+' - SymPlusEqual // 7: '+=' - SymDoublePlus // 8: '++' - SymStar // 9: '*' - SymDoubleStar // 10: '**' - SymSlash // 11: '/' - SymBackSlash // 12: '\' - SymVertBar // 13: '|' - SymDoubleVertBar // 14: '||' - SymComma // 15: ',' - SymColon // 16: ':' - SymSemiColon // 17: ';' - SymDot // 18: '.' - SymDotSlash // 19: './' - SymQuote // 20: '\'' - SymDoubleQuote // 21: '"' - SymBackTick // 22: '`' - SymExclamation // 23: '!' - SymQuestion // 24: '?' - SymAmpersand // 25: '&' - SymDoubleAmpersand // 26: '&&' - SymPercent // 27: '%' - SymAt // 28: '@' - SymUndescore // 29: '_' - SymEqual // 30: '=' - SymColonEqual // 31: ':=' - SymDoubleEqual // 32: '==' - SymLess // 33: '<' - SymLessOrEqual // 34: '<=' - SymGreater // 35: '>' - SymGreaterOrEqual // 36: '>=' - SymLessGreater // 37: '<>' - SymNotEqual // 38: '!=' - SymDollar // 39: '$' - SymHash // 40: '#' - SymOpenRound // 41: '(' - SymClosedRound // 42: ')' - SymOpenSquare // 43: '[' - SymClosedSquare // 44: ']' - SymOpenBrace // 45: '{' - SymClosedBrace // 46: '}' - SymTilde // 47: '~' - SymDoubleQuestion // 48: '??' - SymQuestionEqual // 49: '?=' - SymQuestionExclam // 50: '?!' - SymDoubleAt // 51: '@@' - SymDoubleColon // 52: '::' - SymDoubleGreater // 53: '>>' - SymDoubleLess // 54: '<<' - SymCaret // 55: '^' - SymDollarRound // 56: '$(' - SymOpenClosedRound // 57: '()' - SymDoubleDollar // 58: '$$' - SymDoubleDot // 59: '..' - SymTripleDot // 60: '...' - SymStarEqual // 61: '*=' - SymSlashEqual // 62: '/=' - SymPercEqual // 63: '%=' - SymDoubleLessEqual // 64: '<<=' - SymDoubleGreaterEqual // 65: '>>=' - SymAmpersandEqual // 66: '&=' - SymVertBarEqual // 67: '|=' - SymCaretEqual // 68: '^=' - SymPlusGreater // 69: '+>' - SymLessPlus // 70: '<+' - SymChangeSign // 71: '-' - SymUnchangeSign // 72: '+'' - SymDereference // 73: '*' - SymPreInc // 74: '++' - SymPreDec // 75: '--' - SymIdentifier // 76: identifier - SymBool // 77: boolean - SymInteger // 78: integer - SymVariable // 79: variable - SymFloat // 80: float - SymFraction // 81: fraction - SymString // 82: string - SymIterator // 83: iterator - SymOr // 84: 'or' - SymAnd // 85: 'and' - SymNot // 86: 'not' - SymComment // 87: comment - SymFuncCall // 88: function call - SymFuncDef // 89: function definition - SymList // 90: list - SymDict // 91: dict - SymIndex // 92: index - SymRange // 93: range [index : index] - SymExpression // 94: expression - SymSelector // 95: selector ::= "?" {":" } ["::" ] - SymSelectorCase // 96: ::= [] "{" "}" + SymUnknown Symbol = iota - 1 // -1: Unknown symbol + SymNone // 0: Null value for variable of type symbol + SymError // 1: Error reading from stream + SymEos // 2: End of stream + SymMinus // 3: '-' + SymMinusEqual // 4: '-=' + SymDoubleMinus // 5: '--' + SymPlus // 6: '+' + SymPlusEqual // 7: '+=' + SymDoublePlus // 8: '++' + SymStar // 9: '*' + SymDoubleStar // 10: '**' + SymSlash // 11: '/' + SymBackSlash // 12: '\' + SymVertBar // 13: '|' + SymDoubleVertBar // 14: '||' + SymComma // 15: ',' + SymColon // 16: ':' + SymSemiColon // 17: ';' + SymDot // 18: '.' + SymDotSlash // 19: './' + SymQuote // 20: '\'' + SymDoubleQuote // 21: '"' + SymBackTick // 22: '`' + SymExclamation // 23: '!' + SymQuestion // 24: '?' + SymAmpersand // 25: '&' + SymDoubleAmpersand // 26: '&&' + SymPercent // 27: '%' + SymAt // 28: '@' + SymUndescore // 29: '_' + SymEqual // 30: '=' + SymColonEqual // 31: ':=' + SymDoubleEqual // 32: '==' + SymLess // 33: '<' + SymLessOrEqual // 34: '<=' + SymGreater // 35: '>' + SymGreaterOrEqual // 36: '>=' + SymLessGreater // 37: '<>' + SymNotEqual // 38: '!=' + SymDollar // 39: '$' + SymHash // 40: '#' + SymOpenRound // 41: '(' + SymClosedRound // 42: ')' + SymOpenSquare // 43: '[' + SymClosedSquare // 44: ']' + SymOpenBrace // 45: '{' + SymClosedBrace // 46: '}' + SymTilde // 47: '~' + SymDoubleQuestion // 48: '??' + SymQuestionEqual // 49: '?=' + SymQuestionExclam // 50: '?!' + SymDoubleAt // 51: '@@' + SymDoubleColon // 52: '::' + SymDoubleGreater // 53: '>>' + SymDoubleLess // 54: '<<' + SymCaret // 55: '^' + SymDollarRound // 56: '$(' + SymOpenClosedRound // 57: '()' + SymDoubleDollar // 58: '$$' + SymDoubleDot // 59: '..' + SymTripleDot // 60: '...' + SymStarEqual // 61: '*=' + SymSlashEqual // 62: '/=' + SymPercEqual // 63: '%=' + SymDoubleLessEqual // 64: '<<=' + SymDoubleGreaterEqual // 65: '>>=' + SymAmpersandEqual // 66: '&=' + SymVertBarEqual // 67: '|=' + SymCaretEqual // 68: '^=' + SymPlusGreater // 69: '+>' + SymLessPlus // 70: '<+' + SymChangeSign // 71: '-' + SymUnchangeSign // 72: '+'' + SymDereference // 73: '*' + SymPreInc // 74: '++' + SymPreDec // 75: '--' + SymIdentifier // 76: identifier + SymBool // 77: boolean + SymInteger // 78: integer + SymVariable // 79: variable + SymFloat // 80: float + SymFraction // 81: fraction + SymString // 82: string + SymIterator // 83: iterator + SymOr // 84: 'or' + SymAnd // 85: 'and' + SymNot // 86: 'not' + SymComment // 87: comment + SymFuncCall // 88: function call + SymFuncDef // 89: function definition + SymList // 90: list + SymDict // 91: dict + SymIndex // 92: index + SymRange // 93: range [index : index] + SymExpression // 94: expression + SymSelector // 95: selector ::= "?" {":" } ["::" ] + SymSelectorCase // 96: ::= [] "{" "}" + SymOpenSquareLess // 97: '[<' + SymGreaterClosedSquare // 98: '>]' + SymLinkedList // 99: linked-list // SymOpenComment // 0: '/*' // SymClosedComment // 0: '*/' // SymOneLineComment // 0: '//' diff --git a/t_builtin-base_test.go b/t_builtin-base_test.go index 2f9042a..0557185 100644 --- a/t_builtin-base_test.go +++ b/t_builtin-base_test.go @@ -118,8 +118,8 @@ func TestFuncBaseOthers(t *testing.T) { inputs := []inputType{ /* 1 */ {`set("a", 3); a`, int64(3), nil}, /* 2 */ {`set(true, 3)`, nil, `set(): the "name" parameter must be a string, got a bool (true)`}, - // /* 3 */ {`a=3; unset("a"); a`, nil, `undefined variable or function "a"`}, - // /* 4 */ {`unset("a")`, nil, `undefined variable or function "a"`}, + /* 3 */ {`seq(1,2,3)`, kern.NewLinkedListA(int64(1), int64(2), int64(3)), nil}, + // /* 4 */ {`seq(1,2,4)`, kern.NewLinkedListA(int64(1), int64(2), int64(3)), nil}, } // runTestSuiteSpec(t, section, inputs, 4) diff --git a/t_list_test.go b/t_list_test.go index 4125b67..ef8a822 100644 --- a/t_list_test.go +++ b/t_list_test.go @@ -57,10 +57,24 @@ func TestListParser(t *testing.T) { /* 41 */ {`[0] << $([1,2,3,4])`, kern.NewListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, /* 42 */ {`L=[]; [1] >> L; L`, kern.NewListA(), nil}, /* 43 */ {`L=[]; L << [1]; L`, kern.NewListA(), nil}, + // /* 44 */ {`[0,1,2,3,4][2:3]`, kern.NewListA(int64(20)), nil}, } // t.Setenv("EXPR_PATH", ".") - // runTestSuiteSpec(t, section, inputs, 42) + // runTestSuiteSpec(t, section, inputs, 44) + runTestSuite(t, section, inputs) +} + +func TestLinkedListParser(t *testing.T) { + section := "Linked-List" + + inputs := []inputType{ + /* 1 */ {`[<1,2>]`, kern.NewLinkedListA(int64(1), int64(2)), nil}, + } + + // t.Setenv("EXPR_PATH", ".") + + // runTestSuiteSpec(t, section, inputs, 44) runTestSuite(t, section, inputs) }