// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // operator-insert.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/array" "git.portale-stac.it/go-pkg/expr/types/list" ) //-------- prepend term func newPrependTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriInsert, EvalFunc: evalPrepend, } } func newAppendTerm(tk *scan.Token) (inst *scan.Term) { return &scan.Term{ Tk: *tk, Children: make([]*scan.Term, 0, 2), Position: scan.PosInfix, Priority: scan.PriInsert, EvalFunc: evalAppend, } } func prependToList(opTerm kern.Term, leftValue, rightValue any) (result any, err error) { if a, ok := rightValue.(*array.ArrayType); ok { var it kern.Iterator if it, ok = leftValue.(kern.Iterator); !ok { it = NewFormalIterator(leftValue) } ls := list.NewLinkedList() ls.SeqPushBack(it) newArray := array.ArrayType(nil) if newSize := len(*a) + int(ls.Len()); newSize > cap(*a) { newArray = make([]any, 0, newSize) for node := ls.FirstNode(); node != nil; node = node.Next() { newArray = append(newArray, node.Data()) } } for _, item := range *a { newArray = append(newArray, item) } if opTerm.GetRightChild().IsVar() { // Update the original array if the right operand is a variable *a = newArray } result = &newArray } else if ll, ok := rightValue.(*list.LinkedList); ok { var it kern.Iterator if it, ok = leftValue.(kern.Iterator); !ok { it = NewFormalIterator(leftValue) } result = ll.SeqPushBack(it) } else { err = opTerm.ErrIncompatibleTypes(leftValue, rightValue) } return } func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil { return } v, err = prependToList(opTerm, leftValue, rightValue) return } func appendToList(opTerm kern.Term, leftValue, rightValue any) (result any, err error) { if a, ok := leftValue.(*array.ArrayType); ok { var it kern.Iterator if it, ok = rightValue.(kern.Iterator); !ok { it = NewFormalIterator(rightValue) } ls := list.NewLinkedList() ls.SeqPushBack(it) newArray := *a if newSize := len(*a) + int(ls.Len()); newSize > cap(*a) { newArray = make([]any, 0, newSize) for _, item := range *a { newArray = append(newArray, item) } } for node := ls.FirstNode(); node != nil; node = node.Next() { newArray = append(newArray, node.Data()) } if opTerm.GetLeftChild().IsVar() { // Update the original array if the left operand is a variable *a = newArray } result = &newArray } else if ll, ok := leftValue.(*list.LinkedList); ok { var it kern.Iterator if it, ok = rightValue.(kern.Iterator); !ok { it = NewFormalIterator(rightValue) } result = ll.SeqPushBack(it) } else { err = opTerm.ErrIncompatibleTypes(leftValue, rightValue) } return } func evalAppend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil { return } v, err = appendToList(opTerm, leftValue, rightValue) return } // init func init() { scan.RegisterTermConstructor(sym.SymPlusGreater, newPrependTerm) scan.RegisterTermConstructor(sym.SymLessPlus, newAppendTerm) }