summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2012-03-07 10:35:32 -0600
committerJohn Wiegley <johnw@newartisans.com>2012-03-07 10:35:32 -0600
commitc33d7480a60515e4d8b184e01e683e9e74fe7c21 (patch)
tree3fb5cad9c9838d78dd02ea80d5ad668dc419f0a1
parentbe778e387967e56c711ed66e5aafda2d6d7bbc11 (diff)
downloadfork-ledger-c33d7480a60515e4d8b184e01e683e9e74fe7c21.tar.gz
fork-ledger-c33d7480a60515e4d8b184e01e683e9e74fe7c21.tar.bz2
fork-ledger-c33d7480a60515e4d8b184e01e683e9e74fe7c21.zip
Created merged_expr_t class for chained expressions
-rw-r--r--src/expr.cc41
-rw-r--r--src/expr.h62
2 files changed, 102 insertions, 1 deletions
diff --git a/src/expr.cc b/src/expr.cc
index 74d16ecc..8c8e995a 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -163,6 +163,47 @@ void expr_t::dump(std::ostream& out) const
if (ptr) ptr->dump(out, 0);
}
+bool merged_expr_t::check_for_single_identifier(const string& expr)
+{
+ bool single_identifier = true;
+ for (const char * p = expr.c_str(); *p; ++p)
+ if (! std::isalnum(*p) || *p == '_') {
+ single_identifier = false;
+ break;
+ }
+
+ if (single_identifier) {
+ set_base_expr(expr);
+ exprs.clear();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void merged_expr_t::compile(scope_t& scope)
+{
+ if (exprs.empty()) {
+ parse(base_expr);
+ } else {
+ std::ostringstream buf;
+
+ buf << "__tmp_" << term << "=(" << term << "=(" << base_expr << ")";
+ foreach (const string& expr, exprs) {
+ if (merge_operator == ";")
+ buf << merge_operator << term << "=" << expr;
+ else
+ buf << merge_operator << "(" << expr << ")";
+ }
+ buf << ";" << term << ");__tmp_" << term;
+
+ DEBUG("expr.merged.compile", "Compiled expr: " << buf.str());
+ parse(buf.str());
+ }
+
+ expr_t::compile(scope);
+}
+
value_t source_command(call_scope_t& args)
{
std::istream * in = NULL;
diff --git a/src/expr.h b/src/expr.h
index ab3487fe..5dc6430a 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -172,8 +172,68 @@ inline value_t expr_value(expr_t::ptr_op_t op) {
return temp;
}
-class call_scope_t;
+// A merged expression allows one to set an expression term, "foo", and
+// a base expression, "bar", and then merge in later expressions that
+// utilize foo. For example:
+//
+// foo: bar
+// merge: foo * 10
+// merge: foo + 20
+//
+// When this expression is finally compiled, the base and merged
+// elements are written into this:
+//
+// __tmp=(foo=bar; foo=foo*10; foo=foo+20);__tmp
+//
+// This allows users to select flags like -O, -B or -I at any time, and
+// also combine flags such as -V and -A.
+
+class merged_expr_t : public expr_t
+{
+public:
+ string term;
+ string base_expr;
+ string merge_operator;
+ std::list<string> exprs;
+
+ merged_expr_t(const string& _term, const string& expr,
+ const string& merge_op = ";")
+ : expr_t(), term(_term), base_expr(expr), merge_operator(merge_op) {
+ TRACE_CTOR(merged_expr_t, "string, string, string");
+ }
+
+ virtual ~merged_expr_t() {
+ TRACE_DTOR(merged_expr_t);
+ }
+
+ void set_term(const string& _term) {
+ term = _term;
+ }
+ void set_base_expr(const string& expr) {
+ base_expr = expr;
+ }
+ void set_merge_operator(const string& merge_op) {
+ merge_operator = merge_op;
+ }
+
+ bool check_for_single_identifier(const string& expr);
+ void prepend(const string& expr) {
+ if (! check_for_single_identifier(expr))
+ exprs.push_front(expr);
+ }
+ void append(const string& expr) {
+ if (! check_for_single_identifier(expr))
+ exprs.push_back(expr);
+ }
+ void remove(const string& expr) {
+ exprs.remove(expr);
+ }
+
+ virtual void compile(scope_t& scope);
+};
+
+class call_scope_t;
value_t source_command(call_scope_t& scope);
} // namespace ledger