OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "tools/gn/parse_tree.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/stl_util.h" | |
10 #include "base/strings/string_number_conversions.h" | |
11 #include "tools/gn/functions.h" | |
12 #include "tools/gn/operators.h" | |
13 #include "tools/gn/scope.h" | |
14 #include "tools/gn/string_utils.h" | |
15 | |
16 namespace { | |
17 | |
18 std::string IndentFor(int value) { | |
19 std::string ret; | |
20 for (int i = 0; i < value; i++) | |
21 ret.append(" "); | |
22 return ret; | |
23 } | |
24 | |
25 } // namespace | |
26 | |
27 ParseNode::ParseNode() { | |
28 } | |
29 | |
30 ParseNode::~ParseNode() { | |
31 } | |
32 | |
33 const AccessorNode* ParseNode::AsAccessor() const { return NULL; } | |
34 const BinaryOpNode* ParseNode::AsBinaryOp() const { return NULL; } | |
35 const BlockNode* ParseNode::AsBlock() const { return NULL; } | |
36 const ConditionNode* ParseNode::AsConditionNode() const { return NULL; } | |
37 const FunctionCallNode* ParseNode::AsFunctionCall() const { return NULL; } | |
38 const IdentifierNode* ParseNode::AsIdentifier() const { return NULL; } | |
39 const ListNode* ParseNode::AsList() const { return NULL; } | |
40 const LiteralNode* ParseNode::AsLiteral() const { return NULL; } | |
41 const UnaryOpNode* ParseNode::AsUnaryOp() const { return NULL; } | |
42 | |
43 // AccessorNode --------------------------------------------------------------- | |
44 | |
45 AccessorNode::AccessorNode() { | |
46 } | |
47 | |
48 AccessorNode::~AccessorNode() { | |
49 } | |
50 | |
51 const AccessorNode* AccessorNode::AsAccessor() const { | |
52 return this; | |
53 } | |
54 | |
55 Value AccessorNode::Execute(Scope* scope, Err* err) const { | |
56 Value index_value = index_->Execute(scope, err); | |
57 if (err->has_error()) | |
58 return Value(); | |
59 if (!index_value.VerifyTypeIs(Value::INTEGER, err)) | |
60 return Value(); | |
61 | |
62 const Value* base_value = scope->GetValue(base_.value(), true); | |
63 if (!base_value) { | |
64 *err = MakeErrorDescribing("Undefined identifier."); | |
65 return Value(); | |
66 } | |
67 if (!base_value->VerifyTypeIs(Value::LIST, err)) | |
68 return Value(); | |
69 | |
70 int64 index_int = index_value.int_value(); | |
71 if (index_int < 0) { | |
72 *err = Err(index_->GetRange(), "Negative array subscript.", | |
73 "You gave me " + base::Int64ToString(index_int) + "."); | |
74 return Value(); | |
75 } | |
76 size_t index_sizet = static_cast<size_t>(index_int); | |
77 if (index_sizet >= base_value->list_value().size()) { | |
78 *err = Err(index_->GetRange(), "Array subscript out of range.", | |
79 "You gave me " + base::Int64ToString(index_int) + | |
80 " but I was expecting something from 0 to " + | |
81 base::Int64ToString( | |
82 static_cast<int64>(base_value->list_value().size()) - 1) + | |
83 ", inclusive."); | |
84 return Value(); | |
85 } | |
86 | |
87 // Doing this assumes that there's no way in the language to do anything | |
88 // between the time the reference is created and the time that the reference | |
89 // is used. If there is, this will crash! Currently, this is just used for | |
90 // array accesses where this "shouldn't" happen. | |
91 return base_value->list_value()[index_sizet]; | |
92 } | |
93 | |
94 LocationRange AccessorNode::GetRange() const { | |
95 return LocationRange(base_.location(), index_->GetRange().end()); | |
96 } | |
97 | |
98 Err AccessorNode::MakeErrorDescribing(const std::string& msg, | |
99 const std::string& help) const { | |
100 return Err(GetRange(), msg, help); | |
101 } | |
102 | |
103 void AccessorNode::Print(std::ostream& out, int indent) const { | |
104 out << IndentFor(indent) << "ACCESSOR\n"; | |
105 out << IndentFor(indent + 1) << base_.value() << "\n"; | |
106 index_->Print(out, indent + 1); | |
107 } | |
108 | |
109 // BinaryOpNode --------------------------------------------------------------- | |
110 | |
111 BinaryOpNode::BinaryOpNode() { | |
112 } | |
113 | |
114 BinaryOpNode::~BinaryOpNode() { | |
115 } | |
116 | |
117 const BinaryOpNode* BinaryOpNode::AsBinaryOp() const { | |
118 return this; | |
119 } | |
120 | |
121 Value BinaryOpNode::Execute(Scope* scope, Err* err) const { | |
122 return ExecuteBinaryOperator(scope, this, left_.get(), right_.get(), err); | |
123 } | |
124 | |
125 LocationRange BinaryOpNode::GetRange() const { | |
126 return left_->GetRange().Union(right_->GetRange()); | |
127 } | |
128 | |
129 Err BinaryOpNode::MakeErrorDescribing(const std::string& msg, | |
130 const std::string& help) const { | |
131 return Err(op_, msg, help); | |
132 } | |
133 | |
134 void BinaryOpNode::Print(std::ostream& out, int indent) const { | |
135 out << IndentFor(indent) << "BINARY(" << op_.value() << ")\n"; | |
136 left_->Print(out, indent + 1); | |
137 right_->Print(out, indent + 1); | |
138 } | |
139 | |
140 // BlockNode ------------------------------------------------------------------ | |
141 | |
142 BlockNode::BlockNode(bool has_scope) | |
143 : has_scope_(has_scope), | |
144 begin_token_(NULL), | |
145 end_token_(NULL) { | |
146 } | |
147 | |
148 BlockNode::~BlockNode() { | |
149 STLDeleteContainerPointers(statements_.begin(), statements_.end()); | |
150 } | |
151 | |
152 const BlockNode* BlockNode::AsBlock() const { | |
153 return this; | |
154 } | |
155 | |
156 Value BlockNode::Execute(Scope* containing_scope, Err* err) const { | |
157 if (has_scope_) { | |
158 Scope our_scope(containing_scope); | |
159 Value ret = ExecuteBlockInScope(&our_scope, err); | |
160 if (err->has_error()) | |
161 return Value(); | |
162 | |
163 // Check for unused vars in the scope. | |
164 //our_scope.CheckForUnusedVars(err); | |
165 return ret; | |
166 } | |
167 return ExecuteBlockInScope(containing_scope, err); | |
168 } | |
169 | |
170 LocationRange BlockNode::GetRange() const { | |
171 if (begin_token_ && end_token_) { | |
172 return begin_token_->range().Union(end_token_->range()); | |
173 } | |
174 return LocationRange(); // TODO(brettw) indicate the entire file somehow. | |
175 } | |
176 | |
177 Err BlockNode::MakeErrorDescribing(const std::string& msg, | |
178 const std::string& help) const { | |
179 if (begin_token_) | |
180 return Err(*begin_token_, msg, help); | |
181 // TODO(brettw) this should have the beginning of the file in it or something. | |
182 return Err(Location(NULL, 1, 1), msg, help); | |
183 } | |
184 | |
185 void BlockNode::Print(std::ostream& out, int indent) const { | |
186 out << IndentFor(indent) << "BLOCK\n"; | |
187 for (size_t i = 0; i < statements_.size(); i++) | |
188 statements_[i]->Print(out, indent + 1); | |
189 } | |
190 | |
191 Value BlockNode::ExecuteBlockInScope(Scope* our_scope, Err* err) const { | |
192 for (size_t i = 0; i < statements_.size() && !err->has_error(); i++) { | |
193 // Check for trying to execute things with no side effects in a block. | |
194 const ParseNode* cur = statements_[i]; | |
195 if (cur->AsList() || cur->AsLiteral() || cur->AsUnaryOp() || | |
196 cur->AsIdentifier()) { | |
197 *err = cur->MakeErrorDescribing( | |
198 "This statment has no effect.", | |
199 "Either delete it or do something with the result."); | |
200 return Value(); | |
201 } | |
202 cur->Execute(our_scope, err); | |
203 } | |
204 return Value(); | |
205 } | |
206 | |
207 // ConditionNode -------------------------------------------------------------- | |
208 | |
209 ConditionNode::ConditionNode() { | |
210 } | |
211 | |
212 ConditionNode::~ConditionNode() { | |
213 } | |
214 | |
215 const ConditionNode* ConditionNode::AsConditionNode() const { | |
216 return this; | |
217 } | |
218 | |
219 Value ConditionNode::Execute(Scope* scope, Err* err) const { | |
220 Value condition_result = condition_->Execute(scope, err); | |
221 if (err->has_error()) | |
222 return Value(); | |
223 if (condition_result.type() == Value::NONE) { | |
224 *err = condition_->MakeErrorDescribing( | |
225 "This does not evaluate to a value.", | |
226 "Please give me something to work with for the if statement."); | |
227 err->AppendRange(if_token_.range()); | |
228 return Value(); | |
229 } | |
230 | |
231 if (condition_result.InterpretAsInt()) { | |
232 if_true_->ExecuteBlockInScope(scope, err); | |
233 } else if (if_false_) { | |
234 // The else block is optional. It's either another condition (for an | |
235 // "else if" and we can just Execute it and the condition will handle | |
236 // the scoping) or it's a block indicating an "else" in which ase we | |
237 // need to be sure it inherits our scope. | |
238 const BlockNode* if_false_block = if_false_->AsBlock(); | |
239 if (if_false_block) | |
240 if_false_block->ExecuteBlockInScope(scope, err); | |
241 else | |
242 if_false_->Execute(scope, err); | |
243 } | |
244 | |
245 return Value(); | |
246 } | |
247 | |
248 LocationRange ConditionNode::GetRange() const { | |
249 if (if_false_) | |
250 return if_token_.range().Union(if_false_->GetRange()); | |
251 return if_token_.range().Union(if_true_->GetRange()); | |
252 } | |
253 | |
254 Err ConditionNode::MakeErrorDescribing(const std::string& msg, | |
255 const std::string& help) const { | |
256 return Err(if_token_, msg, help); | |
257 } | |
258 | |
259 void ConditionNode::Print(std::ostream& out, int indent) const { | |
260 out << IndentFor(indent) << "CONDITION\n"; | |
261 condition_->Print(out, indent + 1); | |
262 if_true_->Print(out, indent + 1); | |
263 if (if_false_) | |
264 if_false_->Print(out, indent + 1); | |
265 } | |
266 | |
267 // FunctionCallNode ----------------------------------------------------------- | |
268 | |
269 FunctionCallNode::FunctionCallNode() { | |
270 } | |
271 | |
272 FunctionCallNode::~FunctionCallNode() { | |
273 } | |
274 | |
275 const FunctionCallNode* FunctionCallNode::AsFunctionCall() const { | |
276 return this; | |
277 } | |
278 | |
279 Value FunctionCallNode::Execute(Scope* scope, Err* err) const { | |
280 Value args = args_->Execute(scope, err); | |
281 if (err->has_error()) | |
282 return Value(); | |
283 return ExecuteFunction(scope, this, args.list_value(), block_.get(), err); | |
284 } | |
285 | |
286 LocationRange FunctionCallNode::GetRange() const { | |
287 if (block_) | |
288 return function_.range().Union(block_->GetRange()); | |
289 return function_.range().Union(args_->GetRange()); | |
290 } | |
291 | |
292 Err FunctionCallNode::MakeErrorDescribing(const std::string& msg, | |
293 const std::string& help) const { | |
294 return Err(function_, msg, help); | |
295 } | |
296 | |
297 void FunctionCallNode::Print(std::ostream& out, int indent) const { | |
298 out << IndentFor(indent) << "FUNCTION(" << function_.value() << ")\n"; | |
299 args_->Print(out, indent + 1); | |
300 if (block_) | |
301 block_->Print(out, indent + 1); | |
302 } | |
303 | |
304 // IdentifierNode -------------------------------------------------------------- | |
305 | |
306 IdentifierNode::IdentifierNode() { | |
307 } | |
308 | |
309 IdentifierNode::IdentifierNode(const Token& token) : value_(token) { | |
310 } | |
311 | |
312 IdentifierNode::~IdentifierNode() { | |
313 } | |
314 | |
315 const IdentifierNode* IdentifierNode::AsIdentifier() const { | |
316 return this; | |
317 } | |
318 | |
319 Value IdentifierNode::Execute(Scope* scope, Err* err) const { | |
320 const Value* result = scope->GetValue(value_.value(), true); | |
321 if (!result) { | |
322 *err = MakeErrorDescribing("Undefined identifier"); | |
323 return Value(); | |
324 } | |
325 return *result; | |
326 } | |
327 | |
328 LocationRange IdentifierNode::GetRange() const { | |
329 return value_.range(); | |
330 } | |
331 | |
332 Err IdentifierNode::MakeErrorDescribing(const std::string& msg, | |
333 const std::string& help) const { | |
334 return Err(value_, msg, help); | |
335 } | |
336 | |
337 void IdentifierNode::Print(std::ostream& out, int indent) const { | |
338 out << IndentFor(indent) << "IDENTIFIER(" << value_.value() << ")\n"; | |
339 } | |
340 | |
341 // ListNode ------------------------------------------------------------------- | |
342 | |
343 ListNode::ListNode() { | |
344 } | |
345 | |
346 ListNode::~ListNode() { | |
347 STLDeleteContainerPointers(contents_.begin(), contents_.end()); | |
348 } | |
349 | |
350 const ListNode* ListNode::AsList() const { | |
351 return this; | |
352 } | |
353 | |
354 Value ListNode::Execute(Scope* scope, Err* err) const { | |
355 Value result_value(this, Value::LIST); | |
356 std::vector<Value>& results = result_value.list_value(); | |
357 results.resize(contents_.size()); | |
358 | |
359 for (size_t i = 0; i < contents_.size(); i++) { | |
360 const ParseNode* cur = contents_[i]; | |
361 results[i] = cur->Execute(scope, err); | |
362 if (err->has_error()) | |
363 return Value(); | |
364 if (results[i].type() == Value::NONE) { | |
365 *err = cur->MakeErrorDescribing( | |
366 "This does not evaluate to a value.", | |
367 "I can't do something with nothing."); | |
368 return Value(); | |
369 } | |
370 } | |
371 return result_value; | |
372 } | |
373 | |
374 LocationRange ListNode::GetRange() const { | |
375 return LocationRange(begin_token_.location(), end_token_.location()); | |
376 } | |
377 | |
378 Err ListNode::MakeErrorDescribing(const std::string& msg, | |
379 const std::string& help) const { | |
380 return Err(begin_token_, msg, help); | |
381 } | |
382 | |
383 void ListNode::Print(std::ostream& out, int indent) const { | |
384 out << IndentFor(indent) << "LIST\n"; | |
385 for (size_t i = 0; i < contents_.size(); i++) | |
386 contents_[i]->Print(out, indent + 1); | |
387 } | |
388 | |
389 // LiteralNode ----------------------------------------------------------------- | |
390 | |
391 LiteralNode::LiteralNode() { | |
392 } | |
393 | |
394 LiteralNode::LiteralNode(const Token& token) : value_(token) { | |
395 } | |
396 | |
397 LiteralNode::~LiteralNode() { | |
398 } | |
399 | |
400 const LiteralNode* LiteralNode::AsLiteral() const { | |
401 return this; | |
402 } | |
403 | |
404 Value LiteralNode::Execute(Scope* scope, Err* err) const { | |
405 switch (value_.type()) { | |
406 case Token::INTEGER: { | |
407 int64 result_int; | |
408 if (!base::StringToInt64(value_.value(), &result_int)) { | |
409 *err = MakeErrorDescribing("This does not look like an integer"); | |
410 return Value(); | |
411 } | |
412 return Value(this, result_int); | |
413 } | |
414 case Token::STRING: { | |
415 // TODO(brettw) Unescaping probably needs to be moved & improved. | |
416 // The input value includes the quotes around the string, strip those | |
417 // off and unescape. | |
418 Value v(this, Value::STRING); | |
419 ExpandStringLiteral(scope, value_, &v, err); | |
420 return v; | |
421 } | |
422 default: | |
423 NOTREACHED(); | |
424 return Value(); | |
425 } | |
426 } | |
427 | |
428 LocationRange LiteralNode::GetRange() const { | |
429 return value_.range(); | |
430 } | |
431 | |
432 Err LiteralNode::MakeErrorDescribing(const std::string& msg, | |
433 const std::string& help) const { | |
434 return Err(value_, msg, help); | |
435 } | |
436 | |
437 void LiteralNode::Print(std::ostream& out, int indent) const { | |
438 out << IndentFor(indent) << "LITERAL(" << value_.value() << ")\n"; | |
439 } | |
440 | |
441 // UnaryOpNode ---------------------------------------------------------------- | |
442 | |
443 UnaryOpNode::UnaryOpNode() { | |
444 } | |
445 | |
446 UnaryOpNode::~UnaryOpNode() { | |
447 } | |
448 | |
449 const UnaryOpNode* UnaryOpNode::AsUnaryOp() const { | |
450 return this; | |
451 } | |
452 | |
453 Value UnaryOpNode::Execute(Scope* scope, Err* err) const { | |
454 Value operand_value = operand_->Execute(scope, err); | |
455 if (err->has_error()) | |
456 return Value(); | |
457 return ExecuteUnaryOperator(scope, this, operand_value, err); | |
458 } | |
459 | |
460 LocationRange UnaryOpNode::GetRange() const { | |
461 return op_.range().Union(operand_->GetRange()); | |
462 } | |
463 | |
464 Err UnaryOpNode::MakeErrorDescribing(const std::string& msg, | |
465 const std::string& help) const { | |
466 return Err(op_, msg, help); | |
467 } | |
468 | |
469 void UnaryOpNode::Print(std::ostream& out, int indent) const { | |
470 out << IndentFor(indent) << "UNARY(" << op_.value() << ")\n"; | |
471 operand_->Print(out, indent + 1); | |
472 } | |
OLD | NEW |