Closed jitwit closed 4 years ago
My feeling is that the top
tag shouldn't be necessary, but it seems to keep things simple, so I'd go ahead and keep it.
When the define bodies reference earlier ones, the symbol of the referenced variable is what appears in the result.
For the symbol of the referenced variable, do you mean the global variable index?
Do you have an example of what could go wrong?
If it's something like
(define foo (cons (lambda () (bar 'foo)) '()))
(define bar (lambda (foo) foo))
that shouldn't be a problem, since we have defined all our variables before anyone made a call to bar
.
If it's something like
(define a (cons 'a b))
(define b (cons 'b a))
then I'm pretty sure that's not allowed in Scheme.
Sorry, should have given examples about what goes wrong.
(define f cons)
(define x (f y 12))
(define y "abc")
(define (do-test)
(write x) (newline))
prints out (y . 12)
instead of ("abc" . 12)
, when x
's definition appears before y
's.
Edit: nevermind about the commented out w
, you were right, it works!
prints out
(y . 12)
instead of("abc" . 12)
, whenx
's definition appears beforey
's.
Ah, so that looks like it's illegal. Just to make sure, I ran it in Chez Scheme and it throws an exception when you try to define x
saying that y
is not bound. I think we need to be sure to do something similar here.
Good news! Could the check be done by putting some extra initialization/checking in the part of the start
function for setting up the top level definitions?
I'd probably do the checking in the parsing phase, where we're adding a variable to the environment. It looks like we'll need some way to split the bodies of top-level function from the top-level values, since the environment is different for those two cases. The bodies of top-level functions can see all the top level defines, but the top-level values can only see the defines that have come earlier.
Here's a version that's linear in export list size, but I'm not 100% sure it's preferable to the simpler current one... Maybe I'm missing a more natural way?
(define (%parse-definitions definitions env-whole env-part)
(if (null? definitions)
'()
(let ((def (car definitions)))
(if (function-definition? def)
(cons (define-function def env-whole)
(%parse-definitions (cdr definitions) env-whole env-part))
(let ((env-part (memp (lambda (n.d)
(eq? (definition-name def) (car n.d)))
env-part)))
(cons (define-value def env-part)
(%parse-definitions (cdr definitions) env-whole env-part)))))))
(define (parse-definitions definitions env)
(reverse (%parse-definitions (reverse definitions) env env))
;; (map (lambda (fn) (parse-definition fn env)) definitions)
)
The added test passes but there are a few issues. The
define
s behave likelet*
and the commented out test variable fails in finding free variables.I added a
top
tag to distinguish the top level variables. Maybe this isn't the right approach?When the define bodies reference earlier ones, the symbol of the referenced variable is what appears in the result. I'm not sure, but I'm guessing something like adding a level of indirection to the global variables ora sorting them based on references might be necessary?