1/* 2* The contents of this file are subject to the Netscape Public 3* License Version 1.1 (the "License"); you may not use this file 4* except in compliance with the License. You may obtain a copy of 5* the License at http://www.mozilla.org/NPL/ 6* 7* Software distributed under the License is distributed on an "AS 8* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 9* implied. See the License for the specific language governing 10* rights and limitations under the License. 11* 12* The Original Code is mozilla.org code. 13* 14* The Initial Developer of the Original Code is Netscape 15* Communications Corporation. Portions created by Netscape are 16* Copyright (C) 1998 Netscape Communications Corporation. All 17* Rights Reserved. 18* 19* Contributor(s): pschwartau@netscape.com, rogerl@netscape.com 20* Date: 28 May 2001 21* 22* SUMMARY: Functions are scoped statically, not dynamically 23* 24* See ECMA Section 10.1.4 Scope Chain and Identifier Resolution 25* (This section defines the scope chain of an execution context) 26* 27* See ECMA Section 12.10 The with Statement 28* 29* See ECMA Section 13 Function Definition 30* (This section defines the scope chain of a function object as that 31* of the running execution context when the function was declared) 32*/ 33//------------------------------------------------------------------------------------------------- 34var UBound = 0; 35var bug = '(none)'; 36var summary = 'Testing that functions are scoped statically, not dynamically'; 37var self = this; // capture a reference to the global object 38var status = ''; 39var statusitems = [ ]; 40var actual = ''; 41var actualvalues = [ ]; 42var expect= ''; 43var expectedvalues = [ ]; 44 45/* 46 * In this section the expected value is 1, not 2. 47 * 48 * Why? f captures its scope chain from when it's declared, and imposes that chain 49 * when it's executed. In other words, f's scope chain is from when it was compiled. 50 * Since f is a top-level function, this is the global object only. Hence 'a' resolves to 1. 51 */ 52status = 'Section A of test'; 53var a = 1; 54function f() 55{ 56 return a; 57} 58var obj = {a:2}; 59with (obj) 60{ 61 actual = f(); 62} 63expect = 1; 64addThis(); 65 66 67/* 68 * In this section the expected value is 2, not 1. That is because here 69 * f's associated scope chain now includes 'obj' before the global object. 70 */ 71status = 'Section B of test'; 72var a = 1; 73var obj = {a:2}; 74with (obj) 75{ 76 function f() 77 { 78 return a; 79 } 80 actual = f(); 81} 82// Mozilla result, which contradicts IE and the ECMA spec: expect = 2; 83expect = 1; 84addThis(); 85 86 87/* 88 * Like Section B , except that we call f outside the with block. 89 * By the principles explained above, we still expect 2 - 90 */ 91status = 'Section C of test'; 92var a = 1; 93var obj = {a:2}; 94with (obj) 95{ 96 function f() 97 { 98 return a; 99 } 100} 101actual = f(); 102// Mozilla result, which contradicts IE and the ECMA spec: expect = 2; 103expect = 1; 104addThis(); 105 106 107/* 108 * Like Section C, but with one more level of indirection - 109 */ 110status = 'Section D of test'; 111var a = 1; 112var obj = {a:2, obj:{a:3}}; 113with (obj) 114{ 115 with (obj) 116 { 117 function f() 118 { 119 return a; 120 } 121 } 122} 123actual = f(); 124// Mozilla result, which contradicts IE and the ECMA spec: expect = 3; 125expect = 1; 126addThis(); 127 128 129/* 130 * Like Section C, but here we actually delete obj before calling f. 131 * We still expect 2 - 132 */ 133status = 'Section E of test'; 134var a = 1; 135var obj = {a:2}; 136with (obj) 137{ 138 function f() 139 { 140 return a; 141 } 142} 143delete obj; 144actual = f(); 145// Mozilla result, which contradicts IE and the ECMA spec: expect = 2; 146expect = 1; 147addThis(); 148 149 150/* 151 * Like Section E. Here we redefine obj and call f under with (obj) - 152 * We still expect 2 - 153 */ 154status = 'Section F of test'; 155var a = 1; 156var obj = {a:2}; 157with (obj) 158{ 159 function f() 160 { 161 return a; 162 } 163} 164delete obj; 165var obj = {a:3}; 166with (obj) 167{ 168 actual = f(); 169} 170// Mozilla result, which contradicts IE and the ECMA spec: expect = 2; // NOT 3 !!! 171expect = 1; 172addThis(); 173 174 175/* 176 * Explicitly verify that f exists at global level, even though 177 * it was defined under the with(obj) block - 178 */ 179status = 'Section G of test'; 180var a = 1; 181var obj = {a:2}; 182with (obj) 183{ 184 function f() 185 { 186 return a; 187 } 188} 189actual = String([obj.hasOwnProperty('f'), self.hasOwnProperty('f')]); 190expect = String([false, true]); 191addThis(); 192 193 194/* 195 * Explicitly verify that f exists at global level, even though 196 * it was defined under the with(obj) block - 197 */ 198status = 'Section H of test'; 199var a = 1; 200var obj = {a:2}; 201with (obj) 202{ 203 function f() 204 { 205 return a; 206 } 207} 208actual = String(['f' in obj, 'f' in self]); 209expect = String([false, true]); 210addThis(); 211 212 213 214//------------------------------------------------------------------------------------------------- 215test(); 216//------------------------------------------------------------------------------------------------- 217 218 219function addThis() 220{ 221 statusitems[UBound] = status; 222 actualvalues[UBound] = actual; 223 expectedvalues[UBound] = expect; 224 UBound++; 225 resetTestVars(); 226} 227 228 229function resetTestVars() 230{ 231 delete a; 232 delete obj; 233 delete f; 234} 235 236 237function test() 238{ 239 enterFunc ('test'); 240 printBugNumber (bug); 241 printStatus (summary); 242 243 for (var i = 0; i < UBound; i++) 244 { 245 reportCompare(expectedvalues[i], actualvalues[i], statusitems[i]); 246 } 247 248 exitFunc ('test'); 249} 250