Loading...
Searching...
No Matches
op.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-2023, John Wiegley. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of New Artisans LLC nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
42#pragma once
43
44#include "expr.h"
45
46namespace ledger {
47
48using namespace boost::placeholders;
49
50class expr_t::op_t : public noncopyable
51{
52 friend class expr_t;
53 friend class expr_t::parser_t;
54
55public:
57
58private:
59 mutable short refc;
60 ptr_op_t left_;
61
62 variant<boost::blank,
63 ptr_op_t, // used by all binary operators
64 value_t, // used by constant VALUE
65 string, // used by constant IDENT
66 expr_t::func_t, // used by terminal FUNCTION
67 shared_ptr<scope_t> // used by terminal SCOPE
68 > data;
69
70public:
124
126
127 explicit op_t() : refc(0), kind(UNKNOWN) {
128 TRACE_CTOR(op_t, "");
129 }
130 explicit op_t(const kind_t _kind) : refc(0), kind(_kind) {
131 TRACE_CTOR(op_t, "const kind_t");
132 }
135 assert(refc == 0);
136 }
137
138 bool is_value() const {
139 if (kind == VALUE) {
140 assert(data.type() == typeid(value_t));
141 return true;
142 }
143 return false;
144 }
146 assert(is_value());
147 value_t& val(boost::get<value_t>(data));
148 VERIFY(val.valid());
149 return val;
150 }
151 const value_t& as_value() const {
152 return const_cast<op_t *>(this)->as_value_lval();
153 }
154 void set_value(const value_t& val) {
155 VERIFY(val.valid());
156 data = val;
157 }
158
159 bool is_ident() const {
160 if (kind == IDENT) {
161 assert(data.type() == typeid(string));
162 return true;
163 }
164 return false;
165 }
166 string& as_ident_lval() {
167 assert(is_ident());
168 return boost::get<string>(data);
169 }
170 const string& as_ident() const {
171 return const_cast<op_t *>(this)->as_ident_lval();
172 }
173 void set_ident(const string& val) {
174 data = val;
175 }
176
177 bool is_function() const {
178 return kind == FUNCTION;
179 }
182 return boost::get<expr_t::func_t>(data);
183 }
185 return const_cast<op_t *>(this)->as_function_lval();
186 }
188 data = val;
189 }
190
191 bool is_scope() const {
192 return kind == SCOPE;
193 }
194 bool is_scope_unset() const {
195 return data.which() == 0;
196 }
198 assert(is_scope());
199 return boost::get<shared_ptr<scope_t> >(data);
200 }
202 return const_cast<op_t *>(this)->as_scope_lval();
203 }
205 data = val;
206 }
207
208 // These three functions must use 'kind == IDENT' rather than
209 // 'is_ident()', because they are called before the `data' member gets
210 // set, which is_ident() tests.
212 assert(kind > TERMINALS || kind == IDENT || is_scope());
213 return left_;
214 }
215 const ptr_op_t& left() const {
216 assert(kind > TERMINALS || kind == IDENT || is_scope());
217 return left_;
218 }
219 void set_left(const ptr_op_t& expr) {
220 assert(kind > TERMINALS || kind == IDENT || is_scope());
221 left_ = expr;
222 }
223
226 return boost::get<ptr_op_t>(data);
227 }
228 const ptr_op_t& as_op() const {
229 return const_cast<op_t *>(this)->as_op_lval();
230 }
231
234 return as_op_lval();
235 }
236 const ptr_op_t& right() const {
238 return as_op();
239 }
240 void set_right(const ptr_op_t& expr) {
242 data = expr;
243 }
244 bool has_right() const {
245 if (kind < TERMINALS)
246 return false;
247 return data.which() != 0 && as_op();
248 }
249
250private:
251 void acquire() const {
252 DEBUG("op.memory",
253 "Acquiring " << this << ", refc now " << refc + 1);
254 assert(refc >= 0);
255 refc++;
256 }
257 void release() const {
258 DEBUG("op.memory",
259 "Releasing " << this << ", refc now " << refc - 1);
260 assert(refc > 0);
261 if (--refc == 0)
262 checked_delete(this);
263 }
264
265 friend void intrusive_ptr_add_ref(const op_t * op);
266 friend void intrusive_ptr_release(const op_t * op);
267
268 ptr_op_t copy(ptr_op_t _left = NULL, ptr_op_t _right = NULL) const {
270 if (kind < TERMINALS)
271 node->data = data;
272 return node;
273 }
274
275public:
278
279 ptr_op_t compile(scope_t& scope, const int depth = 0,
281 value_t calc(scope_t& scope, ptr_op_t * locus = NULL,
282 const int depth = 0);
283
284 value_t call(const value_t& args, scope_t& scope,
285 ptr_op_t * locus = NULL, const int depth = 0);
286
288 {
291 std::ostream::pos_type * start_pos;
292 std::ostream::pos_type * end_pos;
294
296
298 const ptr_op_t& _op_to_find,
299 std::ostream::pos_type * const _start_pos = NULL,
300 std::ostream::pos_type * const _end_pos = NULL,
301 const bool _relaxed = true)
304 relaxed(_relaxed) {}
305 };
306
307 bool print(std::ostream& out, const context_t& context = context_t()) const;
308 void dump(std::ostream& out, const int depth = 0) const;
309
310 static ptr_op_t wrap_value(const value_t& val);
313
314private:
315 value_t calc_call(scope_t& scope, ptr_op_t * locus, const int depth);
316 value_t calc_cons(scope_t& scope, ptr_op_t * locus, const int depth);
317 value_t calc_seq(scope_t& scope, ptr_op_t * locus, const int depth);
318};
319
320inline expr_t::ptr_op_t
322{
323 ptr_op_t node(new op_t(_kind));
324 if (_left) node->set_left(_left);
325 if (_right) node->set_right(_right);
326 return node;
327}
328
331 temp->set_value(val);
332 return temp;
333}
334
335inline expr_t::ptr_op_t
338 temp->set_function(fobj);
339 return temp;
340}
341
342#define MAKE_FUNCTOR(x) expr_t::op_t::wrap_functor(bind(&x, this, _1))
343#define WRAP_FUNCTOR(x) expr_t::op_t::wrap_functor(x)
344
346 const expr_t::ptr_op_t locus = NULL);
347
349
350} // namespace ledger
#define VERIFY(x)
Definition utils.h:141
#define TRACE_DTOR(cls)
Definition utils.h:144
#define TRACE_CTOR(cls, args)
Definition utils.h:143
#define DEBUG(cat, msg)
Definition utils.h:327
#define assert(x)
Definition utils.h:92
value_t split_cons_expr(expr_t::ptr_op_t op)
string op_context(const expr_t::ptr_op_t op, const expr_t::ptr_op_t locus=NULL)
std::string string
Definition utils.h:59
T & downcast(U &object)
Definition utils.h:468
intrusive_ptr< op_t > ptr_op_t
Definition expr.h:57
function< result_type(call_scope_t &) func_t)
Definition exprbase.h:75
static ptr_op_t wrap_scope(shared_ptr< scope_t > sobj)
bool is_scope() const
Definition op.h:191
op_t(const kind_t _kind)
Definition op.h:130
static ptr_op_t new_node(kind_t _kind, ptr_op_t _left=NULL, ptr_op_t _right=NULL)
Definition op.h:321
string & as_ident_lval()
Definition op.h:166
const expr_t::func_t & as_function() const
Definition op.h:184
static ptr_op_t wrap_functor(expr_t::func_t fobj)
Definition op.h:336
expr_t::func_t & as_function_lval()
Definition op.h:180
void set_right(const ptr_op_t &expr)
Definition op.h:240
bool is_value() const
Definition op.h:138
bool is_function() const
Definition op.h:177
static ptr_op_t wrap_value(const value_t &val)
Definition op.h:329
ptr_op_t & as_op_lval()
Definition op.h:224
void set_value(const value_t &val)
Definition op.h:154
void set_left(const ptr_op_t &expr)
Definition op.h:219
friend void intrusive_ptr_add_ref(const op_t *op)
void set_ident(const string &val)
Definition op.h:173
shared_ptr< scope_t > as_scope_lval()
Definition op.h:197
value_t call(const value_t &args, scope_t &scope, ptr_op_t *locus=NULL, const int depth=0)
const ptr_op_t & right() const
Definition op.h:236
void set_function(const expr_t::func_t &val)
Definition op.h:187
const ptr_op_t & left() const
Definition op.h:215
friend void intrusive_ptr_release(const op_t *op)
bool is_ident() const
Definition op.h:159
bool print(std::ostream &out, const context_t &context=context_t()) const
ptr_op_t compile(scope_t &scope, const int depth=0, scope_t *param_scope=NULL)
ptr_op_t & left()
Definition op.h:211
const shared_ptr< scope_t > as_scope() const
Definition op.h:201
void set_scope(shared_ptr< scope_t > val)
Definition op.h:204
bool has_right() const
Definition op.h:244
expr_t::ptr_op_t ptr_op_t
Definition op.h:56
const ptr_op_t & as_op() const
Definition op.h:228
value_t calc(scope_t &scope, ptr_op_t *locus=NULL, const int depth=0)
const value_t & as_value() const
Definition op.h:151
bool is_scope_unset() const
Definition op.h:194
const string & as_ident() const
Definition op.h:170
void dump(std::ostream &out, const int depth=0) const
value_t & as_value_lval()
Definition op.h:145
ptr_op_t & right()
Definition op.h:232
std::ostream::pos_type * end_pos
Definition op.h:292
std::ostream::pos_type * start_pos
Definition op.h:291
context_t(const ptr_op_t &_expr_op, const ptr_op_t &_op_to_find, std::ostream::pos_type *const _start_pos=NULL, std::ostream::pos_type *const _end_pos=NULL, const bool _relaxed=true)
Definition op.h:297
Dynamic type representing various numeric types.
Definition value.h:83