2019-04-10 23:51:49 +01:00
|
|
|
REM Step 4 of mal in BBC BASIC
|
2019-04-07 22:27:28 +01:00
|
|
|
|
|
|
|
|
LIBRARY "types"
|
|
|
|
|
LIBRARY "reader"
|
|
|
|
|
LIBRARY "printer"
|
|
|
|
|
LIBRARY "env"
|
2019-04-10 22:08:59 +01:00
|
|
|
LIBRARY "core"
|
2019-04-07 22:27:28 +01:00
|
|
|
|
|
|
|
|
PROCtypes_init
|
|
|
|
|
|
|
|
|
|
repl_env% = FNalloc_environment(FNnil)
|
2019-04-08 00:52:22 +01:00
|
|
|
PROCcore_ns : REM This sets the data pointer
|
2019-04-07 22:27:28 +01:00
|
|
|
REPEAT
|
2019-04-08 00:52:22 +01:00
|
|
|
READ sym$, i%
|
2019-04-07 22:27:28 +01:00
|
|
|
IF sym$ <> "" THEN
|
2022-01-10 00:15:40 +01:00
|
|
|
PROCenv_set(repl_env%, sym$, FNalloc_corefn(i%))
|
2019-04-07 22:27:28 +01:00
|
|
|
ENDIF
|
|
|
|
|
UNTIL sym$ = ""
|
|
|
|
|
|
2019-04-08 21:47:07 +01:00
|
|
|
val$ = FNrep("(def! not (fn* (a) (if a false true)))")
|
|
|
|
|
|
2019-05-17 00:35:02 +01:00
|
|
|
sav% = FNgc_save
|
2019-04-07 22:27:28 +01:00
|
|
|
REPEAT
|
|
|
|
|
REM Catch all errors apart from "Escape".
|
2019-05-17 00:35:02 +01:00
|
|
|
ON ERROR LOCAL IF ERR = 17 ON ERROR OFF: ERROR ERR, REPORT$ ELSE PRINT REPORT$
|
|
|
|
|
PROCgc_restore(sav%)
|
2019-05-03 22:57:56 +01:00
|
|
|
sav% = FNgc_save
|
2019-04-22 20:44:21 +01:00
|
|
|
PRINT "user> ";
|
|
|
|
|
LINE INPUT "" line$
|
|
|
|
|
PRINT FNrep(line$)
|
|
|
|
|
UNTIL FALSE
|
2019-04-07 22:27:28 +01:00
|
|
|
|
|
|
|
|
END
|
|
|
|
|
|
|
|
|
|
DEF FNREAD(a$)
|
2019-05-18 22:28:13 +01:00
|
|
|
=FNread_str(FNalloc_string(a$))
|
2019-04-07 22:27:28 +01:00
|
|
|
|
|
|
|
|
DEF FNEVAL(ast%, env%)
|
2019-04-18 22:40:33 +01:00
|
|
|
PROCgc
|
|
|
|
|
PROCgc_enter
|
|
|
|
|
=FNgc_exit(FNEVAL_(ast%, env%))
|
|
|
|
|
|
|
|
|
|
DEF FNEVAL_(ast%, env%)
|
2022-01-10 00:15:40 +01:00
|
|
|
LOCAL car%, val%, bindings%, key$
|
|
|
|
|
PROCgc_keep_only2(ast%, env%)
|
|
|
|
|
val% = FNenv_find(env%, "DEBUG-EVAL")
|
|
|
|
|
IF NOT FNis_nil(val%) THEN
|
|
|
|
|
IF FNis_truish(FNenv_get(val%, "DEBUG-EVAL")) THEN
|
|
|
|
|
PRINT "EVAL: " + FNunbox_string(FNpr_str(ast%, TRUE))
|
|
|
|
|
ENDIF
|
|
|
|
|
ENDIF
|
|
|
|
|
IF FNis_symbol(ast%) THEN =FNenv_get(env%, FNunbox_symbol(ast%))
|
|
|
|
|
IF FNis_hashmap(ast%) THEN
|
|
|
|
|
val% = FNempty_hashmap
|
|
|
|
|
bindings% = FNhashmap_keys(ast%)
|
|
|
|
|
WHILE NOT FNis_empty(bindings%)
|
|
|
|
|
key$ = FNunbox_string(FNfirst(bindings%))
|
|
|
|
|
val% = FNhashmap_set(val%, key$, FNEVAL(FNhashmap_get(ast%, key$), env%))
|
|
|
|
|
bindings% = FNrest(bindings%)
|
|
|
|
|
ENDWHILE
|
|
|
|
|
=val%
|
|
|
|
|
ENDIF
|
|
|
|
|
IF NOT FNis_seq(ast%) THEN =ast%
|
2019-04-07 22:27:28 +01:00
|
|
|
IF FNis_empty(ast%) THEN =ast%
|
2019-05-06 12:00:25 +01:00
|
|
|
car% = FNfirst(ast%)
|
2022-01-10 00:15:40 +01:00
|
|
|
IF FNis_vector(ast%) THEN =FNalloc_vector_pair(FNEVAL(car%, env%), FNeval_ast(FNrest(ast%), env%))
|
2019-04-07 22:27:28 +01:00
|
|
|
IF FNis_symbol(car%) THEN
|
2022-01-10 00:15:40 +01:00
|
|
|
key$ = FNunbox_symbol(car%)
|
|
|
|
|
CASE key$ OF
|
2019-04-07 22:27:28 +01:00
|
|
|
REM Special forms
|
|
|
|
|
WHEN "def!"
|
2022-01-10 00:15:40 +01:00
|
|
|
val% = FNEVAL(FNnth(ast%, 2), env%)
|
|
|
|
|
PROCenv_set(env%, FNunbox_symbol(FNnth(ast%, 1)), val%)
|
|
|
|
|
=val%
|
2019-04-07 22:27:28 +01:00
|
|
|
WHEN "let*"
|
2022-01-10 00:15:40 +01:00
|
|
|
env% = FNalloc_environment(env%)
|
|
|
|
|
bindings% = FNnth(ast%, 1)
|
|
|
|
|
WHILE NOT FNis_empty(bindings%)
|
|
|
|
|
PROCenv_set(env%, FNunbox_symbol(FNfirst(bindings%)), FNEVAL(FNnth(bindings%, 1), env%))
|
|
|
|
|
bindings% = FNrest(FNrest(bindings%))
|
|
|
|
|
ENDWHILE
|
|
|
|
|
=FNEVAL(FNnth(ast%, 2), env%)
|
2019-04-07 22:27:28 +01:00
|
|
|
WHEN "do"
|
2022-01-10 00:15:40 +01:00
|
|
|
WHILE TRUE
|
|
|
|
|
ast% = FNrest(ast%)
|
|
|
|
|
IF FNis_empty(ast%) THEN = val%
|
|
|
|
|
val% = FNEVAL(FNfirst(ast%), env%)
|
|
|
|
|
ENDWHILE
|
2019-04-07 22:27:28 +01:00
|
|
|
WHEN "if"
|
2022-01-10 00:15:40 +01:00
|
|
|
IF FNis_truish(FNEVAL(FNnth(ast%, 1), env%)) THEN =FNEVAL(FNnth(ast%, 2), env%)
|
|
|
|
|
IF FNcount(ast%) = 3 THEN =FNnil
|
|
|
|
|
=FNEVAL(FNnth(ast%, 3), env%)
|
2019-04-07 23:45:29 +01:00
|
|
|
WHEN "fn*"
|
2022-01-10 00:15:40 +01:00
|
|
|
=FNalloc_fn(FNnth(ast%, 2), FNnth(ast%, 1), env%)
|
|
|
|
|
OTHERWISE
|
|
|
|
|
car% = FNenv_get(env%, key$)
|
2019-04-07 22:27:28 +01:00
|
|
|
ENDCASE
|
2022-01-10 00:15:40 +01:00
|
|
|
ELSE
|
|
|
|
|
car% = FNEVAL(car%, env%)
|
|
|
|
|
ENDIF
|
|
|
|
|
REM This is the "apply" part.
|
|
|
|
|
ast% = FNeval_ast(FNrest(ast%), env%)
|
|
|
|
|
IF FNis_corefn(car%) THEN
|
|
|
|
|
=FNcore_call(FNunbox_corefn(car%), ast%)
|
2019-04-07 22:27:28 +01:00
|
|
|
ENDIF
|
2019-04-07 23:45:29 +01:00
|
|
|
IF FNis_fn(car%) THEN
|
2022-01-10 00:15:40 +01:00
|
|
|
env% = FNnew_env(FNfn_env(car%), FNfn_params(car%), ast%)
|
2019-04-10 23:59:17 +01:00
|
|
|
=FNEVAL(FNfn_ast(car%), env%)
|
2019-04-07 23:45:29 +01:00
|
|
|
ENDIF
|
|
|
|
|
ERROR &40E80918, "Not a function"
|
2019-04-07 22:27:28 +01:00
|
|
|
|
|
|
|
|
DEF FNPRINT(a%)
|
2019-05-18 22:28:13 +01:00
|
|
|
=FNunbox_string(FNpr_str(a%, TRUE))
|
2019-04-07 22:27:28 +01:00
|
|
|
|
|
|
|
|
DEF FNrep(a$)
|
|
|
|
|
=FNPRINT(FNEVAL(FNREAD(a$), repl_env%))
|
|
|
|
|
|
|
|
|
|
DEF FNeval_ast(ast%, env%)
|
|
|
|
|
IF FNis_empty(ast%) THEN =ast%
|
2022-01-10 00:15:40 +01:00
|
|
|
=FNalloc_pair(FNEVAL(FNfirst(ast%), env%), FNeval_ast(FNrest(ast%), env%))
|
2019-04-19 17:44:19 +01:00
|
|
|
|
|
|
|
|
REM Local Variables:
|
|
|
|
|
REM indent-tabs-mode: nil
|
|
|
|
|
REM End:
|