read.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. ; -*- mode: scheme; coding: utf-8 -*-
  2. ; (c) Daniel Llorens - 2017-2019
  3. ; This library is free software; you can redistribute it and/or modify it under
  4. ; the terms of the GNU General Public License as published by the Free
  5. ; Software Foundation; either version 3 of the License, or (at your option) any
  6. ; later version.
  7. ;;; Commentary:
  8. ;; Reader for ra objects. They start with #% instead of #, otherwise the syntax
  9. ;; is the same as for regular Guile arrays.
  10. ;;; Code:
  11. (define-module (newra read)
  12. #:export (list->ra list->typed-ra))
  13. (import (newra base) (newra map) (newra tools)
  14. (only (newra print) *ra-parenthesized-rank-zero*)
  15. (ice-9 match) (ice-9 rdelim)
  16. (rnrs io ports) (only (rnrs base) vector-map)
  17. (srfi srfi-71) (srfi srfi-26) (only (srfi srfi-1) fold unzip2 car+cdr))
  18. (re-export *ra-parenthesized-rank-zero*)
  19. (define vector-fold (@ (newra vector) vector-fold))
  20. ; take a looked ahead 'c'. FIXME shouldn't look ahead the last one and then again in the caller.
  21. (define (read-number port)
  22. (let* ((c (lookahead-char port))
  23. (m c (if (eqv? c #\-)
  24. (begin (get-char port) (values -1 (lookahead-char port)))
  25. (values 1 c))))
  26. (unless (char-numeric? c)
  27. (throw 'failed-to-read-number))
  28. (* m (let loop ((n 0) (c c))
  29. (if (char-numeric? c)
  30. (loop (+ (* 10 n) (string->number (string (get-char port)))) (lookahead-char port))
  31. n)))))
  32. (define (skip-whitespace port)
  33. (let loop ((c (lookahead-char port)))
  34. (cond ((char-whitespace? c) (get-char port) (loop (lookahead-char port)))
  35. (else c))))
  36. (define pick-functions (@ (newra base) pick-functions))
  37. (define pick-make (@ (newra base) pick-make))
  38. (define (make-root type size)
  39. ((pick-make type) size))
  40. (define (root-type root)
  41. (let ((type vlen vref vset! (pick-functions root))) type))
  42. (define (root-length root)
  43. (let ((type vlen vref vset! (pick-functions root))) (vlen root)))
  44. (define (root-ref root i)
  45. (let ((type vlen vref vset! (pick-functions root))) (vref root i)))
  46. (define (root-set! root o i)
  47. (let ((type vlen vref vset! (pick-functions root))) (vset! root i o)))
  48. ; Don't resize but make a list of vectors and cat once at the end.
  49. (define (root-resize old newsize)
  50. (let ((oldsize (root-length old)))
  51. (if (= newsize oldsize)
  52. old
  53. (let ((new (make-root (root-type old) newsize))
  54. (size (min oldsize newsize)))
  55. (let loop ((j 0))
  56. (cond ((= j size) new)
  57. (else (root-set! new (root-ref old j) j)
  58. (loop (+ j 1)))))))))
  59. (define (make-temp-root len type)
  60. (let* ((rank (vector-length len))
  61. (temp final-size?
  62. (let loop ((size 1) (k 0))
  63. (if (= k rank)
  64. (values (make-root type size) #t)
  65. (let ((l (vector-ref len k)))
  66. (if l (loop (* size l) (+ 1 k))
  67. (values (make-root type 8) #f)))))))
  68. (values temp
  69. (if final-size?
  70. (lambda (temp j) temp)
  71. (lambda (temp j)
  72. (let ((n (root-length temp)))
  73. (if (> j n)
  74. (root-resize temp (ceiling (* (+ n j) 3/2)))
  75. temp)))))))
  76. (define (delim-pair c)
  77. (match c
  78. (#\[ #\])
  79. (#\( #\))
  80. (#\] #\[)
  81. (#\) #\()))
  82. (define (delim-open? c)
  83. (match c
  84. ((or #\[ #\() #t)
  85. (else #f)))
  86. (define (delim-close? c)
  87. (match c
  88. ((or #\] #\)) #t)
  89. (else #f)))
  90. (read-hash-extend
  91. #\%
  92. (lambda (chr port)
  93. (let* ((c (lookahead-char port))
  94. (rank (if (char-numeric? c)
  95. (let ((rank (read-number port)))
  96. (if (negative? rank)
  97. (throw 'bad-rank rank)
  98. rank))
  99. 1))
  100. (type (read-delimited ":@([ " port 'peek))
  101. (type (if (zero? (string-length type)) #t (string->symbol type)))
  102. (lo (make-vector rank 0))
  103. (len (make-vector rank #f)))
  104. (let loop ((k 0))
  105. (let ((c (lookahead-char port)))
  106. (cond
  107. ((eqv? c #\@)
  108. (unless (< k rank) (throw 'too-many-dimensions-for-rank k rank))
  109. (get-char port)
  110. (vector-set! lo k (read-number port))
  111. (let ((c (lookahead-char port)))
  112. (cond ((eqv? c #\:)
  113. (unless (< k rank) (throw 'too-many-dimensions-for-rank k rank))
  114. (get-char port)
  115. (vector-set! len k (read-number port)))
  116. (else
  117. (vector-set! len k #f)))
  118. (loop (+ k 1))))
  119. ((eqv? c #\:)
  120. (unless (< k rank) (throw 'too-many-dimensions-for-rank k rank))
  121. (get-char port)
  122. (vector-set! len k (read-number port))
  123. (vector-set! lo k 0)
  124. (loop (+ k 1)))
  125. (else
  126. (unless (or (zero? k) (= k rank)) (throw 'too-few-dimensions-for-rank k rank))
  127. (let ((delim-stack (list c)))
  128. ; read content here
  129. (cond
  130. ((zero? rank)
  131. (if (*ra-parenthesized-rank-zero*)
  132. (let ((c (get-char port)))
  133. (unless (delim-open? c) (throw 'expected-open-paren c))
  134. (let* ((item (read port))
  135. (cc (get-char port)))
  136. (unless (eqv? (delim-pair c) cc)
  137. (throw 'mismatched-delimiters-in-zero-rank-array c cc))
  138. (make-ra-new type item #())))
  139. (make-ra-new type (read port) #())))
  140. (else
  141. (unless (delim-open? c) (throw 'expected-open-paren c))
  142. (let ((temp resize-temp (make-temp-root len type))
  143. (j 0))
  144. (let loop-rank ((k rank))
  145. (cond
  146. ; read element
  147. ((zero? k)
  148. (set! temp (resize-temp temp (+ j 1)))
  149. (root-set! temp (read port) j)
  150. (set! j (+ j 1)))
  151. ; read slice
  152. (else
  153. (let ((c (skip-whitespace port)))
  154. (unless (delim-open? c) (throw 'expected-open-paren-at-dim (- rank k) c))
  155. (set! delim-stack (cons c delim-stack))
  156. (get-char port))
  157. (let ((lenk (vector-ref len (- rank k))))
  158. (cond
  159. ; read a whole slice when the dimension is known
  160. ((and (= k 1) lenk)
  161. (set! temp (resize-temp temp (+ j lenk)))
  162. (do ((i 0 (+ i 1))) ((= i lenk))
  163. (root-set! temp (read port) (+ j i)))
  164. (set! j (+ j lenk))
  165. (let ((c (skip-whitespace port)))
  166. (unless (delim-close? c)
  167. (throw 'too-many-elements-in-dim (- rank k) c lenk))
  168. (unless (eqv? (delim-pair c) (car delim-stack))
  169. (throw 'mismatched-delimiters-in-dim (- rank k) c lenk))
  170. (set! delim-stack (cdr delim-stack))
  171. (get-char port)))
  172. ; general case, feeling for the end
  173. (else
  174. (let loop-dim ((i 0))
  175. (let ((c (skip-whitespace port)))
  176. (cond
  177. ((delim-close? c)
  178. (unless (eqv? (delim-pair c) (car delim-stack))
  179. (throw 'mismatched-delimiters-in-dim (- rank k) c lenk))
  180. (set! delim-stack (cdr delim-stack))
  181. (get-char port)
  182. (cond
  183. ((not lenk)
  184. (vector-set! len (- rank k) i))
  185. ((< i lenk)
  186. (throw 'too-few-elements-in-dim (- rank k) i lenk))))
  187. ((or (not lenk) (< i lenk))
  188. (loop-rank (- k 1))
  189. (loop-dim (+ i 1)))
  190. (else
  191. (throw 'too-many-elements-on-dim (- rank k))))))))))))
  192. (make-ra-root
  193. (root-resize temp (vector-fold (lambda (a b) (* (if a a 0) b)) 1 len))
  194. (apply c-dims
  195. (vector->list (vector-map (lambda (lo len) (if len (list lo (+ lo len -1)) (list 0 -1)))
  196. lo len)))))))))))))))
  197. ; The docstring is from Guile's list->typed-array.
  198. (define list->ra
  199. (case-lambda
  200. "
  201. list->ra [type] shape l -> ra
  202. Convert the nested list @var{l} to array of @var{type}. @var{type} defaults to
  203. @code{#t}.
  204. @var{SHAPE} determines the number of dimensions of the array and their
  205. shape. It is either an exact integer, giving the number of dimensions directly,
  206. or a list whose length specifies the number of dimensions and each element
  207. specified the lower and optionally the upper bound of the corresponding
  208. dimension. When the element is list of two elements, these elements give the
  209. lower and upper bounds. When it is an exact integer, it gives only the lower
  210. bound.
  211. See also: list->typed-ra ra->list ra-copy ra-copy! as-ra
  212. "
  213. ((shape l) (list->typed-ra #t shape l))
  214. ((type shape l) (list->typed-ra type shape l))))
  215. ; FIXME looks up all lengths first. Is that necessary?
  216. (define (list->typed-ra type shape l)
  217. "Equivalent to (list->ra TYPE SHAPE L).
  218. See also: list->ra ra->list ra-copy ra-copy! as-ra
  219. "
  220. (define (list-len l rank)
  221. (let loop ((k rank) (l l))
  222. (if (zero? k) '() (cons (length l) (loop (- k 1) (car l))))))
  223. (let* ((rank lo len
  224. (cond
  225. ((number? shape)
  226. (values shape (make-list shape 0) (list-len l shape)))
  227. ((list shape)
  228. (let* ((rank (length shape))
  229. (len (list-len l rank))
  230. (lo (map (lambda (x) (if (number? x) x (car x))) shape)))
  231. (for-each
  232. (lambda (s lo len)
  233. (unless (number? s)
  234. (unless (= len (- (cadr s) lo -1)) (throw 'mismatched-shape shape))))
  235. shape lo len)
  236. (values rank lo len)))
  237. (else (throw 'bad-shape-spec shape))))
  238. (temp (make-root type (fold * 1 len)))
  239. (j 0))
  240. (let loop-rank ((len len) (l l))
  241. (cond
  242. ; read element
  243. ((null? len)
  244. (root-set! temp l j)
  245. (set! j (+ j 1)))
  246. (else
  247. (let ((lenk len (car+cdr len)))
  248. (cond
  249. ; read 1-slice
  250. ((null? len)
  251. (do ((i 0 (+ i 1)) (l l (cdr l)))
  252. ((= i lenk)
  253. (unless (null? l) (throw 'mismatched-list-length-dim l lenk (- rank 1))))
  254. (root-set! temp (car l) (+ j i)))
  255. (set! j (+ j lenk)))
  256. ; general case
  257. (else
  258. (do ((i 0 (+ i 1)) (l l (cdr l)))
  259. ((= i lenk)
  260. (unless (null? l) (throw 'mismatched-list-length-dim (- rank 1 (length len)))))
  261. (loop-rank len (car l)))))))))
  262. ; FIXME c-dims takes len | (lo hi) as in Guile, but I'd prefer len | (len lo) as in ra-iota
  263. (make-ra-root
  264. temp (apply c-dims (map (lambda (lo len) (list lo (+ lo len -1))) lo len))))) ; FIXME