;; ncompile v180819b ;; usage: ;; (ncompile-file "foo.m") ;; first checks for first line of the form ;; #lang ;; then uses file ending ".m" => nx-matlab (define-module (ncompile) #:export (ncompile-file) ) (define (lang-from-port port) (define (release chl) (let loop ((chl chl)) (unless (null? chl) (unread-char (car chl) port) (loop (cdr chl)))) #f) (define (return chl) (string->symbol (reverse-list->string chl))) (let loop ((cl '()) (st 0) (kl '(#\# #\l #\a #\n #\g)) (ch (read-char port))) (case st ((0) (cond ; read `#lang' ((eof-object? ch) (release cl)) ((null? kl) (loop cl 1 kl ch)) ((char=? ch (car kl)) (loop (cons ch cl) st (cdr kl) (read-char port))) (else (release (cons ch cl))))) ((1) (cond ; skip spaces ((eof-object? ch) (release cl)) ((char=? ch #\space) (loop (cons ch cl) st kl (read-char port))) (else (loop cl 2 '() ch)))) ((2) (cond ; collect lang name ((eof-object? ch) (return kl)) ((char=? ch #\newline) (return kl)) ((char-whitespace? ch) (loop cl 3 kl ch)) (else (loop cl st (cons ch kl) (read-char port))))) ((3) (cond ((eof-object? ch) (return kl)) ((char=? ch #\newline) (return kl)) (else (loop cl st kl (read-char port)))))))) (define %file-extension-map '(("scm" . scheme) ("el" . elisp) ("m" . nx-matlab) ("js" . ecmascript))) (define* (lang-from-file file) (let* ((ix (string-rindex file #\.)) (ext (and ix (substring file (1+ ix))))) (and ext (assoc-ref %file-extension-map ext)))) (define call-with-output-file/atomic (@@ (system base compile) call-with-output-file/atomic)) (define language-printer (@ (system base language) language-printer)) (define ensure-language (@@ (system base compile) ensure-language)) (define ensure-directory (@@ (system base compile) ensure-directory)) (define read-and-compile (@@ (system base compile) read-and-compile)) (define compiled-file-name (@@ (system base compile) compiled-file-name)) (define default-environment (@@ (system base compile) default-environment)) (define* (ncompile-file file #:key (output-file #f) (from #f) (to 'bytecode) (env #f) (opts '()) (canonicalization 'relative)) (with-fluids ((%file-port-name-canonicalization canonicalization)) (let* ((comp (or output-file (compiled-file-name file) (error "failed to create path for auto-compiled file" file))) (in (open-input-file file)) (enc (file-encoding in))) ;; Choose the input encoding deterministically. (set-port-encoding! in (or enc "UTF-8")) (ensure-directory (dirname comp)) (call-with-output-file/atomic comp (lambda (port) (let* ((from (or from (lang-from-port in) (lang-from-file file) (current-language))) (env (or env (default-environment from)))) (simple-format (current-error-port) "compiling from lang ~A\n" from) ((language-printer (ensure-language to)) (read-and-compile in #:env env #:from from #:to to #:opts (cons* #:to-file? #t opts)) port))) file) comp))) ;; Local Variables: ;; eval: (put 'call-with-output-file/atomic 'scheme-indent-function 1) ;; End: ;; --- last line ---