blob: f1ad42f3e5004592eca781ddfa8290f144dab73a [file] [log] [blame]
Shinichiro Hamaji1d545aa2015-06-23 15:29:13 +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
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015// +build ignore
16
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090017#include "eval.h"
18
Shinichiro Hamaji861bd642015-06-19 16:59:13 +090019#include <errno.h>
Dan Willemsen36e57292017-10-09 11:23:32 -070020#include <pthread.h>
Shinichiro Hamaji861bd642015-06-19 16:59:13 +090021#include <string.h>
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +090022
Shinichiro Hamaji645cca72015-09-24 17:04:21 +090023#include "expr.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090024#include "file.h"
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +090025#include "file_cache.h"
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +090026#include "fileutil.h"
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +090027#include "parser.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090028#include "rule.h"
Shinichiro Hamaji645cca72015-09-24 17:04:21 +090029#include "stmt.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090030#include "strutil.h"
Shinichiro Hamajie7992752015-06-29 18:38:35 +090031#include "symtab.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090032#include "var.h"
33
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +090034Evaluator::Evaluator()
35 : last_rule_(NULL),
Shinichiro Hamajife002942015-07-02 03:42:27 +090036 current_scope_(NULL),
Shinichiro Hamaji28da2372015-11-30 19:03:53 +090037 avoid_io_(false),
Shinichiro Hamaji2941ea02016-04-27 17:26:21 +090038 eval_depth_(0),
39 posix_sym_(Intern(".POSIX")),
Dan Willemsenf87d49e2016-09-29 20:09:47 -070040 is_posix_(false),
Sasha Smundak8174f9b2018-08-13 11:07:30 -070041 export_error_(false) {
Dan Willemsen36e57292017-10-09 11:23:32 -070042#if defined(__APPLE__)
43 stack_size_ = pthread_get_stacksize_np(pthread_self());
44 stack_addr_ = (char*)pthread_get_stackaddr_np(pthread_self()) - stack_size_;
45#else
46 pthread_attr_t attr;
47 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
48 CHECK(pthread_attr_getstack(&attr, &stack_addr_, &stack_size_) == 0);
49 CHECK(pthread_attr_destroy(&attr) == 0);
50#endif
51
52 lowest_stack_ = (char*)stack_addr_ + stack_size_;
53 LOG_STAT("Stack size: %zd bytes", stack_size_);
54}
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090055
56Evaluator::~Evaluator() {
Shinichiro Hamajiffc52c32015-06-23 16:51:07 +090057 // delete vars_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090058 // for (auto p : rule_vars) {
59 // delete p.second;
60 // }
61}
62
Dan Willemsen3ce083f2017-10-11 22:17:48 -070063Var* Evaluator::EvalRHS(Symbol lhs,
64 Value* rhs_v,
65 StringPiece orig_rhs,
66 AssignOp op,
Sasha Smundakb4482cb2018-08-23 11:21:28 -070067 bool is_override,
Dan Willemsenee57a3f2018-11-05 16:18:44 -080068 bool* needs_assign) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -070069 VarOrigin origin =
70 ((is_bootstrap_ ? VarOrigin::DEFAULT
71 : is_commandline_ ? VarOrigin::COMMAND_LINE
72 : is_override ? VarOrigin::OVERRIDE
73 : VarOrigin::FILE));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090074
Sasha Smundakb4482cb2018-08-23 11:21:28 -070075 Var* result = NULL;
Dan Willemsenff90ea32017-11-21 13:22:26 -080076 Var* prev = NULL;
Sasha Smundakb4482cb2018-08-23 11:21:28 -070077 *needs_assign = true;
Dan Willemsen276e96a2017-10-03 14:24:48 -070078
Shinichiro Hamaji784b9952015-06-23 14:29:32 +090079 switch (op) {
Shinichiro Hamaji90e52ce2016-02-10 13:53:41 +090080 case AssignOp::COLON_EQ: {
Dan Willemsenff90ea32017-11-21 13:22:26 -080081 prev = PeekVarInCurrentScope(lhs);
Sasha Smundakb4482cb2018-08-23 11:21:28 -070082 result = new SimpleVar(origin, this, rhs_v);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090083 break;
Shinichiro Hamaji90e52ce2016-02-10 13:53:41 +090084 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090085 case AssignOp::EQ:
Dan Willemsenff90ea32017-11-21 13:22:26 -080086 prev = PeekVarInCurrentScope(lhs);
Sasha Smundakb4482cb2018-08-23 11:21:28 -070087 result = new RecursiveVar(rhs_v, origin, orig_rhs);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090088 break;
89 case AssignOp::PLUS_EQ: {
Dan Willemsenff90ea32017-11-21 13:22:26 -080090 prev = LookupVarInCurrentScope(lhs);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090091 if (!prev->IsDefined()) {
Sasha Smundakb4482cb2018-08-23 11:21:28 -070092 result = new RecursiveVar(rhs_v, origin, orig_rhs);
Dan Willemsenf87d49e2016-09-29 20:09:47 -070093 } else if (prev->ReadOnly()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -070094 Error(StringPrintf("*** cannot assign to readonly variable: %s",
95 lhs.c_str()));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090096 } else {
Sasha Smundakb4482cb2018-08-23 11:21:28 -070097 result = prev;
98 result->AppendVar(this, rhs_v);
99 *needs_assign = false;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900100 }
101 break;
102 }
103 case AssignOp::QUESTION_EQ: {
Dan Willemsenff90ea32017-11-21 13:22:26 -0800104 prev = LookupVarInCurrentScope(lhs);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900105 if (!prev->IsDefined()) {
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700106 result = new RecursiveVar(rhs_v, origin, orig_rhs);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900107 } else {
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700108 result = prev;
109 *needs_assign = false;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900110 }
111 break;
112 }
113 }
114
Dan Willemsenff90ea32017-11-21 13:22:26 -0800115 if (prev != NULL) {
116 prev->Used(this, lhs);
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700117 if (prev->Deprecated() && *needs_assign) {
118 result->SetDeprecated(prev->DeprecatedMessage());
Dan Willemsen276e96a2017-10-03 14:24:48 -0700119 }
120 }
121
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700122 LOG("Assign: %s=%s", lhs.c_str(), result->DebugString().c_str());
123 return result;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900124}
125
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900126void Evaluator::EvalAssign(const AssignStmt* stmt) {
127 loc_ = stmt->loc();
Shinichiro Hamaji784b9952015-06-23 14:29:32 +0900128 last_rule_ = NULL;
Shinichiro Hamaji92a47382016-02-17 17:19:21 +0900129 Symbol lhs = stmt->GetLhsSymbol(this);
Shinichiro Hamaji0d4deb62015-06-26 07:47:17 +0900130 if (lhs.empty())
131 Error("*** empty variable name.");
Dan Willemsenf87d49e2016-09-29 20:09:47 -0700132
Sasha Smundak8174f9b2018-08-13 11:07:30 -0700133 if (lhs == kKatiReadonlySym) {
Dan Willemsenf87d49e2016-09-29 20:09:47 -0700134 string rhs;
135 stmt->rhs->Eval(this, &rhs);
136 for (auto const& name : WordScanner(rhs)) {
137 Var* var = Intern(name).GetGlobalVar();
138 if (!var->IsDefined()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700139 Error(
140 StringPrintf("*** unknown variable: %s", name.as_string().c_str()));
Dan Willemsenf87d49e2016-09-29 20:09:47 -0700141 }
142 var->SetReadOnly();
143 }
144 return;
145 }
146
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700147 bool needs_assign;
Dan Willemsenee57a3f2018-11-05 16:18:44 -0800148 Var* var =
149 EvalRHS(lhs, stmt->rhs, stmt->orig_rhs, stmt->op,
150 stmt->directive == AssignDirective::OVERRIDE, &needs_assign);
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700151 if (needs_assign) {
Dan Willemsenf87d49e2016-09-29 20:09:47 -0700152 bool readonly;
Sasha Smundakce812f52018-08-15 14:49:39 -0700153 lhs.SetGlobalVar(var, stmt->directive == AssignDirective::OVERRIDE,
Dan Willemsenf87d49e2016-09-29 20:09:47 -0700154 &readonly);
155 if (readonly) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700156 Error(StringPrintf("*** cannot assign to readonly variable: %s",
157 lhs.c_str()));
Dan Willemsenf87d49e2016-09-29 20:09:47 -0700158 }
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700159 }
160
161 if (stmt->is_final) {
162 var->SetReadOnly();
Sasha Smundakce812f52018-08-15 14:49:39 -0700163 }
164}
165
166// With rule broken into
167// <before_term> <term> <after_term>
168// parses <before_term> into Symbol instances until encountering ':'
169// Returns the remainder of <before_term>.
170static StringPiece ParseRuleTargets(const Loc& loc,
171 const StringPiece& before_term,
172 vector<Symbol>* targets,
173 bool* is_pattern_rule) {
174 size_t pos = before_term.find(':');
175 if (pos == string::npos) {
176 ERROR_LOC(loc, "*** missing separator.");
177 }
178 StringPiece targets_string = before_term.substr(0, pos);
179 size_t pattern_rule_count = 0;
180 for (auto const& word : WordScanner(targets_string)) {
181 StringPiece target = TrimLeadingCurdir(word);
182 targets->push_back(Intern(target));
183 if (Rule::IsPatternRule(target)) {
184 ++pattern_rule_count;
185 }
186 }
187 // Check consistency: either all outputs are patterns or none.
188 if (pattern_rule_count && (pattern_rule_count != targets->size())) {
189 ERROR_LOC(loc, "*** mixed implicit and normal rules: deprecated syntax");
190 }
191 *is_pattern_rule = pattern_rule_count;
192 return before_term.substr(pos + 1);
193}
194
Sasha Smundakce812f52018-08-15 14:49:39 -0700195void Evaluator::MarkVarsReadonly(Value* vars_list) {
196 string vars_list_string;
197 vars_list->Eval(this, &vars_list_string);
198 for (auto const& name : WordScanner(vars_list_string)) {
199 Var* var = current_scope_->Lookup(Intern(name));
200 if (!var->IsDefined()) {
201 Error(StringPrintf("*** unknown variable: %s", name.as_string().c_str()));
202 }
203 var->SetReadOnly();
204 }
205}
206
207void Evaluator::EvalRuleSpecificAssign(const vector<Symbol>& targets,
208 const RuleStmt* stmt,
209 const StringPiece& after_targets,
210 size_t separator_pos) {
211 StringPiece var_name;
212 StringPiece rhs_string;
213 AssignOp assign_op;
214 ParseAssignStatement(after_targets, separator_pos, &var_name, &rhs_string,
215 &assign_op);
216 Symbol var_sym = Intern(var_name);
217 bool is_final = (stmt->sep == RuleStmt::SEP_FINALEQ);
218 for (Symbol target : targets) {
219 auto p = rule_vars_.emplace(target, nullptr);
220 if (p.second) {
221 p.first->second = new Vars;
222 }
223
224 Value* rhs;
225 if (rhs_string.empty()) {
226 rhs = stmt->rhs;
227 } else if (stmt->rhs) {
228 StringPiece sep(stmt->sep == RuleStmt::SEP_SEMICOLON ? " ; " : " = ");
Dan Willemsenee57a3f2018-11-05 16:18:44 -0800229 rhs = Value::NewExpr(Value::NewLiteral(rhs_string),
230 Value::NewLiteral(sep), stmt->rhs);
Sasha Smundakce812f52018-08-15 14:49:39 -0700231 } else {
Sasha Smundakae1d58c2018-08-22 09:39:42 -0700232 rhs = Value::NewLiteral(rhs_string);
Sasha Smundakce812f52018-08-15 14:49:39 -0700233 }
234
235 current_scope_ = p.first->second;
236 if (var_sym == kKatiReadonlySym) {
237 MarkVarsReadonly(rhs);
238 } else {
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700239 bool needs_assign;
Dan Willemsenee57a3f2018-11-05 16:18:44 -0800240 Var* rhs_var = EvalRHS(var_sym, rhs, StringPiece("*TODO*"), assign_op,
241 false, &needs_assign);
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700242 if (needs_assign) {
Sasha Smundakce812f52018-08-15 14:49:39 -0700243 bool readonly;
Sasha Smundakae1d58c2018-08-22 09:39:42 -0700244 rhs_var->SetAssignOp(assign_op);
245 current_scope_->Assign(var_sym, rhs_var, &readonly);
Sasha Smundakce812f52018-08-15 14:49:39 -0700246 if (readonly) {
247 Error(StringPrintf("*** cannot assign to readonly variable: %s",
248 var_name));
249 }
Sasha Smundakb4482cb2018-08-23 11:21:28 -0700250 }
251 if (is_final) {
252 rhs_var->SetReadOnly();
Sasha Smundakce812f52018-08-15 14:49:39 -0700253 }
254 }
255 current_scope_ = NULL;
Dan Willemsenf87d49e2016-09-29 20:09:47 -0700256 }
Shinichiro Hamaji784b9952015-06-23 14:29:32 +0900257}
258
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900259void Evaluator::EvalRule(const RuleStmt* stmt) {
260 loc_ = stmt->loc();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900261 last_rule_ = NULL;
262
Sasha Smundakce812f52018-08-15 14:49:39 -0700263 const string&& before_term = stmt->lhs->Eval(this);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900264 // See semicolon.mk.
Sasha Smundakce812f52018-08-15 14:49:39 -0700265 if (before_term.find_first_not_of(" \t;") == string::npos) {
266 if (stmt->sep == RuleStmt::SEP_SEMICOLON)
Shinichiro Hamajiea549762015-12-07 14:24:23 +0900267 Error("*** missing rule before commands.");
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900268 return;
Shinichiro Hamajiea549762015-12-07 14:24:23 +0900269 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900270
Sasha Smundakce812f52018-08-15 14:49:39 -0700271 vector<Symbol> targets;
272 bool is_pattern_rule;
273 StringPiece after_targets =
274 ParseRuleTargets(loc_, before_term, &targets, &is_pattern_rule);
275 bool is_double_colon = (after_targets[0] == ':');
276 if (is_double_colon) {
277 after_targets = after_targets.substr(1);
278 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900279
Sasha Smundakce812f52018-08-15 14:49:39 -0700280 // Figure out if this is a rule-specific variable assignment.
281 // It is an assignment when either after_targets contains an assignment token
282 // or separator is an assignment token, but only if there is no ';' before the
283 // first assignment token.
284 size_t separator_pos = after_targets.find_first_of("=;");
285 char separator = '\0';
286 if (separator_pos != string::npos) {
287 separator = after_targets[separator_pos];
288 } else if (separator_pos == string::npos &&
Dan Willemsenee57a3f2018-11-05 16:18:44 -0800289 (stmt->sep == RuleStmt::SEP_EQ ||
290 stmt->sep == RuleStmt::SEP_FINALEQ)) {
Sasha Smundakce812f52018-08-15 14:49:39 -0700291 separator_pos = after_targets.size();
292 separator = '=';
293 }
Shinichiro Hamaji2928f462015-06-23 20:24:53 +0900294
Sasha Smundakce812f52018-08-15 14:49:39 -0700295 // If variable name is not empty, we have rule- or target-specific
296 // variable assignment.
297 if (separator == '=' && separator_pos) {
298 EvalRuleSpecificAssign(targets, stmt, after_targets, separator_pos);
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900299 return;
300 }
301
Sasha Smundakce812f52018-08-15 14:49:39 -0700302 // "test: =foo" is questionable but a valid rule definition (not a
303 // target specific variable).
304 // See https://github.com/google/kati/issues/83
305 string buf;
306 if (!separator_pos) {
307 KATI_WARN_LOC(loc_,
308 "defining a target which starts with `=', "
309 "which is not probably what you meant");
310 buf = after_targets.as_string();
311 if (stmt->sep == RuleStmt::SEP_SEMICOLON) {
312 buf += ';';
Dan Willemsenee57a3f2018-11-05 16:18:44 -0800313 } else if (stmt->sep == RuleStmt::SEP_EQ ||
314 stmt->sep == RuleStmt::SEP_FINALEQ) {
Sasha Smundakce812f52018-08-15 14:49:39 -0700315 buf += '=';
Shinichiro Hamaji784b9952015-06-23 14:29:32 +0900316 }
Sasha Smundakce812f52018-08-15 14:49:39 -0700317 if (stmt->rhs) {
318 buf += stmt->rhs->Eval(this);
Shinichiro Hamaji784b9952015-06-23 14:29:32 +0900319 }
Sasha Smundakce812f52018-08-15 14:49:39 -0700320 after_targets = buf;
321 separator_pos = string::npos;
Shinichiro Hamaji784b9952015-06-23 14:29:32 +0900322 }
Sasha Smundakce812f52018-08-15 14:49:39 -0700323
324 Rule* rule = new Rule();
325 rule->loc = loc_;
326 rule->is_double_colon = is_double_colon;
327 if (is_pattern_rule) {
328 rule->output_patterns.swap(targets);
329 } else {
330 rule->outputs.swap(targets);
331 }
332 rule->ParsePrerequisites(after_targets, separator_pos, stmt);
333
334 if (stmt->sep == RuleStmt::SEP_SEMICOLON) {
335 rule->cmds.push_back(stmt->rhs);
336 }
337
338 for (Symbol o : rule->outputs) {
339 if (o == posix_sym_)
340 is_posix_ = true;
341 }
342
343 LOG("Rule: %s", rule->DebugString().c_str());
344 rules_.push_back(rule);
345 last_rule_ = rule;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900346}
347
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900348void Evaluator::EvalCommand(const CommandStmt* stmt) {
349 loc_ = stmt->loc();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900350
351 if (!last_rule_) {
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900352 vector<Stmt*> stmts;
353 ParseNotAfterRule(stmt->orig, stmt->loc(), &stmts);
354 for (Stmt* a : stmts)
Shinichiro Hamaji631a9f82015-07-05 14:18:15 +0900355 a->Eval(this);
356 return;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900357 }
358
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900359 last_rule_->cmds.push_back(stmt->expr);
Shinichiro Hamajiff4584d2015-06-24 17:45:14 +0900360 if (last_rule_->cmd_lineno == 0)
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900361 last_rule_->cmd_lineno = stmt->loc().lineno;
Sasha Smundak8174f9b2018-08-13 11:07:30 -0700362 LOG("Command: %s", Value::DebugString(stmt->expr).c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900363}
364
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900365void Evaluator::EvalIf(const IfStmt* stmt) {
366 loc_ = stmt->loc();
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +0900367
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900368 bool is_true;
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900369 switch (stmt->op) {
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900370 case CondOp::IFDEF:
371 case CondOp::IFNDEF: {
Shinichiro Hamaji4421dda2015-10-21 13:36:50 +0900372 string var_name;
373 stmt->lhs->Eval(this, &var_name);
Shinichiro Hamajid236eb02015-10-27 10:02:15 +0900374 Symbol lhs = Intern(TrimRightSpace(var_name));
375 if (lhs.str().find_first_of(" \t") != string::npos)
Shinichiro Hamaji4421dda2015-10-21 13:36:50 +0900376 Error("*** invalid syntax in conditional.");
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900377 Var* v = LookupVarInCurrentScope(lhs);
Dan Willemsencf015302018-09-15 12:57:42 -0700378 v->Used(this, lhs);
Shinichiro Hamaji52fe6fc2016-06-09 16:14:51 +0900379 is_true = (v->String().empty() == (stmt->op == CondOp::IFNDEF));
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900380 break;
381 }
382 case CondOp::IFEQ:
383 case CondOp::IFNEQ: {
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900384 const string&& lhs = stmt->lhs->Eval(this);
385 const string&& rhs = stmt->rhs->Eval(this);
386 is_true = ((lhs == rhs) == (stmt->op == CondOp::IFEQ));
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900387 break;
388 }
389 default:
390 CHECK(false);
Shinichiro Hamaji8d503012015-07-03 16:26:15 +0900391 abort();
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900392 }
393
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900394 const vector<Stmt*>* stmts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900395 if (is_true) {
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900396 stmts = &stmt->true_stmts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900397 } else {
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900398 stmts = &stmt->false_stmts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900399 }
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900400 for (Stmt* a : *stmts) {
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900401 LOG("%s", a->DebugString().c_str());
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900402 a->Eval(this);
403 }
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900404}
405
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900406void Evaluator::DoInclude(const string& fname) {
Dan Willemsen36e57292017-10-09 11:23:32 -0700407 CheckStack();
408
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +0900409 Makefile* mk = MakefileCacheManager::Get()->ReadMakefile(fname);
Nick Lewycky067e9f12016-06-22 13:57:25 -0700410 if (!mk->Exists()) {
411 Error(StringPrintf("%s does not exist", fname.c_str()));
412 }
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +0900413
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900414 Var* var_list = LookupVar(Intern("MAKEFILE_LIST"));
Dan Willemsenee57a3f2018-11-05 16:18:44 -0800415 var_list->AppendVar(
416 this, Value::NewLiteral(Intern(TrimLeadingCurdir(fname)).str()));
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900417 for (Stmt* stmt : mk->stmts()) {
418 LOG("%s", stmt->DebugString().c_str());
419 stmt->Eval(this);
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +0900420 }
421}
422
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900423void Evaluator::EvalInclude(const IncludeStmt* stmt) {
424 loc_ = stmt->loc();
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +0900425 last_rule_ = NULL;
426
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900427 const string&& pats = stmt->expr->Eval(this);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900428 for (StringPiece pat : WordScanner(pats)) {
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +0900429 ScopedTerminator st(pat);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900430 vector<string>* files;
431 Glob(pat.data(), &files);
432
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900433 if (stmt->should_exist) {
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900434 if (files->empty()) {
Nick Lewyckyf8dad362016-06-22 14:22:33 -0700435 // TODO: Kati does not support building a missing include file.
Shinichiro Hamaji85c74a22015-09-28 13:54:11 +0900436 Error(StringPrintf("%s: %s", pat.data(), strerror(errno)));
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +0900437 }
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900438 }
439
440 for (const string& fname : *files) {
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900441 if (!stmt->should_exist && g_flags.ignore_optional_include_pattern &&
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900442 Pattern(g_flags.ignore_optional_include_pattern).Match(fname)) {
Stefan Becker786881c2016-04-08 15:45:16 +0300443 continue;
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900444 }
445 DoInclude(fname);
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +0900446 }
447 }
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900448}
449
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900450void Evaluator::EvalExport(const ExportStmt* stmt) {
451 loc_ = stmt->loc();
Shinichiro Hamaji6e6de8d2015-06-18 11:12:58 +0900452 last_rule_ = NULL;
453
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900454 const string&& exports = stmt->expr->Eval(this);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900455 for (StringPiece tok : WordScanner(exports)) {
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900456 size_t equal_index = tok.find('=');
Dan Willemsenc3f6a972018-02-27 00:25:01 -0800457 StringPiece lhs;
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900458 if (equal_index == string::npos) {
Dan Willemsenc3f6a972018-02-27 00:25:01 -0800459 lhs = tok;
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900460 } else if (equal_index == 0 ||
461 (equal_index == 1 &&
462 (tok[0] == ':' || tok[0] == '?' || tok[0] == '+'))) {
463 // Do not export tokens after an assignment.
464 break;
465 } else {
Dan Willemsenc3f6a972018-02-27 00:25:01 -0800466 StringPiece rhs;
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900467 AssignOp op;
468 ParseAssignStatement(tok, equal_index, &lhs, &rhs, &op);
Dan Willemsenc3f6a972018-02-27 00:25:01 -0800469 }
470 Symbol sym = Intern(lhs);
471 exports_[sym] = stmt->is_export;
472
473 if (export_message_) {
474 const char* prefix = "";
475 if (!stmt->is_export) {
476 prefix = "un";
477 }
478
479 if (export_error_) {
480 Error(StringPrintf("*** %s: %sexport is obsolete%s.", sym.c_str(),
481 prefix, export_message_->c_str()));
482 } else {
483 WARN_LOC(loc(), "%s: %sexport has been deprecated%s.", sym.c_str(),
484 prefix, export_message_->c_str());
485 }
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900486 }
487 }
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900488}
489
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900490Var* Evaluator::LookupVarGlobal(Symbol name) {
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +0900491 Var* v = name.GetGlobalVar();
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900492 if (v->IsDefined())
493 return v;
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900494 used_undefined_vars_.insert(name);
495 return v;
496}
497
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900498Var* Evaluator::LookupVar(Symbol name) {
Shinichiro Hamaji784b9952015-06-23 14:29:32 +0900499 if (current_scope_) {
500 Var* v = current_scope_->Lookup(name);
501 if (v->IsDefined())
502 return v;
503 }
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900504 return LookupVarGlobal(name);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900505}
506
Dan Willemsen74197412017-12-27 16:50:09 -0800507Var* Evaluator::PeekVar(Symbol name) {
508 if (current_scope_) {
509 Var* v = current_scope_->Peek(name);
510 if (v->IsDefined())
511 return v;
512 }
513 return name.PeekGlobalVar();
514}
515
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900516Var* Evaluator::LookupVarInCurrentScope(Symbol name) {
Shinichiro Hamaji784b9952015-06-23 14:29:32 +0900517 if (current_scope_) {
518 return current_scope_->Lookup(name);
519 }
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900520 return LookupVarGlobal(name);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900521}
522
Dan Willemsenff90ea32017-11-21 13:22:26 -0800523Var* Evaluator::PeekVarInCurrentScope(Symbol name) {
524 if (current_scope_) {
525 return current_scope_->Peek(name);
526 }
527 return name.PeekGlobalVar();
528}
529
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900530string Evaluator::EvalVar(Symbol name) {
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900531 return LookupVar(name)->Eval(this);
532}
533
Shinichiro Hamaji2941ea02016-04-27 17:26:21 +0900534string Evaluator::GetShell() {
535 return EvalVar(kShellSym);
536}
537
538string Evaluator::GetShellFlag() {
539 // TODO: Handle $(.SHELLFLAGS)
540 return is_posix_ ? "-ec" : "-c";
541}
542
543string Evaluator::GetShellAndFlag() {
544 string shell = GetShell();
545 shell += ' ';
546 shell += GetShellFlag();
547 return shell;
548}
549
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900550void Evaluator::Error(const string& msg) {
Dan Willemsene41c7552017-02-22 14:31:16 -0800551 ERROR_LOC(loc_, "%s", msg.c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900552}
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900553
Dan Willemsen36e57292017-10-09 11:23:32 -0700554void Evaluator::DumpStackStats() const {
555 LOG_STAT("Max stack use: %zd bytes at %s:%d",
556 ((char*)stack_addr_ - (char*)lowest_stack_) + stack_size_,
557 LOCF(lowest_loc_));
558}
559
Sasha Smundak8174f9b2018-08-13 11:07:30 -0700560SymbolSet Evaluator::used_undefined_vars_;