Implement ++ and -- operators.
Implement ++ and -- operators.
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, "<") \