Implement switch.
Implement switch.
1.1 --- a/src/AST.h Sun Aug 12 13:22:56 2012 -0700
1.2 +++ b/src/AST.h Sun Aug 12 20:48:49 2012 -0700
1.3 @@ -51,7 +51,8 @@
1.4 _(UnaryExpression) \
1.5 _(TernaryExpression) \
1.6 _(BooleanLiteral) \
1.7 - _(StructureStatement)
1.8 + _(StructureStatement) \
1.9 + _(SwitchStatement)
1.10
1.11 // Forward declarations.
1.12 #define _(name) class name;
1.13 @@ -905,6 +906,87 @@
1.14 }
1.15 };
1.16
1.17 +class Case : public PoolObject
1.18 +{
1.19 + public:
1.20 + Case(Expression *expression, ExpressionList *others, Statement *statement)
1.21 + : expression_(expression),
1.22 + others_(others),
1.23 + statement_(statement)
1.24 + {
1.25 + }
1.26 +
1.27 + Expression *expression() const {
1.28 + return expression_;
1.29 + }
1.30 + PoolList<Expression *> *others() const {
1.31 + return others_;
1.32 + }
1.33 + Statement *statement() const {
1.34 + return statement_;
1.35 + }
1.36 +
1.37 + private:
1.38 + Expression *expression_;
1.39 + PoolList <Expression *> *others_;
1.40 + Statement *statement_;
1.41 +};
1.42 +
1.43 +struct CaseValue
1.44 +{
1.45 + BoxedPrimitive box;
1.46 + size_t statement;
1.47 +
1.48 + CaseValue(size_t statement)
1.49 + : statement(statement)
1.50 + {
1.51 + }
1.52 +};
1.53 +
1.54 +typedef PoolList<CaseValue> CaseValueList;
1.55 +
1.56 +class SwitchStatement : public Statement
1.57 +{
1.58 + public:
1.59 + SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
1.60 + Statement *def)
1.61 + : Statement(pos),
1.62 + expression_(expression),
1.63 + cases_(cases),
1.64 + default_(def),
1.65 + table_(NULL)
1.66 + {
1.67 + }
1.68 +
1.69 + Kind kind() const {
1.70 + return kSwitchStatement;
1.71 + }
1.72 + Expression *expression() const {
1.73 + return expression_;
1.74 + }
1.75 + PoolList<Case *> *cases() const {
1.76 + return cases_;
1.77 + }
1.78 + Statement *defaultCase() const {
1.79 + return default_;
1.80 + }
1.81 + void setCaseValueList(CaseValueList *list) {
1.82 + table_ = list;
1.83 + }
1.84 + CaseValueList *caseValueList() const {
1.85 + return table_;
1.86 + }
1.87 + void accept(AstVisitor *visitor) {
1.88 + visitor->visit(this);
1.89 + }
1.90 +
1.91 + private:
1.92 + Expression *expression_;
1.93 + PoolList<Case *> *cases_;
1.94 + Statement *default_;
1.95 + CaseValueList *table_;
1.96 +};
1.97 +
1.98 class StructureStatement : public Statement
1.99 {
1.100 public:
2.1 --- a/src/BytecodeCompiler.cpp Sun Aug 12 13:22:56 2012 -0700
2.2 +++ b/src/BytecodeCompiler.cpp Sun Aug 12 20:48:49 2012 -0700
2.3 @@ -971,6 +971,115 @@
2.4 __ bind(&join);
2.5 }
2.6
2.7 +bool
2.8 +BytecodeCompiler::tableswitch(SwitchStatement *node)
2.9 +{
2.10 + CaseValueList *values = node->caseValueList();
2.11 +
2.12 + if (values->length() < 3)
2.13 + return false;
2.14 +
2.15 + // Find the delta between the largest and smallest value.
2.16 + int hi = values->at(values->length() - 1).box.toInt();
2.17 + int lo = values->at(0).box.toInt();
2.18 + assert(hi > lo);
2.19 +
2.20 + unsigned tablesize = TableSwitchEntries(lo, hi);
2.21 + if (tablesize > MAX_TABLESWITCH_ENTRIES)
2.22 + return false;
2.23 +
2.24 + Label def, join;
2.25 +
2.26 + // Create the list of labels that each statement will bind to.
2.27 + Label *labels = new Label[node->cases()->length()];
2.28 +
2.29 + // Create the table of labels we'll use for each case.
2.30 + Label **table = new Label *[tablesize];
2.31 +
2.32 + // Link all cases, by default, to the default label.
2.33 + for (size_t i = 0; i < tablesize; i++)
2.34 + table[i] = &def;
2.35 +
2.36 + // Now patch actual cases to their correct labels.
2.37 + for (size_t i = 0; i < values->length(); i++) {
2.38 + CaseValue &v = values->at(i);
2.39 + assert(v.statement < node->cases()->length());
2.40 +
2.41 + unsigned index = unsigned(v.box.toInt() - lo);
2.42 + assert(index < tablesize);
2.43 +
2.44 + table[index] = &labels[v.statement];
2.45 + }
2.46 +
2.47 + // Emit the tableswitch opcode and the jump table.
2.48 + __ tableswitch(lo, hi, &def, table);
2.49 +
2.50 + // We're done with the jump table now.
2.51 + delete [] table;
2.52 +
2.53 + // Emit each statement.
2.54 + for (size_t i = 0; i < node->cases()->length(); i++) {
2.55 + Statement *stmt = node->cases()->at(i)->statement();
2.56 +
2.57 + __ bind(&labels[i]);
2.58 + stmt->accept(this);
2.59 + __ jump(&join);
2.60 + }
2.61 +
2.62 + // We're done with the statement labels.
2.63 + delete [] labels;
2.64 +
2.65 + // Emit the default case.
2.66 + __ bind(&def);
2.67 + if (node->defaultCase())
2.68 + node->defaultCase()->accept(this);
2.69 +
2.70 + __ bind(&join);
2.71 +
2.72 + return true;
2.73 +}
2.74 +
2.75 +void
2.76 +BytecodeCompiler::visit(SwitchStatement *node)
2.77 +{
2.78 + node->expression()->accept(this);
2.79 +
2.80 + if (tableswitch(node))
2.81 + return;
2.82 +
2.83 + Label join;
2.84 +
2.85 + for (size_t i = 0; i < node->cases()->length(); i++) {
2.86 + Case *c = node->cases()->at(i);
2.87 +
2.88 + Label success, fail;
2.89 + if (c->others()) {
2.90 + for (size_t j = 0; j < c->others()->length(); j++) {
2.91 + Expression *expr = c->others()->at(j);
2.92 +
2.93 + __ dup();
2.94 + expr->accept(this);
2.95 + __ j(OP_JEQ, &success);
2.96 + }
2.97 + }
2.98 +
2.99 + // The final test.
2.100 + __ dup();
2.101 + c->expression()->accept(this);
2.102 + __ j(OP_JNE, &fail);
2.103 + __ bind(&success);
2.104 + c->statement()->accept(this);
2.105 + __ jump(&join);
2.106 + __ bind(&fail);
2.107 + }
2.108 +
2.109 + if (node->defaultCase())
2.110 + node->defaultCase()->accept(this);
2.111 +
2.112 + __ drop(1);
2.113 + __ bind(&join);
2.114 +}
2.115 +
2.116 void
2.117 BytecodeCompiler::visit(FunctionStatement *node)
2.118 {
3.1 --- a/src/BytecodeCompiler.h Sun Aug 12 13:22:56 2012 -0700
3.2 +++ b/src/BytecodeCompiler.h Sun Aug 12 20:48:49 2012 -0700
3.3 @@ -114,6 +114,8 @@
3.4 void getEnvSlot(Variable *var);
3.5 void setEnvSlot(Variable *var);
3.6
3.7 + bool tableswitch(SwitchStatement *node);
3.8 +
3.9 public:
3.10 BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
3.11
3.12 @@ -145,6 +147,7 @@
3.13 void visit(TernaryExpression *node);
3.14 void visit(StructureStatement *node);
3.15 void visit(FieldExpression *node);
3.16 + void visit(SwitchStatement *node);
3.17 };
3.18
3.19 }
4.1 --- a/src/BytecodeEmitter.h Sun Aug 12 13:22:56 2012 -0700
4.2 +++ b/src/BytecodeEmitter.h Sun Aug 12 20:48:49 2012 -0700
4.3 @@ -624,6 +624,23 @@
4.4 singleByteOp(OP_FALSE);
4.5 }
4.6
4.7 + void tableswitch(int low, int high, Label *def, Label **labels) {
4.8 + unsigned tablesize = TableSwitchEntries(low, high);
4.9 + assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
4.10 +
4.11 + ensure(OP_TABLESWITCH_LENGTH);
4.12 + writeOp(OP_TABLESWITCH);
4.13 + writeInt32(low);
4.14 + writeInt32(high);
4.15 + jump(def);
4.16 +
4.17 + // When labels are patched, we assume each position is a jump. Rather
4.18 + // than hack position offsets to make labels work without actual
4.19 + // incoming jumps, we emit a jump inline.
4.20 + for (unsigned i = 0; i < tablesize; i++)
4.21 + jump(labels[i]);
4.22 + }
4.23 +
4.24 // Helpers.
4.25 void get(Variable *var) {
4.26 if (var->location() == Variable::STACK) {
5.1 --- a/src/Interpreter.cpp Sun Aug 12 13:22:56 2012 -0700
5.2 +++ b/src/Interpreter.cpp Sun Aug 12 20:48:49 2012 -0700
5.3 @@ -1078,6 +1078,24 @@
5.4 break;
5.5 }
5.6
5.7 +case OP_TABLESWITCH:
5.8 +{
5.9 + int value = top.sp[-1].i32;
5.10 + int low = READ_TABLESWITCH_LOW(top.pc);
5.11 + int high = READ_TABLESWITCH_HIGH(top.pc);
5.12 +
5.13 + top.sp--;
5.14 +
5.15 + unsigned index = unsigned(value - low);
5.16 + unsigned tablesize = TableSwitchEntries(low, high);
5.17 + if (index < tablesize) {
5.18 + top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
5.19 + top.pc += index * OP_JUMP_LENGTH;
5.20 + continue;
5.21 + }
5.22 + break;
5.23 +}
5.24 +
5.25 default:
5.26 assert(false);
5.27 return false;
6.1 --- a/src/Messages.tbl Sun Aug 12 13:22:56 2012 -0700
6.2 +++ b/src/Messages.tbl Sun Aug 12 20:48:49 2012 -0700
6.3 @@ -67,4 +67,10 @@
6.4 MSG(TypeMismatch, TypeError, "type mismatch (expected '%s', got '%s')")
6.5 MSG(PropertyNotFound, TypeError, "property '%s' not found on type '%s'")
6.6 MSG(MustBeConstant, SyntaxError, "default value must be a constant")
6.7 +MSG(DefaultMustBeLastCase, SyntaxError, "the \"default\" case must be the last case in a switch statement")
6.8 +MSG(OneDefaultPerSwitch, SyntaxError, "only one default case is allowed per switch")
6.9 +MSG(SingleStatementPerCase, SyntaxError, "only one statement is allowed per case")
6.10 +MSG(CaseMustBeConstant, SyntaxError, "case expression must be a constant")
6.11 +MSG(CaseHasSameValue, SyntaxError, "case value appears twice in the same switch")
6.12 +MSG(CaseMustBeInteger, SyntaxError, "switch may only operate on integer values")
6.13
7.1 --- a/src/Opcodes.cpp Sun Aug 12 13:22:56 2012 -0700
7.2 +++ b/src/Opcodes.cpp Sun Aug 12 20:48:49 2012 -0700
7.3 @@ -289,6 +289,14 @@
7.4 fprintf(fp, "%u %u", READ_UINT32(pc), READ_UINT32(pc + 4));
7.5 break;
7.6
7.7 + case OP_TABLESWITCH:
7.8 + {
7.9 + int low = READ_TABLESWITCH_LOW(pc);
7.10 + int high = READ_TABLESWITCH_HIGH(pc);
7.11 + fprintf(fp, "%d, %d\n", low, high);
7.12 + break;
7.13 + }
7.14 +
7.15 default:
7.16 // Unknown opcode!
7.17 assert(false);
8.1 --- a/src/Opcodes.h Sun Aug 12 13:22:56 2012 -0700
8.2 +++ b/src/Opcodes.h Sun Aug 12 20:48:49 2012 -0700
8.3 @@ -1,19 +1,20 @@
8.4 -/*
8.5 +/* vim: set ts=4 sw=4 tw=99 et:
8.6 + *
8.7 * Copyright (C) 2012 David Anderson
8.8 *
8.9 - * This file is part of JITCraft.
8.10 + * This file is part of SourcePawn.
8.11 *
8.12 - * JITCraft is free software: you can redistribute it and/or modify it under
8.13 + * SourcePawn is free software: you can redistribute it and/or modify it under
8.14 * the terms of the GNU General Public License as published by the Free
8.15 * Software Foundation, either version 3 of the License, or (at your option)
8.16 * any later version.
8.17 *
8.18 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
8.19 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
8.20 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8.21 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8.22 *
8.23 * You should have received a copy of the GNU General Public License along with
8.24 - * JITCraft. If not, see http://www.gnu.org/licenses/.
8.25 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
8.26 */
8.27 #ifndef _include_opcodes_h_
8.28 #define _include_opcodes_h_
8.29 @@ -69,6 +70,14 @@
8.30 }
8.31 }
8.32
8.33 +static const unsigned MAX_TABLESWITCH_ENTRIES = 256;
8.34 +
8.35 +static inline unsigned
8.36 +TableSwitchEntries(int low, int high)
8.37 +{
8.38 + return unsigned(high - low) + 1;
8.39 +}
8.40 +
8.41 static inline int
8.42 READ_INT32(bytecode *pc)
8.43 {
8.44 @@ -85,6 +94,18 @@
8.45 return *reinterpret_cast<float *>(pc + 1);
8.46 }
8.47
8.48 +static inline int
8.49 +READ_TABLESWITCH_LOW(bytecode *pc)
8.50 +{
8.51 + return READ_INT32(pc);
8.52 +}
8.53 +
8.54 +static inline int
8.55 +READ_TABLESWITCH_HIGH(bytecode *pc)
8.56 +{
8.57 + return READ_INT32(pc + sizeof(int));
8.58 +}
8.59 +
8.60 class Code;
8.61
8.62 void Disassemble(Code *code, FILE *fp);
9.1 --- a/src/Opcodes.tbl Sun Aug 12 13:22:56 2012 -0700
9.2 +++ b/src/Opcodes.tbl Sun Aug 12 20:48:49 2012 -0700
9.3 @@ -261,3 +261,7 @@
9.4
9.5 OPDEF(OP_FIELDREF_LIFO, 100, "fieldref.lifo", 5, 1, 1)
9.6
9.7 +// Table-based jump.
9.8 +// [u8 op] [i32 low] [i32 high] [u32 jump] [u32 jumps...]
9.9 +OPDEF(OP_TABLESWITCH, 101, "tableswitch", 9, 1, 0)
9.10 +
10.1 --- a/src/Parser.cpp Sun Aug 12 13:22:56 2012 -0700
10.2 +++ b/src/Parser.cpp Sun Aug 12 20:48:49 2012 -0700
10.3 @@ -518,10 +518,13 @@
10.4 if (!match(TOK_QMARK))
10.5 return cond;
10.6
10.7 + Expression *left;
10.8 SourcePosition pos = scanner_.begin();
10.9 - Expression *left = expression();
10.10 - if (!left)
10.11 - return NULL;
10.12 + AutoAllowTags<false> disableTags(scanner_);
10.13 + {
10.14 + if ((left = expression()) == NULL)
10.15 + return NULL;
10.16 + }
10.17
10.18 if (!expect(TOK_COLON))
10.19 return NULL;
10.20 @@ -629,6 +632,97 @@
10.21 }
10.22
10.23 Statement *
10.24 +Parser::switch_()
10.25 +{
10.26 + expect(TOK_SWITCH);
10.27 +
10.28 + SourcePosition pos = scanner_.begin();
10.29 +
10.30 + if (!expect(TOK_LPAREN))
10.31 + return NULL;
10.32 + Expression *expr = expression();
10.33 + if (!expr)
10.34 + return NULL;
10.35 + if (!expect(TOK_RPAREN))
10.36 + return NULL;
10.37 +
10.38 + if (!expect(TOK_LBRACE))
10.39 + return NULL;
10.40 +
10.41 + SourcePosition defaultPos;
10.42 + PoolList<Case *> *cases = new (pool_) PoolList<Case *>();
10.43 +
10.44 + Statement *defaultCase = NULL;
10.45 +
10.46 + while (!peek(TOK_RBRACE)) {
10.47 + Expression *expr = NULL;
10.48 + ExpressionList *others = NULL;
10.49 + if (match(TOK_DEFAULT)) {
10.50 + if (defaultCase) {
10.51 + cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch);
10.52 + return NULL;
10.53 + }
10.54 +
10.55 + defaultPos = scanner_.begin();
10.56 + } else {
10.57 + if (defaultCase) {
10.58 + cc_.reportError(defaultPos, Message_DefaultMustBeLastCase);
10.59 + return NULL;
10.60 + }
10.61 +
10.62 + if (!expect(TOK_CASE))
10.63 + return NULL;
10.64 +
10.65 + // A limitation in the grammar is that |case <NAME>:| will be
10.66 + // detected as a label.
10.67 + AutoAllowTags<false> disableTags(scanner_);
10.68 +
10.69 + if ((expr = expression()) == NULL)
10.70 + return NULL;
10.71 +
10.72 + if (peek(TOK_COMMA)) {
10.73 + others = new (pool_) ExpressionList();
10.74 + while (match(TOK_COMMA)) {
10.75 + Expression *other = expression();
10.76 + if (!other)
10.77 + return NULL;
10.78 + if (!others->append(other))
10.79 + return NULL;
10.80 + }
10.81 + }
10.82 + }
10.83 +
10.84 + if (!expect(TOK_COLON))
10.85 + return NULL;
10.86 +
10.87 + Statement *statement = localStatement();
10.88 + if (!statement)
10.89 + return NULL;
10.90 +
10.91 + if (!peek(TOK_CASE) &&
10.92 + !peek(TOK_DEFAULT) &&
10.93 + !peek(TOK_RBRACE))
10.94 + {
10.95 + cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase);
10.96 + return NULL;
10.97 + }
10.98 +
10.99 + if (expr) {
10.100 + Case *caze = new (pool_) Case(expr, others, statement);
10.101 + if (!cases->append(caze))
10.102 + return NULL;
10.103 + } else {
10.104 + defaultCase = statement;
10.105 + }
10.106 + }
10.107 +
10.108 + if (!expect(TOK_RBRACE))
10.109 + return NULL;
10.110 +
10.111 + return new (pool_) SwitchStatement(pos, expr, cases, defaultCase);
10.112 +}
10.113 +
10.114 +Statement *
10.115 Parser::forStatement()
10.116 {
10.117 SourcePosition pos = scanner_.begin();
10.118 @@ -903,7 +997,7 @@
10.119 case TOK_NEW:
10.120 scanner_.scan();
10.121 if ((statement = vars(TOK_STOCK, kind)) == NULL)
10.122 - return NULL;
10.123 + return NULL;
10.124 break;
10.125
10.126 case TOK_FOR:
10.127 @@ -929,19 +1023,22 @@
10.128
10.129 case TOK_RETURN:
10.130 if ((statement = returnStatement()) == NULL)
10.131 - return NULL;
10.132 + return NULL;
10.133 break;
10.134
10.135 case TOK_ENUM:
10.136 if ((statement = enum_()) == NULL)
10.137 - return NULL;
10.138 + return NULL;
10.139 break;
10.140
10.141 case TOK_STRUCT:
10.142 if ((statement = struct_()) == NULL)
10.143 - return NULL;
10.144 + return NULL;
10.145 break;
10.146
10.147 + case TOK_SWITCH:
10.148 + return switch_();
10.149 +
10.150 case TOK_IF:
10.151 return if_();
10.152
10.153 @@ -1567,6 +1664,26 @@
10.154 node->left()->accept(this);
10.155 unindent();
10.156 }
10.157 + void visit(SwitchStatement *node) {
10.158 + prefix();
10.159 + fprintf(fp_, "[ SwitchStatement\n");
10.160 + indent();
10.161 + node->expression()->accept(this);
10.162 + for (size_t i = 0; i < node->cases()->length(); i++) {
10.163 + Case *c = node->cases()->at(i);
10.164 + c->expression()->accept(this);
10.165 + if (c->others()) {
10.166 + for (size_t j = 0; j < c->others()->length(); j++)
10.167 + c->others()->at(j)->accept(this);
10.168 + }
10.169 + indent();
10.170 + c->statement()->accept(this);
10.171 + unindent();
10.172 + }
10.173 + if (node->defaultCase())
10.174 + node->defaultCase()->accept(this);
10.175 + unindent();
10.176 + }
10.177 };
10.178
10.179 void
11.1 --- a/src/Parser.h Sun Aug 12 13:22:56 2012 -0700
11.2 +++ b/src/Parser.h Sun Aug 12 20:48:49 2012 -0700
11.3 @@ -78,6 +78,7 @@
11.4 Expression *assignment();
11.5 Expression *expression();
11.6
11.7 + Statement *switch_();
11.8 Statement *struct_();
11.9 Statement *enum_();
11.10 Statement *if_();
12.1 --- a/src/Scanner.cpp Sun Aug 12 13:22:56 2012 -0700
12.2 +++ b/src/Scanner.cpp Sun Aug 12 20:48:49 2012 -0700
12.3 @@ -39,6 +39,7 @@
12.4 stream_(stream),
12.5 length_(length),
12.6 pushed_(false),
12.7 + allowTags_(true),
12.8 saved_('\0'),
12.9 pos_(stream_)
12.10 {
12.11 @@ -425,7 +426,7 @@
12.12 return kind;
12.13 }
12.14
12.15 - if (c == ':')
12.16 + if (c == ':' && allowTags_)
12.17 return TOK_LABEL;
12.18
12.19 putChar(c);
13.1 --- a/src/Scanner.h Sun Aug 12 13:22:56 2012 -0700
13.2 +++ b/src/Scanner.h Sun Aug 12 20:48:49 2012 -0700
13.3 @@ -1,19 +1,20 @@
13.4 -/*
13.5 +/* vim: set ts=4 sw=4 tw=99 et:
13.6 + *
13.7 * Copyright (C) 2012 David Anderson
13.8 *
13.9 - * This file is part of JITCraft.
13.10 + * This file is part of SourcePawn.
13.11 *
13.12 - * JITCraft is free software: you can redistribute it and/or modify it under
13.13 + * SourcePawn is free software: you can redistribute it and/or modify it under
13.14 * the terms of the GNU General Public License as published by the Free
13.15 * Software Foundation, either version 3 of the License, or (at your option)
13.16 * any later version.
13.17 *
13.18 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
13.19 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
13.20 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13.21 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13.22 *
13.23 * You should have received a copy of the GNU General Public License along with
13.24 - * JITCraft. If not, see http://www.gnu.org/licenses/.
13.25 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
13.26 */
13.27 #ifndef _include_jitcraft_scanner_h_
13.28 #define _include_jitcraft_scanner_h_
13.29 @@ -27,10 +28,14 @@
13.30
13.31 class Scanner
13.32 {
13.33 + template <bool Enabled>
13.34 + friend class AutoAllowTags;
13.35 +
13.36 CompileContext &cc_;
13.37 const char *stream_;
13.38 size_t length_;
13.39 bool pushed_;
13.40 + bool allowTags_;
13.41 char saved_;
13.42 const char *pos_;
13.43 Vector<char> literal_;
13.44 @@ -63,6 +68,13 @@
13.45 return lastToken_;
13.46 }
13.47
13.48 + bool tagsEnabled() const {
13.49 + return allowTags_;
13.50 + }
13.51 + void setTagsEnabled(bool enabled) {
13.52 + allowTags_ = enabled;
13.53 + }
13.54 +
13.55 // Beginning source position of the last instruction.
13.56 SourcePosition begin() const {
13.57 return begin_;
13.58 @@ -77,6 +89,25 @@
13.59 }
13.60 };
13.61
13.62 +template <bool Enabled>
13.63 +class AutoAllowTags
13.64 +{
13.65 + Scanner &scanner_;
13.66 + bool prev_;
13.67 +
13.68 + public:
13.69 + AutoAllowTags(Scanner &scanner)
13.70 + : scanner_(scanner),
13.71 + prev_(scanner_.tagsEnabled())
13.72 + {
13.73 + scanner_.setTagsEnabled(Enabled);
13.74 + }
13.75 + ~AutoAllowTags()
13.76 + {
13.77 + scanner_.setTagsEnabled(prev_);
13.78 + }
13.79 +};
13.80 +
13.81 } // namespace ke
13.82
13.83 #endif // _include_jitcraft_scanner_h_
14.1 --- a/src/SemanticAnalysis.cpp Sun Aug 12 13:22:56 2012 -0700
14.2 +++ b/src/SemanticAnalysis.cpp Sun Aug 12 20:48:49 2012 -0700
14.3 @@ -114,7 +114,7 @@
14.4 }
14.5
14.6 case AstNode::kBooleanLiteral:
14.7 - *out = BoxedPrimitive::Bool(expression->toBooleanLiteral()->token() == TOK_TRUE);
14.8 + *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
14.9 return true;
14.10
14.11 case AstNode::kIntegerLiteral:
14.12 @@ -154,17 +154,7 @@
14.13
14.14 // We pre-fill global enum types, since they may occur in function
14.15 // signatures. This should probably be somewhere else...
14.16 - Local<String> name(zone_, enumstmt->name());
14.17 - Local<Type> type(zone_);
14.18 - if (name)
14.19 - type = zone_->types()->newEnum(name);
14.20 - else
14.21 - type = zone_->types()->getPrimitive(PrimitiveType_Int32);
14.22 -
14.23 - if (!type)
14.24 - return false;
14.25 -
14.26 - enumstmt->decl()->setType(type);
14.27 + enumstmt->accept(this);
14.28 } else if (statement->isStructureStatement()) {
14.29 StructureStatement *node = statement->toStructureStatement();
14.30 node->accept(this);
14.31 @@ -175,6 +165,11 @@
14.32
14.33 for (size_t i = 0; i < tree_->statements()->length(); i++) {
14.34 Statement *statement = tree_->statements()->at(i);
14.35 +
14.36 + // We can't double-process these. Maybe put this check somewhere else.
14.37 + if (statement->isEnumStatement())
14.38 + continue;
14.39 +
14.40 statement->accept(this);
14.41 }
14.42
14.43 @@ -848,26 +843,19 @@
14.44 Box *
14.45 SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
14.46 {
14.47 - // First see if we can get a constant expression.
14.48 + Local<Type> given(zone_, visitForLoad(parameter->initializer()));
14.49 +
14.50 BoxedPrimitive prim;
14.51 if (EvaluateForConstant(parameter->initializer(), &prim)) {
14.52 - Local<Type> given(zone_, zone_->types()->getPrimitive(prim.type()));
14.53 if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
14.54 return NULL;
14.55
14.56 if (prim.type() == PrimitiveType_Int32)
14.57 - return Box::New(zone_, type, prim.toInt());
14.58 - return Box::New(zone_, type, int(prim.toBool()));
14.59 + return Box::New(zone_, given, prim.toInt());
14.60 + return Box::New(zone_, given, prim.toFloat());
14.61 } else if (parameter->initializer()->isStringLiteral()) {
14.62 StringLiteral *literal = parameter->initializer()->toStringLiteral();
14.63
14.64 - // This actually builds a mutable string, so we can use it as-is. The
14.65 - // bytecode compiler will copy it if needed.
14.66 - literal->accept(this);
14.67 - if (!literal->type())
14.68 - return NULL;
14.69 -
14.70 - Local<Type> given(zone_, literal->type());
14.71 if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
14.72 return NULL;
14.73
14.74 @@ -1268,6 +1256,18 @@
14.75 }
14.76
14.77 void
14.78 +SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
14.79 +{
14.80 + if (other.returns() < status().returns())
14.81 + return;
14.82 +
14.83 + if (other.terminates())
14.84 + terminate(other.returns());
14.85 + else
14.86 + returns(other.returns());
14.87 +}
14.88 +
14.89 +void
14.90 SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
14.91 {
14.92 // If both sides terminate in a return, we consider this a return as well.
14.93 @@ -1360,9 +1360,18 @@
14.94 void
14.95 SemanticAnalysis::visit(EnumStatement *node)
14.96 {
14.97 - Local<Type> type(zone_, node->decl()->type());
14.98 + Local<String> name(zone_, node->name());
14.99 + Local<Type> type(zone_);
14.100 + if (name)
14.101 + type = zone_->types()->newEnum(name);
14.102 + else
14.103 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
14.104
14.105 - assert(type);
14.106 + if (!type)
14.107 + return;
14.108 +
14.109 + if (node->decl())
14.110 + node->decl()->setType(type);
14.111
14.112 int value = 0;
14.113 for (size_t i = 0; i < node->entries()->length(); i++) {
14.114 @@ -1385,6 +1394,107 @@
14.115 }
14.116 }
14.117
14.118 +static int
14.119 +SortCaseIntValues(const void *p1, const void *p2)
14.120 +{
14.121 + CaseValue *v1 = (CaseValue *)p1;
14.122 + CaseValue *v2 = (CaseValue *)p2;
14.123 +
14.124 + return v1->box.toInt() - v2->box.toInt();
14.125 +}
14.126 +
14.127 +void
14.128 +SemanticAnalysis::visit(SwitchStatement *node)
14.129 +{
14.130 + Local<Type> caseType(zone_, visitForLoad(node->expression()));
14.131 + if (!caseType)
14.132 + return;
14.133 +
14.134 + if (!caseType->isEnum() && !caseType->isInt32()) {
14.135 + cc_.reportError(node->pos(), Message_CaseMustBeInteger);
14.136 + return;
14.137 + }
14.138 +
14.139 + PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
14.140 + ControlStatus status = ControlStatus(false, Returns_Never);
14.141 +
14.142 + Local<Type> check(zone_);
14.143 + for (size_t i = 0; i < node->cases()->length(); i++) {
14.144 + Case *c = node->cases()->at(i);
14.145 +
14.146 + check = visitForLoad(c->expression());
14.147 + if (!check)
14.148 + return;
14.149 +
14.150 + if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
14.151 + return;
14.152 +
14.153 + CaseValue v(i);
14.154 + if (!EvaluateForConstant(c->expression(), &v.box)) {
14.155 + cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
14.156 + return;
14.157 + }
14.158 + if (!values->append(v))
14.159 + return;
14.160 +
14.161 + if (c->others()) {
14.162 + for (size_t j = 0; j < c->others()->length(); j++) {
14.163 + Expression *expr = c->others()->at(j);
14.164 + check = visitForLoad(expr);
14.165 + if (!check)
14.166 + return;
14.167 +
14.168 + if (!typeCheckAssignment(expr->pos(), check, caseType, false))
14.169 + return;
14.170 +
14.171 + CaseValue v(i);
14.172 + if (!EvaluateForConstant(expr, &v.box)) {
14.173 + cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
14.174 + return;
14.175 + }
14.176 + if (!values->append(v))
14.177 + return;
14.178 + }
14.179 + }
14.180 +
14.181 + ControlStatus latest = visitForControl(c->statement());
14.182 +
14.183 + if (i != 0)
14.184 + control_->merge(status, latest);
14.185 +
14.186 + status = latest;
14.187 + }
14.188 +
14.189 + if (node->defaultCase()) {
14.190 + ControlStatus latest = visitForControl(node->defaultCase());
14.191 +
14.192 + if (node->cases()->length()) {
14.193 + // If we had any other cases, we must merge.
14.194 + control_->merge(status, latest);
14.195 + } else {
14.196 + // Otherwise, control-flow always flows through here.
14.197 + control_->inherit(latest);
14.198 + }
14.199 + } else if (node->cases()->length()) {
14.200 + control_->merge(status, ControlStatus(false, Returns_Never));
14.201 + }
14.202 +
14.203 + if (values->length() > 1) {
14.204 + qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
14.205 +
14.206 + for (size_t i = 1; i < values->length(); i++) {
14.207 + CaseValue &prev = values->at(i - 1);
14.208 + CaseValue &cur = values->at(i);
14.209 + if (prev.box.toInt() == cur.box.toInt()) {
14.210 + cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
14.211 + return;
14.212 + }
14.213 + }
14.214 + }
14.215 +
14.216 + node->setCaseValueList(values);
14.217 +}
14.218 +
14.219 void
14.220 SemanticAnalysis::visit(StructureStatement *node)
14.221 {
15.1 --- a/src/SemanticAnalysis.h Sun Aug 12 13:22:56 2012 -0700
15.2 +++ b/src/SemanticAnalysis.h Sun Aug 12 20:48:49 2012 -0700
15.3 @@ -102,6 +102,7 @@
15.4 returns_ = status;
15.5 }
15.6 void merge(const ControlStatus &left, const ControlStatus &right);
15.7 + void inherit(const ControlStatus &other);
15.8
15.9 ~ControlScope()
15.10 {
15.11 @@ -210,6 +211,7 @@
15.12 void visit(BooleanLiteral *node);
15.13 void visit(StructureStatement *node);
15.14 void visit(FieldExpression *node);
15.15 + void visit(SwitchStatement *node);
15.16 };
15.17
15.18 const char *GetTypeName(Type *type);
16.1 --- a/src/Token.h Sun Aug 12 13:22:56 2012 -0700
16.2 +++ b/src/Token.h Sun Aug 12 20:48:49 2012 -0700
16.3 @@ -45,6 +45,7 @@
16.4 // * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
16.5 // op-and-assign equivalent.
16.6 #define TOKENMAP(_) \
16.7 + _(NONE, "<none>") \
16.8 _(ERROR, "<error>") \
16.9 _(NEW, "'new'") \
16.10 _(FOR, "'for'") \
16.11 @@ -69,6 +70,9 @@
16.12 _(TRUE, "<true>") \
16.13 _(FALSE, "<false>") \
16.14 _(STRUCT, "<struct>") \
16.15 + _(SWITCH, "<switch>") \
16.16 + _(CASE, "<case>") \
16.17 + _(DEFAULT, "<default>") \
16.18 _(ELLIPSES, "...") \
16.19 _(PLUS, "+") \
16.20 _(MINUS, "-") \
17.1 --- a/src/Types.h Sun Aug 12 13:22:56 2012 -0700
17.2 +++ b/src/Types.h Sun Aug 12 20:48:49 2012 -0700
17.3 @@ -301,7 +301,7 @@
17.4 PrimitiveType type_;
17.5 union {
17.6 int i_;
17.7 - bool b_;
17.8 + float f_;
17.9 };
17.10
17.11 public:
17.12 @@ -311,10 +311,10 @@
17.13 b.i_ = i;
17.14 return b;
17.15 }
17.16 - static BoxedPrimitive Bool(bool v) {
17.17 + static BoxedPrimitive Float(float f) {
17.18 BoxedPrimitive b;
17.19 - b.type_ = PrimitiveType_Bool;
17.20 - b.b_ = v;
17.21 + b.type_ = PrimitiveType_Float;
17.22 + b.f_ = f;
17.23 return b;
17.24 }
17.25
17.26 @@ -325,9 +325,9 @@
17.27 assert(type() == PrimitiveType_Int32);
17.28 return i_;
17.29 }
17.30 - bool toBool() const {
17.31 - assert(type() == PrimitiveType_Bool);
17.32 - return b_;
17.33 + float toFloat() const {
17.34 + assert(type() == PrimitiveType_Float);
17.35 + return f_;
17.36 }
17.37 };
17.38