1 // Copyright 2015 Google Inc. All rights reserved 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build ignore 16 17 #include "command.h" 18 19 #include <unordered_map> 20 #include <unordered_set> 21 22 #include "dep.h" 23 #include "eval.h" 24 #include "flags.h" 25 #include "log.h" 26 #include "strutil.h" 27 #include "var.h" 28 29 namespace { 30 31 class AutoVar : public Var { 32 public: 33 AutoVar() : Var(VarOrigin::AUTOMATIC) {} 34 virtual const char* Flavor() const override { return "undefined"; } 35 36 virtual void AppendVar(Evaluator*, Value*) override { CHECK(false); } 37 38 virtual StringPiece String() const override { 39 ERROR("$(value %s) is not implemented yet", sym_); 40 return ""; 41 } 42 43 virtual string DebugString() const override { 44 return string("AutoVar(") + sym_ + ")"; 45 } 46 47 protected: 48 AutoVar(CommandEvaluator* ce, const char* sym) : ce_(ce), sym_(sym) {} 49 virtual ~AutoVar() = default; 50 51 CommandEvaluator* ce_; 52 const char* sym_; 53 }; 54 55 #define DECLARE_AUTO_VAR_CLASS(name) \ 56 class name : public AutoVar { \ 57 public: \ 58 name(CommandEvaluator* ce, const char* sym) : AutoVar(ce, sym) {} \ 59 virtual ~name() = default; \ 60 virtual void Eval(Evaluator* ev, string* s) const override; \ 61 } 62 63 DECLARE_AUTO_VAR_CLASS(AutoAtVar); 64 DECLARE_AUTO_VAR_CLASS(AutoLessVar); 65 DECLARE_AUTO_VAR_CLASS(AutoHatVar); 66 DECLARE_AUTO_VAR_CLASS(AutoPlusVar); 67 DECLARE_AUTO_VAR_CLASS(AutoStarVar); 68 DECLARE_AUTO_VAR_CLASS(AutoNotImplementedVar); 69 70 class AutoSuffixDVar : public AutoVar { 71 public: 72 AutoSuffixDVar(CommandEvaluator* ce, const char* sym, Var* wrapped) 73 : AutoVar(ce, sym), wrapped_(wrapped) {} 74 virtual ~AutoSuffixDVar() = default; 75 virtual void Eval(Evaluator* ev, string* s) const override; 76 77 private: 78 Var* wrapped_; 79 }; 80 81 class AutoSuffixFVar : public AutoVar { 82 public: 83 AutoSuffixFVar(CommandEvaluator* ce, const char* sym, Var* wrapped) 84 : AutoVar(ce, sym), wrapped_(wrapped) {} 85 virtual ~AutoSuffixFVar() = default; 86 virtual void Eval(Evaluator* ev, string* s) const override; 87 88 private: 89 Var* wrapped_; 90 }; 91 92 void AutoAtVar::Eval(Evaluator*, string* s) const { 93 *s += ce_->current_dep_node()->output.str(); 94 } 95 96 void AutoLessVar::Eval(Evaluator*, string* s) const { 97 auto& ai = ce_->current_dep_node()->actual_inputs; 98 if (!ai.empty()) 99 *s += ai[0].str(); 100 } 101 102 void AutoHatVar::Eval(Evaluator*, string* s) const { 103 unordered_set<StringPiece> seen; 104 WordWriter ww(s); 105 for (Symbol ai : ce_->current_dep_node()->actual_inputs) { 106 if (seen.insert(ai.str()).second) 107 ww.Write(ai.str()); 108 } 109 } 110 111 void AutoPlusVar::Eval(Evaluator*, string* s) const { 112 WordWriter ww(s); 113 for (Symbol ai : ce_->current_dep_node()->actual_inputs) { 114 ww.Write(ai.str()); 115 } 116 } 117 118 void AutoStarVar::Eval(Evaluator*, string* s) const { 119 const DepNode* n = ce_->current_dep_node(); 120 if (!n->output_pattern.IsValid()) 121 return; 122 Pattern pat(n->output_pattern.str()); 123 pat.Stem(n->output.str()).AppendToString(s); 124 } 125 126 void AutoNotImplementedVar::Eval(Evaluator* ev, string*) const { 127 ev->Error(StringPrintf("Automatic variable `$%s' isn't supported yet", sym_)); 128 } 129 130 void AutoSuffixDVar::Eval(Evaluator* ev, string* s) const { 131 string buf; 132 wrapped_->Eval(ev, &buf); 133 WordWriter ww(s); 134 for (StringPiece tok : WordScanner(buf)) { 135 ww.Write(Dirname(tok)); 136 } 137 } 138 139 void AutoSuffixFVar::Eval(Evaluator* ev, string* s) const { 140 string buf; 141 wrapped_->Eval(ev, &buf); 142 WordWriter ww(s); 143 for (StringPiece tok : WordScanner(buf)) { 144 ww.Write(Basename(tok)); 145 } 146 } 147 148 void ParseCommandPrefixes(StringPiece* s, bool* echo, bool* ignore_error) { 149 *s = TrimLeftSpace(*s); 150 while (true) { 151 char c = s->get(0); 152 if (c == '@') { 153 *echo = false; 154 } else if (c == '-') { 155 *ignore_error = true; 156 } else if (c == '+') { 157 // ignore recursion marker 158 } else { 159 break; 160 } 161 *s = TrimLeftSpace(s->substr(1)); 162 } 163 } 164 165 } // namespace 166 167 CommandEvaluator::CommandEvaluator(Evaluator* ev) : ev_(ev) { 168 #define INSERT_AUTO_VAR(name, sym) \ 169 do { \ 170 Var* v = new name(this, sym); \ 171 Intern(sym).SetGlobalVar(v); \ 172 Intern(sym "D").SetGlobalVar(new AutoSuffixDVar(this, sym "D", v)); \ 173 Intern(sym "F").SetGlobalVar(new AutoSuffixFVar(this, sym "F", v)); \ 174 } while (0) 175 INSERT_AUTO_VAR(AutoAtVar, "@"); 176 INSERT_AUTO_VAR(AutoLessVar, "<"); 177 INSERT_AUTO_VAR(AutoHatVar, "^"); 178 INSERT_AUTO_VAR(AutoPlusVar, "+"); 179 INSERT_AUTO_VAR(AutoStarVar, "*"); 180 // TODO: Implement them. 181 INSERT_AUTO_VAR(AutoNotImplementedVar, "%"); 182 INSERT_AUTO_VAR(AutoNotImplementedVar, "?"); 183 INSERT_AUTO_VAR(AutoNotImplementedVar, "|"); 184 } 185 186 void CommandEvaluator::Eval(DepNode* n, vector<Command*>* commands) { 187 ev_->set_loc(n->loc); 188 ev_->set_current_scope(n->rule_vars); 189 current_dep_node_ = n; 190 for (Value* v : n->cmds) { 191 const string&& cmds_buf = v->Eval(ev_); 192 StringPiece cmds = cmds_buf; 193 bool global_echo = !g_flags.is_silent_mode; 194 bool global_ignore_error = false; 195 ParseCommandPrefixes(&cmds, &global_echo, &global_ignore_error); 196 if (cmds == "") 197 continue; 198 while (true) { 199 size_t lf_cnt; 200 size_t index = FindEndOfLine(cmds, 0, &lf_cnt); 201 if (index == cmds.size()) 202 index = string::npos; 203 StringPiece cmd = TrimLeftSpace(cmds.substr(0, index)); 204 cmds = cmds.substr(index + 1); 205 206 bool echo = global_echo; 207 bool ignore_error = global_ignore_error; 208 ParseCommandPrefixes(&cmd, &echo, &ignore_error); 209 210 if (!cmd.empty()) { 211 Command* command = new Command(n->output); 212 command->cmd = cmd.as_string(); 213 command->echo = echo; 214 command->ignore_error = ignore_error; 215 commands->push_back(command); 216 } 217 if (index == string::npos) 218 break; 219 } 220 continue; 221 } 222 223 if (!ev_->delayed_output_commands().empty()) { 224 vector<Command*> output_commands; 225 for (const string& cmd : ev_->delayed_output_commands()) { 226 Command* c = new Command(n->output); 227 c->cmd = cmd; 228 c->echo = false; 229 c->ignore_error = false; 230 output_commands.push_back(c); 231 } 232 // Prepend |output_commands|. 233 commands->swap(output_commands); 234 copy(output_commands.begin(), output_commands.end(), 235 back_inserter(*commands)); 236 ev_->clear_delayed_output_commands(); 237 } 238 239 ev_->set_current_scope(NULL); 240 } 241