blob: ac7faddd81a194ee4bcc8e610344806e1fe14b51 [file] [log] [blame]
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +09001// 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"
Shinichiro Hamajib6a04542015-09-09 17:37:41 +090024#include "flags.h"
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +090025#include "log.h"
26#include "strutil.h"
27#include "var.h"
28
29namespace {
30
31class AutoVar : public Var {
32 public:
33 virtual const char* Flavor() const override {
34 return "undefined";
35 }
36 virtual VarOrigin Origin() const override {
37 return VarOrigin::AUTOMATIC;
38 }
39
40 virtual void AppendVar(Evaluator*, Value*) override { CHECK(false); }
41
42 virtual StringPiece String() const override {
43 ERROR("$(value %s) is not implemented yet", sym_);
44 return "";
45 }
46
47 virtual string DebugString() const override {
48 return string("AutoVar(") + sym_ + ")";
49 }
50
51 protected:
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
68DECLARE_AUTO_VAR_CLASS(AutoAtVar);
69DECLARE_AUTO_VAR_CLASS(AutoLessVar);
70DECLARE_AUTO_VAR_CLASS(AutoHatVar);
71DECLARE_AUTO_VAR_CLASS(AutoPlusVar);
72DECLARE_AUTO_VAR_CLASS(AutoStarVar);
Shinichiro Hamajib552df32015-12-12 12:37:51 +090073DECLARE_AUTO_VAR_CLASS(AutoNotImplementedVar);
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +090074
75class AutoSuffixDVar : public AutoVar {
76 public:
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
87class AutoSuffixFVar : public AutoVar {
88 public:
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
98void AutoAtVar::Eval(Evaluator*, string* s) const {
Shinichiro Hamajie7992752015-06-29 18:38:35 +090099 *s += ce_->current_dep_node()->output.str();
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900100}
101
102void AutoLessVar::Eval(Evaluator*, string* s) const {
103 auto& ai = ce_->current_dep_node()->actual_inputs;
104 if (!ai.empty())
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900105 *s += ai[0].str();
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900106}
107
108void AutoHatVar::Eval(Evaluator*, string* s) const {
109 unordered_set<StringPiece> seen;
110 WordWriter ww(s);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900111 for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
112 if (seen.insert(ai.str()).second)
113 ww.Write(ai.str());
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900114 }
115}
116
117void AutoPlusVar::Eval(Evaluator*, string* s) const {
118 WordWriter ww(s);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900119 for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
120 ww.Write(ai.str());
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900121 }
122}
123
124void AutoStarVar::Eval(Evaluator*, string* s) const {
Shinichiro Hamajia7984ad2015-09-11 16:33:16 +0900125 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);
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900130}
131
Shinichiro Hamajib91fb6f2015-12-18 15:59:13 +0900132void AutoNotImplementedVar::Eval(Evaluator* ev, string*) const {
133 ev->Error(StringPrintf(
134 "Automatic variable `$%s' isn't supported yet", sym_));
Shinichiro Hamajib552df32015-12-12 12:37:51 +0900135}
136
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900137void 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
146void 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
155void 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 {
164 break;
165 }
166 *s = TrimLeftSpace(s->substr(1));
167 }
168}
169
170} // namespace
171
172CommandEvaluator::CommandEvaluator(Evaluator* ev)
173 : ev_(ev) {
174 Vars* vars = ev_->mutable_vars();
175#define INSERT_AUTO_VAR(name, sym) do { \
176 Var* v = new name(this, sym); \
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900177 (*vars)[Intern(sym)] = v; \
178 (*vars)[Intern(sym"D")] = new AutoSuffixDVar(this, sym"D", v); \
179 (*vars)[Intern(sym"F")] = new AutoSuffixFVar(this, sym"F", v); \
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900180 } while (0)
181 INSERT_AUTO_VAR(AutoAtVar, "@");
182 INSERT_AUTO_VAR(AutoLessVar, "<");
183 INSERT_AUTO_VAR(AutoHatVar, "^");
184 INSERT_AUTO_VAR(AutoPlusVar, "+");
185 INSERT_AUTO_VAR(AutoStarVar, "*");
Shinichiro Hamajib552df32015-12-12 12:37:51 +0900186 // TODO: Implement them.
187 INSERT_AUTO_VAR(AutoNotImplementedVar, "%");
188 INSERT_AUTO_VAR(AutoNotImplementedVar, "?");
189 INSERT_AUTO_VAR(AutoNotImplementedVar, "|");
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900190}
191
192void CommandEvaluator::Eval(DepNode* n, vector<Command*>* commands) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900193 ev_->set_loc(n->loc);
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900194 ev_->set_current_scope(n->rule_vars);
195 current_dep_node_ = n;
196 for (Value* v : n->cmds) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900197 const string&& cmds_buf = v->Eval(ev_);
198 StringPiece cmds = cmds_buf;
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900199 bool global_echo = !g_flags.is_silent_mode;
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900200 bool global_ignore_error = false;
201 ParseCommandPrefixes(&cmds, &global_echo, &global_ignore_error);
202 if (cmds == "")
203 continue;
204 while (true) {
205 size_t lf_cnt;
206 size_t index = FindEndOfLine(cmds, 0, &lf_cnt);
207 if (index == cmds.size())
208 index = string::npos;
209 StringPiece cmd = TrimLeftSpace(cmds.substr(0, index));
210 cmds = cmds.substr(index + 1);
211
212 bool echo = global_echo;
213 bool ignore_error = global_ignore_error;
214 ParseCommandPrefixes(&cmd, &echo, &ignore_error);
215
216 if (!cmd.empty()) {
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900217 Command* command = new Command(n->output);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900218 command->cmd = cmd.as_string();
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900219 command->echo = echo;
220 command->ignore_error = ignore_error;
221 commands->push_back(command);
222 }
223 if (index == string::npos)
224 break;
225 }
226 continue;
227 }
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900228
229 if (!ev_->delayed_output_commands().empty()) {
230 vector<Command*> output_commands;
231 for (const string& cmd : ev_->delayed_output_commands()) {
232 Command* c = new Command(n->output);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900233 c->cmd = cmd;
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900234 c->echo = false;
235 c->ignore_error = false;
236 output_commands.push_back(c);
237 }
238 // Prepend |output_commands|.
239 commands->swap(output_commands);
240 copy(output_commands.begin(), output_commands.end(),
241 back_inserter(*commands));
242 ev_->clear_delayed_output_commands();
243 }
244
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900245 ev_->set_current_scope(NULL);
246}