Add support for SP1-style fixed array initializers.
authorDavid Anderson <dvander@alliedmods.net>
Sun Sep 16 19:02:23 2012 -0700 (2012-09-16)
changeset 1879308d52205a0
parent 186 03a663e96860
child 188 bab29bcec7fe
Add support for SP1-style fixed array initializers.
src/API.cpp
src/AST.h
src/Array.cpp
src/Array.h
src/BytecodeCompiler.cpp
src/BytecodeCompiler.h
src/BytecodeEmitter.h
src/Interpreter.cpp
src/Messages.tbl
src/Opcodes.tbl
src/Parser.cpp
src/Parser.h
src/SemanticAnalysis.cpp
src/SemanticAnalysis.h
src/Types.h
     1.1 --- a/src/API.cpp	Sat Sep 15 19:33:24 2012 -0700
     1.2 +++ b/src/API.cpp	Sun Sep 16 19:02:23 2012 -0700
     1.3 @@ -496,7 +496,7 @@
     1.4                  if (!slot.obj)
     1.5                      return false;
     1.6              } else {
     1.7 -                Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
     1.8 +                Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
     1.9                  if (!slot.obj)
    1.10                      return false;
    1.11                  memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int));
    1.12 @@ -513,7 +513,7 @@
    1.13                  if (!slot.obj)
    1.14                      return false;
    1.15              } else {
    1.16 -                Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
    1.17 +                Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
    1.18                  if (!slot.obj)
    1.19                      return false;
    1.20                  memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char));
     2.1 --- a/src/AST.h	Sat Sep 15 19:33:24 2012 -0700
     2.2 +++ b/src/AST.h	Sun Sep 16 19:02:23 2012 -0700
     2.3 @@ -53,7 +53,8 @@
     2.4      _(TernaryExpression)        \
     2.5      _(BooleanLiteral)           \
     2.6      _(StructureStatement)       \
     2.7 -    _(SwitchStatement)
     2.8 +    _(SwitchStatement)          \
     2.9 +    _(ArrayLiteral)
    2.10  
    2.11  // Forward declarations.
    2.12  #define _(name) class name;
    2.13 @@ -83,7 +84,8 @@
    2.14      virtual Kind kind() const = 0;
    2.15  
    2.16  #define _(name)     bool is##name() { return kind() == k##name; }                   \
    2.17 -                    name *to##name() { assert(is##name()); return (name *)this; }
    2.18 +                    name *to##name() { assert(is##name()); return (name *)this; }   \
    2.19 +                    name *as##name() { if (!is##name()) return NULL; return to##name(); }
    2.20      ASTKINDS(_)
    2.21  #undef _
    2.22  
    2.23 @@ -337,6 +339,36 @@
    2.24      }
    2.25  };
    2.26  
    2.27 +class ArrayLiteral : public Expression
    2.28 +{
    2.29 +    TokenKind token_;
    2.30 +    ExpressionList *expressions_;
    2.31 +
    2.32 +  public:
    2.33 +    ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
    2.34 +      : Expression(pos),
    2.35 +        token_(token),
    2.36 +        expressions_(expressions)
    2.37 +    {
    2.38 +    }
    2.39 +
    2.40 +    Kind kind() const {
    2.41 +        return kArrayLiteral;
    2.42 +    }
    2.43 +    TokenKind token() const {
    2.44 +        return token_;
    2.45 +    }
    2.46 +    ExpressionList *expressions() const {
    2.47 +        return expressions_;
    2.48 +    }
    2.49 +    bool isFixed() const {
    2.50 +        return token_ == TOK_LBRACE;
    2.51 +    }
    2.52 +    void accept(AstVisitor *visitor) {
    2.53 +        visitor->visit(this);
    2.54 +    }
    2.55 +};
    2.56 +
    2.57  class UnaryExpression : public Expression
    2.58  {
    2.59      Expression *expression_;
     3.1 --- a/src/Array.cpp	Sat Sep 15 19:33:24 2012 -0700
     3.2 +++ b/src/Array.cpp	Sun Sep 16 19:02:23 2012 -0700
     3.3 @@ -72,58 +72,121 @@
     3.4  }
     3.5  
     3.6  Array *
     3.7 -Array::New(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
     3.8 +Array::NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure)
     3.9  {
    3.10 -    assert(map->type()->isFixedLength());
    3.11 +    if (nelements > (INT_MAX / SizeFor(map->type(), 1))) {
    3.12 +        zone->reportError(Message_ArraySizeTooBig);
    3.13 +        return NULL;
    3.14 +    }
    3.15  
    3.16 -    return Array::New(zone, map, map->type()->fixedLength(), tenure);
    3.17 -}
    3.18 -
    3.19 -Array *
    3.20 -Array::New(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure)
    3.21 -{
    3.22 -    size_t elementBytes = SizeFor(map->type(), elements);
    3.23 +    size_t elementBytes = SizeFor(map->type(), nelements);
    3.24      size_t bytes = sizeof(Array) + elementBytes;
    3.25      Local<Array> array(zone, Array::cast(zone->allocate(map, bytes, tenure)));
    3.26      if (!array)
    3.27          return NULL;
    3.28  
    3.29 -    array->nelements_ = elements;
    3.30 +    array->nelements_ = nelements;
    3.31      array->elements_ = (Array *)array + 1;
    3.32 +    memset(array->vec(), 0, elementBytes);
    3.33  
    3.34 -    if (map->type()->contained()->isArray()) {
    3.35 -        Local<ArrayMap> childMap(zone, ArrayMap::cast(map->type()->contained()->newMap()));
    3.36 -        Local<Array> child(zone);
    3.37 -        for (unsigned i = 0; i < elements; i++) {
    3.38 -            unsigned length = map->type()->contained()->isFixedLength()
    3.39 -                              ? map->type()->contained()->fixedLength()
    3.40 -                              : 0;
    3.41 -            child = Array::New(zone, childMap, length, tenure);
    3.42 -            if (!child)
    3.43 -                return NULL;
    3.44 -
    3.45 -            array->writeObject(zone, i, child);
    3.46 -        }
    3.47 -    } else if (map->type()->contained()->isStruct()) {
    3.48 +    if (map->type()->contained()->isStruct()) {
    3.49          Local<StructMap> childMap(zone, StructMap::cast(map->type()->contained()->newMap()));
    3.50          Local<Struct> child(zone);
    3.51 -        for (unsigned i = 0; i < elements; i++) {
    3.52 +        for (unsigned i = 0; i < nelements; i++) {
    3.53              child = Struct::New(zone, childMap, tenure);
    3.54              if (!child)
    3.55                  return NULL;
    3.56  
    3.57              array->writeObject(zone, i, child);
    3.58          }
    3.59 -    } else {
    3.60 -        memset(array->elements_, 0, elementBytes);
    3.61 +    }
    3.62 +
    3.63 +    return array;
    3.64 +}
    3.65 +
    3.66 +static Array *
    3.67 +ConstructSizedArray(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH],
    3.68 +                    unsigned level, Heap::Tenure tenure)
    3.69 +{
    3.70 +    Local<Array> array(zone, Array::NewRaw(zone, map, dims[level], tenure));
    3.71 +    if (!array)
    3.72 +        return NULL;
    3.73 +
    3.74 +    if (map->type()->contained()->isArray()) {
    3.75 +        Local<ArrayMap> childMap(zone, ArrayMap::cast(map->type()->contained()->newMap()));
    3.76 +        Local<Array> child(zone);
    3.77 +
    3.78 +        for (unsigned i = 0; i < unsigned(dims[level]); i++) {
    3.79 +            child = ConstructSizedArray(zone, childMap, dims, level + 1, tenure);
    3.80 +            if (!child)
    3.81 +                return NULL;
    3.82 +
    3.83 +            array->writeObject(zone, i, child);
    3.84 +        }
    3.85 +    }
    3.86 +
    3.87 +    return array;
    3.88 +}
    3.89 +
    3.90 +Array *
    3.91 +Array::NewSized(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH], Heap::Tenure tenure)
    3.92 +{
    3.93 +    for (size_t i = 0; i < map->type()->levels(); i++) {
    3.94 +        if (dims[i] < 0) {
    3.95 +            zone->reportError(Message_InvalidDimensionSize, dims[i], i);
    3.96 +            return NULL;
    3.97 +        }
    3.98      }
    3.99 +
   3.100 +    return ConstructSizedArray(zone, map, dims, 0, tenure);
   3.101 +}
   3.102 +
   3.103 +static Array *
   3.104 +ConstructFixedArray(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   3.105 +{
   3.106 +    unsigned length = map->type()->fixedLength();
   3.107 +    Local<Array> array(zone, Array::NewRaw(zone, map, length, tenure));
   3.108 +    if (!array)
   3.109 +        return NULL;
   3.110 +
   3.111 +    if (map->type()->contained()->isArray()) {
   3.112 +        Local<ArrayMap> childMap(zone, ArrayMap::cast(map->type()->contained()->newMap()));
   3.113 +        Local<Array> child(zone);
   3.114 +
   3.115 +        if (childMap->type()->isFixedLength()) {
   3.116 +            for (unsigned i = 0; i < length; i++) {
   3.117 +                child = ConstructFixedArray(zone, childMap, tenure);
   3.118 +                if (!child)
   3.119 +                    return NULL;
   3.120 +
   3.121 +                array->writeObject(zone, i, child);
   3.122 +            }
   3.123 +        } else {
   3.124 +            for (unsigned i = 0; i < length; i++) {
   3.125 +                child = Array::NewRaw(zone, childMap, 0, tenure);
   3.126 +                if (!child)
   3.127 +                    return NULL;
   3.128 +
   3.129 +                array->writeObject(zone, i, child);
   3.130 +            }
   3.131 +        }
   3.132 +    }
   3.133 +
   3.134      return array;
   3.135  }
   3.136  
   3.137  Array *
   3.138 +Array::NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   3.139 +{
   3.140 +    return ConstructFixedArray(zone, map, tenure);
   3.141 +}
   3.142 +
   3.143 +Array *
   3.144  Array::NewString(Zone *zone, Handle<ArrayMap> map, Address buffer, size_t length, Heap::Tenure tenure)
   3.145  {
   3.146 -    Local<Array> array(zone, Array::New(zone, map, length, tenure));
   3.147 +    assert(map->type()->isCharArray());
   3.148 +
   3.149 +    Local<Array> array(zone, Array::New1D(zone, map, length, tenure));
   3.150      if (!array)
   3.151          return NULL;
   3.152  
   3.153 @@ -133,6 +196,21 @@
   3.154  }
   3.155  
   3.156  Array *
   3.157 +Array::New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure)
   3.158 +{
   3.159 +    assert(map->type()->levels());
   3.160 +    return Array::NewRaw(zone, map, elements, tenure);
   3.161 +}
   3.162 +
   3.163 +Array *
   3.164 +Array::NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   3.165 +{
   3.166 +    assert(!map->type()->isFixedLength());
   3.167 +
   3.168 +    return Array::NewRaw(zone, map, 0, tenure);
   3.169 +}
   3.170 +
   3.171 +Array *
   3.172  Array::NewExternal(Zone *zone, Handle<ArrayMap> map, uint32 nelements, void *buffer,
   3.173                     Heap::Tenure tenure)
   3.174  {
     4.1 --- a/src/Array.h	Sat Sep 15 19:33:24 2012 -0700
     4.2 +++ b/src/Array.h	Sun Sep 16 19:02:23 2012 -0700
     4.3 @@ -1,19 +1,20 @@
     4.4 -/*
     4.5 +/* vim: set ts=4 sw=4 tw=99 et:
     4.6 + *
     4.7   * Copyright (C) 2012 David Anderson
     4.8   *
     4.9 - * This file is part of JITCraft.
    4.10 + * This file is part of SourcePawn.
    4.11   *
    4.12 - * JITCraft is free software: you can redistribute it and/or modify it under
    4.13 + * SourcePawn is free software: you can redistribute it and/or modify it under
    4.14   * the terms of the GNU General Public License as published by the Free
    4.15   * Software Foundation, either version 3 of the License, or (at your option)
    4.16   * any later version.
    4.17   * 
    4.18 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    4.19 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    4.20   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.21   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    4.22   *
    4.23   * You should have received a copy of the GNU General Public License along with
    4.24 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    4.25 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
    4.26   */
    4.27  #ifndef _include_jitcraft_array_h_
    4.28  #define _include_jitcraft_array_h_
    4.29 @@ -34,13 +35,16 @@
    4.30      void *elements_;
    4.31  
    4.32    public:
    4.33 -    static Array *New(Zone *zone, Handle<ArrayMap> map, Heap::Tenure = Heap::Tenure_Default);
    4.34 -    static Array *New(Zone *zone, Handle<ArrayMap> map, uint32 elements,
    4.35 -                      Heap::Tenure = Heap::Tenure_Default);
    4.36 +    static Array *NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure = Heap::Tenure_Default);
    4.37      static Array *NewString(Zone *zone, Handle<ArrayMap> map, Address buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
    4.38 +    static Array *NewSized(Zone *zone, Handle<ArrayMap> map, int sizes[MAX_ARRAY_DEPTH], Heap::Tenure = Heap::Tenure_Default);
    4.39      static Array *NewExternal(Zone *zone, Handle<ArrayMap> map, uint32 nelements,
    4.40                                void *elements, Heap::Tenure = Heap::Tenure_Default);
    4.41  
    4.42 +    static Array *New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure = Heap::Tenure_Default);
    4.43 +    static Array *NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
    4.44 +    static Array *NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure);
    4.45 +
    4.46      uint32 length() {
    4.47          return nelements_;
    4.48      }
     5.1 --- a/src/BytecodeCompiler.cpp	Sat Sep 15 19:33:24 2012 -0700
     5.2 +++ b/src/BytecodeCompiler.cpp	Sun Sep 16 19:02:23 2012 -0700
     5.3 @@ -739,20 +739,25 @@
     5.4      __ float_((float)node->value());
     5.5  }
     5.6  
     5.7 +static inline Array *
     5.8 +StringLiteralToArray(Zone *zone, StringLiteral *node)
     5.9 +{
    5.10 +    Local<Type> type(zone, node->type());
    5.11 +    Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
    5.12 +    if (!map)
    5.13 +        return NULL;
    5.14 +
    5.15 +    return Array::NewString(zone,
    5.16 +                            map,
    5.17 +                            node->string()->raw(),
    5.18 +                            node->string()->length(),
    5.19 +                            Heap::Tenure_Old);
    5.20 +}
    5.21 +
    5.22  void
    5.23  BytecodeCompiler::visit(StringLiteral *node)
    5.24  {
    5.25 -    Local<Type> type(zone_, node->type());
    5.26 -    Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
    5.27 -    if (!map)
    5.28 -        return;
    5.29 -
    5.30 -    Local<Array> array(zone_,
    5.31 -        Array::NewString(zone_,
    5.32 -                         map,
    5.33 -                         node->string()->raw(),
    5.34 -                         node->string()->length(),
    5.35 -                         Heap::Tenure_Old));
    5.36 +    Local<Array> array(zone_, StringLiteralToArray(zone_, node));
    5.37      if (!array)
    5.38          return;
    5.39  
    5.40 @@ -774,6 +779,106 @@
    5.41      __ setglobal(var);
    5.42  }
    5.43  
    5.44 +static bool
    5.45 +FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
    5.46 +{
    5.47 +    Local<Array> string(zone);
    5.48 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
    5.49 +        Expression *expr = literal->expressions()->at(i);
    5.50 +        StringLiteral *lit = expr->toStringLiteral();
    5.51 +        if ((string = StringLiteralToArray(zone, lit)) == NULL)
    5.52 +            return false;
    5.53 +
    5.54 +        array->writeObject(zone, i, string);
    5.55 +
    5.56 +        if (string->length() > *maxsize)
    5.57 +            *maxsize = string->length();
    5.58 +
    5.59 +        assert(!array->type()->contained()->isFixedLength() ||
    5.60 +                array->type()->contained()->fixedLength() >= string->length());
    5.61 +    }
    5.62 +
    5.63 +    return true;
    5.64 +}
    5.65 +
    5.66 +static bool
    5.67 +FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
    5.68 +{
    5.69 +    assert(array->type()->fixedLength() == literal->expressions()->length());
    5.70 +
    5.71 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
    5.72 +        Expression *expr = literal->expressions()->at(i);
    5.73 +        if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
    5.74 +            array->writeInt32(i, lit->value());
    5.75 +            continue;
    5.76 +        }
    5.77 +        if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
    5.78 +            if (lit->token() == TOK_TRUE)
    5.79 +                array->writeInt32(i, 1);
    5.80 +            else
    5.81 +                array->writeInt32(i, 0);
    5.82 +            continue;
    5.83 +        }
    5.84 +        if (FloatLiteral *lit = expr->asFloatLiteral()) {
    5.85 +            array->writeFloat(i, lit->value());
    5.86 +            continue;
    5.87 +        }
    5.88 +
    5.89 +        // Unrecognized literal type.
    5.90 +        assert(false);
    5.91 +    }
    5.92 +
    5.93 +    return true;
    5.94 +}
    5.95 +
    5.96 +static bool
    5.97 +TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
    5.98 +                     unsigned *maxsize)
    5.99 +{
   5.100 +    assert(type->fixedLength() == literal->expressions()->length());
   5.101 +
   5.102 +    Local<Type> contained(zone, type->contained());
   5.103 +    if (contained->isCharArray())
   5.104 +        return FillArrayLiteral_String(zone, array, literal, maxsize);
   5.105 +
   5.106 +    if (!contained->isArray())
   5.107 +        return FillArrayLiteral_Primitive(zone, array, literal);
   5.108 +
   5.109 +    Local<Array> subarray(zone);
   5.110 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   5.111 +        Expression *expr = literal->expressions()->at(i);
   5.112 +        subarray = Array::cast(array->readObject(i));
   5.113 +        if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
   5.114 +            return false;
   5.115 +    }
   5.116 +
   5.117 +    return true;
   5.118 +}
   5.119 +
   5.120 +static Array *
   5.121 +BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
   5.122 +{
   5.123 +    Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
   5.124 +    if (!root)
   5.125 +        return NULL;
   5.126 +
   5.127 +    // This should have allocated everything in the array, so all we need to
   5.128 +    // do is traverse down to the lowest levels and copy things.
   5.129 +    Local<Type> type(zone, map->type());
   5.130 +    if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
   5.131 +        return NULL;
   5.132 +
   5.133 +    return root;
   5.134 +}
   5.135 +
   5.136 +static inline bool
   5.137 +ArrayContainsCharBuffers(Type *type)
   5.138 +{
   5.139 +    if (type->contained()->isArray())
   5.140 +        return ArrayContainsCharBuffers(type->contained());
   5.141 +    return type->isCharArray();
   5.142 +}
   5.143 +
   5.144  void
   5.145  BytecodeCompiler::visit(VariableDeclaration *node)
   5.146  {
   5.147 @@ -784,21 +889,91 @@
   5.148          Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
   5.149          __ note_position(node->pos());
   5.150  
   5.151 -        Opcode op;
   5.152 -        if (type->isFixedLength())
   5.153 -            op = OP_NEWFIXED;
   5.154 -        else
   5.155 -            op = OP_NEWEMPTY;
   5.156 +        Local<Type> right(zone_);
   5.157 +        if (node->initialization())
   5.158 +            right = node->initialization()->type();
   5.159 +
   5.160 +        // There are a few methods for allocating, here:
   5.161 +        // (1) If the array is fixed,
   5.162 +        //    (a) Initializer not present,
   5.163 +        //              NEWFIXED
   5.164 +        //    (b) Left is const non-string:
   5.165 +        //              <nothing>
   5.166 +        //    (b) Otherwise:
   5.167 +        //              NEWFIXED
   5.168 +        //              COPYARRAY
   5.169 +        // (2) If the array is not fixed,
   5.170 +        //    (a) Initializer is not present,
   5.171 +        //              NEWEMPTY
   5.172 +        //    (b) Initializer is not a string literal,
   5.173 +        //        or left is const:
   5.174 +        //              <nothing>
   5.175 +        //    (c) Initializer is a string literal,
   5.176 +        //              NEWSIZED
   5.177 +        //              COPYARRAY
   5.178 +        //
   5.179 +
   5.180 +        Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
   5.181 +                              ? Heap::Tenure_Old
   5.182 +                              : Heap::Tenure_Default;
   5.183 +
   5.184 +        if (Expression *init = node->initialization()) {
   5.185 +            if (init->isArrayLiteral()) {
   5.186 +                unsigned maxsize = 0;
   5.187 +                Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
   5.188 +                if (!array)
   5.189 +                    return;
   5.190 +
   5.191 +                assert(type->isFixedLength());
   5.192  
   5.193 -        if (var->scope()->kind() == Scope::GLOBAL)
   5.194 -            __ newarray(op, map, Heap::Tenure_Old);
   5.195 -        else
   5.196 -            __ newarray(op, map, Heap::Tenure_Default);
   5.197 -
   5.198 -        if (node->initialization()) {
   5.199 -            node->initialization()->accept(this);
   5.200 -            __ note_position(node->pos());
   5.201 -            __ copyarray();
   5.202 +                if (type->isConst()) {
   5.203 +                    __ object(array);
   5.204 +                } else if (ArrayContainsCharBuffers(type)) {
   5.205 +                    // This array contains mutable char buffers, so
   5.206 +                    // unfortunately this gets a little more complicated. We
   5.207 +                    // compute the maximum size needed for the innermost
   5.208 +                    // string, which is similar to SP1. This means we can use
   5.209 +                    // CopyArray rather than individually emit opcodes to clone
   5.210 +                    // every string.
   5.211 +                    Local<Type> child(zone_, type);
   5.212 +                    for (size_t i = 0; i < type->levels() - 1; i++) {
   5.213 +                        __ int_(child->fixedLength());
   5.214 +                        child = child->contained();
   5.215 +                    }
   5.216 +                    __ int_(maxsize);
   5.217 +                    __ newarray(OP_NEWSIZED, map, tenure);
   5.218 +                    __ object(array);
   5.219 +                    __ copyarray();
   5.220 +                } else {
   5.221 +                    __ newarray(OP_NEWFIXED, map, tenure);
   5.222 +                    __ object(array);
   5.223 +                    __ copyarray();
   5.224 +                }
   5.225 +            } else if (type->isFixedLength()) {
   5.226 +                // Note in the case of:
   5.227 +                // const String:buffer[50] = "hello";
   5.228 +                //
   5.229 +                // We want to preserve sizeof(buffer) == 50.
   5.230 +                if (type->isConst() && !type->isCharArray()) {
   5.231 +                    init->accept(this);
   5.232 +                } else {
   5.233 +                    __ newarray(OP_NEWFIXED, map, tenure);
   5.234 +                    init->accept(this);
   5.235 +                    __ copyarray();
   5.236 +                }
   5.237 +            } else if (!type->isConst() && init->isStringLiteral()) {
   5.238 +                // This is a degenerate case of ArrayLiteral.
   5.239 +                __ int_(right->fixedLength());
   5.240 +                __ newarray(OP_NEWSIZED, map, tenure);
   5.241 +                init->accept(this);
   5.242 +                __ copyarray();
   5.243 +            } else if (type->isConst()) {
   5.244 +                init->accept(this);
   5.245 +            }
   5.246 +        } else if (type->isFixedLength()) {
   5.247 +            __ newarray(OP_NEWFIXED, map, tenure);
   5.248 +        } else {
   5.249 +            __ newarray(OP_NEWEMPTY, map, tenure);
   5.250          }
   5.251      } else if (type->isStruct()) {
   5.252          Local<Map> map(zone_, type->newMap());
   5.253 @@ -1157,6 +1332,14 @@
   5.254  {
   5.255  }
   5.256  
   5.257 +void
   5.258 +BytecodeCompiler::visit(ArrayLiteral *node)
   5.259 +{
   5.260 +    // We shouldn't reach these; they're handled manually when initializing
   5.261 +    // declared arrays.
   5.262 +    assert(false);
   5.263 +}
   5.264 +
   5.265  Code *
   5.266  BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
   5.267  {
     6.1 --- a/src/BytecodeCompiler.h	Sat Sep 15 19:33:24 2012 -0700
     6.2 +++ b/src/BytecodeCompiler.h	Sun Sep 16 19:02:23 2012 -0700
     6.3 @@ -26,6 +26,8 @@
     6.4  namespace ke {
     6.5  
     6.6  class Module;
     6.7 +class Array;
     6.8 +class ArrayMap;
     6.9  
    6.10  struct ModuleData
    6.11  {
    6.12 @@ -149,6 +151,7 @@
    6.13      void visit(FieldExpression *node);
    6.14      void visit(SwitchStatement *node);
    6.15      void visit(FunctionTypeStatement *node);
    6.16 +    void visit(ArrayLiteral *node);
    6.17  };
    6.18  
    6.19  }
     7.1 --- a/src/BytecodeEmitter.h	Sat Sep 15 19:33:24 2012 -0700
     7.2 +++ b/src/BytecodeEmitter.h	Sun Sep 16 19:02:23 2012 -0700
     7.3 @@ -25,11 +25,13 @@
     7.4  #include "NameBinding.h"
     7.5  #include "Handles.h"
     7.6  #include "CompactBuffer.h"
     7.7 +#include "Array.h"
     7.8  
     7.9  namespace ke {
    7.10  
    7.11  class Type;
    7.12  class Map;
    7.13 +class ArrayMap;
    7.14  
    7.15  typedef PoolList<ScopedRoot<Object> > ObjectList;
    7.16  
    7.17 @@ -436,7 +438,7 @@
    7.18      void cvt_i2f() {
    7.19          singleByteOp(OP_CVT_I2F);
    7.20      }
    7.21 -    void newarray(Opcode op, Handle<Map> map, Heap::Tenure tenure) {
    7.22 +    void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
    7.23          assert(op == OP_NEWFIXED ||
    7.24                 op == OP_NEWEMPTY ||
    7.25                 op == OP_NEWSIZED);
    7.26 @@ -446,6 +448,10 @@
    7.27          writeOp(op);
    7.28          writeUint8(tenure);
    7.29          writeObject(map);
    7.30 +
    7.31 +        if (op == OP_NEWSIZED)
    7.32 +            drop(map->type()->levels());
    7.33 +
    7.34          markOop(1);
    7.35      }
    7.36      void newstruct(Handle<Map> map, Heap::Tenure tenure) {
     8.1 --- a/src/Interpreter.cpp	Sat Sep 15 19:33:24 2012 -0700
     8.2 +++ b/src/Interpreter.cpp	Sun Sep 16 19:02:23 2012 -0700
     8.3 @@ -99,7 +99,8 @@
     8.4              return false;
     8.5      }
     8.6  
     8.7 -    if (source->type()->contained()->isArray()) {
     8.8 +    Local<Type> contained(zone, source->type()->contained());
     8.9 +    if (contained->isArray() && contained->isFixedLength()) {
    8.10          assert(dest->type()->contained()->isArray());
    8.11          assert(source->length() == dest->length());
    8.12  
    8.13 @@ -111,8 +112,11 @@
    8.14              if (!CopyArray(zone, left, right))
    8.15                  return false;
    8.16          }
    8.17 -    } else if (source->type()->contained()->isStruct()) {
    8.18 -        assert(dest->type()->contained() == source->type()->contained());
    8.19 +        return true;
    8.20 +    }
    8.21 +    
    8.22 +    if (contained->isStruct()) {
    8.23 +        assert(dest->type()->contained() == contained);
    8.24          assert(source->length() == dest->length());
    8.25  
    8.26          Local<Struct> left(zone);
    8.27 @@ -123,14 +127,21 @@
    8.28              if (!CopyStruct(zone, left, right))
    8.29                  return false;
    8.30          }
    8.31 -    } else {
    8.32 -        assert(source->type()->contained()->pod() == dest->type()->contained()->pod());
    8.33 -        assert(source->type()->contained()->pod() == PrimitiveType_Char
    8.34 -               ? source->length() <= dest->length()
    8.35 -               : source->length() == dest->length());
    8.36 +        return true;
    8.37 +    }
    8.38  
    8.39 -        memcpy(dest->vec(), source->vec(), source->length() * source->elementSize());
    8.40 +    if (contained->isTraceable()) {
    8.41 +        for (unsigned i = 0; i < source->length(); i++)
    8.42 +            dest->writeObject(zone, i, source->readObject(i));
    8.43 +        return true;
    8.44      }
    8.45 +
    8.46 +    assert(contained->pod() == dest->type()->contained()->pod());
    8.47 +    assert(contained->pod() == PrimitiveType_Char
    8.48 +           ? source->length() <= dest->length()
    8.49 +           : source->length() == dest->length());
    8.50 +
    8.51 +    memcpy(dest->vec(), source->vec(), source->length() * source->elementSize());
    8.52      return true;
    8.53  }
    8.54  
    8.55 @@ -811,7 +822,7 @@
    8.56  {
    8.57      Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
    8.58      Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
    8.59 -    Array *array = Array::New(zone, map, tenure);
    8.60 +    Array *array = Array::NewFixed(zone, map, tenure);
    8.61      if (!array)
    8.62          goto error;
    8.63      top.sp->obj = array;
    8.64 @@ -823,7 +834,25 @@
    8.65  {
    8.66      Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
    8.67      Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
    8.68 -    Array *array = Array::New(zone, map, 0, tenure);
    8.69 +    Array *array = Array::NewEmpty(zone, map, tenure);
    8.70 +    if (!array)
    8.71 +        goto error;
    8.72 +    top.sp->obj = array;
    8.73 +    top.sp++;
    8.74 +    break;
    8.75 +}
    8.76 +
    8.77 +case OP_NEWSIZED:
    8.78 +{
    8.79 +    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
    8.80 +    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
    8.81 +    assert(map->type()->levels() < MAX_ARRAY_DEPTH);
    8.82 +
    8.83 +    int dims[MAX_ARRAY_DEPTH];
    8.84 +    for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
    8.85 +        dims[i] = POP_I32(top);
    8.86 +
    8.87 +    Array *array = Array::NewSized(zone, map, dims, tenure);
    8.88      if (!array)
    8.89          goto error;
    8.90      top.sp->obj = array;
     9.1 --- a/src/Messages.tbl	Sat Sep 15 19:33:24 2012 -0700
     9.2 +++ b/src/Messages.tbl	Sun Sep 16 19:02:23 2012 -0700
     9.3 @@ -73,3 +73,8 @@
     9.4  MSG(CaseHasSameValue,               SyntaxError,            "case value appears twice in the same switch")
     9.5  MSG(CaseMustBeInteger,              SyntaxError,            "switch may only operate on integer values")
     9.6  MSG(StructCantBeEmpty,              SyntaxError,            "struct cannot be declared without any fields")
     9.7 +MSG(CannotInitializeEvalArray,      SyntaxError,            "cannot mix dynamic array sizes and initializers")
     9.8 +MSG(ExpectedStringLiteral,          SyntaxError,            "expected string literal")
     9.9 +MSG(UnexpectedArrayLiteral,         SyntaxError,            "unexpected array literal")
    9.10 +MSG(InvalidDimensionSize,           TypeError,              "invalid size %d for dimension %d")
    9.11 +
    10.1 --- a/src/Opcodes.tbl	Sat Sep 15 19:33:24 2012 -0700
    10.2 +++ b/src/Opcodes.tbl	Sun Sep 16 19:02:23 2012 -0700
    10.3 @@ -115,7 +115,7 @@
    10.4  //  [u8 op] [u8 tenure] [u32 index]
    10.5  OPDEF(OP_NEWFIXED,      40,         "newfixed",     6,      0, 1)
    10.6  OPDEF(OP_NEWEMPTY,      41,         "newempty",     6,      0, 1)
    10.7 -OPDEF(OP_NEWSIZED,      42,         "newsized",     6,      1, 1)
    10.8 +OPDEF(OP_NEWSIZED,      42,         "newsized",     6,     -1, 1)
    10.9  
   10.10  // Performs an array-to-array assignment.
   10.11  //   Left = pop()
    11.1 --- a/src/Parser.cpp	Sat Sep 15 19:33:24 2012 -0700
    11.2 +++ b/src/Parser.cpp	Sun Sep 16 19:02:23 2012 -0700
    11.3 @@ -128,14 +128,6 @@
    11.4  {
    11.5      TokenKind kind = scanner_.peek();
    11.6      switch (kind) {
    11.7 -      case TOK_NAME:
    11.8 -      {
    11.9 -        Local<String> name(zone_, expectName());
   11.10 -        if (!name)
   11.11 -            return NULL;
   11.12 -        return bind(name);
   11.13 -      }
   11.14 -
   11.15        case TOK_FLOAT_LITERAL:
   11.16        {
   11.17          scanner_.scan();
   11.18 @@ -182,6 +174,47 @@
   11.19  }
   11.20  
   11.21  Expression *
   11.22 +Parser::arrayLiteral(TokenKind kind)
   11.23 +{
   11.24 +    assert(kind == TOK_LBRACE || kind == TOK_LBRACKET);
   11.25 +
   11.26 +    TokenKind close = (kind == TOK_LBRACE)
   11.27 +                      ? TOK_RBRACE
   11.28 +                      : TOK_RBRACKET;
   11.29 +
   11.30 +    SourcePosition pos = scanner_.begin();
   11.31 +
   11.32 +    ExpressionList *list = new (pool_) ExpressionList();
   11.33 +    do {
   11.34 +        if (match(close))
   11.35 +            break;
   11.36 +
   11.37 +        Expression *expr = NULL;
   11.38 +        if (kind == TOK_LBRACE) {
   11.39 +            if (peek(TOK_LBRACE))
   11.40 +                expr = arrayLiteral(TOK_LBRACE);
   11.41 +            else
   11.42 +                expr = primitive();
   11.43 +        } else {
   11.44 +            expr = expression();
   11.45 +        }
   11.46 +        if (!expr)
   11.47 +            return NULL;
   11.48 +
   11.49 +        if (!list->append(expr))
   11.50 +            return NULL;
   11.51 +
   11.52 +        if (!match(TOK_COMMA)) {
   11.53 +            if (!expect(close))
   11.54 +                return NULL;
   11.55 +            break;
   11.56 +        }
   11.57 +    } while (true);
   11.58 +
   11.59 +    return new (pool_) ArrayLiteral(pos, kind, list);
   11.60 +}
   11.61 +
   11.62 +Expression *
   11.63  Parser::prefix()
   11.64  {
   11.65      switch (scanner_.peek()) {
   11.66 @@ -196,6 +229,14 @@
   11.67          return expr;
   11.68        }
   11.69  
   11.70 +      case TOK_NAME:
   11.71 +      {
   11.72 +        Local<String> name(zone_, expectName());
   11.73 +        if (!name)
   11.74 +            return NULL;
   11.75 +        return bind(name);
   11.76 +      }
   11.77 +
   11.78        default:
   11.79          return primitive();
   11.80      }
   11.81 @@ -844,8 +885,18 @@
   11.82      
   11.83      Expression *expr = NULL;
   11.84      if (match(TOK_ASSIGN)) {
   11.85 -        if ((expr = expression()) == NULL)
   11.86 -            return NULL;
   11.87 +        switch (scanner_.peek()) {
   11.88 +          // Note: we don't support [] literals yet.
   11.89 +          case TOK_LBRACE:
   11.90 +            if ((expr = arrayLiteral(scanner_.scan())) == NULL)
   11.91 +                return NULL;
   11.92 +            break;
   11.93 +
   11.94 +          default:
   11.95 +            if ((expr = expression()) == NULL)
   11.96 +                return NULL;
   11.97 +            break;
   11.98 +        }
   11.99      }
  11.100  
  11.101      return new (pool_) VariableDeclaration(var->pos(), kind, var, type, postDimensions, expr);
  11.102 @@ -1718,6 +1769,17 @@
  11.103              node->defaultCase()->accept(this);
  11.104          unindent();
  11.105      }
  11.106 +    void visit(ArrayLiteral *node) {
  11.107 +        prefix();
  11.108 +        fprintf(fp_, "[ ArrayLiteral\n");
  11.109 +        indent();
  11.110 +        for (size_t i = 0; i < node->expressions()->length(); i++) {
  11.111 +            Expression *expr = node->expressions()->at(i);
  11.112 +            indent();
  11.113 +            expr->accept(this);
  11.114 +            unindent();
  11.115 +        }
  11.116 +    }
  11.117  };
  11.118  
  11.119  void
    12.1 --- a/src/Parser.h	Sat Sep 15 19:33:24 2012 -0700
    12.2 +++ b/src/Parser.h	Sun Sep 16 19:02:23 2012 -0700
    12.3 @@ -58,6 +58,7 @@
    12.4      String *expectName();
    12.5  
    12.6      Expression *primitive();
    12.7 +    Expression *arrayLiteral(TokenKind kind);
    12.8      Expression *call(Expression *callee);
    12.9      Expression *field(Expression *left);
   12.10      Expression *index(Expression *left);
    13.1 --- a/src/SemanticAnalysis.cpp	Sat Sep 15 19:33:24 2012 -0700
    13.2 +++ b/src/SemanticAnalysis.cpp	Sun Sep 16 19:02:23 2012 -0700
    13.3 @@ -703,6 +703,128 @@
    13.4      return false;
    13.5  }
    13.6  
    13.7 +static const int INFER_ARRAY_SIZE = 0;
    13.8 +static const int EVAL_ARRAY_SIZE = -1;
    13.9 +static const int DYNAMIC_ARRAY_SIZE = -2;
   13.10 +
   13.11 +bool
   13.12 +SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
   13.13 +{
   13.14 +    for (size_t i = 0; i < exprs->length(); i++) {
   13.15 +        Expression *expr = exprs->at(i);
   13.16 +        if (!expr) {
   13.17 +            dims[i] = INFER_ARRAY_SIZE;
   13.18 +            continue;
   13.19 +        }
   13.20 +
   13.21 +        BoxedPrimitive box;
   13.22 +        if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
   13.23 +            int size = box.toInt();
   13.24 +            if (size <= 0) {
   13.25 +                cc_.reportError(expr->pos(), Message_BadArraySize);
   13.26 +                return false;
   13.27 +            }
   13.28 +
   13.29 +            dims[i] = size;
   13.30 +            continue;
   13.31 +        }
   13.32 +
   13.33 +        Local<Type> exprType(zone_, visitForLoad(expr));
   13.34 +        if (!exprType)
   13.35 +            return false;
   13.36 +
   13.37 +        if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
   13.38 +            cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
   13.39 +            return false;
   13.40 +        }
   13.41 +
   13.42 +        dims[i] = EVAL_ARRAY_SIZE;
   13.43 +    }
   13.44 +
   13.45 +    return true;
   13.46 +}
   13.47 +
   13.48 +bool
   13.49 +SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
   13.50 +                                         int dims[MAX_ARRAY_DEPTH],
   13.51 +                                         unsigned dimcount, unsigned level)
   13.52 +{
   13.53 +    if (dims[level] == EVAL_ARRAY_SIZE) {
   13.54 +        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
   13.55 +        return false;
   13.56 +    }
   13.57 +
   13.58 +    if (dims[level] == INFER_ARRAY_SIZE) {
   13.59 +        // Strings always become dynamic arrays.
   13.60 +        if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
   13.61 +            dims[level] = literal->expressions()->length();
   13.62 +    } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
   13.63 +        cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
   13.64 +        return false;
   13.65 +    } else {
   13.66 +        if (literal->expressions()->length() != unsigned(dims[level])) {
   13.67 +            cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
   13.68 +            return false;
   13.69 +        }
   13.70 +    }
   13.71 +
   13.72 +    if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
   13.73 +        for (size_t i = 0; i < literal->expressions()->length(); i++) {
   13.74 +            Expression *expr = literal->expressions()->at(i);
   13.75 +            if (!expr->isStringLiteral()) {
   13.76 +                cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
   13.77 +                return false;
   13.78 +            }
   13.79 +
   13.80 +            StringLiteral *lit = expr->toStringLiteral();
   13.81 +            if (dims[level + 1] > 0 &&
   13.82 +                unsigned(dims[level]) < lit->string()->length())
   13.83 +            {
   13.84 +                cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
   13.85 +                return false;
   13.86 +            }
   13.87 +            if (!visitAndApplyType(lit))
   13.88 +                return false;
   13.89 +        }
   13.90 +    } else if (level == dimcount - 1) {
   13.91 +        Local<Type> type(zone_);
   13.92 +        for (size_t i = 0; i < literal->expressions()->length(); i++) {
   13.93 +            Expression *expr = literal->expressions()->at(i);
   13.94 +            if (expr->isArrayLiteral()) {
   13.95 +                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
   13.96 +                return false;
   13.97 +            }
   13.98 +
   13.99 +            if ((type = visitAndApplyType(expr)) == NULL)
  13.100 +                return false;
  13.101 +
  13.102 +            if (!typeCheckAssignment(expr->pos(), type, contained, true))
  13.103 +                return false;
  13.104 +        }
  13.105 +    } else {
  13.106 +        for (size_t i = 0; i < literal->expressions()->length(); i++) {
  13.107 +            Expression *expr = literal->expressions()->at(i);
  13.108 +            if (!expr->isArrayLiteral()) {
  13.109 +                cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
  13.110 +                return false;
  13.111 +            }
  13.112 +
  13.113 +            assert(expr->toArrayLiteral()->isFixed());
  13.114 +
  13.115 +            if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
  13.116 +                                        contained,
  13.117 +                                        dims,
  13.118 +                                        dimcount,
  13.119 +                                        level + 1))
  13.120 +            {
  13.121 +                return false;
  13.122 +            }
  13.123 +        }
  13.124 +    }
  13.125 +
  13.126 +    return true;
  13.127 +}
  13.128 +
  13.129  void
  13.130  SemanticAnalysis::visit(VariableDeclaration *node)
  13.131  {
  13.132 @@ -710,97 +832,83 @@
  13.133      if (!type)
  13.134          return;
  13.135  
  13.136 -    if (node->postDimensions()) {
  13.137 -        Local<Type> init(zone_);
  13.138 -        if (node->initialization()) {
  13.139 -            if ((init = visitForLoad(node->initialization())) == NULL)
  13.140 -                return;
  13.141 -        }
  13.142 -
  13.143 -        if (node->postDimensions()->length() > Type::MAX_ARRAY_DEPTH) {
  13.144 +    if (node->postDimensions() || type->isArray()) {
  13.145 +        // The type could be an array type, so sum the type and postDimensions
  13.146 +        // together.
  13.147 +        unsigned dimcount = node->postDimensions()->length();
  13.148 +        if (type->isArray())
  13.149 +            dimcount += type->levels();
  13.150 +        if (dimcount > MAX_ARRAY_DEPTH) {
  13.151              cc_.reportError(node->pos(), Message_MaximumArrayDepth);
  13.152              return;
  13.153          }
  13.154  
  13.155 -        // If we have an initializer, make sure it's the same type.
  13.156 -        if (init && node->postDimensions()->length() != init->levels()) {
  13.157 -            cc_.reportError(node->pos(), Message_ArrayInitializerDepth);
  13.158 +        // Take an initial guess at the array dimension sizes.
  13.159 +        int dims[MAX_ARRAY_DEPTH];
  13.160 +        if (!evaluateDimensions(node->postDimensions(), dims))
  13.161              return;
  13.162 +
  13.163 +        // Now add in the type's array dimensions.
  13.164 +        Local<Type> contained(zone_, type);
  13.165 +        for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
  13.166 +            if (type->isFixedLength())
  13.167 +                dims[i] = type->fixedLength();
  13.168 +            else
  13.169 +                dims[i] = DYNAMIC_ARRAY_SIZE;
  13.170 +            contained = contained->contained();
  13.171          }
  13.172  
  13.173 -        Local<Type> check(zone_, init);
  13.174 -        for (size_t i = node->postDimensions()->length() - 1; i < node->postDimensions()->length(); i--) {
  13.175 -            Expression *expr = node->postDimensions()->at(i);
  13.176 -            int size = -1;
  13.177 -
  13.178 -            if (expr) {
  13.179 -                Local<Type> exprType(zone_, visitForLoad(expr));
  13.180 -                if (!exprType)
  13.181 -                    return;
  13.182 -
  13.183 -                if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
  13.184 -                    cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
  13.185 -                    return;
  13.186 -                }
  13.187 -
  13.188 -                BoxedPrimitive box;
  13.189 -                if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
  13.190 -                    size = box.toInt();
  13.191 -                    if (size <= 0) {
  13.192 -                        cc_.reportError(expr->pos(), Message_BadArraySize);
  13.193 -                        return;
  13.194 -                    }
  13.195 -                    if (size >= int(INT_MAX / sizeof(int))) {
  13.196 -                        cc_.reportError(expr->pos(), Message_ArraySizeTooBig);
  13.197 -                        return;
  13.198 -                    }
  13.199 +        Expression *initializer = node->initialization();
  13.200 +        if (initializer &&
  13.201 +            initializer->isArrayLiteral() &&
  13.202 +            initializer->toArrayLiteral()->isFixed())
  13.203 +        {
  13.204 +            // Fixed array initializers are special; we use them to infer any
  13.205 +            // missing information in the original array. We do not evaluate
  13.206 +            // the array initializer as an expression.
  13.207 +            if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
  13.208 +                                        contained,
  13.209 +                                        dims,
  13.210 +                                        dimcount,
  13.211 +                                        0))
  13.212 +            {
  13.213 +                return;
  13.214 +            }
  13.215 +            initializer = NULL;
  13.216 +        }
  13.217  
  13.218 -                    if (check) {
  13.219 -                        if (!check->isFixedLength()) {
  13.220 -                            cc_.reportError(expr->pos(), Message_ArraySizeCannotBeDetermined);
  13.221 -                            return;
  13.222 -                        }
  13.223 -
  13.224 -                        if (check->isCharArray()) {
  13.225 -                            if (check->fixedLength() > unsigned(size)) {
  13.226 -                                cc_.reportError(node->pos(), Message_ArrayAssignmentTooBig);
  13.227 -                                return;
  13.228 -                            }
  13.229 -                        } else if (check->fixedLength() != unsigned(size)) {
  13.230 -                            cc_.reportError(node->pos(), Message_ArrayDimensionSizeMismatch, unsigned(i));
  13.231 -                            return;
  13.232 -                        }
  13.233 -                    }
  13.234 -                } else {
  13.235 -                    if (init) {
  13.236 -                        cc_.reportError(node->pos(), Message_DynamicArrayHasInitializer);
  13.237 -                        return;
  13.238 -                    }
  13.239 -
  13.240 -                    // here until we get dynamic array support.
  13.241 -                    cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
  13.242 -                    return;
  13.243 -                }
  13.244 -            } else {
  13.245 -                if (init && init->isFixedLength())
  13.246 -                    size = init->fixedLength();
  13.247 -                else
  13.248 -                    size = Type::DYNAMIC_ARRAY_SIZE;
  13.249 -            }
  13.250 +        // We now have enough information to build the actual array type.
  13.251 +        // Start from the original dimcount, not the one computed for
  13.252 +        // initializers.
  13.253 +        for (size_t i = node->postDimensions()->length() - 1;
  13.254 +             i < node->postDimensions()->length();
  13.255 +             i--)
  13.256 +        {
  13.257 +            int size = dims[i] > 0
  13.258 +                       ? dims[i]
  13.259 +                       : Type::DYNAMIC_ARRAY_SIZE;
  13.260  
  13.261              type = zone_->types()->newArray(type, size, false);
  13.262              if (!type)
  13.263                  return;
  13.264 +        }
  13.265  
  13.266 -            if (check)
  13.267 -                check = check->contained();
  13.268 +        // Finally, if we had a non-fixed initializer, make sure it type
  13.269 +        // checks. 
  13.270 +        if (initializer) {
  13.271 +            Local<Type> right(zone_, visitForLoad(initializer));
  13.272 +            if (!right)
  13.273 +                return;
  13.274 +
  13.275 +            if (!typeCheckAssignment(node->pos(), right, type, true))
  13.276 +                return;
  13.277          }
  13.278      } else {
  13.279          if (node->initialization()) {
  13.280              Local<Type> right(zone_, visitForLoad(node->initialization()));
  13.281              if (!right)
  13.282                  return;
  13.283 -            if (!typeCheckAssignment(node->pos(), type, right, true))
  13.284 +            if (!typeCheckAssignment(node->pos(), right, type, true))
  13.285                  return;
  13.286          }
  13.287  
  13.288 @@ -911,7 +1019,8 @@
  13.289              if (!type)
  13.290                  return false;
  13.291          } else if (parameter->dimensions()) {
  13.292 -            if (parameter->dimensions()->length() > Type::MAX_ARRAY_DEPTH) {
  13.293 +            // :TODO: factor in type dimcount
  13.294 +            if (parameter->dimensions()->length() > MAX_ARRAY_DEPTH) {
  13.295                  cc_.reportError(parameter->variable()->pos(), Message_MaximumArrayDepth);
  13.296                  return false;
  13.297              }
  13.298 @@ -1128,7 +1237,7 @@
  13.299              }
  13.300          } else if (given->isFixedLength()) {
  13.301              // We do not allow assignments in the form:
  13.302 -            //    [][] = [X][Y]
  13.303 +            //    [][] = [][Y]
  13.304              //
  13.305              // Otherwise, the following code could break the size guarantees
  13.306              // of the right-hand side:
  13.307 @@ -1697,3 +1806,11 @@
  13.308  
  13.309      control_->terminate(Returns_Never);
  13.310  }
  13.311 +
  13.312 +void
  13.313 +SemanticAnalysis::visit(ArrayLiteral *node)
  13.314 +{
  13.315 +    // We should never visit this.
  13.316 +    cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
  13.317 +}
  13.318 +
    14.1 --- a/src/SemanticAnalysis.h	Sat Sep 15 19:33:24 2012 -0700
    14.2 +++ b/src/SemanticAnalysis.h	Sun Sep 16 19:02:23 2012 -0700
    14.3 @@ -21,6 +21,7 @@
    14.4  
    14.5  #include <assert.h>
    14.6  #include "AST.h"
    14.7 +#include "Types.h"
    14.8  
    14.9  namespace ke {
   14.10  
   14.11 @@ -174,6 +175,13 @@
   14.12      Type *visitAndApplyType(Expression *expression);
   14.13      ControlStatus visitForControl(Statement *statement);
   14.14  
   14.15 +    bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
   14.16 +    bool inferFixedArrayLiteral(ArrayLiteral *literal,
   14.17 +                                Handle<Type> type,
   14.18 +                                int dims[MAX_ARRAY_DEPTH],
   14.19 +                                unsigned dimcount,
   14.20 +                                unsigned level);
   14.21 +
   14.22      Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
   14.23      bool checkArgumentCount(Handle<Type> type, unsigned actual);
   14.24      bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
   14.25 @@ -215,6 +223,7 @@
   14.26      void visit(FieldExpression *node);
   14.27      void visit(SwitchStatement *node);
   14.28      void visit(FunctionTypeStatement *node);
   14.29 +    void visit(ArrayLiteral *node);
   14.30  };
   14.31  
   14.32  const char *GetTypeName(Type *type);
    15.1 --- a/src/Types.h	Sat Sep 15 19:33:24 2012 -0700
    15.2 +++ b/src/Types.h	Sun Sep 16 19:02:23 2012 -0700
    15.3 @@ -28,6 +28,8 @@
    15.4  class String;
    15.5  class Descriptor;
    15.6  
    15.7 +#define MAX_ARRAY_DEPTH     5
    15.8 +
    15.9  enum PrimitiveType
   15.10  {
   15.11      // A boolean type semantically represents 0 or 1. As an optimization, its
   15.12 @@ -98,7 +100,6 @@
   15.13  
   15.14    public:
   15.15      static const int DYNAMIC_ARRAY_SIZE = -1;
   15.16 -    static const size_t MAX_ARRAY_DEPTH = 5;
   15.17      
   15.18      static Type *NewVoid(Zone *zone);
   15.19      static Type *NewUnchecked(Zone *zone);