123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- package zygo
- import (
- "errors"
- "fmt"
- )
- var NotAList = errors.New("not a list")
- func ListToArray(expr Sexp) ([]Sexp, error) {
- if !IsList(expr) {
- return nil, NotAList
- }
- arr := make([]Sexp, 0)
- for expr != SexpNull {
- list := expr.(*SexpPair)
- arr = append(arr, list.Head)
- expr = list.Tail
- }
- return arr, nil
- }
- func MakeList(expressions []Sexp) Sexp {
- if len(expressions) == 0 {
- return SexpNull
- }
- return Cons(expressions[0], MakeList(expressions[1:]))
- }
- func MapList(env *Zlisp, fun *SexpFunction, expr Sexp) (Sexp, error) {
- if expr == SexpNull {
- return SexpNull, nil
- }
- var list = &SexpPair{}
- switch e := expr.(type) {
- case *SexpPair:
- list.Head = e.Head
- list.Tail = e.Tail
- default:
- return SexpNull, NotAList
- }
- var err error
- list.Head, err = env.Apply(fun, []Sexp{list.Head})
- if err != nil {
- return SexpNull, err
- }
- list.Tail, err = MapList(env, fun, list.Tail)
- if err != nil {
- return SexpNull, err
- }
- return list, nil
- }
- // O(n^2) for n total nodes in all lists. So this is
- // not super efficient. We have to
- // find the tail of each list in turn by
- // linear search. Avoid lists if possible in favor
- // of arrays.
- func ConcatLists(a *SexpPair, bs []Sexp) (Sexp, error) {
- result := a
- for _, b := range bs {
- res, err := ConcatTwoLists(result, b)
- if err != nil {
- return SexpNull, err
- }
- x, ok := res.(*SexpPair)
- if !ok {
- return SexpNull, NotAList
- }
- result = x
- }
- return result, nil
- }
- func ConcatTwoLists(a *SexpPair, b Sexp) (Sexp, error) {
- if !IsList(b) {
- return SexpNull, NotAList
- }
- if a.Tail == SexpNull {
- return Cons(a.Head, b), nil
- }
- switch t := a.Tail.(type) {
- case *SexpPair:
- newtail, err := ConcatTwoLists(t, b)
- if err != nil {
- return SexpNull, err
- }
- return Cons(a.Head, newtail), nil
- }
- return SexpNull, NotAList
- }
- func ListLen(expr Sexp) (int, error) {
- sz := 0
- var list *SexpPair
- ok := false
- for expr != SexpNull {
- list, ok = expr.(*SexpPair)
- if !ok {
- return 0, fmt.Errorf("ListLen() called on non-list")
- }
- sz++
- expr = list.Tail
- }
- return sz, nil
- }
|