1 # coding: utf-8
2 # frozen_string_literal: true
3
4
5
6 module Umu
7
8 module ConcreteSyntax
9
10 module Core
11
12 module Pattern
13
14 module Container
15
16 module Morph
17
18 class Abstract < Container::Abstract
19 alias pats array
20 attr_reader :opt_last_pat
21
22 def initialize(loc, pats, opt_last_pat)
23 ASSERT.kind_of pats, ::Array
24 ASSERT.opt_kind_of opt_last_pat, ElementOfContainer::Variable
25 ASSERT.assert (if pats.empty? then opt_last_pat.nil? else true end)
26
27 init_hash = if self.opt_last_pat
28 {self.opt_last_pat.var_sym => true}
29 else
30 {}
31 end
32
33 pats.reject(&:wildcard?).inject(init_hash) do |hash, vpat|
34 ASSERT.kind_of vpat, ElementOfContainer::Variable
35 ASSERT.kind_of hash, ::Hash
36
37 hash.merge(vpat.var_sym => true) {
38 raise X::SyntaxError.new(
39 vpat.loc,
40 "Duplicated pattern variable: '%s'", vpat.to_s
41 )
42 }
43 end
44
45 super(loc, pats)
46
47 @opt_last_pat = opt_last_pat
48 end
49
50
51 def to_s
52 [
53 __bb__,
54
55 self.map(&:to_s).join(', '),
56
57 if self.opt_last_pat
58 '|' + self.opt_last_pat.to_s
59 else
60 ''
61 end,
62
63 __eb__
64 ].join
65 end
66
67
68 def pretty_print(q)
69 if self.opt_last_pat
70 last_pat = self.opt_last_pat
71
72 PRT.group_for_enum q, self, bb:__bb__, join:', '
73
74 PRT.group q, bb:'|', eb:__eb__ do
75 q.pp last_pat
76 end
77 else
78 PRT.group_for_enum q, self, bb:__bb__, eb:__eb__, join:', '
79 end
80 end
81
82
83 def exported_vars
84 (self.pats + [self.opt_last_pat]).reject(&:wildcard?).inject([]) {
85 |array, vpat|
86 ASSERT.kind_of array, ::Array
87 ASSERT.kind_of vpat, ElementOfContainer::Variable
88
89 array + vpat.exported_vars
90 }.freeze
91 end
92
93
94 private
95
96 def __bb__
97 raise X::InternalSubclassResponsibility
98 end
99
100
101 def __eb__
102 raise X::InternalSubclassResponsibility
103 end
104
105
106 def __desugar_value__(expr, env, _event)
107 ASSERT.kind_of expr, ASCE::Abstract
108
109 decl = if self.pats.empty?
110 __desugar_value_nil__(self.loc, expr)
111 else
112 ASCD.make_seq_of_declaration(
113 self.loc, __desugar__(expr, env)
114 )
115 end
116
117 ASSERT.kind_of decl, ASCD::Abstract
118 end
119
120
121 def __desugar_lambda__(seq_num, env, _event)
122 ASSERT.kind_of seq_num, ::Integer
123
124 var_sym = __gen_sym__ seq_num
125
126 opt_result = (
127 if self.pats.empty?
128 __desugar_lambda_nil__(self.loc)
129 else
130 CSCP.make_result(
131 ASCE.make_identifier(self.loc, var_sym),
132
133 __desugar__(
134 ASCE.make_identifier(self.loc, var_sym),
135 env
136 ),
137
138 __opt_type_sym_of_cons__
139 )
140 end
141 )
142
143 ASSERT.opt_kind_of opt_result, CSCP::Result
144 end
145
146
147 def __desugar__(expr, _env)
148 ASSERT.kind_of expr, ASCE::Abstract
149
150 head_vpat, *tail_pats = self.pats
151 ASSERT.kind_of head_vpat, ElementOfContainer::Variable
152
153 init_loc = head_vpat.loc
154
155 init_seq_num = 1
156
157 init_pair_sym = __gen_pair_sym__ init_seq_num
158
159 init_decls = [
160 ASCD.make_value(
161 init_loc,
162 init_pair_sym,
163 __make_send_dest__(init_loc, expr)
164 ),
165
166 ASCD.make_value(
167 init_loc,
168 head_vpat.var_sym,
169 __make_select_head__(init_loc, init_pair_sym),
170 head_vpat.opt_type_sym
171 )
172 ]
173
174 _final_seq_num, final_pair_sym, final_decls = tail_pats.inject(
175 [init_seq_num, init_pair_sym, init_decls]
176 ) {
177 |(seq_num, pair_sym, decls ), vpat|
178 ASSERT.kind_of seq_num, ::Integer
179 ASSERT.kind_of pair_sym, ::Symbol
180 ASSERT.kind_of decls, ::Array
181 ASSERT.kind_of vpat, ElementOfContainer::Variable
182
183 loc = vpat.loc
184 next_seq_num = seq_num + 1
185 next_pair_sym = __gen_pair_sym__ next_seq_num
186 tail_list_expr = __make_select_tail__ loc, pair_sym
187
188 next_decls = (
189 decls
190 ) + (
191 if vpat.wildcard?
192 [
193 ASCD.make_value(
194 loc,
195 next_pair_sym,
196 ASCE.make_product(
197 loc,
198 __make_send_dest__(loc, tail_list_expr),
199 ASCE.make_number_selector(loc, 2)
200 ),
201 vpat.opt_type_sym
202 )
203 ]
204 else
205 [
206 ASCD.make_value(
207 loc,
208 next_pair_sym,
209 __make_send_dest__(loc, tail_list_expr)
210 ),
211
212 ASCD.make_value(
213 loc,
214 vpat.var_sym,
215 __make_select_head__(loc, next_pair_sym),
216 vpat.opt_type_sym
217 )
218
219 ]
220 end
221 )
222
223 [next_seq_num, next_pair_sym, next_decls]
224 }
225
226 (
227 final_decls
228 ) + (
229 if self.opt_last_pat
230 last_pat = self.opt_last_pat
231
232 [
233 ASCD.make_value(
234 last_pat.loc,
235 last_pat.var_sym,
236 __make_select_tail__(last_pat.loc, final_pair_sym),
237 last_pat.opt_type_sym
238 )
239 ]
240 else
241 [
242 __desugar_value_nil__(
243 loc,
244 __make_select_tail__(loc, final_pair_sym)
245 )
246 ]
247 end
248 )
249 end
250
251
252 def __desugar_value_nil__(loc, expr)
253 ASCD.make_value(
254 loc, WILDCARD, expr, __opt_type_sym_of_nil__
255 )
256 end
257
258
259 def __desugar_lambda_nil__(loc)
260 CSCP.make_result(
261 ASCE.make_identifier(loc, WILDCARD),
262 [],
263 __opt_type_sym_of_nil__
264 )
265 end
266
267
268 def __gen_pair_sym__(num)
269 ASSERT.kind_of num, ::Integer
270
271 format("%%p%d", num).to_sym
272 end
273
274
275 def __make_send_dest__(loc, expr)
276 ASSERT.kind_of loc, LOC::Entry
277 ASSERT.kind_of expr, ASCE::Abstract
278
279 opt_type_sym = if self.opt_last_pat
280 self.opt_last_pat.opt_type_sym
281 else
282 __opt_type_sym_of_morph__
283 end
284
285 ASCE.make_send(
286 loc, expr, ASCE.make_message(loc, :dest!), [], opt_type_sym
287 )
288 end
289
290
291 def __make_select_by_number__(loc, var_sym, sel_num)
292 ASSERT.kind_of loc, LOC::Entry
293 ASSERT.kind_of var_sym, ::Symbol
294 ASSERT.kind_of sel_num, ::Integer
295
296 ASCE.make_product(
297 loc,
298 ASCE.make_identifier(loc, var_sym),
299 ASCE.make_number_selector(loc, sel_num)
300 )
301 end
302
303
304 def __make_select_head__(loc, var_sym)
305 ASSERT.kind_of loc, LOC::Entry
306 ASSERT.kind_of var_sym, ::Symbol
307
308 __make_select_by_number__ loc, var_sym, 1
309 end
310
311
312 def __make_select_tail__(loc, var_sym)
313 ASSERT.kind_of loc, LOC::Entry
314 ASSERT.kind_of var_sym, ::Symbol
315
316 __make_select_by_number__ loc, var_sym, 2
317 end
318
319
320 def __opt_type_sym_of_morph__
321 raise X::InternalSubclassResponsibility
322 end
323
324 alias __opt_type_sym_of_nil__ __opt_type_sym_of_morph__
325 alias __opt_type_sym_of_cons__ __opt_type_sym_of_morph__
326 end
327
328 end # Umu::ConcreteSyntax::Core::Pattern::Container::Morph
329
330 end # Umu::ConcreteSyntax::Core::Pattern::Container
331
332 end # Umu::ConcreteSyntax::Core::Pattern
333
334 end # Umu::ConcreteSyntax::Core
335
336 end # Umu::ConcreteSyntax
337
338 end # Umu