2 # mal (Make Lisp) Parser/Reader
5 ifndef __mal_reader_included
6 __mal_reader_included
:= true
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
15 _TOKEN_DELIMS
:= $(SEMI
) $(COMMA
) $(DQUOTE
) $(QQUOTE
) $(_SP
) $(_NL
) $(_LC
) $(_RC
) $(_LP
) $(_RP
) $(LBRACKET
) $(RBRACKET
)
18 $(foreach ch
,$(word 1,$($(1))),\
20 $(if
$(filter $(_TOKEN_DELIMS
),$(ch
)),\
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))))),\
31 $(foreach ch
,$(word 1,$($(1))),\
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
)),\
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))))),))
45 $(foreach ch
,$(word 1,$($(1))),\
47 $(if
$(filter $(_TOKEN_DELIMS
),$(ch
)),\
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)))),\
56 $(foreach ch
,$(word 1,$($(1))),\
58 $(if
$(filter $(_TOKEN_DELIMS
),$(ch
)),\
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)))),\
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
)),\
82 $(if
$(call _EQ
,true
,$(sym
)),\
84 $(if
$(call _EQ
,false
,$(sym
)),\
86 $(call _symbol
,$(sym
))))))))))
89 # read and return tokens until $(2) found
91 $(and
$(READER_DEBUG
),$(info READ_UNTIL
: $($(1)) [$(2) $(3)]))
92 $(foreach ch
,$(word 1,$($(1))),\
94 $(if
$(filter $(2),$(ch
)),\
96 $(call READ_FORM
,$(1))\
97 $(call READ_UNTIL
,$(1),$(2),$(3))),\
98 $(call _error
,Expected
'$(3)')))
102 $(and
$(READER_DEBUG
),$(info DROP_UNTIL
: $($(1)) [$(2)]))
103 $(foreach ch
,$(word 1,$($(1))),\
105 $(if
$(filter $(2),$(ch
)),\
107 $(eval
$(1) := $(wordlist
2,$(words $($(1))),$($(1))))\
108 $(call DROP_UNTIL
,$(1),$(2),$(3))),\
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)),))
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)')))\
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)')))\
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)')))\
177 $(call READ_ATOM
,$(1))))))))))))))))
178 $(call READ_SPACES
,$(1))
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
))