1 REM Step 6 of mal in BBC BASIC
11 repl_env
% = FNalloc_environment(FNnil
)
12 PROCcore_ns
: REM This sets the data pointer
16 PROCenv_set(repl_env
%, FNalloc_symbol(sym
$), FNalloc_corefn(i
%))
20 REM Initial forms to evaluate
22 DATA (def
! not (fn
* (a
) (if a
false true)))
23 DATA (def
! load-file (fn
* (f
) (eval (read
-string (str
"(do " (slurp f
) "\nnil)")))))
27 IF form$
<> "" THEN val$
= FNrep(form
$)
32 IF FNis_empty(argv
%) THEN
33 PROCenv_set(repl_env
%, FNalloc_symbol("*ARGV*"), FNempty
)
35 PROCenv_set(repl_env
%, FNalloc_symbol("*ARGV*"), FNrest(argv
%))
36 val$
= FNrep("(load-file " + FNunbox_string(FNpr_str(FNfirst(argv
%), TRUE)) + ")")
42 REM Catch all errors apart from "Escape".
43 ON ERROR LOCAL
IF ERR
= 17 ON ERROR OFF
: ERROR ERR
, REPORT$
ELSE PRINT REPORT$
54 =FNread_str(FNalloc_string(a
$))
56 DEF
FNEVAL(ast
%, env
%)
58 =FNgc_exit(FNEVAL_(ast
%, env
%))
60 DEF
FNEVAL_(ast
%, env
%)
61 LOCAL car
%, specialform
%, val
%, bindings
%
63 PROCgc_keep_only2(ast
%, env
%)
64 IF NOT FNis_list(ast
%) THEN =FNeval_ast(ast
%, env
%)
65 IF FNis_empty(ast
%) THEN =ast
%
68 IF FNis_symbol(car
%) THEN
70 CASE FNunbox_symbol(car
%) OF
73 val
% = FNEVAL(FNnth(ast
%, 2), env
%)
74 PROCenv_set(env
%, FNnth(ast
%, 1), val
%)
77 env
% = FNalloc_environment(env
%)
78 bindings
% = FNnth(ast
%, 1)
79 WHILE NOT FNis_empty(bindings
%)
80 PROCenv_set(env
%, FNfirst(bindings
%), FNEVAL(FNnth(bindings
%, 1), env
%))
81 bindings
% = FNrest(FNrest(bindings
%))
84 REM Loop round for tail-call optimisation.
86 REM The guide has us call FNeval_ast on the sub-list that excludes
87 REM the last element of ast%, but that's a bit painful without
88 REM native list slicing, so it's easier to just re-implement the
89 REM bit of FNeval_ast that we need.
91 WHILE NOT FNis_empty(FNrest(ast
%))
92 val
% = FNEVAL(FNfirst(ast
%), env
%)
97 IF FNis_truish(FNEVAL(FNnth(ast
%, 1), env
%)) THEN
100 IF FNcount(ast
%) = 3 THEN =FNnil
ELSE ast
% = FNnth(ast
%, 3)
102 REM Loop round for tail-call optimisation.
104 =FNalloc_fn(FNnth(ast
%, 2), FNnth(ast
%, 1), env
%)
109 IF NOT specialform
% THEN
110 REM This is the "apply" part.
111 ast
% = FNeval_ast(ast
%, env
%)
113 IF FNis_corefn(car
%) THEN
114 =FNcore_call(FNunbox_corefn(car
%), FNrest(ast
%))
116 IF FNis_fn(car
%) THEN
117 env
% = FNnew_env(FNfn_env(car
%), FNfn_params(car
%), FNrest(ast
%))
118 ast
% = FNfn_ast(car
%)
119 REM Loop round for tail-call optimisation.
121 ERROR &40E80918
, "Not a function"
127 =FNunbox_string(FNpr_str(a
%, TRUE))
130 =FNPRINT(FNEVAL(FNREAD(a
$), repl_env
%))
132 DEF
FNeval_ast(ast
%, env
%)
133 LOCAL val
%, car
%, cdr
%, map
%, keys
%, key$
134 IF FNis_symbol(ast
%) THEN =FNenv_get(env
%, ast
%)
135 IF FNis_seq(ast
%) THEN
136 IF FNis_empty(ast
%) THEN =ast
%
137 car
% = FNEVAL(FNfirst(ast
%), env
%)
138 cdr
% = FNeval_ast(FNrest(ast
%), env
%)
139 IF FNis_vector(ast
%) THEN =FNalloc_vector_pair(car
%, cdr
%)
140 =FNalloc_pair(car
%, cdr
%)
142 IF FNis_hashmap(ast
%) THEN
143 map
% = FNempty_hashmap
144 keys
% = FNhashmap_keys(ast
%)
145 WHILE NOT FNis_empty(keys
%)
146 key$
= FNunbox_string(FNfirst(keys
%))
147 map
% = FNhashmap_set(map
%, key
$, FNEVAL(FNhashmap_get(ast
%, key
$), env
%))
148 keys
% = FNrest(keys
%)
156 LOCAL argv
%, rargv
%, cmdptr
%, arg
$, len
%
158 IF !PAGE
= &D7C1C7C5
THEN
159 REM Running under Brandy, so ARGC and ARGV$ are usable.
161 FOR i
% = ARGC
TO 1 STEP
-1
162 argv
% = FNalloc_pair(FNalloc_string(ARGV
$(i%)), argv
%)
166 IF (INKEY(-256) AND &F0
) = &A0
THEN
168 REM Running under RISC OS
169 REM Vexingly, we can only get the command line that was passed to
170 REM the BASIC interpreter. This means that we need to extract
171 REM the arguments from that. Typically, we will have been started
172 REM with "BASIC -quit <filename> <args>".
175 SYS
"OS_GetEnv" TO cmdptr
%
177 SYS
"OS_GSTrans", cmdptr
%, q
%, &20000000 + 256 TO cmdptr
%, , len
%
179 rargv
% = FNalloc_pair(FNalloc_string($q%), rargv
%)
181 REM Put argv back into the right order.
182 WHILE NOT FNis_empty(rargv
%)
183 argv
% = FNalloc_pair(FNfirst(rargv
%), argv
%)
184 rargv
% = FNrest(rargv
%)
186 IF FNis_empty(argv
%) THEN =FNgc_exit(argv
%)
187 argv
% = FNrest(argv
%) : REM skip "BASIC"
188 IF FNis_empty(argv
%) THEN =FNgc_exit(argv
%)
189 IF FNunbox_string(FNfirst(argv
%)) <> "-quit" THEN =FNgc_exit(argv
%)
190 argv
% = FNrest(argv
%) : REM skip "-quit"
191 IF FNis_empty(argv
%) THEN =FNgc_exit(argv
%)
192 argv
% = FNrest(argv
%) : REM skip filename
199 REM indent-tabs-mode: nil