diff --git a/lib/chibi/highlight.module b/lib/chibi/highlight.module
new file mode 100644
index 00000000..ce7762af
--- /dev/null
+++ b/lib/chibi/highlight.module
@@ -0,0 +1,7 @@
+
+(module (chibi highlight)
+ (export highlight highlight-detect-language highlight-style
+ highlight-scheme highlight-c highlight-assembly)
+ (import-immutable (scheme))
+ (import (srfi 1) (chibi io) (chibi ast))
+ (include "highlight.scm"))
diff --git a/lib/chibi/highlight.scm b/lib/chibi/highlight.scm
new file mode 100644
index 00000000..afaf7f89
--- /dev/null
+++ b/lib/chibi/highlight.scm
@@ -0,0 +1,472 @@
+;; highlight.scm -- source code highlighting library
+;; Copyright (c) 2011 Alex Shinn. All rights reserved.
+;; BSD-style license: http://synthcode.com/license.txt
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (string-concatenate-reverse ls)
+ (string-concatenate (reverse ls)))
+
+(define (reverse-list->string ls)
+ (list->string (reverse ls)))
+
+(define (highlight-detect-language str)
+ (cond
+ ((or (string-contains str "(define")
+ (string-contains str "(eval")
+ (string-contains str "(set")
+ (string-contains str "(string")
+ (string-contains str "(let")
+ (string-contains str "(lambda (")
+ )
+ 'scheme)
+ ((string-contains str "\tmovl\t")
+ 'asm)
+ (else
+ 'c)))
+
+(define (highlight source)
+ (let ((str (if (string? source) source (port->string source))))
+ ((case (highlight-detect-language str)
+ ((scheme) highlight-scheme)
+ ((asm) highlight-assembly)
+ ((c) highlight-c))
+ str)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define highlight-themes
+ '((light
+ (keyword . "#800080")
+ (type . "#008000")
+ (function . "#0000FF")
+ (variable . "#B8860B")
+ (comment . "#FF0000")
+ (string . "#BC8F8F")
+ (attribute . "#FF5000")
+ (preprocessor . "#FF00FF")
+ (builtin . "#FF00FF")
+ (character . "#0055AA")
+ (syntaxerror . "#FF0000")
+ (diff-deleted . "#5F2121")
+ (diff-added . "#215F21"))))
+
+(define highlight-paren-styles
+ ;;'("#BAFFFF" "#FFCACA" "#FFFFBA" "#CACAFF" "#CAFFCA" "FFBAFF")
+ '("#AAAAAA" "#888888" "#666666" "#444444" "#222222" "#000000"))
+
+(define (highlight-style . theme)
+ (string-concatenate
+ (append
+ (map
+ (lambda (x)
+ (string-append
+ "." (symbol->string (car x)) " { color: " (cdr x)
+ "; background-color: inherit; }\n"))
+ (cond ((assq (and (pair? theme) (car theme)) highlight-themes) => cdr)
+ (else (cdar highlight-themes))))
+ (map
+ (lambda (s i)
+ (string-append
+ ;;"span.paren" (number->string i)
+ ;;":hover { color: inherit; background-color: " s "; }\n"
+ "span.paren" (number->string i)
+ " { color: " s "; background-color: inherit; }\n"))
+ highlight-paren-styles
+ (cdr (iota (+ 1 (length highlight-paren-styles)))))
+ )))
+
+(define (highlight-start class out)
+ (display "" out))
+
+(define (highlight-end class out)
+ (display "" out))
+
+(define (highlight-class class str out)
+ (highlight-start class out)
+ (display str out)
+ (highlight-end class out))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (read-whitespace in)
+ (let lp ((res '()))
+ (if (char-whitespace? (peek-char in))
+ (lp (cons (read-char in) res))
+ (reverse-list->string res))))
+
+(define (read-to-whitespace in res)
+ (cond
+ ((char-whitespace? (peek-char in))
+ (reverse-list->string res))
+ (else
+ (read-to-whitespace in (cons (read-char in) res)))))
+
+(define (read-escaped in term ls)
+ (let ((c (read-char in)))
+ (cond
+ ((eof-object? c) (reverse-list->string ls))
+ ((eqv? c term) (reverse-list->string (cons c ls)))
+ ((eqv? c #\<) (read-escaped in term `(#\; #\t #\l #\& ,@ls)))
+ ;;((eqv? c #\>) (read-escaped in term `(#\; #\t #\g #\& ,@ls)))
+ ((eqv? c #\&) (read-escaped in term `(#\; #\p #\m #\a #\& ,@ls)))
+ ;;((eqv? c #\\) (read-escaped in term (cons (read-char in) (cons c ls))))
+ (else (read-escaped in term (cons c ls))))))
+
+(define (html-escape str)
+ (call-with-input-string str (lambda (in) (read-escaped in #f '()))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (highlight-scheme-delimiter? ch)
+ (or (eof-object? ch)
+ (char-whitespace? ch)
+ (memq ch '(#\; #\# #\( #\) #\[ #\] #\{ #\} #\' #\` #\, #\"))))
+
+(define (highlight-scheme-definition? id)
+ (memq id '(define define-syntax define-module define-class
+ define-record define-record-type)))
+
+(define (highlight-scheme-syntax? id)
+ (memq id '(if lambda define set! cond case let let* letrec letrec*
+ let-values let-values* let-optionals let-optionals*
+ let-keywords let-keywords* and-let* rec receive do
+ loop rxmatch-cond rxmatch-case begin when unless
+ match match-lambda match-let match-let* dotimes dolist
+ quote quasiquote unquote unquote-splicing error errorf
+ define-syntax let-syntax letrec-syntax syntax-rules
+ syntax-case parameterize module library require
+ require-extension use use-modules import export
+ define-module select-module provide autoload
+ condition-case guard cond-expand for with to by
+ in-list in-lists in-string in-string-reverse
+ in-vector in-vector-reverse in-file listing appending
+ summing multpliying up-from down-from else
+ )))
+
+(define (highlight-scheme source)
+ (let ((in (if (string? source) (open-input-string source) source)))
+ (call-with-output-string
+ (lambda (out)
+ (define (read-to-eol ls)
+ (let ((c (read-char in)))
+ (cond
+ ((eof-object? c) (reverse-list->string ls))
+ ((eqv? c #\newline) (reverse-list->string (cons c ls)))
+ (else (read-to-eol (cons c ls))))))
+ (define (read-identifier ls)
+ (let ((c (peek-char in)))
+ (cond
+ ((highlight-scheme-delimiter? c)
+ (string->symbol (reverse-list->string ls)))
+ (else
+ (read-char in)
+ (read-identifier (cons c ls))))))
+ (define (hash-mark n)
+ (let ((c (read-char in)))
+ (case c
+ ((#\;)
+ (highlight-start 'comment out)
+ (highlight n)
+ (highlight-end 'comment out))
+ ((#\\)
+ (let ((id (read-identifier (list (read-char in) #\\ #\#))))
+ (highlight-class 'string id out)
+ (highlight n)))
+ (else
+ (write-char #\# out)
+ (write-char c out)
+ (highlight n)))))
+ (define (highlight n)
+ (let ((c (read-char in)))
+ (if (eof-object? c)
+ #f
+ (case c
+ ((#\;)
+ (let lp ((ls '()))
+ (let ((ls (cons (read-to-eol (list #\;)) ls)))
+ (cond
+ ((eqv? #\; (peek-char in))
+ (lp ls))
+ (else
+ (highlight-class 'comment
+ (string-concatenate-reverse ls)
+ out)
+ (highlight n))))))
+ ((#\")
+ (let ((str (read-escaped in #\" (list #\"))))
+ (highlight-class 'string str out)
+ (highlight n)))
+ ((#\()
+ ;;(highlight-start
+ ;; (string->symbol
+ ;; (string-append
+ ;; "paren"
+ ;; (number->string
+ ;; (+ 1 (modulo n (length highlight-paren-styles))))))
+ ;;out)
+ (write-char #\( out)
+ (if (highlight-scheme-delimiter? (peek-char in))
+ (highlight (+ n 1))
+ (let ((id (read-identifier '())))
+ (cond
+ ((highlight-scheme-definition? id)
+ (highlight-class 'keyword id out)
+ (display (read-whitespace in) out)
+ (if (eqv? #\( (peek-char in))
+ (write-char (read-char in) out))
+ (highlight-class 'function (read-identifier '()) out)
+ (highlight (+ n 1)))
+ ((highlight-scheme-syntax? id)
+ (highlight-class 'keyword id out)
+ (highlight (+ n 1)))
+ (else
+ (display "" out)
+ (display id out)
+ (display "" out)
+ (highlight (+ n 1)))))))
+ ((#\))
+ (cond
+ ((zero? n)
+ (highlight-class 'syntaxerror c out)
+ (highlight n))
+ (else
+ (write-char c out)
+ ;;(highlight-end 'paren out)
+ (highlight (- n 1)))))
+ ((#\#)
+ (hash-mark n))
+ ((#\<)
+ (display "<" out)
+ (highlight n))
+ ((#\&)
+ (display "&" out)
+ (highlight n))
+ ;;((#\newline)
+ ;; (write-char c out)
+ ;; (highlight 0))
+ (else
+ (cond
+ ((highlight-scheme-delimiter? c)
+ (write-char c out)
+ (highlight n))
+ (else
+ (let ((id (read-identifier (list c))))
+ (display "")
+ (display id out)
+ (display "")
+ (highlight n)))))))))
+ (highlight 0)))))
+
+(define (highlight-c-keyword? id)
+ (memq id '(asm break case catch const_cast continue default delete
+ do dynamic_cast else explicit export false for friend goto
+ if mutable namespace new operator private protected public
+ register reinterpret_cast return sizeof static_cast switch
+ template this throw true try typedef typeid typename using
+ virtual while)))
+
+(define (highlight-c-type? id)
+ (memq id '(auto bool char class const double enum extern float inline int long
+ short signed static struct union unsigned void volatile wchar_t)))
+
+(define (highlight-c source)
+ (let ((in (if (string? source) (open-input-string source) source)))
+ (call-with-output-string
+ (lambda (out)
+ (define (read-to-eol ls)
+ (let ((c (read-char in)))
+ (cond
+ ((eof-object? c) (reverse-list->string ls))
+ ((eqv? c #\newline) (reverse-list->string (cons c ls)))
+ (else (read-to-eol (cons c ls))))))
+ (define (char-c-initial? c)
+ (and (char? c) (or (char-alphabetic? c) (eqv? c #\_) (eqv? c #\$))))
+ (define (char-c-identifier? c)
+ (and (char? c) (or (char-c-initial? c) (char-numeric? c))))
+ (define (read-identifier ls)
+ (let ((c (peek-char in)))
+ (if (char-c-identifier? c)
+ (read-identifier (cons (read-char in) ls))
+ (string->symbol (reverse-list->string ls)))))
+ (define (write-identifier id)
+ (cond
+ ((highlight-c-keyword? id)
+ (highlight-class 'keyword id out))
+ ((highlight-c-type? id)
+ (highlight-class 'type id out))
+ (else
+ (display id out))))
+ (define (highlight-line)
+ (cond
+ ((eqv? #\# (peek-char in))
+ (highlight-start 'preprocessor out)
+ (write-char (read-char in) out)
+ (display (read-whitespace in) out)
+ (let ((id (read-identifier '())))
+ (display id out)
+ (highlight-end 'preprocessor out)
+ (display (read-whitespace in) out)
+ (cond
+ ((eq? 'define id)
+ (highlight-class
+ 'function
+ (html-escape (read-to-whitespace in '()))
+ out))
+ ((memq id '(include import))
+ (highlight-class
+ 'string
+ (html-escape (read-to-whitespace in '()))
+ out)))))
+ ((char-c-initial? (peek-char in))
+ ;; line beginning w/ an identifier is probably a
+ ;; function declaration
+ (let ((id1 (read-identifier '())))
+ (cond
+ ((eqv? #\: (peek-char in))
+ (highlight-class 'function id1 out))
+ (else
+ (let lp ((decls '())
+ (id id1))
+ (let ((space (read-whitespace in)))
+ (cond
+ ((char-c-initial? (peek-char in))
+ (lp (cons space (cons id decls))
+ (read-identifier '())))
+ ((eqv? #\( (peek-char in))
+ (highlight-start 'type out)
+ (for-each (lambda (x) (display x out))
+ (reverse decls))
+ (highlight-end 'type out)
+ (highlight-start 'function out)
+ (display id out)
+ (highlight-end 'function out)
+ (display space out))
+ (else
+ (for-each write-identifier (reverse decls))
+ (display id out)
+ (display space out))))))))))
+ (highlight))
+ (define (highlight)
+ (let ((c (read-char in)))
+ (if (eof-object? c)
+ #f
+ (case c
+ ((#\/)
+ (case (peek-char in)
+ ((#\/)
+ (highlight-start 'comment out)
+ (write-char c out)
+ (display (read-to-eol '()) out)
+ (highlight-end 'comment out)
+ (newline out)
+ (highlight))
+ ((#\*)
+ (highlight-start 'comment out)
+ (write-char c out)
+ (write-char (read-char in) out)
+ (let ((prev (read-char in)))
+ (write-char prev out)
+ (let lp ((prev prev))
+ (let ((c (read-char in)))
+ (write-char c out)
+ (if (not (and (eqv? prev #\*) (eqv? c #\/)))
+ (lp c)
+ #f))))
+ (highlight-end 'comment out)
+ (highlight))
+ (else
+ (write-char c out)
+ (highlight))))
+ ((#\" #\')
+ (let ((str (read-escaped in c (list c))))
+ (highlight-class 'string str out)
+ (highlight)))
+ ((#\newline)
+ (newline out)
+ (highlight-line))
+ ((#\<)
+ (display "<" out)
+ (highlight))
+ ((#\&)
+ (display "&" out)
+ (highlight))
+ (else
+ (cond
+ ((char-c-initial? c)
+ (let ((id (read-identifier (list c))))
+ (if (eqv? #\: (peek-char in))
+ (highlight-class 'function id out)
+ (write-identifier id))))
+ (else
+ (write-char c out)))
+ (highlight))))))
+ (highlight-line)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (highlight-assembly source)
+ (let ((in (if (string? source) (open-input-string source) source)))
+ (call-with-output-string
+ (lambda (out)
+ (define (read-to-eol ls)
+ (let ((c (read-char in)))
+ (cond
+ ((eof-object? c) (reverse-list->string ls))
+ ((eqv? c #\newline) (reverse-list->string (cons c ls)))
+ (else (read-to-eol (cons c ls))))))
+ (define (char-asm-initial? c)
+ (and (char? c) (or (char-alphabetic? c) (memv c '(#\_ #\$ #\.)))))
+ (define (char-asm-identifier? c)
+ (and (char? c) (or (char-asm-initial? c) (char-numeric? c))))
+ (define (read-identifier ls)
+ (let ((c (peek-char in)))
+ (if (char-asm-identifier? c)
+ (read-identifier (cons (read-char in) ls))
+ (string->symbol (reverse-list->string ls)))))
+ (define (highlight)
+ (let ((c (read-char in)))
+ (cond
+ ((eof-object? c))
+ (else
+ (case c
+ ((#\newline)
+ (write-char c out)
+ (line))
+ ((#\")
+ (let ((str (read-escaped in c (list c))))
+ (highlight-class 'string str out)
+ (highlight)))
+ ((#\%)
+ (highlight-class 'variable (read-identifier (list c)) out)
+ (highlight))
+ ((#\;)
+ (highlight-class 'comment (read-to-eol (list c)) out)
+ (highlight))
+ ((#\<)
+ (display "<" out)
+ (highlight))
+ ((#\&)
+ (display "&" out)
+ (highlight))
+ (else
+ (write-char c out)
+ (highlight)))))))
+ (define (line)
+ (cond
+ ((eof-object? (peek-char in)))
+ ((char-asm-initial? (peek-char in))
+ (let ((id (read-identifier '())))
+ (if (eqv? #\: (peek-char in))
+ (highlight-class 'function id out)
+ (highlight-class 'keyword id out))
+ (highlight)))
+ ((eqv? #\tab (peek-char in))
+ (write-char (read-char in) out)
+ (highlight-class 'keyword (read-identifier '()) out)
+ (highlight))
+ (else
+ (highlight))))
+ (line)))))