summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2008-11-14 22:42:31 +0100
committerAndy Wingo <wingo@pobox.com>2008-11-14 22:42:31 +0100
commitb0b180d5227d76f5ca1e2f48b06f6d45195bd1f8 (patch)
treec4402c9e04ec35d4e22092cc829b6cbddaa383eb
parent7493339cfc36cf95b77aa8a1ad4cd0b5dd36710a (diff)
downloadguile-b0b180d5227d76f5ca1e2f48b06f6d45195bd1f8.tar.gz
nifty generic compiler infrastructure -- no more hardcoded passes
* module/system/base/language.scm (<language>): Rework so that instead of hardcoding passes in the language, we define compilers that translate from one language to another. Add `parser' to the language fields, a bit of a hack but useful for languages with s-expression external representations but with record internal representations. (define-language, *compilation-cache*, invalidate-compilation-cache!) (compute-compilation-order, lookup-compilation-order): Add an algorithm that does a depth-first search for a translation path from a source language to a target language, caching the result in a lookup table. * module/language/scheme/spec.scm: * module/language/ghil/spec.scm: Update to the new language format. * module/language/glil/spec.scm: Add a language specification for GLIL, with a compiler to objcode. Also there are parsers and printers, for repl usage, but for some reason this doesn't work yet. * module/language/objcode/spec.scm: Define a language specification for object code. There is some sleight of hand here, in the "compiler" to values; but there is method behind the madness, because this way we higher levels can pass environments (a module + externals pair) to objcode->program. * module/language/value/spec.scm: Define a language specification for values. There is something intellectually dishonest about this, but it does serve its purpose as a foundation for the language hierarchy. * configure.in: * module/language/Makefile.am * module/language/ghil/Makefile.am * module/language/glil/Makefile.am * module/language/objcode/Makefile.am * module/language/value/Makefile.am: Autotomfoolery for the ghil, glil, objcode, and value languages. * module/language/scheme/translate.scm (translate): Import the bits that understand `compile-time-environment' here, and pass on the relevant portions of the environment to the next compiler pass. * module/system/base/compile.scm (current-language): New procedure, refs the current language fluid, or lazily sets it to scheme. (call-once, call-with-output-file/atomic): Refactor these bits to use with-throw-handler. No functional change. (compile-file, compile-and-load, compile-passes, compile-fold) (compile): Refactor the public interface of the compiler to be generic and simple. Uses `lookup-compilation-order' to find a path from the source language to the target language. * module/system/base/syntax.scm (define-type): Adapt to changes in define-record. (define-record): Instead of expecting all slots in the first form, expect them in the body, and let the first form hold the options. * module/system/il/compile.scm (compile): Adapt to the compilation pass API (three in and two out). * module/system/il/ghil.scm (<ghil-var>, <ghil-env>) (<ghil-toplevel-env>): Adapt to define-record changes. * module/system/il/glil.scm (<glil-vars>): Adapt to define-record changes. (<glil>, print-glil): Add a GLIL record printer that uses unparse. (parse-glil, unparse-glil): Update unparse (formerly known as pprint), and write a parse function. * module/system/repl/common.scm (<repl>): Adapt to define-record changes. (repl-parse): New function, parses the read form using the current language. Something of a hack. (repl-compile): Adapt to changes in `compile'. (repl-eval): Fix up the does-the-language-have-a-compiler check for changes in <language>. * module/system/repl/repl.scm (start-repl): Parse the form before eval. * module/system/repl/command.scm (describe): Parse. (compile): Be more generic. (compile-file): Adapt to changes in compile-file. (disassemble, time, profile, trace): Parse. * module/system/vm/debug.scm: * module/system/vm/assemble.scm: Adapt to define-record changes. * module/language/scheme/translate.scm (receive): Fix an important bug that gave `receive' letrec semantics instead of let semantics. Whoops!
-rw-r--r--configure.in4
-rw-r--r--module/language/Makefile.am2
-rw-r--r--module/language/ghil/Makefile.am3
-rw-r--r--module/language/ghil/spec.scm9
-rw-r--r--module/language/glil/Makefile.am3
-rw-r--r--module/language/glil/spec.scm48
-rw-r--r--module/language/objcode/Makefile.am3
-rw-r--r--module/language/objcode/spec.scm52
-rw-r--r--module/language/scheme/spec.scm5
-rw-r--r--module/language/scheme/translate.scm52
-rw-r--r--module/language/value/Makefile.am3
-rw-r--r--module/language/value/spec.scm31
-rw-r--r--module/oop/goops.scm6
-rw-r--r--module/oop/goops/compile.scm2
-rw-r--r--module/system/base/compile.scm222
-rw-r--r--module/system/base/language.scm50
-rw-r--r--module/system/base/syntax.scm14
-rw-r--r--module/system/il/compile.scm5
-rw-r--r--module/system/il/ghil.scm6
-rw-r--r--module/system/il/glil.scm167
-rw-r--r--module/system/repl/command.scm23
-rw-r--r--module/system/repl/common.scm26
-rw-r--r--module/system/repl/repl.scm3
-rw-r--r--module/system/vm/assemble.scm12
-rw-r--r--module/system/vm/debug.scm2
-rw-r--r--test-suite/tests/compiler.test8
-rw-r--r--testsuite/run-vm-tests.scm7
27 files changed, 422 insertions, 346 deletions
diff --git a/configure.in b/configure.in
index 881a472a1..8008d800c 100644
--- a/configure.in
+++ b/configure.in
@@ -1557,6 +1557,10 @@ AC_CONFIG_FILES([
module/system/repl/Makefile
module/language/Makefile
module/language/scheme/Makefile
+ module/language/ghil/Makefile
+ module/language/glil/Makefile
+ module/language/objcode/Makefile
+ module/language/value/Makefile
module/ice-9/Makefile
module/ice-9/debugger/Makefile
module/ice-9/debugging/Makefile
diff --git a/module/language/Makefile.am b/module/language/Makefile.am
index 2e97652fc..f31a648d3 100644
--- a/module/language/Makefile.am
+++ b/module/language/Makefile.am
@@ -1 +1 @@
-SUBDIRS=scheme
+SUBDIRS=scheme ghil glil objcode value
diff --git a/module/language/ghil/Makefile.am b/module/language/ghil/Makefile.am
new file mode 100644
index 000000000..07cea2d93
--- /dev/null
+++ b/module/language/ghil/Makefile.am
@@ -0,0 +1,3 @@
+SOURCES = spec.scm
+modpath = language/ghil
+include $(top_srcdir)/am/guilec
diff --git a/module/language/ghil/spec.scm b/module/language/ghil/spec.scm
index 6e07f0265..d40945d6d 100644
--- a/module/language/ghil/spec.scm
+++ b/module/language/ghil/spec.scm
@@ -21,14 +21,16 @@
(define-module (language ghil spec)
#:use-module (system base language)
+ #:use-module (language glil spec)
#:use-module (system il ghil)
+ #:use-module ((system il compile) #:select ((compile . compile-il)))
#:export (ghil))
(define (write-ghil exp . port)
(apply write (unparse-ghil exp) port))
-(define (translate x e)
- (call-with-ghil-environment e '()
+(define (parse x)
+ (call-with-ghil-environment (make-ghil-toplevel-env e) '()
(lambda (env vars)
(make-ghil-lambda env #f vars #f '() (parse-ghil env x)))))
@@ -37,5 +39,6 @@
#:version "0.3"
#:reader read
#:printer write-ghil
- #:translator translate
+ #:parser parse
+ #:compilers `((,glil . ,compile-il))
)
diff --git a/module/language/glil/Makefile.am b/module/language/glil/Makefile.am
new file mode 100644
index 000000000..080bfc15a
--- /dev/null
+++ b/module/language/glil/Makefile.am
@@ -0,0 +1,3 @@
+SOURCES = spec.scm
+modpath = language/glil
+include $(top_srcdir)/am/guilec
diff --git a/module/language/glil/spec.scm b/module/language/glil/spec.scm
new file mode 100644
index 000000000..6d54bc059
--- /dev/null
+++ b/module/language/glil/spec.scm
@@ -0,0 +1,48 @@
+;;; Guile Lowlevel Intermediate Language
+
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(define-module (language glil spec)
+ #:use-module (system base language)
+ #:use-module (language objcode spec)
+ #:use-module (system il glil)
+ #:use-module (system vm assemble)
+ #:export (glil))
+
+(define (write-glil exp . port)
+ (apply write (unparse-glil exp) port))
+
+(define (translate x)
+ ;; Don't wrap in a thunk -- if you're down in these weeds you can
+ ;; thunk it yourself. We don't know how many locs there will be,
+ ;; anyway.
+ (parse-glil x))
+
+(define (compile x e opts)
+ (values (assemble x e) e))
+
+(define-language glil
+ #:title "Guile Lowlevel Intermediate Language (GLIL)"
+ #:version "0.3"
+ #:reader read
+ #:printer write-glil
+ #:parser translate
+ #:compilers `((,objcode . ,compile))
+ )
diff --git a/module/language/objcode/Makefile.am b/module/language/objcode/Makefile.am
new file mode 100644
index 000000000..6d81c41c1
--- /dev/null
+++ b/module/language/objcode/Makefile.am
@@ -0,0 +1,3 @@
+SOURCES = spec.scm
+modpath = language/objcode
+include $(top_srcdir)/am/guilec
diff --git a/module/language/objcode/spec.scm b/module/language/objcode/spec.scm
new file mode 100644
index 000000000..5e0ae3cc3
--- /dev/null
+++ b/module/language/objcode/spec.scm
@@ -0,0 +1,52 @@
+;;; Guile Lowlevel Intermediate Language
+
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(define-module (language objcode spec)
+ #:use-module (system base language)
+ #:use-module (language value spec)
+ #:use-module (system vm objcode)
+ #:export (objcode make-objcode-env))
+
+(define (make-objcode-env module externals)
+ (cons module externals))
+
+(define (objcode-env-module env)
+ (if env (car env) (current-module)))
+
+(define (objcode-env-externals env)
+ (if env (cdr env) '()))
+
+(define (objcode->value x e opts)
+ (let ((thunk (objcode->program x (objcode-env-externals e))))
+ (if e
+ (save-module-excursion
+ (lambda ()
+ (set-current-module (objcode-env-module e))
+ (values (thunk) #f)))
+ (values (thunk) #f))))
+
+(define-language objcode
+ #:title "Guile Object Code"
+ #:version "0.3"
+ #:reader #f
+ #:printer (lambda (x port) (uniform-vector-write (objcode->u8vector x) port))
+ #:compilers `((,value . ,objcode->value))
+ )
diff --git a/module/language/scheme/spec.scm b/module/language/scheme/spec.scm
index ad40a3a2a..3f5a70916 100644
--- a/module/language/scheme/spec.scm
+++ b/module/language/scheme/spec.scm
@@ -20,8 +20,9 @@
;;; Code:
(define-module (language scheme spec)
- #:use-module (language scheme translate)
#:use-module (system base language)
+ #:use-module (language scheme translate)
+ #:use-module (language ghil spec)
#:export (scheme))
;;;
@@ -45,7 +46,7 @@
#:version "0.5"
#:reader read
#:read-file read-file
- #:translator translate
+ #:compilers `((,ghil . ,translate))
#:evaluator (lambda (x module) (primitive-eval x))
#:printer write
)
diff --git a/module/language/scheme/translate.scm b/module/language/scheme/translate.scm
index b191ff296..bd804dce1 100644
--- a/module/language/scheme/translate.scm
+++ b/module/language/scheme/translate.scm
@@ -24,17 +24,52 @@
#:use-module (system base language)
#:use-module (system il ghil)
#:use-module (system il inline)
+ #:use-module (system vm objcode)
#:use-module (ice-9 receive)
+ #:use-module (ice-9 optargs)
#:use-module ((ice-9 syncase) #:select (sc-macro))
#:use-module ((system base compile) #:select (syntax-error))
#:export (translate translate-1
*translate-table* define-scheme-translator))
-(define (translate x e)
- (call-with-ghil-environment e '()
- (lambda (env vars)
- (make-ghil-lambda env #f vars #f '() (translate-1 env #f x)))))
+;;; environment := #f
+;;; | MODULE
+;;; | COMPILE-ENV
+;;; compile-env := (MODULE LEXICALS . EXTERNALS)
+(define (cenv-module env)
+ (cond ((not env) #f)
+ ((module? env) env)
+ ((and (pair? env) (module? (car env))) (car env))
+ (else (error "bad environment" env))))
+
+(define (cenv-ghil-env env)
+ (cond ((not env) (make-ghil-toplevel-env))
+ ((module? env) (make-ghil-toplevel-env))
+ ((pair? env)
+ (ghil-env-dereify (cadr env)))
+ (else (error "bad environment" env))))
+
+(define (cenv-externals env)
+ (cond ((not env) '())
+ ((module? env) '())
+ ((pair? env) (cddr env))
+ (else (error "bad environment" env))))
+
+
+
+
+(define (translate x e opts)
+ (save-module-excursion
+ (lambda ()
+ (and=> (cenv-module e) set-current-module)
+ (call-with-ghil-environment (cenv-ghil-env e) '()
+ (lambda (env vars)
+ (values (make-ghil-lambda env #f vars #f '() (translate-1 env #f x))
+ (and e
+ (cons* (cenv-module e)
+ (ghil-env-parent env)
+ (cenv-externals e)))))))))
;;;
@@ -375,10 +410,11 @@
;; macro would do the trick; but it's good to test the mv-bind
;; code.
(receive (syms rest) (parse-formals formals)
- (call-with-ghil-bindings e syms
- (lambda (vars)
- (make-ghil-mv-bind e l (retrans `(lambda () ,producer-exp))
- vars rest (trans-body e l body)))))))
+ (let ((producer (retrans `(lambda () ,producer-exp))))
+ (call-with-ghil-bindings e syms
+ (lambda (vars)
+ (make-ghil-mv-bind e l producer
+ vars rest (trans-body e l body))))))))
(define-scheme-translator values
((,x) (retrans x))
diff --git a/module/language/value/Makefile.am b/module/language/value/Makefile.am
new file mode 100644
index 000000000..9e87c8a78
--- /dev/null
+++ b/module/language/value/Makefile.am
@@ -0,0 +1,3 @@
+SOURCES = spec.scm
+modpath = language/value
+include $(top_srcdir)/am/guilec
diff --git a/module/language/value/spec.scm b/module/language/value/spec.scm
new file mode 100644
index 000000000..51f5e6c66
--- /dev/null
+++ b/module/language/value/spec.scm
@@ -0,0 +1,31 @@
+;;; Guile Lowlevel Intermediate Language
+
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(define-module (language value spec)
+ #:use-module (system base language)
+ #:export (value))
+
+(define-language value
+ #:title "Guile Values"
+ #:version "0.3"
+ #:reader #f
+ #:printer write
+ )
diff --git a/module/oop/goops.scm b/module/oop/goops.scm
index dd993ded2..d944da264 100644
--- a/module/oop/goops.scm
+++ b/module/oop/goops.scm
@@ -1086,17 +1086,17 @@
(if (unbound? x)
(slot-unbound obj)
x)))
- *goops-module*))
+ #:env *goops-module*))
(define (make-get index)
((@ (system base compile) compile)
`(lambda (o) (@slot-ref o ,index))
- *goops-module*))
+ #:env *goops-module*))
(define (make-set index)
((@ (system base compile) compile)
`(lambda (o v) (@slot-set! o ,index v))
- *goops-module*))
+ #:env *goops-module*))
(define bound-check-get
(standard-accessor-method make-bound-check-get bound-check-get-methods))
diff --git a/module/oop/goops/compile.scm b/module/oop/goops/compile.scm
index 856d41a70..edf956ea7 100644
--- a/module/oop/goops/compile.scm
+++ b/module/oop/goops/compile.scm
@@ -148,7 +148,7 @@
,@(improper->proper formals)))
(apply ,next-method-sym args)))))
,@body)))
- (slot-ref method 'compile-env))))
+ #:env (slot-ref method 'compile-env))))
(list-set! (program-external cmethod) 0
(make-next-method (method-generic-function method)
(cdr methods)
diff --git a/module/system/base/compile.scm b/module/system/base/compile.scm
index 1b8183edf..4f1546025 100644
--- a/module/system/base/compile.scm
+++ b/module/system/base/compile.scm
@@ -20,23 +20,18 @@
;;; Code:
(define-module (system base compile)
- #:use-syntax (system base syntax)
+ #:use-module (system base syntax)
#:use-module (system base language)
- #:use-module ((system il compile) #:select ((compile . compile-il)))
- #:use-module (system il ghil)
- #:use-module (system il glil)
- #:use-module (system vm objcode)
- #:use-module (system vm assemble)
- #:use-module (system vm vm) ;; for compile-time evaluation
+ #:use-module (language objcode spec)
+ #:use-module (language value spec)
+ #:use-module (system vm vm) ;; FIXME: there's a reason for this, can't remember why tho
#:use-module (ice-9 regex)
#:use-module (ice-9 optargs)
- #:use-module ((srfi srfi-1) #:select (fold))
- #:export (syntax-error compile-file load-source-file load-file
+ #:use-module (ice-9 receive)
+ #:export (syntax-error
*current-language*
- compiled-file-name
- compile-time-environment
- compile read-file-in compile-in
- load/compile)
+ compiled-file-name compile-file compile-and-load
+ compile compile-time-environment)
#:export-syntax (call-with-compile-error-catch))
;;;
@@ -62,48 +57,47 @@
;;;
(define *current-language* (make-fluid))
+(define (current-language)
+ (or (fluid-ref *current-language*)
+ (begin (fluid-set! *current-language* (lookup-language 'scheme))
+ (current-language))))
-;; This is basically to avoid mucking with the backtrace.
-(define (call-with-nonlocal-exit-protect thunk on-nonlocal-exit)
- (let ((success #f) (entered #f))
+(define (call-once thunk)
+ (let ((entered #f))
(dynamic-wind
(lambda ()
(if entered
(error "thunk may only be entered once: ~a" thunk))
(set! entered #t))
- (lambda ()
- (thunk)
- (set! success #t))
- (lambda ()
- (if (not success)
- (on-nonlocal-exit))))))
-
+ thunk
+ (lambda () #t))))
+
(define (call-with-output-file/atomic filename proc)
(let* ((template (string-append filename ".XXXXXX"))
(tmp (mkstemp! template)))
- (call-with-nonlocal-exit-protect
- (lambda ()
- (with-output-to-port tmp
- (lambda () (proc (current-output-port))))
- (rename-file template filename))
+ (call-once
(lambda ()
- (delete-file template)))))
+ (with-throw-handler #t
+ (lambda ()
+ (with-output-to-port tmp
+ (lambda () (proc (current-output-port))))
+ (rename-file template filename))
+ (lambda args
+ (delete-file template)))))))
-(define (compile-file file . opts)
+(define* (compile-file file #:key (to objcode) (opts '()))
(let ((comp (compiled-file-name file))
- (lang (fluid-ref *current-language*)))
+ (lang (current-language)))
(catch 'nothing-at-all
(lambda ()
(call-with-compile-error-catch
(lambda ()
(call-with-output-file/atomic comp
(lambda (port)
- (let* ((source (read-file-in file lang))
- (objcode (apply compile-in source (current-module)
- lang opts)))
- (if (memq #:c opts)
- (pprint-glil objcode port)
- (uniform-vector-write (objcode->u8vector objcode) port)))))
+ (let ((print (language-printer to)))
+ (print (compile (read-file-in file lang)
+ #:from lang #:to to #:opts opts)
+ port))))
(format #t "wrote `~A'\n" comp))))
(lambda (key . args)
(format #t "ERROR: during compilation of ~A:\n" file)
@@ -113,25 +107,9 @@
(format #t "ERROR: ~A ~A ~A\n" key (car args) (cadddr args))
(delete-file comp)))))
-; (let ((c-f compile-file))
-; ;; XXX: Debugging output
-; (set! compile-file
-; (lambda (file . opts)
-; (format #t "compile-file: ~a ~a~%" file opts)
-; (let ((result (apply c-f (cons file opts))))
-; (format #t "compile-file: returned ~a~%" result)
-; result))))
-
-(define (load-source-file file . opts)
- (let ((lang (fluid-ref *current-language*)))
- (let ((source (read-file-in file lang)))
- (apply compile-in source (current-module) lang opts))))
-
-(define (load-file file . opts)
- (let ((comp (compiled-file-name file)))
- (if (file-exists? comp)
- (load-objcode comp)
- (apply load-source-file file opts))))
+(define* (compile-and-load file #:key (to value) (opts '()))
+ (let ((lang (current-language)))
+ (compile (read-file-in file lang) #:to value #:opts opts)))
(define (compiled-file-name file)
(let ((base (basename file))
@@ -151,112 +129,46 @@
cext))
(else (lp (cdr exts)))))))
-;;; environment := #f
-;;; | MODULE
-;;; | COMPILE-ENV
-;;; compile-env := (MODULE LEXICALS . EXTERNALS)
-(define (cenv-module env)
- (cond ((not env) #f)
- ((module? env) env)
- ((and (pair? env) (module? (car env))) (car env))
- (else (error "bad environment" env))))
-
-(define (cenv-ghil-env env)
- (cond ((not env) (make-ghil-toplevel-env))
- ((module? env) (make-ghil-toplevel-env))
- ((pair? env)
- (ghil-env-dereify (cadr env)))
- (else (error "bad environment" env))))
-
-(define (cenv-externals env)
- (cond ((not env) '())
- ((module? env) '())
- ((pair? env) (cddr env))
- (else (error "bad environment" env))))
-
-(define (compile-time-environment)
- "A special function known to the compiler that, when compiled, will
-return a representation of the lexical environment in place at compile
-time. Useful for supporting some forms of dynamic compilation. Returns
-#f if called from the interpreter."
- #f)
-
-(define* (compile x #:optional env)
- (let ((thunk (objcode->program
- (compile-in x env (fluid-ref *current-language*))
- (cenv-externals env))))
- (if (not env)
- (thunk)
- (save-module-excursion
- (lambda ()
- (set-current-module (cenv-module env))
- (thunk))))))
-
;;;
-;;; Scheme compiler interface
+;;; Compiler interface
;;;
(define (read-file-in file lang)
- (call-with-input-file file (or (language-read-file lang)
- (error "language has no #:read-file" lang))))
-
-;;; FIXME: fold run-pass x (compile-passes lang opts)
-(define (compile-passes lang opts)
- (let lp ((passes (list
- (language-expander lang)
- (language-translator lang)
- (lambda (x e) (apply compile-il x e opts))
- (lambda (x e) (apply assemble x e opts))))
- (keys '(#f #:e #:t #:c))
+ (call-with-input-file file
+ (or (language-read-file lang)
+ (error "language has no #:read-file" lang))))
+
+(define (compile-passes from to opts)
+ (let lp ((langs (or (lookup-compilation-order from to)
+ (error "no way to compile" (language-name from)
+ "to" (language-name to))))
(out '()))
- (if (or (null? keys)
- (and (car keys) (memq (car keys) opts)))
+ (if (null? (cdr langs))
(reverse! out)
- (lp (cdr passes) (cdr keys)
- (if (car passes)
- (cons (car passes) out)
- out)))))
-
-(define (compile-in x e lang . opts)
- (save-module-excursion
- (lambda ()
- (and=> (cenv-module e) set-current-module)
- (let ((env (cenv-ghil-env e)))
- (fold (lambda (pass exp)
- (pass exp env))
- x
- (compile-passes lang opts))))))
-
-;;;
-;;;
-;;;
-
-(define (compile-and-load file . opts)
- (let ((comp (object-file-name file)))
- (if (or (not (file-exists? comp))
- (> (stat:mtime (stat file)) (stat:mtime (stat comp))))
- (compile-file file))
- (load-compiled-file comp)))
+ (lp (cdr langs)
+ (cons (assq-ref (language-compilers (car langs)) (cadr langs))
+ out)))))
-(define (load/compile file . opts)
- (let* ((file (file-full-name file))
- (compiled (object-file-name file)))
- (if (or (not (file-exists? compiled))
- (> (stat:mtime (stat file)) (stat:mtime (stat compiled))))
- (apply compile-file file #f opts))
- (if (memq #:b opts)
- (apply vm-trace (the-vm) (load-objcode compiled) opts)
- ((the-vm) (load-objcode compiled)))))
+(define (compile-fold passes exp env opts)
+ (if (null? passes)
+ exp
+ (receive (exp env) ((car passes) exp env opts)
+ (compile-fold (cdr passes) exp env opts))))
-(define (file-full-name filename)
- (let* ((port (current-load-port))
- (oldname (and port (port-filename port))))
- (if (and oldname
- (> (string-length filename) 0)
- (not (char=? (string-ref filename 0) #\/))
- (not (string=? (dirname oldname) ".")))
- (string-append (dirname oldname) "/" filename)
- filename)))
+(define (compile-time-environment)
+ "A special function known to the compiler that, when compiled, will
+return a representation of the lexical environment in place at compile
+time. Useful for supporting some forms of dynamic compilation. Returns
+#f if called from the interpreter."
+ #f)
-(fluid-set! *current-language* (lookup-language 'scheme))
+(define* (compile x #:key
+ (env #f)
+ (from (current-language))
+ (to value)
+ (opts '()))
+ (compile-fold (compile-passes from to opts)
+ x
+ env
+ opts))
diff --git a/module/system/base/language.scm b/module/system/base/language.scm
index 50de15a7d..208e0e128 100644
--- a/module/system/base/language.scm
+++ b/module/system/base/language.scm
@@ -20,30 +20,56 @@
;;; Code:
(define-module (system base language)
- #:use-syntax (system base syntax)
+ #:use-module (system base syntax)
#:export (define-language lookup-language make-language
- language-name language-title language-version language-reader
- language-printer language-read-file language-expander
- language-translator language-evaluator language-environment))
+ language-name language-title language-version language-reader
+ language-printer language-parser language-read-file
+ language-compilers language-evaluator
+
+ lookup-compilation-order invalidate-compilation-cache!))
;;;
;;; Language class
;;;
-(define-record (<language> name title version reader printer
- (read-file #f)
- (expander #f)
- (translator #f)
- (evaluator #f)
- (environment #f)
- ))
+(define-record <language>
+ name
+ title
+ version
+ reader
+ printer
+ (parser #f)
+ (read-file #f)
+ (compilers '())
+ (evaluator #f))
(define-macro (define-language name . spec)
- `(define ,name (make-language #:name ',name ,@spec)))
+ `(begin
+ (invalidate-compilation-cache!)
+ (define ,name (make-language #:name ',name ,@spec))))
(define (lookup-language name)
(let ((m (resolve-module `(language ,name spec))))
(if (module-bound? m name)
(module-ref m name)
(error "no such language" name))))
+
+(define *compilation-cache* '())
+
+(define (invalidate-compilation-cache!)
+ (set! *compilation-cache* '()))
+
+(define (compute-compilation-order from to)
+ (let lp ((from from) (seen '()))
+ (cond ((eq? from to) (reverse! (cons from seen)))
+ ((memq from seen) #f)
+ (else (or-map (lambda (lang) (lp lang (cons from seen)))
+ (map car (language-compilers from)))))))
+
+(define (lookup-compilation-order from to)
+ (or (assoc-ref *compilation-cache* (cons from to))
+ (let ((order (compute-compilation-order from to)))
+ (set! *compilation-cache*
+ (acons (cons from to) order *compilation-cache*))
+ order)))
diff --git a/module/system/base/syntax.scm b/module/system/base/syntax.scm
index 0e02ba06a..b7b995034 100644
--- a/module/system/base/syntax.scm
+++ b/module/system/base/syntax.scm
@@ -32,8 +32,11 @@
(let ((name (if (pair? name) (car name) name))
(opts (if (pair? name) (cdr name) '())))
(let ((printer (kw-arg-ref opts #:printer)))
- `(begin ,@(map (lambda (def) `(define-record ,def
- ,@(if printer (list printer) '())))
+ `(begin ,@(map (lambda (def)
+ `(define-record ,(if printer
+ `(,(car def) ,printer)
+ (car def))
+ ,@(cdr def)))
rest)))))
@@ -44,14 +47,15 @@
(define (symbol-trim-both sym pred)
(string->symbol (string-trim-both (symbol->string sym) pred)))
-(define-macro (define-record def . printer)
- (let* ((name (car def)) (slots (cdr def))
+(define-macro (define-record name-form . slots)
+ (let* ((name (if (pair? name-form) (car name-form) name-form))
+ (printer (and (pair? name-form) (cadr name-form)))
(slot-names (map (lambda (slot) (if (pair? slot) (car slot) slot))
slots))
(stem (symbol-trim-both name (list->char-set '(#\< #\>)))))
`(begin
(define ,name (make-record-type ,(symbol->string name) ',slot-names
- ,@printer))
+ ,@(if printer (list printer) '())))
(define ,(symbol-append 'make- stem)
(let ((slots (list ,@(map (lambda (slot)
(if (pair? slot)
diff --git a/module/system/il/compile.scm b/module/system/il/compile.scm
index 9a6e5dda2..e5c1b48b7 100644
--- a/module/system/il/compile.scm
+++ b/module/system/il/compile.scm
@@ -26,9 +26,10 @@
#:use-module (ice-9 common-list)
#:export (compile))
-(define (compile x e . opts)
+(define (compile x e opts)
(if (memq #:O opts) (set! x (optimize x)))
- (codegen x))
+ (values (codegen x)
+ (and e (cons (car e) (cddr e)))))
;;;
diff --git a/module/system/il/ghil.scm b/module/system/il/ghil.scm
index 0340c0394..a2f86dfdf 100644
--- a/module/system/il/ghil.scm
+++ b/module/system/il/ghil.scm
@@ -145,7 +145,7 @@
;;; Variables
;;;
-(define-record (<ghil-var> env name kind (index #f)))
+(define-record <ghil-var> env name kind (index #f))
;;;
@@ -157,8 +157,8 @@
;;; Environments
;;;
-(define-record (<ghil-env> parent (table '()) (variables '())))
-(define-record (<ghil-toplevel-env> (table '())))
+(define-record <ghil-env> parent (table '()) (variables '()))
+(define-record <ghil-toplevel-env> (table '()))
(define (ghil-env-ref env sym)
(assq-ref (ghil-env-table env) sym))
diff --git a/module/system/il/glil.scm b/module/system/il/glil.scm
index d26ba16b2..4969a0bad 100644
--- a/module/system/il/glil.scm
+++ b/module/system/il/glil.scm
@@ -20,10 +20,10 @@
;;; Code:
(define-module (system il glil)
- #:use-syntax (system base syntax)
+ #:use-module (system base syntax)
+ #:use-module (system base pmatch)
#:export
- (pprint-glil
- <glil-vars> make-glil-vars
+ (<glil-vars> make-glil-vars
glil-vars-nargs glil-vars-nrest glil-vars-nlocs glil-vars-nexts
<glil-asm> make-glil-asm glil-asm?
@@ -70,11 +70,16 @@
glil-call-inst glil-call-nargs
<glil-mv-call> make-glil-mv-call glil-mv-call?
- glil-mv-call-nargs glil-mv-call-ra))
+ glil-mv-call-nargs glil-mv-call-ra
-(define-record (<glil-vars> nargs nrest nlocs nexts))
+ parse-glil unparse-glil))
-(define-type <glil>
+(define-record <glil-vars> nargs nrest nlocs nexts)
+
+(define (print-glil x port)
+ (format port "#<glil ~s>" (unparse-glil x)))
+
+(define-type (<glil> #:printer print-glil)
;; Meta operations
(<glil-asm> vars meta body)
(<glil-bind> vars)
@@ -97,125 +102,57 @@
(<glil-mv-call> nargs ra))
-;;;
-;;; Parser
-;;;
-
-;;; (define (parse-glil x)
-;;; (match x
-;;; (('@asm args . body)
-;;; (let* ((env (make-new-env e))
-;;; (args (parse-args args env)))
-;;; (make-asm env args (map-parse body env))))
-;;; (else
-;;; (error "Invalid assembly code:" x))))
-;;;
-;;; (define (parse-args x e)
-;;; (let ((args (cond ((symbol? x) (make-args (list (make-local-var x)) #t))
-;;; ((list? x) (make-args (map make-local-var x) #f))
-;;; (else (let loop ((l x) (v '()))
-;;; (if (pair? l)
-;;; (loop (cdr l) (cons (car l) v))
-;;; (make-args (map make-local-var
-;;; (reverse! (cons l v)))
-;;; #t)))))))
-;;; (for-each (lambda (v) (env-add! e v)) (args-vars args))
-;;; args))
-;;;
-;;; (define (map-parse x e)
-;;; (map (lambda (x) (parse x e)) x))
-;;;
-;;; (define (parse x e)
-;;; (match x
-;;; ;; (@asm ARGS BODY...)
-;;; (('@asm args . body)
-;;; (parse-asm x e))
-;;; ;; (@bind VARS BODY...)
-;;; ;; (@block VARS BODY...)
-;;; (((or '@bind '@block) vars . body)
-;;; (let* ((offset (env-nvars e))
-;;; (vars (args-vars (parse-args vars e)))
-;;; (block (make-block (car x) offset vars (map-parse body e))))
-;;; (for-each (lambda (v) (env-remove! e)) vars)
-;;; block))
-;;; ;; (void)
-;;; (('void)
-;;; (make-void))
-;;; ;; (const OBJ)
-;;; (('const obj)
-;;; (make-const obj))
-;;; ;; (ref NAME)
-;;; ;; (set NAME)
-;;; (((or 'ref 'set) name)
-;;; (make-access (car x) (env-ref e name)))
-;;; ;; (label LABEL)
-;;; (('label label)
-;;; (make-label label))
-;;; ;; (br-if LABEL)
-;;; ;; (jump LABEL)
-;;; (((or 'br-if 'jump) label)
-;;; (make-instl (car x) label))
-;;; ;; (call NARGS)
-;;; ;; (tail-call NARGS)
-;;; (((or 'call 'goto/args) n)
-;;; (make-instn (car x) n))
-;;; ;; (INST)
-;;; ((inst)
-;;; (if (instruction? inst)
-;;; (make-inst inst)
-;;; (error "Unknown instruction:" inst)))))
-
-
-;;;
-;;; Unparser
-;;;
-
-(define (unparse glil)
+(define (parse-glil x)
+ (pmatch x
+ ((asm (,nargs ,nrest ,nlocs ,next) ,meta . ,body)
+ (make-glil-asm (make-glil-vars nargs nrest nlocs next)
+ meta (map parse-glil body)))
+ ((bind . ,vars) (make-glil-bind vars))
+ ((mv-bind ,vars . ,rest) (make-glil-mv-bind vars (map parse-glil rest)))
+ ((unbind) (make-glil-unbind))
+ ((source ,loc) (make-glil-source loc))
+ ((void) (make-glil-void))
+ ((const ,obj) (make-glil-const obj))
+ ((argument ,op ,index) (make-glil-argument op index))
+ ((local ,op ,index) (make-glil-local op index))
+ ((external ,op ,depth ,index) (make-glil-external op depth index))
+ ((toplevel ,op ,name) (make-glil-toplevel op name))
+ ((module public ,op ,mod ,name) (make-glil-module op mod name #t))
+ ((module private ,op ,mod ,name) (make-glil-module op mod name #f))
+ ((label ,label) (make-label ,label))
+ ((branch ,inst ,label) (make-glil-branch inst label))
+ ((call ,inst ,nargs) (make-glil-call inst nargs))
+ ((mv-call ,nargs ,ra) (make-glil-mv-call nargs ra))
+ (else (error "invalid glil" x))))
+
+(define (unparse-glil glil)
(record-case glil
;; meta
((<glil-asm> vars meta body)
- `(@asm (,(glil-vars-nargs vars) ,(glil-vars-nrest vars)
- ,(glil-vars-nlocs vars) ,(glil-vars-nexts vars))
- ,meta
- ,@(map unparse body)))
- ((<glil-bind> vars) `(@bind ,@vars))
- ((<glil-unbind>) `(@unbind))
- ((<glil-source> loc) `(@source ,loc))
+ `(asm (,(glil-vars-nargs vars) ,(glil-vars-nrest vars)
+ ,(glil-vars-nlocs vars) ,(glil-vars-nexts vars))
+ ,meta
+ ,@(map unparse-glil body)))
+ ((<glil-bind> vars) `(bind ,@vars))
+ ((<glil-mv-bind> vars rest) `(mv-bind ,vars ,@rest))
+ ((<glil-unbind>) `(unbind))
+ ((<glil-source> loc) `(source ,loc))
;; constants
((<glil-void>) `(void))
((<glil-const> obj) `(const ,obj))
;; variables
((<glil-argument> op index)
- `(,(symbol-append 'argument- op) ,index))
+ `(argument ,op ,index))
((<glil-local> op index)
- `(,(symbol-append 'local- op) ,index))
+ `(local ,op ,index))
((<glil-external> op depth index)
- `(,(symbol-append 'external- op) ,depth ,index))
+ `(external ,op ,depth ,index))
((<glil-toplevel> op name)
- `(,(symbol-append 'toplevel- op) ,name))
+ `(toplevel ,op ,name))
((<glil-module> op mod name public?)
- `(,(symbol-append (if public? 'public 'private) '- op) ,mod ,name))
+ `(module ,(if public? 'public 'private) ,op ,mod ,name))
;; controls
- ((<glil-label> label) label)
- ((<glil-branch> inst label) `(,inst ,label))
- ((<glil-call> inst nargs) `(,inst ,nargs))))
-
-
-;;;
-;;; Printer
-;;;
-
-(define (pprint-glil glil . port)
- (let ((port (if (pair? port) (car port) (current-output-port))))
- (let print ((code (unparse glil)) (column 0))
- (display (make-string column #\space) port)
- (cond ((and (pair? code) (eq? (car code) '@asm))
- (format port "(@asm ~A\n" (cadr code))
- (let ((col (+ column 2)))
- (let loop ((l (cddr code)))
- (print (car l) col)
- (if (null? (cdr l))
- (display ")" port)
- (begin (newline port) (loop (cdr l)))))))
- (else (write code port))))
- (newline port)))
+ ((<glil-label> label) (label ,label))
+ ((<glil-branch> inst label) `(branch ,inst ,label))
+ ((<glil-call> inst nargs) `(call ,inst ,nargs))
+ ((<glil-mv-call> nargs ra) `(mv-call ,nargs ,(unparse-glil ra)))))
diff --git a/module/system/repl/command.scm b/module/system/repl/command.scm
index ca5346d90..2e9299a34 100644
--- a/module/system/repl/command.scm
+++ b/module/system/repl/command.scm
@@ -28,7 +28,6 @@
#:use-module (system vm program)
#:use-module (system vm vm)
#:autoload (system base language) (lookup-language)
- #:autoload (system il glil) (pprint-glil)
#:autoload (system vm disasm) (disassemble-program disassemble-objcode)
#:autoload (system vm debug) (vm-debugger vm-backtrace)
#:autoload (system vm trace) (vm-trace vm-trace-on vm-trace-off)
@@ -168,7 +167,8 @@ Find bindings/modules/packages."
(define (describe repl obj)
"describe OBJ
Show description/documentation."
- (display (object-documentation (repl-eval repl obj)))
+ (display (object-documentation
+ (repl-eval repl (repl-parse repl obj))))
(newline))
(define (option repl . args)
@@ -266,21 +266,20 @@ Generate compiled code.
-O Enable optimization
-D Add debug information"
- (let ((x (apply repl-compile repl form opts)))
- (cond ((or (memq #:e opts) (memq #:t opts)) (puts x))
- ((memq #:c opts) (pprint-glil x))
- (else (disassemble-objcode x)))))
+ (let ((x (apply repl-compile repl (repl-parse repl form) opts)))
+ (cond ((objcode? x) (disassemble-objcode x))
+ (else (repl-print repl x)))))
(define guile:compile-file compile-file)
(define (compile-file repl file . opts)
"compile-file FILE
Compile a file."
- (apply guile:compile-file (->string file) opts))
+ (guile:compile-file (->string file) #:opts opts))
(define (disassemble repl prog)
"disassemble PROGRAM
Disassemble a program."
- (disassemble-program (repl-eval repl prog)))
+ (disassemble-program (repl-eval repl (repl-parse repl prog))))
(define (disassemble-file repl file)
"disassemble-file FILE
@@ -298,7 +297,7 @@ Time execution."
(let* ((vms-start (vm-stats (repl-vm repl)))
(gc-start (gc-run-time))
(tms-start (times))
- (result (repl-eval repl form))
+ (result (repl-eval repl (repl-parse repl form)))
(tms-end (times))
(gc-end (gc-run-time))
(vms-end (vm-stats (repl-vm repl))))
@@ -320,7 +319,7 @@ Time execution."
Profile execution."
(apply vm-profile
(repl-vm repl)
- (repl-compile repl form)
+ (repl-compile repl (repl-parse repl form))
opts))
@@ -346,7 +345,9 @@ Trace execution.
-l Display local variables
-e Display external variables
-b Bytecode level trace"
- (apply vm-trace (repl-vm repl) (repl-compile repl form) opts))
+ (apply vm-trace (repl-vm repl)
+ (repl-compile repl (repl-parse repl form))
+ opts))
(define (step repl)
"step FORM
diff --git a/module/system/repl/common.scm b/module/system/repl/common.scm
index 7aa322e05..03c63bd74 100644
--- a/module/system/repl/common.scm
+++ b/module/system/repl/common.scm
@@ -25,17 +25,17 @@
#:use-module (system base language)
#:use-module (system vm vm)
#:export (<repl> make-repl repl-vm repl-language repl-options
- repl-tm-stats repl-gc-stats repl-vm-stats
- repl-welcome repl-prompt repl-read repl-compile repl-eval
- repl-print repl-option-ref repl-option-set!
- puts ->string user-error))
+ repl-tm-stats repl-gc-stats repl-vm-stats
+ repl-welcome repl-prompt repl-read repl-compile repl-eval
+ repl-parse repl-print repl-option-ref repl-option-set!
+ puts ->string user-error))
;;;
;;; Repl type
;;;
-(define-record (<repl> vm language options tm-stats gc-stats vm-stats))
+(define-record <repl> vm language options tm-stats gc-stats vm-stats)
(define repl-default-options
'((trace . #f)
@@ -65,15 +65,23 @@
((language-reader (repl-language repl))))
(define (repl-compile repl form . opts)
- (apply compile-in form (current-module) (repl-language repl) opts))
+ (let ((to (lookup-language (cond ((memq #:e opts) 'scheme)
+ ((memq #:t opts) 'ghil)
+ ((memq #:c opts) 'glil)
+ (else 'objcode)))))
+ (compile form #:from (repl-language repl) #:to to #:opts opts)))
+
+(define (repl-parse repl form)
+ (let ((parser (language-parser (repl-language repl))))
+ (if parser (parser form) form)))
(define (repl-eval repl form)
(let ((eval (language-evaluator (repl-language repl))))
(if (and eval
- (or (not (language-translator (repl-language repl)))
+ (or (null? (language-compilers (repl-language repl)))
(assq-ref (repl-options repl) 'interp)))
- (eval form (current-module))
- (vm-load (repl-vm repl) (repl-compile repl form)))))
+ (eval form (current-module))
+ (vm-load (repl-vm repl) (repl-compile repl form '())))))
(define (repl-print repl val)
(if (not (eq? val *unspecified*))
diff --git a/module/system/repl/repl.scm b/module/system/repl/repl.scm
index b4422c839..379b52647 100644
--- a/module/system/repl/repl.scm
+++ b/module/system/repl/repl.scm
@@ -121,7 +121,8 @@
(call-with-values (lambda ()
(run-hook before-eval-hook exp)
(start-stack repl-eval
- (repl-eval repl exp)))
+ (repl-eval repl
+ (repl-parse repl exp))))
(lambda l
(for-each (lambda (v)
(run-hook before-print-hook v)
diff --git a/module/system/vm/assemble.scm b/module/system/vm/assemble.scm
index 5e61af40b..81cad8063 100644
--- a/module/system/vm/assemble.scm
+++ b/module/system/vm/assemble.scm
@@ -40,13 +40,13 @@
;;; Types
;;;
-(define-record (<vm-asm> venv glil body))
-(define-record (<venv> parent nexts closure?))
+(define-record <vm-asm> venv glil body)
+(define-record <venv> parent nexts closure?)
;; key is either a symbol or the list (MODNAME SYM PUBLIC?)
-(define-record (<vlink-now> key))
-(define-record (<vlink-later> key))
-(define-record (<vdefine> name))
-(define-record (<bytespec> vars bytes meta objs closure?))
+(define-record <vlink-now> key)
+(define-record <vlink-later> key)
+(define-record <vdefine> name)
+(define-record <bytespec> vars bytes meta objs closure?)
;;;
diff --git a/module/system/vm/debug.scm b/module/system/vm/debug.scm
index b37d5095e..03eb2ecaa 100644
--- a/module/system/vm/debug.scm
+++ b/module/system/vm/debug.scm
@@ -31,7 +31,7 @@
;;; Debugger
;;;
-(define-record (<debugger> vm chain index))
+(define-record <debugger> vm chain index)
(define (vm-debugger vm)
(let ((chain (vm-last-frame-chain vm)))
diff --git a/test-suite/tests/compiler.test b/test-suite/tests/compiler.test
index dc27d6dc1..d83167f34 100644
--- a/test-suite/tests/compiler.test
+++ b/test-suite/tests/compiler.test
@@ -40,15 +40,15 @@
;; fixme: compiling with #t or module
(pass-if "recompiling with environment"
- (equal? ((compile '(lambda () x) env))
+ (equal? ((compile '(lambda () x) #:env env))
1))
(pass-if "recompiling with environment/2"
- (equal? ((compile '(lambda () (set! x (1+ x)) x) env))
+ (equal? ((compile '(lambda () (set! x (1+ x)) x) #:env env))
2))
(pass-if "recompiling with environment/3"
- (equal? ((compile '(lambda () x) env))
+ (equal? ((compile '(lambda () x) #:env env))
2))
)
@@ -57,6 +57,6 @@
10))
(pass-if "compile environment is a module"
- (equal? ((compile '(lambda () 10) (current-module)))
+ (equal? ((compile '(lambda () 10) #:env (current-module)))
10))
) \ No newline at end of file
diff --git a/testsuite/run-vm-tests.scm b/testsuite/run-vm-tests.scm
index 9f07d0561..68379e5e1 100644
--- a/testsuite/run-vm-tests.scm
+++ b/testsuite/run-vm-tests.scm
@@ -22,13 +22,12 @@
(system vm disasm)
(system base compile)
(system base language)
-
+ (language scheme spec)
+ (language objcode spec)
(srfi srfi-1)
(ice-9 r5rs))
-(define %scheme (lookup-language 'scheme))
-
(define (fetch-sexp-from-file file)
(with-input-from-file file
(lambda ()
@@ -40,7 +39,7 @@
(define (compile-to-objcode sexp)
"Compile the expression @var{sexp} into a VM program and return it."
- (compile-in sexp (current-module) %scheme))
+ (compile sexp #:from scheme #:to objcode))
(define (run-vm-program objcode)
"Run VM program contained into @var{objcode}."