@@ -43,6 +43,8 @@ public class JavaScriptLifter: Lifter {
4343 }
4444 private var forLoopHeaderStack = Stack < ForLoopHeader > ( )
4545
46+ private var actualLoopDepth = 0
47+
4648 public init ( prefix: String = " " ,
4749 suffix: String = " " ,
4850 ecmaVersion: ECMAScriptVersion ) {
@@ -1059,14 +1061,20 @@ public class JavaScriptLifter: Lifter {
10591061
10601062 case . beginWhileLoopBody:
10611063 let COND = handleEndSingleExpressionContext ( result: input ( 0 ) , with: & w)
1064+ actualLoopDepth += 1
1065+ w. recordLoopPos ( )
10621066 w. emitBlock ( " while ( \( COND) ) { " )
10631067 w. enterNewBlock ( )
10641068
10651069 case . endWhileLoop:
10661070 w. leaveCurrentBlock ( )
10671071 w. emit ( " } " )
1072+ actualLoopDepth -= 1
1073+ w. popLoopPos ( )
10681074
10691075 case . beginDoWhileLoopBody:
1076+ actualLoopDepth += 1
1077+ w. recordLoopPos ( )
10701078 w. emit ( " do { " )
10711079 w. enterNewBlock ( )
10721080
@@ -1077,6 +1085,8 @@ public class JavaScriptLifter: Lifter {
10771085 case . endDoWhileLoop:
10781086 let COND = handleEndSingleExpressionContext ( result: input ( 0 ) , with: & w)
10791087 w. emitBlock ( " } while ( \( COND) ) " )
1088+ actualLoopDepth -= 1
1089+ w. popLoopPos ( )
10801090
10811091 case . beginForLoopInitializer:
10821092 // While we could inline into the loop header, we probably don't want to do that as it will often lead
@@ -1152,7 +1162,8 @@ public class JavaScriptLifter: Lifter {
11521162 let INITIALIZER = header. initializer
11531163 var CONDITION = header. condition
11541164 var AFTERTHOUGHT = handleEndSingleExpressionContext ( with: & w)
1155-
1165+ actualLoopDepth += 1
1166+ w. recordLoopPos ( )
11561167 if !INITIALIZER. contains ( " \n " ) && !CONDITION. contains ( " \n " ) && !AFTERTHOUGHT. contains ( " \n " ) {
11571168 if !CONDITION. isEmpty { CONDITION = " " + CONDITION }
11581169 if !AFTERTHOUGHT. isEmpty { AFTERTHOUGHT = " " + AFTERTHOUGHT }
@@ -1171,22 +1182,30 @@ public class JavaScriptLifter: Lifter {
11711182 case . endForLoop:
11721183 w. leaveCurrentBlock ( )
11731184 w. emit ( " } " )
1185+ actualLoopDepth -= 1
1186+ w. popLoopPos ( )
11741187
11751188 case . beginForInLoop:
11761189 let LET = w. declarationKeyword ( for: instr. innerOutput)
11771190 let V = w. declare ( instr. innerOutput)
11781191 let OBJ = input ( 0 )
1192+ actualLoopDepth += 1
1193+ w. recordLoopPos ( )
11791194 w. emit ( " for ( \( LET) \( V) in \( OBJ) ) { " )
11801195 w. enterNewBlock ( )
11811196
11821197 case . endForInLoop:
11831198 w. leaveCurrentBlock ( )
11841199 w. emit ( " } " )
1200+ actualLoopDepth -= 1
1201+ w. popLoopPos ( )
11851202
11861203 case . beginForOfLoop:
11871204 let V = w. declare ( instr. innerOutput)
11881205 let LET = w. declarationKeyword ( for: instr. innerOutput)
11891206 let OBJ = input ( 0 )
1207+ actualLoopDepth += 1
1208+ w. recordLoopPos ( )
11901209 w. emit ( " for ( \( LET) \( V) of \( OBJ) ) { " )
11911210 w. enterNewBlock ( )
11921211
@@ -1195,12 +1214,16 @@ public class JavaScriptLifter: Lifter {
11951214 let PATTERN = liftArrayDestructPattern ( indices: op. indices, outputs: outputs, hasRestElement: op. hasRestElement)
11961215 let LET = w. varKeyword
11971216 let OBJ = input ( 0 )
1217+ actualLoopDepth += 1
1218+ w. recordLoopPos ( )
11981219 w. emit ( " for ( \( LET) [ \( PATTERN) ] of \( OBJ) ) { " )
11991220 w. enterNewBlock ( )
12001221
12011222 case . endForOfLoop:
12021223 w. leaveCurrentBlock ( )
12031224 w. emit ( " } " )
1225+ actualLoopDepth -= 1
1226+ w. popLoopPos ( )
12041227
12051228 case . beginRepeatLoop( let op) :
12061229 let LET = w. varKeyword
@@ -1211,12 +1234,16 @@ public class JavaScriptLifter: Lifter {
12111234 I = " i "
12121235 }
12131236 let ITERATIONS = op. iterations
1237+ actualLoopDepth += 1
1238+ w. recordLoopPos ( )
12141239 w. emit ( " for ( \( LET) \( I) = 0; \( I) < \( ITERATIONS) ; \( I) ++) { " )
12151240 w. enterNewBlock ( )
12161241
12171242 case . endRepeatLoop:
12181243 w. leaveCurrentBlock ( )
12191244 w. emit ( " } " )
1245+ actualLoopDepth -= 1
1246+ w. popLoopPos ( )
12201247
12211248 case . loopBreak( _) ,
12221249 . switchBreak:
@@ -1225,6 +1252,34 @@ public class JavaScriptLifter: Lifter {
12251252 case . loopContinue:
12261253 w. emit ( " continue; " )
12271254
1255+ case . breakNested( _) :
1256+ let input = input ( 0 )
1257+ let expectedDepth = Int ( input. text) ?? 0
1258+ let d = expectedDepth % actualLoopDepth
1259+ let pos = w. getLoopPos ( d)
1260+ let pre = String ( repeating: " " , count: 4 * d)
1261+ let s = pre + " label " + String( d) + " : \n "
1262+ if ( !w. getLabelExist ( d) ) {
1263+ w. insertLabel ( pos, s)
1264+ w. setLabelExist ( d)
1265+ w. updateLoopPos ( d + 1 , s. length)
1266+ }
1267+ w. emit ( " break " + " label " + String( d) + " ; " )
1268+
1269+ case . continueNested:
1270+ let input = input ( 0 )
1271+ let expectedDepth = Int ( input. text) ?? 0
1272+ let d = expectedDepth % actualLoopDepth
1273+ let pos = w. getLoopPos ( d)
1274+ let pre = String ( repeating: " " , count: 4 * d)
1275+ let s = pre + " label " + String( d) + " : \n "
1276+ if ( !w. getLabelExist ( d) ) {
1277+ w. insertLabel ( pos, s)
1278+ w. setLabelExist ( d)
1279+ w. updateLoopPos ( d + 1 , s. length)
1280+ }
1281+ w. emit ( " continue " + " label " + String( d) + " ; " )
1282+
12281283 case . beginTry:
12291284 w. emit ( " try { " )
12301285 w. enterNewBlock ( )
@@ -1514,6 +1569,12 @@ public class JavaScriptLifter: Lifter {
15141569 return writer. code
15151570 }
15161571
1572+ struct LoopPosInfo {
1573+ var loopBeginPos : Int
1574+ var exist : Bool
1575+ }
1576+ private var loopPos : [ LoopPosInfo ]
1577+
15171578 // Maps each FuzzIL variable to its JavaScript expression.
15181579 // The expression for a FuzzIL variable can generally either be
15191580 // * an identifier like "v42" if the FuzzIL variable is mapped to a JavaScript variable OR
@@ -1534,6 +1595,7 @@ public class JavaScriptLifter: Lifter {
15341595 self . analyzer = analyzer
15351596 self . varKeyword = version == . es6 ? " let " : " var "
15361597 self . constKeyword = version == . es6 ? " const " : " var "
1598+ self . loopPos = [ ]
15371599 }
15381600
15391601 /// Assign a JavaScript expression to a FuzzIL variable.
@@ -1771,6 +1833,43 @@ public class JavaScriptLifter: Lifter {
17711833 writer. emit ( line)
17721834 }
17731835
1836+ mutating func recordLoopPos( ) {
1837+ loopPos. append ( LoopPosInfo ( loopBeginPos: code. count, exist: false ) )
1838+ }
1839+
1840+ mutating func popLoopPos( ) {
1841+ loopPos. popLast ( )
1842+ }
1843+
1844+ mutating func getLoopPos( _ idx: Int ) -> Int {
1845+ return loopPos [ idx] . loopBeginPos
1846+ }
1847+
1848+ // if we insert one label into code, then the after record index move the same length
1849+ mutating func updateLoopPos( _ startIndex: Int , _ len: Int ) {
1850+ if ( startIndex <= loopPos. count - 1 ) {
1851+ for i in startIndex... loopPos. count - 1 {
1852+ loopPos [ i] . loopBeginPos += len
1853+ }
1854+ }
1855+ }
1856+
1857+ mutating func getLabelExist( _ idx: Int ) -> Bool {
1858+ return loopPos [ idx] . exist
1859+ }
1860+
1861+ mutating func setLabelExist( _ idx: Int ) {
1862+ loopPos [ idx] . exist = true
1863+ }
1864+
1865+ mutating func clearLoopPos( ) {
1866+ loopPos = [ ]
1867+ }
1868+
1869+ mutating func insertLabel( _ pos: Int , _ content: String ) {
1870+ writer. insert ( pos, content)
1871+ }
1872+
17741873 /// Emit a (potentially multi-line) comment.
17751874 mutating func emitComment( _ comment: String ) {
17761875 writer. emitComment ( comment)
0 commit comments