Added array support back.
authorDavid Anderson <dvander@alliedmods.net>
Sun Nov 18 14:53:23 2012 -0800 (2012-11-18)
changeset 212443d24cfdf2d
parent 211 6c1cc50c4808
child 213 a9b8d24967d6
Added array support back.
src/Messages.tbl
src/Types.cpp
src/Types.h
src/compiler/ConstantEvaluator.cpp
src/compiler/HIR.cpp
src/compiler/NameBinding.cpp
src/compiler/Parser.cpp
src/compiler/Parser.h
src/compiler/SemanticAnalysis.cpp
src/compiler/SemanticAnalysis.h
src/jitcraft.vcxproj
tests/basic/float-arrays.out
tests/basic/float-arrays.sp
     1.1 --- a/src/Messages.tbl	Sat Nov 17 23:13:39 2012 -0800
     1.2 +++ b/src/Messages.tbl	Sun Nov 18 14:53:23 2012 -0800
     1.3 @@ -7,7 +7,7 @@
     1.4  MSG(ExpectedExpression,             SyntaxError,            "expected expression, got '%s'")
     1.5  MSG(RedeclaredName,                 SyntaxError,            "name '%s' was redeclared (previous at line %d, col %d)")
     1.6  MSG(ExpectedLValue,                 SyntaxError,            "impossible assignment, expected l-value")
     1.7 -MSG(MaximumArrayDepth,              SyntaxError,            "maximum array dimension depth exceeded")
     1.8 +MSG(MaximumArrayDepth,              TypeError,              "maximum array dimension depth exceeded")
     1.9  MSG(ArrayInitializerDepth,          SyntaxError,            "array declaration and initializer have different dimension counts")
    1.10  MSG(BadArraySize,                   SyntaxError,            "array size must be positive")
    1.11  MSG(ArraySizeTooBig,                SyntaxError,            "array size is too big")
     2.1 --- a/src/Types.cpp	Sat Nov 17 23:13:39 2012 -0800
     2.2 +++ b/src/Types.cpp	Sun Nov 18 14:53:23 2012 -0800
     2.3 @@ -63,6 +63,13 @@
     2.4  ArrayType *
     2.5  ArrayType::New(Zone *zone, Handle<Type> contained, int elements)
     2.6  {
     2.7 +    if (contained->isArray() &&
     2.8 +        ArrayType::cast(contained)->levels() == MAX_ARRAY_DEPTH)
     2.9 +    {
    2.10 +        zone->reportError(Message_MaximumArrayDepth);
    2.11 +        return NULL;
    2.12 +    }
    2.13 +
    2.14      Local<ArrayType> type(zone, ArrayType::cast(zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old)));
    2.15      if (!type)
    2.16          return NULL;
    2.17 @@ -201,7 +208,6 @@
    2.18      }
    2.19  }
    2.20  
    2.21 -
    2.22  StructType *
    2.23  StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
    2.24  {
     3.1 --- a/src/Types.h	Sat Nov 17 23:13:39 2012 -0800
     3.2 +++ b/src/Types.h	Sun Nov 18 14:53:23 2012 -0800
     3.3 @@ -100,9 +100,7 @@
     3.4          return kind_;
     3.5      }
     3.6  
     3.7 -  public:
     3.8 -    static const int DYNAMIC_ARRAY_SIZE = -1;
     3.9 -    
    3.10 +  public:   
    3.11      static Type *NewVoid(Zone *zone);
    3.12      static Type *NewUnchecked(Zone *zone);
    3.13      static Type *NewPrimitive(Zone *zone, PrimitiveType type);
    3.14 @@ -156,6 +154,9 @@
    3.15                   : primitive()
    3.16                 : PrimitiveType_Int32;
    3.17      }
    3.18 +    bool isChar() {
    3.19 +        return isPrimitive() && primitive() == PrimitiveType_Char;
    3.20 +    }
    3.21      bool isFloat() {
    3.22          return isPrimitive() && primitive() == PrimitiveType_Float;
    3.23      }
    3.24 @@ -213,6 +214,8 @@
    3.25  class ArrayType : public Type
    3.26  {
    3.27    public:
    3.28 +    static const int DYNAMIC_ARRAY_SIZE = -1;
    3.29 +
    3.30      static ArrayType *New(Zone *zone, Handle<Type> contained, int elements);
    3.31      static ArrayType *NewExternal(Zone *zone, Handle<Type> contained);
    3.32  
     4.1 --- a/src/compiler/ConstantEvaluator.cpp	Sat Nov 17 23:13:39 2012 -0800
     4.2 +++ b/src/compiler/ConstantEvaluator.cpp	Sun Nov 18 14:53:23 2012 -0800
     4.3 @@ -0,0 +1,92 @@
     4.4 +/* vim: set ts=4 sw=4 tw=99 et:
     4.5 + *
     4.6 + * Copyright (C) 2012 David Anderson
     4.7 + *
     4.8 + * This file is part of SourcePawn.
     4.9 + *
    4.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
    4.11 + * the terms of the GNU General Public License as published by the Free
    4.12 + * Software Foundation, either version 3 of the License, or (at your option)
    4.13 + * any later version.
    4.14 + * 
    4.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    4.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    4.18 + *
    4.19 + * You should have received a copy of the GNU General Public License along with
    4.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
    4.21 + */
    4.22 +#include "AST.h"
    4.23 +#include "ConstantEvaluator.h"
    4.24 +
    4.25 +using namespace ke;
    4.26 +
    4.27 +static inline bool
    4.28 +EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
    4.29 +                        BoxedPrimitive *out)
    4.30 +{
    4.31 +    switch (kind) {
    4.32 +      case TOK_PLUS:
    4.33 +        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
    4.34 +        return true;
    4.35 +
    4.36 +      case TOK_SHL:
    4.37 +        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
    4.38 +        return true;
    4.39 +
    4.40 +      default:
    4.41 +        return false;
    4.42 +    }
    4.43 +}
    4.44 +
    4.45 +static inline bool
    4.46 +EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
    4.47 +{
    4.48 +  switch (kind) {
    4.49 +    case TOK_MINUS:
    4.50 +      *out = BoxedPrimitive::Int(-inner.toInt());
    4.51 +      return true;
    4.52 +
    4.53 +    default:
    4.54 +      return false;
    4.55 +  }
    4.56 +}
    4.57 +
    4.58 +bool
    4.59 +ke::EvaluateForConstant(Expression *expr, BoxedPrimitive *out)
    4.60 +{
    4.61 +    switch (expr->kind()) {
    4.62 +      case AstNode::kBinaryExpression:
    4.63 +      {
    4.64 +        BoxedPrimitive left;
    4.65 +        BoxedPrimitive right;
    4.66 +        BinaryExpression *b = expr->toBinaryExpression();
    4.67 +        if (!EvaluateForConstant(b->left(), &left) ||
    4.68 +            !EvaluateForConstant(b->right(), &right))
    4.69 +        {
    4.70 +            return false;
    4.71 +        }
    4.72 +        return EvaluateBinaryOperation(b->token(), left, right, out);
    4.73 +      }
    4.74 +
    4.75 +      case AstNode::kUnaryExpression:
    4.76 +      {
    4.77 +        BoxedPrimitive inner;
    4.78 +        UnaryExpression *u = expr->toUnaryExpression();
    4.79 +        if (!EvaluateForConstant(u->expression(), &inner))
    4.80 +            return false;
    4.81 +        return EvaluateUnaryOperation(u->token(), inner, out);
    4.82 +      }
    4.83 +
    4.84 +      case AstNode::kBooleanLiteral:
    4.85 +        *out = BoxedPrimitive::Int(expr->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
    4.86 +        return true;
    4.87 +
    4.88 +      case AstNode::kIntegerLiteral:
    4.89 +        *out = BoxedPrimitive::Int(expr->toIntegerLiteral()->value());
    4.90 +        return true;
    4.91 +
    4.92 +      default:
    4.93 +        return false;
    4.94 +    }
    4.95 +}
     5.1 --- a/src/compiler/HIR.cpp	Sat Nov 17 23:13:39 2012 -0800
     5.2 +++ b/src/compiler/HIR.cpp	Sun Nov 18 14:53:23 2012 -0800
     5.3 @@ -44,6 +44,7 @@
     5.4      void visitLocal(HLocal *local);
     5.5      void visitGlobal(HGlobal *global);
     5.6      void visitConvert(HConvert *convert);
     5.7 +    void visitIndex(HIndex *index);
     5.8  
     5.9    private:
    5.10      Zone *zone_;
    5.11 @@ -151,6 +152,13 @@
    5.12  }
    5.13  
    5.14  void
    5.15 +HIRTranslator::visitIndex(HIndex *index)
    5.16 +{
    5.17 +    index->bind(this, emitter_);
    5.18 +    index->load(emitter_);
    5.19 +}
    5.20 +
    5.21 +void
    5.22  HIRTranslator::visitGlobal(HGlobal *global)
    5.23  {
    5.24      __ getglobal(global->sym());
     6.1 --- a/src/compiler/NameBinding.cpp	Sat Nov 17 23:13:39 2012 -0800
     6.2 +++ b/src/compiler/NameBinding.cpp	Sun Nov 18 14:53:23 2012 -0800
     6.3 @@ -194,7 +194,8 @@
     6.4              // And we don't necessarily want this to bind.
     6.5          }
     6.6  
     6.7 -        node->initialization()->accept(this);
     6.8 +        if (node->initialization())
     6.9 +            node->initialization()->accept(this);
    6.10      }
    6.11      void visitEnumStatement(EnumStatement *node) {
    6.12          assert(false);
    6.13 @@ -318,7 +319,8 @@
    6.14              node->ifFalse()->accept(this);
    6.15      }
    6.16      void visitIndexExpression(IndexExpression *node) {
    6.17 -        assert(false);
    6.18 +        node->left()->accept(this);
    6.19 +        node->right()->accept(this);
    6.20      }
    6.21      void visitFloatLiteral(FloatLiteral *node) {
    6.22      }
    6.23 @@ -424,6 +426,10 @@
    6.24      return populator.analyze();
    6.25  }
    6.26  
    6.27 +static const int INFER_ARRAY_SIZE = 0;
    6.28 +static const int EVAL_ARRAY_SIZE = -1;
    6.29 +static const int DYNAMIC_ARRAY_SIZE = -2;
    6.30 +
    6.31  class NameBinder : public AstVisitor
    6.32  {
    6.33    public:
    6.34 @@ -487,14 +493,37 @@
    6.35      void visitVariableDeclaration(VariableDeclaration *node) {
    6.36          // Bind the initializer before registering the declaration, so that we
    6.37          // can error on bogus initializers (new x = x).
    6.38 -        node->initialization()->accept(this);
    6.39 +        if (node->initialization())
    6.40 +            node->initialization()->accept(this);
    6.41  
    6.42          Local<Type> type(zone_, bindType(node->type()));
    6.43          if (!type)
    6.44              return;
    6.45  
    6.46 -        if (node->dims()) {
    6.47 -            
    6.48 +        if (node->dims() || type->isArray()) {
    6.49 +            int dims[MAX_ARRAY_DEPTH];
    6.50 +            int levels = evaluateDimensions(node->pos(), type, node->dims(), dims);
    6.51 +            if (levels < 0)
    6.52 +                return;
    6.53 +
    6.54 +            // Do some extra inference based on the initializer, if present.
    6.55 +            Expression *init = node->initialization();
    6.56 +            if (init &&
    6.57 +                init->isArrayLiteral() &&
    6.58 +                init->toArrayLiteral()->isFixed())
    6.59 +            {
    6.60 +                Local<Type> contained(zone_, type->isArray()
    6.61 +                                             ? ArrayType::cast(type)->contained()
    6.62 +                                             : type);
    6.63 +                if (!inferFixedArrayDimensions(init->toArrayLiteral(), contained, dims, levels))
    6.64 +                    return;
    6.65 +            }
    6.66 +
    6.67 +            // If we got extra dimensions, we need to build a new type.
    6.68 +            if (node->dims()) {
    6.69 +                if ((type = buildArrayType(type, dims, node->dims()->length())) == NULL)
    6.70 +                    return;
    6.71 +            }
    6.72          }
    6.73  
    6.74          // If the node already has a symbol (meaning it was a global), then
    6.75 @@ -654,6 +683,109 @@
    6.76      }
    6.77  
    6.78    private:
    6.79 +    int evaluateDimensions(const SourcePosition &pos, Handle<Type> typeArg, ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) {
    6.80 +        unsigned level = 0;
    6.81 +        Local<Type> type(zone_, typeArg);
    6.82 +        while (type->isArray()) {
    6.83 +            ArrayType *atype = ArrayType::cast(type);
    6.84 +            dims[level] = atype->isFixedLength()
    6.85 +                          ? atype->fixedLength()
    6.86 +                          : DYNAMIC_ARRAY_SIZE;
    6.87 +            type = atype->contained();
    6.88 +            level++;
    6.89 +        }
    6.90 +
    6.91 +        if (!exprs)
    6.92 +            return level;
    6.93 +
    6.94 +        if (level + exprs->length() > MAX_ARRAY_DEPTH) {
    6.95 +            cc_.reportError(pos, Message_MaximumArrayDepth);
    6.96 +            return -1;
    6.97 +        }
    6.98 +
    6.99 +        bool hadEmptySize = false;
   6.100 +        for (size_t i = 0; i < exprs->length(); i++) {
   6.101 +            Expression *expr = exprs->at(i);
   6.102 +            if (!expr) {
   6.103 +                dims[i] = INFER_ARRAY_SIZE;
   6.104 +                hadEmptySize = true;
   6.105 +                continue;
   6.106 +            }
   6.107 +
   6.108 +            BoxedPrimitive box;
   6.109 +            if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
   6.110 +                int size = box.toInt();
   6.111 +                if (size <= 0) {
   6.112 +                    cc_.reportError(expr->pos(), Message_BadArraySize);
   6.113 +                    return false;
   6.114 +                }
   6.115 +
   6.116 +                dims[i] = size;
   6.117 +                continue;
   6.118 +            }
   6.119 +
   6.120 +            if (hadEmptySize) {
   6.121 +                cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
   6.122 +                return false;
   6.123 +            }
   6.124 +
   6.125 +            dims[i] = EVAL_ARRAY_SIZE;
   6.126 +        }
   6.127 +
   6.128 +        return level + exprs->length();
   6.129 +    }
   6.130 +
   6.131 +    // This function computes missing dimension sizes based on a literal
   6.132 +    // initializer. We don't really handle any size rules here; we just
   6.133 +    // do a really dumb inference.
   6.134 +    bool inferFixedArrayDimensions(ArrayLiteral *lit, Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], int levels) {
   6.135 +        for (int i = 0; i < levels; i++) {
   6.136 +            if (dims[i] == EVAL_ARRAY_SIZE || dims[i] == DYNAMIC_ARRAY_SIZE) {
   6.137 +                // The following are invalid:
   6.138 +                //   new x[<expr>] = {...}
   6.139 +                //   new Type:x = {...}  // where Type is a non-fixed array type
   6.140 +                cc_.reportError(lit->pos(), Message_CannotInitializeEvalArray);
   6.141 +                return false;
   6.142 +            }
   6.143 +
   6.144 +            if (dims[i] == INFER_ARRAY_SIZE) {
   6.145 +                // Character arrays are always dynamic when inferred from string literals.
   6.146 +                if (i == levels - 1 && contained->isChar())
   6.147 +                    dims[i] = DYNAMIC_ARRAY_SIZE;
   6.148 +                else
   6.149 +                    dims[i] = lit->expressions()->length();
   6.150 +            }
   6.151 +
   6.152 +            if (i != levels - 1) {
   6.153 +                // Fixed array literals are guaranteed to have at least one expression.
   6.154 +                Expression *next = lit->expressions()->at(0);
   6.155 +                if (!next->isArrayLiteral()) {
   6.156 +                    // Whelp... this array is just malformed. Not the best error message
   6.157 +                    // but whatever.
   6.158 +                    cc_.reportError(next->pos(), Message_ArraySizeCannotBeDetermined);
   6.159 +                    return false;
   6.160 +                }
   6.161 +                lit = next->toArrayLiteral();
   6.162 +            }
   6.163 +        }
   6.164 +
   6.165 +        return true;
   6.166 +    }
   6.167 +
   6.168 +    ArrayType *buildArrayType(Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], size_t postlevels) {
   6.169 +        Local<Type> type(zone_, contained);
   6.170 +        for (size_t i = postlevels - 1; i < postlevels; i--) {
   6.171 +            int size = dims[i] > 0
   6.172 +                       ? dims[i]
   6.173 +                       : ArrayType::DYNAMIC_ARRAY_SIZE;
   6.174 +            
   6.175 +            type = zone_->types()->newArray(contained, size);
   6.176 +            if (!type)
   6.177 +                return NULL;
   6.178 +        }
   6.179 +        return ArrayType::cast(type);
   6.180 +    }
   6.181 +
   6.182      bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
   6.183          Local<Type> type(zone_);
   6.184          if (!fun->returnType()) {
     7.1 --- a/src/compiler/Parser.cpp	Sat Nov 17 23:13:39 2012 -0800
     7.2 +++ b/src/compiler/Parser.cpp	Sun Nov 18 14:53:23 2012 -0800
     7.3 @@ -139,30 +139,21 @@
     7.4  }
     7.5  
     7.6  Expression *
     7.7 -Parser::arrayLiteral(TokenKind kind)
     7.8 +Parser::fixedArrayLiteral()
     7.9  {
    7.10 -    assert(kind == TOK_LBRACE || kind == TOK_LBRACKET);
    7.11 -
    7.12 -    TokenKind close = (kind == TOK_LBRACE)
    7.13 -                      ? TOK_RBRACE
    7.14 -                      : TOK_RBRACKET;
    7.15 -
    7.16      SourcePosition pos = scanner_.begin();
    7.17  
    7.18      ExpressionList *list = new (pool_) ExpressionList();
    7.19      do {
    7.20 -        if (match(close))
    7.21 +        // { } is an illegal array literal.
    7.22 +        if (list->length() > 0 && match(TOK_LBRACE))
    7.23              break;
    7.24  
    7.25          Expression *expr = NULL;
    7.26 -        if (kind == TOK_LBRACE) {
    7.27 -            if (peek(TOK_LBRACE))
    7.28 -                expr = arrayLiteral(TOK_LBRACE);
    7.29 -            else
    7.30 -                expr = primitive();
    7.31 -        } else {
    7.32 -            expr = expression();
    7.33 -        }
    7.34 +        if (peek(TOK_LBRACE))
    7.35 +            expr = fixedArrayLiteral();
    7.36 +        else
    7.37 +            expr = primitive();
    7.38          if (!expr)
    7.39              return NULL;
    7.40  
    7.41 @@ -170,13 +161,13 @@
    7.42              return NULL;
    7.43  
    7.44          if (!match(TOK_COMMA)) {
    7.45 -            if (!expect(close))
    7.46 +            if (!expect(TOK_RBRACE))
    7.47                  return NULL;
    7.48              break;
    7.49          }
    7.50      } while (true);
    7.51  
    7.52 -    return new (pool_) ArrayLiteral(pos, kind, list);
    7.53 +    return new (pool_) ArrayLiteral(pos, TOK_LBRACE, list);
    7.54  }
    7.55  
    7.56  Expression *
    7.57 @@ -882,7 +873,7 @@
    7.58          return NULL;
    7.59  
    7.60      ExpressionList *dims = NULL;
    7.61 -    if (match(TOK_LBRACE)) {
    7.62 +    if (peek(TOK_LBRACKET)) {
    7.63          if ((dims = dimensions()) == NULL)
    7.64              return NULL;;
    7.65      }
    7.66 @@ -894,7 +885,8 @@
    7.67          switch (scanner_.peek()) {
    7.68            // Note: we don't support [] literals yet.
    7.69            case TOK_LBRACE:
    7.70 -            if ((expr = arrayLiteral(scanner_.scan())) == NULL)
    7.71 +            scanner_.scan();
    7.72 +            if ((expr = fixedArrayLiteral()) == NULL)
    7.73                  return NULL;
    7.74              break;
    7.75  
     8.1 --- a/src/compiler/Parser.h	Sat Nov 17 23:13:39 2012 -0800
     8.2 +++ b/src/compiler/Parser.h	Sun Nov 18 14:53:23 2012 -0800
     8.3 @@ -59,7 +59,7 @@
     8.4      String *expectName();
     8.5  
     8.6      Expression *primitive();
     8.7 -    Expression *arrayLiteral(TokenKind kind);
     8.8 +    Expression *fixedArrayLiteral();
     8.9      Expression *call(Expression *callee);
    8.10      Expression *field(Expression *left);
    8.11      Expression *index(Expression *left);
     9.1 --- a/src/compiler/SemanticAnalysis.cpp	Sat Nov 17 23:13:39 2012 -0800
     9.2 +++ b/src/compiler/SemanticAnalysis.cpp	Sun Nov 18 14:53:23 2012 -0800
     9.3 @@ -292,24 +292,56 @@
     9.4      assert(__ stackDepth() == 0);
     9.5  }
     9.6  
     9.7 +static inline Heap::Tenure
     9.8 +InferTenure(Symbol *sym)
     9.9 +{
    9.10 +    if (sym->scope()->kind() == Scope::GLOBAL)
    9.11 +        return Heap::Tenure_Old;
    9.12 +    // :TODO: need to use LIFO!
    9.13 +    return Heap::Tenure_Default;
    9.14 +}
    9.15 +
    9.16  void
    9.17  SemanticAnalysis::visitVariableDeclaration(VariableDeclaration *node)
    9.18  {
    9.19      PoolScope poolScope(zone_->pool());
    9.20      RootScope rootScope(zone_);
    9.21  
    9.22 -    HIR *hir = NULL;
    9.23      if (node->initialization()) {
    9.24 +        HIR *hir = NULL;
    9.25 +
    9.26          if ((hir = eval(node->initialization())) == NULL)
    9.27              return;
    9.28          if ((hir = coerce(hir, node->sym()->type(), Coerce_Assign)) == NULL)
    9.29              return;
    9.30 +
    9.31 +        discharge(hir);
    9.32      } else {
    9.33 -        assert(false);
    9.34 +        if (node->sym()->type()->isInt32() ||
    9.35 +            node->sym()->type()->isEnum() ||
    9.36 +            node->sym()->type()->isChar() ||
    9.37 +            node->sym()->type()->isBool())
    9.38 +        {
    9.39 +            __ int_(0);
    9.40 +        } else if (node->sym()->type()->isFloat()) {
    9.41 +            __ float_(0);
    9.42 +        } else if (node->sym()->type()->isArray()) {
    9.43 +            Local<ArrayType> type(zone_, ArrayType::cast(node->sym()->type()));
    9.44 +            Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
    9.45 +            if (!map)
    9.46 +                return;
    9.47 +
    9.48 +            if (type->isFixedLength()) {
    9.49 +                __ newarray(OP_NEWFIXED, map, InferTenure(node->sym()));
    9.50 +            } else if (node->dims()) {
    9.51 +                assert(false);
    9.52 +                __ newarray(OP_NEWSIZED, map, InferTenure(node->sym()));
    9.53 +            } else {
    9.54 +                __ newarray(OP_NEWEMPTY, map, InferTenure(node->sym()));
    9.55 +            }
    9.56 +        }
    9.57      }
    9.58  
    9.59 -    discharge(hir);
    9.60 -
    9.61      if (!__ allocate(node->sym()))
    9.62          return;
    9.63  
    9.64 @@ -524,6 +556,33 @@
    9.65      __ jump(loop_->continue_());
    9.66  }
    9.67  
    9.68 +void
    9.69 +SemanticAnalysis::visitIndexExpression(IndexExpression *node)
    9.70 +{
    9.71 +    HIR *left = eval(node->left());
    9.72 +    if (!left)
    9.73 +        return;
    9.74 +
    9.75 +    HIR *right = eval(node->right());
    9.76 +    if (!right)
    9.77 +        return;
    9.78 +
    9.79 +    // Hrm... yes, for now, let's coerce here.
    9.80 +    Local<Type> i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
    9.81 +    if ((right = coerce(right, i32, Coerce_Arg)) == NULL)
    9.82 +        return;
    9.83 +    
    9.84 +    // Do not coerce here, there's no reason to yet.
    9.85 +    if (!left->type()->isArray()) {
    9.86 +        cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
    9.87 +        return;
    9.88 +    }
    9.89 +
    9.90 +    hir_ = new (pool_) HIndex(ArrayType::cast(left->type())->contained(),
    9.91 +                              left,
    9.92 +                              right);
    9.93 +}
    9.94 +
    9.95  Type *
    9.96  SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right)
    9.97  {
    10.1 --- a/src/compiler/SemanticAnalysis.h	Sat Nov 17 23:13:39 2012 -0800
    10.2 +++ b/src/compiler/SemanticAnalysis.h	Sun Nov 18 14:53:23 2012 -0800
    10.3 @@ -61,6 +61,7 @@
    10.4      void visitBreakStatement(BreakStatement *node);
    10.5      void visitContinueStatement(ContinueStatement *node);
    10.6      void visitIfStatement(IfStatement *node);
    10.7 +    void visitIndexExpression(IndexExpression *node);
    10.8  #if 0
    10.9      void visitFunctionTypeStatement(FunctionTypeStatement *node);
   10.10      void visitImportStatement(ImportStatement *node);
   10.11 @@ -71,7 +72,6 @@
   10.12  
   10.13      void visitBinaryExpression(BinaryExpression *node);
   10.14      void visitCallExpression(CallExpression *node);
   10.15 -    void visitIndexExpression(IndexExpression *node);
   10.16      void visitStringLiteral(StringLiteral *node);
   10.17      void visitIncDecExpression(IncDecExpression *node);
   10.18      void visitUnaryExpression(UnaryExpression *node);
    11.1 --- a/src/jitcraft.vcxproj	Sat Nov 17 23:13:39 2012 -0800
    11.2 +++ b/src/jitcraft.vcxproj	Sun Nov 18 14:53:23 2012 -0800
    11.3 @@ -99,6 +99,7 @@
    11.4      <ClCompile Include="Box.cpp" />
    11.5      <ClCompile Include="compiler\BytecodeEmitter.cpp" />
    11.6      <ClCompile Include="compiler\CompileContext.cpp" />
    11.7 +    <ClCompile Include="compiler\ConstantEvaluator.cpp" />
    11.8      <ClCompile Include="compiler\HIR.cpp" />
    11.9      <ClCompile Include="compiler\NameBinding.cpp" />
   11.10      <ClCompile Include="compiler\Parser.cpp" />
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/tests/basic/float-arrays.out	Sun Nov 18 14:53:23 2012 -0800
    12.3 @@ -0,0 +1,1 @@
    12.4 +11.500000
    13.1 --- a/tests/basic/float-arrays.sp	Sat Nov 17 23:13:39 2012 -0800
    13.2 +++ b/tests/basic/float-arrays.sp	Sun Nov 18 14:53:23 2012 -0800
    13.3 @@ -1,4 +1,4 @@
    13.4 -native PrintFloat(Float:num);
    13.5 +native PrintFloat(float:num);
    13.6  
    13.7  public main()
    13.8  {