Skip to content

Commit

Permalink
make: improve efficiency and encapsulation
Browse files Browse the repository at this point in the history
Readability
* Use implicit parameter transmission ($(_list?) instead of $(call
  _list?,$1),
  first/lastword instead of word 1/words,
  $1 instead of $(1).
* Use an undefined $(rem) macro and some automatic stripping (if,
  foreach) to indent code with less calls to `strip` functions.
* Name the Make macro implementing a MAL core function exactly like the
  function (modulo the encoding above) and simplify core_ns accordingly.
* Replace empty results representing `nil` with explicit MAL values.
* Implement large conditionals with a computed variable name, as already
  done in printer.mk.  For QUASIQUOTE and EVAL, this reduces a lot the
  diff between steps.
* Represent the reader state as an explicit global variable instead of
  passing the same name as argument again and again.
* Merge read-atom into read-form so that the switch on first character
  is more visible.

Encapsulation
* Hide most representations into types.mk.
* Implement the type as a suffix in order to avoid a conditional in
  _obj_type.
* Implement _error with throw.
* Create distinct types for keywords and macros.
* Move most metadata and atom stuff from core.mk to types.mk.
* Move parameter association from env to types because it hides more
  about the representation of functions.

Representation
* Encode Make special characters in all strings/keywords/symbols, so
  they can be used directly as spaced words and/or variable names for
  map keys. (The encoding adding separating characters is kept for
  read-string and seq).
* Change representation of numbers/strings/keywords/symbols, reducing
  the number of Make variables.

Various
* Allow keyword argument for keyword core function.
* Shorten time-mes,slurp,readline...
* Remove obsolete stuff:
  * `get` and `contains?` for vectors
  * `count` for hash-maps
  * `_join` from util.mk.
  * `type` from core.mk.
* Add a function listing env_keys for DEBUG-EVAL.
* Fix some includes.
  • Loading branch information
asarhaddon committed Aug 8, 2024
1 parent 3f6a40f commit 36f77e9
Show file tree
Hide file tree
Showing 19 changed files with 1,407 additions and 1,370 deletions.
11 changes: 11 additions & 0 deletions impls/make/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
It is often useful to add $(warning /$0/ /$1/ /$2/ /$3/) at the very
start of each interesting macro.

Recal that foreach does nothing when the list only contains spaces,
and adds spaces between the results even if some results are empty.

If debugging the reader:
# export READER_DEBUG=1

In order to get the equivalent of DEBUG_EVAL in step2:
# export EVAL_DEBUG=1
323 changes: 110 additions & 213 deletions impls/make/core.mk

Large diffs are not rendered by default.

42 changes: 16 additions & 26 deletions impls/make/env.mk
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,21 @@ include $(_TOP_DIR)types.mk

# An ENV environment is a hash-map with an __outer__ reference to an
# outer environment
define BIND_ARGS
$(strip \
$(word 1,$(1) \
$(foreach fparam,$(call _nth,$(2),0),\
$(if $(call _EQ,&,$($(fparam)_value)),
$(call ENV_SET,$(1),$($(call _nth,$(2),1)_value),$(strip \
$(foreach new_list,$(call _list),
$(word 1,$(new_list) \
$(foreach val,$(3),$(call _conj!,$(new_list),$(val))))))),\
$(foreach val,$(word 1,$(3)),\
$(call ENV_SET,$(1),$($(fparam)_value),$(val))\
$(foreach left,$(call srest,$(2)),\
$(if $(call _EQ,0,$(call _count,$(left))),\
,\
$(call BIND_ARGS,$(1),$(left),$(wordlist 2,$(words $(3)),$(3))))))))))
endef

# Create a new ENV and optional bind values in it
# $(1): outer environment (set as a key named __outer__)
# $(2): list/vector object of bind forms
# $(3): space separated list of expressions to bind
ENV = $(strip $(foreach new_env,$(call _assoc!,$(call _hash_map),__outer__,$(if $(1),$(1),$(__nil))),$(if $(2),$(call BIND_ARGS,$(new_env),$(2),$(3)),$(new_env))))

ENV_GET = $(if $(call _EQ,$(1),$(__nil)),,$(or $(_get),$(call ENV_GET,$(call _get,$(1),__outer__),$(2))))

ENV_SET = $(if $(call _assoc!,$(1),$(subst =,$(__equal),$(2)),$(3)),$(1),)

# Keys are stored as Make variables named $(env)_$(key). The outer
# environment is the content of the variable itself.

# 1: outer environment, or "" -> new environment
ENV = $(call __new_obj,env,$1)

# 1:env 2:key -> value or ""
ENV_GET = $(if $1,$(or $($1_$2),$(call ENV_GET,$($1),$2)))

# 1:env 2:key 3:value
ENV_SET = $(eval $1_$2 := $3)

# 1:env -> (encoded) keys
env_keys = $(foreach k,$(patsubst $1_%,%,$(filter $1_%,$(.VARIABLES)))\
,$(call _symbol_val,$k))

endif
2 changes: 1 addition & 1 deletion impls/make/numbers.mk
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ int_encode = $(strip $(call _reverse,\
$(foreach a,- 0 1 2 3 4 5 6 7 8 9,\
$(eval __temp := $$(subst $$a,$$a$$(SPACE),$(__temp))))$(__temp)))

int_decode = $(strip $(call _join,$(call _reverse,$(1))))
int_decode = $(subst $(SPACE),,$(_reverse))

# trim extaneous zero digits off the end (front of number)
_trim_zeros = $(if $(call _EQ,0,$(strip $(1))),0,$(if $(call _EQ,0,$(word 1,$(1))),$(call _trim_zeros,$(wordlist 2,$(words $(1)),$(1))),$(1)))
Expand Down
36 changes: 22 additions & 14 deletions impls/make/printer.mk
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,45 @@ include $(_TOP_DIR)types.mk

# return a printable form of the argument, the second parameter is
# 'print_readably' which backslashes quotes in string values
_pr_str = $(if $(1),$(foreach ot,$(call _obj_type,$(1)),$(if $(call _EQ,make,$(ot)),$(call _error,_pr_str failed on $(1)),$(call $(ot)_pr_str,$(1),$(2)))),)
_pr_str = $(call $(_obj_type)_pr_str,$1,$2)

# Like _pr_str but takes multiple values in first argument, the second
# parameter is 'print_readably' which backslashes quotes in string
# values, the third parameter is the delimeter to use between each
# _pr_str'd value
_pr_str_mult = $(call _pr_str,$(word 1,$(1)),$(2))$(if $(word 2,$(1)),$(3)$(call _pr_str_mult,$(wordlist 2,$(words $(1)),$(1)),$(2),$(3)),)
_pr_str_mult = $(subst $(SPACE),$3,$(foreach f,$1,$(call _pr_str,$f,$2)))


# Type specific printing

nil_pr_str = nil
true_pr_str = true
false_pr_str = false
nil_pr_str := nil
true_pr_str := true
false_pr_str := false

number_pr_str = $(call int_decode,$($(1)_value))
number_pr_str = $(_number_val)

symbol_pr_str = $($(1)_value)
symbol_pr_str = $(_symbol_val)

keyword_pr_str = $(COLON)$(patsubst $(__keyword)%,%,$(call str_decode,$($(1)_value)))
keyword_pr_str = $(encoded_colon)$(_keyword_val)

string_pr_str = $(if $(filter $(__keyword)%,$(call str_decode,$($(1)_value))),$(COLON)$(patsubst $(__keyword)%,%,$(call str_decode,$($(1)_value))),$(if $(2),"$(subst $(NEWLINE),$(ESC_N),$(subst $(DQUOTE),$(ESC_DQUOTE),$(subst $(SLASH),$(SLASH)$(SLASH),$(call str_decode,$($(1)_value)))))",$(call str_decode,$($(1)_value))))
string_pr_str = $(if $2\
,"$(subst $(_NL),$(ESC_N),$(rem \
)$(subst $(DQUOTE),$(ESC_DQUOTE),$(rem \
)$(subst $(encoded_slash),$(encoded_slash)$(encoded_slash),$(rem \
)$(_string_val))))"$(rem \
else \
),$(_string_val))

function_pr_str = <Function>
corefn_pr_str := <Core>
function_pr_str := <Function>
macro_pr_str := <Macro>

list_pr_str = ($(foreach v,$(call __get_obj_values,$(1)),$(call _pr_str,$(v),$(2))))
list_pr_str = $(_LP)$(call _pr_str_mult,$(_seq_vals),$2,$(_SP))$(_RP)

vector_pr_str = [$(foreach v,$(call __get_obj_values,$(1)),$(call _pr_str,$(v),$(2)))]
vector_pr_str = [$(call _pr_str_mult,$(_seq_vals),$2,$(_SP))]

hash_map_pr_str = {$(foreach v,$(call __get_obj_values,$(1)),$(foreach vval,$(foreach hcode,$(word 3,$(subst _, ,$(1))),$(patsubst $(1)_%,%,$(v:%_value=%))),$(if $(filter $(__keyword)%,$(vval)),$(patsubst $(__keyword)%,$(COLON)%,$(vval)),"$(vval)")) $(call _pr_str,$($(v)),$(2)))}
map_pr_str = {$(call _pr_str_mult,$(foreach k,$(_keys),$k $(call _get,$1,$k)),$2,$(_SP))}

atom_pr_str = (atom $(call _pr_str,$($(1)_value),$(2)))
atom_pr_str = $(_LP)atom$(_SP)$(call _pr_str,$(deref),$2)$(_RP)

endif
Loading

0 comments on commit 36f77e9

Please sign in to comment.