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