Implemented break and continue support.
Implemented break and continue support.
1.1 --- a/jitcraft/AST.h Thu Jun 28 00:54:45 2012 -0700
1.2 +++ b/jitcraft/AST.h Thu Jun 28 01:38:56 2012 -0700
1.3 @@ -41,7 +41,9 @@
1.4 _(IfStatement) \
1.5 _(IndexExpression) \
1.6 _(EnumStatement) \
1.7 - _(WhileStatement)
1.8 + _(WhileStatement) \
1.9 + _(BreakStatement) \
1.10 + _(ContinueStatement)
1.11
1.12 // Forward declarations.
1.13 #define _(name) class name;
1.14 @@ -423,6 +425,36 @@
1.15 }
1.16 };
1.17
1.18 +class BreakStatement : public Statement
1.19 +{
1.20 + public:
1.21 + BreakStatement()
1.22 + {
1.23 + }
1.24 +
1.25 + Kind kind() const {
1.26 + return kBreakStatement;
1.27 + }
1.28 + void accept(AstVisitor *visitor) {
1.29 + visitor->visit(this);
1.30 + }
1.31 +};
1.32 +
1.33 +class ContinueStatement : public Statement
1.34 +{
1.35 + public:
1.36 + ContinueStatement()
1.37 + {
1.38 + }
1.39 +
1.40 + Kind kind() const {
1.41 + return kContinueStatement;
1.42 + }
1.43 + void accept(AstVisitor *visitor) {
1.44 + visitor->visit(this);
1.45 + }
1.46 +};
1.47 +
1.48 class Assignment : public Expression
1.49 {
1.50 Expression *lvalue_;
2.1 --- a/jitcraft/BytecodeCompiler.cpp Thu Jun 28 00:54:45 2012 -0700
2.2 +++ b/jitcraft/BytecodeCompiler.cpp Thu Jun 28 01:38:56 2012 -0700
2.3 @@ -28,7 +28,8 @@
2.4
2.5 BytecodeCompiler::BytecodeCompiler(ParseTree *tree)
2.6 : tree_(tree),
2.7 - scope_(NULL)
2.8 + scope_(NULL),
2.9 + loop_(NULL)
2.10 {
2.11 }
2.12
2.13 @@ -104,6 +105,15 @@
2.14 }
2.15
2.16 void
2.17 +BytecodeCompiler::unwindTo(Scope *scope)
2.18 +{
2.19 + for (Scope *current = scope_; current != scope; current = current->enclosing()) {
2.20 + if (Variable *var = current->firstUnsafeArray())
2.21 + __ unwind(var->slot());
2.22 + }
2.23 +}
2.24 +
2.25 +void
2.26 BytecodeCompiler::visit(NameProxy *name)
2.27 {
2.28 switch (name->binding()->kind()) {
2.29 @@ -245,6 +255,10 @@
2.30 {
2.31 AutoEnterScope forScope(this, node->scope());
2.32
2.33 + Label join, update;
2.34 +
2.35 + LoopScope loop(scope_, &join, &update, &loop_);
2.36 +
2.37 if (node->declaration())
2.38 node->declaration()->accept(this);
2.39
2.40 @@ -255,6 +269,7 @@
2.41 __ bind(&header);
2.42 node->body()->accept(this);
2.43
2.44 + __ bind(&update);
2.45 if (node->update())
2.46 node->update()->accept(this);
2.47
2.48 @@ -265,6 +280,8 @@
2.49 __ jump(&header);
2.50 }
2.51
2.52 + __ bind(&join);
2.53 +
2.54 leaveScope(node->scope());
2.55 assert(__ stackDepth() == 0);
2.56 }
2.57 @@ -272,20 +289,36 @@
2.58 void
2.59 BytecodeCompiler::visit(WhileStatement *node)
2.60 {
2.61 - Label header;
2.62 + Label header, join;
2.63
2.64 __ bind(&header);
2.65
2.66 + LoopScope loop(scope_, &join, &header, &loop_);
2.67 +
2.68 if (node->token() == TOK_WHILE) {
2.69 - Label join;
2.70 visitForTest(node->condition(), &join, false);
2.71 node->body()->accept(this);
2.72 __ jump(&header);
2.73 - __ bind(&join);
2.74 } else {
2.75 node->body()->accept(this);
2.76 visitForTest(node->condition(), &header, true);
2.77 }
2.78 +
2.79 + __ bind(&join);
2.80 +}
2.81 +
2.82 +void
2.83 +BytecodeCompiler::visit(BreakStatement *node)
2.84 +{
2.85 + unwindTo(loop_->scope());
2.86 + __ jump(loop_->break_());
2.87 +}
2.88 +
2.89 +void
2.90 +BytecodeCompiler::visit(ContinueStatement *node)
2.91 +{
2.92 + unwindTo(loop_->scope());
2.93 + __ jump(loop_->continue_());
2.94 }
2.95
2.96 void
3.1 --- a/jitcraft/BytecodeCompiler.h Thu Jun 28 00:54:45 2012 -0700
3.2 +++ b/jitcraft/BytecodeCompiler.h Thu Jun 28 01:38:56 2012 -0700
3.3 @@ -34,6 +34,44 @@
3.4 Type **locals_;
3.5 Scope *scope_;
3.6
3.7 + class LoopScope
3.8 + {
3.9 + Scope *scope_;
3.10 + BytecodeEmitter::Label *bk_;
3.11 + BytecodeEmitter::Label *ct_;
3.12 + LoopScope **prevp_;
3.13 + LoopScope *prev_;
3.14 +
3.15 + public:
3.16 + LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
3.17 + LoopScope **prevp)
3.18 + : scope_(scope),
3.19 + bk_(bk),
3.20 + ct_(ct),
3.21 + prevp_(prevp),
3.22 + prev_(*prevp)
3.23 + {
3.24 + *prevp_ = this;
3.25 + }
3.26 +
3.27 + ~LoopScope()
3.28 + {
3.29 + *prevp_ = prev_;
3.30 + }
3.31 +
3.32 + BytecodeEmitter::Label *break_() {
3.33 + return bk_;
3.34 + }
3.35 + BytecodeEmitter::Label *continue_() {
3.36 + return ct_;
3.37 + }
3.38 + Scope *scope() {
3.39 + return scope_;
3.40 + }
3.41 + };
3.42 +
3.43 + LoopScope *loop_;
3.44 +
3.45 public:
3.46 class AutoEnterScope
3.47 {
3.48 @@ -55,6 +93,7 @@
3.49
3.50 private:
3.51 void leaveScope(Scope *scope);
3.52 + void unwindTo(Scope *scope);
3.53 void visitForTest(Expression *expression, BytecodeEmitter::Label *label, bool onTrue);
3.54 Code *compileFunction(Module *module, FunctionStatement *fun);
3.55 void visitForALU(Type *needed, Expression *node);
3.56 @@ -81,6 +120,8 @@
3.57 void visit(IndexExpression *node);
3.58 void visit(EnumStatement *node);
3.59 void visit(WhileStatement *node);
3.60 + void visit(BreakStatement *node);
3.61 + void visit(ContinueStatement *node);
3.62 };
3.63
3.64 }
4.1 --- a/jitcraft/Interpreter.cpp Thu Jun 28 00:54:45 2012 -0700
4.2 +++ b/jitcraft/Interpreter.cpp Thu Jun 28 01:38:56 2012 -0700
4.3 @@ -533,6 +533,15 @@
4.4 break;
4.5 }
4.6
4.7 +case OP_UNWIND:
4.8 +{
4.9 + unsigned slot = READ_UINT32(top.pc);
4.10 + UnsafeArray *ua = locals[slot].unsafeArray;
4.11 + assert((char *)ua >= (char *)frame->prevUnsafeStack());
4.12 + ZONE()->unsafeStack().unwind(ua->allocationBase());
4.13 + break;
4.14 +}
4.15 +
4.16 default:
4.17 assert(false);
4.18 return false;
5.1 --- a/jitcraft/Parser.cpp Thu Jun 28 00:54:45 2012 -0700
5.2 +++ b/jitcraft/Parser.cpp Thu Jun 28 01:38:56 2012 -0700
5.3 @@ -613,6 +613,16 @@
5.4 case TOK_WHILE:
5.5 return while_();
5.6
5.7 + case TOK_BREAK:
5.8 + scanner_.scan();
5.9 + statement = new (pool_) BreakStatement();
5.10 + break;
5.11 +
5.12 + case TOK_CONTINUE:
5.13 + scanner_.scan();
5.14 + statement = new (pool_) ContinueStatement();
5.15 + break;
5.16 +
5.17 case TOK_DO:
5.18 if ((statement = do_()) == NULL)
5.19 return NULL;
5.20 @@ -953,6 +963,14 @@
5.21 }
5.22 unindent();
5.23 }
5.24 + void visit(BreakStatement *node) {
5.25 + prefix();
5.26 + fprintf(fp_, "[ BreakStatement\n");
5.27 + }
5.28 + void visit(ContinueStatement *node) {
5.29 + prefix();
5.30 + fprintf(fp_, "[ ContinueStatement\n");
5.31 + }
5.32 };
5.33
5.34 void
6.1 --- a/jitcraft/Scanner.cpp Thu Jun 28 00:54:45 2012 -0700
6.2 +++ b/jitcraft/Scanner.cpp Thu Jun 28 01:38:56 2012 -0700
6.3 @@ -229,6 +229,10 @@
6.4 return TOK_WHILE;
6.5 if (literal_ == "do")
6.6 return TOK_DO;
6.7 + if (literal_ == "break")
6.8 + return TOK_BREAK;
6.9 + if (literal_ == "continue")
6.10 + return TOK_CONTINUE;
6.11 return (c == ':') ? TOK_LABEL : TOK_NAME;
6.12 }
6.13
7.1 --- a/jitcraft/SemanticAnalysis.cpp Thu Jun 28 00:54:45 2012 -0700
7.2 +++ b/jitcraft/SemanticAnalysis.cpp Thu Jun 28 01:38:56 2012 -0700
7.3 @@ -90,7 +90,8 @@
7.4 }
7.5
7.6 SemanticAnalysis::SemanticAnalysis(ParseTree *tree)
7.7 - : tree_(tree)
7.8 + : tree_(tree),
7.9 + loopDepth_(0)
7.10 {
7.11 }
7.12
7.13 @@ -202,6 +203,7 @@
7.14 void
7.15 SemanticAnalysis::visit(ForStatement *node)
7.16 {
7.17 + loopDepth_++;
7.18 if (node->declaration())
7.19 node->declaration()->accept(this);
7.20 if (node->condition())
7.21 @@ -209,13 +211,16 @@
7.22 if (node->update())
7.23 node->update()->accept(this);
7.24 node->body()->accept(this);
7.25 + loopDepth_--;
7.26 }
7.27
7.28 void
7.29 SemanticAnalysis::visit(WhileStatement *node)
7.30 {
7.31 + loopDepth_++;
7.32 node->condition()->accept(this);
7.33 node->body()->accept(this);
7.34 + loopDepth_--;
7.35 }
7.36
7.37 void
7.38 @@ -265,8 +270,10 @@
7.39 type = Type::NewUnsafeArray(type, size);
7.40 }
7.41 } else {
7.42 - Type *right = visitForLoad(node->initialization());
7.43 - assert(TypeCheck(type, right));
7.44 + if (node->initialization()) {
7.45 + Type *right = visitForLoad(node->initialization());
7.46 + assert(TypeCheck(type, right));
7.47 + }
7.48 }
7.49
7.50 node->variable()->setType(type);
7.51 @@ -299,6 +306,10 @@
7.52 void
7.53 SemanticAnalysis::visit(IfStatement *node)
7.54 {
7.55 + visitForLoad(node->condition());
7.56 + node->ifTrue()->accept(this);
7.57 + if (node->ifFalse())
7.58 + node->ifFalse()->accept(this);
7.59 }
7.60
7.61 void
7.62 @@ -356,3 +367,15 @@
7.63
7.64 node->setType(type);
7.65 }
7.66 +
7.67 +void
7.68 +SemanticAnalysis::visit(BreakStatement *node)
7.69 +{
7.70 + assert(loopDepth_ > 0);
7.71 +}
7.72 +
7.73 +void
7.74 +SemanticAnalysis::visit(ContinueStatement *node)
7.75 +{
7.76 + assert(loopDepth_ > 0);
7.77 +}
8.1 --- a/jitcraft/SemanticAnalysis.h Thu Jun 28 00:54:45 2012 -0700
8.2 +++ b/jitcraft/SemanticAnalysis.h Thu Jun 28 01:38:56 2012 -0700
8.3 @@ -26,6 +26,7 @@
8.4 class SemanticAnalysis : public AstVisitor
8.5 {
8.6 ParseTree *tree_;
8.7 + unsigned loopDepth_;
8.8
8.9 private:
8.10 void error() {
8.11 @@ -58,6 +59,8 @@
8.12 void visit(EnumStatement *node);
8.13 void visit(FloatLiteral *node);
8.14 void visit(WhileStatement *node);
8.15 + void visit(BreakStatement *node);
8.16 + void visit(ContinueStatement *node);
8.17 };
8.18
8.19 } // namespace jc
9.1 --- a/jitcraft/Stack.cpp Thu Jun 28 00:54:45 2012 -0700
9.2 +++ b/jitcraft/Stack.cpp Thu Jun 28 01:38:56 2012 -0700
9.3 @@ -103,7 +103,7 @@
9.4 if (!buffer_)
9.5 return false;
9.6
9.7 - pos_ = NULL;
9.8 + pos_ = buffer_;
9.9 end_ = buffer_ + STACK_SIZE;
9.10 return true;
9.11 }
9.12 \ No newline at end of file
10.1 --- a/jitcraft/Stack.h Thu Jun 28 00:54:45 2012 -0700
10.2 +++ b/jitcraft/Stack.h Thu Jun 28 01:38:56 2012 -0700
10.3 @@ -154,7 +154,7 @@
10.4 return NULL;
10.5 }
10.6
10.7 - void *ptr = buffer_;
10.8 + void *ptr = pos_;
10.9 pos_ += nbytes;
10.10 return ptr;
10.11 }
11.1 --- a/jitcraft/Token.h Thu Jun 28 00:54:45 2012 -0700
11.2 +++ b/jitcraft/Token.h Thu Jun 28 01:38:56 2012 -0700
11.3 @@ -34,6 +34,8 @@
11.4 _(LABEL, "<label>") \
11.5 _(WHILE, "<while>") \
11.6 _(DO, "<do>") \
11.7 + _(BREAK, "<break>") \
11.8 + _(CONTINUE, "<continue>") \
11.9 _(PLUS, "+") \
11.10 _(MINUS, "-") \
11.11 _(STAR, "*") \
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/tests/prototype/break-continue-in-for.sp Thu Jun 28 01:38:56 2012 -0700
12.3 @@ -0,0 +1,13 @@
12.4 +main()
12.5 +{
12.6 + new i;
12.7 + for (; i < 100; i = i + 1) {
12.8 + if (i >= 57)
12.9 + break;
12.10 + if (i >= 26) {
12.11 + i = i + 1;
12.12 + continue;
12.13 + }
12.14 + }
12.15 + return i;
12.16 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/tests/prototype/continue-in-while.sp Thu Jun 28 01:38:56 2012 -0700
13.3 @@ -0,0 +1,10 @@
13.4 +main()
13.5 +{
13.6 + new i = 0;
13.7 + do {
13.8 + new a[4];
13.9 + continue;
13.10 + i = i + 37;
13.11 + } while (i < 5);
13.12 + return i;
13.13 +}