Skip to content

Commit

Permalink
bugfix code generation of defer block in loop expression
Browse files Browse the repository at this point in the history
  • Loading branch information
sekiguchi-nagisa committed Sep 8, 2023
1 parent a851d4c commit aaccf0b
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
- option parsing of builtin echo command
- fix common super type resolution that have unresolved type
- common prefix resolution of completion candidates that having multi-bytes characters
- fix code generation of defer block in loop expression

## [0.30.0] - 2023-07-01

Expand Down
1 change: 1 addition & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,7 @@ void ByteCodeGenerator::visitJumpNode(JumpNode &node) {
switch (node.getOpKind()) {
case JumpNode::BREAK:
case JumpNode::CONTINUE:
case JumpNode::IMPLICIT_CONTINUE:
this->generateBreakContinue(node);
break;
case JumpNode::THROW: {
Expand Down
5 changes: 5 additions & 0 deletions src/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,10 @@ LoopNode::LoopNode(unsigned int startPos, std::unique_ptr<Node> &&initNode,
this->iterNode = std::make_unique<EmptyNode>();
}

if (this->blockNode->getNodes().empty() || !isa<JumpNode>(*this->blockNode->getNodes().back())) {
this->blockNode->addNode(JumpNode::newContinue({0, 0}, false));
}

this->updateToken(this->asDoWhile ? this->condNode->getToken() : this->blockNode->getToken());
}

Expand Down Expand Up @@ -759,6 +763,7 @@ void JumpNode::dump(NodeDumper &dumper) const {
#define EACH_ENUM(OP) \
OP(BREAK) \
OP(CONTINUE) \
OP(IMPLICIT_CONTINUE) \
OP(THROW) \
OP(RETURN) \
OP(RETURN_INIT)
Expand Down
6 changes: 4 additions & 2 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -1927,6 +1927,7 @@ class JumpNode : public WithRtti<Node, NodeKind::Jump> {
enum OpKind : unsigned char {
BREAK,
CONTINUE,
IMPLICIT_CONTINUE, // for loop end without explicit continue
THROW,
RETURN,
RETURN_INIT, // for constructor
Expand All @@ -1946,8 +1947,9 @@ class JumpNode : public WithRtti<Node, NodeKind::Jump> {
return std::unique_ptr<JumpNode>(new JumpNode(token, BREAK, std::move(exprNode)));
}

static std::unique_ptr<JumpNode> newContinue(Token token) {
return std::unique_ptr<JumpNode>(new JumpNode(token, CONTINUE, nullptr));
static std::unique_ptr<JumpNode> newContinue(Token token, bool explicitContinue = true) {
return std::unique_ptr<JumpNode>(
new JumpNode(token, explicitContinue ? CONTINUE : IMPLICIT_CONTINUE, nullptr));
}

/**
Expand Down
14 changes: 5 additions & 9 deletions src/type_checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,10 @@ void TypeChecker::checkTypeWithCurrentScope(const DSType *requiredType, BlockNod
for (auto iter = blockNode.refNodes().begin(); iter != blockNode.refNodes().end(); ++iter) {
auto &targetNode = *iter;
if (blockType->isNothingType()) {
this->reportError<Unreachable>(*targetNode);
if (!isa<JumpNode>(*targetNode) ||
cast<JumpNode>(*targetNode).getOpKind() != JumpNode::IMPLICIT_CONTINUE) {
this->reportError<Unreachable>(*targetNode);
}
}

// type check
Expand Down Expand Up @@ -1243,14 +1246,6 @@ void TypeChecker::visitLoopNode(LoopNode &node) {
blockNode.setBaseIndex(baseIndex + 1);
blockNode.setVarSize(varSize - 1);
}

if (!node.getBlockNode().getType().isNothingType()) { // insert continue to block end
auto jumpNode = JumpNode::newContinue({0, 0});
jumpNode->setType(this->typePool().get(TYPE::Nothing));
jumpNode->getExprNode().setType(this->typePool().get(TYPE::Void));
node.getBlockNode().setType(jumpNode->getType());
node.getBlockNode().addNode(std::move(jumpNode));
}
}

void TypeChecker::resolveIfLet(IfNode &node) {
Expand Down Expand Up @@ -1778,6 +1773,7 @@ void TypeChecker::visitJumpNode(JumpNode &node) {
switch (node.getOpKind()) {
case JumpNode::BREAK:
case JumpNode::CONTINUE:
case JumpNode::IMPLICIT_CONTINUE:
this->checkTypeAsBreakContinue(node);
break;
case JumpNode::THROW:
Expand Down
20 changes: 19 additions & 1 deletion test/exec/cases/base/defer1.ds
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,22 @@ var ii = new Interval(10,20)
assert $ii.begin == 10
assert $ii.end == 20

assert "$(new Interval(10, 20))" == $'10010\n10 ~~ 20'
assert "$(new Interval(10, 20))" == $'10010\n10 ~~ 20'

## defer in loop
var o = "$(
for(var i = 0; $i < 5; $i++) {
defer { echo defer: $i; }
echo enter: $i
}
)"
assert $o == "enter: 0
defer: 0
enter: 1
defer: 1
enter: 2
defer: 2
enter: 3
defer: 3
enter: 4
defer: 4" : $o
2 changes: 1 addition & 1 deletion test/node/node_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ static constexpr NodeDumpParam paramTable[] = {
pos: 0
size: 0
type: "Nothing"
opKind: "CONTINUE"
opKind: "IMPLICIT_CONTINUE"
fieldOffset: 0
fieldSize: 0
tryDepth: 0
Expand Down

0 comments on commit aaccf0b

Please sign in to comment.