Add support for array reference semantics.
authorDavid Anderson <dvander@alliedmods.net>
Sat Sep 15 17:39:45 2012 -0700 (2012-09-15)
changeset 184387d76b1e981
parent 183 05571208642f
child 185 10936f3a2ba3
Add support for array reference semantics.
src/Array.cpp
src/BytecodeCompiler.cpp
src/BytecodeEmitter.h
src/Interpreter.cpp
src/Messages.tbl
src/SemanticAnalysis.cpp
src/Types.cpp
src/Types.h
src/Zone.cpp
src/main.cpp
     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          }