Compare commits

..

No commits in common. "main" and "before-6.7.0.4" have entirely different histories.

28 changed files with 142 additions and 2011 deletions

View File

@ -24,20 +24,10 @@ env:
#- RACKET_VERSION=6.1 #- RACKET_VERSION=6.1
#- RACKET_VERSION=6.1.1 #- RACKET_VERSION=6.1.1
#- RACKET_VERSION=6.2 #- RACKET_VERSION=6.2
#- RACKET_VERSION=6.3 - RACKET_VERSION=6.3
#- RACKET_VERSION=6.4 - RACKET_VERSION=6.4
#- RACKET_VERSION=6.5 - RACKET_VERSION=6.5
#- RACKET_VERSION=6.6 - RACKET_VERSION=6.6
#- RACKET_VERSION=6.7
- RACKET_VERSION=6.8
- RACKET_VERSION=6.9
- RACKET_VERSION=6.10
- RACKET_VERSION=6.10.1
- RACKET_VERSION=6.11
- RACKET_VERSION=6.12
- RACKET_VERSION=7.0
- RACKET_VERSION=7.1
- RACKET_VERSION=7.2
- RACKET_VERSION=HEAD - RACKET_VERSION=HEAD
matrix: matrix:
@ -51,7 +41,7 @@ before_install:
- export PATH="${RACKET_DIR}/bin:${PATH}" #install-racket.sh can't set for us - export PATH="${RACKET_DIR}/bin:${PATH}" #install-racket.sh can't set for us
install: install:
- raco pkg install -j 2 --deps search-auto - raco pkg install --deps search-auto
before_script: before_script:

View File

@ -1,5 +1,5 @@
hyper-literate hyper-literate
Copyright (c) 2016 Suzanne Soy Copyright (c) 2016 Georges Dupéron
This package is distributed under the GNU Lesser General Public This package is distributed under the GNU Lesser General Public
License (LGPL). This means that you can link hyper-literate into proprietary License (LGPL). This means that you can link hyper-literate into proprietary

View File

