;;; ----------------------------------------------------------------
;;; Text
;;; ----------------------------------------------------------------
(define (text-fns algdata suppress-reader?)
(let ((print+read
(cond ((algdata-enum? algdata)
(text-enum-fns algdata))
(else
(text-general-fns algdata)))))
(when suppress-reader?
(setf print+read (list (car print+read))))
print+read))
(define (text-enum-fns algdata)
(list
(**define '|showsPrec| '(|d| |x|)
(**case/con algdata (**var '|x|)
(lambda (con vars)
(declare (ignore vars))
(**showString (**string (con-string con))))))
(**define '|readsPrec| '(|d| |str|)
(**listcomp
(**var '|s|)
(list
(**gen '(tuple |tok| |rest|) (**lex (**var '|str|)))
(**gen '|s|
(**case (**var '|tok|)
`(,@(map (lambda (con)
(**alt/simple
(**pat (con-string con))
(**list (**tuple2 (**con/def con)
(**var '|rest|)))))
(algdata-constrs algdata))
,(**alt/simple (**pat '_) (**null))))))))))
;;; This has been hacked to split up the read function for large
;;; data types to avoid choking the lisp compiler.
(define (text-general-fns algdata)
(let ((split-fn-def? (> (algdata-n-constr algdata) 6))) ;; pretty arbitrary!
(list
(**define '|showsPrec| '(|d| |x|)
(**case/con algdata (**var '|x|)
(lambda (con vars)
(if (con-infix? con)
(show-infix con vars)
(show-prefix con vars)))))
(**define '|readsPrec| '(|d| |str|)
(**append/l
(map (lambda (con)
(cond ((con-infix? con)
(read-infix con))
(else
(read-prefix con split-fn-def?))))
(algdata-constrs algdata)))))))
(define (show-infix con vars)
(multiple-value-bind (p lp rp) (get-con-fixity con)
(**showParen
(**< (**Int p) (**var '|d|))
(**dot (**showsPrec (**int lp) (**var (car vars)))
(**showString
(**string (string-append " " (con-string con) " ")))
(**showsPrec (**int rp) (**var (cadr vars)))))))
(define (show-prefix con vars)
(**showParen
(**<= (**int 10) (**var '|d|))
(**dot/l (**showString (**string (con-string con)))
(show-fields vars))))
(define (show-fields vars)
(if (null? vars)
'()
`(,(**space) ,(**showsPrec (**int 10) (**var (car vars)))
,@(show-fields (cdr vars)))))
(define (read-infix con)
(multiple-value-bind (p lp rp) (get-con-fixity con)
(**let
(list
(**define '|readVal| '(|r|)
(**listcomp
(**tuple2 (**app (**con/def con) (**var '|u|) (**var '|v|))
(**var '|s2|))
(list
(**gen '(tuple |u| |s0|)
(**readsPrec (**int lp) (**var '|r|)))
(**gen `(tuple ,(con-string con) |s1|)
(**lex (**var '|s0|)))
(**gen '(tuple |v| |s2|)
(**readsprec (**int rp) (**var '|s1|)))))))
(**readParen (**< (**int p) (**var '|d|))
(**var '|readVal|) (**var '|str|)))))
(define (read-prefix con split?)
(let ((res (read-prefix-1 con)))
(if (not split?)
res
(dynamic-let ((*module-name* (def-module con)))
(dynamic-let ((*module* (table-entry *modules* *module-name*)))
(let* ((alg (con-alg con))
(fn (make-new-var
(string-append (symbol->string (def-name alg))
"/read-"
(remove-con-prefix
(symbol->string (def-name con))))))
(new-code (**app (**var/def fn) (**var '|str|) (**var '|d|)))
(def (**define fn '(|str| |d|) res)))
(setf (module-decls *module*) (cons def (module-decls *module*)))
new-code))))))
(define (read-prefix-1 con)
(let* ((arity (con-arity con))
(vars (temp-vars "x" arity))
(svars (cons '|rest| (temp-vars "s" arity))))
(**let
(list
(**define '|readVal| '(|r|)
(**listcomp
(**tuple2 (**app/l (**con/def con) (map (function **var) vars))
(**var (car (reverse svars))))
(cons
(**gen `(tuple ,(con-string con) |rest|)
(**lex (**var '|r|)))
(read-fields vars svars (cdr svars))))))
(**readParen (**< (**int 9) (**var '|d|))
(**var '|readVal|) (**var '|str|)))))
(define (read-fields vars s0 s1)
(if (null? vars)
'()
(cons
(**gen `(tuple ,(car vars) ,(car s1))
(**readsprec (**int 10) (**var (car s0))))
(read-fields (cdr vars) (cdr s0) (cdr s1)))))
;;; ----------------------------------------------------------------
;;; Binary
;;; ----------------------------------------------------------------
(define (binary-fns algdata)
(let ((res
(cond ((algdata-enum? algdata)
(binary-enum-fns algdata))
((algdata-tuple? algdata)
(binary-tuple-fns algdata))
(else
(binary-general-fns algdata)))))
; (dolist (x res)
; (fresh-line)
; (pprint x))
res))
(define (binary-enum-fns algdata)
(list
(**define '|showBin| '(|x| |b|)
(**showBinInt (**con-number (**var '|x|) algdata) (**var '|b|)))
(**define '|readBin| '(|b|)
(**let
(list
(**define '(tuple |n| |b1|) '()
(**readBinSmallInt
(**var '|b|)
(**int (1- (algdata-n-constr algdata))))))
(**tuple2
(**case/int algdata (**var '|n|)
(lambda (con)
(**con/def con)))
(**var '|b1|))))))
(define (binary-tuple-fns algdata)
(let* ((con (tuple-con algdata))
(arity (con-arity con))
(vars (temp-vars "v" arity)))
(list
(**define '|showBin| `((,con ,@vars) |b|)
(show-binary-body vars '|b|))
(**define '|readBin| '(|b|)
(read-binary-body con)))))
(define (show-binary-body vars b)
(**foldr (lambda (new-term prev-terms)
(**showBin new-term prev-terms))
(map (function **var) vars)
(**var b)))
(define (read-binary-body con)
(let* ((arity (con-arity con))
(vars (temp-vars "v" arity))
(bvars (cons '|b| (temp-vars "b" arity))))
(**let
(map (lambda (v b nb)
(**define `(tuple ,v ,nb) '()
(**readBin (**var b))))
vars bvars (cdr bvars))
(**tuple2
(**app/l (**con/def con)
(map (function **var) vars))
(**var (car (reverse bvars)))))))
(define (binary-general-fns algdata)
(list
(**define '|showBin| '(|x| |b|)
(**showBinInt
(**con-number (**var '|x|) algdata)
(**case/con algdata (**var '|x|)
(lambda (con vars)
(declare (ignore con))
(show-binary-body vars '|b|)))))
(**define '|readBin| '(|bin|)
(**let
(list
(**define '(tuple |i| |b|) '()
(**readBinSmallInt (**var '|bin|)
(**int (1- (algdata-n-constr algdata))))))
(**case/int algdata (**var '|i|) (function read-binary-body))))))
(define (get-con-fixity con)
(let ((fixity (con-fixity con)))
(if (not (eq? fixity '#f))
(let ((p (fixity-precedence fixity))
(a (fixity-associativity fixity)))
(values p (if (eq? a 'L) p (1+ p)) (if (eq? a 'R) p (1+ p))))
(values 9 10 9))))