2014-04-03 07:23:37 +04:00
|
|
|
#
|
|
|
|
# mal (Make a Lisp) Core functions
|
|
|
|
#
|
|
|
|
|
|
|
|
ifndef __mal_core_included
|
|
|
|
__mal_core_included := true
|
|
|
|
|
|
|
|
_TOP_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
|
|
|
|
include $(_TOP_DIR)util.mk
|
|
|
|
include $(_TOP_DIR)types.mk
|
2014-04-17 08:57:50 +04:00
|
|
|
include $(_TOP_DIR)readline.mk
|
|
|
|
include $(_TOP_DIR)reader.mk
|
2014-04-03 07:23:37 +04:00
|
|
|
include $(_TOP_DIR)printer.mk
|
|
|
|
|
|
|
|
|
|
|
|
# Errors/Exceptions
|
|
|
|
throw = $(eval __ERROR := $(1))
|
|
|
|
|
|
|
|
|
|
|
|
# General functions
|
|
|
|
|
|
|
|
# Return the type of the object (or "make" if it's not a object
|
|
|
|
obj_type = $(call _string,$(call _obj_type,$(1)))
|
|
|
|
|
|
|
|
equal? = $(if $(call _equal?,$(word 1,$(1)),$(word 2,$(1))),$(__true),$(__false))
|
|
|
|
|
|
|
|
|
|
|
|
# Scalar functions
|
|
|
|
nil? = $(if $(call _nil?,$(1)),$(__true),$(__false))
|
|
|
|
true? = $(if $(call _true?,$(1)),$(__true),$(__false))
|
|
|
|
false? = $(if $(call _false?,$(1)),$(__true),$(__false))
|
|
|
|
|
|
|
|
|
|
|
|
# Symbol functions
|
2014-12-19 05:33:49 +03:00
|
|
|
symbol = $(call _symbol,$(call str_decode,$($(1)_value)))
|
2014-04-03 07:23:37 +04:00
|
|
|
symbol? = $(if $(call _symbol?,$(1)),$(__true),$(__false))
|
|
|
|
|
2014-12-19 05:33:49 +03:00
|
|
|
# Keyword functions
|
|
|
|
keyword = $(call _keyword,$(call str_decode,$($(1)_value)))
|
|
|
|
keyword? = $(if $(call _keyword?,$(1)),$(__true),$(__false))
|
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
|
|
|
|
# Number functions
|
|
|
|
number? = $(if $(call _number?,$(1)),$(__true),$(__false))
|
|
|
|
|
2015-01-05 00:47:20 +03:00
|
|
|
number_lt = $(if $(call int_lt_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)),$(__true),$(__false))
|
|
|
|
number_lte = $(if $(call int_lte_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)),$(__true),$(__false))
|
|
|
|
number_gt = $(if $(call int_gt_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)),$(__true),$(__false))
|
|
|
|
number_gte = $(if $(call int_gte_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)),$(__true),$(__false))
|
2014-04-03 07:23:37 +04:00
|
|
|
|
2015-01-05 00:47:20 +03:00
|
|
|
number_plus = $(call _pnumber,$(call int_add_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)))
|
|
|
|
number_subtract = $(call _pnumber,$(call int_sub_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)))
|
|
|
|
number_multiply = $(call _pnumber,$(call int_mult_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)))
|
|
|
|
number_divide = $(call _pnumber,$(call int_div_encoded,$($(word 1,$(1))_value),$($(word 2,$(1))_value)))
|
2014-04-18 06:49:07 +04:00
|
|
|
|
2015-01-05 00:47:20 +03:00
|
|
|
time_ms = $(call _number,$(shell echo $$(date +%s%3N)))
|
2014-04-03 07:23:37 +04:00
|
|
|
|
|
|
|
# String functions
|
|
|
|
|
2016-02-11 22:57:49 +03:00
|
|
|
string? = $(if $(call _string?,$(1)),$(if $(call _keyword?,$(1)),$(__false),$(__true)),$(__false))
|
2014-04-17 08:57:50 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
pr_str = $(call _string,$(call _pr_str_mult,$(1),yes, ))
|
|
|
|
str = $(call _string,$(call _pr_str_mult,$(1),,))
|
|
|
|
prn = $(info $(call _pr_str_mult,$(1),yes, ))
|
|
|
|
println = $(info $(subst \n,$(NEWLINE),$(call _pr_str_mult,$(1),, )))
|
|
|
|
|
2014-05-11 00:46:15 +04:00
|
|
|
readline= $(foreach res,$(call _string,$(call READLINE,"$(call str_decode,$($(1)_value))")),$(if $(READLINE_EOF),$(eval READLINE_EOF :=)$(__nil),$(res)))
|
2014-04-17 08:57:50 +04:00
|
|
|
read_str= $(call READ_STR,$(1))
|
|
|
|
slurp = $(call _string,$(call _read_file,$(call str_decode,$($(1)_value))))
|
2014-04-03 07:23:37 +04:00
|
|
|
|
|
|
|
subs = $(strip \
|
2015-01-05 00:47:20 +03:00
|
|
|
$(foreach start,$(call int_add,1,$(call int_decode,$($(word 2,$(1))_value))),\
|
2014-04-03 07:23:37 +04:00
|
|
|
$(foreach end,$(if $(3),$(call int_decode,$($(3)_value)),$(words $($(word 1,$(1))_value))),\
|
|
|
|
$(call _string,$(wordlist $(start),$(end),$($(word 1,$(1))_value))))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Function functions
|
|
|
|
function? = $(if $(call _function?,$(1)),$(__true),$(__false))
|
|
|
|
|
|
|
|
|
|
|
|
# List functions
|
|
|
|
list? = $(if $(call _list?,$(1)),$(__true),$(__false))
|
|
|
|
|
|
|
|
|
|
|
|
# Vector functions
|
|
|
|
vector? = $(if $(call _vector?,$(1)),$(__true),$(__false))
|
|
|
|
|
|
|
|
|
|
|
|
# Hash map (associative array) functions
|
|
|
|
hash_map? = $(if $(call _hash_map?,$(1)),$(__true),$(__false))
|
|
|
|
|
|
|
|
# set a key/value in a copy of the hash map
|
|
|
|
assoc = $(word 1,\
|
|
|
|
$(foreach hm,$(call _clone_obj,$(word 1,$(1))),\
|
|
|
|
$(hm) \
|
|
|
|
$(call _assoc_seq!,$(hm),$(wordlist 2,$(words $(1)),$(1)))))
|
|
|
|
|
|
|
|
# unset keys in a copy of the hash map
|
|
|
|
# TODO: this could be made more efficient by copying only the
|
|
|
|
# keys that not being removed.
|
|
|
|
dissoc = $(word 1,\
|
|
|
|
$(foreach hm,$(call _clone_obj,$(word 1,$(1))),\
|
|
|
|
$(hm) \
|
2014-12-19 05:33:49 +03:00
|
|
|
$(call _dissoc_seq!,$(hm),$(wordlist 2,$(words $(1)),$(1)))))
|
2014-04-03 07:23:37 +04:00
|
|
|
|
2014-12-19 05:33:49 +03:00
|
|
|
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)))))))
|
2014-04-03 07:23:37 +04:00
|
|
|
|
|
|
|
vals = $(foreach new_list,$(call _list),$(new_list)$(eval $(new_list)_value := $(foreach v,$(call __get_obj_values,$(1)),$($(v)))))
|
|
|
|
|
|
|
|
# Hash map and vector functions
|
|
|
|
|
|
|
|
# retrieve the value of a string key object from the hash map, or
|
|
|
|
# retrive a vector by number object index
|
|
|
|
get = $(strip \
|
2014-04-15 10:24:43 +04:00
|
|
|
$(if $(call _nil?,$(word 1,$(1))),\
|
|
|
|
$(__nil),\
|
|
|
|
$(if $(call _hash_map?,$(word 1,$(1))),\
|
|
|
|
$(call _get,$(word 1,$(1)),$(call str_decode,$($(word 2,$(1))_value))),\
|
|
|
|
$(call _get,$(word 1,$(1)),$(call int_decode,$($(word 2,$(1))_value))))))
|
2014-04-03 07:23:37 +04:00
|
|
|
|
|
|
|
contains? = $(if $(call _contains?,$(word 1,$(1)),$(call str_decode,$($(word 2,$(1))_value))),$(__true),$(__false))
|
|
|
|
|
|
|
|
|
|
|
|
# sequence operations
|
|
|
|
|
|
|
|
sequential? = $(if $(call _sequential?,$(1)),$(__true),$(__false))
|
|
|
|
|
|
|
|
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)))))))
|
|
|
|
|
|
|
|
concat = $(word 1,$(foreach new_list,$(call _list),$(new_list) $(eval $(new_list)_value := $(strip $(foreach lst,$1,$(call __get_obj_values,$(lst)))))))
|
|
|
|
|
2014-12-19 05:33:49 +03:00
|
|
|
nth = $(strip \
|
|
|
|
$(if $(call int_lt,$($(word 2,$(1))_value),$(call int_encode,$(call _count,$(word 1,$(1))))),\
|
2015-01-05 00:47:20 +03:00
|
|
|
$(word $(call int_add,1,$(call int_decode,$($(word 2,$(1))_value))),$($(word 1,$(1))_value)),\
|
2014-12-19 05:33:49 +03:00
|
|
|
$(call _error,nth: index out of range)))
|
2014-04-03 07:23:37 +04:00
|
|
|
|
|
|
|
sfirst = $(word 1,$($(1)_value))
|
|
|
|
|
|
|
|
slast = $(word $(words $($(1)_value)),$($(1)_value))
|
|
|
|
|
|
|
|
empty? = $(if $(call _EQ,0,$(if $(call _hash_map?,$(1)),$($(1)_size),$(words $($(1)_value)))),$(__true),$(__false))
|
|
|
|
|
|
|
|
count = $(call _number,$(call _count,$(1)))
|
|
|
|
|
|
|
|
# Creates a new vector/list of the everything after but the first
|
|
|
|
# element
|
|
|
|
srest = $(word 1,$(foreach new_list,$(call _list),\
|
|
|
|
$(new_list) \
|
|
|
|
$(eval $(new_list)_value := $(wordlist 2,$(words $($(1)_value)),$($(1)_value)))))
|
|
|
|
|
|
|
|
# Takes a space separated arguments and invokes the first argument
|
|
|
|
# (function object) using the remaining arguments.
|
2015-10-13 02:58:33 +03:00
|
|
|
sapply = $(call $(word 1,$(1))_value,$(strip \
|
|
|
|
$(wordlist 2,$(call int_sub,$(words $(1)),1),$(1)) \
|
2016-02-11 22:57:49 +03:00
|
|
|
$($(word $(words $(1)),$(1))_value)))
|
2014-04-03 07:23:37 +04:00
|
|
|
|
|
|
|
# Map a function object over a list object
|
|
|
|
smap = $(strip\
|
|
|
|
$(foreach func,$(word 1,$(1)),\
|
|
|
|
$(foreach lst,$(word 2,$(1)),\
|
2015-03-15 01:14:32 +03:00
|
|
|
$(foreach type,list,\
|
2014-04-03 07:23:37 +04:00
|
|
|
$(foreach new_hcode,$(call __new_obj_hash_code),\
|
|
|
|
$(foreach sz,$(words $(call __get_obj_values,$(lst))),\
|
|
|
|
$(eval $(__obj_magic)_$(type)_$(new_hcode)_value := $(strip \
|
|
|
|
$(foreach val,$(call __get_obj_values,$(lst)),\
|
|
|
|
$(call $(func)_value,$(val))))))\
|
|
|
|
$(__obj_magic)_$(type)_$(new_hcode))))))
|
|
|
|
|
2016-02-11 22:57:49 +03:00
|
|
|
conj = $(word 1,$(foreach new_list,$(call __new_obj_like,$(word 1,$(1))),\
|
|
|
|
$(new_list) \
|
|
|
|
$(eval $(new_list)_value := $(strip $($(word 1,$(1))_value))) \
|
|
|
|
$(if $(call _list?,$(new_list)),\
|
|
|
|
$(foreach elem,$(wordlist 2,$(words $(1)),$(1)),\
|
|
|
|
$(eval $(new_list)_value := $(strip $(elem) $($(new_list)_value)))),\
|
|
|
|
$(eval $(new_list)_value := $(strip $($(new_list)_value) $(wordlist 2,$(words $(1)),$(1)))))))
|
|
|
|
|
|
|
|
seq = $(strip\
|
|
|
|
$(if $(call _list?,$(1)),\
|
|
|
|
$(if $(call _EQ,0,$(call _count,$(1))),$(__nil),$(1)),\
|
|
|
|
$(if $(call _vector?,$(1)),\
|
|
|
|
$(if $(call _EQ,0,$(call _count,$(1))),\
|
|
|
|
$(__nil),\
|
|
|
|
$(word 1,$(foreach new_list,$(call _list),\
|
|
|
|
$(new_list) \
|
|
|
|
$(eval $(new_list)_value := $(strip $($(word 1,$(1))_value)))))),\
|
|
|
|
$(if $(call _EQ,string,$(call _obj_type,$(1))),\
|
|
|
|
$(if $(call _EQ,0,$(call _count,$(1))),\
|
|
|
|
$(__nil),\
|
|
|
|
$(word 1,$(foreach new_list,$(call _list),\
|
|
|
|
$(new_list) \
|
|
|
|
$(eval $(new_list)_value := $(strip \
|
|
|
|
$(foreach c,$($(word 1,$(1))_value),\
|
|
|
|
$(call _string,$(c)))))))),\
|
|
|
|
$(if $(call _nil?,$(1)),\
|
|
|
|
$(__nil),\
|
|
|
|
$(call _error,seq: called on non-sequence))))))
|
2014-04-03 07:23:37 +04:00
|
|
|
|
|
|
|
# Metadata functions
|
|
|
|
|
|
|
|
with_meta = $(strip \
|
|
|
|
$(foreach new_obj,$(call _clone_obj,$(word 1,$(1))),\
|
|
|
|
$(eval $(new_obj)_meta := $(strip $(word 2,$(1))))\
|
|
|
|
$(new_obj)))
|
|
|
|
|
|
|
|
meta = $(strip $($(1)_meta))
|
|
|
|
|
|
|
|
|
|
|
|
# Atom functions
|
|
|
|
|
|
|
|
atom = $(strip \
|
|
|
|
$(foreach hcode,$(call __new_obj_hash_code),\
|
|
|
|
$(foreach new_atom,$(__obj_magic)_atom_$(hcode),\
|
|
|
|
$(new_atom)\
|
|
|
|
$(eval $(new_atom)_value := $(1)))))
|
|
|
|
atom? = $(if $(call _atom?,$(1)),$(__true),$(__false))
|
|
|
|
|
|
|
|
deref = $($(1)_value)
|
|
|
|
|
|
|
|
reset! = $(eval $(word 1,$(1))_value := $(word 2,$(1)))$(word 2,$(1))
|
|
|
|
|
|
|
|
swap! = $(foreach resp,$(call $(word 2,$(1))_value,$($(word 1,$(1))_value) $(wordlist 3,$(words $(1)),$(1))),\
|
|
|
|
$(eval $(word 1,$(1))_value := $(resp))\
|
|
|
|
$(resp))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Namespace of core functions
|
|
|
|
|
|
|
|
core_ns = type obj_type \
|
|
|
|
= equal? \
|
|
|
|
throw throw \
|
|
|
|
nil? nil? \
|
|
|
|
true? true? \
|
|
|
|
false? false? \
|
2016-02-11 22:57:49 +03:00
|
|
|
string? string? \
|
2014-12-19 05:33:49 +03:00
|
|
|
symbol symbol \
|
2014-04-03 07:23:37 +04:00
|
|
|
symbol? symbol? \
|
2014-12-19 05:33:49 +03:00
|
|
|
keyword keyword \
|
|
|
|
keyword? keyword? \
|
2014-04-03 07:23:37 +04:00
|
|
|
function? function? \
|
2014-04-17 08:57:50 +04:00
|
|
|
\
|
2014-04-03 07:23:37 +04:00
|
|
|
pr-str pr_str \
|
|
|
|
str str \
|
|
|
|
prn prn \
|
|
|
|
println println \
|
2014-04-17 08:57:50 +04:00
|
|
|
readline readline \
|
|
|
|
read-string read_str \
|
|
|
|
slurp slurp \
|
2014-04-03 07:23:37 +04:00
|
|
|
subs subs \
|
|
|
|
number? number? \
|
|
|
|
< number_lt \
|
|
|
|
<= number_lte \
|
|
|
|
> number_gt \
|
|
|
|
>= number_gte \
|
|
|
|
+ number_plus \
|
|
|
|
- number_subtract \
|
|
|
|
* number_multiply \
|
|
|
|
/ number_divide \
|
2015-01-05 00:47:20 +03:00
|
|
|
time-ms time_ms \
|
2014-04-03 07:23:37 +04:00
|
|
|
\
|
|
|
|
list _list \
|
|
|
|
list? list? \
|
|
|
|
vector _vector \
|
|
|
|
vector? vector? \
|
|
|
|
hash-map _hash_map \
|
|
|
|
map? hash_map? \
|
|
|
|
assoc assoc \
|
|
|
|
dissoc dissoc \
|
|
|
|
get get \
|
|
|
|
contains? contains? \
|
|
|
|
keys keys \
|
|
|
|
vals vals \
|
|
|
|
\
|
|
|
|
sequential? sequential? \
|
|
|
|
cons cons \
|
|
|
|
concat concat \
|
|
|
|
nth nth \
|
|
|
|
first sfirst \
|
|
|
|
rest srest \
|
|
|
|
last slast \
|
|
|
|
empty? empty? \
|
|
|
|
count count \
|
|
|
|
apply sapply \
|
|
|
|
map smap \
|
|
|
|
\
|
2016-02-11 22:57:49 +03:00
|
|
|
conj conj \
|
|
|
|
seq seq \
|
|
|
|
\
|
2014-04-03 07:23:37 +04:00
|
|
|
with-meta with_meta \
|
|
|
|
meta meta \
|
|
|
|
atom atom \
|
|
|
|
atom? atom? \
|
|
|
|
deref deref \
|
|
|
|
reset! reset! \
|
|
|
|
swap! swap!
|
|
|
|
|
|
|
|
endif
|