IppClub / IppClub/YueScript

Macros in 'when' clause don't capture variables

Open
#253 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Lua
Stars
613
Forks
45
PR merge metrics
No merged PRs in 30d

Description

I want to have something at least resembling algebraic data types in Yuescript - these are called enums in Rust, variants in OCaml, tagged unions in C. These are types that you can construct and they carry the underlying variant and some fields that the variant has. An example of this in Rust can be seen here: https://doc.rust-lang.org/rust-by-example/custom_types/enum.html

To that end I've been trying to use existing pattern matching functionality and macros to get this behavior. For the sake of example, let's say we want to encode variants of an enum as an array ['VariantName', ...fields], for example:

lang =
    BinOp: (lhs, op, rhs) => ['BinOp', lhs, op, rhs]
    Var: (name, expr) => ['Var', name, expr]
    Const: (val) => ['Const', val]

Then I'd like to do pattern matching on different variants, but have a bit nicer syntax:

macro binop = (x,y,z) -> {
    code: "['Binop', #{x}, #{y}, #{z}]"
    type: "yue"
}

switch e
    when $binop a,b,c
        print "foo"

But this compiles to:

if {
	'Binop',
	a,
	b,
	c
} == e then
	return print("foo")
end

But this isn't what I want, as it does not assign a, b, c variables for me to use inside the 'when' block. If I use the expected output of the macro directly:

switch e
    when ['Binop', a, b, c]
        print "bar"

I get what I expected - a, b, c are assigned values of e[2..4]:

local _type_0 = type(e)
local _tab_0 = "table" == _type_0 or "userdata" == _type_0
if _tab_0 then
	local a = e[2]
	local b = e[3]
	local c = e[4]
	if 'Binop' == e[1] and a ~= nil and b ~= nil and c ~= nil then
		return print("bar")
	end
end

This behavior is a bit unexpected, seems like macro evaluation happens at some later stage of compilation so instead of variable capture I get table comparison. Is this a bug or working as intended?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the macro-expansion path for switch/when pattern matching and compare it with the direct array-pattern example. Reproduce the shown $binop case and trace whether identifiers are bound after expansion; done means macro-based patterns capture a, b, and c like the direct pattern, or the behavior is documented as intended.

Written by the indexing model from the issue text.

Assessment

Tech stack
lua
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.