builtin_fn_stream.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. package eval
  2. import (
  3. "fmt"
  4. "sort"
  5. "src.elv.sh/pkg/eval/errs"
  6. "src.elv.sh/pkg/eval/vals"
  7. )
  8. // Stream manipulation.
  9. func init() {
  10. addBuiltinFns(map[string]any{
  11. "all": all,
  12. "one": one,
  13. "take": take,
  14. "drop": drop,
  15. "compact": compact,
  16. "count": count,
  17. "order": order,
  18. })
  19. }
  20. func all(fm *Frame, inputs Inputs) error {
  21. out := fm.ValueOutput()
  22. var errOut error
  23. inputs(func(v any) {
  24. if errOut != nil {
  25. return
  26. }
  27. errOut = out.Put(v)
  28. })
  29. return errOut
  30. }
  31. func one(fm *Frame, inputs Inputs) error {
  32. var val any
  33. n := 0
  34. inputs(func(v any) {
  35. if n == 0 {
  36. val = v
  37. }
  38. n++
  39. })
  40. if n == 1 {
  41. return fm.ValueOutput().Put(val)
  42. }
  43. return errs.ArityMismatch{What: "values", ValidLow: 1, ValidHigh: 1, Actual: n}
  44. }
  45. func take(fm *Frame, n int, inputs Inputs) error {
  46. out := fm.ValueOutput()
  47. var errOut error
  48. i := 0
  49. inputs(func(v any) {
  50. if errOut != nil {
  51. return
  52. }
  53. if i < n {
  54. errOut = out.Put(v)
  55. }
  56. i++
  57. })
  58. return errOut
  59. }
  60. func drop(fm *Frame, n int, inputs Inputs) error {
  61. out := fm.ValueOutput()
  62. var errOut error
  63. i := 0
  64. inputs(func(v any) {
  65. if errOut != nil {
  66. return
  67. }
  68. if i >= n {
  69. errOut = out.Put(v)
  70. }
  71. i++
  72. })
  73. return errOut
  74. }
  75. func compact(fm *Frame, inputs Inputs) error {
  76. out := fm.ValueOutput()
  77. first := true
  78. var errOut error
  79. var prev any
  80. inputs(func(v any) {
  81. if errOut != nil {
  82. return
  83. }
  84. if first || !vals.Equal(v, prev) {
  85. errOut = out.Put(v)
  86. first = false
  87. prev = v
  88. }
  89. })
  90. return errOut
  91. }
  92. // The count implementation uses a custom varargs based implementation rather
  93. // than the more common `Inputs` API (see pkg/eval/go_fn.go) because this
  94. // allows the implementation to be O(1) for the common cases rather than O(n).
  95. func count(fm *Frame, args ...any) (int, error) {
  96. var n int
  97. switch nargs := len(args); nargs {
  98. case 0:
  99. // Count inputs.
  100. fm.IterateInputs(func(any) {
  101. n++
  102. })
  103. case 1:
  104. // Get length of argument.
  105. v := args[0]
  106. if len := vals.Len(v); len >= 0 {
  107. n = len
  108. } else {
  109. err := vals.Iterate(v, func(any) bool {
  110. n++
  111. return true
  112. })
  113. if err != nil {
  114. return 0, fmt.Errorf("cannot get length of a %s", vals.Kind(v))
  115. }
  116. }
  117. default:
  118. // The error matches what would be returned if the `Inputs` API was
  119. // used. See GoFn.Call().
  120. return 0, errs.ArityMismatch{What: "arguments", ValidLow: 0, ValidHigh: 1, Actual: nargs}
  121. }
  122. return n, nil
  123. }
  124. type orderOptions struct {
  125. Reverse bool
  126. Key Callable
  127. LessThan Callable
  128. }
  129. func (opt *orderOptions) SetDefaultOptions() {}
  130. func order(fm *Frame, opts orderOptions, inputs Inputs) error {
  131. var values, keys []any
  132. inputs(func(v any) { values = append(values, v) })
  133. if opts.Key != nil {
  134. keys = make([]any, len(values))
  135. for i, value := range values {
  136. outputs, err := fm.CaptureOutput(func(fm *Frame) error {
  137. return opts.Key.Call(fm, []any{value}, NoOpts)
  138. })
  139. if err != nil {
  140. return err
  141. } else if len(outputs) != 1 {
  142. return errs.ArityMismatch{
  143. What: "number of outputs of the &key callback",
  144. ValidLow: 1, ValidHigh: 1, Actual: len(outputs)}
  145. }
  146. keys[i] = outputs[0]
  147. }
  148. }
  149. s := &slice{fm, opts.LessThan, values, keys, nil}
  150. if opts.Reverse {
  151. sort.Stable(sort.Reverse(s))
  152. } else {
  153. sort.Stable(s)
  154. }
  155. if s.err != nil {
  156. return s.err
  157. }
  158. out := fm.ValueOutput()
  159. for _, v := range values {
  160. err := out.Put(v)
  161. if err != nil {
  162. return err
  163. }
  164. }
  165. return nil
  166. }
  167. type slice struct {
  168. fm *Frame
  169. lessThan Callable
  170. values []any
  171. keys []any // nil if no keys
  172. err error
  173. }
  174. func (s *slice) Len() int { return len(s.values) }
  175. func (s *slice) Less(i, j int) bool {
  176. if s.err != nil {
  177. return true
  178. }
  179. var a, b any
  180. if s.keys != nil {
  181. a, b = s.keys[i], s.keys[j]
  182. } else {
  183. a, b = s.values[i], s.values[j]
  184. }
  185. if s.lessThan == nil {
  186. // Use the builtin comparator.
  187. o := cmp(a, b)
  188. if o == uncomparable {
  189. s.err = ErrUncomparable
  190. return true
  191. }
  192. return o == less
  193. }
  194. // Use the &less-than callback.
  195. outputs, err := s.fm.CaptureOutput(func(fm *Frame) error {
  196. return s.lessThan.Call(fm, []any{a, b}, NoOpts)
  197. })
  198. if err != nil {
  199. s.err = err
  200. return true
  201. }
  202. if len(outputs) != 1 {
  203. s.err = errs.ArityMismatch{
  204. What: "number of outputs of the &less-than callback",
  205. ValidLow: 1, ValidHigh: 1, Actual: len(outputs)}
  206. return true
  207. }
  208. if b, ok := outputs[0].(bool); ok {
  209. return b
  210. }
  211. s.err = errs.BadValue{
  212. What: "output of the &less-than callback",
  213. Valid: "boolean", Actual: vals.Kind(outputs[0])}
  214. return true
  215. }
  216. func (s *slice) Swap(i, j int) {
  217. s.values[i], s.values[j] = s.values[j], s.values[i]
  218. if s.keys != nil {
  219. s.keys[i], s.keys[j] = s.keys[j], s.keys[i]
  220. }
  221. }