#! /usr/local/bin/guile \ -e main -s !# ;; ;; eguile - embedding guile codes into a text file. ;; by Satoru Takabayashi ;; ;; % cat foo.txt ;; 1 + 2 = [(+ 1 2)] ;; ;; % eguile < foo.txt ;; 1 + 2 = 3 ;; (use-modules (ice-9 regex)) (define (string-join delim items) (if (null? items) "" (let loop ((result '()) (items items)) (if (null? items) (apply string-append (reverse! (cdr result))) (loop (cons delim (cons (car items) result)) (cdr items)))))) (define-public (filter predicate sequence) (cond ((null? sequence) '()) ((predicate (car sequence)) (cons (car sequence) (filter predicate (cdr sequence)))) (else (filter predicate (cdr sequence))))) (define (read-port port) (let loop ((content '())) (let ((line (car (%read-line port)))) (if (eof-object? line) (begin (close-port port) (reverse! content)) (loop (cons line content)))))) (define (read-file file-name) (read-port (open-file file-name "r"))) (define (eguile input-file) (define (scheme-start contents) (let ((m (string-match "([^[]|\\\\\\[)+" contents))) (cond ((string-null? contents) #f) ((eq? (string-ref contents 0) #\[) 0) ((and m (< (match:end m) (string-length contents))) (match:end m)) (else #f)))) (define (scheme-end contents start) (let ((m (string-match "([^]]|\\\\])+" (substring contents start)))) (if (and m (< (+ start (match:end m)) (string-length contents))) (+ start (match:end m)) (error "Unmatched bracket in" input-file)))) (define (eval-string-display string) (let ((val (eval-string string))) (if (not (eq? val *unspecified*)) (display val)))) (define (unescape string) (let loop ((string string) (result "")) (let ((pos (string-index string #\\))) (if pos (loop (substring string (1+ pos)) (string-append result (substring string 0 pos))) (string-append result string))))) (let loop ((contents (string-join "\n" (read-file input-file)))) (let ((start (scheme-start contents))) (if start (let* ((end (scheme-end contents start)) (preceded-string (substring contents 0 start))) (display (unescape preceded-string)) (eval-string-display (substring contents (1+ start) end)) (loop (substring contents (1+ end)))) (display (unescape contents))))) (newline)) (define (usage) (display "Usage: eguile ") (newline)) (define (main args) (if (not (= (length args) 2)) (usage) (eguile (cadr args))))