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 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 57 Evaluator::~Evaluator() { 58 // delete vars_; 59 // for (auto p : rule_vars) { 60 // delete p.second; 61 // } 62 } 63 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 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 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 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 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 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 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 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 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 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 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 421 Var* Evaluator::LookupVarInCurrentScope(Symbol name) { 422 if (current_scope_) { 423 return current_scope_->Lookup(name); 424 } 425 return LookupVarGlobal(name); 426 } 427 428 Var* Evaluator::PeekVarInCurrentScope(Symbol name) { 429 if (current_scope_) { 430 return current_scope_->Peek(name); 431 } 432 return name.PeekGlobalVar(); 433 } 434 435 string Evaluator::EvalVar(Symbol name) { 436 return LookupVar(name)->Eval(this); 437 } 438 439 string Evaluator::GetShell() { 440 return EvalVar(kShellSym); 441 } 442 443 string Evaluator::GetShellFlag() { 444 // TODO: Handle $(.SHELLFLAGS) 445 return is_posix_ ? "-ec" : "-c"; 446 } 447 448 string Evaluator::GetShellAndFlag() { 449 string shell = GetShell(); 450 shell += ' '; 451 shell += GetShellFlag(); 452 return shell; 453 } 454 455 void Evaluator::Error(const string& msg) { 456 ERROR_LOC(loc_, "%s", msg.c_str()); 457 } 458 459 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