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
Evaluator()33 Evaluator::Evaluator()
34 : last_rule_(NULL),
35 current_scope_(NULL),
36 avoid_io_(false),
37 eval_depth_(0) {
38 }
39
~Evaluator()40 Evaluator::~Evaluator() {
41 // delete vars_;
42 // for (auto p : rule_vars) {
43 // delete p.second;
44 // }
45 }
46
EvalRHS(Symbol lhs,Value * rhs_v,StringPiece orig_rhs,AssignOp op,bool is_override)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
EvalAssign(const AssignStmt * stmt)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
EvalRule(const RuleStmt * stmt)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
EvalCommand(const CommandStmt * stmt)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
EvalIf(const IfStmt * stmt)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
DoInclude(const string & fname)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
EvalInclude(const IncludeStmt * stmt)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
EvalExport(const ExportStmt * stmt)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
LookupVarGlobal(Symbol name)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
LookupVar(Symbol name)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
LookupVarInCurrentScope(Symbol name)302 Var* Evaluator::LookupVarInCurrentScope(Symbol name) {
303 if (current_scope_) {
304 return current_scope_->Lookup(name);
305 }
306 return LookupVarGlobal(name);
307 }
308
EvalVar(Symbol name)309 string Evaluator::EvalVar(Symbol name) {
310 return LookupVar(name)->Eval(this);
311 }
312
Error(const string & msg)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