1 # coding: utf-8
2 # frozen_string_literal: true
3
4
5
6 module Umu
7
8 module AbstractSyntax
9
10 module Core
11
12 module Expression
13
14 module Binary
15
16 module Send
17
18 class Message < Umu::Abstraction::Model
19 attr_reader :sym, :exprs
20
21
22 def initialize(loc, sym, exprs)
23 ASSERT.kind_of sym, ::Symbol
24 ASSERT.kind_of exprs, ::Array
25
26 super(loc)
27
28 @sym = sym
29 @exprs = exprs
30 end
31
32
33 def to_s
34 format(".%s",
35 if self.exprs.empty?
36 self.sym.to_s
37 else
38 format "(%s %s)",
39 self.sym.to_s,
40 self.exprs.map(&:to_s).join(' ')
41 end
42 )
43 end
44
45
46 def pretty_print(q)
47 PRT.group_for_enum(
48 q,
49
50 self.exprs,
51
52 bb: format(self.exprs.empty? ? ".%s" : ".(%s ", self.sym.to_s),
53
54 eb: self.exprs.empty? ? '' : ')',
55
56 join: ' '
57 )
58 end
59 end
60
61
62
63 class Entry < Binary::Abstract
64 alias rhs_head_message rhs
65 attr_reader :rhs_tail_messages
66 attr_reader :opt_receiver_type_sym
67
68
69 def initialize(
70 loc, lhs_expr,
71 rhs_head_message, rhs_tail_messages,
72 opt_receiver_type_sym
73 )
74 ASSERT.kind_of lhs_expr, ASCE::Abstract
75 ASSERT.kind_of rhs_head_message, Message
76 ASSERT.kind_of rhs_tail_messages, ::Array
77 ASSERT.opt_kind_of opt_receiver_type_sym, ::Symbol
78
79 super(loc, lhs_expr, rhs_head_message)
80
81 @rhs_tail_messages = rhs_tail_messages
82 @opt_receiver_type_sym = opt_receiver_type_sym
83 end
84
85
86 def rhs_messages
87 [self.rhs_head_message] + self.rhs_tail_messages
88 end
89
90
91 def to_s
92 format("(%s%s)%s",
93 self.lhs_expr.to_s,
94
95 if self.opt_receiver_type_sym
96 format " : %s", self.opt_receiver_type_sym.to_s
97 else
98 ''
99 end,
100
101 self.rhs_messages.map(&:to_s).join
102 )
103 end
104
105
106 def pretty_print(q)
107 PRT.group q, bb:'(', eb:')' do
108 q.pp lhs_expr
109 if self.opt_receiver_type_sym
110 q.text format(" : %s", self.opt_receiver_type_sym.to_s)
111 end
112 end
113
114 PRT.group_for_enum q, self.rhs_messages
115 end
116
117
118 private
119
120 def __evaluate__(env, event)
121 ASSERT.kind_of env, E::Entry
122 ASSERT.kind_of event, E::Tracer::Event
123
124 new_env = env.enter event
125
126 lhs_result = self.lhs_expr.evaluate new_env
127 ASSERT.kind_of lhs_result, ASR::Value
128 init_receiver = lhs_result.value
129
130 if self.opt_receiver_type_sym
131 receiver_type_sym = opt_receiver_type_sym
132
133 receiver_signat = new_env.ty_lookup receiver_type_sym, self.loc
134 ASSERT.kind_of receiver_signat, ECTSC::Base
135 unless env.ty_kind_of?(init_receiver, receiver_signat)
136 raise X::TypeError.new(
137 self.loc,
138 env,
139 "Expected a %s, but %s : %s",
140 receiver_type_sym,
141 init_receiver,
142 init_receiver.type_sym
143 )
144 end
145 end
146
147 final_receiver = self.rhs_messages.inject(init_receiver) {
148 |receiver, message|
149 ASSERT.kind_of receiver, VC::Top
150 ASSERT.kind_of message, Message
151
152 __send_message__ receiver, message, new_env, event
153 }
154 ASSERT.kind_of final_receiver, VC::Top
155 end
156
157
158 def __send_message__(receiver, message, env, event)
159 ASSERT.kind_of receiver, VC::Top
160 ASSERT.kind_of message, Message
161 ASSERT.kind_of env, E::Entry
162 ASSERT.kind_of event, E::Tracer::Event
163
164 message_sym = message.sym
165 arg_values = message.exprs.map { |expr|
166 result = expr.evaluate env
167 ASSERT.kind_of result, ASR::Value
168
169 result.value
170 }
171 arg_num = arg_values.size
172
173 receiver_signat = env.ty_class_signat_of receiver
174 ASSERT.kind_of receiver_signat, ECTSC::Abstract
175 method_signat = receiver_signat.lookup_instance_method(
176 message_sym, message.loc, env
177 )
178 ASSERT.kind_of method_signat, ECTSM::Entry
179
180 param_signats = method_signat.param_class_signats
181 param_num = method_signat.param_class_signats.size
182
183 result_value =
184 if param_num == arg_num
185 __validate_type_of_args__(
186 message_sym,
187 param_num, arg_values, param_signats, loc, env
188 )
189
190 next_receiver = receiver.invoke(
191 method_signat, message.loc, env, event, *arg_values
192 )
193 ASSERT.assert(
194 env.ty_kind_of?(
195 next_receiver, method_signat.ret_class_signat
196 ), (
197 {
198 nx_recv:
199 next_receiver.class,
200 ret_class_signat:
201 method_signat.ret_class_signat.symbol
202 }.inspect
203 )
204 )
205 ASSERT.kind_of next_receiver, VC::Top
206 elsif param_num < arg_num
207 __validate_type_of_args__(
208 message_sym,
209 param_num, arg_values, param_signats, loc, env
210 )
211
212 invoked_values = if param_num == 0
213 []
214 else
215 arg_values[0 .. param_num - 1]
216 end
217
218 value = receiver.invoke(
219 method_signat, loc, env.enter(event), event,
220 *invoked_values
221 )
222 ASSERT.assert env.ty_kind_of?(
223 value, method_signat.ret_class_signat
224 )
225 ASSERT.kind_of value, VC::Top
226
227 hd_arg_value, *tl_arg_values = arg_values[param_num .. -1]
228
229 value.apply hd_arg_value, tl_arg_values, loc, env
230 elsif param_num > arg_num
231 =begin
232 p({
233 param_num: param_num,
234 arg_num: arg_num,
235 arg_values: arg_values
236 })
237 =end
238 free_idents, bound_idents = (0 .. param_num - 1).inject(
239 [[], []]
240 ) { |(fr_idents, bo_idents), i|
241 ident = ASCE.make_identifier(
242 loc, format("%%x_%d", i + 1).to_sym
243 )
244
245 if i < arg_num
246 [fr_idents + [ident], bo_idents]
247 else
248 [fr_idents, bo_idents + [ident]]
249 end
250 }
251 =begin
252 p({
253 free_idents: free_idents,
254 bound_idents: bound_idents
255 })
256 =end
257 new_env = free_idents.zip(
258 arg_values
259 ).inject(
260 env.va_extend_value :'%r', receiver
261 ) { |e, (ident, v)|
262 ASSERT.kind_of e, E::Entry
263 ASSERT.kind_of ident, ASCEU::Identifier::Short
264 ASSERT.kind_of v, VC::Top
265
266 e.va_extend_value ident.sym, v
267 }
268
269 lamb_params = bound_idents.map { |ident|
270 ASSERT.kind_of ident, ASCEU::Identifier::Short
271
272 ASCE.make_parameter ident.loc, ident
273 }
274
275 VC.make_function(
276 ASCE.make_lambda(
277 loc,
278 lamb_params,
279 ASCE.make_send(
280 loc,
281 ASCE.make_identifier(loc, :'%r'),
282 ASCE.make_message(
283 loc,
284 method_signat.mess_sym,
285 free_idents + bound_idents
286 )
287 )
288 ),
289 new_env.va_context
290 )
291 else
292 ASSERT.abort 'No case'
293 end
294
295 ASSERT.kind_of result_value, VC::Top
296 end
297
298
299 def __validate_type_of_args__(
300 mess_sym, num, arg_values, param_signats, loc, env
301 )
302 ASSERT.kind_of mess_sym, ::Symbol
303 ASSERT.kind_of num, ::Integer
304 ASSERT.kind_of arg_values, ::Array
305 ASSERT.kind_of param_signats, ::Array
306 ASSERT.kind_of loc, LOC::Entry
307 ASSERT.kind_of env, E::Entry
308
309 (0 .. num - 1).each do |i|
310 arg_value = arg_values[i]
311 param_signat = param_signats[i]
312 ASSERT.kind_of arg_value, VC::Top
313 ASSERT.kind_of param_signat, ECTSC::Base
314
315 unless env.ty_kind_of?(arg_value, param_signat)
316 raise X::TypeError.new(
317 loc,
318 env,
319 "For '%s's #%d argument, expected a %s, but %s : %s",
320 mess_sym.to_s,
321 i + 1,
322 param_signat.symbol,
323 arg_value.to_s,
324 arg_value.type_sym
325 )
326 end
327 end
328 end
329 end
330
331 end # Umu::AbstractSyntax::Core::Expression::Binary::Send
332
333 end # Umu::AbstractSyntax::Core::Expression::Binary
334
335
336 module_function
337
338 def make_message(loc, sym, exprs = [])
339 ASSERT.kind_of loc, LOC::Entry
340 ASSERT.kind_of sym, ::Symbol
341 ASSERT.kind_of exprs, ::Array
342
343 Binary::Send::Message.new(loc, sym, exprs.freeze).freeze
344 end
345
346
347 def make_send(
348 loc, lhs_expr,
349 rhs_head_message, rhs_tail_messages = [],
350 opt_receiver_type_sym = nil
351 )
352 ASSERT.kind_of loc, LOC::Entry
353 ASSERT.kind_of lhs_expr, ASCE::Abstract
354 ASSERT.kind_of rhs_head_message, Binary::Send::Message
355 ASSERT.kind_of rhs_tail_messages, ::Array
356 ASSERT.opt_kind_of opt_receiver_type_sym, ::Symbol
357
358 Binary::Send::Entry.new(
359 loc, lhs_expr, rhs_head_message, rhs_tail_messages.freeze,
360 opt_receiver_type_sym
361 ).freeze
362 end
363
364 end # Umu::AbstractSyntax::Core::Expression
365
366 end # Umu::AbstractSyntax::Core
367
368 end # Umu::AbstractSyntax
369
370 end # Umu