Implement switch.
authorDavid Anderson <dvander@alliedmods.net>
Sun Aug 12 20:48:49 2012 -0700 (2012-08-12)
changeset 17248cffae8c9e0
parent 171 023711891116
child 173 bbf9f3809d55
Implement switch.
src/AST.h
src/BytecodeCompiler.cpp
src/BytecodeCompiler.h
src/BytecodeEmitter.h
src/Interpreter.cpp
src/Messages.tbl
src/Opcodes.cpp
src/Opcodes.h
src/Opcodes.tbl
src/Parser.cpp
src/Parser.h
src/Scanner.cpp
src/Scanner.h
src/SemanticAnalysis.cpp
src/SemanticAnalysis.h
src/Token.h
src/Types.h
     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