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
parent
7e3f3f0b0a
commit
beb561eeff
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue