• 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:
Flavor() const33   virtual const char* Flavor() const override {
34     return "undefined";
35   }
Origin() const36   virtual VarOrigin Origin() const override {
37     return VarOrigin::AUTOMATIC;
38   }
39 
AppendVar(Evaluator *,Value *)40   virtual void AppendVar(Evaluator*, Value*) override { CHECK(false); }
41 
String() const42   virtual StringPiece String() const override {
43     ERROR("$(value %s) is not implemented yet", sym_);
44     return "";
45   }
46 
DebugString() const47   virtual string DebugString() const override {
48     return string("AutoVar(") + sym_ + ")";
49   }
50 
51  protected:
AutoVar(CommandEvaluator * ce,const char * sym)52   AutoVar(CommandEvaluator* ce, const char* sym) : ce_(ce), sym_(sym) {}
53   virtual ~AutoVar() = default;
54 
55   CommandEvaluator* ce_;
56   const char* sym_;
57 };
58 
59 #define DECLARE_AUTO_VAR_CLASS(name)                                    \
60   class name : public AutoVar {                                         \
61    public:                                                              \
62    name(CommandEvaluator* ce, const char* sym)                          \
63        : AutoVar(ce, sym) {}                                            \
64    virtual ~name() = default;                                           \
65    virtual void Eval(Evaluator* ev, string* s) const override;          \
66   }
67 
68 DECLARE_AUTO_VAR_CLASS(AutoAtVar);
69 DECLARE_AUTO_VAR_CLASS(AutoLessVar);
70 DECLARE_AUTO_VAR_CLASS(AutoHatVar);
71 DECLARE_AUTO_VAR_CLASS(AutoPlusVar);
72 DECLARE_AUTO_VAR_CLASS(AutoStarVar);
73 DECLARE_AUTO_VAR_CLASS(AutoNotImplementedVar);
74 
75 class AutoSuffixDVar : public AutoVar {
76  public:
AutoSuffixDVar(CommandEvaluator * ce,const char * sym,Var * wrapped)77   AutoSuffixDVar(CommandEvaluator* ce, const char* sym, Var* wrapped)
78       : AutoVar(ce, sym), wrapped_(wrapped) {
79   }
80   virtual ~AutoSuffixDVar() = default;
81   virtual void Eval(Evaluator* ev, string* s) const override;
82 
83  private:
84   Var* wrapped_;
85 };
86 
87 class AutoSuffixFVar : public AutoVar {
88  public:
AutoSuffixFVar(CommandEvaluator * ce,const char * sym,Var * wrapped)89   AutoSuffixFVar(CommandEvaluator* ce, const char* sym, Var* wrapped)
90       : AutoVar(ce, sym), wrapped_(wrapped) {}
91   virtual ~AutoSuffixFVar() = default;
92   virtual void Eval(Evaluator* ev, string* s) const override;
93 
94  private:
95   Var* wrapped_;
96 };
97 
Eval(Evaluator *,string * s) const98 void AutoAtVar::Eval(Evaluator*, string* s) const {
99   *s += ce_->current_dep_node()->output.str();
100 }
101 
Eval(Evaluator *,string * s) const102 void AutoLessVar::Eval(Evaluator*, string* s) const {
103   auto& ai = ce_->current_dep_node()->actual_inputs;
104   if (!ai.empty())
105     *s += ai[0].str();
106 }
107 
Eval(Evaluator *,string * s) const108 void AutoHatVar::Eval(Evaluator*, string* s) const {
109   unordered_set<StringPiece> seen;
110   WordWriter ww(s);
111   for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
112     if (seen.insert(ai.str()).second)
113       ww.Write(ai.str());
114   }
115 }
116 
Eval(Evaluator *,string * s) const117 void AutoPlusVar::Eval(Evaluator*, string* s) const {
118   WordWriter ww(s);
119   for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
120     ww.Write(ai.str());
121   }
122 }
123 
Eval(Evaluator *,string * s) const124 void AutoStarVar::Eval(Evaluator*, string* s) const {
125   const DepNode* n = ce_->current_dep_node();
126   if (!n->output_pattern.IsValid())
127     return;
128   Pattern pat(n->output_pattern.str());
129   pat.Stem(n->output.str()).AppendToString(s);
130 }
131 
Eval(Evaluator * ev,string *) const132 void AutoNotImplementedVar::Eval(Evaluator* ev, string*) const {
133   ev->Error(StringPrintf(
134       "Automatic variable `$%s' isn't supported yet", sym_));
135 }
136 
Eval(Evaluator * ev,string * s) const137 void AutoSuffixDVar::Eval(Evaluator* ev, string* s) const {
138   string buf;
139   wrapped_->Eval(ev, &buf);
140   WordWriter ww(s);
141   for (StringPiece tok : WordScanner(buf)) {
142     ww.Write(Dirname(tok));
143   }
144 }
145 
Eval(Evaluator * ev,string * s) const146 void AutoSuffixFVar::Eval(Evaluator* ev, string* s) const {
147   string buf;
148   wrapped_->Eval(ev, &buf);
149   WordWriter ww(s);
150   for (StringPiece tok : WordScanner(buf)) {
151     ww.Write(Basename(tok));
152   }
153 }
154 
ParseCommandPrefixes(StringPiece * s,bool * echo,bool * ignore_error)155 void ParseCommandPrefixes(StringPiece* s, bool* echo, bool* ignore_error) {
156   *s = TrimLeftSpace(*s);
157   while (true) {
158     char c = s->get(0);
159     if (c == '@') {
160       *echo = false;
161     } else if (c == '-') {
162       *ignore_error = true;
163     } else if (c == '+') {
164       // ignore recursion marker
165     } else {
166       break;
167     }
168     *s = TrimLeftSpace(s->substr(1));
169   }
170 }
171 
172 }  // namespace
173 
CommandEvaluator(Evaluator * ev)174 CommandEvaluator::CommandEvaluator(Evaluator* ev)
175     : ev_(ev) {
176 #define INSERT_AUTO_VAR(name, sym) do {                                 \
177     Var* v = new name(this, sym);                                       \
178     Intern(sym).SetGlobalVar(v);                                        \
179     Intern(sym"D").SetGlobalVar(new AutoSuffixDVar(this, sym"D", v));   \
180     Intern(sym"F").SetGlobalVar(new AutoSuffixFVar(this, sym"F", v));   \
181   } while (0)
182   INSERT_AUTO_VAR(AutoAtVar, "@");
183   INSERT_AUTO_VAR(AutoLessVar, "<");
184   INSERT_AUTO_VAR(AutoHatVar, "^");
185   INSERT_AUTO_VAR(AutoPlusVar, "+");
186   INSERT_AUTO_VAR(AutoStarVar, "*");
187   // TODO: Implement them.
188   INSERT_AUTO_VAR(AutoNotImplementedVar, "%");
189   INSERT_AUTO_VAR(AutoNotImplementedVar, "?");
190   INSERT_AUTO_VAR(AutoNotImplementedVar, "|");
191 }
192 
Eval(DepNode * n,vector<Command * > * commands)193 void CommandEvaluator::Eval(DepNode* n, vector<Command*>* commands) {
194   ev_->set_loc(n->loc);
195   ev_->set_current_scope(n->rule_vars);
196   current_dep_node_ = n;
197   for (Value* v : n->cmds) {
198     const string&& cmds_buf = v->Eval(ev_);
199     StringPiece cmds = cmds_buf;
200     bool global_echo = !g_flags.is_silent_mode;
201     bool global_ignore_error = false;
202     ParseCommandPrefixes(&cmds, &global_echo, &global_ignore_error);
203     if (cmds == "")
204       continue;
205     while (true) {
206       size_t lf_cnt;
207       size_t index = FindEndOfLine(cmds, 0, &lf_cnt);
208       if (index == cmds.size())
209         index = string::npos;
210       StringPiece cmd = TrimLeftSpace(cmds.substr(0, index));
211       cmds = cmds.substr(index + 1);
212 
213       bool echo = global_echo;
214       bool ignore_error = global_ignore_error;
215       ParseCommandPrefixes(&cmd, &echo, &ignore_error);
216 
217       if (!cmd.empty()) {
218         Command* command = new Command(n->output);
219         command->cmd = cmd.as_string();
220         command->echo = echo;
221         command->ignore_error = ignore_error;
222         commands->push_back(command);
223       }
224       if (index == string::npos)
225         break;
226     }
227     continue;
228   }
229 
230   if (!ev_->delayed_output_commands().empty()) {
231     vector<Command*> output_commands;
232     for (const string& cmd : ev_->delayed_output_commands()) {
233       Command* c = new Command(n->output);
234       c->cmd = cmd;
235       c->echo = false;
236       c->ignore_error = false;
237       output_commands.push_back(c);
238     }
239     // Prepend |output_commands|.
240     commands->swap(output_commands);
241     copy(output_commands.begin(), output_commands.end(),
242          back_inserter(*commands));
243     ev_->clear_delayed_output_commands();
244   }
245 
246   ev_->set_current_scope(NULL);
247 }
248