Skip to content

Implemented n3792#132

Open
aalmkainzi wants to merge 7 commits intofuhsnn:mainfrom
aalmkainzi:va-slice
Open

Implemented n3792#132
aalmkainzi wants to merge 7 commits intofuhsnn:mainfrom
aalmkainzi:va-slice

Conversation

@aalmkainzi
Copy link
Copy Markdown

Hi.

This is my attempt at implementing n3792.
Some things were not obvious to me in preprocess.c, so I may have written some redundant code, or incorrect.

But it passes all examples in the paper.

I am not necessarily suggesting that this PR should be merged as-is, but I wanted to share the idea in case it is useful.

@fuhsnn
Copy link
Copy Markdown
Owner

fuhsnn commented Mar 24, 2026

The proposal needs to be clearer with what happens with start/len of __VA_SLICE__, the current wording only says "After macro expansion", while other parts seem to imply "After macro argument substitution, the start/len arguments individually go through place-marker removal and rescanned for macro expansion", without clear specification there might be ambiguity like:

#define FOO 1
#define f(FOO, A, B, ...) __VA_SLICE__(FOO, A##B, ...
f(2, F, OO, ...)

#define BAR 1,2
#define f2(BAR, ...) __VA_SLICE__(BAR, 3, ...) // should start/len be 1,2?
f2(BAR, ...)

from playing with it I think your implementation does this part mostly right, but are the global defines and _INTERNAL() dance necessary? The proposal does describe __VA_COUNT__, __VA_SLICE__ as function-like macros, however it looks like they are intended to be replacement-list-only like __VA_OPT__, which isn't called a function-like macro in the current standard.

This looks like building block for some arcane recursive magic, would be nice to have a more complex example of what the author have in mind to test on.

@aalmkainzi
Copy link
Copy Markdown
Author

I agree that it should be similar to __VA_OPT__ where it can only be used inside variadic macros, and it slices from __VA_ARGS__ implicitly. Same for __VA_COUNT__

The reason I made global defines like __VA_SLICE_INTERNAL__ is mainly for ease of implementation.

__VA_SLICE__ is useful for indexing into a variadic list, the reason I implemented it is I have another idea that relies on such mechanism.

@aalmkainzi
Copy link
Copy Markdown
Author

aalmkainzi commented Mar 25, 2026

I think I got a version of my idea working: https://github.com/aalmkainzi/slimcc/tree/repeat

it's a repeat macro, works like this:

__REPEAT__(100, a) // this pastes `a` 100 times

Using __REPEAT__ and __VA_SLICE__, I can make a FOREACH macro:

#define FOREACH_(base, m, ...) \
__REPEAT__(__VA_COUNT__(__VA_ARGS__), m(__VA_SLICE__(__COUNTER__ - base, 1, __VA_ARGS__)))

#define FOREACH(m, ...) \
FOREACH_(__COUNTER__, m, __VA_ARGS__)

FOREACH(macro, a,b,c,d,e,f,g)

@fuhsnn
Copy link
Copy Markdown
Owner

fuhsnn commented Mar 25, 2026

Ah, the __COUNTER__ trick is cool, you're one of those wizards!

For repeating IMO it'd be more flexible with a new dedicated builtin, like:

__REPEAT__( fn(foo,  ARG1, bar, ARG2); ) : (ARG1, ARG2) = ((a, b),(c, d))
// expands to
fn(foo, a, bar, b);
fn(foo, c, bar, d);

@aalmkainzi
Copy link
Copy Markdown
Author

aalmkainzi commented Mar 26, 2026

yeah maybe it could be just a built-in mechanism, but I think allowing constant expressions to control va args can be powerful.

We can set the len of a slice to 0 conditionally:

#define FOREACH_(base, m, ...) \
__REPEAT__(__VA_COUNT__(__VA_ARGS__), m(__COUNTER__ - base, __VA_ARGS__))

#define FOREACH(m, ...) \
FOREACH_(__COUNTER__, m, __VA_ARGS__)

#define every_other(idx, ...) \
__VA_SLICE__(idx, idx & 1, __VA_ARGS__)

FOREACH(every_other, 1,2,3,4,5,6,7,8,9,10)
// expands to 1 3 5 7 9

#define only_odd(idx, ...) \
__VA_SLICE__(idx, __VA_SLICE__(idx,1,__VA_ARGS__) & 1, __VA_ARGS__)

FOREACH(only_odd, 7,2,10,1,5,9,3,8,6,4)
// expands to 7 1 5 9 3

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

Successfully merging this pull request may close these issues.

2 participants