-
Notifications
You must be signed in to change notification settings - Fork 40
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’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Backcalls in macros get incorrectly compiled #139
Comments
The two problems you mentioned is currently intended. The macro expanded in the middle of a code block, will be treated as a do
do -- without variable scoping
() <- async_fn()
print()
() <- async_fn()
print() It is the problem caused by the compiler implemetation that macros are expanded while translating each line of statement. I think this implementation should be changed to expanding macros before translating any code to Lua code. And the problem of the redundant semicolon is that Yuescript is adding semicolon to reduce the ambiguity caused by Lua multiline expressions. -- the valid code in Lua
func()
(args)()
-- is the same as
func()(args)()
-- to make them two lines of statements you can make use a semicolon
func();
(args)() Currently Yuescript is blindly adding semicolon when it sees a new line started with a left parenthe. Maybe it should check and add semicolons after all codes translated to Lua. |
I agree. Macros getting evaluated and expanded before compilation would be both more intuitive and more useful, I think. I personally only use them when a function would be too limiting (which is rather rare in Yuescript), and having them produce their own isolated blocks severely limits their usefulness for me. Additionally, I think it should be outlined in the documentation when exactly macros get evaluated and expanded, especially if the current behavior were to be kept. |
I think it is better to explicitly write the Yuescript statement that affect the rest codes in the same scope, like macro await = (call, body) ->
object, method, args = call::match([[([a-zA-Z_][a-zA-Z0-9_]*)\([a-zA-Z_][a-zA-Z0-9_]*)%((.*)%)]])
return "
(_, __async_result) <- #{object}::#{method}_async(#{args}, nil)
#{object}::#{method}_finish(__async_result)
#{body::sub(5)\gsub '\n\t', '\n'}
"
do
<- $await output_stream::write("foo", "bar")
print 123
if cond
func 456 compiles to: do
return output_stream:write_async("foo", "bar", nil, function(_, __async_result)
output_stream:write_finish(__async_result)
print(123)
if cond then
return func(456)
end
end)
end In this new macro version, the expressions passed as macro function arguments are being parsed and reformatted to code strings, instead of in the former implementation they are just copy-pasted as pure text. In this manner the backcall function can be passed as code of normal function. <- $func
print 123 now works the same as $func ->
print 123 |
I like the idea of automatically re-formatting the code. But I'd actually take that further: Similarly to |
When defining a macro that 'returns' a backcall, it will not produce the expected code.
The given Yuescript code:
The above will compile to the following Lua code:
I would expect the macro to produce the same code as the written-out version below it.
Just in the case that a more real-world example is useful: I stumbled across this issue when using this macro:
It's intended for working with Gio, a library for asynchronous IO https://docs.gtk.org/gio/method.OutputStream.write_async.html
Each successive
$await
call is intended to become nested in the previous backcall. However, what happens instead is that only the#{object}::#{method}_finish(__async_result)
gets nested, then the block ends.The text was updated successfully, but these errors were encountered: