| 1 | # |
| 2 | # mal (Make a Lisp) Core functions |
| 3 | # |
| 4 | |
| 5 | ifndef __mal_core_included |
| 6 | __mal_core_included := true |
| 7 | |
| 8 | _TOP_DIR := $(dir $(lastword $(MAKEFILE_LIST))) |
| 9 | include $(_TOP_DIR)util.mk |
| 10 | include $(_TOP_DIR)types.mk |
| 11 | include $(_TOP_DIR)readline.mk |
| 12 | include $(_TOP_DIR)reader.mk |
| 13 | include $(_TOP_DIR)printer.mk |
| 14 | |
| 15 | |
| 16 | # Errors/Exceptions |
| 17 | throw = $(eval __ERROR := $(1)) |
| 18 | |
| 19 | |
| 20 | # General functions |
| 21 | |
| 22 | # Return the type of the object (or "make" if it's not a object |
| 23 | obj_type = $(call _string,$(call _obj_type,$(1))) |
| 24 | |
| 25 | equal? = $(if $(call _equal?,$(word 1,$(1)),$(word 2,$(1))),$(__true),$(__false)) |
| 26 | |
| 27 | |
| 28 | # Scalar functions |
| 29 | nil? = $(if $(call _nil?,$(1)),$(__true),$(__false)) |
| 30 | true? = $(if $(call _true?,$(1)),$(__true),$(__false)) |
| 31 | false? = $(if $(call _false?,$(1)),$(__true),$(__false)) |
| 32 | |
| 33 | |
| 34 | # Symbol functions |
| 35 | symbol = $(call _symbol,$(call str_decode,$($(1)_value))) |
| 36 | symbol? = $(if $(call _symbol?,$(1)),$(__true),$(__false)) |
| 37 | |
| 38 | # Keyword functions |
| 39 | keyword = $(call _keyword,$(call str_decode,$($(1)_value))) |
| 40 | keyword? = $(if $(call _keyword?,$(1)),$(__true),$(__false)) |
| 41 | |
| 42 | |
| 43 | # Number functions |
| 44 | number? = $(if $(call _number?,$(1)),$(__true),$(__false)) |
| 45 | |
| 46 | number_lt = $(if $(call int_lt_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)),$(__true),$(__false)) |
| 47 | number_lte = $(if $(call int_lte_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)),$(__true),$(__false)) |
| 48 | number_gt = $(if $(call int_gt_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)),$(__true),$(__false)) |
| 49 | number_gte = $(if $(call int_gte_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)),$(__true),$(__false)) |
| 50 | |
| 51 | number_plus = $(call _pnumber,$(call int_add_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value))) |
| 52 | number_subtract = $(call _pnumber,$(call int_sub_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value))) |
| 53 | number_multiply = $(call _pnumber,$(call int_mult_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value))) |
| 54 | number_divide = $(call _pnumber,$(call int_div_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value))) |
| 55 | |
| 56 | time_ms = $(call _number,$(shell echo $$(date +%s%3N))) |
| 57 | |
| 58 | # String functions |
| 59 | |
| 60 | string? = $(if $(call _string?,$(1)),$(if $(call _keyword?,$(1)),$(__false),$(__true)),$(__false)) |
| 61 | |
| 62 | pr_str = $(call _string,$(call _pr_str_mult,$(1),yes, )) |
| 63 | str = $(call _string,$(call _pr_str_mult,$(1),,)) |
| 64 | prn = $(info $(call _pr_str_mult,$(1),yes, )) |
| 65 | println = $(info $(subst \n,$(NEWLINE),$(call _pr_str_mult,$(1),, ))) |
| 66 | |
| 67 | readline= $(foreach res,$(call _string,$(call READLINE,"$(call str_decode,$($(1)_value))")),$(if $(READLINE_EOF),$(eval READLINE_EOF :=)$(__nil),$(res))) |
| 68 | read_str= $(call READ_STR,$(1)) |
| 69 | slurp = $(call _string,$(call _read_file,$(call str_decode,$($(1)_value)))) |
| 70 | |
| 71 | subs = $(strip \ |
| 72 | $(foreach start,$(call int_add,1,$(call int_decode,$($(word 2,$(1))_value))),\ |
| 73 | $(foreach end,$(if $(3),$(call int_decode,$($(3)_value)),$(words $($(word 1,$(1))_value))),\ |
| 74 | $(call _string,$(wordlist $(start),$(end),$($(word 1,$(1))_value)))))) |
| 75 | |
| 76 | |
| 77 | |
| 78 | # Function functions |
| 79 | fn? = $(if $(call _function?,$(1)),$(if $(_macro_$(1)),$(__false),$(__true)),$(__false)) |
| 80 | macro? = $(if $(_macro_$(1)),$(__true),$(__false)) |
| 81 | |
| 82 | |
| 83 | # List functions |
| 84 | list? = $(if $(call _list?,$(1)),$(__true),$(__false)) |
| 85 | |
| 86 | |
| 87 | # Vector functions |
| 88 | vector? = $(if $(call _vector?,$(1)),$(__true),$(__false)) |
| 89 | |
| 90 | |
| 91 | # Hash map (associative array) functions |
| 92 | hash_map? = $(if $(call _hash_map?,$(1)),$(__true),$(__false)) |
| 93 | |
| 94 | # set a key/value in a copy of the hash map |
| 95 | assoc = $(word 1,\ |
| 96 | $(foreach hm,$(call _clone_obj,$(word 1,$(1))),\ |
| 97 | $(hm) \ |
| 98 | $(call _assoc_seq!,$(hm),$(wordlist 2,$(words $(1)),$(1))))) |
| 99 | |
| 100 | # unset keys in a copy of the hash map |
| 101 | # TODO: this could be made more efficient by copying only the |
| 102 | # keys that not being removed. |
| 103 | dissoc = $(word 1,\ |
| 104 | $(foreach hm,$(call _clone_obj,$(word 1,$(1))),\ |
| 105 | $(hm) \ |
| 106 | $(call _dissoc_seq!,$(hm),$(wordlist 2,$(words $(1)),$(1))))) |
| 107 | |
| 108 | keys = $(foreach new_list,$(call _list),$(new_list)$(eval $(new_list)_value := $(foreach v,$(call __get_obj_values,$(1)),$(foreach vval,$(word 4,$(subst _, ,$(v))),$(if $(filter $(__keyword)%,$(vval)),$(call _keyword,$(patsubst $(__keyword)%,%,$(vval))),$(call _string,$(vval))))))) |
| 109 | |
| 110 | vals = $(foreach new_list,$(call _list),$(new_list)$(eval $(new_list)_value := $(foreach v,$(call __get_obj_values,$(1)),$($(v))))) |
| 111 | |
| 112 | # Hash map and vector functions |
| 113 | |
| 114 | # retrieve the value of a string key object from the hash map, or |
| 115 | # retrive a vector by number object index |
| 116 | get = $(strip \ |
| 117 | $(if $(call _nil?,$(word 1,$(1))),\ |
| 118 | $(__nil),\ |
| 119 | $(if $(call _hash_map?,$(word 1,$(1))),\ |
| 120 | $(call _get,$(word 1,$(1)),$(call str_decode,$($(word 2,$(1))_value))),\ |
| 121 | $(call _get,$(word 1,$(1)),$(call int_decode,$($(word 2,$(1))_value)))))) |
| 122 | |
| 123 | contains? = $(if $(call _contains?,$(word 1,$(1)),$(call str_decode,$($(word 2,$(1))_value))),$(__true),$(__false)) |
| 124 | |
| 125 | |
| 126 | # sequence operations |
| 127 | |
| 128 | sequential? = $(if $(call _sequential?,$(1)),$(__true),$(__false)) |
| 129 | |
| 130 | cons = $(word 1,$(foreach new_list,$(call _list),$(new_list) $(eval $(new_list)_value := $(strip $(word 1,$(1)) $(call __get_obj_values,$(word 2,$(1))))))) |
| 131 | |
| 132 | concat = $(word 1,$(foreach new_list,$(call _list),$(new_list) $(eval $(new_list)_value := $(strip $(foreach lst,$1,$(call __get_obj_values,$(lst))))))) |
| 133 | |
| 134 | nth = $(strip \ |
| 135 | $(if $(call int_lt,$($(word 2,$(1))_value),$(call int_encode,$(call _count,$(word 1,$(1))))),\ |
| 136 | $(word $(call int_add,1,$(call int_decode,$($(word 2,$(1))_value))),$($(word 1,$(1))_value)),\ |
| 137 | $(call _error,nth: index out of range))) |
| 138 | |
| 139 | sfirst = $(word 1,$($(1)_value)) |
| 140 | |
| 141 | slast = $(word $(words $($(1)_value)),$($(1)_value)) |
| 142 | |
| 143 | empty? = $(if $(call _EQ,0,$(if $(call _hash_map?,$(1)),$($(1)_size),$(words $($(1)_value)))),$(__true),$(__false)) |
| 144 | |
| 145 | count = $(call _number,$(call _count,$(1))) |
| 146 | |
| 147 | # Creates a new vector/list of the everything after but the first |
| 148 | # element |
| 149 | srest = $(word 1,$(foreach new_list,$(call _list),\ |
| 150 | $(new_list) \ |
| 151 | $(eval $(new_list)_value := $(wordlist 2,$(words $($(1)_value)),$($(1)_value))))) |
| 152 | |
| 153 | # Takes a space separated arguments and invokes the first argument |
| 154 | # (function object) using the remaining arguments. |
| 155 | sapply = $(call $(word 1,$(1))_value,$(strip \ |
| 156 | $(wordlist 2,$(call int_sub,$(words $(1)),1),$(1)) \ |
| 157 | $($(word $(words $(1)),$(1))_value))) |
| 158 | |
| 159 | # Map a function object over a list object |
| 160 | smap = $(strip\ |
| 161 | $(foreach func,$(word 1,$(1)),\ |
| 162 | $(foreach lst,$(word 2,$(1)),\ |
| 163 | $(foreach type,list,\ |
| 164 | $(foreach new_hcode,$(call __new_obj_hash_code),\ |
| 165 | $(foreach sz,$(words $(call __get_obj_values,$(lst))),\ |
| 166 | $(eval $(__obj_magic)_$(type)_$(new_hcode)_value := $(strip \ |
| 167 | $(foreach val,$(call __get_obj_values,$(lst)),\ |
| 168 | $(call $(func)_value,$(val))))))\ |
| 169 | $(__obj_magic)_$(type)_$(new_hcode)))))) |
| 170 | |
| 171 | conj = $(word 1,$(foreach new_list,$(call __new_obj_like,$(word 1,$(1))),\ |
| 172 | $(new_list) \ |
| 173 | $(eval $(new_list)_value := $(strip $($(word 1,$(1))_value))) \ |
| 174 | $(if $(call _list?,$(new_list)),\ |
| 175 | $(foreach elem,$(wordlist 2,$(words $(1)),$(1)),\ |
| 176 | $(eval $(new_list)_value := $(strip $(elem) $($(new_list)_value)))),\ |
| 177 | $(eval $(new_list)_value := $(strip $($(new_list)_value) $(wordlist 2,$(words $(1)),$(1))))))) |
| 178 | |
| 179 | seq = $(strip\ |
| 180 | $(if $(call _list?,$(1)),\ |
| 181 | $(if $(call _EQ,0,$(call _count,$(1))),$(__nil),$(1)),\ |
| 182 | $(if $(call _vector?,$(1)),\ |
| 183 | $(if $(call _EQ,0,$(call _count,$(1))),\ |
| 184 | $(__nil),\ |
| 185 | $(word 1,$(foreach new_list,$(call _list),\ |
| 186 | $(new_list) \ |
| 187 | $(eval $(new_list)_value := $(strip $($(word 1,$(1))_value)))))),\ |
| 188 | $(if $(call _EQ,string,$(call _obj_type,$(1))),\ |
| 189 | $(if $(call _EQ,0,$(call _count,$(1))),\ |
| 190 | $(__nil),\ |
| 191 | $(word 1,$(foreach new_list,$(call _list),\ |
| 192 | $(new_list) \ |
| 193 | $(eval $(new_list)_value := $(strip \ |
| 194 | $(foreach c,$($(word 1,$(1))_value),\ |
| 195 | $(call _string,$(c)))))))),\ |
| 196 | $(if $(call _nil?,$(1)),\ |
| 197 | $(__nil),\ |
| 198 | $(call _error,seq: called on non-sequence)))))) |
| 199 | |
| 200 | # Metadata functions |
| 201 | |
| 202 | with_meta = $(strip \ |
| 203 | $(foreach new_obj,$(call _clone_obj,$(word 1,$(1))),\ |
| 204 | $(eval $(new_obj)_meta := $(strip $(word 2,$(1))))\ |
| 205 | $(new_obj))) |
| 206 | |
| 207 | meta = $(strip $($(1)_meta)) |
| 208 | |
| 209 | |
| 210 | # Atom functions |
| 211 | |
| 212 | atom = $(strip \ |
| 213 | $(foreach hcode,$(call __new_obj_hash_code),\ |
| 214 | $(foreach new_atom,$(__obj_magic)_atom_$(hcode),\ |
| 215 | $(new_atom)\ |
| 216 | $(eval $(new_atom)_value := $(1))))) |
| 217 | atom? = $(if $(call _atom?,$(1)),$(__true),$(__false)) |
| 218 | |
| 219 | deref = $($(1)_value) |
| 220 | |
| 221 | reset! = $(eval $(word 1,$(1))_value := $(word 2,$(1)))$(word 2,$(1)) |
| 222 | |
| 223 | swap! = $(foreach resp,$(call $(word 2,$(1))_value,$($(word 1,$(1))_value) $(wordlist 3,$(words $(1)),$(1))),\ |
| 224 | $(eval $(word 1,$(1))_value := $(resp))\ |
| 225 | $(resp)) |
| 226 | |
| 227 | |
| 228 | |
| 229 | |
| 230 | # Namespace of core functions |
| 231 | |
| 232 | core_ns = type obj_type \ |
| 233 | = equal? \ |
| 234 | throw throw \ |
| 235 | nil? nil? \ |
| 236 | true? true? \ |
| 237 | false? false? \ |
| 238 | string? string? \ |
| 239 | symbol symbol \ |
| 240 | symbol? symbol? \ |
| 241 | keyword keyword \ |
| 242 | keyword? keyword? \ |
| 243 | number? number? \ |
| 244 | fn? fn? \ |
| 245 | macro? macro? \ |
| 246 | \ |
| 247 | pr-str pr_str \ |
| 248 | str str \ |
| 249 | prn prn \ |
| 250 | println println \ |
| 251 | readline readline \ |
| 252 | read-string read_str \ |
| 253 | slurp slurp \ |
| 254 | subs subs \ |
| 255 | < number_lt \ |
| 256 | <= number_lte \ |
| 257 | > number_gt \ |
| 258 | >= number_gte \ |
| 259 | + number_plus \ |
| 260 | - number_subtract \ |
| 261 | * number_multiply \ |
| 262 | / number_divide \ |
| 263 | time-ms time_ms \ |
| 264 | \ |
| 265 | list _list \ |
| 266 | list? list? \ |
| 267 | vector _vector \ |
| 268 | vector? vector? \ |
| 269 | hash-map _hash_map \ |
| 270 | map? hash_map? \ |
| 271 | assoc assoc \ |
| 272 | dissoc dissoc \ |
| 273 | get get \ |
| 274 | contains? contains? \ |
| 275 | keys keys \ |
| 276 | vals vals \ |
| 277 | \ |
| 278 | sequential? sequential? \ |
| 279 | cons cons \ |
| 280 | concat concat \ |
| 281 | nth nth \ |
| 282 | first sfirst \ |
| 283 | rest srest \ |
| 284 | last slast \ |
| 285 | empty? empty? \ |
| 286 | count count \ |
| 287 | apply sapply \ |
| 288 | map smap \ |
| 289 | \ |
| 290 | conj conj \ |
| 291 | seq seq \ |
| 292 | \ |
| 293 | with-meta with_meta \ |
| 294 | meta meta \ |
| 295 | atom atom \ |
| 296 | atom? atom? \ |
| 297 | deref deref \ |
| 298 | reset! reset! \ |
| 299 | swap! swap! |
| 300 | |
| 301 | endif |