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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lua/Text Macros cant be at the end of a block due to implicit return #178

Open
Le0Developer opened this issue Nov 10, 2024 · 6 comments
Open

Comments

@Le0Developer
Copy link

macro no_return = -> {code: "", type: "lua"}

print 123

$no_return

Fails to compile with

5: lua macro can only be placed where block macro is allowed
$no_return
^

This keeps popping up and annoying me

@pigpigyyy
Copy link
Member

pigpigyyy commented Nov 18, 2024

Apologies for the delay—I thought I had already replied to this issue. The simplest way to resolve this is to add either nil or return as the last line of your source file after the macro code, like this:

macro no_return = -> {code: "", type: "lua"}

print 123

$no_return

nil -- or `return`

This is because Yue implicitly adds a return keyword to the last expression in the file. The compiler cannot determine if the code generated by Lua macros is still a valid expression to be returned, so explicitly ending with nil or return can ensure correctness.

@SkyyySi
Copy link

SkyyySi commented Jan 29, 2025

IMO, it would be best to simply let the programmer explicitly tell the compiler what they want:

macro foo = () ->
    { code: "123", type: "lua", expression: true }

--- Can be used as a statement despite `123` being an expression,
--- and despite Lua not normally allowing a usage of expressions
--- as statement (except for function calls)
$foo()

This way, expressions could be wrapped in an IIFE to ensure that they are always syntactically valid:

((function(...)
    return 123
end)(...))

Alternatively, something like { unchecked: true, ... } could be used as a more general "trust me, I know what I'm doing, just paste my code".

@MTadder
Copy link
Contributor

MTadder commented Jan 29, 2025

how about

__expression: true

?

@SkyyySi
Copy link

SkyyySi commented Jan 29, 2025

Thinking about it again, the expression-option might best be delegated to a sub-table called language_options or langopts or something like that. After all, it's specific to Lua output and doesn't really make sense as a shared option.
So it would look like this:

macro foo = () ->
    {
        code: "123"
        type: "lua"
        langopts: {
            expression: true
        }
    }

Note: I understand that Yuescript is focused on concise syntax, but in this case (of macros that produce uncheckable / "unsafe" code), being more explicit would probably be for the best. With this more verbose version, you're given plenty of time to think about whether you really want to / should do this, or if you're just making your code unnecessarily complex. Not that I have any experience with that 🫠

@pigpigyyy
Copy link
Member

Speaking of concise syntax, I'm considering leveraging a Lua parser to determine whether the user’s code is an expression or a statement. This shouldn't require much effort. Once that's in place, maybe the Lua inserter macro could be implemented as a built-in feature.

pigpigyyy added a commit that referenced this issue Jan 30, 2025
@pigpigyyy
Copy link
Member

pigpigyyy commented Jan 31, 2025

Made a new commit supporting using Lua inserter macro to insert either expression or statement.

macro foo = -> code: "tb:func(123)", type: "lua"

f = ->
  x = $foo\bar 456 -- as expression
  $foo -- as expression with implicit return

f1 = ->
  $foo! -- as statement
  return

compiles to:

local f
f = function()
  local x = (tb:func(123)):bar(456)
  return (tb:func(123))
end
local f1
f1 = function()
  do
tb:func(123)
  end
  return
end

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

4 participants