README: make NalaGinrut user name into a link.
[jackhill/mal.git] / make / step6_file.mk
1 #
2 # mal (Make Lisp)
3 #
4 _TOP_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
5 include $(_TOP_DIR)types.mk
6 include $(_TOP_DIR)reader.mk
7 include $(_TOP_DIR)printer.mk
8 include $(_TOP_DIR)env.mk
9 include $(_TOP_DIR)core.mk
10
11 SHELL := /bin/bash
12 INTERACTIVE ?= yes
13 EVAL_DEBUG ?=
14
15 # READ: read and parse input
16 define READ
17 $(if $(READLINE_EOF)$(__ERROR),,$(call READ_STR,$(if $(1),$(1),$(call READLINE,"user> "))))
18 endef
19
20 # EVAL: evaluate the parameter
21 define LET
22 $(strip \
23 $(word 1,$(2) \
24 $(foreach var,$(call _nth,$(1),0),\
25 $(foreach val,$(call _nth,$(1),1),\
26 $(call ENV_SET,$(2),$($(var)_value),$(call EVAL,$(val),$(2)))\
27 $(foreach left,$(call srest,$(call srest,$(1))),
28 $(if $(call _EQ,0,$(call _count,$(left))),\
29 ,\
30 $(call LET,$(left),$(2))))))))
31 endef
32
33 define EVAL_AST
34 $(strip \
35 $(and $(EVAL_DEBUG),$(info EVAL_AST: $(call _pr_str,$(1))))\
36 $(if $(call _symbol?,$(1)),\
37 $(foreach key,$($(1)_value),\
38 $(call ENV_GET,$(2),$(key))),\
39 $(if $(call _list?,$(1)),\
40 $(call _smap,EVAL,$(1),$(2)),\
41 $(if $(call _vector?,$(1)),\
42 $(call _smap_vec,EVAL,$(1),$(2)),\
43 $(if $(call _hash_map?,$(1)),\
44 $(foreach new_hmap,$(call __new_obj,hmap),\
45 $(foreach v,$(call __get_obj_values,$(1)),\
46 $(eval $(v:$(1)_%=$(new_hmap)_%) := $(call EVAL,$($(v)),$(2))))\
47 $(eval $(new_hmap)_size := $($(1)_size))\
48 $(new_hmap)),\
49 $(1))))))
50 endef
51
52 define EVAL_INVOKE
53 $(if $(__ERROR),,\
54 $(and $(EVAL_DEBUG),$(info EVAL_INVOKE: $(call _pr_str,$(1))))
55 $(foreach a0,$(call _nth,$(1),0),\
56 $(if $(call _EQ,def!,$($(a0)_value)),\
57 $(foreach a1,$(call _nth,$(1),1),\
58 $(foreach a2,$(call _nth,$(1),2),\
59 $(foreach res,$(call EVAL,$(a2),$(2)),\
60 $(if $(__ERROR),,\
61 $(if $(call ENV_SET,$(2),$($(a1)_value),$(res)),$(res),))))),\
62 $(if $(call _EQ,let*,$($(a0)_value)),\
63 $(foreach a1,$(call _nth,$(1),1),\
64 $(foreach a2,$(call _nth,$(1),2),\
65 $(call EVAL,$(a2),$(call LET,$(a1),$(call ENV,$(2)))))),\
66 $(if $(call _EQ,do,$($(a0)_value)),\
67 $(call slast,$(call EVAL_AST,$(call srest,$(1)),$(2))),\
68 $(if $(call _EQ,if,$($(a0)_value)),\
69 $(foreach a1,$(call _nth,$(1),1),\
70 $(foreach a2,$(call _nth,$(1),2),\
71 $(foreach cond,$(call EVAL,$(a1),$(2)),\
72 $(if $(or $(call _EQ,$(__nil),$(cond)),$(call _EQ,$(__false),$(cond))),\
73 $(foreach a3,$(call _nth,$(1),3),$(call EVAL,$(a3),$(2))),\
74 $(call EVAL,$(a2),$(2)))))),\
75 $(if $(call _EQ,fn*,$($(a0)_value)),\
76 $(foreach a1,$(call _nth,$(1),1),\
77 $(foreach a2,$(call _nth,$(1),2),\
78 $(call _function,$$(call EVAL,$(a2),$$(call ENV,$(2),$(a1),$$1))))),\
79 $(foreach el,$(call EVAL_AST,$(1),$(2)),\
80 $(and $(EVAL_DEBUG),$(info invoke: $(call _pr_str,$(el))))\
81 $(foreach f,$(call sfirst,$(el)),\
82 $(foreach args,$(call srest,$(el)),\
83 $(call apply,$(f),$(args))))))))))))
84 endef
85
86 define EVAL
87 $(strip $(if $(__ERROR),,\
88 $(and $(EVAL_DEBUG),$(info EVAL: $(call _pr_str,$(1))))\
89 $(if $(call _list?,$(1)),\
90 $(word 1,$(strip $(call EVAL_INVOKE,$(1),$(2)) $(__nil))),\
91 $(call EVAL_AST,$(1),$(2)))))
92 endef
93
94
95 # PRINT:
96 define PRINT
97 $(if $(__ERROR),Error: $(call _pr_str,$(__ERROR),yes),$(if $(1),$(call _pr_str,$(1),yes)))$(if $(__ERROR),$(eval __ERROR :=),)
98 endef
99
100 # REPL:
101 REPL_ENV := $(call ENV)
102 REP = $(call PRINT,$(strip $(call EVAL,$(strip $(call READ,$(1))),$(REPL_ENV))))
103 REPL = $(info $(call REP,$(call READLINE,"user> ")))$(if $(READLINE_EOF),,$(call REPL))
104
105 # core.mk: defined using Make
106 _fref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(call _function,$$(call $(2),$$1))))
107 _import_core = $(if $(strip $(1)),$(call _fref,$(word 1,$(1)),$(word 2,$(1)))$(call _import_core,$(wordlist 3,$(words $(1)),$(1))),)
108 $(call _import_core,$(core_ns))
109 REPL_ENV := $(call ENV_SET,$(REPL_ENV),eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
110 _argv := $(call _list)
111 REPL_ENV := $(call ENV_SET,$(REPL_ENV),*ARGV*,$(_argv))
112
113 # core.mal: defined in terms of the language itself
114 $(call do,$(call REP, (def! not (fn* (a) (if a false true))) ))
115 $(call do,$(call REP, (def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")"))))) ))
116
117 # Load and eval any files specified on the command line
118 $(if $(MAKECMDGOALS),\
119 $(foreach arg,$(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)),\
120 $(call do,$(call _conj!,$(_argv),$(call _string,$(arg)))))\
121 $(call do,$(call REP, (load-file "$(word 1,$(MAKECMDGOALS))") )) \
122 $(eval INTERACTIVE :=),)
123
124 # repl loop
125 $(if $(strip $(INTERACTIVE)),$(call REPL))
126
127 .PHONY: none $(MAKECMDGOALS)
128 none $(MAKECMDGOALS):
129 @true