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