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 Expression
13
14 module Nary
15
16 module Lambda
17
18 class Abstract < Expression::Abstract
19 attr_reader :pats, :expr, :decls
20
21
22 def initialize(loc, pats, expr, decls)
23 ASSERT.kind_of pats, ::Array
24 ASSERT.kind_of expr, CSCE::Abstract
25 ASSERT.kind_of decls, CSCD::SeqOfDeclaration
26
27 super(loc)
28
29 @pats = pats
30 @expr = expr
31 @decls = decls
32 end
33
34
35 def to_s
36 format "%s -> %s", self.pats.map(&:to_s).join(' '), self.expr.to_s
37 end
38
39
40 private
41
42 def __name_sym__
43 raise X::InternalSubclassResponsibility
44 end
45
46
47 def __desugar__(env, event)
48 new_env = env.enter event
49
50 lamb_params, lamb_decls = self.pats.each_with_index.inject(
51 [[], []]
52 ) {
53 |(params, decls), (pat, index)|
54 ASSERT.kind_of params, ::Array
55 ASSERT.kind_of decls, ::Array
56 ASSERT.kind_of pat, CSCP::Abstract
57 ASSERT.kind_of index, ::Integer
58
59 seq_num = index + 1
60
61 opt_result = pat.desugar_lambda seq_num, new_env
62 ASSERT.opt_kind_of opt_result, CSCP::Result
63 if opt_result
64 result = opt_result
65
66 param = ASCE.make_parameter(
67 result.ident.loc,
68 result.ident,
69 result.opt_type_sym
70 )
71
72
73 [
74 params + [param],
75 decls + result.decls
76 ]
77 else
78 ident_sym = format("%%x_%d", seq_num).to_sym
79
80 param = ASCE.make_parameter(
81 pat.loc,
82 ASCE.make_identifier(loc, ident_sym)
83 )
84
85 decl = ASCD.make_value(
86 pat.loc,
87
88 WILDCARD,
89
90 ASCE.make_if(
91 pat.loc,
92
93 [
94 ASCE.make_rule(
95 pat.loc,
96
97 ASCE.make_send(
98 pat.loc,
99
100 ASCE.make_identifier(
101 pat.loc,
102 ident_sym
103 ),
104
105 ASCE.make_message(
106 pat.loc,
107 :'empty?'
108 )
109 ),
110
111 ASCE.make_unit(pat.loc)
112 )
113 ],
114
115 ASCE.make_raise(
116 pat.loc,
117
118 X::EmptyError,
119
120 ASCE.make_string(
121 pat.loc,
122 "Empty morph cannot be destructible"
123 )
124 )
125 )
126 )
127
128 [
129 params + [param],
130 decls + [decl]
131 ]
132 end
133 }
134
135 local_decls = lamb_decls + self.decls.desugar(new_env).to_a
136 body_expr = self.expr.desugar new_env
137 lamb_expr = if local_decls.empty?
138 body_expr
139 else
140 ASCE.make_let(
141 self.loc,
142
143 ASCD.make_seq_of_declaration(
144 self.loc,
145 local_decls
146 ),
147
148 body_expr
149 )
150 end
151
152 ASCE.make_lambda self.loc, lamb_params, lamb_expr, __name_sym__
153 end
154 end
155
156
157
158 class Named < Abstract
159 attr_reader :sym
160
161
162 def initialize(loc, pats, expr, decls, sym)
163 ASSERT.kind_of pats, ::Array
164 ASSERT.kind_of expr, CSCE::Abstract
165 ASSERT.kind_of decls, CSCD::SeqOfDeclaration
166 ASSERT.kind_of sym, ::Symbol
167
168 super(loc, pats, expr, decls)
169
170 @sym = sym
171 end
172
173
174 def to_s
175 format("%s = %s%s",
176 self.sym.to_s,
177
178 super,
179
180 if self.decls.empty?
181 ''
182 else
183 format " %%WHERE {%s}", self.decls.to_s
184 end
185 )
186 end
187
188
189 def pretty_print(q)
190 PRT.group_for_enum(
191 q,
192 self.pats,
193 bb: format("%s = ", self.sym.to_s),
194 join: ' '
195 )
196
197 q.breakable
198
199 PRT.group q, bb:'-> ' do
200 q.pp self.expr
201 end
202
203 unless self.decls.empty?
204 q.breakable
205
206 PRT.group_for_enum(
207 q, self.decls, bb:'%WHERE {', eb:'}', sep:' '
208 )
209 end
210 end
211
212
213 private
214
215 def __name_sym__
216 self.sym
217 end
218 end
219
220
221
222 class Anonymous < Abstract
223
224 def to_s
225 format("{%s%s}",
226 super,
227
228 if self.decls.empty?
229 ''
230 else
231 format " %%WHERE %s", self.decls.to_s
232 end
233 )
234 end
235
236
237 def pretty_print(q)
238 PRT.group_for_enum q, self.pats, bb:'{', sep:' '
239
240 q.breakable
241
242 PRT.group q, bb:'-> ' do
243 q.pp self.expr
244 end
245
246 unless self.decls.empty?
247 q.breakable
248
249 PRT.group_for_enum q, self.decls, bb:'%WHERE', sep:' '
250 end
251
252 q.breakable
253
254 q.text '}'
255 end
256
257 private
258
259 def __name_sym__
260 nil
261 end
262 end
263
264 end # Umu::ConcreteSyntax::Core::Expression::Nary::Lambda
265
266 end # Umu::ConcreteSyntax::Core::Expression::Nary
267
268
269 module_function
270
271 def make_lambda(loc, pats, expr, opt_decls = nil)
272 ASSERT.kind_of loc, LOC::Entry
273 ASSERT.kind_of pats, ::Array
274 ASSERT.kind_of expr, CSCE::Abstract
275 ASSERT.opt_kind_of opt_decls, CSCD::SeqOfDeclaration
276
277 decls = opt_decls ? opt_decls : CSCD.make_empty_seq_of_declaration
278 Nary::Lambda::Anonymous.new(loc, pats, expr, decls.freeze).freeze
279 end
280
281
282 def make_named_lambda(loc, pats, expr, decls, sym)
283 ASSERT.kind_of loc, LOC::Entry
284 ASSERT.kind_of pats, ::Array
285 ASSERT.kind_of expr, CSCE::Abstract
286 ASSERT.kind_of decls, CSCD::SeqOfDeclaration
287 ASSERT.kind_of sym, ::Symbol
288
289 Nary::Lambda::Named.new(loc, pats, expr, decls.freeze, sym).freeze
290 end
291
292 end # Umu::ConcreteSyntax::Core::Expression
293
294 end # Umu::ConcreteSyntax::Core
295
296 end # Umu::ConcreteSyntax
297
298 end # Umu