• 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 "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