• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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