DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / make / reader.mk
CommitLineData
31690700
JM
1#
2# mal (Make Lisp) Parser/Reader
3#
4
5ifndef __mal_reader_included
6__mal_reader_included := true
7
8_TOP_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
9include $(_TOP_DIR)util.mk
10include $(_TOP_DIR)types.mk
11include $(_TOP_DIR)readline.mk
12
13READER_DEBUG ?=
14
15_TOKEN_DELIMS := $(SEMI) $(COMMA) $(DQUOTE) $(QQUOTE) $(_SP) $(_NL) $(_LC) $(_RC) $(_LP) $(_RP) $(LBRACKET) $(RBRACKET)
16
17define READ_NUMBER
18$(foreach ch,$(word 1,$($(1))),\
19 $(if $(ch),\
20 $(if $(filter $(_TOKEN_DELIMS),$(ch)),\
21 ,\
4c0073a3 22 $(if $(filter-out $(MINUS) $(NUMBERS),$(ch)),\
31690700
JM
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 ))
28endef
29
8d78bc26
JM
30# $(_NL) is used here instead of $(NEWLINE) because $(strip) removes
31# $(NEWLINE). str_encode will just pass through $(_NL) so str_decode
32# later will restore a correct newline
31690700
JM
33define READ_STRING
34$(foreach ch,$(word 1,$($(1))),\
35 $(if $(ch),\
36 $(if $(and $(filter \,$(ch)),$(filter $(DQUOTE),$(word 2,$($(1))))),\
37 $(eval $(1) := $(wordlist 3,$(words $($(1))),$($(1))))\
38 $(and $(READER_DEBUG),$(info READ_STRING ch: \$(word 1,$($(1))) | $($(1))))\
39 $(DQUOTE) $(strip $(call READ_STRING,$(1))),\
8d78bc26
JM
40 $(if $(and $(filter \,$(ch)),$(filter n,$(word 2,$($(1))))),\
41 $(eval $(1) := $(wordlist 3,$(words $($(1))),$($(1))))\
42 $(and $(READER_DEBUG),$(info READ_STRING ch: \$(word 1,$($(1))) | $($(1))))\
43 $(_NL) $(strip $(call READ_STRING,$(1))),\
44 $(if $(and $(filter \,$(ch)),$(filter \,$(word 2,$($(1))))),\
45 $(eval $(1) := $(wordlist 3,$(words $($(1))),$($(1))))\
46 $(and $(READER_DEBUG),$(info READ_STRING ch: \$(word 1,$($(1))) | $($(1))))\
47 \ $(strip $(call READ_STRING,$(1))),\
31690700
JM
48 $(if $(filter $(DQUOTE),$(ch)),\
49 ,\
50 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
51 $(and $(READER_DEBUG),$(info READ_STRING ch: $(ch) | $($(1))))\
8d78bc26 52 $(ch) $(strip $(call READ_STRING,$(1))))))),))
31690700
JM
53endef
54
55define READ_SYMBOL
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_SYMBOL ch: $(ch) | $($(1))))\
62 $(ch)$(strip $(call READ_SYMBOL,$(1)))),\
63 ))
64endef
65
b8ee29b2
JM
66define READ_KEYWORD
67$(foreach ch,$(word 1,$($(1))),\
68 $(if $(ch),\
69 $(if $(filter $(_TOKEN_DELIMS),$(ch)),\
70 ,\
71 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
72 $(and $(READER_DEBUG),$(info READ_KEYWORD ch: $(ch) | $($(1))))\
73 $(ch)$(strip $(call READ_KEYWORD,$(1)))),\
74 ))
75endef
76
31690700 77define READ_ATOM
b137ff4f 78$(and $(READER_DEBUG),$(info READ_ATOM: $($(1))))
31690700 79$(foreach ch,$(word 1,$($(1))),\
4c0073a3
JM
80 $(if $(and $(filter $(MINUS),$(ch)),$(filter $(NUMBERS),$(word 2,$($(1))))),\
81 $(call _number,$(call READ_NUMBER,$(1))),\
31690700 82 $(if $(filter $(NUMBERS),$(ch)),\
ea81a808 83 $(call _number,$(call READ_NUMBER,$(1))),\
31690700
JM
84 $(if $(filter $(DQUOTE),$(ch)),\
85 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
ea81a808 86 $(call __string,$(strip $(call READ_STRING,$(1))))\
31690700
JM
87 $(eval $(if $(filter $(DQUOTE),$(word 1,$($(1)))),\
88 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1)))),\
4aa0ebdf 89 $(call _error,Expected '$(DQUOTE)' in; $($(1))$(COMMA) got EOF))),\
b8ee29b2
JM
90 $(if $(filter $(COLON),$(ch)),\
91 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
92 $(call _keyword,$(call READ_KEYWORD,$(1))),\
31690700
JM
93 $(foreach sym,$(call READ_SYMBOL,$(1)),\
94 $(if $(call _EQ,nil,$(sym)),\
95 $(__nil),\
96 $(if $(call _EQ,true,$(sym)),\
97 $(__true),\
98 $(if $(call _EQ,false,$(sym)),\
99 $(__false),\
4c0073a3 100 $(call _symbol,$(sym)))))))))))
31690700
JM
101endef
102
103# read and return tokens until $(2) found
104define READ_UNTIL
105$(and $(READER_DEBUG),$(info READ_UNTIL: $($(1)) [$(2) $(3)]))
106$(foreach ch,$(word 1,$($(1))),\
107 $(if $(ch),\
108 $(if $(filter $(2),$(ch)),\
109 ,\
110 $(call READ_FORM,$(1))\
111 $(call READ_UNTIL,$(1),$(2),$(3))),\
ae6e2220 112 $(call _error,Expected '$(3)'$(COMMA) got EOF)))
31690700
JM
113endef
114
115define DROP_UNTIL
116$(and $(READER_DEBUG),$(info DROP_UNTIL: $($(1)) [$(2)]))
117$(foreach ch,$(word 1,$($(1))),\
118 $(if $(ch),\
119 $(if $(filter $(2),$(ch)),\
120 ,\
121 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
122 $(call DROP_UNTIL,$(1),$(2),$(3))),\
123 ))
124endef
125
126define READ_SPACES
127$(and $(READER_DEBUG),$(info READ_SPACES: $($(1))))
128$(foreach ch,$(word 1,$($(1))),\
129 $(if $(filter $(_SP) $(_NL) $(COMMA),$(ch)),\
130 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
131 $(call READ_SPACES,$(1)),))
132endef
133
134define READ_FORM
135$(and $(READER_DEBUG),$(info READ_FORM: $($(1))))
136$(call READ_SPACES,$(1))
137$(foreach ch,$(word 1,$($(1))),\
138 $(if $(filter $(SEMI),$(ch)),\
139 $(call DROP_UNTIL,$(1),$(_NL)),\
140 $(if $(filter $(SQUOTE),$(ch)),\
141 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
ea81a808 142 $(call _list,$(call _symbol,quote) $(strip $(call READ_FORM,$(1)))),\
31690700
JM
143 $(if $(filter $(QQUOTE),$(ch)),\
144 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
ea81a808 145 $(call _list,$(call _symbol,quasiquote) $(strip $(call READ_FORM,$(1)))),\
31690700
JM
146 $(if $(filter $(UNQUOTE),$(ch)),\
147 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
ea81a808 148 $(call _list,$(call _symbol,unquote) $(strip $(call READ_FORM,$(1)))),\
31690700
JM
149 $(if $(filter $(_SUQ),$(ch)),\
150 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
ea81a808 151 $(call _list,$(call _symbol,splice-unquote) $(strip $(call READ_FORM,$(1)))),\
31690700
JM
152 $(if $(filter $(CARET),$(ch)),\
153 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
154 $(foreach meta,$(strip $(call READ_FORM,$(1))),\
ea81a808 155 $(call _list,$(call _symbol,with-meta) $(strip $(call READ_FORM,$(1))) $(meta))),\
31690700
JM
156 $(if $(filter $(ATSIGN),$(ch)),\
157 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
ea81a808 158 $(call _list,$(call _symbol,deref) $(strip $(call READ_FORM,$(1)))),\
31690700
JM
159 $(if $(filter $(_RC),$(ch)),\
160 $(call _error,Unexpected '$(RCURLY)'),\
161 $(if $(filter $(_LC),$(ch)),\
162 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
b137ff4f 163 $(call READ_SPACES,$(1))\
ea81a808 164 $(foreach thm,$(call _hash_map),\
31690700
JM
165 $(call do,$(call _assoc_seq!,$(thm),$(strip $(call READ_UNTIL,$(1),$(_RC),$(RCURLY)))))\
166 $(eval $(if $(filter $(_RC),$(word 1,$($(1)))),\
167 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1)))),\
ae6e2220 168 $(call _error,Expected '$(RCURLY)'$(COMMA) got EOF)))\
31690700
JM
169 $(thm)),\
170 $(if $(filter $(_RP),$(ch)),\
171 $(call _error,Unexpected '$(RPAREN)'),\
172 $(if $(filter $(_LP),$(ch)),\
173 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
b137ff4f 174 $(call READ_SPACES,$(1))\
31690700
JM
175 $(foreach tlist,$(call _list),\
176 $(eval $(foreach item,$(strip $(call READ_UNTIL,$(1),$(_RP),$(RPAREN))),\
177 $(call do,$(call _conj!,$(tlist),$(item)))))\
178 $(eval $(if $(filter $(_RP),$(word 1,$($(1)))),\
179 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1)))),\
ae6e2220 180 $(call _error,Expected '$(RPAREN)'$(COMMA) got EOF)))\
31690700
JM
181 $(tlist)),\
182 $(if $(filter $(RBRACKET),$(ch)),\
183 $(call _error,Unexpected '$(RBRACKET)'),\
184 $(if $(filter $(LBRACKET),$(ch)),\
185 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1))))\
b137ff4f 186 $(call READ_SPACES,$(1))\
31690700
JM
187 $(foreach tvec,$(call _vector),\
188 $(eval $(foreach item,$(strip $(call READ_UNTIL,$(1),$(RBRACKET),$(RBRACKET))),\
189 $(call do,$(call _conj!,$(tvec),$(item)))))\
190 $(eval $(if $(filter $(RBRACKET),$(word 1,$($(1)))),\
191 $(eval $(1) := $(wordlist 2,$(words $($(1))),$($(1)))),\
ae6e2220 192 $(call _error,Expected '$(RBRACKET)'$(COMMA) got EOF)))\
31690700
JM
193 $(tvec)),\
194 $(call READ_ATOM,$(1))))))))))))))))
195$(call READ_SPACES,$(1))
196endef
197
198# read-str from a raw "string" or from a string object
199READ_STR = $(strip $(eval __reader_temp := $(call str_encode,$(if $(call _string?,$(1)),$(call str_decode,$($(1)_value)),$(1))))$(call READ_FORM,__reader_temp))
200
201endif