rebirth: Kluge to expose procedures to macros

See code comments.  This is _not_ a long-term solution; we just need
something working in the meantime to get out of this repass cycle we're in.

* build-aux/bootstrap/rebirth.scm (cdfn-proc): Assign proc to env root.
  (es:empty-env): Add `root' property to reference self.  This allows
    easy access to the root of the prototype chain without traversing.
master
Mike Gerwitz 2018-04-04 01:22:56 -04:00
parent 7e3f3f0b0a
commit beb561eeff
Signed by: mikegerwitz
GPG Key ID: 8C917B7F5DC51BA2
1 changed files with 41 additions and 7 deletions

View File

@ -454,23 +454,52 @@
;; Compile procedure definition into an ES function definition
;;
;; This will fail if the given token is not a `define'.
;;
;; The output does something peculiar: it not only assigns to the active
;; scope, but also to the root of the environment, which has the effect of
;; making the procedure available to _everything_. The reason for this is a
;; kluge to make procedures available to macros during compilation without
;; having to wait for a rebirth repass. But this does have its issues and
;; it's important to understand that this is a temporary solution until
;; Ulambda has some level of static analysis.
;;
;; Care needs to be taken to make sure, regardless of scope, procedures of
;; the same name are not defined if used within macros, otherwise the latter
;; (again, regardless of scope) in the file will take precedence. This
;; behavior will not be observed by execution of compiled code, though,
;; because the scope will have the correct version. However, if a procedure
;; is _not_ in scope, then rather than being undefined, the one assigned to
;; root would be available.
;;
;; The generated ECMAScript is evaluated immediately to make it available to
;; macros during the compilation process.
(define (cdfn-proc t id-override)
;; e.g. (define (foo ...) body)
(let* ((dfn (cadr t))
(id (or id-override
(tname->id (token-value (car dfn)))))
(named? (not (string=? id "")))
(params (cdr dfn))
(fparams (params->es params))
(fenv (env-params params))
(body (body->es (cddr t) #t)))
;; this is the final format---each procedure becomes its own function
;; definition in ES
(string-append
"function " id "(" fparams ")\n{"
"return (function(_env){\n" fenv "\n"
body
"\n})(Object.create(_env));}"
(if (string=? id "") "" (string-append ";_env." id " = " id)))))
(let ((es (string-append
"function " id "(" fparams ")\n{"
"return (function(_env){\n" fenv "\n"
body
"\n})(Object.create(_env));}"
(if named?
(string-append ";_env." id " = " id
";_env.root." id " = " id)
""))))
;; Immediately evaluate to make available to macros during
;; compilation. See procedure notes above.
(cond-expand
(string->es
(if named? (string->es "eval($$es)"))))
es)))
;; Quote an expression
@ -845,8 +874,13 @@
"})(" env-es ");"))
;; An empty environment.
;;
;; This holds a reference to itself as `root' so that we can access the top
;; of the prototype chain easily. The reason for this is a kluge to give
;; macros access to procedures as they are defined (without having to wait
;; until the execution of a new version of rebirth). See `cdfn-proc'.
(define (es:empty-env)
"{macros:{}}")
"(function(){let o = {macros:{}}; o.root = o; return o;})()")
;; at this point, this program can parse itself and output a CST (sans