~ chicken-core (chicken-5) 0be9d247a57da082bb2126b2e91958ea191c5513
commit 0be9d247a57da082bb2126b2e91958ea191c5513 Author: Evan Hanson <evhan@foldling.org> AuthorDate: Wed Jun 13 19:35:24 2018 +1200 Commit: felix <felix@call-with-current-continuation.org> CommitDate: Mon Jun 18 20:21:03 2018 +0200 Splice includes into body contexts so definitions are handled correctly Now that non-toplevel definitions outside a "body" context are no longer allowed, we have to expand include forms during body canonicalisation so that any definitions in the included file are correctly spliced into the surrounding context. Otherwise, they won't be recognised as internal definitions and the compiler will reject them as "toplevel definitions in non-toplevel context". So, whenever a `##core#include' node is encountered, it's now extended to include the remainder of the forms in the surrounding body and control is handed back to the compiler. Then, whenever the compiler reads forms from an included file, it checks for a body and, if one is present, it knows it should return to the canonicalisation routine with the included forms (as well as the remainder of the original body context). If no body is present, included forms are treated as usual, i.e. as a normal sequence that gets inserted into a `##core#begin' node. This treatment is similar to what we currently do for modules, which must also be handled as a special case during body canonicalisation. Signed-off-by: felix <felix@call-with-current-continuation.org> diff --git a/NEWS b/NEWS index 40ff4aec..df0efd7f 100644 --- a/NEWS +++ b/NEWS @@ -120,6 +120,9 @@ predicates no longer return #t for records with the same tag defined in another module. This tag is now also available under an identifier that matches the record type name (fixes #1342). + - `include` now splices included expressions in the context in which + the inclusion appears and does not treat the expressions as toplevel + expressions by default. - Eggs management - Egg-installation and building has been completely overhauled. diff --git a/core.scm b/core.scm index a09ba4af..2bbed0b2 100644 --- a/core.scm +++ b/core.scm @@ -111,7 +111,7 @@ ; (##core#set! <variable> <exp>) ; (##core#ensure-toplevel-definition <variable>) ; (##core#begin <exp> ...) -; (##core#include <string> <string> | #f) +; (##core#include <string> <string> | #f [<body>]) ; (##core#loop-lambda <llist> <body>) ; (##core#undefined) ; (##core#primitive <name>) @@ -951,7 +951,13 @@ (cadr x) (caddr x) (lambda (forms) - (walk `(##core#begin ,@forms) e dest ldest h ln tl?))))) + (walk (if (pair? (cdddr x)) ; body? + (canonicalize-body/ln + ln + (append forms (cadddr x)) + compiler-syntax-enabled) + `(##core#begin ,@forms)) + e dest ldest h ln tl?))))) ((##core#let-module-alias) (##sys#with-module-aliases diff --git a/eval.scm b/eval.scm index ae70f888..7aad9636 100644 --- a/eval.scm +++ b/eval.scm @@ -519,7 +519,13 @@ (cadr x) (caddr x) (lambda (forms) - (compile `(##core#begin ,@forms) e #f tf cntr tl?)))) + (compile + (if (pair? (cdddr x)) ; body? + (##sys#canonicalize-body + (append forms (cadddr x)) + (##sys#current-environment)) + `(##core#begin ,@forms)) + e #f tf cntr tl?)))) ((##core#let-module-alias) (##sys#with-module-aliases diff --git a/expand.scm b/expand.scm index b2f97d4b..c228735d 100644 --- a/expand.scm +++ b/expand.scm @@ -511,18 +511,20 @@ (##sys#append (reverse exps) (list (expand body))))) (let ((x2 (##sys#expand-0 x se cs?))) (if (eq? x x2) - ;; Modules must be registered before we - ;; can continue with other forms, so - ;; hand back control to the compiler + ;; Modules and includes must be processed before + ;; we can continue with other forms, so hand + ;; control back to the compiler (if (and (pair? x) (symbol? (car x)) - (comp '##core#module (car x))) + (or (comp '##core#module (car x)) + (comp '##core#include (car x)))) `(##core#begin ,@(reverse exps) - ,x - ,@(if (null? rest) - '() - `((##core#let () ,@rest)))) + ,@(if (comp '##core#module (car x)) + (if (null? rest) + `(,x) + `(,x (##core#let () ,@rest))) + `((##core#include ,@(cdr x) ,rest)))) (loop rest (cons x exps))) (loop2 (cons x2 rest)) )) ))) )) ;; We saw defines. Translate to letrec, and let compiler diff --git a/manual/Module (chicken base) b/manual/Module (chicken base) index 4d8396c9..763de5ed 100644 --- a/manual/Module (chicken base) +++ b/manual/Module (chicken base) @@ -1215,7 +1215,7 @@ s ==> "#,(foo 1 2 3)" <macro>(include STRING)</macro> -Include toplevel-expressions from the given source file in the currently +Include expressions from the given source file in the currently compiled/interpreted program. If the included file has the extension {{.scm}}, then it may be omitted. The file is searched for in the current directory and all directories specified by the {{-include-path}} diff --git a/tests/runtests.bat b/tests/runtests.bat index f6856ccc..6030d387 100644 --- a/tests/runtests.bat +++ b/tests/runtests.bat @@ -22,7 +22,7 @@ set compile_r=..\%PROGRAM_PREFIX%csc%PROGRAM_SUFFIX% %COMPILE_OPTIONS% -o a.out set compile_s=..\%PROGRAM_PREFIX%csc%PROGRAM_SUFFIX% %COMPILE_OPTIONS% -s -types %TYPESDB% -ignore-repository set interpret=..\%PROGRAM_PREFIX%csi%PROGRAM_SUFFIX% -n -include-path %TEST_DIR%/.. -del /f /q /s *.exe *.so *.o *.import.* ..\foo.import.* %CHICKEN_INSTALL_REPOSITORY% +del /f /q /s *.exe *.so *.o *.out *.import.* ..\foo.import.* %CHICKEN_INSTALL_REPOSITORY% rmdir /q /s %CHICKEN_INSTALL_REPOSITORY% mkdir %CHICKEN_INSTALL_REPOSITORY% copy %TYPESDB% %CHICKEN_INSTALL_REPOSITORY% diff --git a/tests/runtests.sh b/tests/runtests.sh index a9e8a5b1..06279127 100755 --- a/tests/runtests.sh +++ b/tests/runtests.sh @@ -59,7 +59,7 @@ $time true >/dev/null 2>/dev/null test $? -eq 127 && time= set -e -rm -fr *.exe *.so *.o *.import.* a.out ../foo.import.* test-repository +rm -fr *.exe *.so *.o *.out *.import.* ../foo.import.* test-repository mkdir -p test-repository cp $TYPESDB test-repository/types.db diff --git a/tests/syntax-tests.scm b/tests/syntax-tests.scm index d01d8883..38ae5978 100644 --- a/tests/syntax-tests.scm +++ b/tests/syntax-tests.scm @@ -1239,6 +1239,22 @@ other-eval (assert (eq? req 1))) +;; Includes should be spliced into the surrounding body context: + +(begin-for-syntax + (with-output-to-file "x.out" (cut pp '(define x 2)))) + +(let () + (define x 1) + (include "x.out") + (t 2 x)) + +(let () + (define x 1) + (let () + (include "x.out")) + (t 1 x)) + ;; letrec vs. letrec* ;;XXX this fails - the optimizer substitutes "foo" for it's known constant valueTrap