Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Top-level comptime block is always undefined in the REPL #1195

Open
bbrk24 opened this issue Apr 27, 2024 · 2 comments
Open

Top-level comptime block is always undefined in the REPL #1195

bbrk24 opened this issue Apr 27, 2024 · 2 comments

Comments

@bbrk24
Copy link
Contributor

bbrk24 commented Apr 27, 2024

While testing a local change to comptime serialization:

$ ./dist/civet --comptime
Civet 0.7.1 REPL.  Enter a blank line to execute code.
馃惐> comptime do
...   f := &
...   f.a = 1
...   f
... 
undefined
馃惐> f := comptime do
...   f := &
...   f.a = 1
...   f
... 
undefined
馃惐> f
... 
[Function (anonymous)] { a: 1 }
馃惐> 

I would have expected the first one to also be [Function (anonymous)] { a: 1 }, but because top-level comptime blocks are deleted, there was nothing to evaluate and the result was undefined.

@edemaine
Copy link
Collaborator

edemaine commented Apr 28, 2024

This is a general question I guess for what the REPL should do for top-level statements that can be expressionized. Currently we do not expressionize, but perhaps we should in the REPL? Compare these examples:

馃惐> i .= 5
... while i < 10
...   i++
...
9
馃惐> do
...   i .= 5
...   while i < 10
...     i++
...
9
馃惐> function f
...   i .= 5
...   while i < 10
...     i++
... f()
...
[ 5, 6, 7, 8, 9 ]

Those 9 return values are kind of magical. I guess it's somehow what eval (or the Node equivalents that we use) defines as the last expression, which is different from how Civet defines it.

So I think it'd be nice to wrap the top level in an IIFE at the Civet level so the last Civet expression gets returned to the REPL. Kind of an extension of the code I added recently to handle top-level await in this way. Amusingly, I think the easy way to wrap in an IIFE is async do, because do is "too smart" and only uses braces if the block is top-level so won't be returned. So it'd be async do in all cases, and await the result, even if there aren't any top-level awaits (but just like we currently do if there were).

@edemaine
Copy link
Collaborator

edemaine commented Apr 28, 2024

Actually, I think this might be an issue worth extending beyond the REPL. There are settings where we write scripts where the last expression is meaningful. eval is one example. My SVG Tiler software is another; though exports are encouraged, mapping files can also be the last expression of the file.

To support these use cases, I propose a "civet iife" or similar directive that wraps the whole thing in an IIFE, so that the last Civet expression gets returned; effectively, nothing is at the top level anymore, so a final do or comptime or whatever will get implicitly returned. IIFEs have other use cases (isolation of variables in nonstrict mode), which is why CoffeeScript does them by default too. So it could have other applications too. But in particular the REPL could use this, I think. (Not totally sure about top-level await. Maybe that could be part of it too? Like it could be an async IIFE wrapper in that case, for environments that don't support top-level await too, and you can await the resulting promise.) Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants