rebirth: Extend `cond-expand' to dynamically support features

This will crudely detect "features" by seeing if the requested feature is a
definition.  Ideally that definition would be a procedure, but we don't
check for that.  This does what we need it to do.

Obviously this is a poor implementation and will not persist past Rebirth.

* build-aux/bootstrap/rebirth.scm (es:defined?): New procedure.
  (expand-cond-expand): New procedure.  If first Rebirth pass, only support
    `string->es' and `else'; otherwise detect features using `es:defined?'.
  (fnmap)[cond-expand]: Use it.
master
Mike Gerwitz 2017-12-11 22:36:22 -05:00
parent 0b0003578b
commit 0a1e530a76
Signed by: mikegerwitz
GPG Key ID: 8C917B7F5DC51BA2
1 changed files with 43 additions and 7 deletions

View File

@ -71,6 +71,11 @@
;; for brevity
(string->es "const _truep = x => x !== false")
;; intended for whether a procedure is defined, mostly
(define (es:defined? x)
(let ((id (tname->id x)))
(string->es "eval('typeof ' + $$id) !== 'undefined'")))
(define (es:typeof x)
(string->es "typeof $$x"))
@ -628,6 +633,43 @@
"([" (%quote-maybe sexp #f) "])")))
;; Statically expand expressions based on implementation features
;;
;; Support for `cond-expand' allows Rebirth to introduce new features each
;; time that it is compiled. If matched, expressions will be evaluated as
;; if they were entered in place of the `cond-expand' itself; otherwise,
;; the entire `cond-expand' expression as a whole will be discarded.
;;
;; Birth will always discard `cond-expand' expressions unless they contain
;; an `else' clause, which permits us to compile on the first pass without
;; error.
(define (expand-cond-expand args)
(if (pair? args)
(let* ((clause (car args))
(feature (token-value (car clause)))
(body (cdr clause)))
;; now we get meta
(cond-expand
(string->es
(case feature
(("string->es" "else") (body->es body #f))
(else (if (es:defined? feature)
(body->es body #f)
(expand-cond-expand (cdr args))))))
;; if we're not yet compiled with Rebirth, then string->es will
;; not yet be available---but it _will_ be in Rebirth, so
;; compile cond-expand such that it marks it as supported
(else
(case feature
;; these two are always supported in Rebirth Lisp
(("string->es" "else") (body->es body #f))
;; keep recursing until we find something (this allows us to
;; short-circuit, most notably with "else")
(else
(expand-cond-expand (cdr args)))))))
""))
;; Function/procedure aliases and special forms
;;
;; And here we have what is probably the most grotesque part of this file.
@ -653,13 +695,7 @@
(string-append "console.error(" (map sexp->es args) ")"))
;; very primitive cond-expand
(("cond-expand")
(let* ((clause (car args))
(feature (token-value (car clause)))
(body (cdr clause)))
(case feature
(("string->es") (body->es body #f))
(else ""))))
(("cond-expand") (expand-cond-expand args))
;; output raw code into the compiled ECMAScript (what could go wrong?)
(("string->es")