Implemented break and continue support.
authorDavid Anderson <dvander@alliedmods.net>
Thu Jun 28 01:38:56 2012 -0700 (2012-06-28)
changeset 100c3bcd50e361
parent 9 73781c5a59d7
child 11 a350c2cc736a
Implemented break and continue support.
jitcraft/AST.h
jitcraft/BytecodeCompiler.cpp
jitcraft/BytecodeCompiler.h
jitcraft/Interpreter.cpp
jitcraft/Parser.cpp
jitcraft/Scanner.cpp
jitcraft/SemanticAnalysis.cpp
jitcraft/SemanticAnalysis.h
jitcraft/Stack.cpp
jitcraft/Stack.h
jitcraft/Token.h
tests/prototype/break-continue-in-for.sp
tests/prototype/continue-in-while.sp
     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 +}