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 "eval.h"
18
19 #include <errno.h>
20 #include <pthread.h>
21 #include <string.h>
22
23 #include "expr.h"
24 #include "file.h"
25 #include "file_cache.h"
26 #include "fileutil.h"
27 #include "parser.h"
28 #include "rule.h"
29 #include "stmt.h"
30 #include "strutil.h"
31 #include "symtab.h"
32 #include "var.h"
33
Evaluator()34 Evaluator::Evaluator()
35 : last_rule_(NULL),
36 current_scope_(NULL),
37 avoid_io_(false),
38 eval_depth_(0),
39 posix_sym_(Intern(".POSIX")),
40 is_posix_(false),
41 export_error_(false),
42 kati_readonly_(Intern(".KATI_READONLY")) {
43 #if defined(__APPLE__)
44 stack_size_ = pthread_get_stacksize_np(pthread_self());
45 stack_addr_ = (char*)pthread_get_stackaddr_np(pthread_self()) - stack_size_;
46 #else
47 pthread_attr_t attr;
48 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
49 CHECK(pthread_attr_getstack(&attr, &stack_addr_, &stack_size_) == 0);
50 CHECK(pthread_attr_destroy(&attr) == 0);
51 #endif
52
53 lowest_stack_ = (char*)stack_addr_ + stack_size_;
54 LOG_STAT("Stack size: %zd bytes", stack_size_);
55 }
56
~Evaluator()57 Evaluator::~Evaluator() {
58 // delete vars_;
59 // for (auto p : rule_vars) {
60 // delete p.second;
61 // }
62 }
63
EvalRHS(Symbol lhs,Value * rhs_v,StringPiece orig_rhs,AssignOp op,bool is_override)64 Var* Evaluator::EvalRHS(Symbol lhs,
65 Value* rhs_v,
66 StringPiece orig_rhs,
67 AssignOp op,
68 bool is_override) {
69 VarOrigin origin =
70 ((is_bootstrap_ ? VarOrigin::DEFAULT
71 : is_commandline_ ? VarOrigin::COMMAND_LINE
72 : is_override ? VarOrigin::OVERRIDE
73 : VarOrigin::FILE));
74
75 Var* rhs = NULL;
76 Var* prev = NULL;
77 bool needs_assign = true;
78
79 switch (op) {
80 case AssignOp::COLON_EQ: {
81 prev = PeekVarInCurrentScope(lhs);
82 SimpleVar* sv = new SimpleVar(origin);
83 rhs_v->Eval(this, sv->mutable_value());
84 rhs = sv;
85 break;
86 }
87 case AssignOp::EQ:
88 prev = PeekVarInCurrentScope(lhs);
89 rhs = new RecursiveVar(rhs_v, origin, orig_rhs);
90 break;
91 case AssignOp::PLUS_EQ: {
92 prev = LookupVarInCurrentScope(lhs);
93 if (!prev->IsDefined()) {
94 rhs = new RecursiveVar(rhs_v, origin, orig_rhs);
95 } else if (prev->ReadOnly()) {
96 Error(StringPrintf("*** cannot assign to readonly variable: %s",
97 lhs.c_str()));
98 } else {
99 prev->AppendVar(this, rhs_v);
100 rhs = prev;
101 needs_assign = false;
102 }
103 break;
104 }
105 case AssignOp::QUESTION_EQ: {
106 prev = LookupVarInCurrentScope(lhs);
107 if (!prev->IsDefined()) {
108 rhs = new RecursiveVar(rhs_v, origin, orig_rhs);
109 } else {
110 rhs = prev;
111 needs_assign = false;
112 }
113 break;
114 }
115 }
116
117 if (prev != NULL) {
118 prev->Used(this, lhs);
119 if (prev->Deprecated()) {
120 if (needs_assign) {
121 rhs->SetDeprecated(prev->DeprecatedMessage());
122 }
123 }
124 }
125
126 LOG("Assign: %s=%s", lhs.c_str(), rhs->DebugString().c_str());
127 if (needs_assign) {
128 return rhs;
129 }
130 return NULL;
131 }
132
EvalAssign(const AssignStmt * stmt)133 void Evaluator::EvalAssign(const AssignStmt* stmt) {
134 loc_ = stmt->loc();
135 last_rule_ = NULL;
136 Symbol lhs = stmt->GetLhsSymbol(this);
137 if (lhs.empty())
138 Error("*** empty variable name.");
139
140 if (lhs == kati_readonly_) {
141 string rhs;
142 stmt->rhs->Eval(this, &rhs);
143 for (auto const& name : WordScanner(rhs)) {
144 Var* var = Intern(name).GetGlobalVar();
145 if (!var->IsDefined()) {
146 Error(
147 StringPrintf("*** unknown variable: %s", name.as_string().c_str()));
148 }
149 var->SetReadOnly();
150 }
151 return;
152 }
153
154 Var* rhs = EvalRHS(lhs, stmt->rhs, stmt->orig_rhs, stmt->op,
155 stmt->directive == AssignDirective::OVERRIDE);
156 if (rhs) {
157 bool readonly;
158 lhs.SetGlobalVar(rhs, stmt->directive == AssignDirective::OVERRIDE,
159 &readonly);
160 if (readonly) {
161 Error(StringPrintf("*** cannot assign to readonly variable: %s",
162 lhs.c_str()));
163 }
164 }
165 }
166
EvalRule(const RuleStmt * stmt)167 void Evaluator::EvalRule(const RuleStmt* stmt) {
168 loc_ = stmt->loc();
169 last_rule_ = NULL;
170
171 const string&& expr = stmt->expr->Eval(this);
172 // See semicolon.mk.
173 if (expr.find_first_not_of(" \t;") == string::npos) {
174 if (stmt->term == ';')
175 Error("*** missing rule before commands.");
176 return;
177 }
178
179 Rule* rule;
180 RuleVarAssignment rule_var;
181 function<string()> after_term_fn = [this, stmt]() {
182 return stmt->after_term ? stmt->after_term->Eval(this) : "";
183 };
184 ParseRule(loc_, expr, stmt->term, after_term_fn, &rule, &rule_var);
185
186 if (rule) {
187 if (stmt->term == ';') {
188 rule->cmds.push_back(stmt->after_term);
189 }
190
191 for (Symbol o : rule->outputs) {
192 if (o == posix_sym_)
193 is_posix_ = true;
194 }
195
196 LOG("Rule: %s", rule->DebugString().c_str());
197 rules_.push_back(rule);
198 last_rule_ = rule;
199 return;
200 }
201
202 Symbol lhs = Intern(rule_var.lhs);
203 for (Symbol output : rule_var.outputs) {
204 auto p = rule_vars_.emplace(output, nullptr);
205 if (p.second) {
206 p.first->second = new Vars;
207 }
208
209 Value* rhs = stmt->after_term;
210 if (!rule_var.rhs.empty()) {
211 Value* lit = NewLiteral(rule_var.rhs);
212 if (rhs) {
213 // TODO: We always insert two whitespaces around the
214 // terminator. Preserve whitespaces properly.
215 if (stmt->term == ';') {
216 rhs = NewExpr3(lit, NewLiteral(StringPiece(" ; ")), rhs);
217 } else {
218 rhs = NewExpr3(lit, NewLiteral(StringPiece(" = ")), rhs);
219 }
220 } else {
221 rhs = lit;
222 }
223 }
224
225 current_scope_ = p.first->second;
226
227 if (lhs == kati_readonly_) {
228 string rhs_value;
229 rhs->Eval(this, &rhs_value);
230 for (auto const& name : WordScanner(rhs_value)) {
231 Var* var = current_scope_->Lookup(Intern(name));
232 if (!var->IsDefined()) {
233 Error(StringPrintf("*** unknown variable: %s",
234 name.as_string().c_str()));
235 }
236 var->SetReadOnly();
237 }
238 current_scope_ = NULL;
239 continue;
240 }
241
242 Var* rhs_var = EvalRHS(lhs, rhs, StringPiece("*TODO*"), rule_var.op);
243 if (rhs_var) {
244 bool readonly;
245 current_scope_->Assign(lhs, new RuleVar(rhs_var, rule_var.op), &readonly);
246 if (readonly) {
247 Error(StringPrintf("*** cannot assign to readonly variable: %s",
248 lhs.c_str()));
249 }
250 }
251 current_scope_ = NULL;
252 }
253 }
254
EvalCommand(const CommandStmt * stmt)255 void Evaluator::EvalCommand(const CommandStmt* stmt) {
256 loc_ = stmt->loc();
257
258 if (!last_rule_) {
259 vector<Stmt*> stmts;
260 ParseNotAfterRule(stmt->orig, stmt->loc(), &stmts);
261 for (Stmt* a : stmts)
262 a->Eval(this);
263 return;
264 }
265
266 last_rule_->cmds.push_back(stmt->expr);
267 if (last_rule_->cmd_lineno == 0)
268 last_rule_->cmd_lineno = stmt->loc().lineno;
269 LOG("Command: %s", stmt->expr->DebugString().c_str());
270 }
271
EvalIf(const IfStmt * stmt)272 void Evaluator::EvalIf(const IfStmt* stmt) {
273 loc_ = stmt->loc();
274
275 bool is_true;
276 switch (stmt->op) {
277 case CondOp::IFDEF:
278 case CondOp::IFNDEF: {
279 string var_name;
280 stmt->lhs->Eval(this, &var_name);
281 Symbol lhs = Intern(TrimRightSpace(var_name));
282 if (lhs.str().find_first_of(" \t") != string::npos)
283 Error("*** invalid syntax in conditional.");
284 Var* v = LookupVarInCurrentScope(lhs);
285 is_true = (v->String().empty() == (stmt->op == CondOp::IFNDEF));
286 break;
287 }
288 case CondOp::IFEQ:
289 case CondOp::IFNEQ: {
290 const string&& lhs = stmt->lhs->Eval(this);
291 const string&& rhs = stmt->rhs->Eval(this);
292 is_true = ((lhs == rhs) == (stmt->op == CondOp::IFEQ));
293 break;
294 }
295 default:
296 CHECK(false);
297 abort();
298 }
299
300 const vector<Stmt*>* stmts;
301 if (is_true) {
302 stmts = &stmt->true_stmts;
303 } else {
304 stmts = &stmt->false_stmts;
305 }
306 for (Stmt* a : *stmts) {
307 LOG("%s", a->DebugString().c_str());
308 a->Eval(this);
309 }
310 }
311
DoInclude(const string & fname)312 void Evaluator::DoInclude(const string& fname) {
313 CheckStack();
314
315 Makefile* mk = MakefileCacheManager::Get()->ReadMakefile(fname);
316 if (!mk->Exists()) {
317 Error(StringPrintf("%s does not exist", fname.c_str()));
318 }
319
320 Var* var_list = LookupVar(Intern("MAKEFILE_LIST"));
321 var_list->AppendVar(this, NewLiteral(Intern(TrimLeadingCurdir(fname)).str()));
322 for (Stmt* stmt : mk->stmts()) {
323 LOG("%s", stmt->DebugString().c_str());
324 stmt->Eval(this);
325 }
326 }
327
EvalInclude(const IncludeStmt * stmt)328 void Evaluator::EvalInclude(const IncludeStmt* stmt) {
329 loc_ = stmt->loc();
330 last_rule_ = NULL;
331
332 const string&& pats = stmt->expr->Eval(this);
333 for (StringPiece pat : WordScanner(pats)) {
334 ScopedTerminator st(pat);
335 vector<string>* files;
336 Glob(pat.data(), &files);
337
338 if (stmt->should_exist) {
339 if (files->empty()) {
340 // TODO: Kati does not support building a missing include file.
341 Error(StringPrintf("%s: %s", pat.data(), strerror(errno)));
342 }
343 }
344
345 for (const string& fname : *files) {
346 if (!stmt->should_exist && g_flags.ignore_optional_include_pattern &&
347 Pattern(g_flags.ignore_optional_include_pattern).Match(fname)) {
348 continue;
349 }
350 DoInclude(fname);
351 }
352 }
353 }
354
EvalExport(const ExportStmt * stmt)355 void Evaluator::EvalExport(const ExportStmt* stmt) {
356 loc_ = stmt->loc();
357 last_rule_ = NULL;
358
359 const string&& exports = stmt->expr->Eval(this);
360 for (StringPiece tok : WordScanner(exports)) {
361 size_t equal_index = tok.find('=');
362 StringPiece lhs;
363 if (equal_index == string::npos) {
364 lhs = tok;
365 } else if (equal_index == 0 ||
366 (equal_index == 1 &&
367 (tok[0] == ':' || tok[0] == '?' || tok[0] == '+'))) {
368 // Do not export tokens after an assignment.
369 break;
370 } else {
371 StringPiece rhs;
372 AssignOp op;
373 ParseAssignStatement(tok, equal_index, &lhs, &rhs, &op);
374 }
375 Symbol sym = Intern(lhs);
376 exports_[sym] = stmt->is_export;
377
378 if (export_message_) {
379 const char* prefix = "";
380 if (!stmt->is_export) {
381 prefix = "un";
382 }
383
384 if (export_error_) {
385 Error(StringPrintf("*** %s: %sexport is obsolete%s.", sym.c_str(),
386 prefix, export_message_->c_str()));
387 } else {
388 WARN_LOC(loc(), "%s: %sexport has been deprecated%s.", sym.c_str(),
389 prefix, export_message_->c_str());
390 }
391 }
392 }
393 }
394
LookupVarGlobal(Symbol name)395 Var* Evaluator::LookupVarGlobal(Symbol name) {
396 Var* v = name.GetGlobalVar();
397 if (v->IsDefined())
398 return v;
399 used_undefined_vars_.insert(name);
400 return v;
401 }
402
LookupVar(Symbol name)403 Var* Evaluator::LookupVar(Symbol name) {
404 if (current_scope_) {
405 Var* v = current_scope_->Lookup(name);
406 if (v->IsDefined())
407 return v;
408 }
409 return LookupVarGlobal(name);
410 }
411
PeekVar(Symbol name)412 Var* Evaluator::PeekVar(Symbol name) {
413 if (current_scope_) {
414 Var* v = current_scope_->Peek(name);
415 if (v->IsDefined())
416 return v;
417 }
418 return name.PeekGlobalVar();
419 }
420
LookupVarInCurrentScope(Symbol name)421 Var* Evaluator::LookupVarInCurrentScope(Symbol name) {
422 if (current_scope_) {
423 return current_scope_->Lookup(name);
424 }
425 return LookupVarGlobal(name);
426 }
427
PeekVarInCurrentScope(Symbol name)428 Var* Evaluator::PeekVarInCurrentScope(Symbol name) {
429 if (current_scope_) {
430 return current_scope_->Peek(name);
431 }
432 return name.PeekGlobalVar();
433 }
434
EvalVar(Symbol name)435 string Evaluator::EvalVar(Symbol name) {
436 return LookupVar(name)->Eval(this);
437 }
438
GetShell()439 string Evaluator::GetShell() {
440 return EvalVar(kShellSym);
441 }
442
GetShellFlag()443 string Evaluator::GetShellFlag() {
444 // TODO: Handle $(.SHELLFLAGS)
445 return is_posix_ ? "-ec" : "-c";
446 }
447
GetShellAndFlag()448 string Evaluator::GetShellAndFlag() {
449 string shell = GetShell();
450 shell += ' ';
451 shell += GetShellFlag();
452 return shell;
453 }
454
Error(const string & msg)455 void Evaluator::Error(const string& msg) {
456 ERROR_LOC(loc_, "%s", msg.c_str());
457 }
458
DumpStackStats() const459 void Evaluator::DumpStackStats() const {
460 LOG_STAT("Max stack use: %zd bytes at %s:%d",
461 ((char*)stack_addr_ - (char*)lowest_stack_) + stack_size_,
462 LOCF(lowest_loc_));
463 }
464
465 unordered_set<Symbol> Evaluator::used_undefined_vars_;
466