diff options
Diffstat (limited to 'src/compile.h')
-rw-r--r-- | src/compile.h | 510 |
1 files changed, 510 insertions, 0 deletions
diff --git a/src/compile.h b/src/compile.h new file mode 100644 index 00000000..25e12183 --- /dev/null +++ b/src/compile.h @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2003-2007, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _NODE_H +#define _NODE_H + +#include "journal.h" +#include "value.h" +//#include "parser.h" + +namespace ledger { + +class transaction_t; +class entry_t; +class account_t; +class journal_t; + +namespace xml { + +#define XML_NODE_IS_PARENT 0x1 + +#define ACCOUNT_ATTR "account" +#define ACCOUNT_PATH_NODE "account-path" +#define AMOUNT_EXPR_NODE "amount-expr" +#define ARG_ATTR "arg" +#define AUTO_ENTRY_NODE "auto-entry" +#define BALANCE_ATTR "balance" +#define CHECKIN_NODE "checkin" +#define CLEARED_ATTR "cleared" +#define CODE_ATTR "code" +#define COMMODITY_CONVERSION_NODE "commodity-conversion" +#define COMMODITY_NOMARKET_NODE "commodity-nomarket" +#define COMMODITY_TEMPLATE_NODE "commodity-template" +#define CURRENT_YEAR_NODE "current-year" +#define DATE_ATTR "date" +#define DATE_EFF_ATTR "effective" +#define DEFAULT_ACCOUNT_NODE "default-account" +#define DIRECTIVE_NODE "directive" +#define ENTRY_NODE "entry" +#define FROM_ATTR "from" +#define JOURNAL_NODE "journal" +#define NAME_ATTR "name" +#define NOTE_NODE "note" +#define PAYEE_NODE "payee" +#define PENDING_ATTR "pending" +#define PERIOD_ENTRY_NODE "period-entry" +#define PERIOD_NODE "period" +#define PRICE_ATTR "price" +#define PRICE_HISTORY_NODE "price-history" +#define RULE_NODE "rule" +#define SYMBOL_ATTR "symbol" +#define TEMPLATE_ATTR "template" +#define TIME_ATTR "time" +#define TO_ATTR "to" +#define TRANSACTION_NODE "transaction" +#define VIRTUAL_ATTR "virtual" +#define YEAR_ATTR "year" + +DECLARE_EXCEPTION(conversion_error); + +class parent_node_t; +class document_t; + +class node_t : public supports_flags<> +{ +public: + typedef uint_fast16_t nameid_t; + + nameid_t name_id; +#ifdef THREADSAFE + document_t * document; +#else + static document_t * document; +#endif + parent_node_t * parent; + node_t * next; + node_t * prev; + + typedef std::map<string, string> attrs_map; + + attrs_map * attrs; + + node_t(document_t * _document, parent_node_t * _parent = NULL, + flags_t _flags = 0); + + virtual ~node_t() { + TRACE_DTOR(node_t); + if (parent) extract(); + if (attrs) checked_delete(attrs); + } + + parent_node_t * as_parent_node() { + if (! has_flags(XML_NODE_IS_PARENT)) + throw_(std::logic_error, "Request to cast leaf node to a parent node"); + return polymorphic_downcast<parent_node_t *>(this); + } + const parent_node_t * as_parent_node() const { + if (! has_flags(XML_NODE_IS_PARENT)) + throw_(std::logic_error, "Request to cast leaf node to a parent node"); + return polymorphic_downcast<const parent_node_t *>(this); + } + + void extract(); // extract this node from its parent's child list + + virtual const char * text() const { + assert(false); + return NULL; + } + + const char * name() const; + int set_name(const char * _name); + int set_name(int _name_id) { + name_id = _name_id; + return name_id; + } + + void set_attr(const char * n, const char * v) { + if (! attrs) + attrs = new attrs_map; + std::pair<attrs_map::iterator, bool> result = + attrs->insert(attrs_map::value_type(n, v)); + assert(result.second); + } + const char * get_attr(const char * n) { + if (attrs) { + attrs_map::iterator i = attrs->find(n); + if (i != attrs->end()) + return (*i).second.c_str(); + } + return NULL; + } + + node_t * lookup_child(const char * _name) const; + node_t * lookup_child(const string& _name) const; + virtual node_t * lookup_child(int /* _name_id */) const { + return NULL; + } + + virtual value_t to_value() const { + throw_(conversion_error, "Cannot convert node to a value"); + return value_t(); + } + + virtual void print(std::ostream& out, int depth = 0) const = 0; + +private: + node_t(const node_t&); + node_t& operator=(const node_t&); +}; + +class parent_node_t : public node_t +{ +public: + mutable node_t * _children; + mutable node_t * _last_child; + + parent_node_t(document_t * _document, parent_node_t * _parent = NULL) + : node_t(_document, _parent, XML_NODE_IS_PARENT), + _children(NULL), _last_child(NULL) + { + TRACE_CTOR(parent_node_t, "document_t *, parent_node_t *"); + } + virtual ~parent_node_t() { + TRACE_DTOR(parent_node_t); + if (_children) clear(); + } + + virtual void clear(); // clear out all child nodes + virtual node_t * children() const { + return _children; + } + virtual node_t * last_child() { + if (! _children) + children(); + return _last_child; + } + virtual void add_child(node_t * node); + + void print(std::ostream& out, int depth = 0) const; + +private: + parent_node_t(const parent_node_t&); + parent_node_t& operator=(const parent_node_t&); +}; + +class terminal_node_t : public node_t +{ + string data; + +public: + terminal_node_t(document_t * _document, parent_node_t * _parent = NULL) + : node_t(_document, _parent) + { + TRACE_CTOR(terminal_node_t, "document_t *, parent_node_t *"); + } + virtual ~terminal_node_t() { + TRACE_DTOR(terminal_node_t); + } + + virtual const char * text() const { + return data.c_str(); + } + virtual void set_text(const char * _data) { + data = _data; + } + virtual void set_text(const string& _data) { + data = _data; + } + + virtual value_t to_value() const { + return text(); + } + + void print(std::ostream& out, int depth = 0) const; + +private: + terminal_node_t(const node_t&); + terminal_node_t& operator=(const node_t&); +}; + +class document_t +{ + static const char * ledger_builtins[]; + static const std::size_t ledger_builtins_size; + +public: + enum ledger_builtins_t { + ACCOUNT = 10, + ACCOUNT_PATH, + AMOUNT, + CODE, + COMMODITY, + ENTRIES, + ENTRY, + JOURNAL, + NAME, + NOTE, + PAYEE, + TRANSACTION + }; + +private: + typedef std::vector<string> names_array; + + names_array names; + + typedef std::map<string, int> names_map; + + names_map names_index; + +public: + node_t * top; + +private: + terminal_node_t stub; + +public: + // Ids 0-9 are reserved. 10-999 are for "builtin" names. 1000+ are + // for dynamically registered names. + enum special_names_t { + CURRENT, PARENT, ROOT, ALL + }; + + document_t(node_t * _top = NULL) + : top(_top ? _top : &stub), stub(this) { + TRACE_CTOR(xml::document_t, "node_t *, const char **, const int"); + } + ~document_t(); + + void set_top(node_t * _top); + + int register_name(const string& name); + int lookup_name_id(const string& name) const; + static int lookup_builtin_id(const string& name); + const char * lookup_name(int id) const; + + void print(std::ostream& out) const; + +#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) + class parser_t + { + public: + document_t * document; + XML_Parser parser; + string have_error; + const char * pending; + node_t::attrs_map * pending_attrs; + bool handled_data; + + std::list<parent_node_t *> node_stack; + + parser_t() : document(NULL), pending(NULL), pending_attrs(NULL), + handled_data(false) {} + virtual ~parser_t() {} + + virtual bool test(std::istream& in) const; + virtual document_t * parse(std::istream& in); + }; +#endif +}; + +#if 0 +#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) + +class xml_parser_t : public parser_t +{ + public: + virtual bool test(std::istream& in) const; + + virtual unsigned int parse(std::istream& in, + journal_t * journal, + account_t * master = NULL, + const optional<path>& original = none); +}; + +DECLARE_EXCEPTION(parse_error); + +#endif +#endif + +class commodity_node_t : public parent_node_t +{ +public: + commodity_t * commodity; + + commodity_node_t(document_t * _document, + commodity_t * _commodity, + parent_node_t * _parent = NULL) + : parent_node_t(_document, _parent), commodity(_commodity) { + TRACE_CTOR(commodity_node_t, "document_t *, commodity_t *, parent_node_t *"); + set_name(document_t::COMMODITY); + } + virtual ~commodity_node_t() { + TRACE_DTOR(commodity_node_t); + } + + virtual node_t * children() const; +}; + +class amount_node_t : public parent_node_t +{ +public: + amount_t * amount; + + amount_node_t(document_t * _document, + amount_t * _amount, + parent_node_t * _parent = NULL) + : parent_node_t(_document, _parent), amount(_amount) { + TRACE_CTOR(amount_node_t, "document_t *, amount_t *, parent_node_t *"); + set_name(document_t::AMOUNT); + } + virtual ~amount_node_t() { + TRACE_DTOR(amount_node_t); + } + + virtual node_t * children() const; + + virtual value_t to_value() const { + return *amount; + } +}; + +class transaction_node_t : public parent_node_t +{ + mutable terminal_node_t * payee_virtual_node; + +public: + transaction_t * transaction; + + transaction_node_t(document_t * _document, + transaction_t * _transaction, + parent_node_t * _parent = NULL) + : parent_node_t(_document, _parent), payee_virtual_node(NULL), + transaction(_transaction) { + TRACE_CTOR(transaction_node_t, "document_t *, transaction_t *, parent_node_t *"); + set_name(document_t::TRANSACTION); + } + virtual ~transaction_node_t() { + TRACE_DTOR(transaction_node_t); + if (payee_virtual_node) + checked_delete(payee_virtual_node); + } + + virtual node_t * children() const; + virtual node_t * lookup_child(int _name_id) const; + virtual value_t to_value() const; +}; + +class entry_node_t : public parent_node_t +{ + entry_t * entry; + +public: + entry_node_t(document_t * _document, entry_t * _entry, + parent_node_t * _parent = NULL) + : parent_node_t(_document, _parent), entry(_entry) { + TRACE_CTOR(entry_node_t, "document_t *, entry_t *, parent_node_t *"); + set_name(document_t::ENTRY); + } + virtual ~entry_node_t() { + TRACE_DTOR(entry_node_t); + } + + virtual node_t * children() const; + virtual node_t * lookup_child(int _name_id) const; + + friend class transaction_node_t; +}; + +class account_node_t : public parent_node_t +{ + account_t * account; + +public: + account_node_t(document_t * _document, account_t * _account, + parent_node_t * _parent = NULL) + : parent_node_t(_document, _parent), account(_account) { + TRACE_CTOR(account_node_t, "document_t *, account_t *, parent_node_t *"); + set_name(document_t::ACCOUNT); + } + virtual ~account_node_t() { + TRACE_DTOR(account_node_t); + } + + virtual node_t * children() const; +}; + +class journal_node_t : public parent_node_t +{ + journal_t * journal; + +public: + journal_node_t(document_t * _document, journal_t * _journal, + parent_node_t * _parent = NULL) + : parent_node_t(_document, _parent), journal(_journal) { + TRACE_CTOR(journal_node_t, "document_t *, journal_t *, parent_node_t *"); + set_name(document_t::JOURNAL); + } + virtual ~journal_node_t() { + TRACE_DTOR(journal_node_t); + } + + virtual node_t * children() const; + + friend class transaction_node_t; +}; + +template <typename T> +inline typename T::node_type * +wrap_node(document_t * doc, T * item, void * parent_node = NULL) { + assert(false); + return NULL; +} + +template <> +inline transaction_t::node_type * +wrap_node(document_t * doc, transaction_t * xact, void * parent_node) { + return new transaction_node_t(doc, xact, (parent_node_t *)parent_node); +} + +template <> +inline entry_t::node_type * +wrap_node(document_t * doc, entry_t * entry, void * parent_node) { + return new entry_node_t(doc, entry, (parent_node_t *)parent_node); +} + +template <> +inline account_t::node_type * +wrap_node(document_t * doc, account_t * account, void * parent_node) { + return new account_node_t(doc, account, (parent_node_t *)parent_node); +} + +template <> +inline journal_t::node_type * +wrap_node(document_t * doc, journal_t * journal, void * parent_node) { + return new journal_node_t(doc, journal, (parent_node_t *)parent_node); +} + +} // namespace xml +} // namespace ledger + +#endif // _NODE_H |