@@ -325,17 +325,69 @@ public GenerationResult visit(SwitchNode node, GenerationContext context)
325325 String switchVarName = "@switch_" + System .nanoTime ();
326326 instructions .add (new DefineLocalInstruction (errorReporter , switchVarName , Object .class ));
327327
328- // Generate if-else chain for each case
328+ // Set up context to track break jump targets for this switch
329+ context .setProperty ("inSwitch" , Boolean .TRUE );
330+ List <JumpInstruction > switchBreakTargets = new ArrayList <>();
331+ context .setProperty ("switchBreakTargets" , switchBreakTargets );
332+
333+ // Collect cases and group consecutive cases with empty bodies
329334 List <SwitchCaseNode > cases = node .getCases ();
335+ List <SwitchCaseNode > groupedCases = new ArrayList <>();
336+ List <Integer > caseLabelPositions = new ArrayList <>();
337+
338+ for (int i = 0 ; i < cases .size (); i ++) {
339+ SwitchCaseNode currentCase = cases .get (i );
340+ List <StatementNode > statements = currentCase .getStatements ();
341+
342+ // Check if this case has a body
343+ boolean hasBody = statements != null && !statements .isEmpty ();
344+
345+ if (currentCase .getCondition () != null ) {
346+ // Regular case
347+ if (hasBody ) {
348+ // This case has a body - add it as a new group
349+ groupedCases .add (currentCase );
350+ caseLabelPositions .add (instructions .size ());
351+ } else {
352+ // Empty case - check if next case has a body
353+ if (i + 1 < cases .size ()) {
354+ SwitchCaseNode nextCase = cases .get (i + 1 );
355+ List <StatementNode > nextStatements = nextCase .getStatements ();
356+ boolean nextHasBody = nextStatements != null && !nextStatements .isEmpty ();
357+
358+ if (nextHasBody && nextCase .getCondition () != null ) {
359+ // Next case has a body - combine with current case
360+ // We'll handle this by making the current case jump to the next case's body
361+ groupedCases .add (currentCase );
362+ caseLabelPositions .add (instructions .size ());
363+ } else {
364+ // Skip this empty case
365+ continue ;
366+ }
367+ }
368+ }
369+ } else {
370+ // Default case - always add
371+ groupedCases .add (currentCase );
372+ caseLabelPositions .add (instructions .size ());
373+ }
374+ }
375+
376+ // Generate instructions for grouped cases
330377 List <JumpInstruction > jumpToEndInstructions = new ArrayList <>();
331378 List <Integer > jumpToEndPositions = new ArrayList <>();
379+ List <JumpIfPopInstruction > jumpIfInstructions = new ArrayList <>();
380+ List <Integer > jumpIfPositions = new ArrayList <>();
381+ List <Integer > nextCasePositions = new ArrayList <>();
332382
333- for (int i = 0 ; i < cases .size (); i ++) {
334- SwitchCaseNode switchCase = cases .get (i );
383+ for (int i = 0 ; i < groupedCases .size (); i ++) {
384+ SwitchCaseNode switchCase = groupedCases .get (i );
335385 ExpressionNode caseCondition = switchCase .getCondition ();
336386
337387 if (caseCondition != null ) {
338- // Not a default case - need to check equality
388+ List <StatementNode > statements = switchCase .getStatements ();
389+ boolean hasBody = statements != null && !statements .isEmpty ();
390+
339391 // Load switch value
340392 LoadInstruction loadSwitchVar = new LoadInstruction (errorReporter , switchVarName , null );
341393 instructions .add (loadSwitchVar );
@@ -351,28 +403,45 @@ public GenerationResult visit(SwitchNode node, GenerationContext context)
351403 // Jump to next case if not equal
352404 JumpIfPopInstruction jumpIf = new JumpIfPopInstruction (errorReporter , false , -1 );
353405 instructions .add (jumpIf );
406+ jumpIfInstructions .add (jumpIf );
407+ jumpIfPositions .add (instructions .size () - 1 );
354408
355- int caseStart = instructions .size ();
409+ // If this case has an empty body (fallthrough), find the next case with a body
410+ int targetPos ;
411+ if (!hasBody && i + 1 < groupedCases .size ()) {
412+ // Find the next case with a body
413+ targetPos = -1 ;
414+ for (int j = i + 1 ; j < groupedCases .size (); j ++) {
415+ List <StatementNode > nextStatements = groupedCases .get (j ).getStatements ();
416+ if (nextStatements != null && !nextStatements .isEmpty ()) {
417+ targetPos = caseLabelPositions .get (j );
418+ break ;
419+ }
420+ }
421+ if (targetPos == -1 ) {
422+ targetPos = instructions .size ();
423+ }
424+ nextCasePositions .add (targetPos );
425+ } else {
426+ nextCasePositions .add (instructions .size ());
427+ }
356428
357429 // Generate case body statements
358- List <StatementNode > statements = switchCase .getStatements ();
359430 if (statements != null ) {
360431 for (StatementNode stmt : statements ) {
361432 GenerationResult stmtResult = ((ASTNode )stmt ).accept (this , context );
362433 instructions .addAll (stmtResult .getInstructions ());
363434 }
364435 }
365436
366- // Jump to end after case body (unless it's the last case without break)
367- JumpInstruction jumpToEnd = new JumpInstruction (errorReporter , -1 );
368- instructions .add (jumpToEnd );
369- jumpToEndInstructions .add (jumpToEnd );
370- jumpToEndPositions .add (instructions .size () - 1 ); // Track position of jump instruction
371-
372- // Set jumpIf target (start of next case)
373- jumpIf .setPosition (instructions .size () - caseStart );
374- }
375- else {
437+ // Jump to end after case body
438+ if (hasBody ) {
439+ JumpInstruction jumpToEnd = new JumpInstruction (errorReporter , -1 );
440+ instructions .add (jumpToEnd );
441+ jumpToEndInstructions .add (jumpToEnd );
442+ jumpToEndPositions .add (instructions .size () - 1 );
443+ }
444+ } else {
376445 // Default case - no condition check needed
377446 List <StatementNode > statements = switchCase .getStatements ();
378447 if (statements != null ) {
@@ -384,17 +453,31 @@ public GenerationResult visit(SwitchNode node, GenerationContext context)
384453 }
385454 }
386455
387- // Set all jump to end targets
456+ // Clear the inSwitch flag
457+ context .setProperty ("inSwitch" , Boolean .FALSE );
458+
459+ // Set jumpIf targets
388460 int endPosition = instructions .size ();
461+ for (int i = 0 ; i < jumpIfInstructions .size (); i ++) {
462+ JumpIfPopInstruction jumpIf = jumpIfInstructions .get (i );
463+ int jumpIfPosition = jumpIfPositions .get (i );
464+ int targetPos = nextCasePositions .get (i );
465+ jumpIf .setPosition (targetPos - jumpIfPosition - 1 );
466+ }
467+
468+ // Set all jump to end targets
389469 for (int i = 0 ; i < jumpToEndInstructions .size (); i ++) {
390470 JumpInstruction jump = jumpToEndInstructions .get (i );
391471 int jumpPosition = jumpToEndPositions .get (i );
392- // Calculate relative offset: (endPosition) - (jumpPosition + 1)
393- // The +1 is because the jump instruction will be at jumpPosition, and we need to jump to endPosition
394- // After executing the jump at jumpPosition, i becomes jumpPosition + position
395- // So we need: jumpPosition + position = endPosition
396- // Therefore: position = endPosition - jumpPosition
397- jump .setPosition (endPosition - jumpPosition );
472+ jump .setPosition (endPosition - jumpPosition - 1 );
473+ }
474+
475+ // Set break statement jump targets
476+ for (JumpInstruction breakJump : switchBreakTargets ) {
477+ int jumpPosition = instructions .indexOf (breakJump );
478+ if (jumpPosition >= 0 ) {
479+ breakJump .setPosition (endPosition - jumpPosition - 1 );
480+ }
398481 }
399482
400483 // Push null as result (switch statement doesn't produce a value)
@@ -504,6 +587,26 @@ public GenerationResult visit(ReturnNode node, GenerationContext context)
504587 public GenerationResult visit (BreakNode node , GenerationContext context )
505588 throws Exception {
506589 ErrorReporter errorReporter = createErrorReporter (node );
590+
591+ // Check if we're in a switch statement
592+ Boolean inSwitch = (Boolean )context .getProperty ("inSwitch" );
593+ if (inSwitch != null && inSwitch ) {
594+ // In a switch, break should jump to the end of the switch
595+ JumpInstruction jumpInstruction = new JumpInstruction (errorReporter , -1 );
596+
597+ // Add this jump to the list of break targets
598+ // The position will be calculated after all instructions are generated
599+ @ SuppressWarnings ("unchecked" )
600+ List <JumpInstruction > breakTargets = (List <JumpInstruction >)context .getProperty ("switchBreakTargets" );
601+
602+ if (breakTargets != null ) {
603+ breakTargets .add (jumpInstruction );
604+ }
605+
606+ return new GenerationResult (Collections .singletonList (jumpInstruction ), false , 0 );
607+ }
608+
609+ // In a loop, break returns LOOP_BREAK_RESULT
507610 BreakContinueInstruction instruction = new BreakContinueInstruction (errorReporter , QResult .LOOP_BREAK_RESULT );
508611 return new GenerationResult (Collections .singletonList (instruction ), false , 0 );
509612 }
0 commit comments