All: *ARGV* and *host-language*. Misc syncing/fixes.
[jackhill/mal.git] / make / step9_interop.mk
CommitLineData
31690700
JM
1#
2# mal (Make Lisp)
3#
4_TOP_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
5include $(_TOP_DIR)types.mk
6include $(_TOP_DIR)reader.mk
ea81a808
JM
7include $(_TOP_DIR)printer.mk
8include $(_TOP_DIR)env.mk
9include $(_TOP_DIR)core.mk
31690700
JM
10
11SHELL := /bin/bash
12INTERACTIVE ?= yes
13EVAL_DEBUG ?=
14
15# READ: read and parse input
16define READ
17$(if $(READLINE_EOF)$(__ERROR),,$(call READ_STR,$(if $(1),$(1),$(call READLINE,"user> "))))
18endef
19
20# EVAL: evaluate the parameter
db4c329a 21IS_PAIR = $(if $(call _sequential?,$(1)),$(if $(call _EQ,0,$(call _count,$(1))),,true),)
31690700
JM
22
23define QUASIQUOTE
24$(strip \
25 $(if $(call _NOT,$(call IS_PAIR,$(1))),\
ea81a808 26 $(call _list,$(call _symbol,quote) $(1)),\
31690700
JM
27 $(if $(call _EQ,unquote,$($(call _nth,$(1),0)_value)),\
28 $(call _nth,$(1),1),\
29 $(if $(and $(call IS_PAIR,$(call _nth,$(1),0)),$(call _EQ,splice-unquote,$($(call _nth,$(call _nth,$(1),0),0)_value))),\
ea81a808
JM
30 $(call _list,$(call _symbol,concat) $(call _nth,$(call _nth,$(1),0),1) $(call QUASIQUOTE,$(call srest,$(1)))),\
31 $(call _list,$(call _symbol,cons) $(call QUASIQUOTE,$(call _nth,$(1),0)) $(call QUASIQUOTE,$(call srest,$(1))))))))
31690700
JM
32endef
33
34define IS_MACRO_CALL
35$(if $(call _list?,$(1)),$(call ENV_FIND,$(2),_macro_$($(call _nth,$(1),0)_value)),)
36endef
37
38define MACROEXPAND
39$(strip $(if $(__ERROR),,\
40 $(if $(call IS_MACRO_CALL,$(1),$(2)),\
41 $(foreach mac,$(call ENV_GET,$(2),$($(call _nth,$(1),0)_value)),\
42 $(call MACROEXPAND,$(call apply,$(mac),$(call srest,$(1))),$(2))),\
43 $(1))))
44endef
45
46define LET
47$(strip \
48 $(word 1,$(2) \
49 $(foreach var,$(call _nth,$(1),0),\
50 $(foreach val,$(call _nth,$(1),1),\
51 $(call ENV_SET,$(2),$($(var)_value),$(call EVAL,$(val),$(2)))\
52 $(foreach left,$(call srest,$(call srest,$(1))),
53 $(if $(call _EQ,0,$(call _count,$(left))),\
54 ,\
55 $(call LET,$(left),$(2))))))))
56endef
57
58define EVAL_AST
59$(strip \
60 $(and $(EVAL_DEBUG),$(info EVAL_AST: $(call _pr_str,$(1))))\
61 $(if $(call _symbol?,$(1)),\
62 $(foreach key,$($(1)_value),\
63 $(call ENV_GET,$(2),$(key))),\
64 $(if $(call _list?,$(1)),\
65 $(call _smap,EVAL,$(1),$(2)),\
66 $(if $(call _vector?,$(1)),\
67 $(call _smap_vec,EVAL,$(1),$(2)),\
68 $(if $(call _hash_map?,$(1)),\
69 $(foreach new_hmap,$(call __new_obj,hmap),\
70 $(foreach v,$(call __get_obj_values,$(1)),\
71 $(eval $(v:$(1)_%=$(new_hmap)_%) := $(call EVAL,$($(v)),$(2))))\
72 $(eval $(new_hmap)_size := $($(1)_size))\
73 $(new_hmap)),\
74 $(1))))))
75endef
76
77define EVAL_INVOKE
78$(if $(__ERROR),,\
79 $(and $(EVAL_DEBUG),$(info EVAL_INVOKE: $(call _pr_str,$(1))))
80 $(foreach a0,$(call _nth,$(1),0),\
81 $(if $(call _EQ,def!,$($(a0)_value)),\
82 $(foreach a1,$(call _nth,$(1),1),\
83 $(foreach a2,$(call _nth,$(1),2),\
84 $(foreach res,$(call EVAL,$(a2),$(2)),\
85 $(if $(call ENV_SET,$(2),$($(a1)_value),$(res)),$(res),)))),\
86 $(if $(call _EQ,let*,$($(a0)_value)),\
87 $(foreach a1,$(call _nth,$(1),1),\
88 $(foreach a2,$(call _nth,$(1),2),\
89 $(call EVAL,$(a2),$(call LET,$(a1),$(call ENV,$(2)))))),\
90 $(if $(call _EQ,quote,$($(a0)_value)),\
91 $(call _nth,$(1),1),\
92 $(if $(call _EQ,quasiquote,$($(a0)_value)),\
93 $(call EVAL,$(call QUASIQUOTE,$(call _nth,$(1),1)),$(2)),\
94 $(if $(call _EQ,defmacro!,$($(a0)_value)),\
95 $(foreach a1,$(call _nth,$(1),1),\
96 $(foreach a2,$(call _nth,$(1),2),\
97 $(foreach res,$(call EVAL,$(a2),$(2)),\
98 $(if $(call ENV_SET,$(2),_macro_$($(a1)_value),true),,)\
99 $(if $(call ENV_SET,$(2),$($(a1)_value),$(res)),$(res),)))),\
100 $(if $(call _EQ,macroexpand,$($(a0)_value)),\
101 $(call MACROEXPAND,$(call _nth,$(1),1),$(2)),\
102 $(if $(call _EQ,make*,$($(a0)_value)),\
103 $(foreach a1,$(call _nth,$(1),1),\
104 $(and $(EVAL_DEBUG),$(info make*: $$(eval __result := $(call str_decode,$(value $(a1)_value)))))\
105 $(eval __result := $(call str_decode,$(value $(a1)_value)))$(call READ_STR,$(__result))),\
106 $(if $(call _EQ,do,$($(a0)_value)),\
107 $(call slast,$(call EVAL_AST,$(call srest,$(1)),$(2))),\
108 $(if $(call _EQ,if,$($(a0)_value)),\
109 $(foreach a1,$(call _nth,$(1),1),\
110 $(foreach a2,$(call _nth,$(1),2),\
111 $(foreach cond,$(call EVAL,$(a1),$(2)),\
112 $(if $(or $(call _EQ,$(__nil),$(cond)),$(call _EQ,$(__false),$(cond))),\
113 $(foreach a3,$(call _nth,$(1),3),$(call EVAL,$(a3),$(2))),\
114 $(call EVAL,$(a2),$(2)))))),\
115 $(if $(call _EQ,fn*,$($(a0)_value)),\
116 $(foreach a1,$(call _nth,$(1),1),\
117 $(foreach a2,$(call _nth,$(1),2),\
ea81a808 118 $(call _function,$$(call EVAL,$(a2),$$(call ENV,$(2),$(a1),$$1))))),\
31690700
JM
119 $(foreach el,$(call EVAL_AST,$(1),$(2)),\
120 $(and $(EVAL_DEBUG),$(info invoke: $(call _pr_str,$(el))))\
121 $(foreach f,$(call sfirst,$(el)),\
122 $(foreach args,$(call srest,$(el)),\
123 $(call apply,$(f),$(args)))))))))))))))))
124endef
125
126define EVAL
127$(strip $(if $(__ERROR),,\
128 $(and $(EVAL_DEBUG),$(info EVAL: $(call _pr_str,$(1))))\
129 $(if $(call _list?,$(1)),\
130 $(foreach ast,$(call MACROEXPAND,$(1),$(2)),
131 $(if $(call _list?,$(ast)),\
132 $(word 1,$(strip $(call EVAL_INVOKE,$(ast),$(2)) $(__nil))),\
133 $(ast))),\
134 $(call EVAL_AST,$(1),$(2)))))
135endef
136
137
138# PRINT:
139define PRINT
140$(if $(__ERROR),Error: $(call _pr_str,$(__ERROR),yes),$(if $(1),$(call _pr_str,$(1),yes)))$(if $(__ERROR),$(eval __ERROR :=),)
141endef
142
143# REPL:
144REPL_ENV := $(call ENV)
145REP = $(call PRINT,$(strip $(call EVAL,$(strip $(call READ,$(1))),$(REPL_ENV))))
146REPL = $(info $(call REP,$(call READLINE,"user> ")))$(if $(READLINE_EOF),,$(call REPL))
147
8cb5cda4 148# core.mk: defined using Make
ea81a808 149_fref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(call _function,$$(call $(2),$$1))))
ea81a808
JM
150_import_core = $(if $(strip $(1)),$(call _fref,$(word 1,$(1)),$(word 2,$(1)))$(call _import_core,$(wordlist 3,$(words $(1)),$(1))),)
151$(call _import_core,$(core_ns))
8cb5cda4 152REPL_ENV := $(call ENV_SET,$(REPL_ENV),eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
86b689f3
JM
153_argv := $(call _list)
154REPL_ENV := $(call ENV_SET,$(REPL_ENV),*ARGV*,$(_argv))
31690700 155
8cb5cda4 156# core.mal: defined in terms of the language itself
31690700 157$(call do,$(call REP, (def! not (fn* (a) (if a false true))) ))
1617910a 158$(call do,$(call REP, (def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")"))))) ))
8cb5cda4
JM
159$(call do,$(call REP, (defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw "odd number of forms to cond")) (cons 'cond (rest (rest xs))))))) ))
160$(call do,$(call REP, (defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs)))))))) ))
31690700
JM
161
162# Load and eval any files specified on the command line
163$(if $(MAKECMDGOALS),\
86b689f3
JM
164 $(foreach arg,$(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)),\
165 $(call do,$(call _conj!,$(_argv),$(call _string,$(arg)))))\
166 $(call do,$(call REP, (load-file "$(word 1,$(MAKECMDGOALS))") )) \
31690700
JM
167 $(eval INTERACTIVE :=),)
168.PHONY: none $(MAKECMDGOALS)
169none $(MAKECMDGOALS):
170 @true
171
86b689f3 172# repl loop
31690700 173$(if $(strip $(INTERACTIVE)),$(call REPL))