mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-30 22:42:45 +00:00 
			
		
		
		
	 9d0d3affd4
			
		
	
	
		9d0d3affd4
		
	
	
	
	
		
			
			This includes:
- Parsing proper LabelledStatements with try_parse_labelled_statement()
- Removing LabelableStatement
- Implementing the LoopEvaluation semantics via loop_evaluation() in
  each IterationStatement subclass; and IterationStatement evaluation
  via {For,ForIn,ForOf,ForAwaitOf,While,DoWhile}Statement::execute()
- Updating ReturnStatement, BreakStatement and ContinueStatement to
  return the appropriate completion types
- Basically reimplementing TryStatement and SwitchStatement according to
  the spec, using completions
- Honoring result completion types in AsyncBlockStart and
  OrdinaryCallEvaluateBody
- Removing any uses of the VM unwind mechanism - most importantly,
  VM::throw_exception() now exclusively sets an exception and no longer
  triggers any unwinding mechanism.
  However, we already did a good job updating all of LibWeb and userland
  applications to not use it, and the few remaining uses elsewhere don't
  rely on unwinding AFAICT.
		
	
			
		
			
				
	
	
		
			192 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| test("labelled plain scope", () => {
 | |
|     notused: test: alsonotused: {
 | |
|         let o = 1;
 | |
|         expect(o).toBe(1);
 | |
|         unused: break test;
 | |
|         expect().fail();
 | |
|     }
 | |
| });
 | |
| 
 | |
| test("break on plain scope from inner scope", () => {
 | |
|     notused: outer: alsonotused: {
 | |
|         {
 | |
|             unused: break outer;
 | |
|         }
 | |
|         expect().fail();
 | |
|     }
 | |
| });
 | |
| 
 | |
| test("labelled for loop with break", () => {
 | |
|     let counter = 0;
 | |
|     notused: outer: alsonotused: for (a of [1, 2, 3]) {
 | |
|         for (b of [4, 5, 6]) {
 | |
|             if (a === 2 && b === 5) break outer;
 | |
|             counter++;
 | |
|         }
 | |
|     }
 | |
|     expect(counter).toBe(4);
 | |
| });
 | |
| 
 | |
| test("labelled for loop with continue", () => {
 | |
|     let counter = 0;
 | |
|     notused: outer: alsonotused: for (a of [1, 2, 3]) {
 | |
|         for (b of [4, 5, 6]) {
 | |
|             if (b === 6) continue outer;
 | |
|             counter++;
 | |
|         }
 | |
|     }
 | |
|     expect(counter).toBe(6);
 | |
| });
 | |
| 
 | |
| test("continue label statement is not an iteration statement", () => {
 | |
|     expect(() =>
 | |
|         eval(`
 | |
| outer: outer2: {
 | |
|     for (;;) {
 | |
|         continue outer;
 | |
|     }
 | |
| }`)
 | |
|     ).toThrowWithMessage(
 | |
|         SyntaxError,
 | |
|         "labelled continue statement cannot use non iterating statement (line: 4, column: 18)"
 | |
|     );
 | |
| 
 | |
|     expect(() =>
 | |
|         eval(`
 | |
| for (;;) {
 | |
|     outer: outer2: {
 | |
|         continue outer;
 | |
|     }
 | |
| }`)
 | |
|     ).toThrowWithMessage(
 | |
|         SyntaxError,
 | |
|         "labelled continue statement cannot use non iterating statement (line: 4, column: 18)"
 | |
|     );
 | |
| });
 | |
| 
 | |
| test("break on try catch statement", () => {
 | |
|     let entered = false;
 | |
|     label1: label2: label3: try {
 | |
|         entered = true;
 | |
|         break label2;
 | |
|         expect().fail();
 | |
|     } catch (e) {
 | |
|         expect().fail();
 | |
|     }
 | |
|     expect(entered).toBeTrue();
 | |
| });
 | |
| 
 | |
| test("can break on every label", () => {
 | |
|     let i = 0;
 | |
|     label0: label1: label2: for (; i < 3; i++) {
 | |
|         block: {
 | |
|             break block;
 | |
|             expect().fail();
 | |
|         }
 | |
|         if (i === 0) continue label0;
 | |
|         if (i === 1) continue label1;
 | |
|         if (i === 2) continue label2;
 | |
|         expect().fail();
 | |
|     }
 | |
|     expect(i).toBe(3);
 | |
| });
 | |
| 
 | |
| test("can use certain 'keywords' as labels", () => {
 | |
|     let i = 0;
 | |
| 
 | |
|     yield: {
 | |
|         i++;
 | |
|         break yield;
 | |
|         expect().fail();
 | |
|     }
 | |
| 
 | |
|     await: {
 | |
|         i++;
 | |
|         break await;
 | |
|         expect().fail();
 | |
|     }
 | |
| 
 | |
|     async: {
 | |
|         i++;
 | |
|         break async;
 | |
|         expect().fail();
 | |
|     }
 | |
| 
 | |
|     let: {
 | |
|         i++;
 | |
|         break let;
 | |
|         expect().fail();
 | |
|     }
 | |
| 
 | |
|     // prettier-ignore
 | |
|     l\u0065t: {
 | |
|         i++;
 | |
|         break let;
 | |
|         expect().fail();
 | |
|     }
 | |
| 
 | |
|     private: {
 | |
|         i++;
 | |
|         break private;
 | |
|         expect().fail();
 | |
|     }
 | |
| 
 | |
|     expect(i).toBe(6);
 | |
| 
 | |
|     expect(`const: { break const; }`).not.toEval();
 | |
| });
 | |
| 
 | |
| test("can use certain 'keywords' even in strict mode", () => {
 | |
|     "use strict";
 | |
| 
 | |
|     let i = 0;
 | |
|     await: {
 | |
|         i++;
 | |
|         break await;
 | |
|         expect().fail();
 | |
|     }
 | |
| 
 | |
|     async: {
 | |
|         i++;
 | |
|         break async;
 | |
|         expect().fail();
 | |
|     }
 | |
|     expect(i).toBe(2);
 | |
| 
 | |
|     expect(`'use strict'; let: { break let; }`).not.toEval();
 | |
| 
 | |
|     expect(`'use strict'; l\u0065t: { break l\u0065t; }`).not.toEval();
 | |
| });
 | |
| 
 | |
| test("invalid label usage", () => {
 | |
|     expect(() =>
 | |
|         eval(`
 | |
|             label: {
 | |
|                 (() => {
 | |
|                     break label;
 | |
|                 });
 | |
|             }
 | |
|         `)
 | |
|     ).toThrowWithMessage(SyntaxError, "Label 'label' not found");
 | |
| 
 | |
|     expect(() =>
 | |
|         eval(`
 | |
|             label: {
 | |
|                 while (false) {
 | |
|                     continue label;
 | |
|                 }
 | |
|             }
 | |
|         `)
 | |
|     ).toThrowWithMessage(
 | |
|         SyntaxError,
 | |
|         "labelled continue statement cannot use non iterating statement"
 | |
|     );
 | |
| 
 | |
|     expect(() =>
 | |
|         eval(`
 | |
|             label: label: {
 | |
|                 break label;
 | |
|             }
 | |
|         `)
 | |
|     ).toThrowWithMessage(SyntaxError, "Label 'label' has already been declared");
 | |
| });
 |