basic string evaluator
authorEvan Martin <martine@danga.com>
Fri, 15 Oct 2010 07:10:49 +0000 (00:10 -0700)
committerEvan Martin <martine@danga.com>
Fri, 15 Oct 2010 07:10:49 +0000 (00:10 -0700)
Makefile
ninja.h
ninja_test.cc

index e411b56..375cd57 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 CXXFLAGS := -Wall -g
 
 all_i_currently_care_about: ninja_test
-ninja: ninja.cc | Makefile ninja.h
 
 ninja_test: LDFLAGS = -lgtest -lgtest_main
-ninja_test: ninja_test.cc ninja.h | Makefile
+ninja_test: ninja_test.o
+ninja_test.o: ninja_test.cc ninja.h
diff --git a/ninja.h b/ninja.h
index 7c0c83d..1e66b96 100644 (file)
--- a/ninja.h
+++ b/ninja.h
@@ -31,6 +31,59 @@ struct Node {
   vector<Edge*> out_edges_;
 };
 
+struct EvalString {
+  struct Env {
+    virtual string Evaluate(const string& var) = 0;
+  };
+  bool Parse(const string& input);
+  string Evaluate(Env* env);
+
+  string orig_;
+  enum TokenType { RAW, SPECIAL };
+  typedef vector<pair<string, TokenType> > TokenList;
+  TokenList parsed_;
+};
+
+bool EvalString::Parse(const string& input) {
+  string::size_type start, end;
+  start = 0;
+  do {
+    end = input.find_first_of("@$", start);
+    if (end == string::npos) {
+      end = input.size();
+      break;
+    }
+    if (end > start)
+      parsed_.push_back(make_pair(input.substr(start, end - start), RAW));
+    start = end;
+    for (end = start + 1; end < input.size(); ++end) {
+      if (!('a' <= input[end] && input[end] <= 'z'))
+        break;
+    }
+    if (end == start + 1) {
+      // XXX report bad parse here
+      return false;
+    }
+    parsed_.push_back(make_pair(input.substr(start, end - start), SPECIAL));
+    start = end;
+  } while (end < input.size());
+  if (end > start)
+    parsed_.push_back(make_pair(input.substr(start, end - start), RAW));
+
+  return true;
+}
+
+string EvalString::Evaluate(Env* env) {
+  string result;
+  for (TokenList::iterator i = parsed_.begin(); i != parsed_.end(); ++i) {
+    if (i->second == RAW)
+      result.append(i->first);
+    else
+      result.append(env->Evaluate(i->first));
+  }
+  return result;
+}
+
 struct Rule {
   Rule(const string& name, const string& command) :
     name_(name), command_(command) {}
index 6a680a1..23f4bf1 100644 (file)
@@ -33,3 +33,23 @@ TEST_F(NinjaTest, Basic) {
   ASSERT_TRUE(plan.FindWork());
   ASSERT_FALSE(plan.FindWork());
 }
+
+struct TestEnv : public EvalString::Env {
+  virtual string Evaluate(const string& var) {
+    return vars[var];
+  }
+  map<string, string> vars;
+};
+TEST(EvalString, PlainText) {
+  EvalString str;
+  str.Parse("plain text");
+  ASSERT_EQ("plain text", str.Evaluate(NULL));
+}
+TEST(EvalString, OneVariable) {
+  EvalString str;
+  ASSERT_TRUE(str.Parse("hi $var"));
+  TestEnv env;
+  EXPECT_EQ("hi ", str.Evaluate(&env));
+  env.vars["$var"] = "there";
+  EXPECT_EQ("hi there", str.Evaluate(&env));
+}