bbc-basic: Use distinct error numbers for all errors.
[jackhill/mal.git] / bbc-basic / core
1 REM Core function library for mal in BBC BASIC
2
3 REM BBC BASIC doesn't have function pointers. There are essentially
4 REM two ways to work around this. One is to use the BASIC EVAL function,
5 REM constructing a string that will call an arbitrary function with the
6 REM specified arguments. The other is to us a big CASE statement.
7 REM Following the suggestion in Hints.md, this code takes the latter
8 REM approach.
9
10 REM Call a core function, taking the function number and an array of mal
11 REM objects to pass as arguments.
12 DEF FNcore_call(fn%, args%())
13 CASE fn% OF
14 WHEN 0 : REM +
15 PROCcore_assert_args("ii", "+", args%())
16 =FNalloc_int(FNunbox_int(args%(0)) + FNunbox_int(args%(1)))
17 WHEN 1 : REM -
18 PROCcore_assert_args("ii", "-", args%())
19 =FNalloc_int(FNunbox_int(args%(0)) - FNunbox_int(args%(1)))
20 WHEN 2 : REM *
21 PROCcore_assert_args("ii", "*", args%())
22 =FNalloc_int(FNunbox_int(args%(0)) * FNunbox_int(args%(1)))
23 WHEN 3 : REM /
24 PROCcore_assert_args("ii", "/", args%())
25 =FNalloc_int(FNunbox_int(args%(0)) DIV FNunbox_int(args%(1)))
26 ENDCASE
27 ERROR &40E809F1, "Call to non-existent core function"
28
29 DEF PROCcore_assert_args(spec$, fn$, args%())
30 REM Check that a core function is being provided with the correct
31 REM number and type of arguments. spec$ is the argument specification
32 REM as a string. Each character represents an argument:
33 REM "i" - Must be an integer
34
35 LOCAL i%
36
37 IF DIM(args%(), 1) <> LEN(spec$) THEN
38 ERROR &40E80921, "Core function '"+fn$+"' requires "+STR$(LEN(spec$))+" arguments"
39 ENDIF
40 FOR i% = 1 TO LEN(spec$)
41 CASE MID$(spec$, i%, 1) OF
42 WHEN "i"
43 IF NOT FNis_int(args%(i% - 1)) THEN
44 ERROR &40E80911, "Argument "+STR$(i%)+" to core function '"+fn$+"' must be an integer"
45 ENDIF
46 ENDCASE
47 NEXT i%
48 ENDPROC