1 # coding: utf-8
2 # frozen_string_literal: true
3
4
5
6 module Umu
7
8 module Value
9
10 module Core
11
12 class Fun < Object
13 attr_reader :lam, :va_context
14
15
16 def initialize(lam, va_context)
17 ASSERT.kind_of lam, ASCEN::Lambda::Entry
18 ASSERT.kind_of va_context, ECV::Abstract
19
20 super()
21
22 @lam = lam
23 @va_context = va_context
24 end
25
26
27 def to_s
28 lam = self.lam
29
30 format("#<%s%s>",
31 if lam.opt_name
32 format "%s: ", lam.opt_name
33 else
34 ''
35 end,
36
37 self.lam.to_s
38 )
39 end
40
41
42 def pretty_print(q)
43 bb = if lam.opt_name
44 format "#<%s: ", lam.opt_name
45 else
46 '#<'
47 end
48
49 PRT.group q, bb:bb, eb:'>' do
50 q.pp self.lam
51 end
52 end
53
54
55 def apply(head_value, tail_values, loc, env)
56 ASSERT.kind_of head_value, VC::Top
57 ASSERT.kind_of tail_values, ::Array
58 ASSERT.kind_of loc, LOC::Entry
59 ASSERT.kind_of env, E::Entry
60
61 result_value = E::Tracer.trace(
62 env.pref,
63 env.trace_stack.count,
64 'Apply',
65 self.class,
66 loc,
67 format("(%s %s)",
68 self.to_s,
69 (
70 [head_value] + tail_values
71 ).map(&:to_s).join(' ')
72 )
73 ) { |event|
74 __apply__(
75 head_value, tail_values, loc, env, event
76 )
77 }
78 ASSERT.kind_of result_value, VC::Top
79 end
80
81
82 define_instance_method(
83 :meth_apply,
84 :apply, [],
85 [VC::Top], VC::Top
86 )
87 def meth_apply(loc, env, event, value)
88 ASSERT.kind_of value, VC::Top
89
90 self.apply value, [], loc, env.enter(event)
91 end
92
93
94 define_instance_method(
95 :meth_apply_binary,
96 :'apply-binary', [],
97 [VC::Top, VC::Top], VC::Top
98 )
99 def meth_apply_binary(loc, env, event, fst_value, snd_value)
100 ASSERT.kind_of fst_value, VC::Top
101 ASSERT.kind_of snd_value, VC::Top
102
103 self.apply fst_value, [snd_value], loc, env.enter(event)
104 end
105
106
107 define_instance_method(
108 :meth_apply_nary,
109 :'apply-nary', [],
110 [VC::Top, VC::Top, VCM::Abstract], VC::Top
111 )
112 def meth_apply_nary(loc, env, event, fst_value, snd_value, tail_values)
113 ASSERT.kind_of fst_value, VC::Top
114 ASSERT.kind_of snd_value, VC::Top
115 ASSERT.kind_of tail_values, VCM::Abstract
116
117 self.apply(
118 fst_value,
119 [snd_value] + tail_values.to_a,
120 loc,
121 env.enter(event)
122 )
123 end
124
125
126 private
127
128 def __apply__(init_head_value, init_tail_values, loc, env, event)
129 ASSERT.kind_of init_head_value, VC::Top
130 ASSERT.kind_of init_tail_values, ::Array
131 ASSERT.kind_of loc, LOC::Entry
132 ASSERT.kind_of env, E::Entry
133 ASSERT.kind_of event, E::Tracer::Event
134
135 init_values = [init_head_value] + init_tail_values
136 lam = self.lam
137
138 init_params = lam.params
139 init_params_num = init_params.size
140 init_values_num = init_values.size
141 ASSERT.assert init_params_num >= 1
142 ASSERT.assert init_values_num >= 1
143 init_env = env.update_va_context self.va_context
144
145 result_value =
146 if init_params_num == init_values_num
147 final_params, final_values, final_env = __bind__(
148 init_params_num, init_params, init_values, init_env
149 )
150 ASSERT.assert final_params.empty?
151 ASSERT.assert final_values.empty?
152
153 new_env = final_env.enter event
154 result = self.lam.expr.evaluate new_env
155 ASSERT.kind_of result, ASR::Value
156
157 result.value
158 elsif init_params_num < init_values_num
159 final_params, final_values, final_env = __bind__(
160 init_params_num, init_params, init_values, init_env
161 )
162 ASSERT.assert final_params.empty?
163 ASSERT.assert (not final_values.empty?)
164 final_head_value, *final_tail_values = final_values
165
166 new_env = final_env.enter event
167 result = self.lam.expr.evaluate new_env
168 ASSERT.kind_of result, ASR::Value
169
170 result.value.apply(
171 final_head_value, final_tail_values, loc, new_env
172 )
173 elsif init_params_num > init_values_num
174 final_params, final_values, final_env = __bind__(
175 init_values_num, init_params, init_values, init_env
176 )
177 ASSERT.assert (not final_params.empty?)
178 ASSERT.assert final_values.empty?
179
180 VC.make_function(
181 ASCE.make_lambda(
182 loc, final_params, lam.expr, lam.opt_name
183 ),
184 final_env.va_context
185 )
186 else
187 ASSERT.abort 'No case'
188 end
189
190 ASSERT.kind_of result_value, VC::Top
191 end
192
193
194 def __bind__(init_num, init_params, init_values, init_env)
195 tuple = loop.inject(
196 [init_num, init_params, init_values, init_env]
197 ) {
198 |(num, params, values, env), _|
199 ASSERT.kind_of num, ::Integer
200 ASSERT.kind_of params, ::Array
201 ASSERT.kind_of values, ::Array
202 ASSERT.kind_of env, E::Entry
203
204 if num <= 0
205 break [params, values, env]
206 end
207
208 head_param, *tail_params = params
209 head_value, *tail_values = values
210 ASSERT.kind_of head_param, ASCEN::Lambda::Parameter
211 ASSERT.kind_of tail_params, ::Array
212 ASSERT.kind_of head_value, VC::Top
213 ASSERT.kind_of tail_values, ::Array
214
215 if head_param.opt_type_sym
216 type_sym = head_param.opt_type_sym
217
218 signat = env.ty_lookup type_sym, head_param.loc
219 ASSERT.kind_of signat, ECTSC::Base
220 unless env.ty_kind_of?(head_value, signat)
221 raise X::TypeError.new(
222 head_param.loc,
223 env,
224 "Expected a %s, but %s : %s",
225 type_sym,
226 head_value,
227 head_value.type_sym
228 )
229 end
230 end
231
232 [
233 num - 1,
234
235 tail_params,
236
237 tail_values,
238
239 env.va_extend_value(head_param.ident.sym, head_value)
240 ]
241 }
242
243 ASSERT.tuple_of tuple, [::Array, ::Array, E::Entry]
244 end
245 end
246 Fun.freeze
247
248
249 module_function
250
251 def make_function(lam, va_context)
252 ASSERT.kind_of lam, ASCEN::Lambda::Entry
253 ASSERT.kind_of va_context, ECV::Abstract
254
255 Fun.new(lam, va_context).freeze
256 end
257
258 end # Umu::Value::Core
259
260 end # Umu::Value
261
262 end # Umu