1 //
2 // aegis - project change supervisor
3 // Copyright (C) 1994-1996, 1999, 2002-2008, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published
7 // by the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18
19 #include <common/ac/assert.h>
20 #include <common/ac/math.h>
21
22 #include <common/trace.h>
23 #include <libaegis/aer/expr/mul.h>
24 #include <libaegis/aer/value/error.h>
25 #include <libaegis/aer/value/integer.h>
26 #include <libaegis/aer/value/real.h>
27 #include <libaegis/sub.h>
28
29 #define PAIR(a, b) ((a) * rpt_value_type_MAX + (b))
30
31
~rpt_expr_mul()32 rpt_expr_mul::~rpt_expr_mul()
33 {
34 }
35
36
rpt_expr_mul(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)37 rpt_expr_mul::rpt_expr_mul(const rpt_expr::pointer &lhs,
38 const rpt_expr::pointer &rhs)
39 {
40 append(lhs);
41 append(rhs);
42 }
43
44
45 rpt_expr::pointer
create(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)46 rpt_expr_mul::create(const rpt_expr::pointer &lhs, const rpt_expr::pointer &rhs)
47 {
48 return pointer(new rpt_expr_mul(lhs, rhs));
49 }
50
51
52 rpt_value::pointer
evaluate() const53 rpt_expr_mul::evaluate()
54 const
55 {
56 //
57 // evaluate the left hand side
58 //
59 trace(("mul::evaluate()\n"));
60 assert(get_nchildren() == 2);
61 rpt_value::pointer v1 = nth_child(0)->evaluate(true, true);
62 if (v1->is_an_error())
63 return v1;
64
65 //
66 // coerce the left hand side to an arithmetic type
67 // (will not give error if can't, will copy instead)
68 //
69 rpt_value::pointer v1a = rpt_value::arithmetic(v1);
70
71 //
72 // evaluate the right hand side
73 //
74 rpt_value::pointer v2 = nth_child(1)->evaluate(true, true);
75 if (v2->is_an_error())
76 return v2;
77
78 //
79 // coerce the right hand side to an arithmetic type
80 // (will not give error if can't, will copy instead)
81 //
82 rpt_value::pointer v2a = rpt_value::arithmetic(v2);
83
84 //
85 // the type of the result depends on
86 // the types of the operands
87 //
88 {
89 rpt_value_integer *v1aip = dynamic_cast<rpt_value_integer *>(v1a.get());
90 if (v1aip)
91 {
92 long v1n = v1aip->query();
93
94 {
95 rpt_value_integer *v2aip =
96 dynamic_cast<rpt_value_integer *>(v2a.get());
97 if (v2aip)
98 {
99 return rpt_value_integer::create(v1n * v2aip->query());
100 }
101 }
102
103 {
104 rpt_value_real *v2arp =
105 dynamic_cast<rpt_value_real *>(v2a.get());
106 if (v2arp)
107 {
108 return rpt_value_real::create(v1n * v2arp->query());
109 }
110 }
111 }
112 }
113
114 {
115 rpt_value_real *v1arp = dynamic_cast<rpt_value_real *>(v1a.get());
116 if (v1arp)
117 {
118 double v1n = v1arp->query();
119
120 {
121 rpt_value_integer *v2aip =
122 dynamic_cast<rpt_value_integer *>(v2a.get());
123 if (v2aip)
124 {
125 return rpt_value_real::create(v1n * v2aip->query());
126 }
127 }
128
129 {
130 rpt_value_real *v2arp =
131 dynamic_cast<rpt_value_real *>(v2a.get());
132 if (v2arp)
133 {
134 return rpt_value_real::create(v1n * v2arp->query());
135 }
136 }
137 }
138 }
139
140 sub_context_ty sc;
141 sc.var_set_charstar("Name1", v1a->name());
142 sc.var_set_charstar("Name2", v2a->name());
143 nstring s(sc.subst_intl(i18n("illegal multiplication ($name1 * $name2)")));
144 return rpt_value_error::create(get_pos(), s);
145 }
146
147
~rpt_expr_div()148 rpt_expr_div::~rpt_expr_div()
149 {
150 }
151
152
rpt_expr_div(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)153 rpt_expr_div::rpt_expr_div(const rpt_expr::pointer &lhs,
154 const rpt_expr::pointer &rhs)
155 {
156 append(lhs);
157 append(rhs);
158 }
159
160
161 rpt_expr::pointer
create(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)162 rpt_expr_div::create(const rpt_expr::pointer &lhs, const rpt_expr::pointer &rhs)
163 {
164 return pointer(new rpt_expr_div(lhs, rhs));
165 }
166
167
168 static rpt_value::pointer
div_by_zero_error(const rpt_expr::pointer & ep)169 div_by_zero_error(const rpt_expr::pointer &ep)
170 {
171 sub_context_ty sc;
172 nstring s(sc.subst_intl(i18n("division by zero")));
173 return rpt_value_error::create(ep->get_pos(), s);
174 }
175
176
177 rpt_value::pointer
evaluate() const178 rpt_expr_div::evaluate()
179 const
180 {
181 //
182 // evaluate the left hand side
183 //
184 trace(("div::evaluate()\n"));
185 assert(get_nchildren() == 2);
186 rpt_value::pointer v1 = nth_child(0)->evaluate(true, true);
187 if (v1->is_an_error())
188 return v1;
189
190 //
191 // coerce the left hand side to an arithmetic type
192 // (will not give error if can't, will copy instead)
193 //
194 rpt_value::pointer v1a = rpt_value::arithmetic(v1);
195
196 //
197 // evaluate the right hand side
198 //
199 rpt_value::pointer v2 = nth_child(1)->evaluate(true, true);
200 if (v2->is_an_error())
201 return v2;
202
203 //
204 // coerce the right hand side to an arithmetic type
205 // (will not give error if can't, will copy instead)
206 //
207 rpt_value::pointer v2a = rpt_value::arithmetic(v2);
208
209 //
210 // the type of the result depends on
211 // the types of the operands
212 //
213 {
214 rpt_value_integer *v1aip = dynamic_cast<rpt_value_integer *>(v1a.get());
215 if (v1aip)
216 {
217 long v1n = v1aip->query();
218
219 {
220 rpt_value_integer *v2aip =
221 dynamic_cast<rpt_value_integer *>(v2a.get());
222 if (v2aip)
223 {
224 long den = v2aip->query();
225 if (den == 0)
226 return div_by_zero_error(nth_child(1));
227 return rpt_value_integer::create(v1n / den);
228 }
229 }
230
231 {
232 rpt_value_real *v2arp =
233 dynamic_cast<rpt_value_real *>(v2a.get());
234 if (v2arp)
235 {
236 double den = v2arp->query();
237 if (den == 0)
238 return div_by_zero_error(nth_child(1));
239 return rpt_value_real::create(v1n / den);
240 }
241 }
242 }
243 }
244
245 {
246 rpt_value_real *v1arp = dynamic_cast<rpt_value_real *>(v1a.get());
247 if (v1arp)
248 {
249 double v1n = v1arp->query();
250
251 {
252 rpt_value_integer *v2aip =
253 dynamic_cast<rpt_value_integer *>(v2a.get());
254 if (v2aip)
255 {
256 long den = v2aip->query();
257 if (den == 0)
258 return div_by_zero_error(nth_child(1));
259 return rpt_value_real::create(v1n / den);
260 }
261 }
262
263 {
264 rpt_value_real *v2arp =
265 dynamic_cast<rpt_value_real *>(v2a.get());
266 if (v2arp)
267 {
268 double den = v2arp->query();
269 if (den == 0)
270 return div_by_zero_error(nth_child(1));
271 return rpt_value_real::create(v1n / den);
272 }
273 }
274 }
275 }
276
277 sub_context_ty sc;
278 sc.var_set_charstar("Name1", v1a->name());
279 sc.var_set_charstar("Name2", v2a->name());
280 nstring s(sc.subst_intl(i18n("illegal division ($name1 / $name2)")));
281 return rpt_value_error::create(get_pos(), s);
282 }
283
284
~rpt_expr_mod()285 rpt_expr_mod::~rpt_expr_mod()
286 {
287 }
288
289
rpt_expr_mod(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)290 rpt_expr_mod::rpt_expr_mod(const rpt_expr::pointer &lhs,
291 const rpt_expr::pointer &rhs)
292 {
293 append(lhs);
294 append(rhs);
295 }
296
297
298 rpt_expr::pointer
create(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)299 rpt_expr_mod::create(const rpt_expr::pointer &lhs, const rpt_expr::pointer &rhs)
300 {
301 return pointer(new rpt_expr_mod(lhs, rhs));
302 }
303
304
305 static rpt_value::pointer
mod_by_zero_error(const rpt_expr::pointer & ep)306 mod_by_zero_error(const rpt_expr::pointer &ep)
307 {
308 sub_context_ty sc;
309 nstring s(sc.subst_intl(i18n("modulo by zero")));
310 return rpt_value_error::create(ep->get_pos(), s);
311 }
312
313
314 rpt_value::pointer
evaluate() const315 rpt_expr_mod::evaluate()
316 const
317 {
318 //
319 // evaluate the left hand side
320 //
321 trace(("mod::evaluate()\n"));
322 assert(get_nchildren() == 2);
323 rpt_value::pointer v1 = nth_child(0)->evaluate(true, true);
324 if (v1->is_an_error())
325 return v1;
326
327 //
328 // coerce the left hand side to an arithmetic type
329 // (will not give error if can't, will copy instead)
330 //
331 rpt_value::pointer v1a = rpt_value::arithmetic(v1);
332
333 //
334 // evaluate the right hand side
335 //
336 rpt_value::pointer v2 = nth_child(1)->evaluate(true, true);
337 if (v2->is_an_error())
338 return v2;
339
340 //
341 // coerce the right hand side to an arithmetic type
342 // (will not give error if can't, will copy instead)
343 //
344 rpt_value::pointer v2a = rpt_value::arithmetic(v2);
345
346 //
347 // the type of the result depends on
348 // the types of the operands
349 //
350 {
351 rpt_value_integer *v1aip = dynamic_cast<rpt_value_integer *>(v1a.get());
352 if (v1aip)
353 {
354 long num = v1aip->query();
355
356 {
357 rpt_value_integer *v2aip =
358 dynamic_cast<rpt_value_integer *>(v2a.get());
359 if (v2aip)
360 {
361 long den = v2aip->query();
362 if (den == 0)
363 return mod_by_zero_error(nth_child(1));
364 return rpt_value_integer::create(num % den);
365 }
366 }
367
368 {
369 rpt_value_real *v2arp =
370 dynamic_cast<rpt_value_real *>(v2a.get());
371 if (v2arp)
372 {
373 double den = v2arp->query();
374 if (den == 0)
375 return mod_by_zero_error(nth_child(1));
376 return rpt_value_real::create(fmod(num, den));
377 }
378 }
379 }
380 }
381
382 {
383 rpt_value_real *v1arp = dynamic_cast<rpt_value_real *>(v1a.get());
384 if (v1arp)
385 {
386 double num = v1arp->query();
387
388 {
389 rpt_value_integer *v2aip =
390 dynamic_cast<rpt_value_integer *>(v2a.get());
391 if (v2aip)
392 {
393 long den = v2aip->query();
394 if (den == 0)
395 return mod_by_zero_error(nth_child(1));
396 return rpt_value_real::create(fmod(num, den));
397 }
398 }
399
400 {
401 rpt_value_real *v2arp =
402 dynamic_cast<rpt_value_real *>(v2a.get());
403 if (v2arp)
404 {
405 double den = v2arp->query();
406 if (den == 0)
407 return mod_by_zero_error(nth_child(1));
408 return rpt_value_real::create(fmod(num, den));
409 }
410 }
411 }
412 }
413
414 sub_context_ty sc;
415 sc.var_set_charstar("Name1", v1a->name());
416 sc.var_set_charstar("Name2", v2a->name());
417 // xgettext:no-c-format
418 nstring s(sc.subst_intl(i18n("illegal modulo ($name1 % $name2)")));
419 return rpt_value_error::create(get_pos(), s);
420 }
421
422
423 // vim: set ts=8 sw=4 et :
424