Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(633)

Side by Side Diff: runtime/vm/ast.cc

Issue 18649003: Partial solution to analyze potentially constant expressions (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/ast.h ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/ast.h" 5 #include "vm/ast.h"
6 #include "vm/compiler.h" 6 #include "vm/compiler.h"
7 #include "vm/dart_entry.h" 7 #include "vm/dart_entry.h"
8 #include "vm/isolate.h" 8 #include "vm/isolate.h"
9 #include "vm/object_store.h" 9 #include "vm/object_store.h"
10 #include "vm/resolver.h" 10 #include "vm/resolver.h"
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 } 103 }
104 104
105 105
106 void ArrayNode::VisitChildren(AstNodeVisitor* visitor) const { 106 void ArrayNode::VisitChildren(AstNodeVisitor* visitor) const {
107 for (intptr_t i = 0; i < this->length(); i++) { 107 for (intptr_t i = 0; i < this->length(); i++) {
108 ElementAt(i)->Visit(visitor); 108 ElementAt(i)->Visit(visitor);
109 } 109 }
110 } 110 }
111 111
112 112
113 bool LiteralNode::IsPotentiallyConst() const {
114 return true;
115 }
116
117
113 // TODO(srdjan): Add code for logical negation. 118 // TODO(srdjan): Add code for logical negation.
114 AstNode* LiteralNode::ApplyUnaryOp(Token::Kind unary_op_kind) { 119 AstNode* LiteralNode::ApplyUnaryOp(Token::Kind unary_op_kind) {
115 if (unary_op_kind == Token::kNEGATE) { 120 if (unary_op_kind == Token::kNEGATE) {
116 if (literal().IsSmi()) { 121 if (literal().IsSmi()) {
117 const Smi& smi = Smi::Cast(literal()); 122 const Smi& smi = Smi::Cast(literal());
118 const Instance& literal = 123 const Instance& literal =
119 Instance::ZoneHandle(Integer::New(-smi.Value())); 124 Instance::ZoneHandle(Integer::New(-smi.Value()));
120 return new LiteralNode(this->token_pos(), literal); 125 return new LiteralNode(this->token_pos(), literal);
121 } 126 }
122 if (literal().IsDouble()) { 127 if (literal().IsDouble()) {
(...skipping 15 matching lines...) Expand all
138 || Token::IsTypeTestOperator(kind_) 143 || Token::IsTypeTestOperator(kind_)
139 || Token::IsTypeCastOperator(kind_); 144 || Token::IsTypeCastOperator(kind_);
140 } 145 }
141 146
142 147
143 const char* ComparisonNode::Name() const { 148 const char* ComparisonNode::Name() const {
144 return Token::Str(kind_); 149 return Token::Str(kind_);
145 } 150 }
146 151
147 152
153 bool ComparisonNode::IsPotentiallyConst() const {
154 switch (kind_) {
155 case Token::kLT:
156 case Token::kGT:
157 case Token::kLTE:
158 case Token::kGTE:
159 case Token::kEQ:
160 case Token::kNE:
161 case Token::kEQ_STRICT:
162 case Token::kNE_STRICT:
163 return this->left()->IsPotentiallyConst() &&
164 this->right()->IsPotentiallyConst();
165 default:
166 return false;
167 }
168 }
169
170
148 const Instance* ComparisonNode::EvalConstExpr() const { 171 const Instance* ComparisonNode::EvalConstExpr() const {
149 const Instance* left_val = this->left()->EvalConstExpr(); 172 const Instance* left_val = this->left()->EvalConstExpr();
150 if (left_val == NULL) { 173 if (left_val == NULL) {
151 return NULL; 174 return NULL;
152 } 175 }
153 const Instance* right_val = this->right()->EvalConstExpr(); 176 const Instance* right_val = this->right()->EvalConstExpr();
154 if (right_val == NULL) { 177 if (right_val == NULL) {
155 return NULL; 178 return NULL;
156 } 179 }
157 switch (kind_) { 180 switch (kind_) {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 return false; 232 return false;
210 } 233 }
211 } 234 }
212 235
213 236
214 const char* BinaryOpNode::Name() const { 237 const char* BinaryOpNode::Name() const {
215 return Token::Str(kind_); 238 return Token::Str(kind_);
216 } 239 }
217 240
218 241
242 bool BinaryOpNode::IsPotentiallyConst() const {
243 switch (kind_) {
244 case Token::kADD:
245 case Token::kSUB:
246 case Token::kMUL:
247 case Token::kDIV:
248 case Token::kMOD:
249 case Token::kTRUNCDIV:
250 case Token::kBIT_OR:
251 case Token::kBIT_XOR:
252 case Token::kBIT_AND:
253 case Token::kSHL:
254 case Token::kSHR:
255 case Token::kOR:
256 case Token::kAND:
257 return this->left()->IsPotentiallyConst() &&
258 this->right()->IsPotentiallyConst();
259 default:
260 UNREACHABLE();
261 return false;
262 }
263 }
264
265
219 const Instance* BinaryOpNode::EvalConstExpr() const { 266 const Instance* BinaryOpNode::EvalConstExpr() const {
220 const Instance* left_val = this->left()->EvalConstExpr(); 267 const Instance* left_val = this->left()->EvalConstExpr();
221 if (left_val == NULL) { 268 if (left_val == NULL) {
222 return NULL; 269 return NULL;
223 } 270 }
224 if (!left_val->IsNumber() && !left_val->IsBool()) { 271 if (!left_val->IsNumber() && !left_val->IsBool()) {
225 return NULL; 272 return NULL;
226 } 273 }
227 const Instance* right_val = this->right()->EvalConstExpr(); 274 const Instance* right_val = this->right()->EvalConstExpr();
228 if (right_val == NULL) { 275 if (right_val == NULL) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 AstNode* new_operand = operand->ApplyUnaryOp(kind); 323 AstNode* new_operand = operand->ApplyUnaryOp(kind);
277 if (new_operand != NULL) { 324 if (new_operand != NULL) {
278 return new_operand; 325 return new_operand;
279 } 326 }
280 return new UnaryOpNode(token_pos, kind, operand); 327 return new UnaryOpNode(token_pos, kind, operand);
281 } 328 }
282 329
283 330
284 bool UnaryOpNode::IsKindValid() const { 331 bool UnaryOpNode::IsKindValid() const {
285 switch (kind_) { 332 switch (kind_) {
286 case Token::kADD:
287 case Token::kNEGATE: 333 case Token::kNEGATE:
288 case Token::kNOT: 334 case Token::kNOT:
289 case Token::kBIT_NOT: 335 case Token::kBIT_NOT:
290 return true; 336 return true;
291 default: 337 default:
292 return false; 338 return false;
293 } 339 }
294 } 340 }
295 341
296 342
343 bool UnaryOpNode::IsPotentiallyConst() const {
344 return this->operand()->IsPotentiallyConst();
345 }
346
347
297 const Instance* UnaryOpNode::EvalConstExpr() const { 348 const Instance* UnaryOpNode::EvalConstExpr() const {
298 const Instance* val = this->operand()->EvalConstExpr(); 349 const Instance* val = this->operand()->EvalConstExpr();
299 if (val == NULL) { 350 if (val == NULL) {
300 return NULL; 351 return NULL;
301 } 352 }
302 switch (kind_) { 353 switch (kind_) {
303 case Token::kADD:
304 case Token::kNEGATE: 354 case Token::kNEGATE:
305 return val->IsNumber() ? val : NULL; 355 return val->IsNumber() ? val : NULL;
306 case Token::kNOT: 356 case Token::kNOT:
307 return val->IsBool() ? val : NULL; 357 return val->IsBool() ? val : NULL;
308 case Token::kBIT_NOT: 358 case Token::kBIT_NOT:
309 return val->IsInteger() ? val : NULL; 359 return val->IsInteger() ? val : NULL;
310 default: 360 default:
311 return NULL; 361 return NULL;
312 } 362 }
313 } 363 }
314 364
315 365
366 bool ClosureNode::IsPotentiallyConst() const {
367 if (function().IsImplicitStaticClosureFunction()) {
368 return true;
369 }
370 return false;
371 }
372
373
316 const Instance* ClosureNode::EvalConstExpr() const { 374 const Instance* ClosureNode::EvalConstExpr() const {
317 if (function().IsImplicitStaticClosureFunction()) { 375 if (function().IsImplicitStaticClosureFunction()) {
318 // Return a value that represents an instance. Only the type is relevant. 376 // Return a value that represents an instance. Only the type is relevant.
319 return &Instance::Handle(); 377 return &Instance::Handle();
320 } 378 }
321 return NULL; 379 return NULL;
322 } 380 }
323 381
324 382
325 AstNode* ClosureNode::MakeAssignmentNode(AstNode* rhs) { 383 AstNode* ClosureNode::MakeAssignmentNode(AstNode* rhs) {
(...skipping 14 matching lines...) Expand all
340 const char* UnaryOpNode::Name() const { 398 const char* UnaryOpNode::Name() const {
341 return Token::Str(kind_); 399 return Token::Str(kind_);
342 } 400 }
343 401
344 402
345 const char* JumpNode::Name() const { 403 const char* JumpNode::Name() const {
346 return Token::Str(kind_); 404 return Token::Str(kind_);
347 } 405 }
348 406
349 407
408 bool LoadLocalNode::IsPotentiallyConst() const {
409 // Parameters of const constructors are implicitly final and can be
410 // used in initializer expressions.
411 // We can't check here whether the local variable is indeed a parameter,
412 // but this code is executed before any other local variables are
413 // added to the scope.
414 return local().is_final();
415 }
416
417
350 const Instance* LoadLocalNode::EvalConstExpr() const { 418 const Instance* LoadLocalNode::EvalConstExpr() const {
351 if (local().IsConst()) { 419 if (local().IsConst()) {
352 return local().ConstValue(); 420 return local().ConstValue();
353 } 421 }
354 return NULL; 422 return NULL;
355 } 423 }
356 424
357 425
358 AstNode* LoadLocalNode::MakeAssignmentNode(AstNode* rhs) { 426 AstNode* LoadLocalNode::MakeAssignmentNode(AstNode* rhs) {
359 if (local().is_final()) { 427 if (local().is_final()) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 const String& cls_name = String::Handle(cls.Name()); 508 const String& cls_name = String::Handle(cls.Name());
441 const String& func_name = String::Handle(function().name()); 509 const String& func_name = String::Handle(function().name());
442 if (cls_name.Equals(Symbols::NoSuchMethodError()) && 510 if (cls_name.Equals(Symbols::NoSuchMethodError()) &&
443 func_name.StartsWith(Symbols::ThrowNew())) { 511 func_name.StartsWith(Symbols::ThrowNew())) {
444 return this; 512 return this;
445 } 513 }
446 return NULL; 514 return NULL;
447 } 515 }
448 516
449 517
518 bool StaticGetterNode::IsPotentiallyConst() const {
519 const String& getter_name =
520 String::Handle(Field::GetterName(this->field_name()));
521 const Function& getter_func =
522 Function::Handle(this->cls().LookupStaticFunction(getter_name));
523 if (getter_func.IsNull() || !getter_func.is_const()) {
524 return false;
525 }
526 return true;
527 }
528
529
450 const Instance* StaticGetterNode::EvalConstExpr() const { 530 const Instance* StaticGetterNode::EvalConstExpr() const {
451 const String& getter_name = 531 const String& getter_name =
452 String::Handle(Field::GetterName(this->field_name())); 532 String::Handle(Field::GetterName(this->field_name()));
453 const Function& getter_func = 533 const Function& getter_func =
454 Function::Handle(this->cls().LookupStaticFunction(getter_name)); 534 Function::Handle(this->cls().LookupStaticFunction(getter_name));
455 if (getter_func.IsNull() || !getter_func.is_const()) { 535 if (getter_func.IsNull() || !getter_func.is_const()) {
456 return NULL; 536 return NULL;
457 } 537 }
458 const Object& result = Object::Handle( 538 const Object& result = Object::Handle(
459 DartEntry::InvokeFunction(getter_func, Object::empty_array())); 539 DartEntry::InvokeFunction(getter_func, Object::empty_array()));
460 if (result.IsError() || result.IsNull()) { 540 if (result.IsError() || result.IsNull()) {
461 // TODO(turnidge): We could get better error messages by returning 541 // TODO(turnidge): We could get better error messages by returning
462 // the Error object directly to the parser. This will involve 542 // the Error object directly to the parser. This will involve
463 // replumbing all of the EvalConstExpr methods. 543 // replumbing all of the EvalConstExpr methods.
464 return NULL; 544 return NULL;
465 } 545 }
466 return &Instance::ZoneHandle(Instance::Cast(result).raw()); 546 return &Instance::ZoneHandle(Instance::Cast(result).raw());
467 } 547 }
468 548
469 } // namespace dart 549 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/ast.h ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698