// Frame properties and methods work in generator-resuming onEnterFrame events. // Also tests onPop events, for good measure. let g = newGlobal({newCompartment: true}); g.eval(`\ function* gen(lo, hi) { var a = 1/2; yield a; yield a * a; } `); let dbg = new Debugger; let gw = dbg.addDebuggee(g); let hits = 0; let savedScript = null; let savedEnv = null; let savedOffsets = new Set; function check(frame) { assertEq(frame.type, "call"); assertEq(frame.constructing, false); assertEq(frame.callee, gw.makeDebuggeeValue(g.gen)); // `arguments` elements don't work in resumed generator frames, // because generators don't keep the arguments around. // However, some of this is initialized when the frame.arguments object is // created, so if they are created during the first onEnterFrame or onPop // event, the properties exist, and those events can also see the values. assertEq(frame.arguments.length, args.length); for (var i = 0; i < args.length; i++) { assertEq(frame.arguments.hasOwnProperty(i), true); if (hits < 2) assertEq(frame.arguments[i], gw.makeDebuggeeValue(args[i]), `arguments[${i}]`); else assertEq(frame.arguments[i], undefined); } if (savedEnv === null) { savedEnv = frame.environment; assertEq(savedScript, null); savedScript = frame.script; } else { assertEq(frame.environment, savedEnv); assertEq(frame.script, savedScript); } let a_expected = hits < 3 ? undefined : 1/2; assertEq(savedEnv.getVariable("a"), a_expected); assertEq(frame.onStack, true); let pc = frame.offset; assertEq(savedOffsets.has(pc), false); savedOffsets.add(pc); assertEq(frame.older, null); assertEq(frame.this, gw.makeDebuggeeValue(g)); assertEq(typeof frame.implementation, "string"); // And the moment of truth: assertEq(frame.eval("2 + 2").return, 4); assertEq(frame.eval("a").return, a_expected); assertEq(frame.eval("if (a !== undefined) { assertEq(a < (lo + hi) / 2, true); } 7;").return, 7); } dbg.onEnterFrame = frame => { if (frame.type === "eval") return; check(frame); hits++; frame.onPop = completion => { check(frame); hits++; }; }; // g.gen ignores the arguments passed to it, but we use them to test // frame.arguments. let args = [0, 10, g, dbg]; for (let v of g.gen(...args)) {} assertEq(hits, 8);