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
15 # READ: read and parse input
17 $(if
$(READLINE_EOF
)$(__ERROR
),,$(call READ_STR
,$(if
$(1),$(1),$(call READLINE
,"user> "))))
20 # EVAL: evaluate the parameter
21 IS_PAIR
= $(if
$(call _sequential?
,$(1)),$(if
$(call _EQ
,0,$(call _count
,$(1))),,true
),)
25 $(if
$(call _NOT
,$(call IS_PAIR
,$(1))),\
26 $(call _list
,$(call _symbol
,quote
) $(1)),\
27 $(if
$(call _EQ
,unquote
,$($(call _nth
,$(1),0)_value
)),\
29 $(if
$(and
$(call IS_PAIR
,$(call _nth
,$(1),0)),$(call _EQ
,splice-unquote
,$($(call _nth
,$(call _nth
,$(1),0),0)_value
))),\
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))))))))
35 $(if
$(call _list?
,$(1)),$(call ENV_FIND
,$(2),_macro_
$($(call _nth
,$(1),0)_value
)),)
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))),\
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
))),\
55 $(call LET
,$(left
),$(2))))))))
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
))\
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
)),\
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 _string
,$(__result
))),\
106 $(if
$(call _EQ
,try
*,$($(a0
)_value
)),\
107 $(foreach a1
,$(call _nth
,$(1),1),\
108 $(foreach res
,$(call EVAL
,$(a1
),$(2)),\
110 $(foreach a2
,$(call _nth
,$(1),2),\
111 $(foreach a20
,$(call _nth
,$(a2
),0),\
112 $(if
$(call _EQ
,catch
*,$($(a20
)_value
)),\
113 $(foreach a21
,$(call _nth
,$(a2
),1),\
114 $(foreach a22
,$(call _nth
,$(a2
),2),\
115 $(foreach binds
,$(call _list
,$(a21
)),\
116 $(foreach catch_env
,$(call ENV
,$(2),$(binds
),$(__ERROR
)),\
118 $(call EVAL
,$(a22
),$(catch_env
)))))),\
121 $(if
$(call _EQ
,do
,$($(a0
)_value
)),\
122 $(call slast
,$(call EVAL_AST
,$(call srest
,$(1)),$(2))),\
123 $(if
$(call _EQ
,if
,$($(a0
)_value
)),\
124 $(foreach a1
,$(call _nth
,$(1),1),\
125 $(foreach a2
,$(call _nth
,$(1),2),\
126 $(foreach cond
,$(call EVAL
,$(a1
),$(2)),\
127 $(if
$(or
$(call _EQ
,$(__nil
),$(cond
)),$(call _EQ
,$(__false
),$(cond
))),\
128 $(foreach a3
,$(call _nth
,$(1),3),$(call EVAL
,$(a3
),$(2))),\
129 $(call EVAL
,$(a2
),$(2)))))),\
130 $(if
$(call _EQ
,fn
*,$($(a0
)_value
)),\
131 $(foreach a1
,$(call _nth
,$(1),1),\
132 $(foreach a2
,$(call _nth
,$(1),2),\
133 $(call _function
,$$(call EVAL
,$(a2
),$$(call ENV
,$(2),$(a1
),$$1))))),\
134 $(foreach el
,$(call EVAL_AST
,$(1),$(2)),\
135 $(and
$(EVAL_DEBUG
),$(info invoke
: $(call _pr_str
,$(el
))))\
136 $(foreach f
,$(call sfirst
,$(el
)),\
137 $(foreach args
,$(call srest
,$(el
)),\
138 $(call apply
,$(f
),$(args
))))))))))))))))))
142 $(strip $(if
$(__ERROR
),,\
143 $(and
$(EVAL_DEBUG
),$(info EVAL
: $(call _pr_str
,$(1))))\
144 $(if
$(call _list?
,$(1)),\
145 $(foreach ast
,$(call MACROEXPAND
,$(1),$(2)),
146 $(if
$(call _list?
,$(ast
)),\
147 $(word 1,$(strip $(call EVAL_INVOKE
,$(ast
),$(2)) $(__nil
))),\
149 $(call EVAL_AST
,$(1),$(2)))))
155 $(if
$(__ERROR
),Error
: $(call _pr_str
,$(__ERROR
),yes
),$(if
$(1),$(call _pr_str
,$(1),yes
)))$(if
$(__ERROR
),$(eval __ERROR
:=),)
159 REPL_ENV
:= $(call ENV
)
160 REP
= $(call PRINT
,$(strip $(call EVAL
,$(strip $(call READ
,$(1))),$(REPL_ENV
))))
161 REPL
= $(info $(call REP
,$(call READLINE
,"user> ")))$(if
$(READLINE_EOF
),,$(call REPL
))
163 # core.mk: defined using Make
164 _fref
= $(eval REPL_ENV
:= $(call ENV_SET
,$(REPL_ENV
),$(1),$(call _function
,$$(call
$(2),$$1))))
165 _import_core
= $(if
$(strip $(1)),$(call _fref
,$(word 1,$(1)),$(word 2,$(1)))$(call _import_core
,$(wordlist
3,$(words $(1)),$(1))),)
166 $(call _import_core
,$(core_ns
))
167 REPL_ENV
:= $(call ENV_SET
,$(REPL_ENV
),eval
,$(call _function
,$$(call EVAL
,$$(1),$$(REPL_ENV
))))
168 _argv
:= $(call _list
)
169 REPL_ENV
:= $(call ENV_SET
,$(REPL_ENV
),*ARGV
*,$(_argv
))
171 # core.mal: defined in terms of the language itself
172 $(call do
,$(call REP
, (def
! *host-language
* "make") ))
173 $(call do
,$(call REP
, (def
! not
(fn
* (a
) (if a false true
))) ))
174 $(call do
,$(call REP
, (def
! load-file
(fn
* (f
) (eval
(read-string
(str
"(do " (slurp f
) ")"))))) ))
175 $(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
))))))) ))
176 $(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)))))))) ))
178 # Load and eval any files specified on the command line
179 $(if $(MAKECMDGOALS),\
180 $(foreach arg,$(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)),\
181 $(call do,$(call _conj!,$(_argv),$(call _string,$(arg)))))\
182 $(call do,$(call REP, (load-file "$(word 1,$(MAKECMDGOALS))") )) \
183 $(eval INTERACTIVE :=),)
186 $(if $(strip $(INTERACTIVE)),\
187 $(call do,$(call REP, (println (str "Mal [" *host-language* "]")) )) \
190 .PHONY: none $(MAKECMDGOALS)
191 none $(MAKECMDGOALS):