#lang racket
(provide scan-blocks)
(require "forth_read.rkt")
(require "rewrite.rkt")
(require racket/string)
(require racket/function)
(struct block (number code))
(define (add-line old-block line)
(struct-copy block old-block [code (append (block-code old-block) (list line))]))
(define block-syntax "\\{block ([0-9]+)\\}")
(define (is-block? block) (and (regexp-match block-syntax block) #t))
(define (drop-while pred? list)
(cond
[(null? list) '()]
[(pred? (car list)) (drop-while pred? (cdr list))]
[else list]))
(define (scan-blocks lines)
(define (go line blocks)
(let ([num (regexp-match block-syntax line)])
(if num (cons (block (string->number (cadr num)) '()) blocks)
(cons (add-line (car blocks) line) (cdr blocks)))))
(map (compose rewrite-block block-to-port)
(reverse (foldl go '() (drop-while (negate is-block?) lines)))))
(define (block-to-port old-block)
(struct-copy block old-block
[code (open-input-string (string-join (block-code old-block) "\n"))]))
(define (rewrite-block old-block)
(struct-copy block old-block
[code (open-input-string
(string-join (rewrites
(map (lambda (s) (if (char? s) (string s) s))
(read-to-list (block-code old-block)))) " "))]))
(define (slurp file)
(define (go line lines)
(let ([c (read-char file)])
(cond
[(eof-object? c) (cons line lines)]
[(char=? c #\newline) (go "" (cons line lines))]
[else (go (string-append line (string c)) lines)])))
(reverse (go "" '())))