; .Chapitre n "Vprint: Une Machine de Formattage en CEYX"
; .Auteur "Ge'rard Berry, Jean-Marie Hullot"
(ceyx-load stream)
; .Section "La Machine d'Impression"
(deftclass Vprint
queue-size)
(defvar {Vprint}:printer)
(defvar {Vprint}:level (printlevel))
(defvar {Vprint}:queue)
(defvar {Vprint}:queue-back)
(defvar {Vprint}:stack)
(defvar {Vprint}:stack-back)
(defvar {Vprint}:outbuf)
(defvar {Vprint}:outbuf-back)
(defvar {Vprint}:lmargin-at-cutpoint)
(defvar {Vprint}:something-written)
(defvar {Vprint}:something-written-at-cutpoint)
(de {Vprint}:gen (size)
(let ((queue))
(repeat size (newl queue (VprintCommand () ())))
(nconc queue queue)
(setq {Vprint}:printer (omakeq Vprint queue-size size)
{Vprint}:queue queue)
{Vprint}:printer))
(de {Vprint}:reset ()
(setq {Vprint}:queue-back ()
{Vprint}:stack ()
{Vprint}:stack-back ()
{Vprint}:outbuf-back ()))
(de {Vprint}:connect-outbuf (outbuf)
(setq {Vprint}:outbuf outbuf))
; .Section "Les Blocs d'Impression"
(deftype VprintBlock *)
(dmd VprintBlock (model margin)
`(tcons ,model ,margin))
(dmd {VprintBlock}:margin (block . arg)
(ifn (consp arg) `(tcdr ,block)
`(trplacd ,block ,(car arg))))
(deftype ({VprintBlock}:HorizBlock HorizBlock) VprintBlock)
(deftype ({VprintBlock}:MixedBlock MixedBlock) VprintBlock)
(deftype ({VprintBlock}:VerticBlock VerticBlock) VprintBlock)
(deftype ({VprintBlock}:VerticMixedBlock VerticMixedBlock) VprintBlock)
; .Section "Les Commandes Ele'mentaires de la Machine"
(deftype VprintCommand *)
(de VprintCommand (model arg)
(tcons model arg))
(dmd {VprintCommand}:arg (command . arg)
(ifn (consp arg) `(tcdr ,command)
`(trplacd ,command ,(car arg))))
(deftype ({VprintCommand}:*PushBlock *PushBlock) VprintCommand)
(deftype ({VprintCommand}:*PopBlock *PopBlock) VprintCommand)
(deftype ({VprintCommand}:*Patom *Patom) VprintCommand)
(deftype ({VprintCommand}:*Princn *Princn) VprintCommand)
(deftype ({VprintCommand}:*Princh *Princh) VprintCommand)
(deftype ({VprintCommand}:*Terpri *Terpri) VprintCommand)
(deftype ({VprintCommand}:*Indent *Indent) VprintCommand)
(deftype ({VprintCommand}:*Cutpoint *Cutpoint) VprintCommand)
(de {*PushBlock}:apply (command)
({Vprint}:push-block ({VprintCommand}:arg command)))
(de {*PopBlock}:apply (command)
({Vprint}:pop-block))
(de {*Patom}:apply (command)
(*patom ({VprintCommand}:arg command)))
(de {*Princn}:apply (command)
(*princn ({VprintCommand}:arg command)))
(de {*Princh}:apply (command)
(*princh ({VprintCommand}:arg command)))
(dmd *patom (atom)
`(tag noprin (setq {Vprint}:something-written t) (prin ,atom)))
(dmd *princn (charn)
`(tag noprin (setq {Vprint}:something-written t) (princn ,charn)))
(dmd *princh (char)
`(tag noprin (setq {Vprint}:something-written t) (princh ,char)))
(de {*Terpri}:apply (command)
({Vprint}:terpri))
(de {*Indent}:apply (command)
({VprintBlock}:margin
(car {Vprint}:stack)
(lmargin (+ ({VprintCommand}:arg command) (lmargin)))))
(de {*Cutpoint}:apply (command)
(sendq cutpoint
(car {Vprint}:stack)
({VprintCommand}:arg command)))
(cxcp-inline {*PushBlock}:apply {*PopBlock}:apply
{*Princn}:apply {*Princh}:apply {*Terpri}:apply
{*Indent}:apply {*Cutpoint}:apply)
(de {VerticBlock}:cutpoint (block arg)
({Vprint}:terpri))
(de {MixedBlock}:cutpoint (block arg)
(if ({Vprint}:cutpoint?)
({VprintBlock}:prin-separator arg)
({Vprint}:set-cutpoint)
({VprintBlock}:prin-separator arg))))
(de {VerticMixedBlock}:cutpoint (block arg)
(if ({Vprint}:cutpoint?)
({Vprint}:back-to-cutpoint nil)
(cond
({Vprint}:something-written
(lmargin ({VprintBlock}:margin (car {Vprint}:stack)))
(sendq flush {Vprint}:outbuf)
(sendq newline ({Stream}:destination {Vprint}:outbuf)))
(t
; A FAIRE: CLEAN-BUFFER!!!
(outpos ({VprintBlock}:margin (car {Vprint}:stack)))))
(setq {Vprint}:something-written nil)))))
(de {HorizBlock}:cutpoint (block arg)
(if ({Vprint}:cutpoint?)
(if (neq {Vprint}:stack {Vprint}:stack-back)
({VprintBlock}:prin-separator arg)
({Vprint}:set-cutpoint)
({VprintBlock}:prin-separator arg))
({Vprint}:set-cutpoint)
({VprintBlock}:prin-separator arg)))))
(dmd {VprintBlock}:prin-separator (arg)
`(if ,arg (*patom ,arg) (*princn #\sp)))
; .Section "Se'mantiques de Base"
(dmd {Vprint}:tyo-queue (command)
`(progn
(<- (car {Vprint}:queue) ,command)
(nextl {Vprint}:queue)
(setq {Vprint}:queue-left {Vprint}:queue)))
(dmd {Vprint}:flush-queue ()
`(progn (setq {Vprint}:queue-left {Vprint}:queue-back)
(until (eq {Vprint}:queue-left {Vprint}:queue)
(sendq apply (nextl {Vprint}:queue-left)))))
(dmd {Vprint}:push-block (blockmodel)
`(newl {Vprint}:stack
(VprintBlock ,blockmodel (lmargin))))
(dmd {Vprint}:pop-block ()
`(progn
(when (eq {Vprint}:stack {Vprint}:stack-back)
({Vprint}:reset-cutpoint))
(nextl {Vprint}:stack)
(when {Vprint}:stack
(lmargin ({VprintBlock}:margin (car {Vprint}:stack))))))
(dmd {Vprint}:cutpoint? ()
`(progn {Vprint}:outbuf-back))
(dmd {Vprint}:set-cutpoint ()
`(setq {Vprint}:queue-back {Vprint}:queue-left
{Vprint}:stack-back {Vprint}:stack
{Vprint}:outbuf-back (outpos)
{Vprint}:lmargin-at-cutpoint (lmargin)
{Vprint}:something-written-at-cutpoint {Vprint}:something-written)))
(dmd {Vprint}:reset-cutpoint ()
`(setq {Vprint}:outbuf-back ()
{Vprint}:stack-back ()))
(de {Vprint}:back-to-cutpoint (not-from-VerticMixedBlock)
(setq {Vprint}:stack {Vprint}:stack-back)
; ulte'rieurement deviendra un sendq
(selectq (model (car {Vprint}:stack))
({MixedBlock}
(model (car {Vprint}:stack) '{VerticMixedBlock})
(lmargin {Vprint}:lmargin-at-cutpoint)
({VprintBlock}:margin (car {Vprint}:stack)
{Vprint}:lmargin-at-cutpoint)
(setq {Vprint}:something-written
{Vprint}:something-written-at-cutpoint
not-from-VerticMixedBlock nil))
(t
(lmargin ({VprintBlock}:margin (car {Vprint}:stack)))))
(cond
((or {Vprint}:something-written not-from-VerticMixedBlock)
(outpos {Vprint}:outbuf-back)
(sendq flush {Vprint}:outbuf)
(sendq newline ({Stream}:destination {Vprint}:outbuf)))
(t
; A FAIRE: CLEAN-BUFFER!!!
(outpos (lmargin))))
(setq {Vprint}:something-written nil)
({Vprint}:reset-cutpoint)
({Vprint}:flush-queue))
(dmd {Vprint}:terpri ()
`(if ({Vprint}:cutpoint?)
({Vprint}:back-to-cutpoint t)
(setq {Vprint}:something-written nil)
(sendq flush {Vprint}:outbuf)
(sendq newline ({Stream}:destination {Vprint}:outbuf)))))))
; en attendant mieux
(de {Vprint}:eol (printer) (exit noprin ({Vprint}:terpri)))
;
(defvar {Vprint}:command (omakeq VprintCommand))
(dmd {Vprint}:sendq-command (name arg)
`(progn
(model {Vprint}:command ',name)
({VprintCommand}:arg {Vprint}:command ,arg)
({Vprint}:tyo-queue {Vprint}:command)
(,(symbol name 'apply) {Vprint}:command)))
; Quelques abbreviations
(de begin-hblock () ({Vprint}:sendq-command {*PushBlock} '{HorizBlock}))
(de begin-xblock () ({Vprint}:sendq-command {*PushBlock} '{MixedBlock}))
(de begin-vblock () ({Vprint}:sendq-command {*PushBlock} '{VerticBlock}))
(de end-block () ({Vprint}:sendq-command {*PopBlock} ()))
(de vpatom (atom) ({Vprint}:sendq-command {*Patom} atom))
(de vprincn (charn) ({Vprint}:sendq-command {*Princn} charn))
(de vprinch (charn) ({Vprint}:sendq-command {*Princh} charn))
(de vcutpoint optional-arglist
({Vprint}:sendq-command {*Cutpoint} (car optional-arglist)))
(de vindent (n) ({Vprint}:sendq-command {*Indent} n))
(de vterpri () ({Vprint}:sendq-command {*Terpri} ()))
; .Section "Le Pretty Printer"
(setq p ({Vprint}:gen 250))
({Vprint}:connect-outbuf (OutputBuffer))
(de {OutChannel}:newline (tty)
(when #:system:real-terminal-flag (tyo #\return))
(tyo #\lf)
(tyflush))
(de {Vprint}:open (printer)
({Vprint}:reset))
(de {Vprint}:close (printer) ())
(dmd with-vprint-output body
`(flet ((eol () ({Ceyx}:eol)))
(let (({Vprint}:curlevel 0)
({Vprint}:length (printlength))
({Vprint}:line (printline)))
(with ((outstream {Vprint}:printer))
(hblock 0 ,@body)
(vterpri)))))))
(de vprint args
(let ((x (car args))
({Vprint}:level (if (cadr args) (cadr args) {Vprint}:level)))
(with-vprint-output (vprin x))))
(dmd vpretty l
`(vprint (getdef ',(car l)) ,(cadr l))))
(defvar {Vprint}:indent 3)
(dmd hblock (indent . body)
`(progn
(begin-hblock)
(vindent ,indent)
,@body
(end-block)))
(dmd xblock (indent . body)
`(progn
(begin-xblock)
(vindent ,indent)
,@body
(end-block)))
(dmd vblock (indent . body)
`(progn
(begin-vblock)
(vindent ,indent)
,@body
(end-block)))
(de vplist (l)
(let (({Vprint}:curlength 1))
(vprin (nextl l))
(while (and (consp l) (< {Vprint}:curlength {Vprint}:length))
(vcutpoint) (vprin (nextl l))
(incr {Vprint}:curlength))
(cond
((consp l) (vcutpoint) (vpatom "..."))
(l
(vcutpoint)
(vprincn #/.)
(vcutpoint)
(vprin l))
(t ()))))
(deftype ({Vprint}:Vformat Vformat) *)
(dmd deformat (symbol args . body)
(if (and (symbolp args) (null body))
`(putprop ',args (getprop ',symbol 'vformat) 'vformat)
`(progn
(putprop ',symbol (symbol '{Vformat} ',symbol) 'vformat)
(de ,(symbol '{Vformat} symbol) ,args ,@body))))
(deformat data (l)
(hblock 1 (vprincn #/() (vplist l) (vprincn #/))))
(deformat quote (l)
(vprincn #/')
(vprin (cadr l)))
(deformat progn (l)
(xblock {Vprint}:indent
(vprincn #/()
(vplist l)
(vprincn #/))))
(deformat if (l)
(xblock (+ 2 (plength (car l)))
(vprincn #/()
(vprin (nextl l))
(vprincn #\sp)
(vprin (nextl l))
(vcutpoint)
(xblock 0 (vplist l))
(vprincn #/))))
(deformat defun (l)
(xblock (+ 2 (plength (car l)))
(hblock (+ 3 (plength (car l)))
(vprincn #/()
(vprin (nextl l))
(vprincn #\sp)
(vprin (nextl l))
(vcutpoint)
(vprin (nextl l)))
(vcutpoint)
(xblock 0 (vplist l))
(vprincn #/))))
(deformat cond (l)
(xblock {Vprint}:indent
(vprincn #/()
(vprin (nextl l))
(while l
(vcutpoint)
(xblock 1
(vprincn #/()
(vplist (nextl l))
(vprincn #/))))
(vprincn #/))))
(deformat selectq (l)
(xblock {Vprint}:indent
(vprincn #/()
(vprin (nextl l))
(vprincn #\sp)
(vprin (nextl l))
(while l
(vcutpoint)
(xblock 1
(vprincn #/()
(vplist (nextl l))
(vprincn #/))))
(vprincn #/))))
(deformat setq (l)
(xblock {Vprint}:indent
(vprincn #/()
(vprin (nextl l))
(while l
(vcutpoint)
(xblock 2
(vprin (nextl l))
(vcutpoint)
(vprin (nextl l))))
(vprincn #/))))
(de vprin (x)
(let (({Vprint}:curlevel (1+ {Vprint}:curlevel)))
(if (> {Vprint}:curlevel {Vprint}:level)
(vprincn #/#)
(cond
((tconsp x) (sendq vprin x))
((null x) (vpatom "()"))
((stringp x) (vprincn #/") (vpatom x) (vprincn #/"))
((atom x) (vpatom x))
((consp x)
(if (symbolp (car x))
(selectq (ptype (car x))
(1 ({Vformat}:progn x))
(2 ({Vformat}:if x))
(3 ({Vformat}:defun x))
(4 ({Vformat}:cond x))
(5 ({Vformat}:selectq x))
(6 ({Vformat}:setq x))
(t (let ((vformat (getprop (car x) 'vformat)))
(ifn vformat
({Vformat}:data x)
(funcall vformat x)))))
({Vformat}:data x)))
(t (syserror 'vprin "Type Lisp Inconnu"))))))
(de {*}:vprin (obj) (prin obj))