[Feature request] User-defined functions
- Dominant language
- C++
- Stars
- 1.6k
- Forks
- 193
- Avg merge
- 22h 17m
- Merged PRs (30d)
- 26
Description
I'm sure that this has been mentioned before, but I've been coming up with a full feature proposal and I'd like to know how feasible it is. What follows is a proposed way of implementing functions, at least in a way I'd consider usable.
The idea is to allow the user to define functions, that would be evaluated in-line when called, similar to the various built-ins. Functions can have one or more arguments, which define variables that are local to the function; they are substituted in the expression. An example of the syntax I have in mind would be:
```
;definition
addnums(first, second) = ({first}) + ({second})
;usage
ld hl, wTwoPlusTwo
ld [hl], addnums(2, 2)
```
Functions can be defined with the same name as long as they have a different number of arguments; the proper version of the function would be used when called. For simplicity, all arguments are required.
```
average(one) = {one}
average(one, two) = (({one}) + ({two})) / 2
average(one, two, three) = (({one}) + ({two}) + ({three})) / 3
```
Declaring functions with the same name and number of arguments is not allowed; such declarations would either replace previous ones or cause an error (either works).
Calling built-in functions should obviously be allowed from user-defined functions:
```
linearaddress(label) = (BANK({label}) - 1) * $4000 + ({label})
```
In order to simplify functions like the average one above, varargs functions could be defined. Such functions would be used when there is no suitable non-varargs function (i.e., with the correct number of arguments) to call. For instance:
```
countargs() = 0
countargs(arg, ...) = 1 + countargs({...})
sum() = 0
sum(arg, ...) = ({arg}) + sum({...})
average(...) = sum({...}) / countargs({...})
roundedavg(...) = (2 * sum({...}) + 1) / (2 * countargs({...}))
```
The special symbol `{...}` is replaced by the list of variable arguments. Defining multiple varargs functions with the same name is not allowed; however, they can coexist with non-varargs functions.
As a silly example just to show how they would coexist:
```
fn(a) = {a}
fn(a, b, c) = {c}
fn(a, b, ...) = {b}
db fn(4) ;4
db fn(5, 9) ;9
db fn(2, 6, 3) ;3
db fn(1, 8, 0, 7) ;8
;db fn() is an error because there's no version that takes 0 arguments
```
I hope that this is doable, as it would certainly reduce some repetition and extremely macro-heavy code in some cases. As a simple realistic example, take this macro from Prism (might be slightly different because I'm typing it from memory):
```
;definition
coord: MACRO
if _NARG > 3
ld \1, (\4) + (\2) + ((\3) * SCREEN_WIDTH)
else
ld \1, wTilemap + (\2) + ((\3) * SCREEN_WIDTH)
endc
ENDM
hlcoord EQUS "coord hl, "
;usage
hlcoord 2, 5 ;sets hl to the corresponding tilemap position
```
Which using functions would be a lot cleaner:
```
;definition
coord(x, y, base) = ({base}) + ({x}) + ({y}) * SCREEN_WIDTH
coord(x, y) = coord({x}, {y}, wTilemap)
;usage
ld hl, coord(2, 5)
```
I await your responses; thanks for reading.
Contributor guide
Assessment
This issue has not been assessed yet.