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 "expr.h"
18
19 #include <vector>
20
21 #include "eval.h"
22 #include "func.h"
23 #include "log.h"
24 #include "stringprintf.h"
25 #include "strutil.h"
26 #include "var.h"
27
Evaluable()28 Evaluable::Evaluable() {}
29
~Evaluable()30 Evaluable::~Evaluable() {}
31
Eval(Evaluator * ev) const32 string Evaluable::Eval(Evaluator* ev) const {
33 string s;
34 Eval(ev, &s);
35 return s;
36 }
37
Value()38 Value::Value() {}
39
~Value()40 Value::~Value() {}
41
DebugString(const Value * v)42 string Value::DebugString(const Value* v) {
43 return v ? NoLineBreak(v->DebugString_()) : "(null)";
44 }
45
46 class Literal : public Value {
47 public:
Literal(StringPiece s)48 explicit Literal(StringPiece s) : s_(s) {}
49
val() const50 StringPiece val() const { return s_; }
51
Eval(Evaluator * ev,string * s) const52 virtual void Eval(Evaluator* ev, string* s) const override {
53 ev->CheckStack();
54 s->append(s_.begin(), s_.end());
55 }
56
IsLiteral() const57 virtual bool IsLiteral() const override { return true; }
GetLiteralValueUnsafe() const58 virtual StringPiece GetLiteralValueUnsafe() const override { return s_; }
59
DebugString_() const60 virtual string DebugString_() const override { return s_.as_string(); }
61
62 private:
63 StringPiece s_;
64 };
65
66 class ValueList : public Value {
67 public:
ValueList()68 ValueList() {}
69
ValueList(Value * v1,Value * v2,Value * v3)70 ValueList(Value* v1, Value* v2, Value* v3) : ValueList() {
71 vals_.reserve(3);
72 vals_.push_back(v1);
73 vals_.push_back(v2);
74 vals_.push_back(v3);
75 }
76
ValueList(Value * v1,Value * v2)77 ValueList(Value* v1, Value* v2) : ValueList() {
78 vals_.reserve(2);
79 vals_.push_back(v1);
80 vals_.push_back(v2);
81 }
82
ValueList(vector<Value * > * values)83 ValueList(vector<Value*>* values) : ValueList() {
84 values->shrink_to_fit();
85 values->swap(vals_);
86 }
87
~ValueList()88 virtual ~ValueList() {
89 for (Value* v : vals_) {
90 delete v;
91 }
92 }
93
Eval(Evaluator * ev,string * s) const94 virtual void Eval(Evaluator* ev, string* s) const override {
95 ev->CheckStack();
96 for (Value* v : vals_) {
97 v->Eval(ev, s);
98 }
99 }
100
DebugString_() const101 virtual string DebugString_() const override {
102 string r;
103 for (Value* v : vals_) {
104 if (r.empty()) {
105 r += "ValueList(";
106 } else {
107 r += ", ";
108 }
109 r += DebugString(v);
110 }
111 if (!r.empty())
112 r += ")";
113 return r;
114 }
115
116 private:
117 vector<Value*> vals_;
118 };
119
120 class SymRef : public Value {
121 public:
SymRef(Symbol n)122 explicit SymRef(Symbol n) : name_(n) {}
~SymRef()123 virtual ~SymRef() {}
124
Eval(Evaluator * ev,string * s) const125 virtual void Eval(Evaluator* ev, string* s) const override {
126 ev->CheckStack();
127 Var* v = ev->LookupVar(name_);
128 v->Used(ev, name_);
129 v->Eval(ev, s);
130 }
131
DebugString_() const132 virtual string DebugString_() const override {
133 return StringPrintf("SymRef(%s)", name_.c_str());
134 }
135
136 private:
137 Symbol name_;
138 };
139
140 class VarRef : public Value {
141 public:
VarRef(Value * n)142 explicit VarRef(Value* n) : name_(n) {}
~VarRef()143 virtual ~VarRef() { delete name_; }
144
Eval(Evaluator * ev,string * s) const145 virtual void Eval(Evaluator* ev, string* s) const override {
146 ev->CheckStack();
147 ev->IncrementEvalDepth();
148 const string&& name = name_->Eval(ev);
149 ev->DecrementEvalDepth();
150 Symbol sym = Intern(name);
151 Var* v = ev->LookupVar(sym);
152 v->Used(ev, sym);
153 v->Eval(ev, s);
154 }
155
DebugString_() const156 virtual string DebugString_() const override {
157 return StringPrintf("VarRef(%s)", Value::DebugString(name_).c_str());
158 }
159
160 private:
161 Value* name_;
162 };
163
164 class VarSubst : public Value {
165 public:
VarSubst(Value * n,Value * p,Value * s)166 explicit VarSubst(Value* n, Value* p, Value* s)
167 : name_(n), pat_(p), subst_(s) {}
~VarSubst()168 virtual ~VarSubst() {
169 delete name_;
170 delete pat_;
171 delete subst_;
172 }
173
Eval(Evaluator * ev,string * s) const174 virtual void Eval(Evaluator* ev, string* s) const override {
175 ev->CheckStack();
176 ev->IncrementEvalDepth();
177 const string&& name = name_->Eval(ev);
178 Symbol sym = Intern(name);
179 Var* v = ev->LookupVar(sym);
180 const string&& pat_str = pat_->Eval(ev);
181 const string&& subst = subst_->Eval(ev);
182 ev->DecrementEvalDepth();
183 v->Used(ev, sym);
184 const string&& value = v->Eval(ev);
185 WordWriter ww(s);
186 Pattern pat(pat_str);
187 for (StringPiece tok : WordScanner(value)) {
188 ww.MaybeAddWhitespace();
189 pat.AppendSubstRef(tok, subst, s);
190 }
191 }
192
DebugString_() const193 virtual string DebugString_() const override {
194 return StringPrintf("VarSubst(%s:%s=%s)", Value::DebugString(name_).c_str(),
195 Value::DebugString(pat_).c_str(),
196 Value::DebugString(subst_).c_str());
197 }
198
199 private:
200 Value* name_;
201 Value* pat_;
202 Value* subst_;
203 };
204
205 class Func : public Value {
206 public:
Func(FuncInfo * fi)207 explicit Func(FuncInfo* fi) : fi_(fi) {}
208
~Func()209 ~Func() {
210 for (Value* a : args_)
211 delete a;
212 }
213
Eval(Evaluator * ev,string * s) const214 virtual void Eval(Evaluator* ev, string* s) const override {
215 ev->CheckStack();
216 LOG("Invoke func %s(%s)", name(), JoinValues(args_, ",").c_str());
217 ev->IncrementEvalDepth();
218 fi_->func(args_, ev, s);
219 ev->DecrementEvalDepth();
220 }
221
DebugString_() const222 virtual string DebugString_() const override {
223 return StringPrintf("Func(%s %s)", fi_->name,
224 JoinValues(args_, ",").c_str());
225 }
226
AddArg(Value * v)227 void AddArg(Value* v) { args_.push_back(v); }
228
name() const229 const char* name() const { return fi_->name; }
arity() const230 int arity() const { return fi_->arity; }
min_arity() const231 int min_arity() const { return fi_->min_arity; }
trim_space() const232 bool trim_space() const { return fi_->trim_space; }
trim_right_space_1st() const233 bool trim_right_space_1st() const { return fi_->trim_right_space_1st; }
234
235 private:
236 FuncInfo* fi_;
237 vector<Value*> args_;
238 };
239
CloseParen(char c)240 static char CloseParen(char c) {
241 switch (c) {
242 case '(':
243 return ')';
244 case '{':
245 return '}';
246 }
247 return 0;
248 }
249
SkipSpaces(StringPiece s,const char * terms)250 static size_t SkipSpaces(StringPiece s, const char* terms) {
251 for (size_t i = 0; i < s.size(); i++) {
252 char c = s[i];
253 if (strchr(terms, c))
254 return i;
255 if (!isspace(c)) {
256 if (c != '\\')
257 return i;
258 char n = s.get(i + 1);
259 if (n != '\r' && n != '\n')
260 return i;
261 }
262 }
263 return s.size();
264 }
265
NewExpr(Value * v1,Value * v2)266 Value* Value::NewExpr(Value* v1, Value* v2) {
267 return new ValueList(v1, v2);
268 }
269
NewExpr(Value * v1,Value * v2,Value * v3)270 Value* Value::NewExpr(Value* v1, Value* v2, Value* v3) {
271 return new ValueList(v1, v2, v3);
272 }
273
NewExpr(vector<Value * > * values)274 Value* Value::NewExpr(vector<Value*>* values) {
275 if (values->size() == 1) {
276 Value* v = (*values)[0];
277 values->clear();
278 return v;
279 }
280 return new ValueList(values);
281 }
282
NewLiteral(StringPiece s)283 Value* Value::NewLiteral(StringPiece s) {
284 return new Literal(s);
285 }
286
ShouldHandleComments(ParseExprOpt opt)287 bool ShouldHandleComments(ParseExprOpt opt) {
288 return opt != ParseExprOpt::DEFINE && opt != ParseExprOpt::COMMAND;
289 }
290
ParseFunc(const Loc & loc,Func * f,StringPiece s,size_t i,char * terms,size_t * index_out)291 void ParseFunc(const Loc& loc,
292 Func* f,
293 StringPiece s,
294 size_t i,
295 char* terms,
296 size_t* index_out) {
297 terms[1] = ',';
298 terms[2] = '\0';
299 i += SkipSpaces(s.substr(i), terms);
300 if (i == s.size()) {
301 *index_out = i;
302 return;
303 }
304
305 int nargs = 1;
306 while (true) {
307 if (f->arity() && nargs >= f->arity()) {
308 terms[1] = '\0'; // Drop ','.
309 }
310
311 if (f->trim_space()) {
312 for (; i < s.size(); i++) {
313 if (isspace(s[i]))
314 continue;
315 if (s[i] == '\\') {
316 char c = s.get(i + 1);
317 if (c == '\r' || c == '\n')
318 continue;
319 }
320 break;
321 }
322 }
323 const bool trim_right_space =
324 (f->trim_space() || (nargs == 1 && f->trim_right_space_1st()));
325 size_t n;
326 Value* v = ParseExprImpl(loc, s.substr(i), terms, ParseExprOpt::FUNC, &n,
327 trim_right_space);
328 // TODO: concatLine???
329 f->AddArg(v);
330 i += n;
331 if (i == s.size()) {
332 ERROR_LOC(loc,
333 "*** unterminated call to function '%s': "
334 "missing '%c'.",
335 f->name(), terms[0]);
336 }
337 nargs++;
338 if (s[i] == terms[0]) {
339 i++;
340 break;
341 }
342 i++; // Should be ','.
343 if (i == s.size())
344 break;
345 }
346
347 if (nargs <= f->min_arity()) {
348 ERROR_LOC(loc,
349 "*** insufficient number of arguments (%d) to function `%s'.",
350 nargs - 1, f->name());
351 }
352
353 *index_out = i;
354 return;
355 }
356
ParseDollar(const Loc & loc,StringPiece s,size_t * index_out)357 Value* ParseDollar(const Loc& loc, StringPiece s, size_t* index_out) {
358 CHECK(s.size() >= 2);
359 CHECK(s[0] == '$');
360 CHECK(s[1] != '$');
361
362 char cp = CloseParen(s[1]);
363 if (cp == 0) {
364 *index_out = 2;
365 return new SymRef(Intern(s.substr(1, 1)));
366 }
367
368 char terms[] = {cp, ':', ' ', 0};
369 for (size_t i = 2;;) {
370 size_t n;
371 Value* vname =
372 ParseExprImpl(loc, s.substr(i), terms, ParseExprOpt::NORMAL, &n);
373 i += n;
374 if (s[i] == cp) {
375 *index_out = i + 1;
376 if (vname->IsLiteral()) {
377 Literal* lit = static_cast<Literal*>(vname);
378 Symbol sym = Intern(lit->val());
379 if (g_flags.enable_kati_warnings) {
380 size_t found = sym.str().find_first_of(" ({");
381 if (found != string::npos) {
382 KATI_WARN_LOC(loc, "*warning*: variable lookup with '%c': %.*s",
383 sym.str()[found], SPF(s));
384 }
385 }
386 Value* r = new SymRef(sym);
387 delete lit;
388 return r;
389 }
390 return new VarRef(vname);
391 }
392
393 if (s[i] == ' ' || s[i] == '\\') {
394 // ${func ...}
395 if (vname->IsLiteral()) {
396 Literal* lit = static_cast<Literal*>(vname);
397 if (FuncInfo* fi = GetFuncInfo(lit->val())) {
398 delete lit;
399 Func* func = new Func(fi);
400 ParseFunc(loc, func, s, i + 1, terms, index_out);
401 return func;
402 } else {
403 KATI_WARN_LOC(loc, "*warning*: unknown make function '%.*s': %.*s",
404 SPF(lit->val()), SPF(s));
405 }
406 }
407
408 // Not a function. Drop ' ' from |terms| and parse it
409 // again. This is inefficient, but this code path should be
410 // rarely used.
411 delete vname;
412 terms[2] = 0;
413 i = 2;
414 continue;
415 }
416
417 if (s[i] == ':') {
418 terms[2] = '\0';
419 terms[1] = '=';
420 size_t n;
421 Value* pat =
422 ParseExprImpl(loc, s.substr(i + 1), terms, ParseExprOpt::NORMAL, &n);
423 i += 1 + n;
424 if (s[i] == cp) {
425 *index_out = i + 1;
426 return new VarRef(Value::NewExpr(vname, new Literal(":"), pat));
427 }
428
429 terms[1] = '\0';
430 Value* subst =
431 ParseExprImpl(loc, s.substr(i + 1), terms, ParseExprOpt::NORMAL, &n);
432 i += 1 + n;
433 *index_out = i + 1;
434 return new VarSubst(vname, pat, subst);
435 }
436
437 // GNU make accepts expressions like $((). See unmatched_paren*.mk
438 // for detail.
439 size_t found = s.find(cp);
440 if (found != string::npos) {
441 KATI_WARN_LOC(loc, "*warning*: unmatched parentheses: %.*s", SPF(s));
442 *index_out = s.size();
443 return new SymRef(Intern(s.substr(2, found - 2)));
444 }
445 ERROR_LOC(loc, "*** unterminated variable reference.");
446 }
447 }
448
ParseExprImpl(const Loc & loc,StringPiece s,const char * terms,ParseExprOpt opt,size_t * index_out,bool trim_right_space)449 Value* ParseExprImpl(const Loc& loc,
450 StringPiece s,
451 const char* terms,
452 ParseExprOpt opt,
453 size_t* index_out,
454 bool trim_right_space) {
455 if (s.get(s.size() - 1) == '\r')
456 s.remove_suffix(1);
457
458 size_t b = 0;
459 char save_paren = 0;
460 int paren_depth = 0;
461 size_t i;
462 vector<Value*> list;
463 for (i = 0; i < s.size(); i++) {
464 char c = s[i];
465 if (terms && strchr(terms, c) && !save_paren) {
466 break;
467 }
468
469 // Handle a comment.
470 if (!terms && c == '#' && ShouldHandleComments(opt)) {
471 if (i > b)
472 list.push_back(new Literal(s.substr(b, i - b)));
473 bool was_backslash = false;
474 for (; i < s.size() && !(s[i] == '\n' && !was_backslash); i++) {
475 was_backslash = !was_backslash && s[i] == '\\';
476 }
477 *index_out = i;
478 return Value::NewExpr(&list);
479 }
480
481 if (c == '$') {
482 if (i + 1 >= s.size()) {
483 break;
484 }
485
486 if (i > b)
487 list.push_back(new Literal(s.substr(b, i - b)));
488
489 if (s[i + 1] == '$') {
490 list.push_back(new Literal(StringPiece("$")));
491 i += 1;
492 b = i + 1;
493 continue;
494 }
495
496 if (terms && strchr(terms, s[i + 1])) {
497 *index_out = i + 1;
498 return Value::NewExpr(&list);
499 }
500
501 size_t n;
502 list.push_back(ParseDollar(loc, s.substr(i), &n));
503 i += n;
504 b = i;
505 i--;
506 continue;
507 }
508
509 if ((c == '(' || c == '{') && opt == ParseExprOpt::FUNC) {
510 char cp = CloseParen(c);
511 if (terms && terms[0] == cp) {
512 paren_depth++;
513 save_paren = cp;
514 terms++;
515 } else if (cp == save_paren) {
516 paren_depth++;
517 }
518 continue;
519 }
520
521 if (c == save_paren) {
522 paren_depth--;
523 if (paren_depth == 0) {
524 terms--;
525 save_paren = 0;
526 }
527 }
528
529 if (c == '\\' && i + 1 < s.size() && opt != ParseExprOpt::COMMAND) {
530 char n = s[i + 1];
531 if (n == '\\') {
532 i++;
533 continue;
534 }
535 if (n == '#' && ShouldHandleComments(opt)) {
536 list.push_back(new Literal(s.substr(b, i - b)));
537 i++;
538 b = i;
539 continue;
540 }
541 if (n == '\r' || n == '\n') {
542 if (terms && strchr(terms, ' ')) {
543 break;
544 }
545 if (i > b) {
546 list.push_back(new Literal(TrimRightSpace(s.substr(b, i - b))));
547 }
548 list.push_back(new Literal(StringPiece(" ")));
549 // Skip the current escaped newline
550 i += 2;
551 if (n == '\r' && s.get(i) == '\n')
552 i++;
553 // Then continue skipping escaped newlines, spaces, and tabs
554 for (; i < s.size(); i++) {
555 if (s[i] == '\\' && (s.get(i + 1) == '\r' || s.get(i + 1) == '\n')) {
556 i++;
557 continue;
558 }
559 if (s[i] != ' ' && s[i] != '\t') {
560 break;
561 }
562 }
563 b = i;
564 i--;
565 }
566 }
567 }
568
569 if (i > b) {
570 StringPiece rest = s.substr(b, i - b);
571 if (trim_right_space)
572 rest = TrimRightSpace(rest);
573 if (!rest.empty())
574 list.push_back(new Literal(rest));
575 }
576 *index_out = i;
577 return Value::NewExpr(&list);
578 }
579
ParseExpr(const Loc & loc,StringPiece s,ParseExprOpt opt)580 Value* ParseExpr(const Loc& loc, StringPiece s, ParseExprOpt opt) {
581 size_t n;
582 return ParseExprImpl(loc, s, NULL, opt, &n);
583 }
584
JoinValues(const vector<Value * > & vals,const char * sep)585 string JoinValues(const vector<Value*>& vals, const char* sep) {
586 vector<string> val_strs;
587 for (Value* v : vals) {
588 val_strs.push_back(Value::DebugString(v));
589 }
590 return JoinStrings(val_strs, sep);
591 }
592