listutils.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package zygo
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. var NotAList = errors.New("not a list")
  7. func ListToArray(expr Sexp) ([]Sexp, error) {
  8. if !IsList(expr) {
  9. return nil, NotAList
  10. }
  11. arr := make([]Sexp, 0)
  12. for expr != SexpNull {
  13. list := expr.(*SexpPair)
  14. arr = append(arr, list.Head)
  15. expr = list.Tail
  16. }
  17. return arr, nil
  18. }
  19. func MakeList(expressions []Sexp) Sexp {
  20. if len(expressions) == 0 {
  21. return SexpNull
  22. }
  23. return Cons(expressions[0], MakeList(expressions[1:]))
  24. }
  25. func MapList(env *Zlisp, fun *SexpFunction, expr Sexp) (Sexp, error) {
  26. if expr == SexpNull {
  27. return SexpNull, nil
  28. }
  29. var list = &SexpPair{}
  30. switch e := expr.(type) {
  31. case *SexpPair:
  32. list.Head = e.Head
  33. list.Tail = e.Tail
  34. default:
  35. return SexpNull, NotAList
  36. }
  37. var err error
  38. list.Head, err = env.Apply(fun, []Sexp{list.Head})
  39. if err != nil {
  40. return SexpNull, err
  41. }
  42. list.Tail, err = MapList(env, fun, list.Tail)
  43. if err != nil {
  44. return SexpNull, err
  45. }
  46. return list, nil
  47. }
  48. // O(n^2) for n total nodes in all lists. So this is
  49. // not super efficient. We have to
  50. // find the tail of each list in turn by
  51. // linear search. Avoid lists if possible in favor
  52. // of arrays.
  53. func ConcatLists(a *SexpPair, bs []Sexp) (Sexp, error) {
  54. result := a
  55. for _, b := range bs {
  56. res, err := ConcatTwoLists(result, b)
  57. if err != nil {
  58. return SexpNull, err
  59. }
  60. x, ok := res.(*SexpPair)
  61. if !ok {
  62. return SexpNull, NotAList
  63. }
  64. result = x
  65. }
  66. return result, nil
  67. }
  68. func ConcatTwoLists(a *SexpPair, b Sexp) (Sexp, error) {
  69. if !IsList(b) {
  70. return SexpNull, NotAList
  71. }
  72. if a.Tail == SexpNull {
  73. return Cons(a.Head, b), nil
  74. }
  75. switch t := a.Tail.(type) {
  76. case *SexpPair:
  77. newtail, err := ConcatTwoLists(t, b)
  78. if err != nil {
  79. return SexpNull, err
  80. }
  81. return Cons(a.Head, newtail), nil
  82. }
  83. return SexpNull, NotAList
  84. }
  85. func ListLen(expr Sexp) (int, error) {
  86. sz := 0
  87. var list *SexpPair
  88. ok := false
  89. for expr != SexpNull {
  90. list, ok = expr.(*SexpPair)
  91. if !ok {
  92. return 0, fmt.Errorf("ListLen() called on non-list")
  93. }
  94. sz++
  95. expr = list.Tail
  96. }
  97. return sz, nil
  98. }