-
Notifications
You must be signed in to change notification settings - Fork 324
feature/loopNestedContinue #512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot! Did a first round of review now
@@ -54,7 +54,7 @@ public let CodeGenerators: [CodeGenerator] = [ | |||
ValueGenerator("StringGenerator") { b, n in | |||
for _ in 0..<n { | |||
b.loadString(b.randomString()) | |||
} | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit unnecessary whitespace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for your suggestion, and my apologies for the bad code style.
@@ -2256,7 +2256,7 @@ final class BeginFinally: JsOperation { | |||
|
|||
final class EndTryCatchFinally: JsOperation { | |||
override var opcode: Opcode { .endTryCatchFinally(self) } | |||
|
|||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit same here
@@ -2464,6 +2464,17 @@ class BindMethod: JsOperation { | |||
} | |||
} | |||
|
|||
final class LoopNestedContinue: JsOperation { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe here would be a good place for a short comment describing how this operation works, in particular how depth
is interpreted (e.g. that it wraps around if there are fewer open loops)
w.emitBlock("while (\(COND)) {") | ||
w.enterNewBlock() | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More whitespace here and below
@@ -101,6 +101,8 @@ public class JavaScriptLifter: Lifter { | |||
|
|||
var w = JavaScriptWriter(analyzer: analyzer, version: version, stripComments: !options.contains(.includeComments), includeLineNumbers: options.contains(.includeLineNumbers)) | |||
|
|||
var loopLabelStack = LabelStack(type: .loopblock) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we assert
at the end of the lifting that this stack is now empty? Just to catch any cases where we forget the pop()
|
||
enum LabelType { | ||
case loopblock | ||
case ifblock |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess for this PR, only loopBlock
would be supported? The others should probably move to the corresponding PR
} | ||
} | ||
|
||
mutating func translateBreakLabel(w: inout ScriptWriter, expDepth: Int){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: missing space before {
(also below)
@@ -84,4 +84,12 @@ struct ScriptWriter { | |||
assert(currentIndention.count >= indent.count) | |||
currentIndention.removeLast(indent.count) | |||
} | |||
|
|||
mutating func insert(_ pos: Int, _ content: String){ | |||
if code.index(code.startIndex, offsetBy: pos, limitedBy: code.endIndex) != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this ever not be the case? Wouldn't that be a bug?
@@ -3095,4 +3095,35 @@ class LifterTests: XCTestCase { | |||
""" | |||
XCTAssertEqual(actual, expected) | |||
} | |||
} | |||
|
|||
func testLoopNestedContinueLifting(){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering, does the label insertion work correctly if we also print line numbers? Did this test:
func testLiftingWithLineNumbers() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this change breaks line numbering, maybe we could just add the label to the same line as the loop begin? So lift to something like label1: for (...) {
instead?
} | ||
|
||
/// A structure that manages label positions within a specific control flow block (e.g., loop, if, switch, etc.). | ||
public struct LabelStack { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this struct should actually be part of the ScriptWriter or the JavaScriptWriter itself. It feels a bit awkward that you need to pass in the ScriptWriter or internal state of the script writer (the current position). I think this would all go away if the ScriptWriter/JavaScriptWriter itself maintained this stack. And I think it would also remove the need for the withScriptWriter
method above. Would that work? That way, the ScriptWriter also wound't need to expose the insert
method which probably shouldn't be used for any other purposes.
17edc6b
to
e0e81c9
Compare
Hi Saelo,
First of all, I sincerely apologize for the long delay regarding the implementation of
LabelStatement
.Following your suggestion #479 , I have split this feature into two separate PRs,
LoopNestedContinue
andNestedBreak
.This PR implements
LoopNestedContinue
. As discussed in #479, I add a new JsOperationloopNestedContinueand
and a new CodeGeneratorLoopNestedContinueGenerator
. Beside, the code design inJavaScriptLifter.swift
is as follows:LabelStack
to trace the nested code block.LabelStack
isLabelPin
, which has two fields:beginPos
andhasLabel
.beginPos
is the index of the starting point of the js code block, andhasLabel
indicates whetherbeginPos
has generated a label (with a small probability of generating N lines of break or continue in the same block).continueNested
appears. Therefore, the core operation ofLabelStack
isinsertLabel
, which has three operations: ① Insert label string into js code; ② mark that a label has been inserted here; ③Move the positions of all LabelPins behind the stack at the corresponding depth back by the corresponding size.Please let me know if any changes are needed; Thanks a lot!