(module generator mzscheme
(require "private/matcher.ss")
(provide lang->generator-table
for-each-generated
for-each-generated/size)
(define (lang->generator-table lang
nums
vars
strs
skip-kws
cache-limit)
(define (cache-small gen) gen)
(let ([nts (compiled-lang-lang lang)]
[nt-map (make-hash-table)])
(for-each (lambda (nt) (hash-table-put! nt-map (nt-name nt)
(cons (lambda () 1)
(lambda () +inf.0))))
nts)
(let ([gens (make-hash-table)]
[atomic-alts (lambda (l size)
(values
(lambda (min-size max-size result-k fail-k)
(let loop ([l l][result-k result-k][max-size max-size][fail-k fail-k])
(if (<= min-size size max-size)
(if (null? l)
(fail-k)
(result-k (car l)
size
(lambda (s xs result-k fail-k)
(loop (cdr l) result-k xs fail-k))))
(fail-k))))
(lambda () size)
(lambda () size)))]
[to-do nts])
(letrec ([make-gen/get-size
(lambda (p)
(cond
[(hash-table-get nt-map p (lambda () #f))
=> (lambda (get-sizes)
(values
(lambda (min-size max-size result-k fail-k)
((hash-table-get gens p) min-size max-size result-k fail-k))
(car get-sizes)
(cdr get-sizes)))]
[(eq? 'number p) (atomic-alts nums 1)]
[(eq? 'string p) (atomic-alts strs 1)]
[(eq? 'any p) (atomic-alts (append nums strs vars) 1)]
[(or (eq? 'variable p)
(and (pair? p)
(eq? (car p) 'variable-except)))
(atomic-alts vars 1)]
[(symbol? p) (if (memq p skip-kws)
(values
(lambda (min-size max-size result-k fail-k)
(fail-k))
(lambda () +inf.0)
(lambda () -1))
(atomic-alts (list p) 0))]
[(null? p) (atomic-alts (list null) 0)]
[(and (pair? p)
(or (not (pair? (cdr p)))
(not (eq? '... (cadr p)))))
(make-pair-gen/get-size p cons)]
[(and (pair? p) (pair? (cdr p)) (eq? '... (cadr p)))
(let-values ([(just-rest just-rest-min-size just-rest-max-size)
(make-gen/get-size (cddr p))]
[(both both-min-size both-max-size)
(make-pair-gen/get-size (cons (kleene+ (car p)) (cddr p)) append)])
(values
(lambda (min-size max-size result-k fail-k)
(let loop ([both both][result-k result-k][max-size max-size][fail-k fail-k])
(both min-size max-size
(lambda (v size next-both)
(result-k v size
(lambda (ns xs result-k fail-k)
(loop next-both result-k xs fail-k))))
(lambda ()
(just-rest min-size max-size result-k fail-k)))))
just-rest-min-size
(lambda () +inf.0)))]
[else
(error 'make-gen "unrecognized pattern: ~e" p)]))]
[make-pair-gen/get-size
(lambda (p combiner)
(let*-values ([(first first-min-size first-max-size)
(make-gen/get-size (car p))]
[(rest rest-min-size rest-max-size)
(make-gen/get-size (cdr p))]
[(this-min-size) (let ([v #f])
(lambda ()
(unless v
(set! v (+ (first-min-size)
(rest-min-size))))
v))]
[(this-max-size) (let ([v #f])
(lambda ()
(unless v
(set! v (+ (first-max-size)
(rest-max-size))))
v))])
(values
(cache-small
(lambda (min-size max-size result-k fail-k)
(if (min-size . > . (this-max-size))
(fail-k)
(let rloop ([rest rest][result-k result-k][max-size max-size][fail-k fail-k][failed-size +inf.0])
(if (max-size . < . (this-min-size))
(fail-k)
(rest
(max 0 (- min-size (first-max-size)))
(min (sub1 failed-size) (- max-size (first-min-size)))
(lambda (rest rest-size next-rest)
(if (rest-size . >= . failed-size)
(rloop next-rest result-k max-size fail-k failed-size)
(let floop ([first first]
[result-k result-k]
[max-size max-size]
[fail-k fail-k]
[first-fail-k (lambda ()
(rloop next-rest result-k max-size fail-k rest-size))])
(first (max 0 (- min-size rest-size))
(- max-size rest-size)
(lambda (first first-size next-first)
(result-k
(combiner first rest)
(+ first-size rest-size)
(lambda (ns xs result-k fail-k)
(floop next-first result-k xs fail-k
(lambda ()
(rloop next-rest result-k xs fail-k failed-size))))))
first-fail-k))))
fail-k))))))
this-min-size
this-max-size)))]
[kleene+ (lambda (p)
(let ([n (gensym)])
(hash-table-put! nt-map n (cons (lambda () 1)
(lambda () +inf.0)))
(set! to-do (cons (make-nt
n
(list (make-rhs (cons p '()))
(make-rhs (cons p n))))
to-do))
n))])
(let to-do-loop ([nts (reverse to-do)])
(set! to-do null)
(for-each (lambda (nt)
(hash-table-put!
gens
(nt-name nt)
(let* ([gens+sizes
(map (lambda (rhs)
(let-values ([(gen get-min-size get-max-size)
(make-gen/get-size
(rhs-pattern rhs))])
(cons gen (cons get-min-size get-max-size))))
(nt-rhs nt))]
[get-min-size
(let ([get-min-sizes (map cadr gens+sizes)])
(let ([v #f])
(lambda ()
(unless v
(set! v (add1
(apply min (map (lambda (gs) (gs))
get-min-sizes)))))
v)))]
[get-max-size
(let ([get-max-sizes (map cddr gens+sizes)])
(let ([v #f])
(lambda ()
(unless v
(set! v (add1
(apply max (map (lambda (gs) (gs))
get-max-sizes)))))
v)))])
(hash-table-put! nt-map (nt-name nt)
(cons get-min-size get-max-size))
(cache-small
(lambda (min-size max-size result-k fail-k)
(if (min-size . > . (get-max-size))
(fail-k)
(let loop ([l (map car gens+sizes)][result-k result-k][max-size max-size][fail-k fail-k])
(if (max-size . < . (get-min-size))
(fail-k)
(if (null? l)
(fail-k)
(let iloop ([alt-next (car l)]
[result-k result-k]
[max-size max-size]
[fail-k fail-k])
(alt-next
(max 0 (sub1 min-size))
(sub1 max-size)
(lambda (alt a-size alt-next)
(result-k
alt
(add1 a-size)
(lambda (ns xs result-k fail-k)
(iloop alt-next result-k xs fail-k))))
(lambda ()
(loop (cdr l) result-k max-size fail-k)))))))))))))
nts)
(unless (null? to-do)
(to-do-loop to-do))))
gens)))
(define (for-each-generated/size proc gens min-size max-size nonterm)
(let ([gen (hash-table-get gens nonterm)])
(let loop ([gen gen])
(gen
min-size
max-size
(lambda (val z1 gen-next)
(proc val z1)
(loop gen-next))
void))))
(define (for-each-generated proc gens nonterm)
(let loop ([i 0])
(for-each-generated/size proc gens i i nonterm)
(loop (add1 i)))))