| // 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); | |
| LocalScope* outer_scope = new LocalScope(nullptr, 0, 0); | |
| LocalScope* inner_scope1 = new LocalScope(outer_scope, 0, 0); | |
| LocalScope* inner_scope2 = new LocalScope(outer_scope, 0, 0); | |
| EXPECT(outer_scope->parent() == nullptr); | |
| 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() == nullptr); | |
| EXPECT(inner_scope2->child() == nullptr); | |
| // 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(!outer_scope->AddVariable(var_a)); | |
| // Check the simple layout above. | |
| EXPECT_EQ(var_a, outer_scope->LocalLookupVariable( | |
| a, LocalVariable::kNoKernelOffset)); | |
| EXPECT_EQ(var_a, inner_scope1->LookupVariable( | |
| a, LocalVariable::kNoKernelOffset, true)); | |
| EXPECT(outer_scope->LocalLookupVariable(b, LocalVariable::kNoKernelOffset) == | |
| nullptr); | |
| EXPECT(inner_scope1->LocalLookupVariable(c, LocalVariable::kNoKernelOffset) == | |
| nullptr); | |
| // 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, LocalVariable::kNoKernelOffset, true)); | |
| EXPECT(inner_scope1->LookupVariable(a, LocalVariable::kNoKernelOffset, | |
| 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, LocalVariable::kNoKernelOffset) == | |
| nullptr); | |
| EXPECT(inner_scope2->AddVariable(var_a)); | |
| EXPECT_EQ(var_a, inner_scope2->LocalLookupVariable( | |
| a, LocalVariable::kNoKernelOffset)); | |
| 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 |