Remove `EQUS` expansion
- Dominant language
- C++
- Stars
- 1.6k
- Forks
- 193
- Avg merge
- 22h 17m
- Merged PRs (30d)
- 26
Description
`EQUS` expansion has a few problems.
- Unlike `{interpolation}` and macro arguments, it occurs *after* `peek`ing and reading a complete identifier. This means that the lexer reacts to the identifier's presence before it gets expanded. For example, if `EMPTY EQUS ""`, then `ld a, \ EMPTY` gives an error "Begun line continuation, but encountered character 'E'" whereas `ld a, \ {EMPTY}` does not.
- Like `{interpolation}` and macro arguments, the expanded contents can be anything, even multiple lines, but nothing makes the bare identifier stand out as being so potentially disruptive. For example, in `ld a, 2 plus 2`, if `plus EQUS ";"` then it gets treated as a comment. It can also interact weirdly with statements that parse their own newlines (`REPT`, `FOR`, `MACRO`, etc).
If `EQUS` expansion were eliminated, then string identifiers could work just like numeric ones: evaluate to their literal contents. This would let people write `STRING` instead of `"{STRING}"`, which I think is a big improvement, especially in longer expressions like `STRIN(HAYSTACK, NEEDLE)`.
On the other hand, this would be a very backwards-incompatible change: people rely on `EQUS` expansion for certain use cases that other features don't yet cover. We would need to at least have acceptable substitutes. The use cases I'm familiar with:
- Indirect assignment. For example, `CUR_THING EQUS "X"` and then `CUR_THING EQU 42` will act like `X EQU 42`. This can already be done with interpolation like `{CUR_THING} EQU 42`, and that's *required* for the new `DEF {CUR_THING} EQU 42` syntax. (Expansion in `CUR_THING EQU 42` was confusing anyway.)
- Inline expression pieces. For example, `tiles EQUS "* 16"` lets you do `ld a, 7 tiles`, or `N EQU ($30 + 6) tiles - 1`. Macros have to be a complete line so you need different macros for each situation, and interpolation makes the user-defined pieces stand out too much (`ld a, 7 {tiles}` isn't as plainly readable). This will *eventually* be doable with user-defined functions (see #201), like `ld a, tiles(7)`, although such functions will ideally support variable arguments to match everything `EQUS` can do.
- Small one-line macros. The documentation even recommends this with the example `DEF pusha EQUS "push af\npush bc\npush de\npush hl\n"`. For short cases like `text EQUS db 0,`, it's simpler to write and to read than a three-line `MACRO text / db 0, \# / ENDM`. This *could* be done with a combination of single-line `DEF mac MACRO ...` syntax (see #902) and allowing multiple instructions on one line with a statement separator (see #805). However the discussion for those feature requests brought up some valid objections, and unlike user-defined functions, they aren't really useful except as a substitute for `EQUS`.
If anyone's relying on `EQUS` expansion for something more idiosyncratic or complicated, then at least interpolation can fill all its use cases. On the one hand, `{STRING}` is less user-friendly than `STRING`; on the other hand, `STRING` is more user-friendly than `"{STRING}"`, and I think the latter is a lot more common than the former (after making use of user-defined functions and macros when possible).
Contributor guide
Assessment
This issue has not been assessed yet.