From www@deja.com Fri Jul 16 13:12:36 1999 Message-Id: <7mo3ta$pra$1@nnrp1.deja.com> From: oleg@pobox.com Subject: SRFI-0 and #+/#- "clones" as read-time applications Date: Fri, 16 Jul 1999 20:15:50 GMT Reply-To: oleg@pobox.com Keywords: external representation, printed form, reader-macro, read-time eval, Scheme, SRFI-0, cond-expand Newsgroups: comp.lang.scheme References: <7lqpvr$o6r$1@nnrp1.deja.com> Summary: Implementation of cond-expand as a read-time application X-Article-Creation-Date: Fri Jul 16 20:15:50 1999 GMT Content-Length: 5907 Status: OR As promised, this article shows that a "Feature-based conditional expansion construct" introduced in SRFI-0 can be _easily_ implemented as a read-time application. It immediately follows that a "Feature-based program configuration language", SRFI-7, can be considered a read-time application as well. The 'cond-expand' form discussed in this article is actually a bit more generic as it is no longer required to be a top-level program expression. This form can therefore be used to emulate "Feature Expressions" of Common Lisp (#+ and #- reader macros). This article hopefully shows that read-time applications are far more generic that merely a printable representation for 'records'. The reader-ctor code that implements cond-expand is fairly short; so it seems appropriate to quote it in this article (see below). The code is directly based on a grammar given in SRFI-0; the code looks rather similar to 'cond-expand' syntax rules of the reference implementation. We assume that "feature identifiers" in effect are contained in a list ALL-FEATURES. This list should either be pre-defined in a Scheme system, or otherwise defined prior to reading the code in question. For example one may use various switches, profiles, .rc files, or similar initialization code. The reader-ctor below and read-time application code hopefully demonstrate that the changes to the reader required to implement cond-expand are minor and straightforward -- contrary to what SRFI-0 assumed. Examples: printing cond-expanded code in SRFI-0, example 1... #,(cond-expand ((and srfi-1 srfi-10) (write 1)) ((or srfi-1 srfi-10) (write 2)) (else)) when features (srfi-1) are defined: (begin (write 2)) when features (srfi-10) are defined: (begin (write 2)) when features (srfi-1 srfi-10) are defined: (begin (write 1)) when features (srfi-2) are defined: (begin) cond-expanding code in SRFI-0, example 2... #,(cond-expand (command-line (define (program-name) (car (argv))))) (pp program-name) when features (command-line) are defined: (lambda () (car (argv))) when features (srfi-10 command-line) are defined: (lambda () (car (argv))) when features (srfi-10) are defined: *** ERROR IN "read-apply.scm"@140.24 -- Unfulfilled cond-expand Emulating #+ and #- of CL cond-expanding code similar to CL's "24.1.2.1.1 Examples of Feature Expressions" interpreting string: (cons #,(cond-expand (spice "Spice") ((not spice) "Lispm")) 'X) when features (spice perq) are defined: ("Spice" . X) when features (lispm) are defined: ("Lispm" . X) when features (srfi-10) are defined: ("Lispm" . X) interpreting string: '#,(cond-expand ((or spice lispm) (let ((a 3) (b 3)) (foo a))) (else (let ((a 3)) (foo a)))) when features (spice perq) are defined: (begin (let ((a 3) (b 3)) (foo a))) when features (lispm) are defined: (begin (let ((a 3) (b 3)) (foo a))) when features (srfi-10) are defined: (begin (let ((a 3)) (foo a))) interpreting string: (cons #,(cond-expand (lispm "Spice") (spice "foo") ((not (or lispm spice)) 7)) 'x) when features (spice perq) are defined: ("foo" . x) when features (lispm) are defined: ("Spice" . x) when features (srfi-10) are defined: (7 . x) The examples above are literally pasted from the output of a vcond-expand.scm validation code. Given a string of Scheme code, the validator writes it into a file (possibly wrapped into pretty-print or similar functions). The validator then gets the Gambit to read this file in specific feature environments. References: cond-expand implementation (see also below) http://pobox.com/~oleg/ftp/Scheme/cond-expand.scm The validation code http://pobox.com/~oleg/ftp/Scheme/vcond-expand.scm Reader-constructors, read-time applications, and their implementation are discussed in great detail in: http://pobox.com/~oleg/ftp/Scheme/read-time-apply.txt SRFI-0, "Feature-based conditional expansion construct" http://srfi.schemers.org/srfi-0/srfi-0.html The reader-ctor implementing cond-expand: (define-reader-ctor 'cond-expand (lambda clauses (define (feature-present? id) (memq id ALL-FEATURES)) ; Interpret ; --> ; | (and *) ; | (or *) ; | (not ) (define (eval-feature-req? feature-req) (define (eval-and-clause? req-list) (or (null? req-list) (and (eval-feature-req? (car req-list)) (eval-and-clause? (cdr req-list))))) (define (eval-or-clause? req-list) (and (not (null? req-list)) (or (eval-feature-req? (car req-list)) (eval-or-clause? (cdr req-list))))) (define (eval-not-clause? req) (not (eval-feature-req? req))) (cond ((not (pair? feature-req)) (feature-present? feature-req)) ((eq? 'and (car feature-req)) (eval-and-clause? (cdr feature-req))) ((eq? 'or (car feature-req)) (eval-or-clause? (cdr feature-req))) ((eq? 'not (car feature-req)) (apply eval-not-clause? (cdr feature-req))) (else (error "Invalid ")))) (define (do-cond-expand clauses) (cond ((null? clauses) (error "Unfulfilled cond-expand")) ((not (pair? (car clauses))) (error "Invalid ")) ((eq? 'else (caar clauses)) (or (null? (cdr clauses)) (error "else clause is not the final one")) (cons 'begin (cdar clauses))) ((eval-feature-req? (caar clauses)) (cons 'begin (cdar clauses))) (else (do-cond-expand (cdr clauses))))) (do-cond-expand clauses)))