Loading...
Searching...
No Matches
scope.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-2025, 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
35
42#pragma once
43
44#include "op.h"
45
46namespace ledger {
47
49{
59
61 string name;
63
64 symbol_t() : kind(UNKNOWN), name(""), definition(NULL) {
66 }
67 symbol_t(kind_t _kind, string _name, expr_t::ptr_op_t _definition = NULL)
68 : kind(_kind), name(_name), definition(_definition) {
69 TRACE_CTOR(symbol_t, "symbol_t::kind_t, string");
70 }
71 symbol_t(const symbol_t& sym)
72 : kind(sym.kind), name(sym.name), definition(sym.definition) {
73 TRACE_CTOR(symbol_t, "copy");
74 }
75 ~symbol_t() throw() {
77 }
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:
123 ~empty_scope_t() throw() {
125 }
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 }
143 explicit child_scope_t(scope_t& _parent) : parent(&_parent) {
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
164class bind_scope_t : public child_scope_t
165{
166 bind_scope_t();
167
168public:
170
171 explicit bind_scope_t(scope_t& _parent,
172 scope_t& _grandchild)
173 : child_scope_t(_parent), grandchild(_grandchild) {
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() {
179 TRACE_DTOR(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,
187 expr_t::ptr_op_t def) {
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>
201T * search_scope(scope_t * ptr, bool prefer_direct_parents = false)
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)) {
209 if (T * sought = search_scope<T>(prefer_direct_parents ?
210 scope->parent : &scope->grandchild))
211 return sought;
212 return search_scope<T>(prefer_direct_parents ?
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,
226 prefer_direct_parents))
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{
236 if (T * sought = search_scope<T>(&scope, prefer_direct_parents))
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 }
253 explicit symbol_scope_t(scope_t& _parent) : child_scope_t(_parent) {
254 TRACE_CTOR(symbol_scope_t, "scope_t&");
255 }
259
260 virtual string description() {
261 if (parent)
262 return parent->description();
263 else
264 assert(false);
265 return empty_string;
266 }
267
268 virtual void define(const symbol_t::kind_t kind, const string& name,
269 expr_t::ptr_op_t def);
270
272 const string& name);
273};
274
276{
277 value_t::type_t value_type_context;
278 bool required;
279
280public:
281 explicit context_scope_t(scope_t& _parent,
282 value_t::type_t _type_context = value_t::VOID,
283 const bool _required = true)
284 : child_scope_t(_parent), value_type_context(_type_context),
285 required(_required) {
286 TRACE_CTOR(context_scope_t, "scope_t&, value_t::type_t, bool");
287 }
291
292 virtual string description() {
293 return parent->description();
294 }
295
297 return value_type_context;
298 }
299 virtual bool type_required() const {
300 return required;
301 }
302};
303
305{
306public:
308 mutable void * ptr;
309
310 value_t& resolve(const std::size_t index,
312 const bool required = false);
313
314public:
316 const int depth;
317
318 explicit call_scope_t(scope_t& _parent,
319 expr_t::ptr_op_t * _locus = NULL,
320 const int _depth = 0)
321 : context_scope_t(_parent, _parent.type_context(),
322 _parent.type_required()),
323 ptr(NULL), locus(_locus), depth(_depth) {
324 TRACE_CTOR(call_scope_t, "scope_t&, expr_t::ptr_op_t *, const int");
325 }
326 virtual ~call_scope_t() {
328 }
329
330 void set_args(const value_t& _args) {
331 args = _args;
332 }
334 // Make sure that all of the arguments have been resolved.
335 for (std::size_t index = 0; index < args.size(); index++)
336 resolve(index);
337 return args;
338 }
339
340 value_t& operator[](const std::size_t index) {
341 return resolve(index);
342 }
343#if 0
344 const value_t& operator[](const std::size_t index) const {
345 return args[index];
346 }
347#endif
348
349 bool has(std::size_t index) {
350 return index < args.size() && ! (*this)[index].is_null();
351 }
352 template <typename T>
353 bool has(std::size_t index);
354 template <typename T>
355 T get(std::size_t index, bool convert = true);
356
357 template <typename T>
358 T& context() {
359 if (ptr == NULL)
360 ptr = &find_scope<T>(*this);
361 assert(ptr != NULL);
362 return *static_cast<T *>(ptr);
363 }
364
365 void push_front(const value_t& val) {
366 args.push_front(val);
367 }
368 void push_back(const value_t& val) {
369 args.push_back(val);
370 }
371 void pop_back() {
372 args.pop_back();
373 }
374
375 typedef value_t::sequence_t::iterator iterator;
376
377 value_t::sequence_t::iterator begin() {
378 return args.begin();
379 }
380 value_t::sequence_t::iterator end() {
381 return args.end();
382 }
383
384 typedef value_t::sequence_t::const_iterator const_iterator;
385
386 value_t::sequence_t::const_iterator begin() const {
387 return args.begin();
388 }
389 value_t::sequence_t::const_iterator end() const {
390 return args.end();
391 }
392
393 std::size_t size() const {
394 return args.size();
395 }
396 bool empty() const {
397 return args.size() == 0;
398 }
399};
400
401template <>
402inline bool call_scope_t::has<bool>(std::size_t index) {
403 if (index < args.size()) {
404 resolve(index, value_t::BOOLEAN, false);
405 return ! args[index].is_null();
406 }
407 return false;
408}
409template <>
410inline bool call_scope_t::has<int>(std::size_t index) {
411 if (index < args.size()) {
412 resolve(index, value_t::INTEGER, false);
413 return ! args[index].is_null();
414 }
415 return false;
416}
417template <>
418inline bool call_scope_t::has<long>(std::size_t index) {
419 if (index < args.size()) {
420 resolve(index, value_t::INTEGER, false);
421 return ! args[index].is_null();
422 }
423 return false;
424}
425template <>
426inline bool call_scope_t::has<amount_t>(std::size_t index) {
427 if (index < args.size()) {
428 resolve(index, value_t::AMOUNT, false);
429 return ! args[index].is_null();
430 }
431 return false;
432}
433template <>
434inline bool call_scope_t::has<balance_t>(std::size_t index) {
435 if (index < args.size()) {
436 resolve(index, value_t::BALANCE, false);
437 return ! args[index].is_null();
438 }
439 return false;
440}
441template <>
442inline bool call_scope_t::has<string>(std::size_t index) {
443 if (index < args.size()) {
444 resolve(index, value_t::STRING, false);
445 return ! args[index].is_null();
446 }
447 return false;
448}
449template <>
450inline bool call_scope_t::has<date_t>(std::size_t index) {
451 if (index < args.size()) {
452 resolve(index, value_t::DATE, false);
453 return ! args[index].is_null();
454 }
455 return false;
456}
457template <>
458inline bool call_scope_t::has<datetime_t>(std::size_t index) {
459 if (index < args.size()) {
460 resolve(index, value_t::DATETIME, false);
461 return ! args[index].is_null();
462 }
463 return false;
464}
465template <>
466inline bool call_scope_t::has<scope_t *>(std::size_t index) {
467 if (index < args.size()) {
468 resolve(index, value_t::SCOPE, false);
469 return ! args[index].is_null();
470 }
471 return false;
472}
473template <>
474inline bool call_scope_t::has<expr_t::ptr_op_t>(std::size_t index) {
475 if (index < args.size()) {
476 resolve(index, value_t::ANY, false);
477 return ! args[index].is_null();
478 }
479 return false;
480}
481
482template <>
483inline bool call_scope_t::get<bool>(std::size_t index, bool convert) {
484 if (convert)
485 return resolve(index, value_t::BOOLEAN, false).to_boolean();
486 else
487 return resolve(index, value_t::BOOLEAN).as_boolean();
488}
489template <>
490inline int call_scope_t::get<int>(std::size_t index, bool) {
491 return resolve(index, value_t::INTEGER, false).to_int();
492}
493template <>
494inline long call_scope_t::get<long>(std::size_t index, bool convert) {
495 if (convert)
496 return resolve(index, value_t::INTEGER, false).to_long();
497 else
498 return resolve(index, value_t::INTEGER).as_long();
499}
500template <>
501inline amount_t call_scope_t::get<amount_t>(std::size_t index, bool convert) {
502 if (convert)
503 return resolve(index, value_t::AMOUNT, false).to_amount();
504 else
505 return resolve(index, value_t::AMOUNT).as_amount();
506}
507template <>
508inline balance_t call_scope_t::get<balance_t>(std::size_t index, bool convert) {
509 if (convert)
510 return resolve(index, value_t::BALANCE, false).to_balance();
511 else
512 return resolve(index, value_t::BALANCE).as_balance();
513}
514template <>
515inline string call_scope_t::get<string>(std::size_t index, bool convert) {
516 if (convert)
517 return resolve(index, value_t::STRING, false).to_string();
518 else
519 return resolve(index, value_t::STRING).as_string();
520}
521template <>
522inline mask_t call_scope_t::get<mask_t>(std::size_t index, bool convert) {
523 if (convert)
524 return resolve(index, value_t::MASK, false).to_mask();
525 else
526 return resolve(index, value_t::MASK).as_mask();
527}
528template <>
529inline date_t call_scope_t::get<date_t>(std::size_t index, bool convert) {
530 if (convert)
531 return resolve(index, value_t::DATE, false).to_date();
532 else
533 return resolve(index, value_t::DATE).as_date();
534}
535template <>
536inline datetime_t call_scope_t::get<datetime_t>(std::size_t index, bool convert) {
537 if (convert)
538 return resolve(index, value_t::DATETIME, false).to_datetime();
539 else
540 return resolve(index, value_t::DATETIME).as_datetime();
541}
542
543#if 0
544template <>
546call_scope_t::get<value_t::sequence_t&>(std::size_t index, bool) {
547 return resolve(index, value_t::SEQUENCE).as_sequence_lval();
548}
549template <>
550inline const value_t::sequence_t&
551call_scope_t::get<const value_t::sequence_t&>(std::size_t index, bool) {
552 return resolve(index, value_t::SEQUENCE).as_sequence();
553}
554#endif
555
556template <>
557inline scope_t * call_scope_t::get<scope_t *>(std::size_t index, bool) {
558 return resolve(index, value_t::SCOPE).as_scope();
559}
560template <>
562call_scope_t::get<expr_t::ptr_op_t>(std::size_t index, bool) {
563 return args[index].as_any<expr_t::ptr_op_t>();
564}
565
566inline string join_args(call_scope_t& args) {
567 std::ostringstream buf;
568 bool first = true;
569
570 for (std::size_t i = 0; i < args.size(); i++) {
571 if (first)
572 first = false;
573 else
574 buf << ' ';
575 buf << args[i];
576 }
577
578 return buf.str();
579}
580
582{
583 value_t value;
584
585 value_t get_value(call_scope_t&) {
586 return value;
587 }
588
589public:
590 value_scope_t(scope_t& _parent, const value_t& _value)
591 : child_scope_t(_parent), value(_value) {
592 TRACE_CTOR(value_scope_t, "scope_t&, value_t");
593 }
594 ~value_scope_t() throw() {
596 }
597
598 virtual string description() {
599 return parent->description();
600 }
601
603 const string& name)
604 {
605 if (kind != symbol_t::FUNCTION)
606 return NULL;
607
608 if (name == "value")
609 return MAKE_FUNCTOR(value_scope_t::get_value);
610
611 return child_scope_t::lookup(kind, name);
612 }
613};
614
615} // namespace ledger
#define throw_(cls, msg)
Definition error.h:55
#define MAKE_FUNCTOR(x)
Definition op.h:342
#define TRACE_DTOR(cls)
Definition utils.h:144
#define TRACE_CTOR(cls, args)
Definition utils.h:143
#define DEBUG(cat, msg)
Definition utils.h:287
#define assert(x)
Definition utils.h:92
boost::gregorian::date date_t
Definition times.h:60
string empty_string
string join_args(call_scope_t &args)
Definition scope.h:566
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
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:292
context_scope_t(scope_t &_parent, value_t::type_t _type_context=value_t::VOID, const bool _required=true)
Definition scope.h:281
virtual ~context_scope_t()
Definition scope.h:288
virtual value_t::type_t type_context() const
Definition scope.h:296
virtual bool type_required() const
Definition scope.h:299
value_t & value()
Definition scope.h:333
T get(std::size_t index, bool convert=true)
value_t::sequence_t::iterator iterator
Definition scope.h:375
value_t::sequence_t::const_iterator const_iterator
Definition scope.h:384
void push_back(const value_t &val)
Definition scope.h:368
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:389
value_t & operator[](const std::size_t index)
Definition scope.h:340
bool empty() const
Definition scope.h:396
value_t::sequence_t::const_iterator begin() const
Definition scope.h:386
expr_t::ptr_op_t * locus
Definition scope.h:315
bool has(std::size_t index)
const int depth
Definition scope.h:316
bool has(std::size_t index)
Definition scope.h:349
void set_args(const value_t &_args)
Definition scope.h:330
value_t::sequence_t::iterator begin()
Definition scope.h:377
call_scope_t(scope_t &_parent, expr_t::ptr_op_t *_locus=NULL, const int _depth=0)
Definition scope.h:318
value_t::sequence_t::iterator end()
Definition scope.h:380
void push_front(const value_t &val)
Definition scope.h:365
std::size_t size() const
Definition scope.h:393
virtual ~call_scope_t()
Definition scope.h:326
virtual string description()
Definition scope.h:598
value_scope_t(scope_t &_parent, const value_t &_value)
Definition scope.h:590
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string &name)
Definition scope.h:602
Dynamic type representing various numeric types.
Definition value.h:86
const datetime_t & as_datetime() const
Definition value.h:583
const date_t & as_date() const
Definition value.h:600
mask_t to_mask() const
scope_t * as_scope() const
Definition value.h:740
const long & as_long() const
Definition value.h:617
const balance_t & as_balance() const
Definition value.h:652
const mask_t & as_mask() const
Definition value.h:703
int to_int() const
const string & as_string() const
Definition value.h:679
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:102
datetime_t to_datetime() const
const amount_t & as_amount() const
Definition value.h:634
balance_t to_balance() const
amount_t to_amount() const
const bool & as_boolean() const
Definition value.h:566
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:92
bool to_boolean() const
Data conversion methods.