@samitouri / QOS-React / commits / 8e7b68506f

You get a debugger and you get a debugger and you get a

Adds support for DebuggerStatement.

Joe Savona committed Apr 26, 2023 at 11:27 UTC 8e7b68506f0b490c7eca3ee886bfd1ff7991d07c
12 files changed +85 -8
compiler/forget/src/HIR/BuildHIR.ts
+14 -1
@@ -866,9 +866,22 @@ function lowerStatement(
866 );
867 return;
868 }
869 + case "DebuggerStatement": {
870 + const stmt = stmtPath as NodePath<t.DebuggerStatement>;
871 + const loc = stmt.node.loc ?? GeneratedSource;
872 + builder.push({
873 + id: makeInstructionId(0),
874 + lvalue: buildTemporaryPlace(builder, loc),
875 + value: {
876 + kind: "Debugger",
877 + loc,
878 + },
879 + loc,
880 + });
881 + return;
882 + }
883 case "ForInStatement":
884 case "ClassDeclaration":
871 - case "DebuggerStatement":
885 case "DeclareClass":
886 case "DeclareExportAllDeclaration":
887 case "DeclareExportDeclaration":
compiler/forget/src/HIR/HIR.ts
+2
@@ -710,6 +710,8 @@ export type InstructionValue =
710 value: Place;
711 loc: SourceLocation;
712 }
713 + // `debugger` statement
714 + | { kind: "Debugger"; loc: SourceLocation }
715 /**
716 * Catch-all for statements such as type imports, nested class declarations, etc
717 * which are not directly represented, but included for completeness and to allow
compiler/forget/src/HIR/PrintHIR.ts
+4
@@ -478,6 +478,10 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
478 value = `ExpressionStatement ${printPlace(instrValue.value)}`;
479 break;
480 }
481 + case "Debugger": {
482 + value = `Debugger`;
483 + break;
484 + }
485 default: {
486 assertExhaustive(
487 instrValue,
compiler/forget/src/HIR/visitors.ts
+2
@@ -184,6 +184,7 @@ export function* eachInstructionValueOperand(
184 yield instrValue.value;
185 break;
186 }
187 + case "Debugger":
188 case "RegExpLiteral":
189 case "LoadGlobal":
190 case "UnsupportedNode":
@@ -451,6 +452,7 @@ export function mapInstructionOperands(
452 instrValue.value = fn(instrValue.value);
453 break;
454 }
455 + case "Debugger":
456 case "RegExpLiteral":
457 case "LoadGlobal":
458 case "UnsupportedNode":
compiler/forget/src/Inference/InferReferenceEffects.ts
+1
@@ -673,6 +673,7 @@ function inferBlock(
673 effectKind = Effect.Mutate;
674 break;
675 }
676 + case "Debugger":
677 case "LoadGlobal":
678 case "JSXText":
679 case "Primitive": {
compiler/forget/src/Optimization/DeadCodeElimination.ts
+4
@@ -190,6 +190,10 @@ function pruneableValue(value: InstructionValue, state: State): boolean {
190 }
191 return true;
192 }
193 + case "Debugger": {
194 + // explicitly retain debugger statements to not break debugging workflows
195 + return false;
196 + }
197 case "ExpressionStatement": {
198 // We create ExpressionStatements specifically for expressions that would otherwise
199 // be dropped but which we don't want to eliminate.
compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+8 -6
@@ -439,7 +439,6 @@ function codegenInstructionNullable(
439 cx: Context,
440 instr: ReactiveInstruction
441 ): t.Statement | null {
442 - let statement;
442 if (
443 instr.value.kind === "StoreLocal" ||
444 instr.value.kind === "Destructure" ||
@@ -514,14 +513,16 @@ function codegenInstructionNullable(
513 assertExhaustive(kind, `Unexpected instruction kind '${kind}'`);
514 }
515 }
516 + } else if (instr.value.kind === "Debugger") {
517 + return t.debuggerStatement();
518 } else {
519 const value = codegenInstructionValue(cx, instr.value);
519 - statement = codegenInstruction(cx, instr, value);
520 - }
521 - if (statement.type === "EmptyStatement") {
522 - return null;
520 + const statement = codegenInstruction(cx, instr, value);
521 + if (statement.type === "EmptyStatement") {
522 + return null;
523 + }
524 + return statement;
525 }
524 - return statement;
526 }
527
528 function codegenForInit(
@@ -1000,6 +1001,7 @@ function codegenInstructionValue(
1001 value = codegenPlace(cx, instrValue.value);
1002 break;
1003 }
1004 + case "Debugger":
1005 case "DeclareLocal":
1006 case "Destructure":
1007 case "StoreLocal": {
compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts
+2 -1
@@ -235,7 +235,8 @@ function mayAllocate(value: InstructionValue): boolean {
235 case "TemplateLiteral":
236 case "Primitive":
237 case "NextIterableOf":
238 - case "ExpressionStatement": {
238 + case "ExpressionStatement":
239 + case "Debugger": {
240 return false;
241 }
242 case "RegExpLiteral":
compiler/forget/src/ReactiveScopes/PruneNonEscapingScopes.ts
+1
@@ -417,6 +417,7 @@ function computeMemoizationInputs(
417 rvalues: value.children,
418 };
419 }
420 + case "Debugger":
421 case "ComputedDelete":
422 case "PropertyDelete":
423 case "LoadGlobal":
compiler/forget/src/TypeInference/InferTypes.ts
+1
@@ -212,6 +212,7 @@ function* generateInstructionTypes(
212 case "NextIterableOf":
213 case "ExpressionStatement":
214 case "UnsupportedNode":
215 + case "Debugger":
216 break;
217 default:
218 assertExhaustive(value, `Unhandled instruction value kind: ${value}`);
compiler/forget/src/__tests__/fixtures/compiler/debugger.expect.md new
+35
@@ -0,0 +1,35 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + debugger;
7 + if (props.cond) {
8 + debugger;
9 + } else {
10 + while (props.cond) {
11 + debugger;
12 + }
13 + }
14 + debugger;
15 +}
16 +
17 +```
18 +
19 +## Code
20 +
21 +```javascript
22 +function Component(props) {
23 + debugger;
24 + if (props.cond) {
25 + debugger;
26 + } else {
27 + while (props.cond) {
28 + debugger;
29 + }
30 + }
31 + debugger;
32 +}
33 +
34 +```
35 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/debugger.js new
+11
@@ -0,0 +1,11 @@
1 +function Component(props) {
2 + debugger;
3 + if (props.cond) {
4 + debugger;
5 + } else {
6 + while (props.cond) {
7 + debugger;
8 + }
9 + }
10 + debugger;
11 +}