~ chicken-r7rs (master) fda5e06fbaffcb589351132670af043f21ab51ed
commit fda5e06fbaffcb589351132670af043f21ab51ed Author: felix <felix@call-with-current-continuation.org> AuthorDate: Wed Jun 5 10:01:43 2013 +0000 Commit: Evan Hanson <evhan@foldling.org> CommitDate: Wed Jun 5 10:01:43 2013 +0000 Added various extensions and restructured the modules, initial implementation of define-library diff --git a/NOTES.org b/NOTES.org new file mode 100644 index 0000000..d2b636f --- /dev/null +++ b/NOTES.org @@ -0,0 +1,10 @@ +NOTES + + +* Redefinition of "import" may be tricky, as it is implicit and not in any module. + - possible reimplement using core functionality. + +* Use of "define-values" is elegant but loses lambda-info for the defined procedures. + +* "export" does not support "(rename ...)" specifier yet. + - this needs extensions to the core module system. diff --git a/r7rs-compile-time-module.scm b/r7rs-compile-time-module.scm new file mode 100644 index 0000000..172a7f9 --- /dev/null +++ b/r7rs-compile-time-module.scm @@ -0,0 +1,14 @@ +(module r7rs-compile-time (parse-library-definition + process-cond-expand + fixup-import/export-spec + parse-library-name + read-forms + current-source-filename + register-r7rs-module + locate-library) + +(import scheme chicken) + +(include "r7rs-compile-time.scm") + +) diff --git a/r7rs-compile-time.scm b/r7rs-compile-time.scm new file mode 100644 index 0000000..229a7be --- /dev/null +++ b/r7rs-compile-time.scm @@ -0,0 +1,160 @@ +;;;; compile-time support code (mostly for modules) + + +(import matchable) +(use srfi-1 files extras data-structures) + + +(define (parse-library-name name loc) + (define (fail) (syntax-error loc "invalid library name" name)) + (match name + ((? symbol?) name) + ((parts ...) + (string->symbol + (string-intersperse + (map (lambda (part) + (cond ((symbol? part) (symbol->string part)) + ((number? part) (number->string part)) + (else (fail)))) + parts) + "."))) + (_ (fail)))) + +(define (locate-library name loc) ; must be stripped + ;;XXX scan include-path? + (let* ((name2 (parse-library-name name loc)) + (sname2 (symbol->string name2))) + (or (file-exists? (string-append sname2 ".import.so")) + (file-exists? (string-append sname2 ".import.scm")) + (extension-information name2)))) + +(define (process-cond-expand clauses) + ;; returns list of forms of successful clause or #f + (define (fail msg . args) + (apply + syntax-error + msg + (append args + `((cond-expand + ,@(map (lambda (clause) (cons (car clause) '(...))) clauses)))))) + (define (check test) + (match test + ('else #t) + (('and tests ...) (every check tests)) + (('or tests ...) (any check tests)) + (('library name) (locate-library name 'cond-expand)) + ((? symbol? feature) (feature? feature)) + (_ (fail "invalid test expression in \"cond-expand\" form" test)))) + (let loop ((cs clauses)) + (match cs + (() (fail "no clause applies in \"cond-expand\" form")) + (((test body ...) . more) + (if (check (strip-syntax test)) + body + (loop more))) + (else (fail "invalid \"cond-expand\" form"))))) + +(define (fixup-import/export-spec spec loc) + (match spec + (((and head (or 'only 'except 'rename 'prefix)) name . more) + (cons* head (fixup-import/export-spec name loc) more)) + ((name ...) + (parse-library-name name loc)) + (_ (syntax-error loc "invalid import/export specifier" spec)))) + +(define (current-source-filename) + (or (and (feature? #:compiling) ##compiler#source-filename) + ##sys#current-source-filename)) + +(define (read-forms filename ci?) + (read-file + (if (absolute-pathname? filename) + filename + (make-pathname (current-source-filename) filename)) + (lambda (port) + (parameterize ((case-sensitive ci?)) + (read port))))) + +(define (parse-library-definition form dummy-export) ; expects stripped syntax + (match form + ((_ name decls ...) + (let ((real-name (parse-library-name name 'define-library))) + (define (parse-exports specs) + (map (match-lambda + ((and spec ('rename _ _)) + (syntax-error + 'define-library + "\"rename\" export specifier currently not supported" + name)) + ((? symbol? exp) + `(export ,exp)) + (spec (syntax-error 'define-library "invalid export specifier" spec name))) + specs)) + (define (parse-imports specs) + (map (lambda (spec) + `(import ,(fixup-import/export-spec spec 'import))) + specs)) + (define (process-includes fnames ci?) + `(##core#begin + ,@(map (match-lambda + ((? string? fname) + `(##core#begin ,@(read-forms fname ci?))) + (fname (syntax-error 'include "invalid include-filename" fname))) + fnames))) + (define (process-include-decls fnames) + (parse-decls (append-map (lambda (fname) (read-forms fname #t)) fnames))) + (define (parse-decls decls) + (match decls + (() '(##core#begin)) + ((('export specs ...) . more) + `(##core#begin + ,@(parse-exports specs) + ,(parse-decls more))) + ((('import specs ...) . more) + `(##core#begin + ,@(parse-imports specs) + ,(parse-decls more))) + ((('include fnames ...) . more) + `(##core#begin + ,@(process-includes fnames #f) + ,(parse-decls more))) + ((('include-ci fnames ...) . more) + `(##core#begin + ,@(process-includes fnames #t) + ,(parse-decls more))) + ((('include-library-declarations fnames ...) . more) + `(##core#begin + ,@(process-include-decls fnames) + ,(parse-decls more))) + ((('cond-expand decls ...) . more) + (parse-decls (process-cond-expand decls))) + ((('begin code ...) . more) + `(##core#begin + (##core#begin ,@code) + ,(parse-decls more))) + (decl (syntax-error 'define-library "invalid library declaration" decl)))) + `(##core#module ,real-name ((,dummy-export)) + ;; gruesome hack: we add a dummy export for adding indirect exports + (import (rename scheme (define-syntax hidden:define-syntax))) + (import (only scheme.base import export)) ; overwrites existing "import" + (hidden:define-syntax ,dummy-export (lambda () #f)) + ,(parse-decls decls)))) + (_ (syntax-error 'define-library "invalid library definition" form)))) + +(define (register-r7rs-module name) + (let ((dummy (string->symbol (string-append (symbol->string name) "-dummy-export")))) + (put! name '##r7rs#module dummy) + dummy)) + +(set! ##sys#register-export + (let ((register-export ##sys#register-export)) + (lambda (sym mod) + (when mod + (let-values (((explist ve se) (##sys#module-exports mod))) + (and-let* ((dummy (get (##sys#module-name mod) '##r7rs#module))) + (unless (eq? sym dummy) + (cond ((memq sym explist)) + ((find (lambda (a) (and (pair? a) (eq? (car a) dummy))) explist) => + (lambda (dummylist) + (set-cdr! dummylist (cons sym (cdr dummylist)))))))) + (register-export sym mod)))))) diff --git a/r7rs.meta b/r7rs.meta index d351fcd..5854b1b 100644 --- a/r7rs.meta +++ b/r7rs.meta @@ -2,6 +2,6 @@ (author "The Chicken Team") (category lang-exts) (license "BSD") - (depends) + (depends matchable make numbers) (test-depends test) (foreign-depends)) diff --git a/r7rs.scm b/r7rs.scm index 619c2aa..9d731bb 100644 --- a/r7rs.scm +++ b/r7rs.scm @@ -1,29 +1,18 @@ -(module r7rs +(module r7rs (define-library) -( - ;; Exception handling - guard - ;; Exceptions - with-exception-handler - raise - raise-continuable - error-object? - error-object-message - error-object-irritants - read-error? - file-error? - ;; Input & output - call-with-port - close-port - eof-object - ;; System interface - command-line - exit - emergency-exit - ) + (import scheme) ;XXX except ... + (import chicken) ;XXX except ... + (import numbers) + (import scheme.base) + (include "scheme.base-interface.scm") -(import chicken scheme foreign) -(use srfi-13) + (begin-for-syntax + (require-library r7rs-compile-time numbers)) + (import-for-syntax r7rs-compile-time matchable) + +(use srfi-13) ;XXX get rid of this! (used for "string-downcase"?) + +(require-library scheme.base) (define (read-asserted-ci-symbol port valid-symbols error-message) (let ((sym (##sys#read port ##sys#default-read-info-hook))) @@ -44,185 +33,17 @@ (else (old-hook char port)))))) ;;; -;;; 4.2.7. Exception handling -;;; - -;; guard & guard-aux copied verbatim from the draft. -(define-syntax guard - (syntax-rules () - ((guard (var clause ...) e1 e2 ...) - ((call/cc - (lambda (guard-k) - (with-exception-handler - (lambda (condition) - ((call/cc - (lambda (handler-k) - (guard-k - (lambda () - (let ((var condition)) - (guard-aux - (handler-k - (lambda () - (raise-continuable condition))) - clause ...)))))))) - (lambda () - (call-with-values - (lambda () e1 e2 ...) - (lambda args - (guard-k - (lambda () - (apply values args))))))))))))) - -(define-syntax guard-aux - (syntax-rules (else =>) - ((guard-aux reraise (else result1 result2 ...)) - (begin result1 result2 ...)) - ((guard-aux reraise (test => result)) - (let ((temp test)) - (if temp - (result temp) - reraise))) - ((guard-aux reraise (test => result) - clause1 clause2 ...) - (let ((temp test)) - (if temp - (result temp) - (guard-aux reraise clause1 clause2 ...)))) - ((guard-aux reraise (test)) - (or test reraise)) - ((guard-aux reraise (test) clause1 clause2 ...) - (let ((temp test)) - (if temp - temp - (guard-aux reraise clause1 clause2 ...)))) - ((guard-aux reraise (test result1 result2 ...)) - (if test - (begin result1 result2 ...) - reraise)) - ((guard-aux reraise - (test result1 result2 ...) - clause1 clause2 ...) - (if test - (begin result1 result2 ...) - (guard-aux reraise clause1 clause2 ...))))) - -;;; -;;; 6.11. Exceptions -;;; - -(define-values (with-exception-handler raise raise-continuable) - (let ((exception-handlers - (let ((lst (list ##sys#current-exception-handler))) - (set-cdr! lst lst) - lst))) - (values - ;; with-exception-handler - (lambda (handler thunk) - (dynamic-wind - (lambda () - (set! exception-handlers (cons handler exception-handlers)) - (set! ##sys#current-exception-handler handler)) - thunk - (lambda () - (set! exception-handlers (cdr exception-handlers)) - (set! ##sys#current-exception-handler (car exception-handlers))))) - ;; raise - (lambda (obj) - (with-exception-handler - (cadr exception-handlers) - (lambda () - ((cadr exception-handlers) obj) - ((car exception-handlers) - (make-property-condition - 'exn - 'message "exception handler returned" - 'arguments '() - 'location #f))))) - ;; raise-continuable - (lambda (obj) - (with-exception-handler - (cadr exception-handlers) - (lambda () - ((cadr exception-handlers) obj))))))) - -(define error-object? condition?) -(define error-object-message (condition-property-accessor 'exn 'message)) -(define error-object-irritants (condition-property-accessor 'exn 'arguments)) - -(define-values (read-error? file-error?) - (let ((exn? (condition-predicate 'exn)) - (i/o? (condition-predicate 'i/o)) - (file? (condition-predicate 'file)) - (syntax? (condition-predicate 'syntax))) - (values - ;; read-error? - (lambda (obj) - (and (exn? obj) - (or (i/o? obj) ; XXX Not fine-grained enough. - (syntax? obj)))) - ;; file-error? - (lambda (obj) - (and (exn? obj) - (file? obj)))))) - -;;; -;;; 6.13. Input and Output +;;; 5.6.1. Libraries ;;; -(define (call-with-port port proc) - (dynamic-wind void (lambda () (proc port)) (lambda () (close-port port)))) - -(define (close-port port) - (cond ((input-port? port) - (close-input-port port)) - ((output-port? port) - (close-output-port port)) - (else - (error 'close-port "not a port" port)))) - -(define (eof-object) #!eof) - -;;; -;;; 6.14. System interface. -;;; - -;; Should these go in a separate module (process-context)? - -(define command-line - (let ((command-line #f) - (arguments (command-line-arguments))) - (lambda () - (unless command-line - (set! command-line (cons (program-name) arguments))) - command-line))) - -(define (->exit-status obj) - (cond ((integer? obj) obj) - ((eq? obj #f) 1) - (else 0))) - -(define exit - (case-lambda - (() - (exit 0)) - ((obj) - (##sys#cleanup-before-exit) - ;; ##sys#dynamic-unwind is hidden, have to unwind manually. - ; (##sys#dynamic-unwind '() (length ##sys#dynamic-winds)) - (let unwind () - (unless (null? ##sys#dynamic-winds) - (let ((after (cdar ##sys#dynamic-winds))) - (set! ##sys#dynamic-winds (cdr ##sys#dynamic-winds)) - (after) - (unwind)))) - (##core#inline "C_exit_runtime" (->exit-status obj))))) +(define-syntax define-library + (er-macro-transformer + (lambda (x r c) + (match (strip-syntax x) + ((_ name decls ...) + (let ((dummy (register-r7rs-module (parse-library-name name 'define-library)))) + (parse-library-definition x dummy))) + (_ (syntax-error 'define-library "invalid library definition" x)))))) -(define emergency-exit - (case-lambda - (() - (emergency-exit 0)) - ((obj) - (##sys#cleanup-before-exit) - ((foreign-lambda void "_exit" int) (->exit-status obj))))) ) diff --git a/r7rs.setup b/r7rs.setup index 8046c71..1f2585f 100644 --- a/r7rs.setup +++ b/r7rs.setup @@ -1,7 +1,37 @@ -(compile -d0 -O2 -J -s r7rs.scm) -(compile -d0 -O2 -s r7rs.import.scm) +(use make) + + +(define scheme-modules + '("base" "process-context")) ;XXX + +(make (("r7rs-compile-time.so" ("r7rs-compile-time.scm" "r7rs-compile-time-module.scm") + (compile -s -O3 -d1 r7rs-compile-time-module.scm -J -o r7rs-compile-time.so) + (compile -s -O3 -d0 r7rs-compile-time.import.scm)) + ("scheme.base.so" ("scheme.base.scm" "scheme.base-interface.scm") + (compile -s -O3 -d1 scheme.base.scm -J) + (compile -s -O3 -d0 scheme.base.import.scm))) + '("r7rs-compile-time.so" "scheme.base.so")) + +(for-each + (lambda (m) + (let* ((mname (string-append "scheme." m)) + (so (string-append mname ".so")) + (scm (string-append mname ".scm"))) + (make/proc (list (list so (list scm) + (lambda () + (compile -s -O3 -d1 ,scm -J) + (compile -s -O3 -d0 ,(string-append mname ".import.scm"))))) + (list so)))) + scheme-modules) + +(make (("r7rs.so" ("r7rs.scm" "scheme.base-interface.scm") + (compile -s -O3 -d0 r7rs.scm -J) + (compile -s -O3 -d0 r7rs.import.scm)))) (install-extension 'r7rs - '("r7rs.so" "r7rs.import.so") + '("r7rs.so" "r7rs.import.so" + "r7rs-compile-time.so" "r7rs-compile-time.import.so" + "scheme.base.so" "scheme.base.import.so" + "scheme.process-context.so" "scheme.process-context.import.so") '((version "0.0.1"))) diff --git a/scheme.base-interface.scm b/scheme.base-interface.scm new file mode 100644 index 0000000..91c0c0b --- /dev/null +++ b/scheme.base-interface.scm @@ -0,0 +1,183 @@ +(export + #| + * + - / + <= < >= = > + abs + and + append + apply + assoc assq assv + begin + binary-port? + boolean? boolean=? + bytevector-append bytevector-copy bytevector-copy! + bytevector-length bytevector-u8-ref bytevector-u8-set! + bytevector? + car cdr caar cadr cdar + call-with-current-continuation call/cc + |# + call-with-port + #| + call-with-values + case + ceiling + char-ready? + char->integer integer->char + char<? char>? char<=? char>=? + char? + close-input-port close-output-port close-port + complex? + cond + |# + cond-expand + #| + cons + current-input-port current-output-port current-error-port + define + define-record-type + define-syntax + define-values + denominator numerator + do + dynamic-wind + else + |# + eof-object + #| + eof-object? + eq? eqv? equal? + error + |# + error-object-irritants error-object-message + error-object? + #| + even? odd? + exact inexact + exact-integer-sqrt + exact-integer? + exact? inexact? + expt + features + |# + file-error? + #| + floor floor-quotient floor-remainder + floor/ + flush-output-port + for-each + gcd lcm + get-output-bytevector + get-output-string + |# + guard + #| + if + import + ;; import-for-syntax XXX should we? + include include-ci + input-port-open? output-port-open? + input-port? output-port? + integer? + lambda + length + let let* + letrec letrec* + let-values let*-values + let-syntax + letrec-syntax + library ; for "cond-expand" + list + list-copy + list-ref list-set! + list-tail + list? + make-bytevector + make-list + make-parameter + make-string + make-vector + map + max min + member memq memv + modulo remainder + negative? positive? + newline + not + null? + number->string string->number + number? + open-input-bytevector open-output-bytevector + open-input-string open-output-string + pair? + parameterize + peek-char + peek-u8 + port? + procedure? + quasiquote + quote + quotient remainder + |# + raise raise-continuable + #| + rational? + rationalize + read-bytevector read-bytevector! + read-char + |# + read-error? + #| + read-line + read-string + read-u8 + real? + reverse + round + set! + set-car! set-cdr! + square + string + string->list list->string + string->utf8 utf8->string + string->symbol symbol->string + string->vector + string-append + string-copy string-copy! + string-fill! + string-for-each + string-length + string-map + string-ref string-set! + string=? string<? string>? string<=? string>=? + string? + substring + symbol=? + symbol? + syntax-error + ;syntax-rules XXX??? + textual-port? + truncate + truncate-quotient truncate-remainder + truncate/ + u8-ready? + unless + unquote unquote-splicing + values + vector + vector-append + vector-copy vector-copy! + vector-for-each + vector-length + vector-map + vector-ref vector-set! + when + |# + with-exception-handler + #| + write-bytevector + write-char + write-string + write-u8 + zero? + |# + ) diff --git a/scheme.base.scm b/scheme.base.scm new file mode 100644 index 0000000..1e03416 --- /dev/null +++ b/scheme.base.scm @@ -0,0 +1,164 @@ +(module scheme.base () + +(import (except scheme cond-expand)) +(import (except chicken with-exception-handler raise)) + +(include "scheme.base-interface.scm") + +(begin-for-syntax (require-library r7rs-compile-time)) +(import-for-syntax r7rs-compile-time) + + +;;; +;;; 4.2.1. Conditionals +;;; + +(define-syntax cond-expand + (er-macro-transformer + (lambda (x r c) + (process-cond-expand (cdr x))))) + + +;;; +;;; 4.2.7. Exception handling +;;; + +;; guard & guard-aux copied verbatim from the draft. +(define-syntax guard + (syntax-rules () + ((guard (var clause ...) e1 e2 ...) + ((call/cc + (lambda (guard-k) + (with-exception-handler + (lambda (condition) + ((call/cc + (lambda (handler-k) + (guard-k + (lambda () + (let ((var condition)) + (guard-aux + (handler-k + (lambda () + (raise-continuable condition))) + clause ...)))))))) + (lambda () + (call-with-values + (lambda () e1 e2 ...) + (lambda args + (guard-k + (lambda () + (apply values args))))))))))))) + +(define-syntax guard-aux + (syntax-rules (else =>) + ((guard-aux reraise (else result1 result2 ...)) + (begin result1 result2 ...)) + ((guard-aux reraise (test => result)) + (let ((temp test)) + (if temp + (result temp) + reraise))) + ((guard-aux reraise (test => result) + clause1 clause2 ...) + (let ((temp test)) + (if temp + (result temp) + (guard-aux reraise clause1 clause2 ...)))) + ((guard-aux reraise (test)) + (or test reraise)) + ((guard-aux reraise (test) clause1 clause2 ...) + (let ((temp test)) + (if temp + temp + (guard-aux reraise clause1 clause2 ...)))) + ((guard-aux reraise (test result1 result2 ...)) + (if test + (begin result1 result2 ...) + reraise)) + ((guard-aux reraise + (test result1 result2 ...) + clause1 clause2 ...) + (if test + (begin result1 result2 ...) + (guard-aux reraise clause1 clause2 ...))))) + + +;;; +;;; 6.11. Exceptions +;;; + +(define-values (with-exception-handler raise raise-continuable) + (let ((exception-handlers + (let ((lst (list ##sys#current-exception-handler))) + (set-cdr! lst lst) + lst))) + (values + ;; with-exception-handler + (lambda (handler thunk) + (dynamic-wind + (lambda () + (set! exception-handlers (cons handler exception-handlers)) + (set! ##sys#current-exception-handler handler)) + thunk + (lambda () + (set! exception-handlers (cdr exception-handlers)) + (set! ##sys#current-exception-handler (car exception-handlers))))) + ;; raise + (lambda (obj) + (with-exception-handler + (cadr exception-handlers) + (lambda () + ((cadr exception-handlers) obj) + ((car exception-handlers) + (make-property-condition + 'exn + 'message "exception handler returned" + 'arguments '() + 'location #f))))) + ;; raise-continuable + (lambda (obj) + (with-exception-handler + (cadr exception-handlers) + (lambda () + ((cadr exception-handlers) obj))))))) + +(define error-object? condition?) +(define error-object-message (condition-property-accessor 'exn 'message)) +(define error-object-irritants (condition-property-accessor 'exn 'arguments)) + +(define-values (read-error? file-error?) + (let ((exn? (condition-predicate 'exn)) + (i/o? (condition-predicate 'i/o)) + (file? (condition-predicate 'file)) + (syntax? (condition-predicate 'syntax))) + (values + ;; read-error? + (lambda (obj) + (and (exn? obj) + (or (i/o? obj) ; XXX Not fine-grained enough. + (syntax? obj)))) + ;; file-error? + (lambda (obj) + (and (exn? obj) + (file? obj)))))) + + +;;; +;;; 6.13. Input and Output +;;; + +(define (call-with-port port proc) + (dynamic-wind void (lambda () (proc port)) (lambda () (close-port port)))) + +(define (close-port port) + (cond ((input-port? port) + (close-input-port port)) + ((output-port? port) + (close-output-port port)) + (else + (error 'close-port "not a port" port)))) + +(define (eof-object) #!eof) + + +) diff --git a/scheme.process-context.scm b/scheme.process-context.scm new file mode 100644 index 0000000..26d9a22 --- /dev/null +++ b/scheme.process-context.scm @@ -0,0 +1,56 @@ +(module scheme.process-context (command-line + exit + emergency-exit + ;;XXX + ;get-environment-variable + ;get-environment-variables + ) + + (import scheme + (rename chicken (exit chicken:exit)) + foreign) + +;;; +;;; 6.14. System interface. +;;; + +;; Should these go in a separate module (process-context)? + +(define command-line + (let ((command-line #f) + (arguments (command-line-arguments))) + (lambda () + (unless command-line + (set! command-line (cons (program-name) arguments))) + command-line))) + +(define (->exit-status obj) + (cond ((integer? obj) obj) + ((eq? obj #f) 1) + (else 0))) + +(define exit + (case-lambda + (() + (chicken:exit 0)) + ((obj) + (##sys#cleanup-before-exit) + ;; ##sys#dynamic-unwind is hidden, have to unwind manually. + ; (##sys#dynamic-unwind '() (length ##sys#dynamic-winds)) + (let unwind () + (unless (null? ##sys#dynamic-winds) + (let ((after (cdar ##sys#dynamic-winds))) + (set! ##sys#dynamic-winds (cdr ##sys#dynamic-winds)) + (after) + (unwind)))) + (##core#inline "C_exit_runtime" (->exit-status obj))))) + +(define emergency-exit + (case-lambda + (() + (emergency-exit 0)) + ((obj) + (##sys#cleanup-before-exit) + ((foreign-lambda void "_exit" int) (->exit-status obj))))) + +) diff --git a/tests/run.scm b/tests/run.scm index ccb0a2b..e33838a 100644 --- a/tests/run.scm +++ b/tests/run.scm @@ -3,7 +3,7 @@ (define (read-from-string s) (with-input-from-string s read)) -(test-group "long boolean literalsa" +(test-group "long boolean literals" (test #t (read-from-string "#t")) (test #f (read-from-string "#f")) (test #t (read-from-string "#true"))Trap