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