Allow access to scopes of suspended generator objects
The scopes of suspended generators can now be accessed through GeneratorMirror (similar to FrameMirror). BUG=v8:5235 Review-Url: https://codereview.chromium.org/2228393002 Cr-Commit-Position: refs/heads/master@{#38530}
This commit is contained in:
parent
a91811e192
commit
4cff8218b8
@ -125,6 +125,19 @@ ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
|
||||
UnwrapEvaluationContext();
|
||||
}
|
||||
|
||||
ScopeIterator::ScopeIterator(Isolate* isolate,
|
||||
Handle<JSGeneratorObject> generator)
|
||||
: isolate_(isolate),
|
||||
frame_inspector_(NULL),
|
||||
context_(generator->context()),
|
||||
seen_script_scope_(false),
|
||||
failed_(false) {
|
||||
if (!generator->function()->shared()->IsSubjectToDebugging()) {
|
||||
context_ = Handle<Context>();
|
||||
}
|
||||
UnwrapEvaluationContext();
|
||||
}
|
||||
|
||||
void ScopeIterator::UnwrapEvaluationContext() {
|
||||
while (true) {
|
||||
if (context_.is_null()) return;
|
||||
@ -623,6 +636,7 @@ bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info,
|
||||
bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info,
|
||||
Handle<String> variable_name,
|
||||
Handle<Object> new_value) {
|
||||
if (frame_inspector_ == nullptr) return false;
|
||||
JavaScriptFrame* frame = GetFrame();
|
||||
// Setting stack locals of optimized frames is not supported.
|
||||
if (frame->is_optimized()) return false;
|
||||
|
@ -43,6 +43,7 @@ class ScopeIterator {
|
||||
Option options = DEFAULT);
|
||||
|
||||
ScopeIterator(Isolate* isolate, Handle<JSFunction> function);
|
||||
ScopeIterator(Isolate* isolate, Handle<JSGeneratorObject> generator);
|
||||
|
||||
MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScopeDetails();
|
||||
|
||||
|
@ -1022,7 +1022,7 @@ FunctionMirror.prototype.scopeCount = function() {
|
||||
|
||||
FunctionMirror.prototype.scope = function(index) {
|
||||
if (this.resolved()) {
|
||||
return new ScopeMirror(UNDEFINED, this, index);
|
||||
return new ScopeMirror(UNDEFINED, this, UNDEFINED, index);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1451,6 +1451,27 @@ GeneratorMirror.prototype.receiver = function() {
|
||||
};
|
||||
|
||||
|
||||
GeneratorMirror.prototype.scopeCount = function() {
|
||||
// This value can change over time as the underlying generator is suspended
|
||||
// at different locations.
|
||||
return %GetGeneratorScopeCount(this.value());
|
||||
};
|
||||
|
||||
|
||||
GeneratorMirror.prototype.scope = function(index) {
|
||||
return new ScopeMirror(UNDEFINED, UNDEFINED, this, index);
|
||||
};
|
||||
|
||||
|
||||
GeneratorMirror.prototype.allScopes = function() {
|
||||
var scopes = [];
|
||||
for (let i = 0; i < this.scopeCount(); i++) {
|
||||
scopes.push(this.scope(i));
|
||||
}
|
||||
return scopes;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base mirror object for properties.
|
||||
* @param {ObjectMirror} mirror The mirror object having this property
|
||||
@ -1973,7 +1994,7 @@ FrameMirror.prototype.scopeCount = function() {
|
||||
|
||||
|
||||
FrameMirror.prototype.scope = function(index) {
|
||||
return new ScopeMirror(this, UNDEFINED, index);
|
||||
return new ScopeMirror(this, UNDEFINED, UNDEFINED, index);
|
||||
};
|
||||
|
||||
|
||||
@ -1984,7 +2005,8 @@ FrameMirror.prototype.allScopes = function(opt_ignore_nested_scopes) {
|
||||
!!opt_ignore_nested_scopes);
|
||||
var result = [];
|
||||
for (var i = 0; i < scopeDetails.length; ++i) {
|
||||
result.push(new ScopeMirror(this, UNDEFINED, i, scopeDetails[i]));
|
||||
result.push(new ScopeMirror(this, UNDEFINED, UNDEFINED, i,
|
||||
scopeDetails[i]));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
@ -2163,7 +2185,7 @@ var kScopeDetailsStartPositionIndex = 3;
|
||||
var kScopeDetailsEndPositionIndex = 4;
|
||||
var kScopeDetailsFunctionIndex = 5;
|
||||
|
||||
function ScopeDetails(frame, fun, index, opt_details) {
|
||||
function ScopeDetails(frame, fun, gen, index, opt_details) {
|
||||
if (frame) {
|
||||
this.break_id_ = frame.break_id_;
|
||||
this.details_ = opt_details ||
|
||||
@ -2173,10 +2195,15 @@ function ScopeDetails(frame, fun, index, opt_details) {
|
||||
index);
|
||||
this.frame_id_ = frame.details_.frameId();
|
||||
this.inlined_frame_id_ = frame.details_.inlinedFrameIndex();
|
||||
} else {
|
||||
} else if (fun) {
|
||||
this.details_ = opt_details || %GetFunctionScopeDetails(fun.value(), index);
|
||||
this.fun_value_ = fun.value();
|
||||
this.break_id_ = UNDEFINED;
|
||||
} else {
|
||||
this.details_ =
|
||||
opt_details || %GetGeneratorScopeDetails(gen.value(), index);
|
||||
this.gen_value_ = gen.value();
|
||||
this.break_id_ = UNDEFINED;
|
||||
}
|
||||
this.index_ = index;
|
||||
}
|
||||
@ -2235,9 +2262,12 @@ ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) {
|
||||
%CheckExecutionState(this.break_id_);
|
||||
raw_res = %SetScopeVariableValue(this.break_id_, this.frame_id_,
|
||||
this.inlined_frame_id_, this.index_, name, new_value);
|
||||
} else {
|
||||
} else if (!IS_UNDEFINED(this.fun_value_)) {
|
||||
raw_res = %SetScopeVariableValue(this.fun_value_, null, null, this.index_,
|
||||
name, new_value);
|
||||
} else {
|
||||
raw_res = %SetScopeVariableValue(this.gen_value_, null, null, this.index_,
|
||||
name, new_value);
|
||||
}
|
||||
if (!raw_res) throw %make_error(kDebugger, "Failed to set variable value");
|
||||
};
|
||||
@ -2248,12 +2278,13 @@ ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) {
|
||||
* be specified.
|
||||
* @param {FrameMirror} frame The frame this scope is a part of
|
||||
* @param {FunctionMirror} function The function this scope is a part of
|
||||
* @param {GeneratorMirror} gen The generator this scope is a part of
|
||||
* @param {number} index The scope index in the frame
|
||||
* @param {Array=} opt_details Raw scope details data
|
||||
* @constructor
|
||||
* @extends Mirror
|
||||
*/
|
||||
function ScopeMirror(frame, fun, index, opt_details) {
|
||||
function ScopeMirror(frame, fun, gen, index, opt_details) {
|
||||
%_Call(Mirror, this, MirrorType.SCOPE_TYPE);
|
||||
if (frame) {
|
||||
this.frame_index_ = frame.index_;
|
||||
@ -2261,7 +2292,7 @@ function ScopeMirror(frame, fun, index, opt_details) {
|
||||
this.frame_index_ = UNDEFINED;
|
||||
}
|
||||
this.scope_index_ = index;
|
||||
this.details_ = new ScopeDetails(frame, fun, index, opt_details);
|
||||
this.details_ = new ScopeDetails(frame, fun, gen, index, opt_details);
|
||||
}
|
||||
inherits(ScopeMirror, Mirror);
|
||||
|
||||
|
@ -919,6 +919,48 @@ RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
|
||||
RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails());
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
|
||||
if (!args[0]->IsJSGeneratorObject()) return Smi::FromInt(0);
|
||||
|
||||
// Check arguments.
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
|
||||
|
||||
// Count the visible scopes.
|
||||
int n = 0;
|
||||
for (ScopeIterator it(isolate, gen); !it.Done(); it.Next()) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return Smi::FromInt(n);
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
|
||||
if (!args[0]->IsJSGeneratorObject()) {
|
||||
return *isolate->factory()->undefined_value();
|
||||
}
|
||||
|
||||
// Check arguments.
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
|
||||
CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
|
||||
|
||||
// Find the requested scope.
|
||||
int n = 0;
|
||||
ScopeIterator it(isolate, gen);
|
||||
for (; !it.Done() && n < index; it.Next()) {
|
||||
n++;
|
||||
}
|
||||
if (it.Done()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails());
|
||||
}
|
||||
|
||||
static bool SetScopeVariableValue(ScopeIterator* it, int index,
|
||||
Handle<String> variable_name,
|
||||
@ -967,10 +1009,14 @@ RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
|
||||
|
||||
ScopeIterator it(isolate, &frame_inspector);
|
||||
res = SetScopeVariableValue(&it, index, variable_name, new_value);
|
||||
} else {
|
||||
} else if (args[0]->IsJSFunction()) {
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
|
||||
ScopeIterator it(isolate, fun);
|
||||
res = SetScopeVariableValue(&it, index, variable_name, new_value);
|
||||
} else {
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
|
||||
ScopeIterator it(isolate, gen);
|
||||
res = SetScopeVariableValue(&it, index, variable_name, new_value);
|
||||
}
|
||||
|
||||
return isolate->heap()->ToBoolean(res);
|
||||
|
@ -156,6 +156,8 @@ namespace internal {
|
||||
F(GetAllScopesDetails, 4, 1) \
|
||||
F(GetFunctionScopeCount, 1, 1) \
|
||||
F(GetFunctionScopeDetails, 2, 1) \
|
||||
F(GetGeneratorScopeCount, 1, 1) \
|
||||
F(GetGeneratorScopeDetails, 2, 1) \
|
||||
F(SetScopeVariableValue, 6, 1) \
|
||||
F(DebugPrintScopes, 0, 1) \
|
||||
F(SetBreakPointsActive, 1, 1) \
|
||||
|
470
test/mjsunit/debug-scopes-suspended-generators.js
Normal file
470
test/mjsunit/debug-scopes-suspended-generators.js
Normal file
@ -0,0 +1,470 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --expose-debug-as debug --allow-natives-syntax --ignition
|
||||
// The functions used for testing backtraces. They are at the top to make the
|
||||
// testing of source line/column easier.
|
||||
|
||||
// Get the Debug object exposed from the debug context global object.
|
||||
var Debug = debug.Debug;
|
||||
|
||||
var test_name;
|
||||
var exception;
|
||||
var begin_test_count = 0;
|
||||
var end_test_count = 0;
|
||||
|
||||
// Initialize for a new test.
|
||||
function BeginTest(name) {
|
||||
test_name = name;
|
||||
exception = null;
|
||||
begin_test_count++;
|
||||
}
|
||||
|
||||
// Check result of a test.
|
||||
function EndTest() {
|
||||
assertNull(exception, test_name + " / " + exception);
|
||||
end_test_count++;
|
||||
}
|
||||
|
||||
// Check that two scope are the same.
|
||||
function assertScopeMirrorEquals(scope1, scope2) {
|
||||
assertEquals(scope1.scopeType(), scope2.scopeType());
|
||||
assertEquals(scope1.frameIndex(), scope2.frameIndex());
|
||||
assertEquals(scope1.scopeIndex(), scope2.scopeIndex());
|
||||
assertPropertiesEqual(scope1.scopeObject().value(),
|
||||
scope2.scopeObject().value());
|
||||
}
|
||||
|
||||
// Check that the scope chain contains the expected types of scopes.
|
||||
function CheckScopeChain(scopes, gen_mirror) {
|
||||
var all_scopes = gen_mirror.allScopes();
|
||||
assertEquals(scopes.length, gen_mirror.scopeCount());
|
||||
assertEquals(scopes.length, all_scopes.length,
|
||||
"FrameMirror.allScopes length");
|
||||
for (var i = 0; i < scopes.length; i++) {
|
||||
var scope = gen_mirror.scope(i);
|
||||
assertTrue(scope.isScope());
|
||||
assertEquals(scopes[i], scope.scopeType(),
|
||||
`Scope ${i} has unexpected type`);
|
||||
assertScopeMirrorEquals(all_scopes[i], scope);
|
||||
|
||||
// Check the global object when hitting the global scope.
|
||||
if (scopes[i] == debug.ScopeType.Global) {
|
||||
// Objects don't have same class (one is "global", other is "Object",
|
||||
// so just check the properties directly.
|
||||
assertPropertiesEqual(this, scope.scopeObject().value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the content of the scope is as expected. For functions just check
|
||||
// that there is a function.
|
||||
function CheckScopeContent(content, number, gen_mirror) {
|
||||
var scope = gen_mirror.scope(number);
|
||||
var count = 0;
|
||||
for (var p in content) {
|
||||
var property_mirror = scope.scopeObject().property(p);
|
||||
assertFalse(property_mirror.isUndefined(),
|
||||
'property ' + p + ' not found in scope');
|
||||
if (typeof(content[p]) === 'function') {
|
||||
assertTrue(property_mirror.value().isFunction());
|
||||
} else {
|
||||
assertEquals(content[p], property_mirror.value().value(),
|
||||
'property ' + p + ' has unexpected value');
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
// 'arguments' and might be exposed in the local and closure scope. Just
|
||||
// ignore this.
|
||||
var scope_size = scope.scopeObject().properties().length;
|
||||
if (!scope.scopeObject().property('arguments').isUndefined()) {
|
||||
scope_size--;
|
||||
}
|
||||
// Ditto for 'this'.
|
||||
if (!scope.scopeObject().property('this').isUndefined()) {
|
||||
scope_size--;
|
||||
}
|
||||
// Temporary variables introduced by the parser have not been materialized.
|
||||
assertTrue(scope.scopeObject().property('').isUndefined());
|
||||
|
||||
if (count != scope_size) {
|
||||
print('Names found in scope:');
|
||||
var names = scope.scopeObject().propertyNames();
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
print(names[i]);
|
||||
}
|
||||
}
|
||||
assertEquals(count, scope_size);
|
||||
}
|
||||
|
||||
// Simple empty closure scope.
|
||||
|
||||
function *gen1() {
|
||||
yield 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
var g = gen1();
|
||||
var gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({}, 0, gm);
|
||||
|
||||
// Closure scope with a parameter.
|
||||
|
||||
function *gen2(a) {
|
||||
yield a;
|
||||
return 2;
|
||||
}
|
||||
|
||||
g = gen2(42);
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({a: 42}, 0, gm);
|
||||
|
||||
// Closure scope with a parameter.
|
||||
|
||||
function *gen3(a) {
|
||||
var b = 1
|
||||
yield a;
|
||||
return b;
|
||||
}
|
||||
|
||||
g = gen3(0);
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({a: 0, b: undefined}, 0, gm);
|
||||
|
||||
g.next(); // Create b.
|
||||
CheckScopeContent({a: 0, b: 1}, 0, gm);
|
||||
|
||||
// Closure scope with a parameter.
|
||||
|
||||
function *gen4(a, b) {
|
||||
var x = 2;
|
||||
yield a;
|
||||
var y = 3;
|
||||
return b;
|
||||
}
|
||||
|
||||
g = gen4(0, 1);
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({a: 0, b: 1, x: undefined, y: undefined}, 0, gm);
|
||||
|
||||
g.next(); // Create x.
|
||||
CheckScopeContent({a: 0, b: 1, x: 2, y: undefined}, 0, gm);
|
||||
|
||||
g.next(); // Create y.
|
||||
CheckScopeContent({a: 0, b: 1, x: 2, y: 3}, 0, gm);
|
||||
|
||||
// Closure introducing local variable using eval.
|
||||
|
||||
function *gen5(a) {
|
||||
eval('var b = 2');
|
||||
return b;
|
||||
}
|
||||
|
||||
g = gen5(1);
|
||||
g.next();
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({a: 1, b: 2}, 0, gm);
|
||||
|
||||
// Single empty with block.
|
||||
|
||||
function *gen6() {
|
||||
with({}) {
|
||||
yield 1;
|
||||
}
|
||||
yield 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
g = gen6();
|
||||
g.next();
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.With,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({}, 0, gm);
|
||||
|
||||
g.next();
|
||||
CheckScopeChain([debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
|
||||
// Nested empty with blocks.
|
||||
|
||||
function *gen7() {
|
||||
with({}) {
|
||||
with({}) {
|
||||
yield 1;
|
||||
}
|
||||
yield 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
g = gen7();
|
||||
g.next();
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.With,
|
||||
debug.ScopeType.With,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({}, 0, gm);
|
||||
|
||||
// Nested with blocks using in-place object literals.
|
||||
|
||||
function *gen8() {
|
||||
with({a: 1,b: 2}) {
|
||||
with({a: 2,b: 1}) {
|
||||
yield a;
|
||||
}
|
||||
yield a;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
g = gen8();
|
||||
g.next();
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.With,
|
||||
debug.ScopeType.With,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({a: 2, b: 1}, 0, gm);
|
||||
|
||||
g.next();
|
||||
CheckScopeContent({a: 1, b: 2}, 0, gm);
|
||||
|
||||
// Catch block.
|
||||
|
||||
function *gen9() {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (e) {
|
||||
yield e;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
g = gen9();
|
||||
g.next();
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.Catch,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({e: 42}, 0, gm);
|
||||
|
||||
// For statement with block scope.
|
||||
|
||||
function *gen10() {
|
||||
for (let i = 0; i < 42; i++) yield i;
|
||||
return 3;
|
||||
}
|
||||
|
||||
g = gen10();
|
||||
g.next();
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.Block,
|
||||
debug.ScopeType.Block,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({i: 0}, 0, gm);
|
||||
|
||||
g.next();
|
||||
CheckScopeContent({i: 1}, 0, gm);
|
||||
CheckScopeContent({i: 0}, 1, gm); // Additional block scope with i = 0;
|
||||
|
||||
// Nested generators.
|
||||
|
||||
var gen12;
|
||||
function *gen11() {
|
||||
gen12 = function*() {
|
||||
var a = 1;
|
||||
yield 1;
|
||||
return 2;
|
||||
}();
|
||||
|
||||
var a = 0;
|
||||
yield* gen12;
|
||||
}
|
||||
|
||||
g = gen11();
|
||||
g.next();
|
||||
|
||||
gm = debug.MakeMirror(gen12);
|
||||
CheckScopeChain([debug.ScopeType.Closure,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({a: 1}, 0, gm);
|
||||
CheckScopeContent({a: 0}, 1, gm);
|
||||
|
||||
// Set a variable in an empty scope.
|
||||
|
||||
function *gen13() {
|
||||
yield 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
var g = gen13();
|
||||
var gm = debug.MakeMirror(g);
|
||||
assertThrows(() => gm.scope(0).setVariableValue("a", 42));
|
||||
CheckScopeContent({}, 0, gm);
|
||||
|
||||
// Set a variable in a simple scope.
|
||||
|
||||
function *gen14() {
|
||||
var a = 0;
|
||||
yield 1;
|
||||
yield a;
|
||||
return 2;
|
||||
}
|
||||
|
||||
var g = gen14();
|
||||
assertEquals(1, g.next().value);
|
||||
|
||||
var gm = debug.MakeMirror(g);
|
||||
CheckScopeContent({a: 0}, 0, gm);
|
||||
|
||||
gm.scope(0).setVariableValue("a", 1);
|
||||
CheckScopeContent({a: 1}, 0, gm);
|
||||
|
||||
assertEquals(1, g.next().value);
|
||||
|
||||
// Set a variable in nested with blocks using in-place object literals.
|
||||
|
||||
function *gen15() {
|
||||
var c = 3;
|
||||
with({a: 1,b: 2}) {
|
||||
var d = 4;
|
||||
yield a;
|
||||
var e = 5;
|
||||
}
|
||||
yield e;
|
||||
return e;
|
||||
}
|
||||
|
||||
var g = gen15();
|
||||
assertEquals(1, g.next().value);
|
||||
|
||||
var gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.With,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({a: 1, b: 2}, 0, gm);
|
||||
CheckScopeContent({c: 3, d: 4, e: undefined}, 1, gm);
|
||||
|
||||
// Variables don't exist in given scope.
|
||||
assertThrows(() => gm.scope(0).setVariableValue("c", 42));
|
||||
assertThrows(() => gm.scope(1).setVariableValue("a", 42));
|
||||
|
||||
// Variables in with scope are immutable.
|
||||
assertThrows(() => gm.scope(0).setVariableValue("a", 3));
|
||||
assertThrows(() => gm.scope(0).setVariableValue("b", 3));
|
||||
|
||||
gm.scope(1).setVariableValue("c", 1);
|
||||
gm.scope(1).setVariableValue("e", 42);
|
||||
|
||||
CheckScopeContent({a: 1, b: 2}, 0, gm);
|
||||
CheckScopeContent({c: 1, d: 4, e: 42}, 1, gm);
|
||||
assertEquals(5, g.next().value); // Initialized after set.
|
||||
|
||||
CheckScopeChain([debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
|
||||
gm.scope(0).setVariableValue("e", 42);
|
||||
|
||||
CheckScopeContent({c: 1, d: 4, e: 42}, 0, gm);
|
||||
assertEquals(42, g.next().value);
|
||||
|
||||
// Set a variable in nested with blocks using in-place object literals plus a
|
||||
// nested block scope.
|
||||
|
||||
function *gen16() {
|
||||
var c = 3;
|
||||
with({a: 1,b: 2}) {
|
||||
let d = 4;
|
||||
yield a;
|
||||
let e = 5;
|
||||
yield d;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
var g = gen16();
|
||||
g.next();
|
||||
|
||||
var gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.Block,
|
||||
debug.ScopeType.With,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({d: 4}, 0, gm);
|
||||
CheckScopeContent({a: 1, b: 2}, 1, gm);
|
||||
CheckScopeContent({c: 3}, 2, gm);
|
||||
|
||||
gm.scope(0).setVariableValue("d", 1);
|
||||
CheckScopeContent({d: 1}, 0, gm);
|
||||
|
||||
assertEquals(1, g.next().value);
|
||||
|
||||
// Set variable in catch block.
|
||||
|
||||
var yyzyzzyz = 4829;
|
||||
let xxxyyxxyx = 42284;
|
||||
function *gen17() {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (e) {
|
||||
yield e;
|
||||
yield e;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
g = gen17();
|
||||
g.next();
|
||||
|
||||
gm = debug.MakeMirror(g);
|
||||
CheckScopeChain([debug.ScopeType.Catch,
|
||||
debug.ScopeType.Closure,
|
||||
debug.ScopeType.Script,
|
||||
debug.ScopeType.Global], gm);
|
||||
CheckScopeContent({e: 42}, 0, gm);
|
||||
CheckScopeContent({xxxyyxxyx: 42284}, 2, gm);
|
||||
|
||||
gm.scope(0).setVariableValue("e", 1);
|
||||
CheckScopeContent({e: 1}, 0, gm);
|
||||
|
||||
assertEquals(1, g.next().value);
|
||||
|
||||
// Script scope.
|
||||
gm.scope(2).setVariableValue("xxxyyxxyx", 42);
|
||||
assertEquals(42, xxxyyxxyx);
|
||||
|
||||
// Global scope.
|
||||
assertThrows(() => gm.scope(3).setVariableValue("yyzyzzyz", 42));
|
||||
assertEquals(4829, yyzyzzyz);
|
Loading…
Reference in New Issue
Block a user