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