(module core-layout mzscheme
(require "loc-wrapper.ss"
"arrow.ss"
(lib "utils.ss" "texpict")
(lib "mrpict.ss" "texpict")
(lib "etc.ss")
(lib "class.ss")
(lib "mred.ss" "mred")
(lib "struct.ss"))
(provide lw->pict
basic-text
default-style
label-style
label-font-size
default-font-size
non-terminal
set-literal-style!
set-metafunction-style!)
(define STIX? #f)
(define atomic-rewrite-table
(make-parameter
`((... ,(if STIX?
(basic-text "\u22ef" default-style)
"..."))
(hole "[]"))))
(define compound-rewrite-table
(make-parameter
`((in-hole ,(λ (args)
(let ([context (list-ref args 2)]
[thing-in-hole (list-ref args 3)])
(list context
(if (= (loc-wrapper-line thing-in-hole)
(loc-wrapper-line context))
(make-loc-wrapper "["
(loc-wrapper-line thing-in-hole)
0
(+ (loc-wrapper-column context)
(loc-wrapper-column-span context))
(- (loc-wrapper-column thing-in-hole)
(+ (loc-wrapper-column context)
(loc-wrapper-column-span context))))
(make-loc-wrapper "["
(loc-wrapper-line thing-in-hole)
0
(loc-wrapper-column thing-in-hole)
0))
thing-in-hole
(make-loc-wrapper "]"
(+ (loc-wrapper-line thing-in-hole)
(loc-wrapper-line-span thing-in-hole))
0
(+ (loc-wrapper-column thing-in-hole)
(loc-wrapper-column-span thing-in-hole))
0))))))))
(define-struct token (column span) (make-inspector))
(define-struct (string-token token) (string style) (make-inspector))
(define-struct (pict-token token) (pict) (make-inspector))
(define-struct (spacer-token token) () (make-inspector))
(define-struct align-token (pict) (make-inspector))
(define (lw->pict nts lw)
(lines->pict
(setup-lines
(build-lines
nts
(push-down-quo
(apply-rewrites lw))))))
(define (push-down-quo lw)
(define (pd/lw lw depth)
(cond
[(quo? lw) (pd/lw (quo-e lw) (+ depth 1))]
[(unq? lw) (pd/lw (unq-e lw) (- depth 1))]
[else
(copy-struct loc-wrapper
lw
[loc-wrapper-e (pd/e (loc-wrapper-e lw) depth)])]))
(define (pd/e e depth)
(cond
[(symbol? e)
(if (depth . <= . 0)
(pinkize (symbol->string e))
e)]
[(string? e)
(if (depth . <= . 0)
(pinkize e)
e)]
[(pict? e) e]
[else (map (λ (x) (pd/lw x depth)) e)]))
(define (pinkize str)
(pink-background
(text str 'modern (default-font-size))))
(pd/lw lw 1))
(define (apply-rewrites orig-lw)
(define (ar/lw lw)
(cond
[(unq? lw) (make-unq (ar/lw (unq-e lw)))]
[(quo? lw) (make-quo (ar/lw (quo-e lw)))]
[else
(copy-struct loc-wrapper
lw
[loc-wrapper-e (ar/e (loc-wrapper-e lw)
(loc-wrapper-line lw)
(loc-wrapper-column lw))])]))
(define (ar/e e line col)
(cond
[(and (symbol? e) (assoc e (atomic-rewrite-table)))
=>
(λ (m)
(when (eq? (cadr m) e)
(error 'apply-rewrites "rewritten version of ~s is still ~s" e e))
(cadr m))]
[(symbol? e) e]
[(string? e) e]
[(pict? e) e]
[(and (loc-wrapper? (cadr e))
(assoc (loc-wrapper-e (cadr e)) (compound-rewrite-table)))
=>
(λ (m)
(let ([rewritten ((cadr m) e)])
(when (and (pair? rewritten)
(pair? (cdr rewritten))
(eq? (cadr rewritten)
(cadr e)))
(error 'apply-rewrites "rewritten version still has symbol of the same name as original: ~s"
(cadr rewritten)))
(adjust-spacing rewritten e line col)))]
[else
(map ar/lw e)]))
(ar/lw orig-lw))
(define (adjust-spacing in-rewrittens in-originals init-line init-column)
(let loop ([rewrittens in-rewrittens]
[originals in-originals]
[line init-line]
[column init-column])
(cond
[(null? rewrittens)
null]
[(null? originals)
(map (λ (rw) (if (loc-wrapper? rw)
rw
(make-loc-wrapper rw line 0 column 0)))
rewrittens)]
[else
(let ([orig (car originals)]
[rewritten (car rewrittens)])
(cond
[(loc-wrapper? rewritten)
(let ([new-line (+ (loc-wrapper-line rewritten)
(loc-wrapper-line-span rewritten))]
[new-col (+ (loc-wrapper-column orig)
(loc-wrapper-column-span rewritten))])
(cond
[(memq rewritten originals)
(let ([rw-line (loc-wrapper-line rewritten)])
(let d-loop ([originals originals]
[first-column #f])
(cond
[(eq? (car originals) rewritten)
(if first-column
(list* (make-loc-wrapper (blank)
rw-line
0
first-column
(- (loc-wrapper-column rewritten)
first-column))
rewritten
(loop (cdr rewrittens) (cdr originals) new-line new-col))
(cons rewritten
(loop (cdr rewrittens) (cdr originals) new-line new-col)))]
[(and (not first-column) (= rw-line (loc-wrapper-line (car originals))))
(d-loop (cdr originals)
(loc-wrapper-column (car originals)))]
[else
(d-loop (cdr originals)
first-column)])))]
[(memq rewritten in-originals)
(error 'adjust-spacing "found an out of order loc-wrapper ~s" rewritten)]
[else
(unless (<= line (loc-wrapper-line orig))
(error 'adjust-spacing
"new loc-wrapper's line is earlier than a loc-wrapper's line that appears earlier in the list: ~s"
rewritten))
(unless (<= column (loc-wrapper-column orig))
(error 'adjust-spacing
"new loc-wrapper's column is earlier than a loc-wrapper's column that appears earlier in the list: ~s"
rewritten))
(cons rewritten (loop (cdr rewrittens) originals new-line new-col))]))]
[else
(cons (make-loc-wrapper rewritten line 0 column 0)
(loop (cdr rewrittens) originals line column))]))])))
(define (build-lines all-nts lw)
(define initial-column (loc-wrapper-column lw))
(define initial-line (loc-wrapper-line lw))
(define current-line (loc-wrapper-line lw))
(define current-column (loc-wrapper-column lw))
(define tokens '())
(define lines '())
(define (eject line col span atom)
(unless (= current-line line)
(for-each
(λ (x)
(set! lines (cons (reverse! tokens) lines))
(set! tokens '()))
(build-list (max 0 (- line current-line)) (λ (x) 'whatever)))
(set! tokens (cons (make-spacer-token 0 (- col initial-column))
tokens))
(set! current-line line)
(set! current-column col))
(when (< current-column col)
(let ([space-span (- col current-column)])
(set! tokens (cons (make-string-token (- current-column initial-column)
space-span
(apply string (build-list space-span (λ (x) #\space)))
default-style)
tokens))))
(set! tokens (append
(reverse
(atom->tokens (- col initial-column) span atom all-nts))
tokens))
(set! current-column (+ col span)))
(define (handle-loc-wrapped lw last-line last-column last-span)
(handle-object (loc-wrapper-e lw)
(loc-wrapper-line lw)
(loc-wrapper-column lw)
(loc-wrapper-column-span lw)))
(define (handle-object obj line col span)
(cond
[(symbol? obj) (eject line col span obj)]
[(string? obj) (eject line col span obj)]
[(pict? obj) (eject line col span obj)]
[(unq? obj) (handle-object (unq-e obj) line col span)]
[else
(for-each (λ (x) (handle-loc-wrapped x line col span))
obj)]))
(handle-loc-wrapped lw 0 0 0)
(set! lines (cons (reverse! tokens) lines)) lines)
(define (setup-lines lines)
(let loop ([lines lines])
(cond
[(null? lines) null]
[else
(let ([line (car lines)]
[rst (cdr lines)])
(if (null? line)
(cons line (loop (cdr lines)))
(if (spacer-token? (car line))
(let ([pict (blank)])
(if (andmap null? rst)
(cons (cdr line) (loop rst))
(let ([rst (split-out (token-span (car line))
pict
rst)])
(cons (cons (make-align-token pict) (cdr line))
(loop rst)))))
(cons line (loop (cdr lines))))))])))
(define (split-out col pict lines)
(let ([new-token (make-pict-token col 0 pict)])
(let loop ([lines lines])
(cond
[(null? lines)
(error 'exchange-spacer "could not find matching line")]
[else (let ([line (car lines)])
(if (null? line)
(cons line (loop (cdr lines)))
(let ([spacer (car line)])
(cond
[(not (spacer-token? spacer))
(cons (insert-new-token col new-token (token-column spacer) (car lines))
(cdr lines))]
[(= (token-span spacer)
col)
(cons (list* spacer new-token (cdr line))
(cdr lines))]
[(> (token-span spacer)
col)
(cons line (loop (cdr lines)))]
[(< (token-span spacer)
col)
(cons (insert-new-token col new-token (token-column spacer) (car lines))
(cdr lines))]))))]))))
(define (insert-new-token column-to-insert new-token init-width line)
(let loop ([line line])
(cond
[(null? line)
(error 'insert-new-token "not yet finished (need to go to a previous line)")]
[else
(let ([tok (car line)])
(unless (token? tok)
(error 'insert-new-token "ack ~s" tok))
(cond
[(<= column-to-insert (token-column tok))
(cons new-token line)]
[(< (token-column tok)
column-to-insert
(+ (token-column tok) (token-span tok)))
(append (split-token (- column-to-insert (token-column tok)) tok new-token)
(cdr line))]
[(= column-to-insert (+ (token-column tok) (token-span tok)))
(list* (car line) new-token (cdr line))]
[else
(cons (car line)
(loop (cdr line)))]))])))
(define (split-token offset tok new-token)
(cond
[(string-token? tok)
(list (make-string-token (token-column tok)
offset
(substring (string-token-string tok)
0 offset)
(string-token-style tok))
new-token
(make-string-token (+ (token-column tok) offset)
(- (token-span tok) offset)
(substring (string-token-string tok)
offset
(string-length (string-token-string tok)))
(string-token-style tok)))]
[(pict-token? tok)
(list new-token)]))
(define (lines->pict lines)
(let loop ([lines lines])
(cond
[(null? lines) (blank)]
[(null? (cdr lines))
(handle-single-line (car lines) (blank))]
[else
(let ([rst (loop (cdr lines))])
(vl-append rst (handle-single-line (car lines) rst)))])))
(define (handle-single-line line rst)
(cond
[(null? line)
(let ([h (pict-height (token->pict (make-string-token 0 0 "x" default-style)))])
(blank 0 h))]
[else
(if (align-token? (car line))
(let-values ([(x y) (lt-find rst (align-token-pict (car line)))])
(apply hbl-append
(blank x 0)
(map token->pict (cdr line))))
(apply hbl-append (map token->pict line)))]))
(define (token->pict tok)
(cond
[(string-token? tok)
(basic-text (string-token-string tok) (string-token-style tok))]
[(pict-token? tok) (pict-token-pict tok)]
[else (error 'token->pict "~s" tok)]))
(define (atom->tokens col span atom all-nts)
(cond
[(pict? atom)
(list (make-pict-token col span atom))]
[(and (symbol? atom)
(regexp-match #rx"^([^_]*)_(.*)$" (symbol->string atom)))
=>
(λ (m)
(let* ([first-part (cadr m)]
[second-part (caddr m)]
[first-span (- span (string-length first-part))])
(list
(make-string-token col
first-span
first-part
non-terminal-style)
(make-string-token (+ col first-span)
(- span first-span)
second-part
non-terminal-subscript-style))))]
[(memq atom all-nts)
(list (make-string-token col span (format "~s" atom) non-terminal-style))]
[(symbol? atom)
(list (make-string-token col span (symbol->string atom) literal-style))]
[(string? atom)
(list (make-string-token col span atom literal-style))]
[else (error 'atom->tokens "unk ~s" atom)]))
(define (il-memq sym s)
(and (pair? s)
(or (eq? sym (car s))
(il-memq sym (cdr s)))))
(define (il-remq sym s)
(if (pair? s)
(if (eq? sym (car s))
(cdr s)
(cons (car s) (il-remq sym (cdr s))))
s))
(define (basic-text str style)
(if (il-memq 'caps style)
(caps-text str (il-remq 'caps style) (default-font-size))
(text str style (default-font-size))))
(define (non-terminal str) (text str non-terminal-style (default-font-size)))
(define (unksc str) (pink-background (text str 'modern (default-font-size))))
(define non-terminal-style '(italic . roman))
(define non-terminal-subscript-style `(subscript . ,non-terminal-style))
(define default-style 'roman)
(define metafunction-style 'swiss)
(define literal-style 'swiss)
(define label-style 'swiss)
(define default-font-size (make-parameter 14))
(define label-font-size (make-parameter 14))
(define (set-literal-style! s) (set! literal-style s))
(define (set-metafunction-style! s) (set! metafunction-style s))
(require (lib "match.ss"))
(define (side-condition->pict sc)
(let loop ([sc sc])
(match sc
[(? pict? sc) sc]
[`(or ,s1 ,s2)
(hbl-append
(loop s1)
(basic-text " or " 'roman)
(loop s2))]
[`(or ,s1 ,s2 ...)
(apply hbl-append
(add-between (basic-text ", or " 'roman)
(map loop (cons s1 s2))))]
[else
(fprintf (current-error-port) "unknown Scheme code: ~s\n" sc)
(render-side-condition sc)])))
(define (render-side-condition sc)
(cond
[(pict? sc) sc]
[(null? sc) (unksc "()")]
[(pair? sc)
(hbl-append
(unksc "(")
(render-side-condition (car sc))
(if (null? (cdr sc))
(blank)
(render-side-condition/list (cdr sc)))
(unksc ")"))]
[else
(unksc (format "~s" sc))]))
(define (render-side-condition/list sc)
(cond
[(null? (cdr sc))
(hbl-append
(unksc " ")
(render-side-condition (car sc)))]
[(pair? (cdr sc))
(hbl-append
(unksc " ")
(render-side-condition (car sc))
(render-side-condition/list (cdr sc)))]
[else
(hbl-append
(unksc " ")
(render-side-condition (car sc))
(unksc " . ")
(render-side-condition (cdr sc)))]))
(define (pink-background p)
(refocus
(cc-superimpose
(colorize (filled-rectangle (pict-width p)
(pict-height p))
"pink")
p)
p))
(define (add-between i l)
(cond
[(null? l) l]
[else
(cons (car l)
(apply append
(map (λ (x) (list i x)) (cdr l))))]))
)