Add support for array reference semantics.
Add support for array reference semantics.
1.1 --- a/src/Array.cpp Sat Sep 15 13:32:01 2012 -0700
1.2 +++ b/src/Array.cpp Sat Sep 15 17:39:45 2012 -0700
1.3 @@ -87,7 +87,7 @@
1.4 Local<ArrayMap> childMap(zone, ArrayMap::cast(map->type()->contained()->newMap()));
1.5 Local<Array> child(zone);
1.6 for (unsigned i = 0; i < elements; i++) {
1.7 - child = Array::New(zone, childMap, map->type()->contained()->elements(), tenure);
1.8 + child = Array::New(zone, childMap, map->type()->contained()->declaredLength(), tenure);
1.9 if (!child)
1.10 return NULL;
1.11
2.1 --- a/src/BytecodeCompiler.cpp Sat Sep 15 13:32:01 2012 -0700
2.2 +++ b/src/BytecodeCompiler.cpp Sat Sep 15 17:39:45 2012 -0700
2.3 @@ -199,10 +199,18 @@
2.4 __ pop();
2.5 }
2.6
2.7 +static inline bool
2.8 +IsCompositeValueType(Type *type)
2.9 +{
2.10 + return type->isStruct() ||
2.11 + (type->isArray() && type->isFixedLength());
2.12 +}
2.13 +
2.14 void
2.15 BytecodeCompiler::visit(Assignment *node)
2.16 {
2.17 - Local<Type> type(zone_, node->expression()->type());
2.18 + Local<Type> left(zone_, node->type());
2.19 + Local<Type> right(zone_, node->expression()->type());
2.20
2.21 // The first step is three sub-steps:
2.22 //
2.23 @@ -215,13 +223,12 @@
2.24 NameProxy *proxy = node->lvalue()->toNameProxy();
2.25 Variable *var = proxy->binding()->toVariable();
2.26
2.27 - // Bind.
2.28 - if (var->type()->isReference() ||
2.29 - var->type()->isArray() ||
2.30 - var->type()->isStruct())
2.31 - {
2.32 + // We need to fetch the variable under the following circumstances:
2.33 + // (1) The variable is a reference, since we'll store into the ref.
2.34 + // (2) The variable is a fixed array, since we need to copy into it.
2.35 + // (3) The variable is a struct, since we need to copy into it.
2.36 + if (var->type()->isReference() || IsCompositeValueType(var->type()))
2.37 __ get(var);
2.38 - }
2.39
2.40 // Get the value if needed.
2.41 if (node->token() != TOK_ASSIGN) {
2.42 @@ -247,8 +254,8 @@
2.43 if (node->token() != TOK_ASSIGN)
2.44 __ dup();
2.45
2.46 - if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray()))
2.47 - __ getfield(expr->fieldIndex(), expr->type());
2.48 + if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
2.49 + __ getfield(expr->fieldIndex(), left);
2.50 } else {
2.51 IndexExpression *index = node->lvalue()->toIndexExpression();
2.52 __ note_position(index->pos());
2.53 @@ -259,14 +266,14 @@
2.54 if (node->token() != TOK_ASSIGN)
2.55 __ dup2();
2.56
2.57 - if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray()))
2.58 - __ getelem(index->type());
2.59 + if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
2.60 + __ getelem(left);
2.61 }
2.62
2.63 if (node->token() == TOK_ASSIGN) {
2.64 node->expression()->accept(this);
2.65 } else {
2.66 - visitForALU(node->type(), node->expression());
2.67 + visitForALU(left, node->expression());
2.68
2.69 TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
2.70 __ note_position(node->pos());
2.71 @@ -274,14 +281,16 @@
2.72 }
2.73
2.74 // Emit the store.
2.75 - if (type->isArray()) {
2.76 - // Unlike references, which can only be computed from a NamePRoxy,
2.77 - // arrays can be computed from multiple lvalue types.
2.78 + if (left->isArray() && left->isFixedLength()) {
2.79 + // (x = y) returns the left-hand side; if |x| is a fixed-length array,
2.80 + // then |y| is as well, and we perform a deep copy.
2.81 + assert(right->isFixedLength());
2.82 __ note_position(node->pos());
2.83 __ copyarray();
2.84 - } else if (type->isStruct()) {
2.85 + } else if (left->isStruct()) {
2.86 // Structs have value semantics, so emit a full copy. We don't break
2.87 // this down into u-ops, to avoid unnecessary bytecode explosion.
2.88 + assert(right->isStruct());
2.89 __ note_position(node->pos());
2.90 __ copystruct();
2.91 } else if (node->lvalue()->isNameProxy()) {
2.92 @@ -296,10 +305,9 @@
2.93 __ set(var);
2.94 } else if (node->lvalue()->isFieldExpression()) {
2.95 FieldExpression *expr = node->lvalue()->toFieldExpression();
2.96 - __ setfield(expr->fieldIndex(), expr->type());
2.97 + __ setfield(expr->fieldIndex(), left);
2.98 } else {
2.99 - IndexExpression *index = node->lvalue()->toIndexExpression();
2.100 - __ setelem(index->type());
2.101 + __ setelem(left);
2.102 }
2.103 }
2.104
3.1 --- a/src/BytecodeEmitter.h Sat Sep 15 13:32:01 2012 -0700
3.2 +++ b/src/BytecodeEmitter.h Sat Sep 15 17:39:45 2012 -0700
3.3 @@ -373,8 +373,6 @@
3.4 }
3.5 void setelem(Type *type) {
3.6 singleByteOp(OP_SETELEM);
3.7 -
3.8 - assert(!type->isTraceable());
3.9 }
3.10
3.11 void getfield(unsigned index, Type *type) {
4.1 --- a/src/Interpreter.cpp Sat Sep 15 13:32:01 2012 -0700
4.2 +++ b/src/Interpreter.cpp Sat Sep 15 17:39:45 2012 -0700
4.3 @@ -811,7 +811,7 @@
4.4 {
4.5 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
4.6 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
4.7 - Array *array = Array::New(zone, map, map->type()->elements(), tenure);
4.8 + Array *array = Array::New(zone, map, map->type()->declaredLength(), tenure);
4.9 if (!array)
4.10 goto error;
4.11 top.sp->obj = array;
5.1 --- a/src/Messages.tbl Sat Sep 15 13:32:01 2012 -0700
5.2 +++ b/src/Messages.tbl Sat Sep 15 17:39:45 2012 -0700
5.3 @@ -34,7 +34,6 @@
5.4 MSG(ArrayAssignmentTooBig, SyntaxError, "destination array is too small")
5.5 MSG(CannotDeclareStringCell, SyntaxError, "cannot declare a String cell")
5.6 MSG(BinaryTypeError, SyntaxError, "operator '%s' does not support types '%s' and '%s'")
5.7 -MSG(ArraySizeNotKnown, SyntaxError, "array size is not known")
5.8 MSG(UnaryTypeError, SyntaxError, "operator '%s' does not support type '%s'")
5.9 MSG(CantOpenFile, SyntaxError, "cannot open file")
5.10 MSG(ErrorSeekingFile, SyntaxError, "error seeking file")
6.1 --- a/src/SemanticAnalysis.cpp Sat Sep 15 13:32:01 2012 -0700
6.2 +++ b/src/SemanticAnalysis.cpp Sat Sep 15 17:39:45 2012 -0700
6.3 @@ -717,7 +717,7 @@
6.4 return;
6.5 }
6.6
6.7 - if (node->postDimensions()->length() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
6.8 + if (node->postDimensions()->length() > Type::MAX_ARRAY_DEPTH) {
6.9 cc_.reportError(node->pos(), Message_MaximumArrayDepth);
6.10 return;
6.11 }
6.12 @@ -756,17 +756,17 @@
6.13 }
6.14
6.15 if (check) {
6.16 - if (check->elements() == -1) {
6.17 + if (!check->isFixedLength()) {
6.18 cc_.reportError(expr->pos(), Message_ArraySizeCannotBeDetermined);
6.19 return;
6.20 }
6.21
6.22 if (check->isCharArray()) {
6.23 - if (check->elements() > size) {
6.24 + if (check->fixedLength() > unsigned(size)) {
6.25 cc_.reportError(node->pos(), Message_ArrayAssignmentTooBig);
6.26 return;
6.27 }
6.28 - } else if (check->elements() != size) {
6.29 + } else if (check->fixedLength() != unsigned(size)) {
6.30 cc_.reportError(node->pos(), Message_ArrayDimensionSizeMismatch, unsigned(i));
6.31 return;
6.32 }
6.33 @@ -787,11 +787,11 @@
6.34 cc_.reportError(node->pos(), Message_ArraySizeNotSpecified);
6.35 return;
6.36 }
6.37 - if (init->elements() == -1) {
6.38 + if (!init->isFixedLength()) {
6.39 cc_.reportError(node->pos(), Message_ArraySizeCannotBeDetermined);
6.40 return;
6.41 }
6.42 - size = init->elements();
6.43 + size = init->fixedLength();
6.44 }
6.45
6.46 type = zone_->types()->unsafeArray(type, size, false);
6.47 @@ -917,7 +917,7 @@
6.48 if (!type)
6.49 return false;
6.50 } else if (parameter->dimensions()) {
6.51 - if (parameter->dimensions()->length() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
6.52 + if (parameter->dimensions()->length() > Type::MAX_ARRAY_DEPTH) {
6.53 cc_.reportError(parameter->variable()->pos(), Message_MaximumArrayDepth);
6.54 return false;
6.55 }
6.56 @@ -929,9 +929,9 @@
6.57
6.58 for (size_t i = parameter->dimensions()->length() - 1;
6.59 i < parameter->dimensions()->length();
6.60 - i++)
6.61 + i--)
6.62 {
6.63 - int size = Type::UNKNOWN_SIZE;
6.64 + int size = Type::DYNAMIC_ARRAY_SIZE;
6.65 if (Expression *expr = parameter->dimensions()->at(i)) {
6.66 BoxedPrimitive box;
6.67 if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
6.68 @@ -1112,30 +1112,44 @@
6.69
6.70 unsigned level = 1;
6.71 while (given->isArray()) {
6.72 - if (actual->elements() != -1) {
6.73 + if (actual->isFixedLength()) {
6.74 if (forAssign) {
6.75 - if (given->elements() == -1 || actual->elements() == -1) {
6.76 - cc_.reportError(pos, Message_ArraySizeNotKnown);
6.77 + if (!given->isFixedLength()) {
6.78 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
6.79 return false;
6.80 }
6.81
6.82 if (actual->isCharArray()) {
6.83 // String assignment can have a truncated |given|.
6.84 - if (given->elements() > actual->elements()) {
6.85 + if (given->fixedLength() > actual->fixedLength()) {
6.86 cc_.reportError(pos, Message_ArrayAssignmentTooBig);
6.87 return false;
6.88 }
6.89 } else {
6.90 - if (given->elements() != actual->elements()) {
6.91 + if (given->fixedLength() != actual->fixedLength()) {
6.92 cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
6.93 return false;
6.94 }
6.95 }
6.96 - } else {
6.97 - if (actual->elements() != -1 && given->elements() != actual->elements()) {
6.98 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
6.99 - return false;
6.100 - }
6.101 + }
6.102 + } else if (given->isFixedLength()) {
6.103 + // We do not allow assignments in the form:
6.104 + // [][] = [X][Y]
6.105 + //
6.106 + // Otherwise, the following code could break the size guarantees
6.107 + // of the right-hand side:
6.108 + //
6.109 + // new x[][5];
6.110 + // new y[][];
6.111 + // new z[3];
6.112 + //
6.113 + // y = x;
6.114 + // y[0] = z;
6.115 + //
6.116 + // Now |x[0]| contains a 4-length array.
6.117 + if (level > 1) {
6.118 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
6.119 + return false;
6.120 }
6.121 }
6.122 given = given->contained();
7.1 --- a/src/Types.cpp Sat Sep 15 13:32:01 2012 -0700
7.2 +++ b/src/Types.cpp Sat Sep 15 17:39:45 2012 -0700
7.3 @@ -214,8 +214,8 @@
7.4 {
7.5 if (left->levels() != right->levels())
7.6 return false;
7.7 - if (left->elements() != right->elements())
7.8 - return false;
7.9 + if (left->declaredLength() != right->declaredLength())
7.10 + return false;
7.11 return Compare(left->contained(), right->contained());
7.12 }
7.13
8.1 --- a/src/Types.h Sat Sep 15 13:32:01 2012 -0700
8.2 +++ b/src/Types.h Sat Sep 15 17:39:45 2012 -0700
8.3 @@ -97,8 +97,8 @@
8.4 }
8.5
8.6 public:
8.7 - static const int UNKNOWN_SIZE = -1;
8.8 - static const size_t MAX_UNSAFE_ARRAY_DEPTH = 5;
8.9 + static const int DYNAMIC_ARRAY_SIZE = -1;
8.10 + static const size_t MAX_ARRAY_DEPTH = 5;
8.11
8.12 static Type *NewVoid(Zone *zone);
8.13 static Type *NewUnchecked(Zone *zone);
8.14 @@ -166,8 +166,16 @@
8.15 assert(isArray() || isReference());
8.16 return Type::cast(contained_);
8.17 }
8.18 - int elements() {
8.19 + bool isFixedLength() {
8.20 assert(isArray());
8.21 + return elements_ > 0;
8.22 + }
8.23 + int declaredLength() {
8.24 + assert(isArray());
8.25 + return elements_;
8.26 + }
8.27 + unsigned fixedLength() {
8.28 + assert(isFixedLength());
8.29 return elements_;
8.30 }
8.31 unsigned levels() {
9.1 --- a/src/Zone.cpp Sat Sep 15 13:32:01 2012 -0700
9.2 +++ b/src/Zone.cpp Sat Sep 15 17:39:45 2012 -0700
9.3 @@ -114,7 +114,7 @@
9.4 if (!type)
9.5 return false;
9.6
9.7 - type = types_->unsafeArray(type, Type::UNKNOWN_SIZE, false);
9.8 + type = types_->unsafeArray(type, Type::DYNAMIC_ARRAY_SIZE, false);
9.9 if (!type)
9.10 return false;
9.11
9.12 @@ -126,7 +126,7 @@
9.13 if (!type)
9.14 return false;
9.15
9.16 - type = types_->unsafeArray(type, Type::UNKNOWN_SIZE, false);
9.17 + type = types_->unsafeArray(type, Type::DYNAMIC_ARRAY_SIZE, false);
9.18 if (!type)
9.19 return false;
9.20
10.1 --- a/src/main.cpp Sat Sep 15 13:32:01 2012 -0700
10.2 +++ b/src/main.cpp Sat Sep 15 17:39:45 2012 -0700
10.3 @@ -117,7 +117,6 @@
10.4 if (!fun) {
10.5 fprintf(stdout, "Plugin compiles!\nNot running; no public 'main'.\n");
10.6 } else {
10.7 - Local<Function> fun = module->getPublic(0);
10.8 if (!Keima::Invoke(fun, NULL, 0, true, &rval))
10.9 rval = 1;
10.10 }