Add support for SP1-style fixed array initializers.
Add support for SP1-style fixed array initializers.
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);