|  | // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #include "vm/scopes.h" | 
|  | #include "platform/assert.h" | 
|  | #include "vm/unit_test.h" | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | ISOLATE_UNIT_TEST_CASE(LocalScope) { | 
|  | // Allocate a couple of local variables first. | 
|  | const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType()); | 
|  | const String& a = String::ZoneHandle(Symbols::New(thread, "a")); | 
|  | LocalVariable* var_a = new LocalVariable( | 
|  | TokenPosition::kNoSource, TokenPosition::kNoSource, a, dynamic_type); | 
|  | LocalVariable* inner_var_a = new LocalVariable( | 
|  | TokenPosition::kNoSource, TokenPosition::kNoSource, a, dynamic_type); | 
|  | const String& b = String::ZoneHandle(Symbols::New(thread, "b")); | 
|  | LocalVariable* var_b = new LocalVariable( | 
|  | TokenPosition::kNoSource, TokenPosition::kNoSource, b, dynamic_type); | 
|  | const String& c = String::ZoneHandle(Symbols::New(thread, "c")); | 
|  | LocalVariable* var_c = new LocalVariable( | 
|  | TokenPosition::kNoSource, TokenPosition::kNoSource, c, dynamic_type); | 
|  | const String& L = String::ZoneHandle(Symbols::New(thread, "L")); | 
|  | SourceLabel* label_L = | 
|  | new SourceLabel(TokenPosition::kNoSource, L, SourceLabel::kFor); | 
|  |  | 
|  | LocalScope* outer_scope = new LocalScope(NULL, 0, 0); | 
|  | LocalScope* inner_scope1 = new LocalScope(outer_scope, 0, 0); | 
|  | LocalScope* inner_scope2 = new LocalScope(outer_scope, 0, 0); | 
|  |  | 
|  | EXPECT(outer_scope->parent() == NULL); | 
|  | EXPECT_EQ(outer_scope, inner_scope1->parent()); | 
|  | EXPECT_EQ(outer_scope, inner_scope2->parent()); | 
|  | EXPECT_EQ(inner_scope2, outer_scope->child()); | 
|  | EXPECT_EQ(inner_scope1, inner_scope2->sibling()); | 
|  | EXPECT(inner_scope1->child() == NULL); | 
|  | EXPECT(inner_scope2->child() == NULL); | 
|  |  | 
|  | // Populate the local scopes as follows: | 
|  | // {  // outer_scope | 
|  | //   var a; | 
|  | //   {  // inner_scope1 | 
|  | //     var b; | 
|  | //   } | 
|  | //   L: {  // inner_scope2 | 
|  | //     var c; | 
|  | //   } | 
|  | // } | 
|  | EXPECT(outer_scope->AddVariable(var_a)); | 
|  | EXPECT(inner_scope1->AddVariable(var_b)); | 
|  | EXPECT(inner_scope2->AddVariable(var_c)); | 
|  | EXPECT(inner_scope2->AddLabel(label_L)); | 
|  | EXPECT(!outer_scope->AddVariable(var_a)); | 
|  |  | 
|  | // Check the simple layout above. | 
|  | EXPECT_EQ(var_a, outer_scope->LocalLookupVariable(a)); | 
|  | EXPECT_EQ(var_a, inner_scope1->LookupVariable(a, true)); | 
|  | EXPECT_EQ(label_L, inner_scope2->LookupLabel(L)); | 
|  | EXPECT(outer_scope->LocalLookupVariable(b) == NULL); | 
|  | EXPECT(inner_scope1->LocalLookupVariable(c) == NULL); | 
|  |  | 
|  | // Modify the local scopes to contain shadowing: | 
|  | // {  // outer_scope | 
|  | //   var a; | 
|  | //   {  // inner_scope1 | 
|  | //     var b; | 
|  | //     var a;  // inner_var_a | 
|  | //   } | 
|  | //   {  // inner_scope2 | 
|  | //     var c; | 
|  | //     L: ... | 
|  | //   } | 
|  | // } | 
|  | EXPECT(inner_scope1->AddVariable(inner_var_a)); | 
|  | EXPECT_EQ(inner_var_a, inner_scope1->LookupVariable(a, true)); | 
|  | EXPECT(inner_scope1->LookupVariable(a, true) != var_a); | 
|  |  | 
|  | // Modify the local scopes with access of an outer scope variable: | 
|  | // {  // outer_scope | 
|  | //   var a; | 
|  | //   {  // inner_scope1 | 
|  | //     var b; | 
|  | //     var a;  // inner_var_a | 
|  | //   } | 
|  | //   {  // inner_scope2 | 
|  | //     var c = a; | 
|  | //     L: ... | 
|  | //   } | 
|  | // } | 
|  | EXPECT(inner_scope2->LocalLookupVariable(a) == NULL); | 
|  | EXPECT(inner_scope2->AddVariable(var_a)); | 
|  | EXPECT_EQ(var_a, inner_scope2->LocalLookupVariable(a)); | 
|  |  | 
|  | EXPECT_EQ(1, outer_scope->num_variables()); | 
|  | EXPECT_EQ(2, inner_scope1->num_variables()); | 
|  | EXPECT_EQ(2, inner_scope2->num_variables()); | 
|  |  | 
|  | // Cannot depend on the order, but we should find the variables. | 
|  | EXPECT(outer_scope->VariableAt(0) == var_a); | 
|  | EXPECT((inner_scope1->VariableAt(0) == inner_var_a) || | 
|  | (inner_scope1->VariableAt(1) == inner_var_a)); | 
|  | EXPECT((inner_scope1->VariableAt(0) == var_b) || | 
|  | (inner_scope1->VariableAt(1) == var_b)); | 
|  | EXPECT((inner_scope2->VariableAt(0) == var_a) || | 
|  | (inner_scope2->VariableAt(1) == var_a) || | 
|  | (inner_scope2->VariableAt(2) == var_a)); | 
|  | EXPECT((inner_scope2->VariableAt(0) == var_c) || | 
|  | (inner_scope2->VariableAt(1) == var_c) || | 
|  | (inner_scope2->VariableAt(2) == var_c)); | 
|  | } | 
|  |  | 
|  | }  // namespace dart |