@@ -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,32 @@ public class JavaScriptLifter: Lifter {
12251252 case . loopContinue:
12261253 w. emit ( " continue; " )
12271254
1255+ case . loopBreakNested( let op) :
1256+ let expectedDepth = op. depth
1257+ let d = expectedDepth % actualLoopDepth
1258+ let pos = w. getLoopPos ( d)
1259+ let pre = String ( repeating: " " , count: 4 * d)
1260+ let s = pre + " label " + String( d) + " : \n "
1261+ if ( !w. getLabelExist ( d) ) {
1262+ w. insertLabel ( pos, s)
1263+ w. setLabelExist ( d)
1264+ w. updateLoopPos ( d + 1 , s. length)
1265+ }
1266+ w. emit ( " break " + " label " + String( d) + " ; " )
1267+
1268+ case . loopContinueNested( let op) :
1269+ let expectedDepth = op. depth
1270+ let d = expectedDepth % actualLoopDepth
1271+ let pos = w. getLoopPos ( d)
1272+ let pre = String ( repeating: " " , count: 4 * d)
1273+ let s = pre + " label " + String( d) + " : \n "
1274+ if ( !w. getLabelExist ( d) ) {
1275+ w. insertLabel ( pos, s)
1276+ w. setLabelExist ( d)
1277+ w. updateLoopPos ( d + 1 , s. length)
1278+ }
1279+ w. emit ( " continue " + " label " + String( d) + " ; " )
1280+
12281281 case . beginTry:
12291282 w. emit ( " try { " )
12301283 w. enterNewBlock ( )
@@ -1514,6 +1567,12 @@ public class JavaScriptLifter: Lifter {
15141567 return writer. code
15151568 }
15161569
1570+ struct LoopPosInfo {
1571+ var loopBeginPos : Int
1572+ var exist : Bool
1573+ }
1574+ private var loopPos : [ LoopPosInfo ]
1575+
15171576 // Maps each FuzzIL variable to its JavaScript expression.
15181577 // The expression for a FuzzIL variable can generally either be
15191578 // * an identifier like "v42" if the FuzzIL variable is mapped to a JavaScript variable OR
@@ -1534,6 +1593,7 @@ public class JavaScriptLifter: Lifter {
15341593 self . analyzer = analyzer
15351594 self . varKeyword = version == . es6 ? " let " : " var "
15361595 self . constKeyword = version == . es6 ? " const " : " var "
1596+ self . loopPos = [ ]
15371597 }
15381598
15391599 /// Assign a JavaScript expression to a FuzzIL variable.
@@ -1771,6 +1831,43 @@ public class JavaScriptLifter: Lifter {
17711831 writer. emit ( line)
17721832 }
17731833
1834+ mutating func recordLoopPos( ) {
1835+ loopPos. append ( LoopPosInfo ( loopBeginPos: code. count, exist: false ) )
1836+ }
1837+
1838+ mutating func popLoopPos( ) {
1839+ loopPos. popLast ( )
1840+ }
1841+
1842+ mutating func getLoopPos( _ idx: Int ) -> Int {
1843+ return loopPos [ idx] . loopBeginPos
1844+ }
1845+
1846+ // if we insert one label into code, then the after record index move the same length
1847+ mutating func updateLoopPos( _ startIndex: Int , _ len: Int ) {
1848+ if ( startIndex <= loopPos. count - 1 ) {
1849+ for i in startIndex... loopPos. count - 1 {
1850+ loopPos [ i] . loopBeginPos += len
1851+ }
1852+ }
1853+ }
1854+
1855+ mutating func getLabelExist( _ idx: Int ) -> Bool {
1856+ return loopPos [ idx] . exist
1857+ }
1858+
1859+ mutating func setLabelExist( _ idx: Int ) {
1860+ loopPos [ idx] . exist = true
1861+ }
1862+
1863+ mutating func clearLoopPos( ) {
1864+ loopPos = [ ]
1865+ }
1866+
1867+ mutating func insertLabel( _ pos: Int , _ content: String ) {
1868+ writer. insert ( pos, content)
1869+ }
1870+
17741871 /// Emit a (potentially multi-line) comment.
17751872 mutating func emitComment( _ comment: String ) {
17761873 writer. emitComment ( comment)
0 commit comments