blob: 2758b8da38b5d97c6a6c29c531d486fa5887cc68 [file] [log] [blame]
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09001#include "value.h"
2
3#include <vector>
4
5#include "eval.h"
6#include "func.h"
7#include "log.h"
8#include "stringprintf.h"
9#include "strutil.h"
10#include "var.h"
11
12Evaluable::Evaluable() {
13}
14
15Evaluable::~Evaluable() {
16}
17
18shared_ptr<string> Evaluable::Eval(Evaluator* ev) const {
19 shared_ptr<string> s = make_shared<string>();
20 Eval(ev, s.get());
21 return s;
22}
23
24Value::Value() {
25}
26
27Value::~Value() {
28}
29
30string Value::DebugString() const {
31 if (this) {
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090032 return NoLineBreak(DebugString_());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090033 }
34 return "(null)";
35}
36
37class Literal : public Value {
38 public:
39 explicit Literal(StringPiece s)
40 : s_(s) {
41 }
42
43 StringPiece val() const { return s_; }
44
45 virtual void Eval(Evaluator*, string* s) const override {
46 s->append(s_.begin(), s_.end());
47 }
48
49 virtual string DebugString_() const override {
50 return s_.as_string();
51 }
52
53 private:
54 StringPiece s_;
55};
56
57class Expr : public Value {
58 public:
59 Expr() {
60 }
61
62 virtual ~Expr() {
63 for (Value* v : vals_) {
64 delete v;
65 }
66 }
67
68 // Takes the ownership of |v|.
69 void AddValue(Value* v) {
70 vals_.push_back(v);
71 }
72
73 virtual void Eval(Evaluator* ev, string* s) const override {
74 for (Value* v : vals_) {
75 v->Eval(ev, s);
76 }
77 }
78
79 virtual string DebugString_() const override {
80 string r;
81 for (Value* v : vals_) {
82 if (r.empty()) {
83 r += "Expr(";
84 } else {
85 r += ", ";
86 }
87 r += v->DebugString();
88 }
89 r += ")";
90 return r;
91 }
92
93 virtual Value* Compact() {
94 if (vals_.size() != 1) {
95 return this;
96 }
97 Value* r = vals_[0];
98 vals_.clear();
99 delete this;
100 return r;
101 }
102
103 private:
104 vector<Value*> vals_;
105};
106
107class VarRef : public Value {
108 public:
109 explicit VarRef(Value* n)
110 : name_(n) {
111 }
112 virtual ~VarRef() {
113 delete name_;
114 }
115
116 virtual shared_ptr<string> Eval(Evaluator* ev) const override {
117 shared_ptr<string> name = name_->Eval(ev);
118 Var* v = ev->LookupVar(*name);
119 return v->Eval(ev);
120 }
121
122 virtual void Eval(Evaluator* ev, string* s) const override {
123 shared_ptr<string> name = name_->Eval(ev);
124 Var* v = ev->LookupVar(*name);
125 v->Eval(ev, s);
126 }
127
128 virtual string DebugString_() const override {
129 return StringPrintf("VarRef(%s)", name_->DebugString().c_str());
130 }
131
132 private:
133 Value* name_;
134};
135
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900136class VarSubst : public Value {
137 public:
138 explicit VarSubst(Value* n, Value* p, Value* s)
139 : name_(n), pat_(p), subst_(s) {
140 }
141 virtual ~VarSubst() {
142 delete name_;
143 delete pat_;
144 delete subst_;
145 }
146
147 virtual void Eval(Evaluator* ev, string* s) const override {
148 shared_ptr<string> name = name_->Eval(ev);
149 Var* v = ev->LookupVar(*name);
150 shared_ptr<string> value = v->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900151 shared_ptr<string> pat_str = pat_->Eval(ev);
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900152 shared_ptr<string> subst = subst_->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900153 WordWriter ww(s);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900154 Pattern pat(*pat_str);
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900155 for (StringPiece tok : WordScanner(*value)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900156 ww.MaybeAddWhitespace();
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900157 pat.AppendSubstRef(tok, *subst, s);
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900158 }
159 }
160
161 virtual string DebugString_() const override {
162 return StringPrintf("VarSubst(%s:%s=%s)",
163 name_->DebugString().c_str(),
164 pat_->DebugString().c_str(),
165 subst_->DebugString().c_str());
166 }
167
168 private:
169 Value* name_;
170 Value* pat_;
171 Value* subst_;
172};
173
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900174class Func : public Value {
175 public:
176 explicit Func(FuncInfo* fi)
177 : fi_(fi) {
178 }
179
Shinichiro Hamajid0e188e2015-06-16 18:53:01 +0900180 ~Func() {
181 for (Value* a : args_)
182 delete a;
183 }
184
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900185 virtual void Eval(Evaluator* ev, string* s) const override {
186 LOG("Invoke func %s(%s)", name(), JoinValues(args_, ",").c_str());
187 fi_->func(args_, ev, s);
188 }
189
190 virtual string DebugString_() const override {
191 return StringPrintf("Func(%s %s)",
192 fi_->name,
193 JoinValues(args_, ",").c_str());
194 }
195
196 void AddArg(Value* v) {
197 args_.push_back(v);
198 }
199
200 const char* name() const { return fi_->name; }
201 int arity() const { return fi_->arity; }
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900202 int min_arity() const { return fi_->min_arity; }
203 bool trim_space() const { return fi_->trim_space; }
204 bool trim_right_space_1st() const { return fi_->trim_right_space_1st; }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900205
206 private:
207 FuncInfo* fi_;
208 vector<Value*> args_;
209};
210
211static char CloseParen(char c) {
212 switch (c) {
213 case '(':
214 return ')';
215 case '{':
216 return '}';
217 }
218 return 0;
219}
220
221static size_t SkipSpaces(StringPiece s, const char* terms) {
222 for (size_t i = 0; i < s.size(); i++) {
223 char c = s[i];
224 if ((c != ' ' && c != '\t') || strchr(terms, c))
225 return i;
226 }
227 return s.size();
228}
229
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900230Value* ParseFunc(Func* f, StringPiece s, size_t i, char* terms,
231 size_t* index_out) {
232 terms[1] = ',';
233 terms[2] = '\0';
234 i += SkipSpaces(s.substr(i), terms);
235 if (i == s.size()) {
236 *index_out = i;
237 return f;
238 }
239
240 int nargs = 1;
241 while (true) {
242 if (f->arity() && nargs >= f->arity()) {
243 terms[1] = '\0'; // Drop ','.
244 }
245
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900246 if (f->trim_space()) {
247 while (i < s.size() && isspace(s[i]))
248 i++;
249 }
250 const bool trim_right_space = (f->trim_space() ||
251 (nargs == 1 && f->trim_right_space_1st()));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900252 size_t n;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900253 Value* v = ParseExprImpl(s.substr(i), terms, ParseExprOpt::NORMAL,
254 &n, trim_right_space);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900255 // TODO: concatLine???
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900256 f->AddArg(v);
257 i += n;
258 nargs++;
259 if (s[i] == terms[0]) {
260 i++;
261 break;
262 }
263 i++; // Should be ','.
264 if (i == s.size())
265 break;
266 }
267
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900268 if (nargs <= f->min_arity()) {
Shinichiro Hamaji81b2d0f2015-06-16 19:25:35 +0900269 // TODO: Show filename and line number.
270 ERROR("*** insufficient number of arguments (%d) to function `%s'.",
271 nargs - 1, f->name());
272 }
273
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900274 *index_out = i;
275 return f;
276}
277
278Value* ParseDollar(StringPiece s, size_t* index_out) {
279 CHECK(s.size() >= 2);
280 CHECK(s[0] == '$');
281 CHECK(s[1] != '$');
282
283 char cp = CloseParen(s[1]);
284 if (cp == 0) {
285 *index_out = 2;
286 return new VarRef(new Literal(s.substr(1, 1)));
287 }
288
289 char terms[] = {cp, ':', ' ', 0};
290 for (size_t i = 2;;) {
291 size_t n;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900292 Value* vname = ParseExprImpl(s.substr(i), terms, ParseExprOpt::NORMAL, &n);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900293 i += n;
294 if (s[i] == cp) {
295 *index_out = i + 1;
296 return new VarRef(vname);
297 }
298
299 if (s[i] == ' ') {
300 // ${func ...}
301 if (Literal* lit = reinterpret_cast<Literal*>(vname)) {
302 if (FuncInfo* fi = GetFuncInfo(lit->val())) {
Shinichiro Hamajid0e188e2015-06-16 18:53:01 +0900303 delete lit;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900304 Func* func = new Func(fi);
305 return ParseFunc(func, s, i+1, terms, index_out);
306 }
307 }
308
309 // Not a function. Drop ' ' from |terms| and parse it
310 // again. This is inefficient, but this code path should be
311 // rarely used.
312 delete vname;
313 terms[2] = 0;
314 i = 2;
315 continue;
316 }
317
318 if (s[i] == ':') {
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900319 terms[2] = '\0';
320 terms[1] = '=';
321 size_t n;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900322 Value* pat = ParseExprImpl(s.substr(i+1), terms, ParseExprOpt::NORMAL,
323 &n);
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900324 i += 1 + n;
325 if (s[i] == cp) {
326 Expr* v = new Expr;
327 v->AddValue(vname);
328 v->AddValue(new Literal(":"));
329 v->AddValue(pat);
330 return new VarRef(v);
331 }
332
333 terms[1] = '\0';
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900334 Value* subst = ParseExprImpl(s.substr(i+1), terms, ParseExprOpt::NORMAL,
335 &n);
Shinichiro Hamaji02fc55b2015-06-16 17:19:07 +0900336 i += 1 + n;
337 return new VarSubst(vname->Compact(), pat, subst);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900338 }
339
340 CHECK(false);
341 }
342}
343
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900344Value* ParseExprImpl(StringPiece s, const char* terms, ParseExprOpt opt,
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900345 size_t* index_out, bool trim_right_space) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900346 // TODO: A faulty optimization.
347#if 0
348 char specials[] = "$(){}\\\n";
349 size_t found = s.find_first_of(specials);
350 if (found == string::npos) {
351 *index_out = s.size();
352 return new Literal(s);
353 }
354 if (terms && strchr(terms, s[found])) {
355 *index_out = found;
356 return new Literal(s.substr(0, found));
357 }
358#endif
Shinichiro Hamaji47898a82015-06-19 16:45:33 +0900359 if (s.get(s.size() - 1) == '\r')
360 s.remove_suffix(1);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900361
362 Expr* r = new Expr;
363 size_t b = 0;
364 char save_paren = 0;
365 int paren_depth = 0;
366 size_t i;
367 for (i = 0; i < s.size(); i++) {
368 char c = s[i];
369 if (terms && strchr(terms, c)) {
370 break;
371 }
372
373 // Handle a comment.
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900374 if (!terms && c == '#' && opt == ParseExprOpt::NORMAL) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900375 if (i > b)
376 r->AddValue(new Literal(s.substr(b, i-b)));
377 bool was_backslash = false;
378 for (; i < s.size() && !(s[i] == '\n' && !was_backslash); i++) {
379 was_backslash = !was_backslash && s[i] == '\\';
380 }
381 *index_out = i;
382 return r->Compact();
383 }
384
385 if (c == '$') {
386 if (i + 1 >= s.size()) {
387 break;
388 }
389
390 if (i > b)
391 r->AddValue(new Literal(s.substr(b, i-b)));
392
393 if (s[i+1] == '$') {
394 r->AddValue(new Literal(STRING_PIECE("$")));
395 i += 2;
396 b = i;
397 continue;
398 }
399
400 if (terms && strchr(terms, s[i+1])) {
401 *index_out = i + 1;
402 return r->Compact();
403 }
404
405 size_t n;
406 Value* v = ParseDollar(s.substr(i), &n);
407 i += n;
408 b = i;
409 i--;
410 r->AddValue(v);
411 continue;
412 }
413
414 if (c == '(' || c == '{') {
415 char cp = CloseParen(c);
416 if (terms && terms[0] == cp) {
417 paren_depth++;
418 save_paren = cp;
419 terms++;
420 } else if (cp == save_paren) {
421 paren_depth++;
422 }
423 continue;
424 }
425
426 if (c == save_paren) {
427 paren_depth--;
428 if (paren_depth == 0) {
429 terms--;
430 save_paren = 0;
431 }
432 }
433
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900434 if (c == '\\' && i + 1 < s.size() && opt != ParseExprOpt::COMMAND) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900435 char n = s[i+1];
436 if (n == '\\') {
437 i++;
438 continue;
439 }
440 if (n == '\r' || n == '\n') {
Shinichiro Hamaji47898a82015-06-19 16:45:33 +0900441 if (i > b) {
442 r->AddValue(new Literal(s.substr(b, i-b)));
443 }
444 r->AddValue(new Literal(STRING_PIECE(" ")));
445 i++;
446 if (n == '\r' && s.get(i+1) == '\n')
447 i++;
448 b = i + 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900449 }
450 }
451 }
452
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900453 if (i > b) {
454 StringPiece rest = s.substr(b, i-b);
455 if (trim_right_space)
456 rest = TrimRightSpace(rest);
457 if (!rest.empty())
458 r->AddValue(new Literal(rest));
459 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900460 *index_out = i;
461 return r->Compact();
462}
463
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900464Value* ParseExpr(StringPiece s, ParseExprOpt opt) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900465 size_t n;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900466 return ParseExprImpl(s, NULL, opt, &n);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900467}
468
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900469Value* ParseExprUntilComma(StringPiece s, size_t* index_out) {
470 char terms[] = {',', '\0'};
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900471 return ParseExprImpl(s, terms, ParseExprOpt::NORMAL, index_out);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900472}
473
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900474string JoinValues(const vector<Value*>& vals, const char* sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900475 vector<string> val_strs;
476 for (Value* v : vals) {
477 val_strs.push_back(v->DebugString());
478 }
479 return JoinStrings(val_strs, sep);
480}
Shinichiro Hamaji4c469b32015-06-15 19:53:36 +0900481
Shinichiro Hamaji784b9952015-06-23 14:29:32 +0900482Value* NewExpr2(Value* v1, Value* v2) {
483 Expr* e = new Expr();
484 e->AddValue(v1);
485 e->AddValue(v2);
486 return e;
487}
488
Shinichiro Hamaji4c469b32015-06-15 19:53:36 +0900489Value* NewExpr3(Value* v1, Value* v2, Value* v3) {
490 Expr* e = new Expr();
491 e->AddValue(v1);
492 e->AddValue(v2);
493 e->AddValue(v3);
494 return e;
495}
496
Shinichiro Hamajib74b8902015-06-22 18:22:30 +0900497Value* NewLiteral(StringPiece s) {
Shinichiro Hamaji4c469b32015-06-15 19:53:36 +0900498 return new Literal(s);
499}