Implement ++ and -- operators.
authorDavid Anderson <dvander@alliedmods.net>
Sun Jul 01 18:21:15 2012 -0700 (2012-07-01)
changeset 238a31742781c1
parent 22 765ab1b672a3
child 24 03c6a312213b
Implement ++ and -- operators.
jitcraft/AST.h
jitcraft/BytecodeCompiler.cpp
jitcraft/BytecodeCompiler.h
jitcraft/BytecodeEmitter.h
jitcraft/Interpreter.cpp
jitcraft/Opcodes.cpp
jitcraft/Opcodes.tbl
jitcraft/Parser.cpp
jitcraft/Scanner.cpp
jitcraft/SemanticAnalysis.cpp
jitcraft/SemanticAnalysis.h
jitcraft/Token.h
     1.1 --- a/jitcraft/AST.h	Sun Jul 01 16:36:39 2012 -0700
     1.2 +++ b/jitcraft/AST.h	Sun Jul 01 18:21:15 2012 -0700
     1.3 @@ -44,7 +44,8 @@
     1.4      _(EnumStatement)            \
     1.5      _(WhileStatement)           \
     1.6      _(BreakStatement)           \
     1.7 -    _(ContinueStatement)
     1.8 +    _(ContinueStatement)        \
     1.9 +    _(IncDecExpression)
    1.10  
    1.11  // Forward declarations.
    1.12  #define _(name) class name;
    1.13 @@ -694,6 +695,37 @@
    1.14      EntryList *entries_;
    1.15  };
    1.16  
    1.17 +class IncDecExpression : public Expression
    1.18 +{
    1.19 +    TokenKind token_;
    1.20 +    Expression *expression_;
    1.21 +    bool postfix_;
    1.22 +
    1.23 +  public:
    1.24 +    IncDecExpression(TokenKind token, Expression *expression, bool postfix)
    1.25 +      : token_(token),
    1.26 +        expression_(expression),
    1.27 +        postfix_(postfix)
    1.28 +    {
    1.29 +    }
    1.30 +
    1.31 +    Kind kind() const {
    1.32 +        return kIncDecExpression;
    1.33 +    }
    1.34 +    TokenKind token() const {
    1.35 +        return token_;
    1.36 +    }
    1.37 +    Expression *expression() const {
    1.38 +        return expression_;
    1.39 +    }
    1.40 +    bool postfix() const {
    1.41 +        return postfix_;
    1.42 +    }
    1.43 +    void accept(AstVisitor *visitor) {
    1.44 +        visitor->visit(this);
    1.45 +    }
    1.46 +};
    1.47 +
    1.48  class Scope;
    1.49  
    1.50  typedef std::vector<NameProxy *> NameProxyList;
     2.1 --- a/jitcraft/BytecodeCompiler.cpp	Sun Jul 01 16:36:39 2012 -0700
     2.2 +++ b/jitcraft/BytecodeCompiler.cpp	Sun Jul 01 18:21:15 2012 -0700
     2.3 @@ -194,7 +194,7 @@
     2.4                  __ get(var);
     2.5              }
     2.6          }
     2.7 -    } else if (node->lvalue()->isIndexExpression()) {
     2.8 +    } else {
     2.9          IndexExpression *index = node->lvalue()->toIndexExpression();
    2.10  
    2.11          // Note: Eventually, watch out for a whole here. An expression like:
    2.12 @@ -241,7 +241,7 @@
    2.13              __ set(var);
    2.14      } else {
    2.15          IndexExpression *index = node->lvalue()->toIndexExpression();
    2.16 -        // :TODO: get rid of the BOUNDS instruction, embed it in setarray*?
    2.17 +        // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
    2.18          // We can't emit it here because the stack is slightly out of position.
    2.19          // __ bounds();
    2.20          __ setarray(index->left()->type()->contained()->primitive());
    2.21 @@ -249,6 +249,110 @@
    2.22  }
    2.23  
    2.24  void
    2.25 +BytecodeCompiler::visit(IncDecExpression *node)
    2.26 +{
    2.27 +    // In the postfix case, the logic looks like:
    2.28 +    //      (1) Bind       -> REF
    2.29 +    //      (2) Dup        -> REF REF
    2.30 +    //      (3) Fetch      -> REF VAL
    2.31 +    //      (4) Swap       -> VAL REF
    2.32 +    //      (5) Pick       -> VAL REF VAL
    2.33 +    //      (6) Add        -> VAL REF VAL+1
    2.34 +    //      (7) Store      -> VAL VAL+1
    2.35 +    //      (8) Drop       -> VAL
    2.36 +    //
    2.37 +    // In the prefix case, the logic looks like:
    2.38 +    //      (1) Bind       -> REF
    2.39 +    //      (2) Dup        -> REF REF
    2.40 +    //      (3) Fetch      -> REF VAL
    2.41 +    //      --
    2.42 +    //      --
    2.43 +    //      (6) Add        -> REF VAL+1
    2.44 +    //      (7) Store      -> VAL+1
    2.45 +    //      --
    2.46 +    //
    2.47 +    // This is squirrely enough such that we don't bother sharing too much
    2.48 +    // with the above.
    2.49 +    // 
    2.50 +    // Note: We simulate a "Pick" operation with a dup2+pop.
    2.51 +
    2.52 +    // This is steps (1) to (5).
    2.53 +    Expression *expr = node->expression();
    2.54 +    if (expr->isNameProxy()) {
    2.55 +        NameProxy *proxy = expr->toNameProxy();
    2.56 +        Variable *var = proxy->binding()->toVariable();
    2.57 +
    2.58 +        // Bind.
    2.59 +        if (var->type()->isReference() || var->type()->isArray())
    2.60 +            __ get(var);
    2.61 +
    2.62 +        // Dup and fetch.
    2.63 +        if (var->type()->isReference()) {
    2.64 +            __ dup();
    2.65 +            __ getref(node->type()->primitive());
    2.66 +            if (node->postfix()) {
    2.67 +                __ swap();
    2.68 +                __ pick2();
    2.69 +            }
    2.70 +        } else {
    2.71 +            assert(!var->type()->isArray());
    2.72 +            __ get(var);
    2.73 +            if (node->postfix())
    2.74 +                __ dup();
    2.75 +        }
    2.76 +    } else {
    2.77 +        IndexExpression *index = expr->toIndexExpression();
    2.78 +        index->left()->accept(this);
    2.79 +        index->right()->accept(this);
    2.80 +
    2.81 +        assert(!node->type()->isArray());
    2.82 +        __ bounds();
    2.83 +        __ dup2();
    2.84 +        __ getarray(node->type()->primitive());
    2.85 +
    2.86 +        if (node->postfix()) {
    2.87 +            // The stack looks like this now:
    2.88 +            // ARRAY INDEX VALUE
    2.89 +            //
    2.90 +            // So we must use a PICK operation to rotate the stack into position.
    2.91 +            __ roll3();         // INDEX VALUE ARRAY
    2.92 +            __ roll3();         // VALUE ARRAY INDEX
    2.93 +            __ pick3();         // VALUE ARRAY INDEX VALUE
    2.94 +        }
    2.95 +    }
    2.96 +
    2.97 +    // Perform step (6).
    2.98 +    if (node->type()->isFloat()) {
    2.99 +        __ float_(1.0);
   2.100 +    } else {
   2.101 +        assert(node->type()->isInt32());
   2.102 +        __ int_(1);
   2.103 +    }
   2.104 +
   2.105 +    if (node->token() == TOK_INCREMENT)
   2.106 +        __ binary(OP_ADD);
   2.107 +    else
   2.108 +        __ binary(OP_SUB);
   2.109 +
   2.110 +    // Perform step (7).
   2.111 +    if (expr->isNameProxy()) {
   2.112 +        NameProxy *proxy = expr->toNameProxy();
   2.113 +        Variable *var = proxy->binding()->toVariable();
   2.114 +
   2.115 +        if (var->type()->isReference())
   2.116 +            __ setref(node->type()->primitive());
   2.117 +        else
   2.118 +            __ set(var);
   2.119 +    } else {
   2.120 +        __ setarray(node->type()->primitive());
   2.121 +    }
   2.122 +
   2.123 +    // Perform step (8).
   2.124 +    if (node->postfix())
   2.125 +        __ pop();
   2.126 +}
   2.127 +
   2.128 +void
   2.129  BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   2.130  {
   2.131      node->accept(this);
     3.1 --- a/jitcraft/BytecodeCompiler.h	Sun Jul 01 16:36:39 2012 -0700
     3.2 +++ b/jitcraft/BytecodeCompiler.h	Sun Jul 01 18:21:15 2012 -0700
     3.3 @@ -123,6 +123,7 @@
     3.4      void visit(WhileStatement *node);
     3.5      void visit(BreakStatement *node);
     3.6      void visit(ContinueStatement *node);
     3.7 +    void visit(IncDecExpression *node);
     3.8  };
     3.9  
    3.10  }
     4.1 --- a/jitcraft/BytecodeEmitter.h	Sun Jul 01 16:36:39 2012 -0700
     4.2 +++ b/jitcraft/BytecodeEmitter.h	Sun Jul 01 18:21:15 2012 -0700
     4.3 @@ -389,6 +389,18 @@
     4.4      void dup2() {
     4.5          singleByteOp(OP_DUP2);
     4.6      }
     4.7 +    void swap() {
     4.8 +        singleByteOp(OP_SWAP);
     4.9 +    }
    4.10 +    void roll3() {
    4.11 +        singleByteOp(OP_ROLL3);
    4.12 +    }
    4.13 +    void pick2() {
    4.14 +        singleByteOp(OP_PICK2);
    4.15 +    }
    4.16 +    void pick3() {
    4.17 +        singleByteOp(OP_PICK3);
    4.18 +    }
    4.19  };
    4.20  
    4.21  }
     5.1 --- a/jitcraft/Interpreter.cpp	Sun Jul 01 16:36:39 2012 -0700
     5.2 +++ b/jitcraft/Interpreter.cpp	Sun Jul 01 18:21:15 2012 -0700
     5.3 @@ -551,6 +551,7 @@
     5.4  {
     5.5      top.sp[-2].ref->setInt(top.sp[-1].i32);
     5.6      top.sp[-2].i32 = top.sp[-1].i32;
     5.7 +    top.sp--;
     5.8      break;
     5.9  }
    5.10  
    5.11 @@ -588,14 +589,47 @@
    5.12  
    5.13  case OP_DUP:
    5.14  {
    5.15 -    *top.sp++ = *top.sp;
    5.16 +    top.sp++;
    5.17 +    top.sp[-1] = top.sp[-2];
    5.18      break;
    5.19  }
    5.20  
    5.21  case OP_DUP2:
    5.22  {
    5.23 -    *top.sp++ = top.sp[-2];
    5.24 -    *top.sp++ = top.sp[-2];
    5.25 +    top.sp += 2;
    5.26 +    top.sp[-2] = top.sp[-4];
    5.27 +    top.sp[-1] = top.sp[-3];
    5.28 +    break;
    5.29 +}
    5.30 +
    5.31 +case OP_SWAP:
    5.32 +{
    5.33 +    LocalSlot slot = top.sp[-2];
    5.34 +    top.sp[-2] = top.sp[-1];
    5.35 +    top.sp[-1] = slot;
    5.36 +    break;
    5.37 +}
    5.38 +
    5.39 +case OP_ROLL3:
    5.40 +{
    5.41 +    LocalSlot slot = top.sp[-3];
    5.42 +    top.sp[-3] = top.sp[-2];
    5.43 +    top.sp[-2] = top.sp[-1];
    5.44 +    top.sp[-1] = slot;
    5.45 +    break;
    5.46 +}
    5.47 +
    5.48 +case OP_PICK2:
    5.49 +{
    5.50 +    top.sp++;
    5.51 +    top.sp[-1] = top.sp[-3];
    5.52 +    break;
    5.53 +}
    5.54 +
    5.55 +case OP_PICK3:
    5.56 +{
    5.57 +    top.sp++;
    5.58 +    top.sp[-1] = top.sp[-4];
    5.59      break;
    5.60  }
    5.61  
     6.1 --- a/jitcraft/Opcodes.cpp	Sun Jul 01 16:36:39 2012 -0700
     6.2 +++ b/jitcraft/Opcodes.cpp	Sun Jul 01 18:21:15 2012 -0700
     6.3 @@ -106,6 +106,10 @@
     6.4            case OP_ARRAYCOPY:
     6.5            case OP_DUP:
     6.6            case OP_DUP2:
     6.7 +          case OP_SWAP:
     6.8 +          case OP_ROLL3:
     6.9 +          case OP_PICK2:
    6.10 +          case OP_PICK3:
    6.11              break;
    6.12  
    6.13            case OP_STOP:
     7.1 --- a/jitcraft/Opcodes.tbl	Sun Jul 01 16:36:39 2012 -0700
     7.2 +++ b/jitcraft/Opcodes.tbl	Sun Jul 01 18:21:15 2012 -0700
     7.3 @@ -163,3 +163,23 @@
     7.4  
     7.5  // Duplicates the top two items on the stack.
     7.6  OPDEF(OP_DUP2,          57,         "dup2",         1,      2,  4)
     7.7 +
     7.8 +// Swaps the two items at the top of the stack.
     7.9 +OPDEF(OP_SWAP,          58,         "swap",         1,      2,  2)
    7.10 +
    7.11 +// Roll operation is the same as Forth. It steals a value on the stack,
    7.12 +// shifting all stack values down, and then places the stolen value back at
    7.13 +// the top of the stack.
    7.14 +//
    7.15 +//  p = sp[-3]
    7.16 +//  sp[-3] = sp[-2]
    7.17 +//  sp[-2] = sp[-1]
    7.18 +//  sp[-1] = p
    7.19 +OPDEF(OP_ROLL3,         59,         "roll3",        1,      3, 3)
    7.20 +
    7.21 +// Pick operation is the same as Forth. It pushes a copy of a slot at a
    7.22 +// specific depth.
    7.23 +//
    7.24 +// push(sp[-n])
    7.25 +OPDEF(OP_PICK2,         60,         "pick2",        1,      2, 3)
    7.26 +OPDEF(OP_PICK3,         61,         "pick3",        1,      3, 4)
     8.1 --- a/jitcraft/Parser.cpp	Sun Jul 01 16:36:39 2012 -0700
     8.2 +++ b/jitcraft/Parser.cpp	Sun Jul 01 18:21:15 2012 -0700
     8.3 @@ -226,7 +226,30 @@
     8.4  Expression *
     8.5  Parser::unary()
     8.6  {
     8.7 -    return primary();
     8.8 +    TokenKind token = scanner_.peek();
     8.9 +
    8.10 +    switch (token) {
    8.11 +      case TOK_INCREMENT:
    8.12 +      case TOK_DECREMENT:
    8.13 +      {
    8.14 +        scanner_.scan();
    8.15 +        Expression *expr = expression();
    8.16 +        if (!expr)
    8.17 +            return NULL;
    8.18 +
    8.19 +        return new (pool_) IncDecExpression(token, expr, false);
    8.20 +      }
    8.21 +    }
    8.22 +
    8.23 +    Expression *expr = primary();
    8.24 +
    8.25 +    token = scanner_.peek();
    8.26 +    if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
    8.27 +        scanner_.scan();
    8.28 +        return new (pool_) IncDecExpression(token, expr, true);
    8.29 +    }
    8.30 +
    8.31 +    return expr;
    8.32  }
    8.33  
    8.34  Expression *
    8.35 @@ -1014,6 +1037,13 @@
    8.36          prefix();
    8.37          fprintf(fp_, "[ StringLiteral\n");
    8.38      }
    8.39 +    void visit(IncDecExpression *node) {
    8.40 +        prefix();
    8.41 +        fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
    8.42 +        indent();
    8.43 +        node->expression()->accept(this);
    8.44 +        unindent();
    8.45 +    }
    8.46  };
    8.47  
    8.48  void
     9.1 --- a/jitcraft/Scanner.cpp	Sun Jul 01 16:36:39 2012 -0700
     9.2 +++ b/jitcraft/Scanner.cpp	Sun Jul 01 18:21:15 2012 -0700
     9.3 @@ -387,6 +387,8 @@
     9.4              c = getChar();
     9.5              if (c == '=')
     9.6                  return TOK_ASSIGN_ADD;
     9.7 +            if (c == '+')
     9.8 +                return TOK_INCREMENT;
     9.9              putChar(c);
    9.10              return TOK_PLUS;
    9.11  
    9.12 @@ -415,6 +417,8 @@
    9.13              c = getChar();
    9.14              if (c == '=')
    9.15                  return TOK_ASSIGN_SUB;
    9.16 +            if (c == '-')
    9.17 +                return TOK_DECREMENT;
    9.18              putChar(c);
    9.19              return TOK_MINUS;
    9.20  
    10.1 --- a/jitcraft/SemanticAnalysis.cpp	Sun Jul 01 16:36:39 2012 -0700
    10.2 +++ b/jitcraft/SemanticAnalysis.cpp	Sun Jul 01 18:21:15 2012 -0700
    10.3 @@ -211,30 +211,46 @@
    10.4      return left;
    10.5  }
    10.6  
    10.7 +Type *
    10.8 +SemanticAnalysis::visitForLValue(Expression *expression)
    10.9 +{
   10.10 +    if (expression->isIndexExpression()) {
   10.11 +        expression->accept(this);
   10.12 +        if (!expression->type())
   10.13 +            return NULL;
   10.14 +        return expression->type()->contained();
   10.15 +    }
   10.16 +
   10.17 +    if (!expression->isNameProxy()) {
   10.18 +        assert(false);
   10.19 +        return NULL;
   10.20 +    }
   10.21 +
   10.22 +    NameProxy *proxy = expression->toNameProxy();
   10.23 +    if (!proxy->binding()->kind() == BoundName::VARIABLE) {
   10.24 +        fprintf(stderr, "error\n");
   10.25 +        return NULL;
   10.26 +    }
   10.27 +
   10.28 +    Variable *var = proxy->binding()->toVariable();
   10.29 +    if (!var->type())
   10.30 +        return NULL;
   10.31 +
   10.32 +    if  (var->type()->isReference())
   10.33 +        return var->type()->contained();
   10.34 +    return var->type();
   10.35 +}
   10.36 +
   10.37  void
   10.38  SemanticAnalysis::visit(Assignment *node)
   10.39  {
   10.40      visitForLoad(node->expression());
   10.41  
   10.42 -    if (node->lvalue()->isIndexExpression()) {
   10.43 -        node->lvalue()->accept(this);
   10.44 -        node->setType(node->lvalue()->type()->contained());
   10.45 -    } else {
   10.46 -        NameProxy *proxy = node->lvalue()->toNameProxy();
   10.47 -        if (!proxy->binding()->kind() == BoundName::VARIABLE) {
   10.48 -            fprintf(stderr, "error\n");
   10.49 -            return;
   10.50 -        }
   10.51 -
   10.52 -        Variable *var = proxy->binding()->toVariable();
   10.53 -        if (!var->type())
   10.54 -            return;
   10.55 -
   10.56 -        if  (var->type()->isReference())
   10.57 -            node->setType(var->type()->contained());
   10.58 -        else
   10.59 -            node->setType(var->type());
   10.60 -    }
   10.61 +    // :TODO: use Local
   10.62 +    Type *type = visitForLValue(node->lvalue());
   10.63 +    if (!type)
   10.64 +        return;
   10.65 +    node->setType(type);
   10.66  
   10.67      if (node->token() != TOK_ASSIGN)
   10.68          assert(TypeCheckBinary(node->token(), node->type(), node->expression()->type()));
   10.69 @@ -243,6 +259,25 @@
   10.70  }
   10.71  
   10.72  void
   10.73 +SemanticAnalysis::visit(IncDecExpression *node)
   10.74 +{
   10.75 +    // :TODO: use Local
   10.76 +    Type *type = visitForLValue(node->expression());
   10.77 +    if (!type)
   10.78 +        return;
   10.79 +
   10.80 +    assert(!type->isReference());
   10.81 +    if (type->isArray()) {
   10.82 +        // can't a[]++
   10.83 +        assert(false);
   10.84 +        return;
   10.85 +    }
   10.86 +
   10.87 +    assert((type->isInt32() && !type->tag()) || type->isFloat());
   10.88 +    node->setType(type);
   10.89 +}
   10.90 +
   10.91 +void
   10.92  SemanticAnalysis::visit(BinaryExpression *node)
   10.93  {
   10.94      // :TODO: use Local
    11.1 --- a/jitcraft/SemanticAnalysis.h	Sun Jul 01 16:36:39 2012 -0700
    11.2 +++ b/jitcraft/SemanticAnalysis.h	Sun Jul 01 18:21:15 2012 -0700
    11.3 @@ -39,6 +39,7 @@
    11.4      Type *visitForLoad(Expression *expression);
    11.5      Type *visitForRef(Expression *expression);
    11.6      bool preanalyze(FunctionStatement *node);
    11.7 +    Type *visitForLValue(Expression *expression);
    11.8  
    11.9    public:
   11.10      SemanticAnalysis(ParseTree *tree);
   11.11 @@ -64,6 +65,7 @@
   11.12      void visit(BreakStatement *node);
   11.13      void visit(ContinueStatement *node);
   11.14      void visit(StringLiteral *node);
   11.15 +    void visit(IncDecExpression *node);
   11.16  };
   11.17  
   11.18  } // namespace jc
    12.1 --- a/jitcraft/Token.h	Sun Jul 01 16:36:39 2012 -0700
    12.2 +++ b/jitcraft/Token.h	Sun Jul 01 18:21:15 2012 -0700
    12.3 @@ -70,6 +70,8 @@
    12.4      _(ASSIGN_SHR,         ">>=")                        \
    12.5      _(ASSIGN_USHR,        ">>>=")                       \
    12.6      _(ASSIGN_SHL,         "<<=")                        \
    12.7 +    _(INCREMENT,          "++")                         \
    12.8 +    _(DECREMENT,          "--")                         \
    12.9      _(EQUALS,             "==")                         \
   12.10      _(NOTEQUALS,          "!=")                         \
   12.11      _(LT,                 "<")                          \