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 Product
17
18 class Abstract < Container::Abstract
19 alias pats array
20
21
22 def exported_vars
23 self.reject(&:wildcard?).inject([]) { |array, epat|
24 ASSERT.kind_of array, ::Array
25 ASSERT.kind_of epat, Pattern::Abstract
26
27 array + epat.exported_vars
28 }.freeze
29 end
30
31
32 private
33
34 def __desugar_value__(expr, env, _event)
35 ASSERT.kind_of expr, ASCE::Abstract
36
37 ASCD.make_seq_of_declaration(
38 self.loc,
39 [
40 ASCD.make_value(self.loc, :'%t', expr, __type_sym__)
41 ] + (
42 __desugar_pattern__(:'%t')
43 )
44 )
45 end
46
47
48 def __desugar_lambda__(seq_num, env, _event)
49 ASSERT.kind_of seq_num, ::Integer
50
51 var_sym = __gen_sym__ seq_num
52
53 CSCP.make_result(
54 ASCE.make_identifier(self.loc, var_sym),
55 __desugar_pattern__(var_sym),
56 __type_sym__
57 )
58 end
59
60
61 def __desugar_pattern__(var_sym)
62 ASSERT.kind_of var_sym, ::Symbol
63
64 self.each_with_index.reject { |epat, _index|
65 ASSERT.kind_of epat, ElementOfContainer::Abstract
66
67 epat.wildcard? && epat.opt_type_sym.nil?
68 }.map { |epat, index|
69 ASSERT.kind_of epat, ElementOfContainer::Abstract
70 ASSERT.kind_of index, ::Integer
71
72 expr = ASCE.make_product(
73 epat.loc,
74 ASCE.make_identifier(epat.loc, var_sym),
75 __make_selector__(epat.loc, index, epat)
76 )
77
78 ASCD.make_value(
79 epat.loc,
80 epat.var_pat.var_sym,
81 expr,
82 epat.var_pat.opt_type_sym
83 )
84 }
85 end
86
87
88 def __type_sym__
89 raise X::InternalSubclassResponsibility
90 end
91
92
93 def __make_selector__(_loc, _index, _epat)
94 raise X::InternalSubclassResponsibility
95 end
96 end
97
98
99
100 class Tuple < Abstract
101 def initialize(loc, vpats)
102 ASSERT.kind_of vpats, ::Array
103 ASSERT.assert vpats.size >= 2
104
105 vpats.reject(&:wildcard?).inject({}) do |hash, vpat|
106 ASSERT.kind_of hash, ::Hash
107 ASSERT.kind_of vpat, ElementOfContainer::Variable
108
109 hash.merge(vpat.var_sym => true) {
110 raise X::SyntaxError.new(
111 vpat.loc,
112 "Duplicated pattern variable: '%s'", vpat.to_s
113 )
114 }
115 end
116
117 super
118 end
119
120
121 def each
122 self.pats.each do |vpat|
123 ASSERT.kind_of vpat, ElementOfContainer::Variable
124
125 yield vpat
126 end
127 end
128
129
130 def to_s
131 format "(%s)", self.map(&:to_s).join(', ')
132 end
133
134
135 def pretty_print(q)
136 PRT.group_for_enum q, self, bb:'(', eb:')', join:', '
137 end
138
139
140 private
141
142 def __type_sym__
143 :Product
144 end
145
146
147 def __make_selector__(loc, index, _pat)
148 ASCE.make_number_selector loc, index + 1
149 end
150 end
151
152
153
154 module Named
155
156 class Label < Abstraction::Model
157 attr_reader :sym
158
159
160 def initialize(loc, sym)
161 ASSERT.kind_of sym, ::Symbol
162
163 super(loc)
164
165 @sym = sym
166 end
167
168
169 def hash
170 self.sym.hash
171 end
172
173
174 def eql?(other)
175 self.sym.eql? other.sym
176 end
177
178
179 def to_s
180 self.sym.to_s + ':'
181 end
182 end
183
184
185
186 class Entry < Abstract
187 attr_reader :index_by_label
188
189
190 def initialize(loc, fields)
191 ASSERT.kind_of fields, ::Array
192 ASSERT.assert fields.size >= 1
193
194 @index_by_label, vpat_hash, _index =
195 fields
196 .inject(
197 [{}, {}, 0 ]
198 ) { |(l_hash, v_hash, index), (label, vpat)|
199 ASSERT.kind_of l_hash, ::Hash
200 ASSERT.kind_of v_hash, ::Hash
201 ASSERT.kind_of label, Label
202 ASSERT.kind_of vpat, ElementOfContainer::Variable
203
204 [
205 l_hash.merge(label => index) {
206 raise X::SyntaxError.new(
207 label.loc,
208 "Duplicated pattern label: '%s'", label.to_s
209 )
210 },
211
212 v_hash.merge(vpat => true) {
213 raise X::SyntaxError.new(
214 vpat.loc,
215 "Duplicated pattern variable: '%s'", vpat.to_s
216 )
217 },
218
219 index + 1
220 ]
221 }
222
223 super(loc, vpat_hash.keys)
224 end
225
226
227 def each
228 self.index_by_label.each do |label, index|
229 ASSERT.kind_of label, Label
230 ASSERT.kind_of index, ::Integer
231
232 yield CSCP.make_named_tuple_field(
233 self.loc,
234 label,
235 self.pats[index]
236 )
237 end
238 end
239
240
241 def to_s
242 format "(%s)", self.map(&:to_s).join(' ')
243 end
244
245
246 def pretty_print(q)
247 PRT.group_for_enum q, self, bb:'(', eb:')', join:' '
248 end
249
250
251 private
252
253 def __type_sym__
254 :Named
255 end
256
257
258 def __make_selector__(loc, _index, fpat)
259 ASSERT.kind_of fpat, ElementOfContainer::Field
260
261 ASCE.make_label_selector loc, fpat.label.sym
262 end
263 end
264
265 end # Umu::ConcreteSyntax::Core::Pattern::Container::Product::Named
266
267 end # Umu::ConcreteSyntax::Core::Pattern::Container::Product
268
269 end # Umu::ConcreteSyntax::Core::Pattern::Container
270
271
272 module_function
273
274 def make_tuple(loc, vpats)
275 ASSERT.kind_of loc, LOC::Entry
276 ASSERT.kind_of vpats, ::Array
277
278 Container::Product::Tuple.new(loc, vpats.freeze).freeze
279 end
280
281
282 def make_named_tuple(loc, fields)
283 ASSERT.kind_of loc, LOC::Entry
284 ASSERT.kind_of fields, ::Array
285
286 Container::Product::Named::Entry.new(loc, fields.freeze).freeze
287 end
288
289 def make_named_tuple_label(loc, sym)
290 ASSERT.kind_of loc, LOC::Entry
291 ASSERT.kind_of sym, ::Symbol
292
293 Container::Product::Named::Label.new(loc, sym).freeze
294 end
295
296
297 end # Umu::ConcreteSyntax::Core::Pattern
298
299 end # Umu::ConcreteSyntax::Core
300
301 end # Umu::ConcreteSyntax
302
303 end # Umu