@ -1,5 +1,5 @@
[![Build Status,](https://img.shields.io/travis/jsmaniac/hyper-literate/main.svg)](https://travis-ci.org/jsmaniac/hyper-literate) [![Build Status,](https://img.shields.io/travis/jsmaniac/hyper-literate/master.svg)](https://travis-ci.org/jsmaniac/hyper-literate)
[![Coverage Status,](https://img.shields.io/coveralls/jsmaniac/hyper-literate/main.svg)](https://coveralls.io/github/jsmaniac/hyper-literate) [![Coverage Status,](https://img.shields.io/coveralls/jsmaniac/hyper-literate/master.svg)](https://coveralls.io/github/jsmaniac/hyper-literate)
[![Build Stats,](https://img.shields.io/badge/build-stats-blue.svg)](http://jsmaniac.github.io/travis-stats/#jsmaniac/hyper-literate) [![Build Stats,](https://img.shields.io/badge/build-stats-blue.svg)](http://jsmaniac.github.io/travis-stats/#jsmaniac/hyper-literate)
[![Online Documentation.](https://img.shields.io/badge/docs-online-blue.svg)](http://docs.racket-lang.org/hyper-literate/) [![Online Documentation.](https://img.shields.io/badge/docs-online-blue.svg)](http://docs.racket-lang.org/hyper-literate/)

View File

@ -1,99 +0,0 @@
;; Copied and modified from https://github.com/racket/scribble/blob/
;; 31ad440b75b189a2b0838aab011544d44d6b580/
;; scribble-lib/scribble/comment-reader.rkt
;;
;; Maybe this should use instead the 'scribble property? See
;; https://docs.racket-lang.org/scribble/
;; reader-internals.html#%28part._.Syntax_.Properties%29
(module comment-reader scheme/base
(require (only-in racket/port peeking-input-port))
(provide (rename-out [*read read]
[*read-syntax read-syntax])
make-comment-readtable)
(define unsyntaxer (make-parameter 'unsyntax))
(define (*read [inp (current-input-port)])
(parameterize ([unsyntaxer (read-unsyntaxer inp)]
[current-readtable (make-comment-readtable)])
(read/recursive inp)))
(define (*read-syntax src [port (current-input-port)])
(parameterize ([unsyntaxer (read-unsyntaxer port)]
[current-readtable (make-comment-readtable)])
(read-syntax/recursive src port)))
(define (read-unsyntaxer port)
(let ([p (peeking-input-port port)])
(if (eq? (read p) '#:escape-id)
(begin (read port) (read port))
'unsyntax)))
(define (make-comment-readtable #:readtable [rt (current-readtable)]
#:comment-wrapper [comment-wrapper 'code:comment]
#:unsyntax [unsyntax? #t])
(make-readtable rt
#\; 'terminating-macro
(case-lambda
[(char port)
(do-comment port
(lambda () (read/recursive port #\@))
#:comment-wrapper comment-wrapper
#:unsyntax unsyntax?)]
[(char port src line col pos)
(let ([v (do-comment port
(lambda () (read-syntax/recursive src port #\@))
#:comment-wrapper comment-wrapper
#:unsyntax unsyntax?)])
(let-values ([(eline ecol epos) (port-next-location port)])
(datum->syntax
#f
v
(list src line col pos (and pos epos (- epos pos))))))])))
(define (do-comment port
recur
#:comment-wrapper [comment-wrapper 'code:comment]
#:unsyntax [unsyntax? #t])
(define comment-text
`(t
,@(append-strings
(let loop ()
(let ([c (read-char port)])
(cond
[(or (eof-object? c)
(char=? c #\newline))
null]
[(char=? c #\@)
(cons (recur) (loop))]
[else
(cons (string c)
(loop))]))))))
(define comment-unsyntax
(if unsyntax?
`(,(unsyntaxer) ,comment-text)
comment-text))
`(,comment-wrapper ,comment-text))
(define (append-strings l)
(let loop ([l l][s null])
(cond
[(null? l) (if (null? s)
null
(preserve-space (apply string-append (reverse s))))]
[(string? (car l))
(loop (cdr l) (cons (car l) s))]
[else
(append (loop null s)
(cons
(car l)
(loop (cdr l) null)))])))
(define (preserve-space s)
(let ([m (regexp-match-positions #rx" +" s)])
(if m
(append (preserve-space (substring s 0 (caar m)))
(list `(hspace ,(- (cdar m) (caar m))))
(preserve-space (substring s (cdar m))))
(list s)))))

View File

@ -1,140 +0,0 @@
#lang typed/racket
(require (rename-in syntax/parse [...+ …+])
syntax/stx
racket/match
racket/set
racket/list
racket/function
racket/vector
racket/contract
sexp-diff
racket/pretty
rackunit
(only-in racket/base [... ])
(for-syntax (rename-in racket/base [... ]))
tr-immutable/typed-syntax
"syntax-properties-typed.rkt")
(provide hide-#%comment)
;; ([#%comment c1] a [#%comment c2] . ([#%comment c3] b [#%comment c4]))
;; => (aᶜ² . (bᶜ⁴)⁻ᶜ³)⁻ᶜ¹
;; (c1 a c2 . (c3 . (c4 b c5)))
;; => (aᶜ² . (bᶜ⁵)⁻ᶜ³⁻⁻ᶜ⁴)⁻ᶜ¹
;; (c1 a c2 . (c3 . (c4 c5)))
;; => (aᶜ² . ()⁻ᶜ³⁻⁻ᶜ⁴ᶜ⁵)⁻ᶜ¹
;; (c1 a (c2) b)
;; => (a ()⁻ᶜ² b)⁻ᶜ¹
;; (c1 a (c2 . b) c)
;; => (a b⁻ᶜ² c)⁻ᶜ¹
;; (c1 a (c2 . (c3 c4)) c)
;; => (a ()⁻ᶜ²⁻⁻ᶜ³ᶜ⁴ c)⁻ᶜ¹
(: hide-#%comment ( ISyntax/Non-Stx ISyntax/Non-Stx))
(define (hide-#%comment stx)
(cond
[(pair? (syntax-e stx))
(hide-in-pair (syntax-e stx))]
[else
;; TODO: recurse down vectors etc.
stx]))
(define-type ISyntax/Non-List*
(Rec L (U ISyntax/Non
Null
(Pairof ISyntax/Non L))))
(define pair (ann cons ( (A B) ( A B (Pairof A B)))))
(: hide-in-pair ( ISyntax/Non-List*
ISyntax/Non-Stx))
(define (hide-in-pair e*)
(let loop ([rest : ISyntax/Non-List* e*]
[groups : (Pairof (Listof Comment)
(Listof (Pairof ISyntax/Non (Listof Comment))))
'(())])
(if (pair? rest)
(if (comment? (car rest))
(loop (cdr rest)
(pair (pair (ann (car rest) Comment) (car groups))
(cdr groups)))
(loop (cdr rest)
(pair (ann '() (Listof Comment))
(pair (pair (car rest) (reverse (car groups)))
(cdr groups)))))
(values rest groups)))
(error "TODOrtfdsvc"))
(define-type Comment (Syntaxof (Pairof (Syntaxof '#%comment) Any)))
(define comment? (make-predicate Comment))
#;(if ((make-predicate (Rec R (Pairof (Syntaxof (Pairof (Syntaxof '#%comment) Any))
(U Boolean
Char
Number
Keyword
Null
String
Symbol
BoxTop
VectorTop
R))))
e*)
(error "TODOwa" e*)
(error "TODOwa" e*))
#|
(: listof? ( (A) ( Any ( Any Boolean : A) Boolean : (Listof A))))
(define (listof? l p?)
(pair? l
p?
(ann (λ (a)
(list*? a p?))
( Any Boolean : ))
|#
#;(match (syntax-e stx)
[(not (? pair?))
;; TODO: recurse down vectors etc.
stx]
[(list* e* ... rest)
(error "TODO")
#;(syntax-parse e*
#:datum-literals (#%comment)
[({~and c₀ [#%comment . _]}
{~seq {~and eᵢ {~not [#%comment . _]}}
{~and cᵢⱼ [#%comment . _]} }
…+)
(define new-e* (map with-comments-after
(map hide-#%comment
(syntax->list #'(eᵢ )))
(map syntax->list
(syntax->list #'((cᵢⱼ ) )))))
(define new-rest (if (null? rest)
rest
(hide-#%comment rest)))
(with-first-comments
(datum->syntax stx (append new-e* new-rest) stx stx)
(cons #f (syntax->list #'(c₀ ))))]
[({~and c₀ [#%comment . _]} )
(define new-rest (if (null? rest)
rest
(hide-#%comment rest)))
(with-first-comments
(with-comments-after
(datum->syntax stx new-rest stx stx)
(if (syntax? new-rest)
(syntax-property new-rest 'comments-after)
'()))
(cons (if (syntax? new-rest)
(cons (datum->syntax new-rest
'saved-props+srcloc
new-rest
new-rest)
(or (syntax-property new-rest 'first-comments)
;; TODO: I'm dubious about this, better typecheck
;; everything…
(cons #f null)))
#f)
(syntax->list #'(c₀ ))))])])

View File

@ -1,75 +0,0 @@
#lang racket
(require (rename-in syntax/parse [...+ …+])
syntax/stx
racket/match
racket/set
racket/list
racket/function
racket/vector
racket/contract
sexp-diff
racket/pretty
rackunit
(only-in racket/base [... ])
(for-syntax (rename-in racket/base [... ]))
"syntax-properties.rkt")
(provide hide-#%comment)
;; ([#%comment c1] a [#%comment c2] . ([#%comment c3] b [#%comment c4]))
;; => (aᶜ² . (bᶜ⁴)⁻ᶜ³)⁻ᶜ¹
;; (c1 a c2 . (c3 . (c4 b c5)))
;; => (aᶜ² . (bᶜ⁵)⁻ᶜ³⁻⁻ᶜ⁴)⁻ᶜ¹
;; (c1 a c2 . (c3 . (c4 c5)))
;; => (aᶜ² . ()⁻ᶜ³⁻⁻ᶜ⁴ᶜ⁵)⁻ᶜ¹
;; (c1 a (c2) b)
;; => (a ()⁻ᶜ² b)⁻ᶜ¹
;; (c1 a (c2 . b) c)
;; => (a b⁻ᶜ² c)⁻ᶜ¹
;; (c1 a (c2 . (c3 c4)) c)
;; => (a ()⁻ᶜ²⁻⁻ᶜ³ᶜ⁴ c)⁻ᶜ¹
(define (hide-#%comment stx)
(match (syntax-e stx)
[(not (? pair?))
;; TODO: recurse down vectors etc.
stx]
[(list* e* ... rest)
(syntax-parse e*
#:datum-literals (#%comment)
[({~and c₀ [#%comment . _]}
{~seq {~and eᵢ {~not [#%comment . _]}}
{~and cᵢⱼ [#%comment . _]} }
…+)
(define new-e* (map with-comments-after
(map hide-#%comment
(syntax->list #'(eᵢ )))
(map syntax->list
(syntax->list #'((cᵢⱼ ) )))))
(define new-rest (if (null? rest)
rest
(hide-#%comment rest)))
(with-first-comments
(datum->syntax stx (append new-e* new-rest) stx stx)
(cons #f (syntax->list #'(c₀ ))))]
[({~and c₀ [#%comment . _]} )
(define new-rest (if (null? rest)
rest
(hide-#%comment rest)))
(with-first-comments
(with-comments-after
(datum->syntax stx new-rest stx stx)
(if (syntax? new-rest)
(syntax-property new-rest 'comments-after)
'()))
(cons (if (syntax? new-rest)
(cons (datum->syntax new-rest
'saved-props+srcloc
new-rest
new-rest)
(or (syntax-property new-rest 'first-comments)
;; TODO: I'm dubious about this, better typecheck
;; everything…
(cons #f null)))
#f)
(syntax->list #'(c₀ ))))])]))

View File

@ -1,130 +0,0 @@
#lang racket
(require (rename-in syntax/parse [...+ …+])
syntax/stx
racket/match
racket/set
racket/list
racket/function
racket/vector
racket/contract
sexp-diff
racket/pretty
rackunit
(only-in racket/base [... ])
(for-syntax (rename-in racket/base [... ]))
"syntax-properties.rkt")
(provide restore-#%comment)
(define/contract (restore-#%comment stx
#:replace-with (replace-with #f)
#:scope [scope (datum->syntax #f 'zero)])
(->* (syntax?)
(#:replace-with [or/c #f syntax? (-> syntax? syntax?)]
#:scope identifier?)
syntax?)
(define (erase-props stx)
(define stx* (if (syntax-property stx 'first-comments)
(syntax-property stx 'first-comments #f)
stx))
(if (syntax-property stx* 'comments-after)
(syntax-property stx* 'comments-after #f)
stx*))
(define (recur stx)
(restore-#%comment stx #:replace-with replace-with #:scope scope))
(define (replace-in commentᵢ)
(syntax-parse commentᵢ
#:datum-literals (#%comment)
[({~and c #%comment} . rest)
(if (syntax? replace-with)
(datum->syntax commentᵢ
`(,(datum->syntax #'c replace-with #'c #'c)
. ,((make-syntax-delta-introducer
scope
(datum->syntax #f 'zero))
#'rest
'add))
commentᵢ
commentᵢ)
(replace-with
(datum->syntax commentᵢ
`(,#'c
. ,((make-syntax-delta-introducer
scope
(datum->syntax #f 'zero))
#'rest
'add))
commentᵢ
commentᵢ)))]
[_
commentᵢ]))
(define (replace-in-after comments)
(if replace-with
(if (eq? comments #f)
comments
(stx-map replace-in comments))
comments))
(define (replace-in-first first-comments)
(define (replace-in-first1 first-comments)
(if (eq? first-comments #f)
first-comments
(cons (cons (caar first-comments)
(replace-in-first1 (cdar first-comments)))
(stx-map replace-in (cdr first-comments)))))
(if replace-with
(if (eq? first-comments #f)
first-comments
(cons (replace-in-first1 (car first-comments))
(stx-map replace-in (cdr first-comments))))
first-comments))
(match (syntax-e stx)
[(list* e* ... rest)
;; TODO: when extracting the comments properties, check that they have
;; the right shape (listof syntax?) or (*list/c syntax? (list/c R))
;; Or append-map when stx is a stx-list (not in a tail position for the
;; comments-after)
(define new-e*
(append-map (λ (eᵢ)
(cons (recur eᵢ)
(or (replace-in-after (extract-comments-after eᵢ))
'())))
e*))
(define new-rest
(if (syntax? rest)
(recur rest)
;; TODO: handle vectors etc. here?
rest))
(define first-comments
(or (replace-in-first (extract-first-comments stx))
#f))
(define (nest first-comments to-nest)
(cond
[(eq? first-comments #f)
to-nest]
[(eq? (car first-comments) #f)
(append (cdr first-comments) to-nest)]
[else
(nest1 first-comments to-nest)]))
(define (nest1 first-comments to-nest)
(if (eq? first-comments #f)
to-nest
(append (cdr first-comments)
(datum->syntax (caar first-comments)
(nest (cdar first-comments) to-nest)))))
(define new-stx
(nest first-comments (append new-e* new-rest)))
(erase-props (datum->syntax stx new-stx stx stx))]
;; TODO: recurse down vectors etc.
[(? vector? v)
;; TODO: what if there is a first-comment property on the vector itself?
(erase-props
(datum->syntax stx
(vector-map (λ (vᵢ)
(recur vᵢ))
v)
stx
stx))]
[other
'TODO…
other]))

View File

@ -1,130 +0,0 @@
#lang racket
(require (rename-in syntax/parse [...+ …+])
syntax/stx
racket/match
racket/set
racket/list
racket/function
racket/vector
racket/contract
sexp-diff
racket/pretty
rackunit
(only-in racket/base [... ])
(for-syntax (rename-in racket/base [... ]))
"syntax-properties.rkt")
(provide restore-#%comment)
(define/contract (restore-#%comment stx
#:replace-with (replace-with #f)
#:scope [scope (datum->syntax #f 'zero)])
(->* (syntax?)
(#:replace-with [or/c #f syntax? (-> syntax? syntax?)]
#:scope identifier?)
syntax?)
(define (erase-props stx)
(define stx* (if (syntax-property stx 'first-comments)
(syntax-property stx 'first-comments #f)
stx))
(if (syntax-property stx* 'comments-after)
(syntax-property stx* 'comments-after #f)
stx*))
(define (recur stx)
(restore-#%comment stx #:replace-with replace-with #:scope scope))
(define (replace-in commentᵢ)
(syntax-parse commentᵢ
#:datum-literals (#%comment)
[({~and c #%comment} . rest)
(if (syntax? replace-with)
(datum->syntax commentᵢ
`(,(datum->syntax #'c replace-with #'c #'c)
. ,((make-syntax-delta-introducer
scope
(datum->syntax #f 'zero))
#'rest
'add))
commentᵢ
commentᵢ)
(replace-with
(datum->syntax commentᵢ
`(,#'c
. ,((make-syntax-delta-introducer
scope
(datum->syntax #f 'zero))
#'rest
'add))
commentᵢ
commentᵢ)))]
[_
commentᵢ]))
(define (replace-in-after comments)
(if replace-with
(if (eq? comments #f)
comments
(stx-map replace-in comments))
comments))
(define (replace-in-first first-comments)
(define (replace-in-first1 first-comments)
(if (eq? first-comments #f)
first-comments
(cons (cons (caar first-comments)
(replace-in-first1 (cdar first-comments)))
(stx-map replace-in (cdr first-comments)))))
(if replace-with
(if (eq? first-comments #f)
first-comments
(cons (replace-in-first1 (car first-comments))
(stx-map replace-in (cdr first-comments))))
first-comments))
(match (syntax-e stx)
[(list* e* ... rest)
;; TODO: when extracting the comments properties, check that they have
;; the right shape (listof syntax?) or (*list/c syntax? (list/c R))
;; Or append-map when stx is a stx-list (not in a tail position for the
;; comments-after)
(define new-e*
(append-map (λ (eᵢ)
(cons (recur eᵢ)
(or (replace-in-after (extract-comments-after eᵢ))
'())))
e*))
(define new-rest
(if (syntax? rest)
(recur rest)
;; TODO: handle vectors etc. here?
rest))
(define first-comments
(or (replace-in-first (extract-first-comments stx))
#f))
(define (nest first-comments to-nest)
(cond
[(eq? first-comments #f)
to-nest]
[(eq? (car first-comments) #f)
(append (cdr first-comments) to-nest)]
[else
(nest1 first-comments to-nest)]))
(define (nest1 first-comments to-nest)
(if (eq? first-comments #f)
to-nest
(append (cdr first-comments)
(datum->syntax (caar first-comments)
(nest (cdar first-comments) to-nest)))))
(define new-stx
(nest first-comments (append new-e* new-rest)))
(erase-props (datum->syntax stx new-stx stx stx))]
;; TODO: recurse down vectors etc.
[(? vector? v)
;; TODO: what if there is a first-comment property on the vector itself?
(erase-props
(datum->syntax stx
(vector-map (λ (vᵢ)
(recur vᵢ))
v)
stx
stx))]
[other
'TODO…
other]))

View File

@ -1,81 +0,0 @@
#lang typed/racket
(provide First-Comments
Comments-After
with-first-comments
with-comments-after
extract-first-comments
extract-comments-after)
(require tr-immutable/typed-syntax
typed-map)
(define-type First-Comments
(Rec R (Pairof (U #f (Pairof (Syntaxof 'saved-props+srcloc)
R))
(Listof ISyntax))))
(define-type Comments-After
(Listof ISyntax))
(: first-comments? ( Any Boolean : (Pairof (U #f (Pairof (Syntaxof 'saved-props+srcloc)
First-Comments))
(Listof ISyntax))))
(define (first-comments? v)
(define p? (inst pairof?
(U #f (Pairof (Syntaxof 'saved-props+srcloc)
First-Comments))
(Listof ISyntax)))
(p? v first-comments1? first-comments2?))
(: first-comments1? ( Any Boolean : (U #f (Pairof (Syntaxof 'saved-props+srcloc)
First-Comments))))
(define (first-comments1? v)
(or (false? v)
(first-comments11? v)))
(: first-comments11? ( Any Boolean : (Pairof (Syntaxof 'saved-props+srcloc)
First-Comments)))
(define (first-comments11? v)
(define p? (inst pairof?
(Syntaxof 'saved-props+srcloc)
First-Comments))
(p? v
(make-predicate (Syntaxof 'saved-props+srcloc))
first-comments?))
(: first-comments2? ( Any Boolean : (Listof ISyntax)))
(define (first-comments2? v)
(and (list? v)
(andmap isyntax? v)))
(: with-first-comments ( (A) ( ISyntax
(U #f First-Comments)
ISyntax)))
(define (with-first-comments e c)
(if (or (not c) (and (= (length c) 1) (not (first c))))
e
(syntax-property e 'first-comments c)))
(: with-comments-after ( (A) ( (Syntaxof A)
(U #f Comments-After)
(Syntaxof A))))
(define (with-comments-after e c)
(if (or (not c) (null? c))
e
(syntax-property e 'comments-after c)))
(: extract-first-comments (-> (Syntaxof Any) (U #f First-Comments)))
(define (extract-first-comments stx)
(define c (syntax-property stx 'first-comments))
(if (first-comments? c)
c
#f))
(: extract-comments-after (-> (Syntaxof Any) (U #f Comments-After)))
(define (extract-comments-after stx)
(define c (syntax-property stx 'comments-after))
(and (list? c)
(andmap isyntax? c)
c))

View File

@ -1,37 +0,0 @@
#lang racket
(provide first-comments/c
comments-after/c
with-first-comments
with-comments-after
extract-first-comments
extract-comments-after)
(define first-comments/c
(flat-rec-contract R (cons/c (or/c #f (cons/c (syntax/c 'saved-props+srcloc)
R)) #| nested |#
(listof syntax?) #| comments |#)))
(define comments-after/c
(listof syntax?))
(define/contract (with-first-comments e c)
(-> syntax?
(or/c #f first-comments/c)
syntax?)
(if (or (not c) (and (= (length c) 1) (not (first c))))
e
(syntax-property e 'first-comments c)))
(define/contract (with-comments-after e c)
(-> syntax? (or/c #f comments-after/c) syntax?)
(if (or (not c) (null? c))
e
(syntax-property e 'comments-after c)))
(define/contract (extract-first-comments stx)
(-> syntax? (or/c #f first-comments/c))
(syntax-property stx 'first-comments))
(define/contract (extract-comments-after stx)
(-> syntax? (or/c #f comments-after/c))
(syntax-property stx 'comments-after))

387
diff1.rkt
View File

@ -1,387 +0,0 @@
#lang at-exp racket/base
(provide hlite)
(require hyper-literate
(for-syntax syntax/parse
(rename-in racket/base [... ])
racket/match
syntax/srcloc)
scribble/core
scribble/html-properties
scribble/latex-properties
scribble/base)
;; For debugging.
(define-for-syntax (show-stx e)
(define (r e)
(cond
([syntax? e]
(display "#'")
(r (syntax-e e)))
[(pair? e)
(display "(")
(let loop ([e e])
(if (pair? e)
(begin (r (car e))
(display " ")
(loop (cdr e)))
(if (null? e)
(display ")")
(begin
(display ". ")
(r e)
(display ")")))))]
[else
(print (syntax->datum (datum->syntax #f e)))]))
(r e)
(newline)
(newline))
(define the-css-addition
#"
.HyperLiterateNormal {
filter: initial;
background: none;
}
.HyperLiterateDim {
filter: brightness(150%) contrast(30%) opacity(0.7);
background: none; /* rgba(82, 103, 255, 0.36); */
}
.HyperLiterateAdd{
filter: initial;
background: rgb(202, 226, 202);
}
.HyperLiterateRemove {
filter: initial;
background: rgb(225, 182, 182);
}")
(define the-latex-addition
#"
%\\usepackage{framed}% \begin{snugshade}\end{snugshade}
\\definecolor{HyperLiterateDimColor}{RGB}{210,210,210}
\\definecolor{HyperLiterateAddColor}{RGB}{202,226,202}
\\definecolor{HyperLiterateRemoveColor}{RGB}{225,182,182}
\\def\\HyperLiterateNormal#1{#1}
\\def\\HyperLiterateDim#1{\\colorbox{HyperLiterateDimColor}{%
\\vphantom{\\RktPn{(}\\RktValDef{Xj}}#1}}
\\def\\HyperLiterateAdd#1{\\colorbox{HyperLiterateAddColor}{%
\\vphantom{\\RktPn{(}\\RktValDef{Xj}}#1}}
\\def\\HyperLiterateRemove#1{\\colorbox{HyperLiterateRemoveColor}{%
\\vphantom{\\RktPn{(}\\RktValDef{Xj}}#1}}
")
(define (init)
(elem
#:style (style #f
(list (css-addition the-css-addition)
(tex-addition the-latex-addition)))))
(begin-for-syntax
(define (stx-null? e)
(or (null? e)
(and (syntax? e)
(null? (syntax-e e)))))
(define (stx-pair? e)
(or (pair? e)
(and (syntax? e)
(pair? (syntax-e e))))))
(define-syntax (hlite stx)
(syntax-case stx ()
[(self name guide1 . body)
(and (identifier? #'self)
(identifier? #'name))
(let ()
(define (simplify-guide g)
(cond
[(and (identifier? g) (free-identifier=? g #'/)) '/]
[(and (identifier? g) (free-identifier=? g #'=)) '=]
[(and (identifier? g) (free-identifier=? g #'-)) '-]
[(and (identifier? g) (free-identifier=? g #'+)) '+]
[(and (identifier? g) (free-identifier=? g #'-/)) '-/]
[(and (identifier? g) (free-identifier=? g #'-=)) '-=]
[(and (identifier? g) (free-identifier=? g #'-+)) '-+]
[(identifier? g) '_]
[(syntax? g) (simplify-guide (syntax-e g))]
[(pair? g) (cons (simplify-guide (car g))
(simplify-guide (cdr g)))]
[(null? g) '()]))
(define (mode→style m)
(case m
[(/) "HyperLiterateDim"]
[(=) "HyperLiterateNormal"]
[(-) "HyperLiterateRemove"]
[(+) "HyperLiterateAdd"]
[(-/) "HyperLiterateDim"]
[(-=) "HyperLiterateNormal"]
[(-+) "HyperLiterateAdd"]))
(define simplified-guide (simplify-guide #'guide1))
(define (syntax-e? v)
(if (syntax? v) (syntax-e v) v))
(define new-body
(let loop ([mode '=]
[guide simplified-guide]
[body #'body])
(match guide
[(cons (and new-mode (or '/ '= '- '+ '-/ '-= '-+)) rest-guide)
(loop new-mode rest-guide body)]
[(list car-guide rest-guide)
#:when (and (pair? (syntax-e? body))
(memq (syntax-e? (car (syntax-e? body)))
'[quote quasiquote
unquote unquote-splicing
quasisyntax syntax
unsyntax unsyntax-splicing])
(pair? (syntax-e? (cdr (syntax-e? body))))
(null? (syntax-e?
(cdr (syntax-e? (cdr (syntax-e? body))))))
(let ([sp (syntax-span (car (syntax-e? body)))])
(or (= sp 1)
(= sp 2))))
(unless (symbol? car-guide)
(raise-syntax-error 'hlite
(format
"expected pattern ~a, found identifier"
car-guide)
(datum->syntax #f (car (syntax-e? body)))))
(define result
`(,(car (syntax-e? body))
,(loop mode
rest-guide
(car (syntax-e? (cdr (syntax-e? body)))))))
(if (syntax? body)
(datum->syntax body result body body)
body)]
[(cons car-guide rest-guide)
(unless (pair? (syntax-e? body))
(raise-syntax-error 'hlite
(format
"expected pair ~a, found non-pair"
guide)
(datum->syntax #f body)))
(define loop2-result
(let loop2 ([first-iteration? #t]
[guide guide]
[body (if (syntax? body) (syntax-e body) body)]
[acc '()])
(cond
[(and (pair? guide)
(memq (car guide) '(/ = - + -/ -= -+)))
(if first-iteration?
(loop (car guide) (cdr guide) body)
;; produce:
;; ({code:hilite {code:line accumulated ...}} . rest)
(let ([r-acc (reverse acc)]
[after (loop (car guide) (cdr guide) body)])
(define (do after)
(datum->syntax
(car r-acc)
`(code:hilite (code:line ,@r-acc . ,after)
,(mode→style mode))
(build-source-location-list
(update-source-location (car r-acc)
#:span 0))))
(if (stx-pair? body)
;; TODO: refactor the two branches, they are very
;; similar.
(cons (do '())
after)
;; Special case to handle (a . b) when b and a
;; do not have the same highlighting.
;; This assigns to the dot the highlighting for
;; b, although it would be possible to assign
;; andother highliughting (just change the
;; mode→style below)
(let* ([loc1 (build-source-location-list
(update-source-location
(car acc)
#:span 0))]
[loc2 (build-source-location-list
(update-source-location
after
#:column (- (syntax-column after)
3) ;; spc + dot + spc
#:span 0))])
`(,(do `(,(datum->syntax
#f
`(code:hilite
,(datum->syntax
#f `(code:line . ,after) loc2)
,(mode→style (car guide)))
loc1))))))))]
[(and (pair? guide) (pair? body))
;; accumulate the first element of body
(loop2 #f
(cdr guide)
(cdr body)
(cons (loop mode (car guide) (car body)) acc))]
;; If body is not a pair, then we will treat it as an
;; "improper tail" element, unless it is null?
[(null? body)
(unless (null? guide)
(raise-syntax-error
'hlite
;; TODO: thread the syntax version of body, so that
;; we can highlight the error.
"Expected non-null body, but found null"
stx))
;; produce:
;; ({code:hilite {code:line accumulated ...}})
(let* ([r-acc (reverse acc)])
`(,(datum->syntax (car r-acc)
`(code:hilite (code:line . ,r-acc)
,(mode→style mode))
(build-source-location-list
(update-source-location (car r-acc)
#:span 0))))
)]
[else
;; produce:
;; ({code:hilite
;; {code:line accumulated ... . improper-tail}})
(let* ([new-body (loop mode guide body)]
[r-acc+tail (append (reverse acc) new-body)])
`(,(datum->syntax
(car r-acc+tail)
`(code:hilite (code:line . ,r-acc+tail)
,(mode→style mode))
(build-source-location-list
(update-source-location (car r-acc+tail)
#:span 0))))
)
])))
(if (syntax? body)
(datum->syntax body loop2-result body body)
loop2-result)]
[(? symbol?)
(datum->syntax body `(code:hilite (code:line ,body)
,(mode→style mode))
(build-source-location-list
(update-source-location body #:span 0)))]
['()
(unless (stx-null? body)
(raise-syntax-error
'hlite
;; TODO: thread the syntax version of body, so that
;; we can highlight the error.
(format "Expected null body, but found non-null ~a"
(syntax->datum body))
stx))
body])))
(define new-executable-code
(let loop ([mode '=]
[guide simplified-guide]
[body #'body])
(match guide
[(cons (and new-mode (or '/ '= '- '+ '-/ '-= '-+)) rest-guide)
(loop new-mode rest-guide body)]
[(cons car-guide rest-guide)
(define (do-append-last-acc last-acc acc)
;; When nothing is later added to acc, we can
;; simply put r as the last element of the
;; reversed acc. This allows r to be an
;; improper list.
;; do-append-last-acc is called when elements follow
;; the current value of last-acc.
(unless (syntax->list (datum->syntax #f last-acc))
(raise-syntax-error
'hlite
(format
(string-append
"the removal of elements caused a list with a"
"dotted tail to be spliced in a non-final position: ~a")
(syntax->datum (datum->syntax #f last-acc)))
stx))
(append (reverse (syntax->list (datum->syntax #f last-acc)))
acc))
(define loop2-result
(let loop2 ([first-iteration? #t]
[guide guide]
[body (if (syntax? body) (syntax-e body) body)]
[acc '()]
[last-acc '()])
(cond
[(and (pair? guide)
(memq (car guide) '(/ = - + -/ -= -+)))
(if (or first-iteration?
(eq? (car guide) mode))
(loop (car guide) (cdr guide) body)
(let ([r (loop (car guide) (cdr guide) body)])
(if (stx-null? r)
;; produce: (accumulated ... . last-acc)
(append (reverse acc) last-acc)
;; produce: (accumulated ... last-acc ... . rest)
(let ([r-acc (reverse (do-append-last-acc
last-acc
acc))])
(append r-acc r)))))]
[(and (pair? guide) (pair? body))
;; accumulate the first element of body, if mode is not '-
;; which means that the element should be removed.
(cond
[(and (memq mode '(- -/ -= -+))
(or (pair? (car body))
(and (syntax? (car body))
(pair? (syntax-e (car body))))))
(let ([r (loop mode (car guide) (car body))])
(loop2 #f
(cdr guide)
(cdr body)
(do-append-last-acc last-acc acc)
r))]
[(memq mode '(- -/ -= -+))
(loop2 #f
(cdr guide)
(cdr body)
acc
last-acc)]
[else
(loop2 #f
(cdr guide)
(cdr body)
(do-append-last-acc last-acc acc)
(list (loop mode (car guide) (car body))))])]
;; If body is not a pair, then we will treat it as an
;; "improper tail" element, unless it is null?
[(null? body)
;; produce:
;; ((accumulated ...))
(let* ([r-acc (append (reverse acc) last-acc)])
r-acc)]
[else
;; produce:
;; (accumulated ... . improper-tail)
(let* ([new-body (loop mode guide body)]
[r-acc+tail (append
(reverse
(do-append-last-acc last-acc acc))
new-body)])
r-acc+tail)])))
(if (syntax? body)
(datum->syntax body loop2-result body body)
loop2-result)]
[(? symbol?)
body]
['()
body])))
;(displayln new-body)
;(show-stx new-body)
#`(begin
(init)
#,(datum->syntax
stx
`(,(datum->syntax #'here 'chunk #'self)
#:display-only
,#'name
. ,(syntax-e new-body))
stx)
(chunk #:save-as dummy name
. #,new-executable-code)))]))

View File

@ -8,24 +8,14 @@
"typed-racket-lib" "typed-racket-lib"
"typed-racket-more" "typed-racket-more"
"typed-racket-doc" "typed-racket-doc"
"scribble-enhanced" "scribble-enhanced"))
"sexp-diff"
"tr-immutable"
"typed-map-lib"
"debug-scopes"
"syntax-color-lib"))
(define build-deps '("scribble-lib" (define build-deps '("scribble-lib"
"racket-doc" "racket-doc"
"rackunit-doc" "rackunit-doc"
"scribble-doc" "scribble-doc"))
"rackunit-doc")) (define scribblings '(("scribblings/hyper-literate.scrbl" ())
(define scribblings '(("scribblings/hyper-literate.scrbl" () ("Scribble Libraries"))
("test/test.hl.rkt" () (omit-start)) ("test/test.hl.rkt" () (omit-start))
("test/test2.hl.rkt" () (omit-start)))) ("test/test2.hl.rkt" () (omit-start))))
(define pkg-desc (define pkg-desc "Description Here")
(string-append "Hyper-literate programming is to literate programming exactly" (define version "0.0")
" what hypertext documents are to regular books and texts." (define pkg-authors '(|Georges Dupéron|))
" For now, this is based on scribble/lp2, and only contains"
" some ε-improvements over it"))
(define version "0.2")
(define pkg-authors '(|Suzanne Soy|))

View File

@ -5,4 +5,4 @@
(provide (rename-out [module-begin/doc #%module-begin]) (provide (rename-out [module-begin/doc #%module-begin])
;; TODO: this is the #%top-interaction from racket/base, not from the ;; TODO: this is the #%top-interaction from racket/base, not from the
;; user-specified language. ;; user-specified language.
#;#%top-interaction) #%top-interaction)

View File

@ -1,55 +0,0 @@
#lang racket/base
(require racket/port)
(provide read-whole-first-line
read-syntax-whole-first-line
narrow-to-one-line
read-line-length)
(define (read-line-length port)
(let* ([peeking (peeking-input-port port)]
[start (file-position peeking)]
[_ (read-line peeking)]
[end (file-position peeking)])
(- end start)))
(define (narrow-to-one-line port)
(make-limited-input-port port (read-line-length port)))
(define (read-*-whole-first-line rec-read in)
(define in1 (peeking-input-port (narrow-to-one-line in)))
(define start-pos (file-position in1))
(let loop ([last-good-pos start-pos])
(define res+
;; Try to read (may fail if the last object to read spills onto the next
;; lines. We read from the peeking-input-port, so that we can retry the
;; last read on the full, non-narrowed port.
(with-handlers ([exn:fail:read? (λ (_) 'read-error)])
(list (rec-read in1))))
(cond
[(eq? res+ 'read-error)
;; Last read was unsuccessful, only consume the bytes from the original
;; input port up to the last successful read. Then, re-try one last read
;; on the whole file (i.e. the last read object may span several lines).
(read-bytes (- last-good-pos start-pos) in)
(list (rec-read in))]
[(eof-object? (car res+))
;; Last successful read, actually consume the bytes from the original
;; input port. Technically, last-good-pos and (file-position pk) should
;; be the same, since the last read returned #<eof> (and therefore did
;; not advance the read pointer.
(read-bytes (- (file-position in1) start-pos) in)
'()]
[else
;; One successful read. Prepend it, and continue reading some more.
(cons (car res+)
(loop (file-position in1)))])))
(define (read-whole-first-line in)
(read-*-whole-first-line (λ (in1) (read in1)) in))
(define (read-syntax-whole-first-line source-name in)
(read-*-whole-first-line (λ (in1) (read-syntax source-name in1)) in))

View File

@ -1,60 +1,31 @@
#lang racket/base #lang racket/base
(require scribble/reader (require scribble/reader
racket/port racket/port)
racket/syntax
syntax/stx
syntax/strip-context
"first-line-utils.rkt"
(only-in "../comment-reader.rkt" make-comment-readtable)
"../comments/hide-comments.rkt")
(provide meta-read-inside (provide meta-read-inside
meta-read-syntax-inside meta-read-syntax-inside)
get-command-char)
(define (make-at-reader+comments #:syntax? [syntax? #t] (define (read-line-length port)
#:inside? [inside? #f] (let* ([peeking (peeking-input-port port)]
#:char [command-char #\@]) [start (file-position peeking)]
(make-at-reader [_ (read-line peeking)]
#:syntax? syntax? [end (file-position peeking)])
#:inside? inside? (- end start)))
#:command-char command-char
#:datum-readtable (λ (rt)
(make-comment-readtable
#:readtable rt
#:comment-wrapper '#%comment
#:unsyntax #f))))
(define (get-command-char rd1) (define (narrow-to-one-line port)
(define rd1-datum (syntax->datum (datum->syntax #f rd1))) (make-limited-input-port port (read-line-length port)))
(if (and (pair? rd1-datum)
(keyword? (car rd1-datum))
(= 1 (string-length (keyword->string (car rd1-datum)))))
(values (string-ref (keyword->string (car rd1-datum)) 0)
(if (syntax? rd1)
(datum->syntax rd1 (stx-cdr rd1) rd1 rd1)
(cdr rd1)))
(values #\@ rd1)))
(define (meta-read-inside in . args) (define (meta-read-inside in . args)
(define rd1 (read-whole-first-line in)) (displayln args)
(define-values (at-exp-char new-rd1) (get-command-char #'rd1)) (apply read-inside args))
(define rd (apply (make-at-reader+comments #:syntax? #f
#:inside? #t
#:char at-exp-char)
args))
`(,new-rd1 . ,rd))
(define (meta-read-syntax-inside source-name in . args) (define (meta-read-syntax-inside source-name in . args)
(with-syntax ([rd1 (read-syntax-whole-first-line source-name in)]) (define in1 (narrow-to-one-line in))
(let-values ([(command-char new-rd1) (get-command-char #'rd1)]) (with-syntax ([rd1 (let loop ([res '()])
(with-syntax* ([new-rd1-stx new-rd1] (define res+ (read-syntax source-name in1))
[rd (apply (make-at-reader+comments #:syntax? #t (if (eof-object? res+)
#:inside? #t (reverse res)
#:char command-char) (loop (cons res+ res))))]
source-name [rd (apply read-syntax-inside source-name in args)])
in #'(rd1 . rd)))
args)]
[rd-hide (hide-#%comment #'rd)])
#'(new-rd1-stx . rd-hide)))))

View File

@ -9,79 +9,8 @@ hyper-literate/lang
;; don't use scribble-base-info for the #:info arg, since ;; don't use scribble-base-info for the #:info arg, since
;; scribble/lp files are not directly scribble'able. ;; scribble/lp files are not directly scribble'able.
#:language-info (scribble-base-language-info) #:language-info (scribble-base-language-info)
#:info (wrapped-scribble-base-reader-info) #:info (scribble-base-reader-info)
(require "meta-first-line.rkt" (require "meta-first-line.rkt"
(only-in scribble/base/reader (only-in scribble/base/reader
scribble-base-reader-info scribble-base-reader-info
scribble-base-language-info) scribble-base-language-info))
"first-line-utils.rkt")
(define orig-scribble-base-reader-info
(scribble-base-reader-info))
(require syntax-color/scribble-lexer
syntax-color/racket-lexer
racket/port)
(define (wrapped-scribble-base-reader-info)
(define (read/at-exp in offset x-mode)
(define-values (mode2 lexr command-char mode)
(apply values x-mode))
(define-values (r1 r2 r3 r4 r5 max-back-up new-mode)
(lexr in offset mode))
(define new-x-mode (list 'main lexr command-char new-mode))
(values r1 r2 r3 r4 r5 max-back-up new-x-mode))
(define (make-lexr command-char)
(make-scribble-inside-lexer #:command-char (or command-char #\@)))
(define (read/options in offset x-mode)
(define-values (mode2 command-char depth)
(apply values x-mode))
(define-values (txt type paren start end status) (racket-lexer/status in))
(define new-depth (case status
[(open) (add1 depth)]
[(close) (sub1 depth)]
[else depth]))
;; TODO: limit the number of newlines to a single newline.
(if (or
;; Fallback to scribble mode fast if we get a close-paren too many.
;; This could be because the text starts right after the last "config"
;; expression (which would start on the first line, then continue).
(< new-depth 0)
(and (= new-depth 0)
(and (eq? type 'white-space)
(regexp-match #px"\n" txt))))
(values txt type paren start end
0 (list 'main (make-lexr command-char) command-char #f))
(let ()
(define new-command-char
(or command-char
(if (memq type '(comment sexp-comment white-space))
#f
(if (eq? type 'hash-colon-keyword)
(let ([rd (read (open-input-string txt))])
(if (and (keyword? rd)
(= (string-length (keyword->string rd)) 1))
(string-ref (keyword->string rd) 0)
#\@))
#\@))))
(values txt type paren start end
0 (list 'options new-command-char new-depth)))))
(lambda (key defval default)
(case key
[(color-lexer)
(λ (in offset x-mode)
(cond
[(eq? x-mode #f)
(read/options in offset (list 'options #f 0))]
[(eq? (car x-mode) 'options)
(read/options in offset x-mode)]
[else
(read/at-exp in offset x-mode)]))]
[else
(orig-scribble-base-reader-info key defval default)])))

View File

@ -7,10 +7,7 @@
(require (for-syntax racket/base syntax/boundmap racket/list (require (for-syntax racket/base syntax/boundmap racket/list
syntax/strip-context syntax/strip-context
syntax/srcloc syntax/srcloc))
racket/struct
syntax/srcloc
debug-scopes/named-scopes/exptime))
(begin-for-syntax (begin-for-syntax
(define first-id #f) (define first-id #f)
@ -32,14 +29,30 @@
chunks id chunks id
`(,@(mapping-get chunks id) ,@exprs)))) `(,@(mapping-get chunks id) ,@exprs))))
(define-for-syntax (tangle orig-stx) (define-for-syntax (tangle orig-stx req-lng)
(define chunk-mentions '()) (define chunk-mentions '())
(unless first-id (unless first-id
(raise-syntax-error 'scribble/lp "no chunks")) (raise-syntax-error 'scribble/lp "no chunks"))
;(define orig-stx (syntax-case stx () [(_ orig) #'orig]))
(define (restore nstx d) (datum->syntax orig-stx d nstx nstx)) (define (restore nstx d) (datum->syntax orig-stx d nstx nstx))
(define (shift nstx) (replace-context orig-stx nstx)) (define (shift nstx) (replace-context orig-stx nstx))
(define body (define body
(let ([main-id (or main-id first-id)]) (let ([main-id (or main-id first-id)])
;; HACK to get arrows drawn for built-ins imported by the module language.
;; TODO: it fails with type-expander.lp2.rkt, because it re-requires λ
;; (the new-λ) from 'main.
(when req-lng
(free-identifier-mapping-put!
chunk-groups main-id
(cons main-id (mapping-get chunk-groups main-id)))
(free-identifier-mapping-put!
chunks main-id
`(,#`(require #,(datum->syntax main-id
req-lng
req-lng
req-lng))
,@(mapping-get chunks main-id))))
;;;;;;;;;;;;;;
(restore (restore
main-id main-id
(let loop ([block (get-chunk main-id)]) (let loop ([block (get-chunk main-id)])
@ -56,9 +69,7 @@
(list (restore expr (loop subs))) (list (restore expr (loop subs)))
(list (shift expr)))))) (list (shift expr))))))
block))))) block)))))
(with-syntax ([body (strip-comments body)] (with-syntax ([(body ...) (strip-comments body)]
;; Hopefully the scopes are correct enough on the whole body.
[body0 (syntax-case body () [(a . _) #'a] [a #'a])]
;; construct arrows manually ;; construct arrows manually
[((b-use b-id) ...) [((b-use b-id) ...)
(append-map (lambda (m) (append-map (lambda (m)
@ -67,13 +78,12 @@
(syntax-local-introduce u))) (syntax-local-introduce u)))
(mapping-get chunk-groups m))) (mapping-get chunk-groups m)))
chunk-mentions)]) chunk-mentions)])
;(displayln (dynamic-require 'tyyyyyyyyyyyped/racket '#%module-begin))
;; TODO: use disappeared-use and disappeared-binding. ;; TODO: use disappeared-use and disappeared-binding.
;; TODO: fix srcloc (already fixed?). ;; TODO: fix srcloc (already fixed?).
;#`(#,(datum->syntax #'body0 'begin) (let ([b-id (void)]) b-use) ... body0 body ...) #`(begin (let ([b-id (void)]) b-use) ... body ...)
(syntax-property #;(replace-context #'#%module-begin;modbeg-ty
(syntax-property #`(#,(datum->syntax #'body0 'begin) . body) #`(begin (let ([b-id (void)]) b-use) ... body ...))))
'disappeared-binding (syntax->list (syntax-local-introduce #'(b-id ...))))
'disappeared-use (syntax->list (syntax-local-introduce #'(b-use ...))))))
(define-for-syntax (strip-comments body) (define-for-syntax (strip-comments body)
(cond (cond
@ -112,9 +122,7 @@
[(and (pair? ad) [(and (pair? ad)
(eq? (syntax-e (car ad)) (eq? (syntax-e (car ad))
'code:line)) 'code:line))
(if (null? (cdr body)) (strip-comments (append (cdr ad) (cdr body)))]
(strip-comments (cdr ad))
(strip-comments (append (cdr ad) (cdr body))))]
[else (cons (strip-comments a) [else (cons (strip-comments a)
(strip-comments (cdr body)))])] (strip-comments (cdr body)))])]
[else body])) [else body]))
@ -136,56 +144,15 @@
(require (for-syntax racket/syntax (require (for-syntax racket/syntax
syntax/parse)) syntax/parse))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require (only-in typed/racket)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; WORKAROUND ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require (for-syntax racket/pretty (require (for-syntax racket/pretty
"no-auto-require.rkt")) "no-auto-require.rkt"))
(define-for-syntax (strip-source e)
(cond [(syntax? e)
(update-source-location
(datum->syntax e (strip-source (syntax-e e)) e e)
#:source #f)]
[(pair? e) (cons (strip-source (car e)) (strip-source (cdr e)))]
[(vector? e) (list->vector (strip-source (vector->list e)))]
[(prefab-struct-key e)
=> (λ (k) (make-prefab-struct k (strip-source (struct->list e))))]
;; TODO: hash tables
[else e]))
;; Many thanks to Alex Knauth and Matthew Flatt for finding out how to make
;; module meta-languages.
(define-syntax (continue stx)
(syntax-case stx ()
[(_self lang-module-begin maybe-chain₊ . body)
(let ()
(define ch₊ (syntax->list #'maybe-chain₊))
(define expanded (local-expand
(datum->syntax stx
`(,#'lang-module-begin ,@ch₊ . ,#'body)
stx
stx)
'module-begin
(list)))
(define meta-language-nesting
;; Use a module-like scope here, instead of (make-syntax-introducer),
;; otherwise DrRacket stops drawing some arrows (why?).
(make-module-like-named-scope 'meta-language-nesting))
(syntax-case expanded (#%plain-module-begin)
[(#%plain-module-begin . expanded-body)
#`(begin
.
#,(meta-language-nesting #'expanded-body))]))]))
(define-for-syntax ((make-module-begin submod?) stx) (define-for-syntax ((make-module-begin submod?) stx)
(syntax-parse stx (syntax-parse stx
;; #:no-require-lang is ignored, but still allowed for compatibility. [(_modbeg (lang:id (~optional (~and no-require-lang #:no-require-lang))
;; TODO: semantically, the no-require-lang and no-auto-require should be (~optional (~and no-auto-require #:no-auto-require)))
;; before the lang, as they are arguments to hyper-literate itself.
[(_modbeg {~or (lang:id
{~optional (~and no-require-lang #:no-require-lang)}
{~optional (~and no-auto-require #:no-auto-require)})
({~optional (~and no-auto-require #:no-auto-require)}
(lang:id
. chain₊))}
body0 . body) body0 . body)
(let () (let ()
(define lang-sym (syntax-e #'lang)) (define lang-sym (syntax-e #'lang))
@ -196,8 +163,7 @@
(for-syntax racket/base (for-syntax racket/base
hyper-literate/private/no-auto-require)) hyper-literate/private/no-auto-require))
(begin-for-syntax (set-box! no-auto-require? (begin-for-syntax (set-box! no-auto-require?
,(if (attribute no-auto-require) #t #f)) ,(if (attribute no-auto-require) #t #f)))
(set-box! preexpanding? #t))
(define-syntax-rule (if-preexpanding a b) a) (define-syntax-rule (if-preexpanding a b) a)
(define-syntax-rule (when-preexpanding . b) (begin . b)) (define-syntax-rule (when-preexpanding . b) (begin . b))
(define-syntax-rule (unless-preexpanding . b) (begin)) (define-syntax-rule (unless-preexpanding . b) (begin))
@ -206,20 +172,25 @@
[(module name elang (mb . stuff)) [(module name elang (mb . stuff))
(let () (let ()
(extract-chunks #'stuff) (extract-chunks #'stuff)
(dynamic-require lang-sym #f)
(namespace-require `(for-meta -1 ,lang-sym))
#;(begin
(define/with-syntax tngl (tangle #'body0))
(define/with-syntax (tngl0 . tngl*) #'tngl)
(define/with-syntax (ex-mod ex-nam ex-lng (ex-#%m . ex-rest))
(expand-syntax
#`(#,#'module hyper-literate-temp-expand #,lang-sym
#,(replace-context #'here #'tngl))))
#`(ex-#%m #,(datum->syntax (syntax-local-introduce #'ex-rest)
'(#%require lang-sym))
. ex-rest))
(define/with-syntax tngl (define/with-syntax tngl
(tangle #'body0)) (tangle #'body0 (if (attribute no-require-lang) #f #'lang)))
(define/with-syntax mb9 (datum->syntax #f '#%module-begin)) ;(replace-context
(define/with-syntax lang-modbeg (datum->syntax #'lang '#%module-begin)) ;(namespace-symbol->identifier '#%module-begin)
; See http://stackoverflow.com/questions/37867859/module-meta-language-in-racket : ;#`(#,(syntax/loc #'lang #%module-begin) …)
#;(define expanded-main-mod-stx #`(#,(namespace-symbol->identifier '#%module-begin)
(local-expand tngl
(syntax-local-introduce
(datum->syntax #f `(,#'module ignored ,(datum->syntax #f lang-sym #'lang #'lang) (,#'mb9 ,(syntax-local-introduce #'tngl)))))
'top-level
(list)))
;(syntax-case expanded-main-mod-stx ();(module #%plain-module-begin)
;[(module _ lng11 (#%plain-module-begin . mod-body11))
#`(#%plain-module-begin
#,@(if submod? #,@(if submod?
(list (list
(with-syntax* (with-syntax*
@ -233,38 +204,32 @@
#:span 14)] #:span 14)]
[lng (datum->syntax #'ctx 'scribble/doclang2 #'bd1 #'bd1)] [lng (datum->syntax #'ctx 'scribble/doclang2 #'bd1 #'bd1)]
[begn (datum->syntax #'ctx 'begin)]) [begn (datum->syntax #'ctx 'begin)])
(strip-source #`(module* doc lng ;module doc scribble/doclang2
#`(module* doc lng ;module doc scribble/doclang2 #,@(syntax-local-introduce
#,@(syntax-local-introduce ;; TODO: instead use:
;; TODO: instead use: ;; (begin-for-syntax (set! preexpanding #f))
;; (begin-for-syntax (set! preexpanding #f)) ;; and make these identifiers exported by
;; and make these identifiers exported by ;; hyper-literate
;; hyper-literate (strip-context
(strip-context #`((require hyper-literate/private/chunks-toc-prefix
#`((require hyper-literate/private/chunks-toc-prefix (for-syntax racket/base
(for-syntax racket/base hyper-literate/private/no-auto-require))
hyper-literate/private/no-auto-require)) (begin-for-syntax (set-box! no-auto-require?
(begin-for-syntax #,(if (attribute no-auto-require) #t #f)))
(set-box! no-auto-require? (define-syntax-rule (if-preexpanding a b)
#,(if (attribute no-auto-require) #t #f)) b)
(set-box! preexpanding? #f)) (define-syntax-rule (when-preexpanding . b)
(define-syntax-rule (if-preexpanding a b) (begin))
b) (define-syntax-rule (unless-preexpanding . b)
(define-syntax-rule (when-preexpanding . b) (begin . b))
(begin)) (require scribble-enhanced/with-manual
(define-syntax-rule (unless-preexpanding . b) hyper-literate))))
(begin . b)) (begn body0 . body))
(require scribble-enhanced/with-manual ;(strip-context
hyper-literate)))) #;#`(modl doc lng ;module doc scribble/doclang2
(begn body0 . body)))))
'()) (begn body0 . body))))
(require lang) '())))])))]))
(continue lang-modbeg
#,(if (attribute chain₊)
#'(chain₊)
#'())
tngl)) ;; TODO: put . tngl and remove the (begin _)
)])))]))
(define-syntax module-begin/plain (make-module-begin #f)) (define-syntax module-begin/plain (make-module-begin #f))
(define-syntax module-begin/doc (make-module-begin #t)) (define-syntax module-begin/doc (make-module-begin #t))

View File

@ -7,10 +7,7 @@
(for-syntax scheme/base (for-syntax scheme/base
syntax/boundmap syntax/boundmap
syntax/parse syntax/parse
racket/syntax racket/syntax))
racket/struct
syntax/srcloc
"../restore-comments.rkt"))
(begin-for-syntax (begin-for-syntax
;; maps chunk identifiers to a counter, so we can distinguish multiple uses ;; maps chunk identifiers to a counter, so we can distinguish multiple uses
@ -116,30 +113,10 @@
#'() #'()
#'((require (for-label for-label-mod ... ...))))))])) #'((require (for-label for-label-mod ... ...))))))]))
(define-for-syntax (strip-source e) (define-for-syntax ((make-chunk-display racketblock) stx)
(cond [(syntax? e)
(update-source-location
(datum->syntax e (strip-source (syntax-e e)) e e)
#:source #f)]
[(pair? e) (cons (strip-source (car e)) (strip-source (cdr e)))]
[(vector? e) (list->vector (strip-source (vector->list e)))]
[(prefab-struct-key e)
=> (λ (k) (make-prefab-struct k (strip-source (struct->list e))))]
;; TODO: hash tables
[else e]))
(define-for-syntax (prettify-chunk-name str)
(regexp-replace #px"^<(.*)>$" str "«\\"))
(define-for-syntax ((make-chunk-display racketblock unsyntax-id) stx)
(syntax-parse stx (syntax-parse stx
;; no need for more error checking, using chunk for the code will do that ;; no need for more error checking, using chunk for the code will do that
[(_ {~optional {~seq #:button button}} [(_ original-name:id name:id stxn:number expr ...)
(original-before-expr ...)
original-name:id
name:id
stxn:number
expr ...)
(define n (syntax-e #'stxn)) (define n (syntax-e #'stxn))
(define original-name:n (syntax-local-introduce (define original-name:n (syntax-local-introduce
(format-id #'original-name (format-id #'original-name
@ -149,7 +126,6 @@
(define n-repeat (get+increment-repeat-chunk-number! (define n-repeat (get+increment-repeat-chunk-number!
original-name:n)) original-name:n))
(define str (symbol->string (syntax-e #'name))) (define str (symbol->string (syntax-e #'name)))
(define str-display (prettify-chunk-name str))
(define/with-syntax tag (format "chunk:~a:~a:~a" str n n-repeat)) (define/with-syntax tag (format "chunk:~a:~a:~a" str n n-repeat))
(define/with-syntax (rest ...) (define/with-syntax (rest ...)
;; if the would-be-next number for this chunk name is "2", then there is ;; if the would-be-next number for this chunk name is "2", then there is
@ -160,20 +136,6 @@
(and c (> c 2))) (and c (> c 2)))
#`((subscript #,(format "~a" n))) #`((subscript #,(format "~a" n)))
#'())) #'()))
;; Restore comments which have been read by the modified comment-reader
;; and stashed away by read-syntax in "../lang/meta-first-line.rkt"
(define/with-syntax (_ . expr*+comments)
(restore-#%comment #'(original-before-expr ... expr ...)
#:replace-with
(λ (stx)
(syntax-parse stx
#:datum-literals (#%comment)
[({~and #%comment com} . rest)
#:with c-c (datum->syntax #'com 'code:comment #'com #'com)
(datum->syntax stx `(,#'c-c (,unsyntax-id . ,#'rest)) stx stx)]
[other
#'other]))
#:scope #'original-name))
;; The (list) here could be important, to avoid the code being ;; The (list) here could be important, to avoid the code being
;; executed multiple times in weird ways, when pre-expanding. ;; executed multiple times in weird ways, when pre-expanding.
#`(list #`(list
@ -183,28 +145,20 @@
(list (elemtag '(prefixable tag) (list (elemtag '(prefixable tag)
(bold (italic (elemref '(prefixable tag) (bold (italic (elemref '(prefixable tag)
#:underline? #f #:underline? #f
#,str-display rest ...)) #,str rest ...))
" ::=")) " ::=")))
#,@(if (attribute button) #'{button} #'{}))
(list (smaller (list (smaller
(make-link-element "plainlink" (make-link-element "plainlink"
(decode-content (decode-content (list #,str rest ...))
(list #,str-display rest ...))
`(elem (prefixable `(elem (prefixable
,@(chunks-toc-prefix) ,@(chunks-toc-prefix)
tag)))))) tag))))))
(#,racketblock (#,racketblock expr ...))))]))
. #,(strip-source #'expr*+comments)))))]))
(define-for-syntax (make-chunk chunk-code chunk-display) (define-for-syntax (make-chunk chunk-code chunk-display)
(syntax-parser (syntax-parser
;; no need for more error checking, using chunk for the code will do that ;; no need for more error checking, using chunk for the code will do that
[(_ {~optional {~seq #:save-as save-as:id}} [(_ (~optional (~seq #:save-as save-as:id)) name:id expr ...)
{~optional {~and #:display-only display-only}}
{~optional {~seq #:button button}}
{~and name:id original-before-expr}
expr ...)
#:with (btn ...) (if (attribute button) #'{#:button button} #'{})
(define n (get-chunk-number (syntax-local-introduce #'name))) (define n (get-chunk-number (syntax-local-introduce #'name)))
(define/with-syntax name:n (format-id #'name "~a:~a" #'name (or n 1))) (define/with-syntax name:n (format-id #'name "~a:~a" #'name (or n 1)))
@ -221,18 +175,12 @@
(define/with-syntax stx-chunk-display chunk-display) (define/with-syntax stx-chunk-display chunk-display)
#`(begin #`(begin
#,@(if (attribute display-only) (stx-chunk-code name expr ...)
#'{}
#`{(stx-chunk-code name
. #,(if preexpanding?
#'(expr ...)
#'(expr ...)
#;(strip-source #'(expr ...))))})
#,@(if n #,@(if n
#'() #'()
#'((define-syntax name (make-element-id-transformer #'((define-syntax name (make-element-id-transformer
(lambda (stx) #'(chunkref name)))) (lambda (stx) #'(chunkref name))))
(define-syntax dummy (init-chunk-number #'name)))) (begin-for-syntax (init-chunk-number #'name))))
#,(if (attribute save-as) #,(if (attribute save-as)
#`(begin #`(begin
#,#'(define-syntax (do-for-syntax _) #,#'(define-syntax (do-for-syntax _)
@ -261,27 +209,20 @@
(quote-syntax name))] (quote-syntax name))]
[(local-expr (... ...)) [(local-expr (... ...))
(syntax-local-introduce (syntax-local-introduce
(quote-syntax #,(strip-source #'(expr ...))))]) (quote-syntax (expr ...)))])
#`(stx-chunk-display #`(stx-chunk-display
btn ...
(original-before-expr)
local-name local-name
newname newname
stx-n stx-n
local-expr (... ...)))]))) local-expr (... ...)))])))
;; The (list) here could be important, to avoid the code being ;; The (list) here could be important, to avoid the code being
;; executed multiple times in weird ways, when pre-expanding. ;; executed multiple times in weird ways, when pre-expanding.
#`(list (stx-chunk-display btn ... #`(list (stx-chunk-display name name stx-n expr ...))))]))
(original-before-expr)
name
name
stx-n
. #,(strip-source #'(expr ...))))))]))
(define-syntax chunk-code (make-chunk-code #t)) (define-syntax chunk-code (make-chunk-code #t))
(define-syntax CHUNK-code (make-chunk-code #f)) (define-syntax CHUNK-code (make-chunk-code #f))
(define-syntax chunk-display (make-chunk-display #'racketblock #'unsyntax)) (define-syntax chunk-display (make-chunk-display #'racketblock))
(define-syntax CHUNK-display (make-chunk-display #'RACKETBLOCK #'UNSYNTAX)) (define-syntax CHUNK-display (make-chunk-display #'RACKETBLOCK))
(define-syntax chunk (make-chunk #'chunk-code #'chunk-display)) (define-syntax chunk (make-chunk #'chunk-code #'chunk-display))
(define-syntax CHUNK (make-chunk #'CHUNK-code #'CHUNK-display)) (define-syntax CHUNK (make-chunk #'CHUNK-code #'CHUNK-display))
@ -290,8 +231,8 @@
[(_ id) [(_ id)
(identifier? #'id) (identifier? #'id)
(with-syntax ([tag (format "chunk:~a:1:1" (syntax-e #'id))] (with-syntax ([tag (format "chunk:~a:1:1" (syntax-e #'id))]
[pretty (prettify-chunk-name (format "~a" (syntax-e #'id)))]) [str (format "~a" (syntax-e #'id))])
#'(elemref '(prefixable tag) #:underline? #f pretty))])) #'(elemref '(prefixable tag) #:underline? #f str))]))
(provide (all-from-out scheme/base (provide (all-from-out scheme/base

View File

@ -2,5 +2,3 @@
(provide no-auto-require?) (provide no-auto-require?)
(define no-auto-require? (box #f)) (define no-auto-require? (box #f))
(provide preexpanding?)
(define preexpanding? (box #f))

View File

@ -1,3 +0,0 @@
#lang racket
(require "comments/restore-comments.rkt")
(provide restore-#%comment)

View File

@ -1,120 +0,0 @@
#lang hyper-literate #:♦ racket/base
;(dotlambda/unhygienic . racket/base)
♦title{Highlighting added, removed and existing parts in literate programs}
♦defmodule[hyper-literate/diff1]
Highly experimental. Contains bugs, API may change in the future.
♦defform[(hlite name pat . body)]{
Like ♦racket[chunk], but highlights parts of the ♦racket[body] according to
the pattern ♦racket[pat].
The ♦racket[pat] should cover the whole ♦racket[body], which can contain
multiple expressions. The ♦racket[pat] can use the following symbols:
♦itemlist[
♦item{♦racket[=] to indicate that the following elements are ``normal'' and
should not be highlighted in any special way.}
♦item{♦racket[/] to indicate that the following elements were already
existing in previous occurrences of the code (the part is dimmed)}
♦item{♦racket[+] to indicate that the following elements are new (highlighted
in green)}
♦item{♦racket[-] to indicate that the following elements are removed
(highlighted in red). Removed elements are also removed from the actual
executable source code. If a removed element contains one or more normal, new
or dimmed elements, these children are spliced in place of the removed
element.}
♦item{Other symbols are placeholders for the elements}]
In the following example, the ♦racket[1] is highlighted as removed (and will
not be present in the executable code), the ♦racket[π] is highlighted as
added, and the rest of the code is dimmed:
♦codeblock|{
#lang hyper-literate #:♦ racket/base
♦hlite[<my-code> {/ (def args (_ - _ + _ / . _))}
(define (foo v)
(+ 1 π . v))]}|
It produces the result shown below:}
♦require[hyper-literate/diff1]
♦hlite[<my-code> {/ (def args (_ - _ + _ / . _))}
(define (foo v)
(+ 1 π . v))]
♦section{Example}
You can look at the source code of this document to see how this example is
done.
♦require[hyper-literate/diff1]
We define the function foo as follows:
♦chunk[<foo>
(define (foo v)
(+ 1 v))]
However, due to implementation details, we need to add ♦racket[π] to this
value:
♦hlite[|<foo'>| {/ (def args (_ _ + _ / . _))}
(define (foo v)
(+ 1 π . v))]
In order to optimise the sum of ♦racket[1] and ♦racket[π], we extract the
computation to a global helper constant:
♦hlite[|<foo''>| {+ _ _ / (def args '(+ a - b + c d . e) (_ - _ _ + _ / _)) = _}
(define π 3.1414592653589793)
(define one-pus-π (+ 1 π))
(define (foo v)
'(a b c d . e)
(+ 1 π one-pus-π v))0]
♦hlite[|<www>| (/ (quote (+ a - b + c d . e))
(quote (+ a - b + c d . e))
(= quote (+ a - b + c d . e))
(quote (quote (+ a - b + c d . e))))
'(a b c d . e)
(quote (a b c d . e))
(quote (a b c d . e))
''(a b c d . e)]
The whole program is therefore:
♦hlite[|<aaa>| {- a + b = c / d}
1 2 3 4]
♦hlite[<bbb> {- (+ a - b = c)}
(x y z)]
♦hlite[<ccc> {(z - (+ a - b / . c))}
(0 (x y . z))]
♦hlite[<ddd> {(z - ((+ a a - b b / . c)))}
(0 ((x x y yy . z)))]
♦hlite[<eee> {(z - ((+ a a - b b / . c)))}
(0 ((x x y yy
. z)))]
♦chunk[<*>
(require rackunit)
|<foo''>|
(check-= (foo 42) (+ 42 1 3.1414592653589793) 0.1)
(check-equal? (list <www>)
'((a c d . e)
(a c d . e)
(a c d . e)
(quote (a c d . e))))
(check-equal? '(<aaa>) '(2 3 4))
(check-equal? '(0 <bbb> 1) '(0 x z 1))
(check-equal? '<ccc> '(0 x . z))
(check-equal? '<ddd> '(0 x x . z))]

View File

@ -5,8 +5,8 @@
(subtract-in scribble/manual hyper-literate) (subtract-in scribble/manual hyper-literate)
racket/contract]] racket/contract]]
@title{Hyper-literate programming} @title{hyper-literate}
@author[@author+email["Suzanne Soy" "racket@suzanne.soy"]] @author{Georges Dupéron}
@(require scribble/manual @(require scribble/manual
scribble/core scribble/core
@ -41,10 +41,8 @@ options:
flow-empty-line flow-empty-line
(list (list
@racketgrammar*[ @racketgrammar*[
(maybe-no-req (code:line) [maybe-no-req #:no-require-lang]
(code:line #:no-require-lang)) [maybe-no-auto #:no-auto-require]])))
(maybe-no-auto (code:line)
(code:line #:no-auto-require))])))
where @racket[_lang] is a module name which can be used as where @racket[_lang] is a module name which can be used as
a @litchar{#lang}, for example @racketmodname[typed/racket] a @litchar{#lang}, for example @racketmodname[typed/racket]
@ -54,11 +52,14 @@ The current implementation of hyper-literate needs to inject
a @racket[(require _lang)] in the expanded module, in order a @racket[(require _lang)] in the expanded module, in order
to have the arrows properly working in DrRacket for to have the arrows properly working in DrRacket for
"built-in" identifiers which are provided by the "built-in" identifiers which are provided by the
@racket[_lang] itself. The @racket[require] statement is @racket[_lang] itself. This extra @racket[require] statement
injected after the whole ``code'' module has been expanded. can however conflict with later user-provided
It is worth noting that an extra scope is added to the expanded @racket[require] statements, which would otherwise shadow
body of the module, in order to make any @racket[require] form the built-ins. The @racket[#:no-require-lang] option
within more specific than the @racket[(require _lang)]. disables that behaviour, and has the only drawback that
built-ins of the @racket[_lang] language do not have an
arrow in DrRacket (but they still should be highlighted with
a turquoise background when hovered over with the mouse).
The current implementation of @racketmodname[scribble/lp2], The current implementation of @racketmodname[scribble/lp2],
on which @racketmodname[hyper-literate] relies (with a few on which @racketmodname[hyper-literate] relies (with a few
@ -77,24 +78,6 @@ possible in this case to disable the feature using
@racket[(require (for-label …))] and handle conflicting @racket[(require (for-label …))] and handle conflicting
identifiers in a more fine-grained way. identifiers in a more fine-grained way.
@deprecated[#:what @racket[#:no-require-lang] ""]{
The @racket[#:no-require-lang] is deprecated starting from version 0.1, and
is not needed anymore. It is still accepted for backwards compatibility. Note
that version 0.1 of this library requires a fairly recent Racket version to
work properly (it needs v.6.7.0.4 with the commit
@tt{8a7852ebbfeb85a8f860700ba5ae481ed7aa9b41}, or v.6.7.0.5 or later). By
default, raco will install v0.0 of hyper-literate on older Racket versions.
The extra @racket[require] statement injected by
@racketmodname[hyper-literate] could in previous versions conflict with
user-written @racket[require] statements. These @racket[require] statements
can shadow some built-ins, and this case would yield conflicts. The
@racket[#:no-require-lang] option disables that behaviour in versions < 0.1,
and has the only drawback that built-ins of the @racket[_lang] language do not
have an arrow in DrRacket (but they still should be highlighted with -a
turquoise background when hovered over with the mouse).}
@section{What is hyper-literate programming?} @section{What is hyper-literate programming?}
Hyper-literate programming is to literate programming Hyper-literate programming is to literate programming
@ -270,6 +253,3 @@ present).
" (lib \"pkg/program.hl.rkt\")))\n" " (lib \"pkg/program.hl.rkt\")))\n"
"@chunk[<*>\n" "@chunk[<*>\n"
" 'program-code-here]\n"]}]} " 'program-code-here]\n"]}]}
@include-section[(submod (lib "hyper-literate/scribblings/diff1-example.hl.rkt")
doc)]

View File

@ -1,142 +0,0 @@
#lang racket
(provide spoiler-wrapper-collapsed
spoiler-default
spoiler-alt
spoiler-button-default-to-alt
spoiler-button-alt-to-default
spoiler1
spler)
(require scribble/manual
scribble/core
scribble/decode
scribble/html-properties
hyper-literate
(for-syntax syntax/parse)
scriblib/render-cond)
(define spoiler-css
#"
.spoiler-wrapper-expanded .spoiler-default,
.spoiler-wrapper-expanded .spoiler-button-default-to-alt {
display:none;
}
.spoiler-wrapper-collapsed .spoiler-alt,
.spoiler-wrapper-collapsed .spoiler-button-alt-to-default {
display:none;
}
.spoiler-button-default-to-alt,
.spoiler-button-alt-to-default {
color: #2a657e;
}
")
(define spoiler-js
(string->bytes/utf-8
#<<EOJS
function toggleSpoiler(e, doExpand) {
var expanded = function(className) {
return className.match(/\bspoiler-wrapper-expanded\b/);
};
var collapsed = function(className) {
return className.match(/\bspoiler-wrapper-collapsed\b/);
};
var found = function(className) {
return expanded(className) || collapsed(className);
};
var wrapper = e;
while (e != document && e != null && ! found(e.className)) {
e = e.parentNode;
}
e.className = e
.className
.replace(/ */g, " ")
.replace(/\bspoiler-wrapper-expanded\b/, '')
.replace(/\bspoiler-wrapper-collapsed\b/, '');
if (doExpand) {
e.className = e.className + " spoiler-wrapper-expanded";
} else {
e.className = e.className + " spoiler-wrapper-collapsed";
}
if (e.preventDefault) { e.preventDefault(); }
return false;
}
EOJS
))
(define-syntax-rule (def-style name)
(define name
(style (symbol->string 'name)
(list (css-addition spoiler-css)
(js-addition spoiler-js)
(alt-tag "div")))))
(def-style spoiler-wrapper-collapsed)
(def-style spoiler-default)
(def-style spoiler-alt)
(define (spoiler-button-default-to-alt txt)
(hyperlink
#:style (style "spoiler-button-default-to-alt"
(list (css-addition spoiler-css)
(js-addition spoiler-js)
(attributes
'([onclick . "return toggleSpoiler(this, true);"]))))
"#"
txt))
(define (spoiler-button-alt-to-default txt)
(hyperlink
#:style (style "spoiler-button-alt-to-default"
(list (css-addition spoiler-css)
(js-addition spoiler-js)
(attributes
'([onclick . "return toggleSpoiler(this, false);"]))))
"#"
txt))
(define (spoiler1 default button-default→alt button-alt→default alternate)
(nested-flow spoiler-wrapper-collapsed
(list
(paragraph (style #f '())
(spoiler-button-default-to-alt button-default→alt))
(nested-flow spoiler-default
(decode-flow default))
(paragraph (style #f '())
(spoiler-button-alt-to-default button-alt→default))
(nested-flow spoiler-alt
(decode-flow alternate)))))
(define-syntax spler
(syntax-parser
[(_ name default ... #:expanded expanded ...)
#'(begin
(chunk #:save-as ck1
#:display-only
#:button
(cond-element
[html (list " " (smaller
(spoiler-button-default-to-alt "expand")))]
[else (list)])
name
default ...)
(chunk #:save-as ck2
#:button
(cond-element
[html (list " " (smaller
(spoiler-button-alt-to-default "collapse")))]
[else (list)])
name
expanded ...)
(cond-block
[html (nested-flow spoiler-wrapper-collapsed
(list (nested-flow spoiler-default
(decode-flow (ck1)))
(nested-flow spoiler-alt
(decode-flow (ck2)))))]
[else (nested-flow (style #f '())
(decode-flow (ck2)))]))]))

View File

@ -1,69 +0,0 @@
#lang typed/racket
(require typed-map
tr-immutable/typed-syntax)
(provide annotate-syntax)
(: annotate-syntax (->* (ISyntax/Non)
(#:srcloc+scopes? Boolean)
Sexp/Non))
(define (annotate-syntax e #:srcloc+scopes? [srcloc+scopes? #f])
(annotate-syntax1 e srcloc+scopes?))
(: annotate-syntax1 ( (U ISyntax/Non ISyntax/Non-E)
Boolean
Sexp/Non))
(define (annotate-syntax1 e srcloc+scopes?)
(cond
[(syntax? e)
(append
(list 'syntax
(append-map (λ ([kᵢ : Symbol])
(if (and (or (eq? kᵢ 'first-comments)
(eq? kᵢ 'comments-after))
(not (syntax-property e kᵢ)))
(list)
(list kᵢ (any->isexp/non (syntax-property e kᵢ)))))
(syntax-property-symbol-keys e)))
(if srcloc+scopes?
(list (any->isexp/non (syntax-source e))
(any->isexp/non (syntax-line e))
(any->isexp/non (syntax-column e))
(any->isexp/non (syntax-position e))
(any->isexp/non (syntax-span e))
(any->isexp/non (syntax-source-module e))
(any->isexp/non (hash-ref (syntax-debug-info e)
'context)))
(list))
(list (annotate-syntax1 (syntax-e e) srcloc+scopes?)))]
[(null? e)
'null]
[(list? e)
(list 'list
(map (λ (eᵢ) (annotate-syntax1 eᵢ srcloc+scopes?))
e))]
[(pair? e)
(list 'cons
(annotate-syntax1 (car e) srcloc+scopes?)
(annotate-syntax1 (cdr e) srcloc+scopes?))]
[(vector? e)
(list 'vector
(immutable? e)
(map (λ (eᵢ) (annotate-syntax1 eᵢ srcloc+scopes?))
(vector->list e)))]
[(box? e)
(list 'box
(immutable? e)
(annotate-syntax1 (unbox e) srcloc+scopes?))]
[(or (symbol? e)
(string? e)
(boolean? e)
(char? e)
(number? e)
(keyword? e))
e]
[(NonSyntax? e)
(list 'NonSyntax (NonSexp (NonSyntax-v e)))]
[(NonSexp? e)
(list 'NonSexp e)]))

View File

@ -1,52 +0,0 @@
#lang racket
(provide annotate-syntax)
(define (annotate-syntax e #:srcloc+scopes? [srcloc+scopes? #f])
(cond
[(syntax? e)
(append
(list 'syntax
(append-map (λ (kᵢ)
(if (and (or (eq? kᵢ 'first-comments)
(eq? kᵢ 'comments-after))
(not (syntax-property e kᵢ)))
(list)
(list kᵢ (syntax-property e kᵢ))))
(syntax-property-symbol-keys e)))
(if srcloc+scopes?
(list (syntax-source e)
(syntax-line e)
(syntax-column e)
(syntax-position e)
(syntax-span e)
(syntax-source-module e)
(hash-ref (syntax-debug-info e) 'context))
(list))
(list (annotate-syntax (syntax-e e) #:srcloc+scopes? srcloc+scopes?)))]
[(null? e)
'null]
[(list? e)
(list 'list
(map (λ (eᵢ) (annotate-syntax eᵢ #:srcloc+scopes? srcloc+scopes?))
e))]
[(pair? e)
(list 'cons
(annotate-syntax (car e) #:srcloc+scopes? srcloc+scopes?)
(annotate-syntax (cdr e) #:srcloc+scopes? srcloc+scopes?))]
[(vector? e)
(list 'vector
(immutable? e)
(map (λ (eᵢ) (annotate-syntax eᵢ #:srcloc+scopes? srcloc+scopes?))
(vector->list e)))]
[(symbol? e)
e]
[(string? e)
e]
[else
(raise-argument-error
'annotate-syntax
(string-append "a syntax object containing recursively on of the"
" following: pair, null, vector, symbol, string")
0
e)]))

View File

@ -1,33 +0,0 @@
#lang typed/racket
(require "annotate-syntax-typed.rkt"
tr-immutable/typed-syntax
rackunit)
(require typed/racket/unsafe)
(unsafe-require/typed sexp-diff
[sexp-diff (case→
( Sexp Sexp Sexp)
( Sexp/Non Sexp/Non Sexp/Non)
( (Sexpof Any) (Sexpof Any) (Sexpof Any)))])
(provide check-same-syntax)
(: same-syntax! ( ISyntax/Non ISyntax/Non Boolean))
(define (same-syntax! a b)
(define answer (equal? (annotate-syntax a #:srcloc+scopes? #f)
(annotate-syntax b #:srcloc+scopes? #f)))
(unless answer
(pretty-write
(sexp-diff (annotate-syntax a)
(annotate-syntax b)))
(displayln a)
(displayln b))
answer)
(define-syntax (check-same-syntax stx)
(syntax-case stx ()
[(_ a b)
(datum->syntax #'here
`(check-true (same-syntax! ,#'a ,#'b))
stx)]))

View File

@ -1,25 +0,0 @@
#lang racket
(require "annotate-syntax.rkt"
sexp-diff
rackunit)
(provide check-same-syntax)
(define (same-syntax! a b)
(define answer (equal? (annotate-syntax a #:srcloc+scopes? #f)
(annotate-syntax b #:srcloc+scopes? #f)))
(unless answer
(pretty-write
(sexp-diff (annotate-syntax a)
(annotate-syntax b)))
(displayln a)
(displayln b))
answer)
(define-syntax (check-same-syntax stx)
(syntax-case stx ()
[(_ a b)
(datum->syntax #'here
`(check-true (same-syntax! ,#'a ,#'b))
stx)]))

View File

@ -1,55 +0,0 @@
#lang racket
(require rackunit
"../../comments/hide-comments.rkt"
"../../comments/restore-comments.rkt"
"same-syntax.rkt")
(define round-trip (compose restore-#%comment hide-#%comment))
(define-syntax (check-round-trip stx)
(syntax-case stx ()
[(_ a)
(datum->syntax #'here
`(begin
(check-same-syntax (round-trip ,#'a) ,#'a)
(check-equal? (syntax->datum (round-trip ,#'a))
(syntax->datum ,#'a)))
stx)]))
;; =============================================================================
(let ([stx #'(a b c)])
(check-same-syntax stx (hide-#%comment stx)))
(check-round-trip #'(a (#%comment "b") c))
(check-round-trip #'((#%comment "0") (#%comment "1")
a
(#%comment "b")
(#%comment "bb")
c
(#%comment "d")
(#%comment "dd")))
(check-round-trip #'([#%comment c1]
a
[#%comment c2]
. ([#%comment c3] b [#%comment c4])))
(check-round-trip #'([#%comment c1]
a
[#%comment c2]
. ([#%comment c3]
. ([#%comment c4] b [#%comment c5]))))
(check-round-trip #'([#%comment c1]
a
[#%comment c2]
. ([#%comment c3]
. ([#%comment c4] [#%comment c5]))))
(check-round-trip #'([#%comment c1]
a
([#%comment c2])
b))
(check-round-trip #'([#%comment c1]
a
([#%comment c2] . b)
c))