Closed Rangi42 closed 1 month ago
Throwing this out there early: how would this interact with REDEF
and traditional macro definitions?
You can PURGE
and redefine macros, so REDEF mac MACRO ...
should work like that. Just like the other REDEF
s, it would only work for an undefined symbol or one that's already a macro. (REDEF
can't change types.)
I don't think the added complexity is worth saving two lines per such macro.
This feature came up in a debate about replacing current uses of EQUS
, so keep that in mind.
It wouldn't really be complex at all to implement. The parser rule is trivial:
def_macro : def_id T_POP_MACRO {
// The `endofline` is handled by `lexer_CaptureDefMacroLine`
if (lexer_CaptureDefMacroLine(&captureBody))
sym_AddMacro($1, captureBody.lineNo, captureBody.body,
captureBody.size);
}
;
And the lexer function is a simplified lexer_CaptureMacroBody
:
bool lexer_CaptureDefMacroLine(struct CaptureBody *capture)
{
startCapture(capture);
/* If the file is `mmap`ed, we need not to unmap it to keep access to the macro */
if (lexerState->isMmapped)
lexerState->isReferenced = true;
int c = EOF;
/* Capture up to a newline or EOF */
do {
c = nextChar();
} while (c != '\n' && c != '\r' && c != EOF);
if (c == '\n' || c == '\r') {
/* The newline has been captured, but we don't want it! */
if (c == '\r' && peek() == '\n') {
shiftChar();
lexerState->captureSize--;
}
lexerState->captureSize--;
}
endCapture(capture);
/* A newline puts us at the start of the line */
if (c != EOF)
lexerState->atLineStart = true;
/* Returns true if a newline terminated the body, false if it reached EOF first */
return c != EOF;
}
(Haven't tested that, but I think it would work.)
That's still some additional maintaining complexity due to more code, which I believe is not worth the associated feature. EQUS
is not meant to be an alternative to macros, it's only a more efficient shorthand whenever things line up right. (Hell, I'm pretty sure you could leverage old-style macro definition and ONE_LINER equs "MACRO\n"
to squeeze out the first line.)
Proper "in-line" macros are separate feature, which have been discussed, and I don't think EQUS
is close to a good fit for them.
I agree that EQUS
is a poor substitute for short macros, but rgbasm(5) specifically recommends it for "small one-line macros", and some projects do use it that way (like text EQUS "db 0,"
). At the very least the documentation should be updated to advise against this: its own example, DEF pusha EQUS "push af\npush bc\npush de\npush hl\n"
, ought to be a macro with a four-line body. Maybe it could recommend an inline usage like DEF tiles EQUS "* 16"
(as used in both pret and gb-open-world) until user-defined functions can do that better.
You're right that the documentation definitely needs updating. Using multiple lines in an EQUS
is largely an "advanced" feature, which interacts with the lexer and parser in non-obvious ways, so the documentation especially should not promote it. (Though very few people seem to read the documentation, lol.)
That's still some additional maintaining complexity due to more code, which I believe is not worth the associated feature.
EQUS
is not meant to be an alternative to macros, it's only a more efficient shorthand whenever things line up right. (Hell, I'm pretty sure you could leverage old-style macro definition andONE_LINER equs "MACRO\n"
to squeeze out the first line.)Proper "in-line" macros are separate feature, which have been discussed, and I don't think
EQUS
is close to a good fit for them.
Whether a feature was meant to be used for a purpose and whether it is used for that purpose are completely separate matters. When you pull the rug under projects by removing a feature because you don't like what it is being used for and don't add a replacement, you create a problem for everyone. (This is why I mentioned this feature was brought up in the context of #905; it isn't really that interesting unless that is being planned.)
This file is a perfectly good example of why single-line macros would be desirable; you can easily imagine that file becoming completely unmanageable if each EQUS
was replaced by a three-line macro expansion. #901 might have helped in that regard, but I can't even imagine how that would interact with macro definitions in any sane way at all, and I'm pretty sure the only sane way to handle regular macros would be to require that ENDM
appears on a line by itself.
All that being said, this is pretty much a non-issue unless #905 is being considered. As long as that's not on the radar, EQUS
covers this use case pretty well.
We will get to alternatives to EQUS
when we get there. Since nobody so far has had the meantime to draft a replacement to EQUS
, it's here to stay.
We will not remove a feature until an acceptable alternative exists for its use cases. I don't know how many times I will have to emphasize this so people will stop complaining about us "pulling the rug"—we aren't, and we won't.
Oh hey, Ruby has something like this: https://zverok.space/blog/2023-12-01-syntax-sugar5-endless-methods.html
(And this combines well with multiple instructions per line: DEF pusha MACRO push af :: push bc :: push de :: push hl
.)
With unlimited-length strings, we could do this:
MACRO DEF_MACRO
REDEF mac_name EQUS "\1"
shift
REDEF mac_body EQUS "\#"
REDEF mac_inner EQUS "MACRO {mac_name}\n\t{mac_body}\nENDM"
{mac_inner}
ENDM
DEF_MACRO text, "db \"<TEXT>\", "
DEF_MACRO pushall, push af :: push bc :: push de :: push hl
DEF_MACRO faceperson, faceobject
Until/unless we remove EQUS
expansion (#905), there's no real need for single-line macro syntax; and by the time we do that, we'll probably have better ideas for how to do this. (By then we may also have named macro args, or other additions that wouldn't work well with this DEF name MACRO body
proposal.) So I'm closing this.
Macros need at least three lines, since the
MACRO
andENDM
have to be on their own. This is kind of verbose for small macros, and the documentation even suggests usingEQUS
instead for brevity. However, that's "cheating" since it's not really a macro invocation; it can't take arguments, and relies onEQUS
expansion (arguably a misfeature).I propose a single-line
DEF mac MACRO ...
syntax for cases like this. After eating theMACRO
token, the parser would call a lexer function to capture everything up to the next newline/end-of-file as a string. This would only allow single-statement macros, but would combine neatly with #901 for multiple statements.Some examples:
Basically these would be equivalent: