sfx.scm added by amk9 on Thu Aug 15 17:11:02 2013

(define-module (sfx)
  #:use-module (ice-9 receive)
  #:use-module (oop goops describe)
  #:use-module (skribilo reader skribe))

;; debug

(define (debug procedure text)
  (display "debug,  ")
  (display procedure)
  (display ": ")
  (display text)
  (newline))

;;

(define (warning text)
  (format #t "warning: ~a " text)
  (newline))


(define (file->sexpr file)
  (define reader (make-skribe-reader))
  (reader (open-input-file file)))


;; dispatch table for consumers

(define consumers (make-hash-table))

(define (consumer-get symbol)
  (hash-ref consumers (string->symbol (string-append "consume-" (symbol->string symbol)))))

(define (consumer-set! procedure)
  (hash-set! consumers (procedure-name procedure) procedure))

;; dispatch table for rewriter

(define rewriters (make-hash-table))

(define (rewriter-get symbol)
  (hash-ref rewriters (string->symbol (string-append "rewrite-" (symbol->string symbol)))))

(define (rewriter-set! procedure)
  (hash-set! rewriters (procedure-name procedure) procedure))

;; consumers

(define (consume-keywords sexpr keywords)
  (cond ((null? sexpr) sexpr)
	((keyword? (car sexpr))
	 (hash-set! keywords (keyword->symbol (car sexpr)) (cadr sexpr))
	 (consume-keywords (cddr sexpr) keywords))
	(else sexpr)))

(define (consume-node name environment output sexpr continue)
  (let* ((keywords (make-hash-table))
	 (body (consume-keywords sexpr keywords))
	 (id (hash-ref keywords `id))
	 (classes (hash-ref keywords `classes))
	 (href (hash-ref keywords `href)))
    (output (format #f "<~a" name))
    (if id (output (format #f " id=~s" (symbol->string id))))
    (if classes (output (format #f " class=~s" classes)))
    (if href (output (format #f " href=~s" href)))
    (output ">")
    (continue environment output body)
    (output (format #f "" name))))


(define (consume-simple-node name environment output sexpr continue)
  (let ((keywords (make-hash-table)))
    (consume-keywords sexpr keywords)
    (output (format #f "<~a " name))
    (hash-for-each (lambda (key value) (output (format #f "~a=~s " (symbol->string key) value)))  keywords)
    (output "/>")))

(define (consume-sexpr environment output sexpr)
  (cond ((null? sexpr))
	((and (symbol? (car sexpr)) (consumer-get (car sexpr))) ((consumer-get (car sexpr)) environment output (cdr sexpr)))
	((and (symbol? (car sexpr)) (rewriter-get (car sexpr)))  (consume-sexpr environment output ((rewriter-get (car sexpr)) environment (cdr sexpr))))
	((list? (car sexpr)) (consume-sexpr environment output (car sexpr)) (consume-sexpr environment output (cdr sexpr)))
	((equal? `quasiquote (car sexpr)) (consume-sexpr environment output (cdr sexpr)))
	((equal? `unquote (car sexpr)) (consume-sexpr environment output (cdr sexpr)))
	((string? (car sexpr)) (output (car sexpr)) (consume-sexpr environment output (cdr sexpr)))))

(define (quote environment output sexpr)
  (consume-node "cite" environment output sexpr consume-sexpr))
(consumer-set! quote)

(define (consume-division environment output sexpr)
  (consume-node "div" environment output sexpr consume-sexpr))
(consumer-set! consume-division)

(define (consume-ordered-list environment output sexpr)
  (consume-node "ol" environment output sexpr consume-sexpr))
(consumer-set! consume-ordered-list)

(define (consume-list environment output sexpr)
  (consume-node "ul" environment output sexpr consume-sexpr))
(consumer-set! consume-list)
  
(define (consume-item environment output sexpr)
  (consume-node "li" environment output sexpr consume-sexpr))
(consumer-set! consume-item)

(define (consume-link environment output sexpr)
  (let* ((keywords (make-hash-table))
	 (body (consume-keywords sexpr keywords))
	 (id (hash-ref keywords `id))
	 (classes (hash-ref keywords `classes))
	 (href (hash-ref keywords `href))
	 (name "a"))
    (output (format #f "<~a" name))
    (if id (output (format #f " id=~s" (symbol->string id))))
    (if classes (output (format #f " class=~s" classes)))
    (if (and href (string-suffix? ".sfx" href))
	(let* ((basename (car (string-split href #\.)))
	       (output-name (string-append basename ".html")))
	  (consume href)
	  (output (format #f " href=~s" output-name)))
	(if href (output (format #f " href=~s" href))))
    (output ">")
    (consume-sexpr environment output body)
    (output (format #f "" name))))

(consumer-set! consume-link)

(define (consume-bold environment output sexpr)
  (consume-node "bold" environment output sexpr consume-sexpr))
(consumer-set! consume-bold)

(define (consume-span environment output sexpr)
  (consume-node "span" environment output sexpr consume-sexpr))
(consumer-set! consume-span)

(define (consume-italic environment output sexpr)
  (consume-node "i" environment output sexpr consume-sexpr))
(consumer-set! consume-italic)

(define (consume-paragraph environment output sexpr)
  (consume-node "p" environment output sexpr consume-sexpr))
(consumer-set! consume-paragraph)

(define (consume-title environment output sexpr)
  (consume-node "h1" environment output sexpr consume-sexpr))
(consumer-set! consume-title)

(define (consume-subtitle environment output sexpr)
  (consume-node "h2" environment output sexpr consume-sexpr))
(consumer-set! consume-subtitle)

(define (consume-subsubtitle environment output sexpr)
  (consume-node "h3" environment output sexpr consume-sexpr))
(consumer-set! consume-subsubtitle)

(define (consume-subsubsubtitle environment output sexpr)
  (consume-node "h4" environment output sexpr consume-sexpr))
(consumer-set! consume-subsubsubtitle)

(define (consume-html environment output sexpr)
  (output "")
  (consume-node "html" environment output sexpr consume-sexpr))
(consumer-set! consume-html)

(define (consume-head environment output sexpr)
  (consume-node "head" environment output sexpr consume-sexpr))
(consumer-set! consume-head)

(define (consume-body environment output sexpr)
  (consume-node "body" environment output sexpr consume-sexpr))
(consumer-set! consume-body)

(define (consume-super-title environment output sexpr)
  (consume-node "title" environment output sexpr consume-sexpr))
(consumer-set! consume-super-title)

(define (consume-super-link environment output sexpr)
  (consume-simple-node "link" environment output sexpr consume-sexpr))
(consumer-set! consume-super-link)

(define (consume-meta environment output sexpr)
  (consume-simple-node "meta" environment output sexpr consume-sexpr))
(consumer-set! consume-meta)

(define (consume-html-document environment output sexpr)
  (let* ((keywords (make-hash-table))
	 (body (consume-keywords sexpr keywords))
	 (title (hash-ref keywords `title))
	 (style (hash-ref keywords `style)))
    (output "")
    (if title (output (format #f "~a" title)))
    (if style (output (format #f "" style)))
    (output "")
    (output "")
    (if body (consume-sexpr environment output body))
    (output "")))
(consumer-set! consume-html-document)


(define (consume-template environment output sexpr)
  (let* ((keywords (make-hash-table))
	(body (consume-keywords sexpr keywords)))
    (consume-sexpr environment output body)
    (cond ((hash-ref keywords `extends)
	   (consume-sexpr environment output (file->sexpr (hash-ref keywords `extends)))))))
(consumer-set! consume-template)

(define (consume-define environment output sexpr)
  (hash-set! environment (car sexpr) (cadr sexpr)))
(consumer-set! consume-define)

(define (rewrite-for-rec symbol values code sexpr)
  (cond ((null? values) sexpr)
	(else
	 (rewrite-for-rec symbol 
			  (cdr values) 
			  code 
			  (cons sexpr 
				(quasiquote ((define ,symbol ,(car values)) ,code)))))))

(define (rewrite-for environment sexpr)
  (let ((symbol (car sexpr))
	(value (cadr sexpr))
	(code (caddr sexpr)))
    (rewrite-for-rec symbol (if (symbol? value) (hash-ref environment value) value) code (list))))
(rewriter-set! rewrite-for)

(define (consume-display environment output sexpr)
  (let ((value (hash-ref environment (car sexpr))))
    (output (if value value (format #f "{{ ~a }}" (symbol->string (car sexpr)))))))
(consumer-set! consume-display)

(define (rewrite-consume environment sexpr)
  (hash-ref environment (car sexpr)))
(rewriter-set! rewrite-consume)

(define (consume filename)
  (display (format #f "processing ~s\n" filename))
  (let* ((basename (car (string-split filename #\.)))
	 (output-file (open-output-file (string-append basename ".html")))
	 (output (lambda (text) (display text output-file)))
	 (sexpr (file->sexpr filename))
	 (environment (make-hash-table)))
    (consume-sexpr environment output sexpr)
    (close output-file)))

(consume "index.sfx")