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 } 39 40 Evaluator::~Evaluator() { 41 // delete vars_; 42 // for (auto p : rule_vars) { 43 // delete p.second; 44 // } 45 } 46 47 Var* Evaluator::EvalRHS(Symbol lhs, Value* rhs_v, StringPiece orig_rhs, 48 AssignOp op, bool is_override) { 49 VarOrigin origin = ( 50 (is_bootstrap_ ? VarOrigin::DEFAULT : 51 is_override ? VarOrigin::OVERRIDE : VarOrigin::FILE)); 52 53 Var* rhs = NULL; 54 bool needs_assign = true; 55 switch (op) { 56 case AssignOp::COLON_EQ: { 57 SimpleVar* sv = new SimpleVar(origin); 58 rhs_v->Eval(this, sv->mutable_value()); 59 rhs = sv; 60 break; 61 } 62 case AssignOp::EQ: 63 rhs = new RecursiveVar(rhs_v, origin, orig_rhs); 64 break; 65 case AssignOp::PLUS_EQ: { 66 Var* prev = LookupVarInCurrentScope(lhs); 67 if (!prev->IsDefined()) { 68 rhs = new RecursiveVar(rhs_v, origin, orig_rhs); 69 } else { 70 prev->AppendVar(this, rhs_v); 71 rhs = prev; 72 needs_assign = false; 73 } 74 break; 75 } 76 case AssignOp::QUESTION_EQ: { 77 Var* prev = LookupVarInCurrentScope(lhs); 78 if (!prev->IsDefined()) { 79 rhs = new RecursiveVar(rhs_v, origin, orig_rhs); 80 } else { 81 rhs = prev; 82 needs_assign = false; 83 } 84 break; 85 } 86 } 87 88 LOG("Assign: %s=%s", lhs.c_str(), rhs->DebugString().c_str()); 89 if (needs_assign) { 90 return rhs; 91 } 92 return NULL; 93 } 94 95 void Evaluator::EvalAssign(const AssignStmt* stmt) { 96 loc_ = stmt->loc(); 97 last_rule_ = NULL; 98 Symbol lhs = stmt->GetLhsSymbol(this); 99 if (lhs.empty()) 100 Error("*** empty variable name."); 101 Var* rhs = EvalRHS(lhs, stmt->rhs, stmt->orig_rhs, stmt->op, 102 stmt->directive == AssignDirective::OVERRIDE); 103 if (rhs) 104 lhs.SetGlobalVar(rhs); 105 } 106 107 void Evaluator::EvalRule(const RuleStmt* stmt) { 108 loc_ = stmt->loc(); 109 last_rule_ = NULL; 110 111 const string&& expr = stmt->expr->Eval(this); 112 // See semicolon.mk. 113 if (expr.find_first_not_of(" \t;") == string::npos) { 114 if (stmt->term == ';') 115 Error("*** missing rule before commands."); 116 return; 117 } 118 119 Rule* rule; 120 RuleVarAssignment rule_var; 121 ParseRule(loc_, expr, stmt->term, &rule, &rule_var); 122 123 if (rule) { 124 if (stmt->term == ';') { 125 rule->cmds.push_back(stmt->after_term); 126 } 127 128 LOG("Rule: %s", rule->DebugString().c_str()); 129 rules_.push_back(rule); 130 last_rule_ = rule; 131 return; 132 } 133 134 Symbol lhs = Intern(rule_var.lhs); 135 for (Symbol output : rule_var.outputs) { 136 auto p = rule_vars_.emplace(output, nullptr); 137 if (p.second) { 138 p.first->second = new Vars; 139 } 140 141 Value* rhs = stmt->after_term; 142 if (!rule_var.rhs.empty()) { 143 Value* lit = NewLiteral(rule_var.rhs); 144 if (rhs) { 145 // TODO: We always insert two whitespaces around the 146 // terminator. Preserve whitespaces properly. 147 if (stmt->term == ';') { 148 rhs = NewExpr3(lit, NewLiteral(StringPiece(" ; ")), rhs); 149 } else { 150 rhs = NewExpr3(lit, NewLiteral(StringPiece(" = ")), rhs); 151 } 152 } else { 153 rhs = lit; 154 } 155 } 156 157 current_scope_ = p.first->second; 158 Var* rhs_var = EvalRHS(lhs, rhs, StringPiece("*TODO*"), rule_var.op); 159 if (rhs_var) 160 current_scope_->Assign(lhs, new RuleVar(rhs_var, rule_var.op)); 161 current_scope_ = NULL; 162 } 163 } 164 165 void Evaluator::EvalCommand(const CommandStmt* stmt) { 166 loc_ = stmt->loc(); 167 168 if (!last_rule_) { 169 vector<Stmt*> stmts; 170 ParseNotAfterRule(stmt->orig, stmt->loc(), &stmts); 171 for (Stmt* a : stmts) 172 a->Eval(this); 173 return; 174 } 175 176 last_rule_->cmds.push_back(stmt->expr); 177 if (last_rule_->cmd_lineno == 0) 178 last_rule_->cmd_lineno = stmt->loc().lineno; 179 LOG("Command: %s", stmt->expr->DebugString().c_str()); 180 } 181 182 void Evaluator::EvalIf(const IfStmt* stmt) { 183 loc_ = stmt->loc(); 184 185 bool is_true; 186 switch (stmt->op) { 187 case CondOp::IFDEF: 188 case CondOp::IFNDEF: { 189 string var_name; 190 stmt->lhs->Eval(this, &var_name); 191 Symbol lhs = Intern(TrimRightSpace(var_name)); 192 if (lhs.str().find_first_of(" \t") != string::npos) 193 Error("*** invalid syntax in conditional."); 194 Var* v = LookupVarInCurrentScope(lhs); 195 const string&& s = v->Eval(this); 196 is_true = (s.empty() == (stmt->op == CondOp::IFNDEF)); 197 break; 198 } 199 case CondOp::IFEQ: 200 case CondOp::IFNEQ: { 201 const string&& lhs = stmt->lhs->Eval(this); 202 const string&& rhs = stmt->rhs->Eval(this); 203 is_true = ((lhs == rhs) == (stmt->op == CondOp::IFEQ)); 204 break; 205 } 206 default: 207 CHECK(false); 208 abort(); 209 } 210 211 const vector<Stmt*>* stmts; 212 if (is_true) { 213 stmts = &stmt->true_stmts; 214 } else { 215 stmts = &stmt->false_stmts; 216 } 217 for (Stmt* a : *stmts) { 218 LOG("%s", a->DebugString().c_str()); 219 a->Eval(this); 220 } 221 } 222 223 void Evaluator::DoInclude(const string& fname) { 224 Makefile* mk = MakefileCacheManager::Get()->ReadMakefile(fname); 225 CHECK(mk->Exists()); 226 227 Var* var_list = LookupVar(Intern("MAKEFILE_LIST")); 228 var_list->AppendVar(this, NewLiteral(Intern(TrimLeadingCurdir(fname)).str())); 229 for (Stmt* stmt : mk->stmts()) { 230 LOG("%s", stmt->DebugString().c_str()); 231 stmt->Eval(this); 232 } 233 } 234 235 void Evaluator::EvalInclude(const IncludeStmt* stmt) { 236 loc_ = stmt->loc(); 237 last_rule_ = NULL; 238 239 const string&& pats = stmt->expr->Eval(this); 240 for (StringPiece pat : WordScanner(pats)) { 241 ScopedTerminator st(pat); 242 vector<string>* files; 243 Glob(pat.data(), &files); 244 245 if (stmt->should_exist) { 246 if (files->empty()) { 247 // TOOD: Kati does not support building a missing include file. 248 Error(StringPrintf("%s: %s", pat.data(), strerror(errno))); 249 } 250 } 251 252 for (const string& fname : *files) { 253 if (!stmt->should_exist && g_flags.ignore_optional_include_pattern && 254 Pattern(g_flags.ignore_optional_include_pattern).Match(fname)) { 255 return; 256 } 257 DoInclude(fname); 258 } 259 } 260 } 261 262 void Evaluator::EvalExport(const ExportStmt* stmt) { 263 loc_ = stmt->loc(); 264 last_rule_ = NULL; 265 266 const string&& exports = stmt->expr->Eval(this); 267 for (StringPiece tok : WordScanner(exports)) { 268 size_t equal_index = tok.find('='); 269 if (equal_index == string::npos) { 270 exports_[Intern(tok)] = stmt->is_export; 271 } else if (equal_index == 0 || 272 (equal_index == 1 && 273 (tok[0] == ':' || tok[0] == '?' || tok[0] == '+'))) { 274 // Do not export tokens after an assignment. 275 break; 276 } else { 277 StringPiece lhs, rhs; 278 AssignOp op; 279 ParseAssignStatement(tok, equal_index, &lhs, &rhs, &op); 280 exports_[Intern(lhs)] = stmt->is_export; 281 } 282 } 283 } 284 285 Var* Evaluator::LookupVarGlobal(Symbol name) { 286 Var* v = name.GetGlobalVar(); 287 if (v->IsDefined()) 288 return v; 289 used_undefined_vars_.insert(name); 290 return v; 291 } 292 293 Var* Evaluator::LookupVar(Symbol name) { 294 if (current_scope_) { 295 Var* v = current_scope_->Lookup(name); 296 if (v->IsDefined()) 297 return v; 298 } 299 return LookupVarGlobal(name); 300 } 301 302 Var* Evaluator::LookupVarInCurrentScope(Symbol name) { 303 if (current_scope_) { 304 return current_scope_->Lookup(name); 305 } 306 return LookupVarGlobal(name); 307 } 308 309 string Evaluator::EvalVar(Symbol name) { 310 return LookupVar(name)->Eval(this); 311 } 312 313 void Evaluator::Error(const string& msg) { 314 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str()); 315 } 316 317 unordered_set<Symbol> Evaluator::used_undefined_vars_; 318