2019-04-20 01:33:31 +01:00
|
|
|
REM > core function library for mal in BBC BASIC
|
2019-04-06 12:43:16 +01:00
|
|
|
|
|
|
|
|
REM BBC BASIC doesn't have function pointers. There are essentially
|
|
|
|
|
REM two ways to work around this. One is to use the BASIC EVAL function,
|
|
|
|
|
REM constructing a string that will call an arbitrary function with the
|
|
|
|
|
REM specified arguments. The other is to us a big CASE statement.
|
|
|
|
|
REM Following the suggestion in Hints.md, this code takes the latter
|
|
|
|
|
REM approach.
|
|
|
|
|
|
2019-04-08 00:52:22 +01:00
|
|
|
DEF PROCcore_ns
|
|
|
|
|
RESTORE +0
|
|
|
|
|
REM The actual DATA statements are embedded in the dispatch table below.
|
|
|
|
|
ENDPROC
|
|
|
|
|
|
2019-04-22 20:29:24 +01:00
|
|
|
REM Call a core function, taking the function number and a mal list of
|
2019-04-06 12:43:16 +01:00
|
|
|
REM objects to pass as arguments.
|
2019-04-22 20:29:24 +01:00
|
|
|
DEF FNcore_call(fn%, args%)
|
|
|
|
|
LOCAL args%(), arg$
|
|
|
|
|
DIM args%(1)
|
2019-04-06 12:43:16 +01:00
|
|
|
CASE fn% OF
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA +, 0
|
|
|
|
|
WHEN 0
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("ii", "+")
|
|
|
|
|
=FNalloc_int(args%(0) + args%(1))
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA -, 1
|
|
|
|
|
WHEN 1
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("ii", "-")
|
|
|
|
|
=FNalloc_int(args%(0) - args%(1))
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA *, 2
|
|
|
|
|
WHEN 2
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("ii", "*")
|
|
|
|
|
=FNalloc_int(args%(0) * args%(1))
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA /, 3
|
|
|
|
|
WHEN 3
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("ii", "/")
|
|
|
|
|
=FNalloc_int(args%(0) DIV args%(1))
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA list, 5
|
|
|
|
|
WHEN 5
|
2019-05-05 23:52:31 +01:00
|
|
|
=FNas_list(args%)
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA list?, 6
|
|
|
|
|
WHEN 6
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("?", "list?")
|
2019-04-08 00:52:22 +01:00
|
|
|
=FNalloc_boolean(FNis_list(args%(0)))
|
|
|
|
|
DATA empty?, 7
|
|
|
|
|
WHEN 7
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("l", "empty?")
|
2019-04-08 00:52:22 +01:00
|
|
|
=FNalloc_boolean(FNis_empty(args%(0)))
|
|
|
|
|
DATA count, 8
|
|
|
|
|
WHEN 8
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("C", "count")
|
2019-04-08 00:52:22 +01:00
|
|
|
IF FNis_nil(args%(0)) THEN =FNalloc_int(0)
|
2019-05-06 12:00:25 +01:00
|
|
|
=FNalloc_int(FNcount(args%(0)))
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA =, 9
|
|
|
|
|
WHEN 9
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("??", "=")
|
2019-04-08 00:52:22 +01:00
|
|
|
=FNalloc_boolean(FNcore_equal(args%(0), args%(1)))
|
|
|
|
|
DATA <, 10
|
|
|
|
|
WHEN 10
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("ii", "<")
|
|
|
|
|
=FNalloc_boolean(args%(0) < args%(1))
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA <=, 11
|
|
|
|
|
WHEN 11
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("ii", "<=")
|
|
|
|
|
=FNalloc_boolean(args%(0) <= args%(1))
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA >, 12
|
|
|
|
|
WHEN 12
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("ii", ">")
|
|
|
|
|
=FNalloc_boolean(args%(0) > args%(1))
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA >=, 13
|
|
|
|
|
WHEN 13
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("ii", ">=")
|
|
|
|
|
=FNalloc_boolean(args%(0) >= args%(1))
|
2019-04-20 15:06:38 +01:00
|
|
|
DATA read-string, 14
|
|
|
|
|
WHEN 14
|
2019-05-18 22:28:13 +01:00
|
|
|
PROCcore_prepare_args("t", "read-string")
|
|
|
|
|
=FNread_str(args%(0))
|
2019-04-20 15:06:38 +01:00
|
|
|
DATA slurp, 15
|
|
|
|
|
WHEN 15
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("s", "slurp")
|
2019-05-18 22:28:13 +01:00
|
|
|
=FNcore_slurp(arg$)
|
2019-04-20 15:06:38 +01:00
|
|
|
DATA eval, 16
|
|
|
|
|
WHEN 16
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("?", "eval")
|
2019-04-20 15:06:38 +01:00
|
|
|
=FNEVAL(args%(0), repl_env%)
|
2019-04-20 16:31:47 +01:00
|
|
|
DATA pr-str, 17
|
|
|
|
|
WHEN 17
|
2019-05-18 22:28:13 +01:00
|
|
|
=FNcore_print(TRUE, " ", args%)
|
2019-04-20 16:31:47 +01:00
|
|
|
DATA str, 18
|
|
|
|
|
WHEN 18
|
2019-05-18 22:28:13 +01:00
|
|
|
=FNcore_print(FALSE, "", args%)
|
2019-04-20 16:31:47 +01:00
|
|
|
DATA prn, 4
|
|
|
|
|
WHEN 4
|
2019-05-18 22:28:13 +01:00
|
|
|
PRINT FNunbox_string(FNcore_print(TRUE, " ", args%))
|
2019-04-20 16:31:47 +01:00
|
|
|
=FNnil
|
|
|
|
|
DATA println, 19
|
|
|
|
|
WHEN 19
|
2019-05-18 22:28:13 +01:00
|
|
|
PRINT FNunbox_string(FNcore_print(FALSE, " ", args%))
|
2019-04-20 16:31:47 +01:00
|
|
|
=FNnil
|
2019-04-20 18:25:09 +01:00
|
|
|
DATA atom, 20
|
|
|
|
|
WHEN 20
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("?", "atom")
|
2019-04-20 18:25:09 +01:00
|
|
|
=FNalloc_atom(args%(0))
|
|
|
|
|
DATA atom?, 21
|
|
|
|
|
WHEN 21
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("?", "atom?")
|
2019-04-20 18:25:09 +01:00
|
|
|
=FNalloc_boolean(FNis_atom(args%(0)))
|
|
|
|
|
DATA deref, 22
|
|
|
|
|
WHEN 22
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("a", "deref")
|
2019-04-20 18:25:09 +01:00
|
|
|
=FNatom_deref(args%(0))
|
|
|
|
|
DATA reset!, 23
|
|
|
|
|
WHEN 23
|
2019-04-22 20:29:24 +01:00
|
|
|
PROCcore_prepare_args("a?", "reset!")
|
2019-04-20 18:25:09 +01:00
|
|
|
PROCatom_reset(args%(0), args%(1))
|
|
|
|
|
=args%(1)
|
2019-04-23 23:14:24 +01:00
|
|
|
DATA swap!, 24
|
|
|
|
|
WHEN 24
|
|
|
|
|
PROCcore_prepare_args("af*", "swap!")
|
|
|
|
|
PROCatom_reset(args%(0), FNcore_apply(args%(1), FNalloc_pair(FNatom_deref(args%(0)), args%)))
|
|
|
|
|
=FNatom_deref(args%(0))
|
2019-04-23 23:25:46 +01:00
|
|
|
DATA cons, 25
|
|
|
|
|
WHEN 25
|
|
|
|
|
PROCcore_prepare_args("?l", "cons")
|
|
|
|
|
=FNalloc_pair(args%(0), args%(1))
|
2019-04-28 10:41:10 +01:00
|
|
|
DATA concat, 26
|
|
|
|
|
WHEN 26
|
|
|
|
|
=FNcore_concat(args%)
|
2019-04-30 22:45:13 +01:00
|
|
|
DATA nth, 27
|
|
|
|
|
WHEN 27
|
|
|
|
|
PROCcore_prepare_args("li", "nth")
|
2019-05-06 12:00:25 +01:00
|
|
|
=FNnth(args%(0), args%(1))
|
2019-04-30 22:45:13 +01:00
|
|
|
DATA first, 28
|
|
|
|
|
WHEN 28
|
2019-05-06 12:24:34 +01:00
|
|
|
PROCcore_prepare_args("C", "first")
|
2019-05-13 23:06:12 +01:00
|
|
|
IF FNis_nil(args%(0)) THEN =FNnil
|
2019-05-06 12:00:25 +01:00
|
|
|
=FNfirst(args%(0))
|
2019-04-30 22:45:13 +01:00
|
|
|
DATA rest, 29
|
|
|
|
|
WHEN 29
|
2019-05-06 12:24:34 +01:00
|
|
|
PROCcore_prepare_args("C", "rest")
|
2019-05-13 23:06:12 +01:00
|
|
|
IF FNis_nil(args%(0)) THEN =FNempty
|
2019-05-06 12:28:26 +01:00
|
|
|
=FNas_list(FNrest(args%(0)))
|
2019-05-01 12:31:48 +01:00
|
|
|
DATA throw, 30
|
|
|
|
|
WHEN 30
|
|
|
|
|
PROCcore_prepare_args("?", "throw")
|
|
|
|
|
MAL_ERR% = args%(0)
|
2019-05-18 22:28:13 +01:00
|
|
|
ERROR &40E80900, "Mal exception: " + FNunbox_string(FNpr_str(args%(0), FALSE))
|
2019-05-01 13:03:16 +01:00
|
|
|
DATA apply, 31
|
|
|
|
|
WHEN 31
|
|
|
|
|
PROCcore_prepare_args("f?*", "apply")
|
|
|
|
|
=FNcore_apply(args%(0), FNcore_apply_args(FNalloc_pair(args%(1), args%)))
|
2019-05-01 13:14:35 +01:00
|
|
|
DATA map, 32
|
|
|
|
|
WHEN 32
|
|
|
|
|
PROCcore_prepare_args("fl", "map")
|
|
|
|
|
=FNcore_map(args%(0), args%(1))
|
2019-05-01 13:20:04 +01:00
|
|
|
DATA nil?, 33
|
|
|
|
|
WHEN 33
|
|
|
|
|
PROCcore_prepare_args("?", "nil?")
|
|
|
|
|
=FNalloc_boolean(FNis_nil(args%(0)))
|
|
|
|
|
DATA true?, 34
|
|
|
|
|
WHEN 34
|
|
|
|
|
PROCcore_prepare_args("?", "true?")
|
|
|
|
|
IF NOT FNis_boolean(args%(0)) THEN =FNalloc_boolean(FALSE)
|
|
|
|
|
=args%(0)
|
|
|
|
|
DATA false?, 35
|
|
|
|
|
WHEN 35
|
|
|
|
|
PROCcore_prepare_args("?", "false?")
|
|
|
|
|
IF NOT FNis_boolean(args%(0)) THEN =FNalloc_boolean(FALSE)
|
|
|
|
|
=FNalloc_boolean(NOT FNunbox_boolean(args%(0)))
|
|
|
|
|
DATA symbol?, 36
|
|
|
|
|
WHEN 36
|
|
|
|
|
PROCcore_prepare_args("?", "symbol?")
|
|
|
|
|
=FNalloc_boolean(FNis_symbol(args%(0)))
|
2019-05-04 21:21:23 +01:00
|
|
|
DATA symbol, 37
|
|
|
|
|
WHEN 37
|
|
|
|
|
PROCcore_prepare_args("s", "symbol")
|
|
|
|
|
=FNalloc_symbol(arg$)
|
|
|
|
|
DATA keyword, 38
|
|
|
|
|
WHEN 38
|
|
|
|
|
PROCcore_prepare_args("s", "keyword")
|
|
|
|
|
IF LEFT$(arg$, 1) <> CHR$(127) THEN arg$ = CHR$(127) + arg$
|
|
|
|
|
=FNalloc_string(arg$)
|
|
|
|
|
DATA keyword?, 39
|
|
|
|
|
WHEN 39
|
|
|
|
|
PROCcore_prepare_args("?", "keyword?")
|
|
|
|
|
IF FNis_string(args%(0)) THEN
|
|
|
|
|
=FNalloc_boolean(LEFT$(FNunbox_string(args%(0)), 1) = CHR$(127))
|
|
|
|
|
ENDIF
|
|
|
|
|
=FNalloc_boolean(FALSE)
|
2019-05-06 00:00:42 +01:00
|
|
|
DATA vector, 40
|
|
|
|
|
WHEN 40
|
|
|
|
|
=FNas_vector(args%)
|
|
|
|
|
DATA vector?, 41
|
|
|
|
|
WHEN 41
|
|
|
|
|
PROCcore_prepare_args("?", "vector?")
|
|
|
|
|
=FNalloc_boolean(FNis_vector(args%(0)))
|
|
|
|
|
DATA sequential?, 42
|
|
|
|
|
WHEN 42
|
|
|
|
|
PROCcore_prepare_args("?", "sequential?")
|
2019-05-11 21:46:24 +01:00
|
|
|
=FNalloc_boolean(FNis_seq(args%(0)))
|
|
|
|
|
DATA hash-map, 43
|
|
|
|
|
WHEN 43
|
2019-05-12 18:28:38 +01:00
|
|
|
=FNcore_assoc(FNempty_hashmap, args%)
|
2019-05-11 21:46:24 +01:00
|
|
|
DATA map?, 44
|
|
|
|
|
WHEN 44
|
|
|
|
|
PROCcore_prepare_args("?", "map?")
|
|
|
|
|
=FNalloc_boolean(FNis_hashmap(args%(0)))
|
2019-05-12 18:28:38 +01:00
|
|
|
DATA assoc, 45
|
|
|
|
|
WHEN 45
|
|
|
|
|
PROCcore_prepare_args("h*", "assoc")
|
|
|
|
|
=FNcore_assoc(args%(0), args%)
|
2019-05-12 21:52:15 +01:00
|
|
|
DATA dissoc, 46
|
|
|
|
|
WHEN 46
|
|
|
|
|
PROCcore_prepare_args("h*", "dissoc")
|
|
|
|
|
WHILE NOT FNis_empty(args%)
|
|
|
|
|
args%(0) = FNhashmap_remove(args%(0), FNunbox_string(FNfirst(args%)))
|
|
|
|
|
args% = FNrest(args%)
|
|
|
|
|
ENDWHILE
|
|
|
|
|
=args%(0)
|
2019-05-12 18:06:54 +01:00
|
|
|
DATA get, 47
|
|
|
|
|
WHEN 47
|
|
|
|
|
IF FNis_nil(FNfirst(args%)) THEN =FNnil
|
|
|
|
|
PROCcore_prepare_args("hs", "get")
|
|
|
|
|
=FNhashmap_get(args%(0), arg$)
|
|
|
|
|
DATA contains?, 48
|
|
|
|
|
WHEN 48
|
|
|
|
|
PROCcore_prepare_args("hs", "contains?")
|
|
|
|
|
=FNalloc_boolean(FNhashmap_contains(args%(0), arg$))
|
2019-05-12 18:28:38 +01:00
|
|
|
DATA keys, 49
|
|
|
|
|
WHEN 49
|
|
|
|
|
PROCcore_prepare_args("h", "keys")
|
|
|
|
|
=FNhashmap_keys(args%(0))
|
2019-05-12 21:52:15 +01:00
|
|
|
DATA vals, 50
|
|
|
|
|
WHEN 50
|
|
|
|
|
PROCcore_prepare_args("h", "vals")
|
|
|
|
|
=FNhashmap_vals(args%(0))
|
2019-05-12 22:53:53 +01:00
|
|
|
DATA readline, 51
|
|
|
|
|
WHEN 51
|
|
|
|
|
PROCcore_prepare_args("s", "readline")
|
|
|
|
|
PRINT arg$;
|
|
|
|
|
LINE INPUT "" arg$
|
|
|
|
|
=FNalloc_string(arg$)
|
2019-05-12 23:49:51 +01:00
|
|
|
DATA meta, 52
|
|
|
|
|
WHEN 52
|
2019-05-14 23:19:26 +01:00
|
|
|
PROCcore_prepare_args("?", "meta")
|
2019-05-12 23:49:51 +01:00
|
|
|
=FNmeta(args%(0))
|
|
|
|
|
DATA with-meta, 53
|
|
|
|
|
WHEN 53
|
2019-05-14 23:19:26 +01:00
|
|
|
PROCcore_prepare_args("??", "with-meta")
|
2019-05-12 23:49:51 +01:00
|
|
|
=FNwith_meta(args%(0), args%(1))
|
2019-05-14 22:54:12 +01:00
|
|
|
DATA time-ms, 54
|
|
|
|
|
WHEN 54
|
|
|
|
|
PROCcore_prepare_args("", "time-ms")
|
|
|
|
|
=FNalloc_int(TIME * 10)
|
2019-05-14 23:00:52 +01:00
|
|
|
DATA conj, 55
|
|
|
|
|
WHEN 55
|
|
|
|
|
PROCcore_prepare_args("l*", "conj")
|
|
|
|
|
IF FNis_list(args%(0)) THEN
|
|
|
|
|
WHILE NOT FNis_empty(args%)
|
|
|
|
|
args%(0) = FNalloc_pair(FNfirst(args%), args%(0))
|
|
|
|
|
args% = FNrest(args%)
|
|
|
|
|
ENDWHILE
|
|
|
|
|
=args%(0)
|
|
|
|
|
ELSE : REM args%(0) is a vector
|
|
|
|
|
=FNas_vector(FNcore_concat1(args%(0), args%))
|
|
|
|
|
ENDIF
|
2019-05-14 23:07:14 +01:00
|
|
|
DATA string?, 56
|
|
|
|
|
WHEN 56
|
|
|
|
|
PROCcore_prepare_args("?", "string?")
|
|
|
|
|
IF FNis_string(args%(0)) THEN
|
|
|
|
|
=FNalloc_boolean(LEFT$(FNunbox_string(args%(0)), 1) <> CHR$(127))
|
|
|
|
|
ENDIF
|
|
|
|
|
=FNalloc_boolean(FALSE)
|
|
|
|
|
DATA number?, 57
|
|
|
|
|
WHEN 57
|
|
|
|
|
PROCcore_prepare_args("?", "number?")
|
|
|
|
|
=FNalloc_boolean(FNis_int(args%(0)))
|
|
|
|
|
DATA fn?, 58
|
|
|
|
|
WHEN 58
|
|
|
|
|
PROCcore_prepare_args("?", "fn?")
|
|
|
|
|
=FNalloc_boolean(FNis_nonmacro_fn(args%(0)) OR FNis_corefn(args%(0)))
|
|
|
|
|
DATA macro?, 59
|
|
|
|
|
WHEN 59
|
|
|
|
|
PROCcore_prepare_args("?", "macro?")
|
|
|
|
|
=FNalloc_boolean(FNis_macro(args%(0)))
|
2019-05-14 23:17:21 +01:00
|
|
|
DATA seq, 60
|
|
|
|
|
WHEN 60
|
|
|
|
|
PROCcore_prepare_args("?", "seq")
|
|
|
|
|
=FNcore_seq(args%(0))
|
2020-07-21 18:01:48 +02:00
|
|
|
DATA vec, 61
|
|
|
|
|
WHEN 61
|
|
|
|
|
PROCcore_prepare_args("l", "vec")
|
|
|
|
|
=FNas_vector(args%(0))
|
2019-04-08 00:52:22 +01:00
|
|
|
DATA "", -1
|
2019-04-06 12:43:16 +01:00
|
|
|
ENDCASE
|
2019-04-07 11:02:20 +01:00
|
|
|
ERROR &40E809F1, "Call to non-existent core function"
|
2019-04-07 09:56:35 +01:00
|
|
|
|
2019-04-22 20:29:24 +01:00
|
|
|
DEF PROCcore_prepare_args(spec$, fn$)
|
2019-04-07 09:56:35 +01:00
|
|
|
REM Check that a core function is being provided with the correct
|
2019-04-22 20:29:24 +01:00
|
|
|
REM number and type of arguments and unbox them as appropriate.
|
|
|
|
|
REM spec$ is the argument specification as a string. Each character
|
|
|
|
|
REM represents an argument:
|
2019-04-07 09:56:35 +01:00
|
|
|
|
2019-04-22 20:29:24 +01:00
|
|
|
REM "i" - Must be an integer; unbox into args%()
|
|
|
|
|
REM "s" - Must be a string; unbox into arg$
|
2019-05-18 22:28:13 +01:00
|
|
|
REM "t" - Must be a string; stuff into args%()
|
2019-05-05 23:52:31 +01:00
|
|
|
REM "l" - Must be a sequence; stuff into args%()
|
2019-04-22 20:29:24 +01:00
|
|
|
REM "f" - Must be a function; stuff into args%()
|
|
|
|
|
REM "a" - Must be an atom; stuff into args%()
|
2019-05-12 18:06:54 +01:00
|
|
|
REM "h" - Must be a hash-map; stuff into args%()
|
2019-04-22 20:29:24 +01:00
|
|
|
REM "C" - Must be 'count'able stuff into args%()
|
|
|
|
|
REM "?" - Any single argument stuff into args%()
|
|
|
|
|
REM "*" - Any number of (trailing) arguments; leave in args%
|
|
|
|
|
|
|
|
|
|
REM This function shares some local variables with FNcore_call.
|
|
|
|
|
|
|
|
|
|
LOCAL i%, val%
|
2019-04-07 09:56:35 +01:00
|
|
|
|
2019-04-20 18:28:15 +01:00
|
|
|
IF RIGHT$(spec$) = "*" THEN
|
|
|
|
|
spec$ = LEFT$(spec$)
|
2019-05-06 12:00:25 +01:00
|
|
|
IF FNcount(args%) < LEN(spec$) THEN
|
2019-04-20 18:28:15 +01:00
|
|
|
ERROR &40E80921, "Core function '"+fn$+"' requires at least "+STR$(LEN(spec$))+" arguments"
|
|
|
|
|
ENDIF
|
|
|
|
|
ELSE
|
2019-05-06 12:00:25 +01:00
|
|
|
IF FNcount(args%) <> LEN(spec$) THEN
|
2019-04-20 18:28:15 +01:00
|
|
|
ERROR &40E80921, "Core function '"+fn$+"' requires "+STR$(LEN(spec$))+" arguments"
|
|
|
|
|
ENDIF
|
2019-04-07 09:56:35 +01:00
|
|
|
ENDIF
|
|
|
|
|
FOR i% = 1 TO LEN(spec$)
|
2019-05-06 12:00:25 +01:00
|
|
|
val% = FNfirst(args%)
|
2019-04-07 09:56:35 +01:00
|
|
|
CASE MID$(spec$, i%, 1) OF
|
|
|
|
|
WHEN "i"
|
2019-04-22 20:29:24 +01:00
|
|
|
IF NOT FNis_int(val%) THEN
|
2019-04-19 17:35:27 +01:00
|
|
|
ERROR &40E80911, "Argument "+STR$(i%)+" to core function '"+fn$+"' must be an integer"
|
|
|
|
|
ENDIF
|
2019-04-22 20:29:24 +01:00
|
|
|
args%(i% - 1) = FNunbox_int(val%)
|
2019-04-20 15:06:38 +01:00
|
|
|
WHEN "s"
|
2019-04-22 20:29:24 +01:00
|
|
|
IF NOT FNis_string(val%) THEN
|
2019-05-11 21:45:38 +01:00
|
|
|
ERROR &40E80914, "Argument "+STR$(i%)+" to core function '"+fn$+"' must be a string"
|
2019-04-20 15:06:38 +01:00
|
|
|
ENDIF
|
2019-04-22 20:29:24 +01:00
|
|
|
arg$ = FNunbox_string(val%)
|
2019-05-18 22:28:13 +01:00
|
|
|
WHEN "t"
|
|
|
|
|
IF NOT FNis_string(val%) THEN
|
|
|
|
|
ERROR &40E80914, "Argument "+STR$(i%)+" to core function '"+fn$+"' must be a string"
|
|
|
|
|
ENDIF
|
|
|
|
|
args%(i% - 1) = val%
|
2019-04-08 00:52:22 +01:00
|
|
|
WHEN "l"
|
2019-05-05 23:52:31 +01:00
|
|
|
IF NOT FNis_seq(val%) THEN
|
|
|
|
|
ERROR &40E80916, "Argument "+STR$(i%)+" to core function '"+fn$+"' must be a sequence"
|
2019-04-19 17:35:27 +01:00
|
|
|
ENDIF
|
2019-04-22 20:29:24 +01:00
|
|
|
args%(i% - 1) = val%
|
2019-04-20 18:28:15 +01:00
|
|
|
WHEN "f"
|
2019-04-22 20:29:24 +01:00
|
|
|
IF NOT FNis_fn(val%) AND NOT FNis_corefn(val%) THEN
|
2019-04-20 18:28:15 +01:00
|
|
|
ERROR &40E80919, "Argument "+STR$(i%)+" to core function '"+fn$+"' must be a function"
|
|
|
|
|
ENDIF
|
2019-04-22 20:29:24 +01:00
|
|
|
args%(i% - 1) = val%
|
2019-04-20 18:25:09 +01:00
|
|
|
WHEN "a"
|
2019-04-22 20:29:24 +01:00
|
|
|
IF NOT FNis_atom(val%) THEN
|
2019-04-20 18:25:09 +01:00
|
|
|
ERROR &40E8091C, "Argument "+STR$(i%)+" to core function '"+fn$+"' must be an atom"
|
|
|
|
|
ENDIF
|
2019-04-22 20:29:24 +01:00
|
|
|
args%(i% - 1) = val%
|
2019-05-12 18:06:54 +01:00
|
|
|
WHEN "h"
|
|
|
|
|
IF NOT FNis_hashmap(val%) THEN
|
|
|
|
|
ERROR &40E8091D, "Argument "+STR$(i%)+" to core function '"+fn$+"' must be a hash-map"
|
|
|
|
|
ENDIF
|
|
|
|
|
args%(i% - 1) = val%
|
2019-04-08 00:52:22 +01:00
|
|
|
WHEN "C"
|
2019-05-05 23:52:31 +01:00
|
|
|
IF NOT FNis_seq(val%) AND NOT FNis_nil(val%) THEN
|
2019-04-19 17:35:27 +01:00
|
|
|
ERROR &40E8091F, "Argument "+STR$(i%)+" to core function '"+fn$+"' must be a countable value"
|
|
|
|
|
ENDIF
|
2019-04-22 20:29:24 +01:00
|
|
|
args%(i% - 1) = val%
|
2019-04-08 00:52:22 +01:00
|
|
|
WHEN "?"
|
2019-04-22 20:29:24 +01:00
|
|
|
args%(i% - 1) = val%
|
2019-04-07 09:56:35 +01:00
|
|
|
ENDCASE
|
2019-05-06 12:00:25 +01:00
|
|
|
args% = FNrest(args%)
|
2019-04-07 09:56:35 +01:00
|
|
|
NEXT i%
|
|
|
|
|
ENDPROC
|
2019-04-08 00:52:22 +01:00
|
|
|
|
|
|
|
|
REM Innards of the '=' function.
|
|
|
|
|
DEF FNcore_equal(a%, b%)
|
|
|
|
|
IF a% = b% THEN =TRUE
|
|
|
|
|
IF FNis_int(a%) AND FNis_int(b%) THEN =FNunbox_int(a%) = FNunbox_int(b%)
|
|
|
|
|
IF FNis_symbol(a%) AND FNis_symbol(b%) THEN
|
|
|
|
|
=FNunbox_symbol(a%) = FNunbox_symbol(b%)
|
|
|
|
|
ENDIF
|
2019-04-20 13:44:12 +01:00
|
|
|
IF FNis_string(a%) AND FNis_string(b%) THEN
|
|
|
|
|
=FNunbox_string(a%) = FNunbox_string(b%)
|
|
|
|
|
ENDIF
|
2019-05-05 23:52:31 +01:00
|
|
|
IF FNis_seq(a%) AND FNis_seq(b%) THEN
|
2019-04-08 00:52:22 +01:00
|
|
|
IF FNis_empty(a%) AND FNis_empty(b%) THEN =TRUE
|
|
|
|
|
IF FNis_empty(a%) <> FNis_empty(b%) THEN =FALSE
|
2019-05-06 12:00:25 +01:00
|
|
|
IF NOT FNcore_equal(FNfirst(a%), FNfirst(b%)) THEN =FALSE
|
|
|
|
|
=FNcore_equal(FNrest(a%), FNrest(b%))
|
2019-04-08 00:52:22 +01:00
|
|
|
ENDIF
|
2019-05-18 14:44:04 +01:00
|
|
|
IF FNis_hashmap(a%) AND FNis_hashmap(b%) THEN
|
|
|
|
|
REM Take advantage of the sorted keys in our hash-maps.
|
|
|
|
|
IF FNcore_equal(FNhashmap_keys(a%), FNhashmap_keys(b%)) THEN
|
|
|
|
|
IF FNcore_equal(FNhashmap_vals(a%), FNhashmap_vals(b%)) THEN =TRUE
|
|
|
|
|
ENDIF
|
|
|
|
|
ENDIF
|
2019-04-08 00:52:22 +01:00
|
|
|
=FALSE
|
2019-04-19 17:44:19 +01:00
|
|
|
|
2019-04-20 15:06:38 +01:00
|
|
|
REM Innards of the 'slurp' function.
|
|
|
|
|
DEF FNcore_slurp(file$)
|
2019-05-18 22:28:13 +01:00
|
|
|
LOCAL f%, out%
|
2019-04-20 15:06:38 +01:00
|
|
|
f% = OPENIN(file$)
|
|
|
|
|
IF f% = 0 THEN ERROR &40E80940, "File '"+file$+"' not found"
|
2019-05-27 22:51:09 +01:00
|
|
|
out% = FNcore_slurp_channel(f%)
|
2019-04-20 15:06:38 +01:00
|
|
|
CLOSE#f%
|
2019-05-18 22:28:13 +01:00
|
|
|
=out%
|
2019-04-20 15:06:38 +01:00
|
|
|
|
2019-05-27 22:51:09 +01:00
|
|
|
DEF FNcore_slurp_channel(f%)
|
|
|
|
|
LOCAL this%
|
|
|
|
|
IF EOF#f% THEN =FNalloc_string("")
|
|
|
|
|
REM GET$# doesn't include a trailing newline.
|
|
|
|
|
this% = FNalloc_string(GET$#f% + CHR$(10))
|
|
|
|
|
=FNstring_concat(this%, FNcore_slurp_channel(f%))
|
|
|
|
|
|
2019-04-20 16:31:47 +01:00
|
|
|
REM General-purpose printing function
|
2019-04-22 20:29:24 +01:00
|
|
|
DEF FNcore_print(print_readably%, sep$, args%)
|
2019-05-18 22:28:13 +01:00
|
|
|
LOCAL out%
|
|
|
|
|
IF FNis_empty(args%) THEN =FNalloc_string("")
|
2019-05-27 12:51:20 +01:00
|
|
|
out% = FNpr_str(FNfirst(args%), print_readably%)
|
2019-05-06 12:00:25 +01:00
|
|
|
args% = FNrest(args%)
|
2019-04-22 20:29:24 +01:00
|
|
|
WHILE NOT FNis_empty(args%)
|
2019-05-27 12:51:20 +01:00
|
|
|
out% = FNstring_append(out%, sep$)
|
|
|
|
|
out% = FNstring_concat(out%, FNpr_str(FNfirst(args%), print_readably%))
|
2019-05-06 12:00:25 +01:00
|
|
|
args% = FNrest(args%)
|
2019-04-22 20:29:24 +01:00
|
|
|
ENDWHILE
|
2019-05-18 22:28:13 +01:00
|
|
|
=out%
|
2019-04-20 16:31:47 +01:00
|
|
|
|
2019-05-01 13:03:16 +01:00
|
|
|
REM Innards of the 'apply' function, also used by 'swap!'
|
2019-04-23 23:14:24 +01:00
|
|
|
DEF FNcore_apply(fn%, args%)
|
|
|
|
|
LOCAL ast%, env%
|
|
|
|
|
IF FNis_corefn(fn%) THEN =FNcore_call(FNunbox_corefn(fn%), args%)
|
|
|
|
|
IF FNis_fn(fn%) THEN
|
|
|
|
|
ast% = FNfn_ast(fn%)
|
|
|
|
|
env% = FNnew_env(FNfn_env(fn%), FNfn_params(fn%), args%)
|
|
|
|
|
=FNEVAL(ast%, env%)
|
|
|
|
|
ENDIF
|
|
|
|
|
ERROR &40E80918, "Not a function"
|
|
|
|
|
|
2019-04-28 10:41:10 +01:00
|
|
|
REM Innards of 'concat' function
|
|
|
|
|
DEF FNcore_concat(args%)
|
|
|
|
|
LOCAL tail%
|
|
|
|
|
IF FNis_empty(args%) THEN =FNempty
|
2019-05-06 12:00:25 +01:00
|
|
|
tail% = FNcore_concat(FNrest(args%))
|
|
|
|
|
=FNcore_concat1(FNfirst(args%), tail%)
|
2019-04-28 10:41:10 +01:00
|
|
|
|
|
|
|
|
DEF FNcore_concat1(prefix%, tail%)
|
|
|
|
|
IF FNis_empty(prefix%) THEN =tail%
|
2019-05-06 12:00:25 +01:00
|
|
|
=FNalloc_pair(FNfirst(prefix%), FNcore_concat1(FNrest(prefix%), tail%))
|
2019-04-28 10:41:10 +01:00
|
|
|
|
2019-05-01 13:03:16 +01:00
|
|
|
REM Recursively assemble the argument list for 'apply'
|
|
|
|
|
DEF FNcore_apply_args(args%)
|
2019-05-06 12:00:25 +01:00
|
|
|
IF FNis_empty(FNrest(args%)) THEN =FNfirst(args%)
|
|
|
|
|
=FNalloc_pair(FNfirst(args%), FNcore_apply_args(FNrest(args%)))
|
2019-05-01 13:03:16 +01:00
|
|
|
|
2019-05-01 13:14:35 +01:00
|
|
|
REM Innards of the 'map' function
|
|
|
|
|
DEF FNcore_map(fn%, args%)
|
|
|
|
|
LOCAL car%, cdr%
|
|
|
|
|
IF FNis_empty(args%) THEN =args%
|
2019-05-06 12:00:25 +01:00
|
|
|
car% = FNcore_apply(fn%, FNalloc_pair(FNfirst(args%), FNempty))
|
|
|
|
|
cdr% = FNcore_map(fn%, FNrest(args%))
|
2019-05-01 13:14:35 +01:00
|
|
|
=FNalloc_pair(car%, cdr%)
|
2019-04-28 10:41:10 +01:00
|
|
|
|
2019-05-11 21:46:24 +01:00
|
|
|
REM Innards of the 'hash-map' function
|
2019-05-12 18:28:38 +01:00
|
|
|
DEF FNcore_assoc(map%, args%)
|
|
|
|
|
LOCAL args%()
|
2019-05-11 21:46:24 +01:00
|
|
|
DIM args%(1)
|
|
|
|
|
WHILE NOT FNis_empty(args%)
|
|
|
|
|
PROCcore_prepare_args("s?*", "hash-map")
|
2019-05-12 18:06:54 +01:00
|
|
|
map% = FNhashmap_set(map%, arg$, args%(1))
|
2019-05-11 21:46:24 +01:00
|
|
|
ENDWHILE
|
|
|
|
|
=map%
|
|
|
|
|
|
2019-05-14 23:17:21 +01:00
|
|
|
REM Innards of the 'seq' function
|
|
|
|
|
DEF FNcore_seq(val%)
|
|
|
|
|
LOCAL s$, i%
|
|
|
|
|
IF FNis_empty(val%) OR FNis_nil(val%) THEN =FNnil
|
|
|
|
|
IF FNis_list(val%) THEN =val%
|
|
|
|
|
IF FNis_vector(val%) THEN =FNas_list(val%)
|
|
|
|
|
IF FNis_string(val%) THEN
|
|
|
|
|
s$ = FNunbox_string(val%)
|
|
|
|
|
IF s$ = "" THEN =FNnil
|
|
|
|
|
val% = FNempty
|
|
|
|
|
FOR i% = LEN(s$) TO 1 STEP -1
|
|
|
|
|
val% = FNalloc_pair(FNalloc_string(MID$(s$, i%, 1)), val%)
|
|
|
|
|
NEXT i%
|
|
|
|
|
=val%
|
|
|
|
|
ENDIF
|
|
|
|
|
ERROR &40E8091F, "Argument to 'seq' must be list, vector, string, or nil"
|
|
|
|
|
|
2019-04-19 17:44:19 +01:00
|
|
|
REM Local Variables:
|
|
|
|
|
REM indent-tabs-mode: nil
|
|
|
|
|
REM End:
|