Buggy code:
public class Grammar { public static class Options { @ Option public List < String > inPaths = new ArrayList < > ( ) ; @ Option ( gloss = "Variables<seq2seq4repair_space>which<seq2seq4repair_space>are<seq2seq4repair_space>used<seq2seq4repair_space>to<seq2seq4repair_space>interpret<seq2seq4repair_space>the<seq2seq4repair_space>grammar<seq2seq4repair_space>file" ) public List < String > tags = new ArrayList < > ( ) ; @ Option public boolean binarizeRules = true ; } public static Grammar . Options opts = new Grammar . Options ( ) ; ArrayList < Rule > rules = new ArrayList < > ( ) ; public List < Rule > getRules ( ) { } Map < String , LispTree > macros = new HashMap < > ( ) ; List < String > statements = new ArrayList < > ( ) ; public void read ( ) { } public void read ( String path ) { } public void read ( List < String > paths ) { } private void verifyValid ( ) { } public void addStatement ( String stmt , String contextPath , Set < String > tags ) { } public void addStatement ( String stmt , String contextPath ) { } public void addStatement ( String stmt ) { } private static LispTree applyMacros ( Map < String , LispTree > macros , LispTree tree ) { } public LispTree applyMacros ( LispTree tree ) { } private void readOnePath ( String path , Set < String > tags ) { } public void write ( ) { } private void interpret ( String path , LispTree tree , Set < String > tags ) { } private boolean interpretBoolean ( LispTree tree , Set < String > tags ) { } public void interpretMacroDef ( LispTree tree ) { } public void interpretFor ( String path , LispTree tree , Set < String > tags ) { } private void interpretRule ( LispTree tree ) { } public synchronized boolean addRule ( Rule rule ) { } public synchronized boolean addRule ( Rule rule , List < Boolean > isOptionals ) { } private int freshCatIndex = 0 ; private String generateFreshCat ( ) { } private List < Rule > binarizeRule ( Rule rule , List < Boolean > isOptionals ) { List < Rule > newRules = new ArrayList < > ( ) ; if ( ( ( rule . sem ) instanceof JoinFn ) && ( ( ( ( JoinFn ) ( rule . sem ) ) . getArg0Fn ( ) ) != null ) ) { int i = 0 ; while ( ( i < ( rule . rhs . size ( ) ) ) && ( ! ( ( Rule . isCat ( rule . rhs . get ( i ) ) ) && ( ! ( isOptionals . get ( i ) ) ) ) ) ) i ++ ; int j = i + 1 ; <START_BUG> while ( ( j < ( rule . rhs . size ( ) ) ) && ( ! ( ( Rule . isCat ( rule . rhs . get ( i ) ) ) && ( ! ( isOptionals . get ( i ) ) ) ) ) ) <END_BUG> j ++ ; if ( j < ( rule . rhs . size ( ) ) ) { String intCat = generateFreshCat ( ) ; List < String > rhs1 = new ArrayList ( rule . rhs . subList ( 0 , ( i + 1 ) ) ) ; newRules . addAll ( binarizeRule ( new Rule ( intCat , rhs1 , rule . sem ) . setInfo ( rule ) , isOptionals . subList ( 0 , ( i + 1 ) ) ) ) ; List < String > rhs2 = new ArrayList < > ( ) ; rhs2 . add ( intCat ) ; rhs2 . addAll ( rule . rhs . subList ( ( i + 1 ) , rule . rhs . size ( ) ) ) ; SemanticFn forwardBetaReduce = new JoinFn ( ) ; forwardBetaReduce . init ( proto . parseFromString ( "(JoinFn<seq2seq4repair_space>forward<seq2seq4repair_space>betaReduce)" ) ) ; newRules . addAll ( binarizeRule ( new Rule ( rule . lhs , rhs2 , forwardBetaReduce ) . setInfo ( rule ) , isOptionals . subList ( i , isOptionals . size ( ) ) ) ) ; return newRules ; } } if ( ! ( Grammar . opts . binarizeRules ) ) { if ( isOptionals . contains ( true ) ) throw new RuntimeException ( ( ( ( "Can't<seq2seq4repair_space>have<seq2seq4repair_space>optionals<seq2seq4repair_space>if<seq2seq4repair_space>don't<seq2seq4repair_space>binarize:<seq2seq4repair_space>" + rule ) + "<seq2seq4repair_space>" ) + isOptionals ) ) ; newRules . add ( rule ) ; return newRules ; } if ( ! ( isOptionals . contains ( false ) ) ) throw new RuntimeException ( ( ( ( "Can't<seq2seq4repair_space>have<seq2seq4repair_space>all<seq2seq4repair_space>RHS<seq2seq4repair_space>items<seq2seq4repair_space>be<seq2seq4repair_space>optional:<seq2seq4repair_space>" + rule ) + "<seq2seq4repair_space>" ) + isOptionals ) ) ; if ( ( rule . rhs . size ( ) ) == 1 ) { newRules . add ( rule ) ; return newRules ; } List < String > newRhs = new ArrayList < > ( ) ; List < Boolean > newIsOptional = new ArrayList < > ( ) ; List < Boolean > isRequiredCat = new ArrayList < > ( ) ; assert ( rule . rhs . size ( ) ) >= 2 ; boolean appliedRuleSem = false ; for ( int i = 0 ; i < ( rule . rhs . size ( ) ) ; i ++ ) { newRhs . add ( rule . rhs . get ( i ) ) ; newIsOptional . add ( isOptionals . get ( i ) ) ; isRequiredCat . add ( ( ( ! ( isOptionals . get ( i ) ) ) && ( Rule . isCat ( rule . rhs . get ( i ) ) ) ) ) ; if ( ( newRhs . size ( ) ) < 2 ) continue ;

Fix:
while ( ( j < ( rule . rhs . size ( ) ) ) && ( ! ( ( Rule . isCat ( rule . rhs . get ( j ) ) ) && ( ! ( isOptionals . get ( j ) ) ) ) ) )