Loading...
Searching...
No Matches
scope.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 "op.h"
45
46namespace ledger {
47
49{
59
61 string name;
63
69 TRACE_CTOR(symbol_t, "symbol_t::kind_t, string");
70 }
78
79 bool operator<(const symbol_t& sym) const {
80 return kind < sym.kind || name < sym.name;
81 }
82 bool operator==(const symbol_t& sym) const {
83 return kind == sym.kind || name == sym.name;
84 }
85};
86
87class empty_scope_t;
88
90{
91public:
94
95 explicit scope_t() {
97 }
98 virtual ~scope_t() {
100 }
101
102 virtual string description() = 0;
103
104 virtual void define(const symbol_t::kind_t, const string&,
107 const string& name) = 0;
108
110 return value_t::VOID;
111 }
112 virtual bool type_required() const {
113 return false;
114 }
115};
116
117class empty_scope_t : public scope_t
118{
119public:
126
127 virtual string description() {
128 return _("<empty>");
129 }
130 virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t, const string&) {
131 return NULL;
132 }
133};
134
135class child_scope_t : public noncopyable, public scope_t
136{
137public:
139
140 explicit child_scope_t() : parent(NULL) {
142 }
144 TRACE_CTOR(child_scope_t, "scope_t&");
145 }
146 virtual ~child_scope_t() {
148 }
149
150 virtual void define(const symbol_t::kind_t kind,
151 const string& name, expr_t::ptr_op_t def) {
152 if (parent)
153 parent->define(kind, name, def);
154 }
155
157 const string& name) {
158 if (parent)
159 return parent->lookup(kind, name);
160 return NULL;
161 }
162};
163
165{
166 bind_scope_t();
167
168public:
170
174 DEBUG("scope.symbols",
175 "Binding scope " << &_parent << " with " << &_grandchild);
176 TRACE_CTOR(bind_scope_t, "scope_t&, scope_t&");
177 }
178 virtual ~bind_scope_t() {
180 }
181
182 virtual string description() {
183 return grandchild.description();
184 }
185
186 virtual void define(const symbol_t::kind_t kind, const string& name,
188 parent->define(kind, name, def);
189 grandchild.define(kind, name, def);
190 }
191
193 const string& name) {
194 if (expr_t::ptr_op_t def = grandchild.lookup(kind, name))
195 return def;
196 return child_scope_t::lookup(kind, name);
197 }
198};
199
200template <typename T>
202{
203 DEBUG("scope.search", "Searching scope " << ptr->description());
204
205 if (T * sought = dynamic_cast<T *>(ptr))
206 return sought;
207
208 if (bind_scope_t * scope = dynamic_cast<bind_scope_t *>(ptr)) {
210 scope->parent : &scope->grandchild))
211 return sought;
213 &scope->grandchild : scope->parent);
214 }
215 else if (child_scope_t * child_scope = dynamic_cast<child_scope_t *>(ptr)) {
216 return search_scope<T>(child_scope->parent);
217 }
218 return NULL;
219}
220
221template <typename T>
222inline T& find_scope(child_scope_t& scope, bool skip_this = true,
223 bool prefer_direct_parents = false)
224{
225 if (T * sought = search_scope<T>(skip_this ? scope.parent : &scope,
227 return *sought;
228
229 throw_(std::runtime_error, _("Could not find scope"));
230 return reinterpret_cast<T&>(scope); // never executed
231}
232
233template <typename T>
234inline T& find_scope(scope_t& scope, bool prefer_direct_parents = false)
235{
237 return *sought;
238
239 throw_(std::runtime_error, _("Could not find scope"));
240 return reinterpret_cast<T&>(scope); // never executed
241}
242
244{
245 typedef std::map<symbol_t, expr_t::ptr_op_t> symbol_map;
246
247 optional<symbol_map> symbols;
248
249public:
252 }
259
260 virtual string description() {
261 if (parent)
262 return parent->description();
263#if !NO_ASSERTS
264 else
265 assert(false);
266#endif
267 return empty_string;
268 }
269
270 virtual void define(const symbol_t::kind_t kind, const string& name,
272
274 const string& name);
275};
276
278{
279 value_t::type_t value_type_context;
280 bool required;
281
282public:
285 const bool _required = true)
286 : child_scope_t(_parent), value_type_context(_type_context),
287 required(_required) {
288 TRACE_CTOR(context_scope_t, "scope_t&, value_t::type_t, bool");
289 }
293
294 virtual string description() {
295 return parent->description();
296 }
297
299 return value_type_context;
300 }
301 virtual bool type_required() const {
302 return required;
303 }
304};
305
307{
308public:
310 mutable void * ptr;
311
312 value_t& resolve(const std::size_t index,
314 const bool required = false);
315
316public:
318 const int depth;
319
322 const int _depth = 0)
326 TRACE_CTOR(call_scope_t, "scope_t&, expr_t::ptr_op_t *, const int");
327 }
328 virtual ~call_scope_t() {
330 }
331
332 void set_args(const value_t& _args) {
333 args = _args;
334 }
336 // Make sure that all of the arguments have been resolved.
337 for (std::size_t index = 0; index < args.size(); index++)
338 resolve(index);
339 return args;
340 }
341
342 value_t& operator[](const std::size_t index) {
343 return resolve(index);
344 }
345#if 0
346 const value_t& operator[](const std::size_t index) const {
347 return args[index];
348 }
349#endif
350
351 bool has(std::size_t index) {
352 return index < args.size() && ! (*this)[index].is_null();
353 }
354 template <typename T>
355 bool has(std::size_t index);
356 template <typename T>
357 T get(std::size_t index, bool convert = true);
358
359 template <typename T>
360 T& context() {
361 if (ptr == NULL)
362 ptr = &find_scope<T>(*this);
363 assert(ptr != NULL);
364 return *static_cast<T *>(ptr);
365 }
366
367 void push_front(const value_t& val) {
369 }
370 void push_back(const value_t& val) {
372 }
373 void pop_back() {
374 args.pop_back();
375 }
376
377 typedef value_t::sequence_t::iterator iterator;
378
379 value_t::sequence_t::iterator begin() {
380 return args.begin();
381 }
382 value_t::sequence_t::iterator end() {
383 return args.end();
384 }
385
386 typedef value_t::sequence_t::const_iterator const_iterator;
387
388 value_t::sequence_t::const_iterator begin() const {
389 return args.begin();
390 }
391 value_t::sequence_t::const_iterator end() const {
392 return args.end();
393 }
394
395 std::size_t size() const {
396 return args.size();
397 }
398 bool empty() const {
399 return args.size() == 0;
400 }
401};
402
403template <>
404inline bool call_scope_t::has<bool>(std::size_t index) {
405 if (index < args.size()) {
406 resolve(index, value_t::BOOLEAN, false);
407 return ! args[index].is_null();
408 }
409 return false;
410}
411template <>
412inline bool call_scope_t::has<int>(std::size_t index) {
413 if (index < args.size()) {
414 resolve(index, value_t::INTEGER, false);
415 return ! args[index].is_null();
416 }
417 return false;
418}
419template <>
420inline bool call_scope_t::has<long>(std::size_t index) {
421 if (index < args.size()) {
422 resolve(index, value_t::INTEGER, false);
423 return ! args[index].is_null();
424 }
425 return false;
426}
427template <>
428inline bool call_scope_t::has<amount_t>(std::size_t index) {
429 if (index < args.size()) {
430 resolve(index, value_t::AMOUNT, false);
431 return ! args[index].is_null();
432 }
433 return false;
434}
435template <>
436inline bool call_scope_t::has<balance_t>(std::size_t index) {
437 if (index < args.size()) {
438 resolve(index, value_t::BALANCE, false);
439 return ! args[index].is_null();
440 }
441 return false;
442}
443template <>
444inline bool call_scope_t::has<string>(std::size_t index) {
445 if (index < args.size()) {
446 resolve(index, value_t::STRING, false);
447 return ! args[index].is_null();
448 }
449 return false;
450}
451template <>
452inline bool call_scope_t::has<date_t>(std::size_t index) {
453 if (index < args.size()) {
454 resolve(index, value_t::DATE, false);
455 return ! args[index].is_null();
456 }
457 return false;
458}
459template <>
460inline bool call_scope_t::has<datetime_t>(std::size_t index) {
461 if (index < args.size()) {
462 resolve(index, value_t::DATETIME, false);
463 return ! args[index].is_null();
464 }
465 return false;
466}
467template <>
468inline bool call_scope_t::has<scope_t *>(std::size_t index) {
469 if (index < args.size()) {
470 resolve(index, value_t::SCOPE, false);
471 return ! args[index].is_null();
472 }
473 return false;
474}
475template <>
476inline bool call_scope_t::has<expr_t::ptr_op_t>(std::size_t index) {
477 if (index < args.size()) {
478 resolve(index, value_t::ANY, false);
479 return ! args[index].is_null();
480 }
481 return false;
482}
483
484template <>
485inline bool call_scope_t::get<bool>(std::size_t index, bool convert) {
486 if (convert)
487 return resolve(index, value_t::BOOLEAN, false).to_boolean();
488 else
489 return resolve(index, value_t::BOOLEAN).as_boolean();
490}
491template <>
492inline int call_scope_t::get<int>(std::size_t index, bool) {
493 return resolve(index, value_t::INTEGER, false).to_int();
494}
495template <>
496inline long call_scope_t::get<long>(std::size_t index, bool convert) {
497 if (convert)
498 return resolve(index, value_t::INTEGER, false).to_long();
499 else
500 return resolve(index, value_t::INTEGER).as_long();
501}
502template <>
503inline amount_t call_scope_t::get<amount_t>(std::size_t index, bool convert) {
504 if (convert)
505 return resolve(index, value_t::AMOUNT, false).to_amount();
506 else
507 return resolve(index, value_t::AMOUNT).as_amount();
508}
509template <>
510inline balance_t call_scope_t::get<balance_t>(std::size_t index, bool convert) {
511 if (convert)
512 return resolve(index, value_t::BALANCE, false).to_balance();
513 else
514 return resolve(index, value_t::BALANCE).as_balance();
515}
516template <>
517inline string call_scope_t::get<string>(std::size_t index, bool convert) {
518 if (convert)
519 return resolve(index, value_t::STRING, false).to_string();
520 else
521 return resolve(index, value_t::STRING).as_string();
522}
523template <>
524inline mask_t call_scope_t::get<mask_t>(std::size_t index, bool convert) {
525 if (convert)
526 return resolve(index, value_t::MASK, false).to_mask();
527 else
528 return resolve(index, value_t::MASK).as_mask();
529}
530template <>
531inline date_t call_scope_t::get<date_t>(std::size_t index, bool convert) {
532 if (convert)
533 return resolve(index, value_t::DATE, false).to_date();
534 else
535 return resolve(index, value_t::DATE).as_date();
536}
537template <>
538inline datetime_t call_scope_t::get<datetime_t>(std::size_t index, bool convert) {
539 if (convert)
540 return resolve(index, value_t::DATETIME, false).to_datetime();
541 else
542 return resolve(index, value_t::DATETIME).as_datetime();
543}
544
545#if 0
546template <>
548call_scope_t::get<value_t::sequence_t&>(std::size_t index, bool) {
549 return resolve(index, value_t::SEQUENCE).as_sequence_lval();
550}
551template <>
552inline const value_t::sequence_t&
553call_scope_t::get<const value_t::sequence_t&>(std::size_t index, bool) {
554 return resolve(index, value_t::SEQUENCE).as_sequence();
555}
556#endif
557
558template <>
559inline scope_t * call_scope_t::get<scope_t *>(std::size_t index, bool) {
560 return resolve(index, value_t::SCOPE).as_scope();
561}
562template <>
564call_scope_t::get<expr_t::ptr_op_t>(std::size_t index, bool) {
565 return args[index].as_any<expr_t::ptr_op_t>();
566}
567
568inline string join_args(call_scope_t& args) {
569 std::ostringstream buf;
570 bool first = true;
571
572 for (std::size_t i = 0; i < args.size(); i++) {
573 if (first)
574 first = false;
575 else
576 buf << ' ';
577 buf << args[i];
578 }
579
580 return buf.str();
581}
582
584{
585 value_t value;
586
587 value_t get_value(call_scope_t&) {
588 return value;
589 }
590
591public:
593 : child_scope_t(_parent), value(_value) {
594 TRACE_CTOR(value_scope_t, "scope_t&, value_t");
595 }
599
600 virtual string description() {
601 return parent->description();
602 }
603
605 const string& name)
606 {
607 if (kind != symbol_t::FUNCTION)
608 return NULL;
609
610 if (name == "value")
611 return MAKE_FUNCTOR(value_scope_t::get_value);
612
613 return child_scope_t::lookup(kind, name);
614 }
615};
616
617} // namespace ledger
#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
#define throw_(cls, msg)
Definition error.h:55
#define MAKE_FUNCTOR(x)
Definition op.h:342
boost::gregorian::date date_t
Definition times.h:60
string empty_string
string join_args(call_scope_t &args)
Definition scope.h:568
T & find_scope(child_scope_t &scope, bool skip_this=true, bool prefer_direct_parents=false)
Definition scope.h:222
T * search_scope(scope_t *ptr, bool prefer_direct_parents=false)
Definition scope.h:201
T & downcast(U &object)
Definition utils.h:468
boost::posix_time::ptime datetime_t
Definition times.h:53
Encapsulate infinite-precision commoditized amounts.
Definition amount.h:96
A wrapper around amount_t allowing addition of multiple commodities.
Definition balance.h:80
intrusive_ptr< op_t > ptr_op_t
Definition expr.h:57
expr_t::ptr_op_t definition
Definition scope.h:62
bool operator==(const symbol_t &sym) const
Definition scope.h:82
symbol_t(kind_t _kind, string _name, expr_t::ptr_op_t _definition=NULL)
Definition scope.h:67
symbol_t(const symbol_t &sym)
Definition scope.h:71
string name
Definition scope.h:61
bool operator<(const symbol_t &sym) const
Definition scope.h:79
kind_t kind
Definition scope.h:60
static empty_scope_t * empty_scope
Definition scope.h:93
virtual string description()=0
virtual void define(const symbol_t::kind_t, const string &, expr_t::ptr_op_t)
Definition scope.h:104
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string &name)=0
virtual ~scope_t()
Definition scope.h:98
static scope_t * default_scope
Definition scope.h:92
virtual value_t::type_t type_context() const
Definition scope.h:109
virtual bool type_required() const
Definition scope.h:112
virtual string description()
Definition scope.h:127
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t, const string &)
Definition scope.h:130
child_scope_t(scope_t &_parent)
Definition scope.h:143
scope_t * parent
Definition scope.h:138
virtual ~child_scope_t()
Definition scope.h:146
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string &name)
Definition scope.h:156
virtual void define(const symbol_t::kind_t kind, const string &name, expr_t::ptr_op_t def)
Definition scope.h:150
virtual ~bind_scope_t()
Definition scope.h:178
virtual void define(const symbol_t::kind_t kind, const string &name, expr_t::ptr_op_t def)
Definition scope.h:186
virtual string description()
Definition scope.h:182
bind_scope_t(scope_t &_parent, scope_t &_grandchild)
Definition scope.h:171
scope_t & grandchild
Definition scope.h:169
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string &name)
Definition scope.h:192
virtual ~symbol_scope_t()
Definition scope.h:256
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string &name)
symbol_scope_t(scope_t &_parent)
Definition scope.h:253
virtual string description()
Definition scope.h:260
virtual void define(const symbol_t::kind_t kind, const string &name, expr_t::ptr_op_t def)
virtual string description()
Definition scope.h:294
context_scope_t(scope_t &_parent, value_t::type_t _type_context=value_t::VOID, const bool _required=true)
Definition scope.h:283
virtual ~context_scope_t()
Definition scope.h:290
virtual value_t::type_t type_context() const
Definition scope.h:298
virtual bool type_required() const
Definition scope.h:301
value_t & value()
Definition scope.h:335
T get(std::size_t index, bool convert=true)
value_t::sequence_t::iterator iterator
Definition scope.h:377
value_t::sequence_t::const_iterator const_iterator
Definition scope.h:386
void push_back(const value_t &val)
Definition scope.h:370
value_t & resolve(const std::size_t index, value_t::type_t context=value_t::VOID, const bool required=false)
value_t::sequence_t::const_iterator end() const
Definition scope.h:391
value_t & operator[](const std::size_t index)
Definition scope.h:342
bool empty() const
Definition scope.h:398
value_t::sequence_t::const_iterator begin() const
Definition scope.h:388
expr_t::ptr_op_t * locus
Definition scope.h:317
bool has(std::size_t index)
const int depth
Definition scope.h:318
bool has(std::size_t index)
Definition scope.h:351
void set_args(const value_t &_args)
Definition scope.h:332
value_t::sequence_t::iterator begin()
Definition scope.h:379
call_scope_t(scope_t &_parent, expr_t::ptr_op_t *_locus=NULL, const int _depth=0)
Definition scope.h:320
value_t::sequence_t::iterator end()
Definition scope.h:382
void push_front(const value_t &val)
Definition scope.h:367
std::size_t size() const
Definition scope.h:395
virtual ~call_scope_t()
Definition scope.h:328
virtual string description()
Definition scope.h:600
value_scope_t(scope_t &_parent, const value_t &_value)
Definition scope.h:592
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string &name)
Definition scope.h:604
Dynamic type representing various numeric types.
Definition value.h:83
const datetime_t & as_datetime() const
Definition value.h:574
const date_t & as_date() const
Definition value.h:591
void pop_back()
Definition value.h:876
bool is_null() const
Definition value.h:499
sequence_t::iterator end()
Definition value.h:899
mask_t to_mask() const
scope_t * as_scope() const
Definition value.h:722
const long & as_long() const
Definition value.h:608
const balance_t & as_balance() const
Definition value.h:643
const mask_t & as_mask() const
Definition value.h:685
int to_int() const
void push_back(const value_t &val)
Definition value.h:868
const string & as_string() const
Definition value.h:661
std::size_t size() const
Definition value.h:913
date_t to_date() const
long to_long() const
type_t
type_t gives the type of the data contained or referenced by a value_t object.
Definition value.h:99
datetime_t to_datetime() const
const amount_t & as_amount() const
Definition value.h:625
sequence_t::iterator begin()
Definition value.h:895
balance_t to_balance() const
amount_t to_amount() const
void push_front(const value_t &val)
Definition value.h:860
const bool & as_boolean() const
Definition value.h:557
string to_string() const
ptr_deque< value_t > sequence_t
The sequence_t member type abstracts the type used to represent a resizable "array" of value_t object...
Definition value.h:89
bool to_boolean() const
Data conversion methods.