All: don't ignore */mal. Fixes #99
[jackhill/mal.git] / make / reader.mk
1 #
2 # mal (Make Lisp) Parser/Reader
3 #
4
5 ifndef __mal_reader_included
6 __mal_reader_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
13 READER_DEBUG ?=
14
15 _TOKEN_DELIMS := $(SEMI) $(COMMA) $(DQUOTE) $(QQUOTE) $(_SP) $(_NL) $(_LC) $(_RC) $(_LP) $(_RP) $(LBRACKET) $(RBRACKET)
16
17 define READ_NUMBER
18 $(foreach ch,$(word 1,$($(1))),\
19 $(if $(ch),\
20 $(if $(filter $(_TOKEN_DELIMS),$(ch)),\
21 ,\
22 $(if $(filter-out $(NUMBERS),$(ch)),\
23 $(call _error,Invalid number character '$(ch)'),\
24 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
25 $(and $(READER_DEBUG),$(info READ_NUMBER ch: $(ch) | $($(1))))\
26 $(ch)$(strip $(call READ_NUMBER,$(1))))),\
27 ))
28 endef
29
30 define READ_STRING
31 $(foreach ch,$(word 1,$($(1))),\
32 $(if $(ch),\
33 $(if $(and $(filter \,$(ch)),$(filter $(DQUOTE),$(word 2,$($(1))))),\
34 $(eval $(1) := $(wordlist 3,$(words $($(1))),$($(1))))\
35 $(and $(READER_DEBUG),$(info READ_STRING ch: \$(word 1,$($(1))) | $($(1))))\
36 $(DQUOTE) $(strip $(call READ_STRING,$(1))),\
37 $(if $(filter $(DQUOTE),$(ch)),\
38 ,\
39 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
40 $(and $(READER_DEBUG),$(info READ_STRING ch: $(ch) | $($(1))))\
41 $(ch) $(strip $(call READ_STRING,$(1))))),))
42 endef
43
44 define READ_SYMBOL
45 $(foreach ch,$(word 1,$($(1))),\
46 $(if $(ch),\
47 $(if $(filter $(_TOKEN_DELIMS),$(ch)),\
48 ,\
49 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
50 $(and $(READER_DEBUG),$(info READ_SYMBOL ch: $(ch) | $($(1))))\
51 $(ch)$(strip $(call READ_SYMBOL,$(1)))),\
52 ))
53 endef
54
55 define READ_KEYWORD
56 $(foreach ch,$(word 1,$($(1))),\
57 $(if $(ch),\
58 $(if $(filter $(_TOKEN_DELIMS),$(ch)),\
59 ,\
60 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
61 $(and $(READER_DEBUG),$(info READ_KEYWORD ch: $(ch) | $($(1))))\
62 $(ch)$(strip $(call READ_KEYWORD,$(1)))),\
63 ))
64 endef
65
66 define READ_ATOM
67 $(foreach ch,$(word 1,$($(1))),\
68 $(if $(filter $(NUMBERS),$(ch)),\
69 $(call _number,$(call READ_NUMBER,$(1))),\
70 $(if $(filter $(DQUOTE),$(ch)),\
71 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
72 $(call __string,$(strip $(call READ_STRING,$(1))))\
73 $(eval $(if $(filter $(DQUOTE),$(word 1,$($(1)))),\
74 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1)))),\
75 $(call _error,Expected '$(DQUOTE)' in; $($(1))))),\
76 $(if $(filter $(COLON),$(ch)),\
77 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
78 $(call _keyword,$(call READ_KEYWORD,$(1))),\
79 $(foreach sym,$(call READ_SYMBOL,$(1)),\
80 $(if $(call _EQ,nil,$(sym)),\
81 $(__nil),\
82 $(if $(call _EQ,true,$(sym)),\
83 $(__true),\
84 $(if $(call _EQ,false,$(sym)),\
85 $(__false),\
86 $(call _symbol,$(sym))))))))))
87 endef
88
89 # read and return tokens until $(2) found
90 define READ_UNTIL
91 $(and $(READER_DEBUG),$(info READ_UNTIL: $($(1)) [$(2) $(3)]))
92 $(foreach ch,$(word 1,$($(1))),\
93 $(if $(ch),\
94 $(if $(filter $(2),$(ch)),\
95 ,\
96 $(call READ_FORM,$(1))\
97 $(call READ_UNTIL,$(1),$(2),$(3))),\
98 $(call _error,Expected '$(3)')))
99 endef
100
101 define DROP_UNTIL
102 $(and $(READER_DEBUG),$(info DROP_UNTIL: $($(1)) [$(2)]))
103 $(foreach ch,$(word 1,$($(1))),\
104 $(if $(ch),\
105 $(if $(filter $(2),$(ch)),\
106 ,\
107 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
108 $(call DROP_UNTIL,$(1),$(2),$(3))),\
109 ))
110 endef
111
112 define READ_SPACES
113 $(and $(READER_DEBUG),$(info READ_SPACES: $($(1))))
114 $(foreach ch,$(word 1,$($(1))),\
115 $(if $(filter $(_SP) $(_NL) $(COMMA),$(ch)),\
116 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
117 $(call READ_SPACES,$(1)),))
118 endef
119
120 define READ_FORM
121 $(and $(READER_DEBUG),$(info READ_FORM: $($(1))))
122 $(call READ_SPACES,$(1))
123 $(foreach ch,$(word 1,$($(1))),\
124 $(if $(filter $(SEMI),$(ch)),\
125 $(call DROP_UNTIL,$(1),$(_NL)),\
126 $(if $(filter $(SQUOTE),$(ch)),\
127 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
128 $(call _list,$(call _symbol,quote) $(strip $(call READ_FORM,$(1)))),\
129 $(if $(filter $(QQUOTE),$(ch)),\
130 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
131 $(call _list,$(call _symbol,quasiquote) $(strip $(call READ_FORM,$(1)))),\
132 $(if $(filter $(UNQUOTE),$(ch)),\
133 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
134 $(call _list,$(call _symbol,unquote) $(strip $(call READ_FORM,$(1)))),\
135 $(if $(filter $(_SUQ),$(ch)),\
136 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
137 $(call _list,$(call _symbol,splice-unquote) $(strip $(call READ_FORM,$(1)))),\
138 $(if $(filter $(CARET),$(ch)),\
139 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
140 $(foreach meta,$(strip $(call READ_FORM,$(1))),\
141 $(call _list,$(call _symbol,with-meta) $(strip $(call READ_FORM,$(1))) $(meta))),\
142 $(if $(filter $(ATSIGN),$(ch)),\
143 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
144 $(call _list,$(call _symbol,deref) $(strip $(call READ_FORM,$(1)))),\
145 $(if $(filter $(_RC),$(ch)),\
146 $(call _error,Unexpected '$(RCURLY)'),\
147 $(if $(filter $(_LC),$(ch)),\
148 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
149 $(foreach thm,$(call _hash_map),\
150 $(call do,$(call _assoc_seq!,$(thm),$(strip $(call READ_UNTIL,$(1),$(_RC),$(RCURLY)))))\
151 $(eval $(if $(filter $(_RC),$(word 1,$($(1)))),\
152 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1)))),\
153 $(call _error,Expected '$(RCURLY)')))\
154 $(thm)),\
155 $(if $(filter $(_RP),$(ch)),\
156 $(call _error,Unexpected '$(RPAREN)'),\
157 $(if $(filter $(_LP),$(ch)),\
158 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
159 $(foreach tlist,$(call _list),\
160 $(eval $(foreach item,$(strip $(call READ_UNTIL,$(1),$(_RP),$(RPAREN))),\
161 $(call do,$(call _conj!,$(tlist),$(item)))))\
162 $(eval $(if $(filter $(_RP),$(word 1,$($(1)))),\
163 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1)))),\
164 $(call _error,Expected '$(RPAREN)')))\
165 $(tlist)),\
166 $(if $(filter $(RBRACKET),$(ch)),\
167 $(call _error,Unexpected '$(RBRACKET)'),\
168 $(if $(filter $(LBRACKET),$(ch)),\
169 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
170 $(foreach tvec,$(call _vector),\
171 $(eval $(foreach item,$(strip $(call READ_UNTIL,$(1),$(RBRACKET),$(RBRACKET))),\
172 $(call do,$(call _conj!,$(tvec),$(item)))))\
173 $(eval $(if $(filter $(RBRACKET),$(word 1,$($(1)))),\
174 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1)))),\
175 $(call _error,Expected '$(RBRACKET)')))\
176 $(tvec)),\
177 $(call READ_ATOM,$(1))))))))))))))))
178 $(call READ_SPACES,$(1))
179 endef
180
181 # read-str from a raw "string" or from a string object
182 READ_STR = $(strip $(eval __reader_temp := $(call str_encode,$(if $(call _string?,$(1)),$(call str_decode,$($(1)_value)),$(1))))$(call READ_FORM,__reader_temp))
183
184 endif