summaryrefslogtreecommitdiff
path: root/src/exprbase.h
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-11-08 23:40:42 -0500
committerJohn Wiegley <johnw@newartisans.com>2009-11-09 02:06:06 -0500
commitc3535d06c89732a0ba4c13274702b0f48198ae79 (patch)
tree5a8153d4c627cc3c7eff687b50a59a1cc9c3d04a /src/exprbase.h
parent523d4243e8c347cb7cbd1f68b03a5098ceb73b70 (diff)
downloadfork-ledger-c3535d06c89732a0ba4c13274702b0f48198ae79.tar.gz
fork-ledger-c3535d06c89732a0ba4c13274702b0f48198ae79.tar.bz2
fork-ledger-c3535d06c89732a0ba4c13274702b0f48198ae79.zip
Redesigned the expr_t, predicate_t, query_t classes
Diffstat (limited to 'src/exprbase.h')
-rw-r--r--src/exprbase.h253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/exprbase.h b/src/exprbase.h
new file mode 100644
index 00000000..605c30f7
--- /dev/null
+++ b/src/exprbase.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2003-2009, 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.
+ */
+
+/**
+ * @addtogroup expr
+ */
+
+/**
+ * @file exprbase.h
+ * @author John Wiegley
+ *
+ * @ingroup expr
+ *
+ * This class provides basic behavior for all the domain specific expression
+ * languages used in Leger:
+ *
+ * | Typename | Description | result_type | Derives |
+ * |-------------+----------------------------+-----------------+-------------|
+ * | expr_t | Value expressions | value_t | |
+ * | predicate_t | Special form of expr_t | bool | expr_t |
+ * | query_t | Report queries | bool | predicate_t |
+ * | period_t | Time periods and durations | date_interval_t | |
+ * | draft_t | Partially filled xacts | xact_t * | |
+ * | format_t | Format strings | string | |
+ */
+#ifndef _EXPRBASE_H
+#define _EXPRBASE_H
+
+#include "utils.h"
+#include "amount.h"
+
+namespace ledger {
+
+DECLARE_EXCEPTION(parse_error, std::runtime_error);
+DECLARE_EXCEPTION(compile_error, std::runtime_error);
+DECLARE_EXCEPTION(calc_error, std::runtime_error);
+DECLARE_EXCEPTION(usage_error, std::runtime_error);
+
+class scope_t;
+class call_scope_t;
+
+template <typename ResultType>
+class expr_base_t
+{
+public:
+ typedef ResultType result_type;
+
+ typedef function<result_type (call_scope_t&)> func_t;
+
+protected:
+ scope_t * context;
+ string str;
+ bool compiled;
+
+ virtual result_type real_calc(scope_t& scope) = 0;
+
+public:
+ expr_base_t(const expr_base_t& other)
+ : context(other.context), str(other.str), compiled(false) {
+ TRACE_CTOR(expr_base_t, "copy");
+ }
+ expr_base_t(scope_t * _context = NULL)
+ : context(_context), compiled(false)
+ {
+ TRACE_CTOR(expr_base_t, "scope_t *");
+ }
+
+ ~expr_base_t() throw() {
+ TRACE_DTOR(expr_base_t);
+ }
+
+ expr_base_t& operator=(const expr_base_t& _expr) {
+ if (this != &_expr) {
+ str = _expr.str;
+ context = _expr.context;
+ compiled = _expr.compiled;
+ }
+ return *this;
+ }
+ expr_base_t& operator=(const string& _expr) {
+ parse(_expr);
+ return *this;
+ }
+
+ virtual operator bool() const throw() {
+ return ! str.empty();
+ }
+
+ virtual string text() {
+ return str;
+ }
+ void set_text(const string& txt) {
+ str = txt;
+ }
+
+ void parse(const string& str, const parse_flags_t& flags = PARSE_DEFAULT) {
+ std::istringstream stream(str);
+ return parse(stream, flags, str);
+ }
+ virtual void parse(std::istream&,
+ const parse_flags_t& = PARSE_DEFAULT,
+ const optional<string>& original_string = none) {
+ str = original_string ? *original_string : "<stream>";
+ context = NULL;
+ compiled = false;
+ }
+
+ void mark_uncompiled() {
+ compiled = false;
+ }
+
+ void recompile(scope_t& scope) {
+ compiled = false;
+ compile(scope);
+ }
+
+ virtual void compile(scope_t& scope) {
+ if (! compiled) {
+ // Derived classes need to do something here.
+ context = &scope;
+ compiled = true;
+ }
+ }
+
+ result_type operator()(scope_t& scope) {
+ return calc(scope);
+ }
+
+ result_type calc(scope_t& scope)
+ {
+ if (! compiled) {
+ if (SHOW_DEBUG("expr.compile")) {
+ DEBUG("expr.compile", "Before compilation:");
+ dump(*_log_stream);
+ }
+
+ compile(scope);
+
+ if (SHOW_DEBUG("expr.compile")) {
+ DEBUG("expr.compile", "After compilation:");
+ dump(*_log_stream);
+ }
+ }
+
+ return real_calc(scope);
+ }
+
+ result_type calc() {
+ assert(context);
+ return calc(*context);
+ }
+
+ scope_t * get_context() {
+ return context;
+ }
+ void set_context(scope_t * scope) {
+ context = scope;
+ }
+
+ virtual string context_to_str() const = 0;
+
+ string print_to_str() const {
+ std::ostringstream out;
+ print(out);
+ return out.str();
+ }
+ string dump_to_str() const {
+ std::ostringstream out;
+ dump(out);
+ return out.str();
+ }
+ string preview_to_str(scope_t& scope) const {
+ std::ostringstream out;
+ preview(out);
+ return out.str();
+ }
+
+ virtual void print(std::ostream& out) const = 0;
+ virtual void dump(std::ostream& out) const = 0;
+
+ result_type preview(std::ostream& out, scope_t& scope) const {
+ out << _("--- Input expression ---") << std::endl;
+ out << text() << std::endl;
+
+ out << std::endl << _("--- Text as parsed ---") << std::endl;
+ print(out);
+ out << std::endl;
+
+ out << std::endl << _("--- Expression tree ---") << std::endl;
+ dump(out);
+
+ out << std::endl << _("--- Compiled tree ---") << std::endl;
+ compile(scope);
+ dump(out);
+
+ out << std::endl << _("--- Result value ---") << std::endl;
+ return calc();
+ }
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive& ar, const unsigned int /* version */) {
+ ar & context;
+ ar & str;
+ if (Archive::is_loading::value)
+ compiled = false;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
+};
+
+template <typename ResultType>
+std::ostream& operator<<(std::ostream& out,
+ const expr_base_t<ResultType>& expr) {
+ expr.print(out);
+ return out;
+}
+
+} // namespace ledger
+
+#endif // _EXPRBASE_H