parse_tree.cc revision d3868032626d59662ff73b372b5d584c1d144c53
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 16namespace { 17 18std::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 27ParseNode::ParseNode() { 28} 29 30ParseNode::~ParseNode() { 31} 32 33const AccessorNode* ParseNode::AsAccessor() const { return NULL; } 34const BinaryOpNode* ParseNode::AsBinaryOp() const { return NULL; } 35const BlockNode* ParseNode::AsBlock() const { return NULL; } 36const ConditionNode* ParseNode::AsConditionNode() const { return NULL; } 37const FunctionCallNode* ParseNode::AsFunctionCall() const { return NULL; } 38const IdentifierNode* ParseNode::AsIdentifier() const { return NULL; } 39const ListNode* ParseNode::AsList() const { return NULL; } 40const LiteralNode* ParseNode::AsLiteral() const { return NULL; } 41const UnaryOpNode* ParseNode::AsUnaryOp() const { return NULL; } 42 43// AccessorNode --------------------------------------------------------------- 44 45AccessorNode::AccessorNode() { 46} 47 48AccessorNode::~AccessorNode() { 49} 50 51const AccessorNode* AccessorNode::AsAccessor() const { 52 return this; 53} 54 55Value 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 94LocationRange AccessorNode::GetRange() const { 95 return LocationRange(base_.location(), index_->GetRange().end()); 96} 97 98Err AccessorNode::MakeErrorDescribing(const std::string& msg, 99 const std::string& help) const { 100 return Err(GetRange(), msg, help); 101} 102 103void 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 111BinaryOpNode::BinaryOpNode() { 112} 113 114BinaryOpNode::~BinaryOpNode() { 115} 116 117const BinaryOpNode* BinaryOpNode::AsBinaryOp() const { 118 return this; 119} 120 121Value BinaryOpNode::Execute(Scope* scope, Err* err) const { 122 return ExecuteBinaryOperator(scope, this, left_.get(), right_.get(), err); 123} 124 125LocationRange BinaryOpNode::GetRange() const { 126 return left_->GetRange().Union(right_->GetRange()); 127} 128 129Err BinaryOpNode::MakeErrorDescribing(const std::string& msg, 130 const std::string& help) const { 131 return Err(op_, msg, help); 132} 133 134void 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 142BlockNode::BlockNode(bool has_scope) 143 : has_scope_(has_scope), 144 begin_token_(NULL), 145 end_token_(NULL) { 146} 147 148BlockNode::~BlockNode() { 149 STLDeleteContainerPointers(statements_.begin(), statements_.end()); 150} 151 152const BlockNode* BlockNode::AsBlock() const { 153 return this; 154} 155 156Value 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 170LocationRange 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 177Err 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 185void 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 191Value 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 209ConditionNode::ConditionNode() { 210} 211 212ConditionNode::~ConditionNode() { 213} 214 215const ConditionNode* ConditionNode::AsConditionNode() const { 216 return this; 217} 218 219Value 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 248LocationRange 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 254Err ConditionNode::MakeErrorDescribing(const std::string& msg, 255 const std::string& help) const { 256 return Err(if_token_, msg, help); 257} 258 259void 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 269FunctionCallNode::FunctionCallNode() { 270} 271 272FunctionCallNode::~FunctionCallNode() { 273} 274 275const FunctionCallNode* FunctionCallNode::AsFunctionCall() const { 276 return this; 277} 278 279Value 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 286LocationRange FunctionCallNode::GetRange() const { 287 if (block_) 288 return function_.range().Union(block_->GetRange()); 289 return function_.range().Union(args_->GetRange()); 290} 291 292Err FunctionCallNode::MakeErrorDescribing(const std::string& msg, 293 const std::string& help) const { 294 return Err(function_, msg, help); 295} 296 297void 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 306IdentifierNode::IdentifierNode() { 307} 308 309IdentifierNode::IdentifierNode(const Token& token) : value_(token) { 310} 311 312IdentifierNode::~IdentifierNode() { 313} 314 315const IdentifierNode* IdentifierNode::AsIdentifier() const { 316 return this; 317} 318 319Value 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 328LocationRange IdentifierNode::GetRange() const { 329 return value_.range(); 330} 331 332Err IdentifierNode::MakeErrorDescribing(const std::string& msg, 333 const std::string& help) const { 334 return Err(value_, msg, help); 335} 336 337void IdentifierNode::Print(std::ostream& out, int indent) const { 338 out << IndentFor(indent) << "IDENTIFIER(" << value_.value() << ")\n"; 339} 340 341// ListNode ------------------------------------------------------------------- 342 343ListNode::ListNode() { 344} 345 346ListNode::~ListNode() { 347 STLDeleteContainerPointers(contents_.begin(), contents_.end()); 348} 349 350const ListNode* ListNode::AsList() const { 351 return this; 352} 353 354Value 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 374LocationRange ListNode::GetRange() const { 375 return LocationRange(begin_token_.location(), end_token_.location()); 376} 377 378Err ListNode::MakeErrorDescribing(const std::string& msg, 379 const std::string& help) const { 380 return Err(begin_token_, msg, help); 381} 382 383void 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 391LiteralNode::LiteralNode() { 392} 393 394LiteralNode::LiteralNode(const Token& token) : value_(token) { 395} 396 397LiteralNode::~LiteralNode() { 398} 399 400const LiteralNode* LiteralNode::AsLiteral() const { 401 return this; 402} 403 404Value 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 428LocationRange LiteralNode::GetRange() const { 429 return value_.range(); 430} 431 432Err LiteralNode::MakeErrorDescribing(const std::string& msg, 433 const std::string& help) const { 434 return Err(value_, msg, help); 435} 436 437void LiteralNode::Print(std::ostream& out, int indent) const { 438 out << IndentFor(indent) << "LITERAL(" << value_.value() << ")\n"; 439} 440 441// UnaryOpNode ---------------------------------------------------------------- 442 443UnaryOpNode::UnaryOpNode() { 444} 445 446UnaryOpNode::~UnaryOpNode() { 447} 448 449const UnaryOpNode* UnaryOpNode::AsUnaryOp() const { 450 return this; 451} 452 453Value 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 460LocationRange UnaryOpNode::GetRange() const { 461 return op_.range().Union(operand_->GetRange()); 462} 463 464Err UnaryOpNode::MakeErrorDescribing(const std::string& msg, 465 const std::string& help) const { 466 return Err(op_, msg, help); 467} 468 469void UnaryOpNode::Print(std::ostream& out, int indent) const { 470 out << IndentFor(indent) << "UNARY(" << op_.value() << ")\n"; 471 operand_->Print(out, indent + 1); 472} 473