diff --git a/kern/linked-list.go b/kern/linked-list.go new file mode 100644 index 0000000..d61ab3f --- /dev/null +++ b/kern/linked-list.go @@ -0,0 +1,273 @@ +// simple-list project slist.go +package kern + +import ( + "fmt" +) + +type ListNode struct { + data any + next *ListNode +} + +func (node *ListNode) Next() *ListNode { + return node.next +} + +func (self *ListNode) Data() any { + return self.data +} + +type LinkedList struct { + count uint32 + first *ListNode + last *ListNode +} + +func NewLinkedList() (list *LinkedList) { + list = &LinkedList{0, nil, nil} + return +} + +func (ls *LinkedList) Len() uint32 { + return ls.count +} + +func (ls *LinkedList) Empty() bool { + return ls.count == 0 +} + +func (ls *LinkedList) PushFront(data any) *ListNode { + ls.first = &ListNode{data, ls.first} + if ls.last == nil { + ls.last = ls.first + } + ls.count++ + return ls.first +} + +func (ls *LinkedList) SeqPushFront(data any) (result *LinkedList) { + switch seq := data.(type) { + case Iterator: + result = ls.IterPushFront(seq) + default: + ls.PushFront(data) + result = ls + } + return +} + +func (ls *LinkedList) IterPushFront(it Iterator) *LinkedList { + for item, err1 := it.Next(); err1 == nil; item, err1 = it.Next() { + ls.PushFront(item) + } + return ls +} + +func (ls *LinkedList) PushBack(data any) (node *ListNode) { + node = &ListNode{data, nil} + if ls.last != nil { + ls.last.next = node + } + ls.last = node + if ls.first == nil { + ls.first = node + } + ls.count++ + return +} + +func (ls *LinkedList) SeqPushBack(data any) (result *LinkedList) { + switch seq := data.(type) { + case Iterator: + result = ls.IterPushBack(seq) + default: + ls.PushBack(data) + result = ls + } + return +} + +func (ls *LinkedList) IterPushBack(it Iterator) *LinkedList { + for item, err1 := it.Next(); err1 == nil; item, err1 = it.Next() { + ls.PushBack(item) + } + return ls +} + +func (ls *LinkedList) FirstNode() *ListNode { + return ls.first +} + +func (ls *LinkedList) First() (data any, err error) { + if ls.first != nil { + data = ls.first.data + } else { + err = errorListEmpty() + } + return +} + +func (ls *LinkedList) LastNode() *ListNode { + return ls.last +} + +func (ls *LinkedList) Last() (data interface{}, err error) { + if ls.last != nil { + data = ls.last.data + } else { + err = errorListEmpty() + } + return +} + +func (ls *LinkedList) NodeAt(index uint32) (node *ListNode, err error) { + if ls.count == 0 { + err = errorListEmpty() + } else if index > ls.count { + err = errorOutOfRange() + } else if index == ls.count-1 { + node = ls.last + } else { + current := ls.first + for pos := uint32(0); pos < index; pos++ { + current = current.next + } + node = current + } + return +} + +func (ls *LinkedList) At(index uint32) (data interface{}, err error) { + node, err := ls.NodeAt(index) + if err == nil { + data = node.data + } + return +} + +func (ls *LinkedList) Insert(index uint32, data interface{}) *ListNode { + var prev *ListNode + + prev = nil + current := ls.first + for pos := uint32(0); current != nil && pos < index; pos++ { + prev = current + current = current.next + } + + node := &ListNode{data, current} + + if prev != nil { + prev.next = node + } + + if ls.first == current { + ls.first = node + } + if node.next == nil { + ls.last = node + } + ls.count++ + return node +} + +func (ls *LinkedList) PushBackStringArray(items []string) { + for _, v := range items { + ls.PushBack(v) + } +} + +// type TraverseOperator func(index uint32, elem interface{}, userData interface{}) (err error) + +// func (self *LinkedList) Traverse(op TraverseOperator, user_data interface{}) (err error) { +// index := uint32(0) +// for current := self.first; current != nil; current = current.next { +// err = op(index, current.data, user_data) +// if err != nil { +// break +// } +// index++ +// } +// return +// } + +// func (self *LinkedList) Traverse2(observer Observer, abortOnError bool) (err error) { +// index := uint32(0) +// for current := self.first; current != nil; current = current.next { +// err = observer.Observe(current, index) +// if err != nil && abortOnError { +// break +// } +// index++ +// } +// return +// } + +type EqualFunc func(current, target any) bool + +func (ls *LinkedList) FindFirst(eqFunc EqualFunc, targetData any) (targetNode *ListNode) { + for current := ls.first; current != nil && targetNode == nil; current = current.next { + if eqFunc(current.data, targetData) { + targetNode = current + } + } + return +} + +func (ls *LinkedList) FindNext(eqFunc EqualFunc, startNode *ListNode) (targetNode *ListNode) { + if startNode != nil { + for current := startNode.next; current != nil && targetNode == nil; current = current.next { + if eqFunc(current.data, startNode.Data()) { + targetNode = current + } + } + } + return +} + +// type DataFeeder func(user_data interface{}) interface{} +// type NodeObserver func(node *ListNode, index uint32, userData interface{}) + +// func (self *LinkedList) FeedTail(feeder DataFeeder, feederUserData interface{}, observer NodeObserver, observerUserData interface{}) (count uint32) { +// count = 0 +// for item := feeder(feederUserData); item != nil; item = feeder(feederUserData) { +// // fmt.Println("Item", count, item) +// node := self.PushBack(item) +// if observer != nil { +// observer(node, count, observerUserData) +// } +// count++ +// } +// return +// } + +// func (self *LinkedList) FeedTail2(feeder Feeder, observer Observer, abortOnError bool) (count uint32, err error) { +// count = 0 +// // item := feeder.Next() +// for item, err1 := feeder.Next(); item != nil; item, err1 = feeder.Next() { +// if err1 != nil { +// if err == nil { +// err = err1 +// } +// if abortOnError { +// break +// } +// } +// // fmt.Println("Item", count, item) +// node := self.PushBack(item) +// if observer != nil { +// observer.Observe(node, count) +// } +// count++ +// } +// return +// } + +func errorListEmpty() error { + return fmt.Errorf("List is empty") +} + +func errorOutOfRange() error { + return fmt.Errorf("Out of range") +} diff --git a/kern/list-type.go b/kern/list-type.go index eec3b48..0e2da80 100644 --- a/kern/list-type.go +++ b/kern/list-type.go @@ -50,13 +50,13 @@ func ListFromStrings(stringList []string) (list *ListType) { return } -func (dict *ListType) ToString(opt FmtOpt) (s string) { +func (ls *ListType) ToString(opt FmtOpt) (s string) { indent := GetFormatIndent(opt) flags := GetFormatFlags(opt) var sb strings.Builder sb.WriteByte('[') - if len(*dict) > 0 { + if len(*ls) > 0 { innerOpt := MakeFormatOptions(flags, indent+1) nest := strings.Repeat(" ", indent+1) @@ -64,7 +64,7 @@ func (dict *ListType) ToString(opt FmtOpt) (s string) { sb.WriteByte('\n') sb.WriteString(nest) } - for i, item := range []any(*dict) { + for i, item := range []any(*ls) { if i > 0 { if flags&MultiLine != 0 { sb.WriteString(",\n") @@ -96,11 +96,11 @@ func (dict *ListType) ToString(opt FmtOpt) (s string) { return } -func (dict *ListType) String() string { - return dict.ToString(0) +func (ls *ListType) String() string { + return ls.ToString(0) } -func (dict *ListType) TypeName() string { +func (ls *ListType) TypeName() string { return "list" } diff --git a/operator-insert.go b/operator-insert.go index 2869d13..15039d7 100644 --- a/operator-insert.go +++ b/operator-insert.go @@ -31,6 +31,41 @@ func newAppendTerm(tk *scan.Token) (inst *scan.Term) { } } +func prependToList(ctx kern.ExprContext, opTerm *scan.Term, leftValue, rightValue any) (result any, err error) { + if list, ok := rightValue.(*kern.ListType); ok { + var it kern.Iterator + if it, ok = leftValue.(kern.Iterator); !ok { + if it, err = NewIterator(ctx, leftValue, nil); err != nil { + return + } + } + + ls := kern.NewLinkedList() + ls.SeqPushBack(it) + + newList := kern.ListType(nil) + if newSize := len(*list) + int(ls.Len()); newSize > cap(*list) { + newList = make([]any, 0, newSize) + for node := ls.FirstNode(); node != nil; node = node.Next() { + newList = append(newList, node.Data()) + } + } + for _, item := range *list { + newList = append(newList, item) + } + result = &newList + + // ***** EVENTUALMENTE ABILITARE LA MODIFICA DELLA VARIABILE + // ***** CON UN OPERATORE SPECIFICO + // if opTerm.Children[1].Symbol() == scan.SymVariable { + // ctx.UnsafeSetVar(opTerm.Children[1].Source(), result) + // } + } else { + err = opTerm.ErrIncompatibleTypes(leftValue, rightValue) + } + return +} + func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any @@ -38,13 +73,39 @@ func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { return } - if kern.IsList(rightValue) { - list, _ := rightValue.(*kern.ListType) - newList := append(kern.ListType{leftValue}, *list...) - v = &newList - if opTerm.Children[1].Symbol() == scan.SymVariable { - ctx.UnsafeSetVar(opTerm.Children[1].Source(), v) + v, err = prependToList(ctx, opTerm, leftValue, rightValue) + return +} + +func appendToList(ctx kern.ExprContext, opTerm *scan.Term, leftValue, rightValue any) (result any, err error) { + if list, ok := leftValue.(*kern.ListType); ok { + var it kern.Iterator + if it, ok = rightValue.(kern.Iterator); !ok { + if it, err = NewIterator(ctx, rightValue, nil); err != nil { + return + } } + + ls := kern.NewLinkedList() + ls.SeqPushBack(it) + + newList := *list + if newSize := len(*list) + int(ls.Len()); newSize > cap(*list) { + newList = make([]any, 0, newSize) + for _, item := range *list { + newList = append(newList, item) + } + } + for node := ls.FirstNode(); node != nil; node = node.Next() { + newList = append(newList, node.Data()) + } + result = &newList + + // ***** EVENTUALMENTE ABILITARE LA MODIFICA DELLA VARIABILE + // ***** CON UN OPERATORE SPECIFICO + // if opTerm.Children[0].Symbol() == scan.SymVariable { + // ctx.UnsafeSetVar(opTerm.Children[0].Source(), result) + // } } else { err = opTerm.ErrIncompatibleTypes(leftValue, rightValue) } @@ -58,16 +119,8 @@ func evalAppend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { return } - if kern.IsList(leftValue) { - list, _ := leftValue.(*kern.ListType) - newList := append(*list, rightValue) - v = &newList - if opTerm.Children[0].Symbol() == scan.SymVariable { - ctx.UnsafeSetVar(opTerm.Children[0].Source(), v) - } - } else { - err = opTerm.ErrIncompatibleTypes(leftValue, rightValue) - } + v, err = appendToList(ctx, opTerm, leftValue, rightValue) + return } diff --git a/operator-shift.go b/operator-shift.go index 043640a..d8ad99e 100644 --- a/operator-shift.go +++ b/operator-shift.go @@ -39,7 +39,9 @@ func evalRightShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) return } - v, err = bitRightShift(opTerm, leftValue, rightValue) + if v, err = bitRightShift(opTerm, leftValue, rightValue); err != nil { + v, err = prependToList(ctx, opTerm, leftValue, rightValue) + } return } @@ -71,7 +73,9 @@ func evalLeftShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { return } - v, err = bitLeftShift(opTerm, leftValue, rightValue) + if v, err = bitLeftShift(opTerm, leftValue, rightValue); err != nil { + v, err = appendToList(ctx, opTerm, leftValue, rightValue) + } return } diff --git a/t_list_test.go b/t_list_test.go index be3c798..4125b67 100644 --- a/t_list_test.go +++ b/t_list_test.go @@ -54,10 +54,13 @@ func TestListParser(t *testing.T) { /* 38 */ {`[0,1,2,3,4][3:-1]`, kern.NewListA(int64(3)), nil}, /* 30 */ {`[0,1,2,3,4][-3:-1]`, kern.NewListA(int64(2), int64(3)), nil}, /* 40 */ {`[0,1,2,3,4][0:]`, kern.NewListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, + /* 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}, } // t.Setenv("EXPR_PATH", ".") - // runTestSuiteSpec(t, section, inputs, 1) + // runTestSuiteSpec(t, section, inputs, 42) runTestSuite(t, section, inputs) } diff --git a/t_operator_test.go b/t_operator_test.go index 2a44143..aed8a38 100644 --- a/t_operator_test.go +++ b/t_operator_test.go @@ -43,6 +43,25 @@ func TestOperator(t *testing.T) { runTestSuite(t, section, inputs) } +func TestOperatorInsert(t *testing.T) { + section := "Operator-Insert" + inputs := []inputType{ + /* 1 */ {`["a", "b"] << nil`, kern.NewListA("a", "b"), nil}, + /* 2 */ {`["a", "b"] << []`, kern.NewListA("a", "b"), nil}, + /* 3 */ {`["a", "b"] << 3`, kern.NewListA("a", "b", int64(3)), nil}, + /* 4 */ {`3 << ["a", "b"]`, nil, `[1:5] left operand '3' [integer] and right operand '["a", "b"]' [list] are not compatible with operator "<<"`}, + /* 5 */ {`nil >> ["a", "b"]`, kern.NewListA("a", "b"), nil}, + /* 6 */ {`[] >> ["a", "b"]`, kern.NewListA("a", "b"), nil}, + /* 7 */ {`["a", "b"] << $([1,2,3])`, kern.NewListA("a", "b", int64(1), int64(2), int64(3)), nil}, + /* 8 */ {`L=["a", "b"]; L << $([1,2,3])`, kern.NewListA("a", "b", int64(1), int64(2), int64(3)), nil}, + /* 9 */ {`L=["a", "b"]; L << $([1,2,3]); L`, kern.NewListA("a", "b", int64(1), int64(2), int64(3)), nil}, + /* 10 */ {`L << $([1,2,3])`, nil, `undefined variable or function "L"`}, + } + + // runTestSuiteSpec(t, section, inputs, 9) + runTestSuite(t, section, inputs) +} + func TestOperatorDigest(t *testing.T) { section := "Operator-Digest" inputs := []inputType{ diff --git a/t_symbol_test.go b/t_symbol_test.go index 3c82442..2e4e196 100644 --- a/t_symbol_test.go +++ b/t_symbol_test.go @@ -32,15 +32,15 @@ func testStringEndingWithOperator(source string) bool { return scan.StringEndsWithOperator(source) } -func testStringArrayEndingWithOperatorSpec(t *testing.T, section string, inputs []inputType, spec ...int) { - for i := range spec { - if spec[i] < 1 || spec[i] > len(inputs) { - t.Errorf("Invalid test spec index: %d (must be between 1 and %d)", spec[i], len(inputs)) - continue - } - doEndingTest(t, section, inputs[spec[i]-1], spec[i]-1) - } -} +// func testStringArrayEndingWithOperatorSpec(t *testing.T, section string, inputs []inputType, spec ...int) { +// for i := range spec { +// if spec[i] < 1 || spec[i] > len(inputs) { +// t.Errorf("Invalid test spec index: %d (must be between 1 and %d)", spec[i], len(inputs)) +// continue +// } +// doEndingTest(t, section, inputs[spec[i]-1], spec[i]-1) +// } +// } func testStringArrayEndingWithOperator(t *testing.T, section string, inputs []inputType) { for i, input := range inputs {