| // 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 |