Record in the current environment that a function closes over a variable. When a function has and environment that closes over a variable this is recorded on the function. Additionally current values are recorded rather than being forgotten.
When calling this function, it creates a new ClosureId. Any objects or functions generated by the function carry the closure id.
This is done in the same way as structural generics. For example, for type arguments we have Array<number>, for closure arguments we have func<#closure 1> etc (all held internally, syntax just for illustration. (this is similar to .create_new_object)
Additionally the initial values are specialized and put onto the current closure state, which (like regular variable properties) is on environment.facts (not the function)
When calling a closure this id is known and passed down when reading variables and setting variables. This id changes the value of the value under key (closure_id, reference) (rather than just reference)
I made this process up. I am not quite sure how engines actually implement it. With Ezno and things like events I am trying to abstract things and reduce overhead. Running the exact same things done in synthesis every function call is off the table... And these need a few fix see follow up issue #56
This PR also tidies some stuff up
Printing uses a single buffer and catches cycles
Moved some files and functions around (got rid of an intermediate call_... function)
No idea what rustfmt is doing, seems to have broken recently (this PR doesn't change parser and it is reporting new formatting issues there). Will try and figure out later
This PR implements the basics of closures.
The additions are shown in these new specification tests https://github.com/kaleidawave/ezno/blob/4591ca369cc8b0e7715f560759a48bd34b2a725d/checker/specification/specification.md?plain=1#L223-L284
This PR does several things to support them:
ClosureId
. Any objects or functions generated by the function carry the closure id.Array<number>
, for closure arguments we havefunc<#closure 1>
etc (all held internally, syntax just for illustration. (this is similar to.create_new_object
)environment.facts
(not the function)id
is known and passed down when reading variables and setting variables. This id changes the value of the value under key(closure_id, reference)
(rather than justreference
)This PR also tidies some stuff up
call_...
function)any
stuff around parent variables