• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
AutoVar()33   AutoVar() : Var(VarOrigin::AUTOMATIC) {}
Flavor() const34   virtual const char* Flavor() const override { return "undefined"; }
35 
AppendVar(Evaluator *,Value *)36   virtual void AppendVar(Evaluator*, Value*) override { CHECK(false); }
37 
String() const38   virtual StringPiece String() const override {
39     ERROR("$(value %s) is not implemented yet", sym_);
40     return "";
41   }
42 
DebugString() const43   virtual string DebugString() const override {
44     return string("AutoVar(") + sym_ + ")";
45   }
46 
47  protected:
AutoVar(CommandEvaluator * ce,const char * sym)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:
AutoSuffixDVar(CommandEvaluator * ce,const char * sym,Var * wrapped)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:
AutoSuffixFVar(CommandEvaluator * ce,const char * sym,Var * wrapped)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 
Eval(Evaluator *,string * s) const92 void AutoAtVar::Eval(Evaluator*, string* s) const {
93   *s += ce_->current_dep_node()->output.str();
94 }
95 
Eval(Evaluator *,string * s) const96 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 
Eval(Evaluator *,string * s) const102 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 
Eval(Evaluator *,string * s) const111 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 
Eval(Evaluator *,string * s) const118 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 
Eval(Evaluator * ev,string *) const126 void AutoNotImplementedVar::Eval(Evaluator* ev, string*) const {
127   ev->Error(StringPrintf("Automatic variable `$%s' isn't supported yet", sym_));
128 }
129 
Eval(Evaluator * ev,string * s) const130 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 
Eval(Evaluator * ev,string * s) const139 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 
ParseCommandPrefixes(StringPiece * s,bool * echo,bool * ignore_error)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 
CommandEvaluator(Evaluator * ev)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 
Eval(DepNode * n,vector<Command * > * commands)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