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 by
7 //      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
13 //      GNU 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
17 //      <http://www.gnu.org/licenses/>.
18 //
19 
20 #include <common/ac/assert.h>
21 
22 #include <common/trace.h>
23 #include <libaegis/aer/expr/logical.h>
24 #include <libaegis/aer/value/boolean.h>
25 #include <libaegis/aer/value/error.h>
26 #include <libaegis/sub.h>
27 
28 
~rpt_expr_and_logical()29 rpt_expr_and_logical::~rpt_expr_and_logical()
30 {
31 }
32 
33 
rpt_expr_and_logical(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)34 rpt_expr_and_logical::rpt_expr_and_logical(const rpt_expr::pointer &lhs,
35     const rpt_expr::pointer &rhs)
36 {
37     append(lhs);
38     append(rhs);
39 }
40 
41 
42 rpt_expr::pointer
create(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)43 rpt_expr_and_logical::create(const rpt_expr::pointer &lhs,
44     const rpt_expr::pointer &rhs)
45 {
46     return pointer(new rpt_expr_and_logical(lhs, rhs));
47 }
48 
49 
50 rpt_value::pointer
evaluate() const51 rpt_expr_and_logical::evaluate()
52     const
53 {
54     //
55     // eveluate the left hand side
56     //
57     assert(get_nchildren() == 2);
58     rpt_value::pointer v1 = nth_child(0)->evaluate(true, true);
59     if (v1->is_an_error())
60         return v1;
61     rpt_value::pointer v1b = rpt_value::booleanize(v1);
62     rpt_value_boolean *v1p = dynamic_cast<rpt_value_boolean *>(v1b.get());
63     if (!v1p)
64     {
65         sub_context_ty sc;
66         sc.var_set_charstar("Name", v1->name());
67         nstring s
68         (
69             sc.subst_intl
70             (
71                 i18n("boolean value required for logical and (was given $name)")
72             )
73         );
74         return rpt_value_error::create(nth_child(0)->get_pos(), s);
75     }
76 
77     //
78     // short circuit the evaluation if the LHS is false
79     //
80     if (!v1p->query())
81         return v1b;
82 
83     //
84     // evaluate the right hand side
85     //
86     rpt_value::pointer v2 = nth_child(1)->evaluate(true, true);
87     if (v2->is_an_error())
88         return v2;
89     rpt_value::pointer v2b = rpt_value::booleanize(v2);
90     rpt_value_boolean *v2p = dynamic_cast<rpt_value_boolean *>(v2b.get());
91     if (!v2p)
92     {
93         sub_context_ty sc;
94         sc.var_set_charstar("Name", v2->name());
95         nstring s
96         (
97             sc.subst_intl
98             (
99                 i18n("boolean value required for logical and (was given $name)")
100             )
101         );
102         return rpt_value_error::create(nth_child(1)->get_pos(), s);
103     }
104     return v2b;
105 }
106 
107 
~rpt_expr_or_logical()108 rpt_expr_or_logical::~rpt_expr_or_logical()
109 {
110 }
111 
112 
rpt_expr_or_logical(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)113 rpt_expr_or_logical::rpt_expr_or_logical(const rpt_expr::pointer &lhs,
114     const rpt_expr::pointer &rhs)
115 {
116     append(lhs);
117     append(rhs);
118 }
119 
120 
121 rpt_expr::pointer
create(const rpt_expr::pointer & lhs,const rpt_expr::pointer & rhs)122 rpt_expr_or_logical::create(const rpt_expr::pointer &lhs,
123     const rpt_expr::pointer &rhs)
124 {
125     return pointer(new rpt_expr_or_logical(lhs, rhs));
126 }
127 
128 
129 rpt_value::pointer
evaluate() const130 rpt_expr_or_logical::evaluate()
131     const
132 {
133     //
134     // evaluate the left hand side
135     //
136     assert(get_nchildren() == 2);
137     rpt_value::pointer v1 = nth_child(0)->evaluate(true, true);
138     if (v1->is_an_error())
139         return v1;
140     rpt_value::pointer v1b = rpt_value::booleanize(v1);
141     rpt_value_boolean *v1p = dynamic_cast<rpt_value_boolean *>(v1b.get());
142     if (!v1p)
143     {
144         sub_context_ty sc;
145         sc.var_set_charstar("Name", v1->name());
146         nstring s
147         (
148             sc.subst_intl
149             (
150                 i18n("boolean value required for logical or (was given $name)")
151             )
152         );
153         return rpt_value_error::create(nth_child(0)->get_pos(), s);
154     }
155 
156     //
157     // short circuit the evaluation if LHS is true
158     //
159     if (v1p->query())
160         return v1b;
161 
162     //
163     // evaluate the right hand side
164     //
165     rpt_value::pointer v2 = nth_child(1)->evaluate(true, true);
166     if (v2->is_an_error())
167         return v2;
168     rpt_value::pointer v2b = rpt_value::booleanize(v2);
169     rpt_value_boolean *v2p = dynamic_cast<rpt_value_boolean *>(v2b.get());
170     if (!v2p)
171     {
172         sub_context_ty sc;
173         sc.var_set_charstar("Name", v2->name());
174         nstring s
175         (
176             sc.subst_intl
177             (
178                 i18n("boolean value required for logical or (was given $name)")
179             )
180         );
181         return rpt_value_error::create(nth_child(1)->get_pos(), s);
182     }
183     return v2b;
184 }
185 
186 
~rpt_expr_not_logical()187 rpt_expr_not_logical::~rpt_expr_not_logical()
188 {
189 }
190 
191 
rpt_expr_not_logical(const rpt_expr::pointer & arg)192 rpt_expr_not_logical::rpt_expr_not_logical(const rpt_expr::pointer &arg)
193 {
194     append(arg);
195 }
196 
197 
198 rpt_expr::pointer
create(const rpt_expr::pointer & arg)199 rpt_expr_not_logical::create(const rpt_expr::pointer &arg)
200 {
201     return pointer(new rpt_expr_not_logical(arg));
202 }
203 
204 
205 rpt_value::pointer
evaluate() const206 rpt_expr_not_logical::evaluate()
207     const
208 {
209     //
210     // evaluate the argument
211     //
212     trace(("not::evaluate()\n{\n"));
213     assert(get_nchildren() == 1);
214     rpt_value::pointer v1 = nth_child(0)->evaluate(true, true);
215     if (v1->is_an_error())
216     {
217         trace(("}\n"));
218         return v1;
219     }
220 
221     //
222     // coerce the argument to boolean type
223     //  (will not give error if can't, will copy instead)
224     //
225     rpt_value::pointer v2 = rpt_value::booleanize(v1);
226 
227     //
228     // the type of the result depends on
229     // the types of the argument
230     //
231     rpt_value_boolean *v2p = dynamic_cast<rpt_value_boolean *>(v2.get());
232     if (!v2p)
233     {
234         sub_context_ty sc;
235         sc.var_set_charstar("Name", v2->name());
236         nstring s(sc.subst_intl(i18n("illegal logical not ($name)")));
237         rpt_value::pointer result =
238             rpt_value_error::create(nth_child(0)->get_pos(), s);
239         trace(("}\n"));
240         return result;
241     }
242 
243     rpt_value::pointer result = rpt_value_boolean::create(!v2p->query());
244     trace(("return %p;\n", result.get()));
245     trace(("}\n"));
246     return result;
247 }
248 
249 
~rpt_expr_if()250 rpt_expr_if::~rpt_expr_if()
251 {
252     trace(("%s\n", __PRETTY_FUNCTION__));
253 }
254 
255 
rpt_expr_if(const rpt_expr::pointer & e1,const rpt_expr::pointer & e2,const rpt_expr::pointer & e3)256 rpt_expr_if::rpt_expr_if(const rpt_expr::pointer &e1,
257     const rpt_expr::pointer &e2, const rpt_expr::pointer &e3)
258 {
259     trace(("%s\n", __PRETTY_FUNCTION__));
260     append(e1);
261     append(e2);
262     append(e3);
263 }
264 
265 
266 rpt_expr::pointer
create(const rpt_expr::pointer & e1,const rpt_expr::pointer & e2,const rpt_expr::pointer & e3)267 rpt_expr_if::create(const rpt_expr::pointer &e1, const rpt_expr::pointer &e2,
268     const rpt_expr::pointer &e3)
269 {
270     trace(("%s\n", __PRETTY_FUNCTION__));
271     return pointer(new rpt_expr_if(e1, e2, e3));
272 }
273 
274 
275 rpt_value::pointer
evaluate() const276 rpt_expr_if::evaluate()
277     const
278 {
279     //
280     // evaluate the argument
281     //
282     trace(("rpt_expr_if::evaluate()\n{\n"));
283     assert(get_nchildren() == 3);
284     rpt_value::pointer v1 = nth_child(0)->evaluate(true, true);
285     if (v1->is_an_error())
286     {
287         trace(("}\n"));
288         return v1;
289     }
290 
291     //
292     // coerce the argument to boolean type
293     // (will not give error if can't, will copy instead)
294     //
295     rpt_value::pointer v1b = rpt_value::booleanize(v1);
296     trace(("v1b->name() = \"%s\"\n", v1b->name()));
297     rpt_value_boolean *v1p = dynamic_cast<rpt_value_boolean *>(v1b.get());
298     if (!v1p)
299     {
300         trace(("mark\n"));
301         sub_context_ty sc;
302         sc.var_set_charstar("Name", v1b->name());
303         nstring s
304         (
305             sc.subst_intl
306             (
307                 i18n("boolean value required for arithmetic if (was "
308                     "given $name)")
309             )
310         );
311         rpt_value::pointer result =
312             rpt_value_error::create(nth_child(0)->get_pos(), s);
313         trace(("}\n"));
314         return result;
315     }
316 
317     trace(("mark\n"));
318     bool cond = v1p->query();
319     rpt_value::pointer result = nth_child(cond ? 1 : 2)->evaluate(true, true);
320 
321     trace(("return %p;\n", result.get()));
322     trace(("}\n"));
323     return result;
324 }
325 
326 
327 // vim: set ts=8 sw=4 et :
328