Get string literals working again.
authorDavid Anderson <dvander@alliedmods.net>
Mon Dec 24 02:49:20 2012 -0800 (2012-12-24)
changeset 23426e3035cdffc
parent 233 bbb498ccb4ac
child 235 43287eef2fff
Get string literals working again.
src/Array.cpp
src/Array.h
src/Interpreter.cpp
src/ObjectVisitor.h
src/Opcodes.cpp
src/Opcodes.tbl
src/Structures.cpp
src/Structures.h
src/TypeManager.cpp
src/Types.h
src/compiler/AST.h
src/compiler/BytecodeEmitter.h
src/compiler/HIR.cpp
src/compiler/HIR.h
src/compiler/Parser.cpp
src/compiler/SemanticAnalysis.cpp
src/compiler/SemanticAnalysis.h
tests/basic/string-lit-1.out
tests/basic/string-lit-1.sp
     1.1 --- a/src/Array.cpp	Sat Dec 22 23:18:57 2012 -0800
     1.2 +++ b/src/Array.cpp	Mon Dec 24 02:49:20 2012 -0800
     1.3 @@ -62,6 +62,8 @@
     1.4  Array *
     1.5  Array::NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure)
     1.6  {
     1.7 +    assert(!map->type()->isFixedLength() || nelements == map->type()->fixedLength());
     1.8 +
     1.9      if (nelements > (INT_MAX / SizeForElement(map->type()))) {
    1.10          zone->reportError(Message_ArraySizeTooBig);
    1.11          return NULL;
    1.12 @@ -209,16 +211,21 @@
    1.13  }
    1.14  
    1.15  Array *
    1.16 -Array::NewString(Zone *zone, Handle<ArrayMap> map, Address buffer, size_t length, Heap::Tenure tenure)
    1.17 +Array::NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure tenure)
    1.18  {
    1.19      assert(map->type()->isCharArray());
    1.20  
    1.21 -    Local<Array> array(zone, Array::New1D(zone, map, length, tenure));
    1.22 +    Local<Array> array(zone);
    1.23 +    
    1.24 +    if (map->type()->isFixedLength())
    1.25 +        array = Array::NewFixed(zone, map, tenure);
    1.26 +    else
    1.27 +        array = Array::New1D(zone, map, length + 1, tenure);
    1.28      if (!array)
    1.29          return NULL;
    1.30  
    1.31 -    assert(array->length() >= length);
    1.32 -    memcpy(array->chars(), buffer, length);
    1.33 +    assert(array->length() >= length + 1);
    1.34 +    memcpy(array->chars(), buffer, length + 1);
    1.35      return array;
    1.36  }
    1.37  
    1.38 @@ -250,3 +257,90 @@
    1.39      return array;
    1.40  }
    1.41  
    1.42 +static bool
    1.43 +CopyArrayElements(Zone *zone, Handle<Type> contained, Handle<Array> dest, Handle<Array> source)
    1.44 +{
    1.45 +    if (contained->isTraceable()) {
    1.46 +        if (contained->isStruct()) {
    1.47 +            assert(dest->type()->contained() == contained);
    1.48 +            assert(source->length() == dest->length());
    1.49 +
    1.50 +            Local<Struct> left(zone);
    1.51 +            Local<Struct> right(zone);
    1.52 +            for (unsigned i = 0; i < source->length(); i++) {
    1.53 +                left = Struct::cast(dest->readObject(i));
    1.54 +                right = Struct::cast(source->readObject(i));
    1.55 +                if (!Struct::Copy(zone, left, right))
    1.56 +                    return false;
    1.57 +            }
    1.58 +        } else {
    1.59 +            assert(dest->length() == source->length());
    1.60 +            for (unsigned i = 0; i < source->length(); i++)
    1.61 +                dest->writeObject(zone, i, source->readObject(i));
    1.62 +        }
    1.63 +    } else {
    1.64 +        assert(contained->pod() == dest->type()->contained()->pod());
    1.65 +        assert(contained->pod() == PrimitiveType_Char
    1.66 +               ? source->length() <= dest->length()
    1.67 +               : source->length() == dest->length());
    1.68 +    
    1.69 +        assert(dest->length());
    1.70 +        memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
    1.71 +    }
    1.72 +    return true;
    1.73 +}
    1.74 +
    1.75 +// Shallow copy an array. Fixed slots in the destination are copied from
    1.76 +// the source, but otherwise, references are assigned.
    1.77 +bool
    1.78 +Array::ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source)
    1.79 +{
    1.80 +#if 0
    1.81 +    Local<Type> contained(zone, source->type()->contained());
    1.82 +    if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) {
    1.83 +        assert(dest->type()->contained()->isArray());
    1.84 +        assert(source->length() == dest->length());
    1.85 +
    1.86 +        Local<Array> left(zone);
    1.87 +        Local<Array> right(zone);
    1.88 +        for (unsigned i = 0; i < source->length(); i++) {
    1.89 +            left = Array::cast(dest->readObject(i));
    1.90 +            right = Array::cast(source->readObject(i));
    1.91 +            if (!ShallowCopy(zone, left, right))
    1.92 +                return false;
    1.93 +        }
    1.94 +        return true;
    1.95 +    }
    1.96 +    
    1.97 +#endif
    1.98 +    assert(false);
    1.99 +    return false;
   1.100 +}
   1.101 +
   1.102 +Array *
   1.103 +Array::DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure)
   1.104 +{
   1.105 +    Local<ArrayMap> map(zone, ArrayMap::cast(source->map()));
   1.106 +
   1.107 +    Local<Array> dest(zone, Array::NewRaw(zone, map, source->length(), tenure));
   1.108 +    if (!dest)
   1.109 +        return NULL;
   1.110 +
   1.111 +    Local<Type> contained(zone, source->type()->contained());
   1.112 +    if (contained->isArray()) {
   1.113 +        assert(false);
   1.114 +        Local<Array> sub(zone);
   1.115 +        for (size_t i = 0; i < source->length(); i++) {
   1.116 +            sub = Array::cast(source->readObject(i));
   1.117 +            sub = DeepCopy(zone, sub, tenure);
   1.118 +            if (!sub)
   1.119 +                return NULL;
   1.120 +            dest->writeObject(zone, i, sub);
   1.121 +        }
   1.122 +    } else {
   1.123 +        if (!CopyArrayElements(zone, contained, dest, source))
   1.124 +            return NULL;
   1.125 +    }
   1.126 +
   1.127 +    return dest;
   1.128 +}
     2.1 --- a/src/Array.h	Sat Dec 22 23:18:57 2012 -0800
     2.2 +++ b/src/Array.h	Mon Dec 24 02:49:20 2012 -0800
     2.3 @@ -48,7 +48,7 @@
     2.4  
     2.5    public:
     2.6      static Array *NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure = Heap::Tenure_Default);
     2.7 -    static Array *NewString(Zone *zone, Handle<ArrayMap> map, Address buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
     2.8 +    static Array *NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
     2.9      static Array *NewSized(Zone *zone, Handle<ArrayMap> map, int sizes[MAX_ARRAY_DEPTH], Heap::Tenure = Heap::Tenure_Default);
    2.10  
    2.11      static Array *New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure = Heap::Tenure_Default);
    2.12 @@ -61,6 +61,15 @@
    2.13                                unsigned length,
    2.14                                Heap::Tenure tenure = Heap::Tenure_Default);
    2.15  
    2.16 +    // Copies an array from one reference to another, obeying language semantics.
    2.17 +    static bool ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source);
    2.18 +
    2.19 +    // Creates a full duplicate of an array, following all array references as if
    2.20 +    // they were fixed. Array references inside structs or objects use ShallowCopy
    2.21 +    // semantics, as this is only intended for duplicating array literals, which
    2.22 +    // cannot contain structs.
    2.23 +    static Array *DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure);
    2.24 +
    2.25      uint32 length() {
    2.26          return length_;
    2.27      }
    2.28 @@ -72,6 +81,7 @@
    2.29      inline char *chars();
    2.30      inline void *bytes();
    2.31  
    2.32 +    bool resize(Zone *zone, size_t newLength);
    2.33  
    2.34      static inline size_t SizeForElement(ArrayType *type) {
    2.35          if (type->contained()->isTraceable())
     3.1 --- a/src/Interpreter.cpp	Sat Dec 22 23:18:57 2012 -0800
     3.2 +++ b/src/Interpreter.cpp	Mon Dec 24 02:49:20 2012 -0800
     3.3 @@ -82,69 +82,27 @@
     3.4      return true;
     3.5  }
     3.6  
     3.7 -static bool CopyStruct(Zone *zone, Handle<Struct> left, Handle<Struct> right);
     3.8 -
     3.9  static bool
    3.10 -ChangeArrayLength(Zone *zone, Handle<Array> source, Handle<Array> dest)
    3.11 +DuplicateArray(Zone *zone, Handle<Array> src)
    3.12  {
    3.13 -    return true;
    3.14 -}
    3.15 +    Local<ArrayMap> map(zone, ArrayMap::cast(src->map()));
    3.16 +    Local<Array> dest(zone);
    3.17  
    3.18 -// Even though this function can fail, we immediately bail out, so it doesn't
    3.19 -// matter if we've leaving things unrooted.
    3.20 -static bool
    3.21 -CopyArray(Zone *zone, Handle<Array> dest, Handle<Array> source)
    3.22 -{
    3.23 -    if (source->length() != dest->length()) {
    3.24 -        if (!ChangeArrayLength(zone, source, dest))
    3.25 -            return false;
    3.26 +    if (map->type()->isFixedLength()) {
    3.27 +        dest = Array::NewFixed(zone, map);
    3.28 +    } else {
    3.29 +        Type *type = map->type();
    3.30 +        int sizes[MAX_ARRAY_DEPTH];
    3.31 +        for (unsigned i = 0; i < map->type()->levels(); i++) {
    3.32 +            ArrayType *atype = ArrayType::cast(type);
    3.33 +            sizes[i] = atype->isFixedLength()
    3.34 +                       ? atype->fixedLength()
    3.35 +                       : 0;
    3.36 +            type = atype->contained();
    3.37 +        }
    3.38      }
    3.39  
    3.40 -    Local<Type> contained(zone, source->type()->contained());
    3.41 -    if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) {
    3.42 -        assert(dest->type()->contained()->isArray());
    3.43 -        assert(source->length() == dest->length());
    3.44 -
    3.45 -        Local<Array> left(zone);
    3.46 -        Local<Array> right(zone);
    3.47 -        for (unsigned i = 0; i < source->length(); i++) {
    3.48 -            left = Array::cast(dest->readObject(i));
    3.49 -            right = Array::cast(source->readObject(i));
    3.50 -            if (!CopyArray(zone, left, right))
    3.51 -                return false;
    3.52 -        }
    3.53 -        return true;
    3.54 -    }
    3.55 -    
    3.56 -    if (contained->isStruct()) {
    3.57 -        assert(dest->type()->contained() == contained);
    3.58 -        assert(source->length() == dest->length());
    3.59 -
    3.60 -        Local<Struct> left(zone);
    3.61 -        Local<Struct> right(zone);
    3.62 -        for (unsigned i = 0; i < source->length(); i++) {
    3.63 -            left = Struct::cast(dest->readObject(i));
    3.64 -            right = Struct::cast(source->readObject(i));
    3.65 -            if (!CopyStruct(zone, left, right))
    3.66 -                return false;
    3.67 -        }
    3.68 -        return true;
    3.69 -    }
    3.70 -
    3.71 -    if (contained->isTraceable()) {
    3.72 -        for (unsigned i = 0; i < source->length(); i++)
    3.73 -            dest->writeObject(zone, i, source->readObject(i));
    3.74 -        return true;
    3.75 -    }
    3.76 -
    3.77 -    assert(contained->pod() == dest->type()->contained()->pod());
    3.78 -    assert(contained->pod() == PrimitiveType_Char
    3.79 -           ? source->length() <= dest->length()
    3.80 -           : source->length() == dest->length());
    3.81 -
    3.82 -    assert(dest->length());
    3.83 -    memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
    3.84 -    return true;
    3.85 +    Local<Array> dst(zone);
    3.86  }
    3.87  
    3.88  static void
    3.89 @@ -269,49 +227,6 @@
    3.90      StoreField(zone, obj, desc, v);
    3.91  }
    3.92  
    3.93 -// Even though this function can fail, we immediately bail out, so it doesn't
    3.94 -// matter if we've leaving things unrooted.
    3.95 -static bool
    3.96 -CopyStruct(Zone *zone, Handle<Struct> left, Handle<Struct> right)
    3.97 -{
    3.98 -    assert(left->map()->type() == right->map()->type());
    3.99 -
   3.100 -    Local<StructType> type(zone, StructType::cast(left->map()->type()));
   3.101 -    Local<Struct> leftStruct(zone);
   3.102 -    Local<Struct> rightStruct(zone);
   3.103 -    Local<Array> leftArray(zone);
   3.104 -    Local<Array> rightArray(zone);
   3.105 -    for (unsigned i = 0; i < type->fields()->length(); i++) {
   3.106 -        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
   3.107 -
   3.108 -        LocalSlot rval;
   3.109 -        FetchField(right, desc, &rval);
   3.110 -
   3.111 -        // If the field is a struct, we need to deep-copy.
   3.112 -        if (desc->type()->isStruct()) {
   3.113 -            LocalSlot lval;
   3.114 -
   3.115 -            FetchField(left, desc, &lval);
   3.116 -            leftStruct = Struct::cast(lval.obj);
   3.117 -            rightStruct = Struct::cast(rval.obj);
   3.118 -            if (!CopyStruct(zone, leftStruct, rightStruct))
   3.119 -                return false;
   3.120 -        } else if (desc->type()->isArray()) {
   3.121 -            LocalSlot lval;
   3.122 -
   3.123 -            FetchField(left, desc, &lval);
   3.124 -            leftArray = Array::cast(lval.obj);
   3.125 -            rightArray = Array::cast(rval.obj);
   3.126 -            if (!CopyArray(zone, leftArray, rightArray))
   3.127 -                return false;
   3.128 -        } else {
   3.129 -            StoreField(zone, left, desc, rval);
   3.130 -        }
   3.131 -    }
   3.132 -
   3.133 -    return true;
   3.134 -}
   3.135 -
   3.136  static bool
   3.137  InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
   3.138               int *result)
   3.139 @@ -773,6 +688,15 @@
   3.140      break;
   3.141  }
   3.142  
   3.143 +case OP_DUPARRAY:
   3.144 +{
   3.145 +    Local<Array> src(zone, Array::cast(top.sp[-1].obj));
   3.146 +    top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
   3.147 +    if (!top.sp[-1].obj)
   3.148 +        goto error;
   3.149 +    break;
   3.150 +}
   3.151 +
   3.152  case OP_NEWFIXED:
   3.153  {
   3.154      Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
   3.155 @@ -905,7 +829,7 @@
   3.156      // right, since in this case the result of the expression could be different.
   3.157      Local<Array> left(zone, Array::cast(top.sp[-2].array));
   3.158      Local<Array> right(zone, Array::cast(top.sp[-1].array));
   3.159 -    if (!CopyArray(zone, left, right))
   3.160 +    if (!Array::ShallowCopy(zone, left, right))
   3.161          goto error;
   3.162      top.sp--;
   3.163      break;
   3.164 @@ -1016,7 +940,7 @@
   3.165  {
   3.166      Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
   3.167      Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
   3.168 -    if (!CopyStruct(zone, left, right))
   3.169 +    if (!Struct::Copy(zone, left, right))
   3.170          goto error;
   3.171      top.sp[-2].obj = top.sp[-1].obj;
   3.172      top.sp--;
     4.1 --- a/src/ObjectVisitor.h	Sat Dec 22 23:18:57 2012 -0800
     4.2 +++ b/src/ObjectVisitor.h	Mon Dec 24 02:49:20 2012 -0800
     4.3 @@ -142,7 +142,7 @@
     4.4      }
     4.5  
     4.6      size_t iterateArray(Array *array, ArrayMap *map) {
     4.7 -        if (!map->type()->fixedLength() || map->type()->contained()->isTraceable())
     4.8 +        if (!map->type()->hasInlineElements())
     4.9              visitField(array, Array::offsetOfElements());
    4.10          return array->objSize(map);
    4.11      }
     5.1 --- a/src/Opcodes.cpp	Sat Dec 22 23:18:57 2012 -0800
     5.2 +++ b/src/Opcodes.cpp	Mon Dec 24 02:49:20 2012 -0800
     5.3 @@ -210,6 +210,7 @@
     5.4            case OP_SIZEOF:
     5.5            case OP_PUBLIC:
     5.6            case OP_LEAVELOOP:
     5.7 +          case OP_DUPARRAY:
     5.8              break;
     5.9  
    5.10            case OP_ENTERLOOP:
     6.1 --- a/src/Opcodes.tbl	Sat Dec 22 23:18:57 2012 -0800
     6.2 +++ b/src/Opcodes.tbl	Mon Dec 24 02:49:20 2012 -0800
     6.3 @@ -100,6 +100,9 @@
     6.4  OPDEF(OP_NEWEMPTY,      "newempty",     6,      0, 1)
     6.5  OPDEF(OP_NEWSIZED,      "newsized",     6,     -1, 1)
     6.6  
     6.7 +// Creates a duplicate copy of an array.
     6.8 +OPDEF(OP_DUPARRAY,      "duparray",     1,      1, 1)
     6.9 +
    6.10  // Performs an array-to-array assignment.
    6.11  //   Left = pop()
    6.12  //   Right = pop()
     7.1 --- a/src/Structures.cpp	Sat Dec 22 23:18:57 2012 -0800
     7.2 +++ b/src/Structures.cpp	Mon Dec 24 02:49:20 2012 -0800
     7.3 @@ -37,8 +37,13 @@
     7.4      *offset = size_;
     7.5  
     7.6      if (!type->isTraceable()) {
     7.7 -        // For now, assume the size of primitives is 4-byte.
     7.8 -        assert(type->isInt32() || type->isFloat());
     7.9 +        // For now, assume the alignment of all primitive storage is 4 bytes,
    7.10 +        // and that all need <= 4 bytes of storage.
    7.11 +        assert(type->isInt32() ||
    7.12 +               type->isFloat() ||
    7.13 +               type->isBool() ||
    7.14 +               type->isChar() ||
    7.15 +               type->isEnum());
    7.16          size_ += 4;
    7.17          return true;
    7.18      }
    7.19 @@ -147,3 +152,50 @@
    7.20      return obj;
    7.21  }
    7.22  
    7.23 +bool
    7.24 +Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
    7.25 +{
    7.26 +    assert(left->map()->type() == right->map()->type());
    7.27 +
    7.28 +    Local<StructType> type(zone, StructType::cast(left->map()->type()));
    7.29 +    Local<Struct> leftStruct(zone);
    7.30 +    Local<Struct> rightStruct(zone);
    7.31 +    Local<Array> leftArray(zone);
    7.32 +    Local<Array> rightArray(zone);
    7.33 +    for (unsigned i = 0; i < type->fields()->length(); i++) {
    7.34 +        Descriptor *desc = Descriptor::cast(type->fields()->at(i));
    7.35 +
    7.36 +        // If the field is a struct, we need to deep-copy.
    7.37 +        if (desc->type()->isStruct()) {
    7.38 +            leftStruct = Struct::cast(left->get<Object *>(desc));
    7.39 +            rightStruct = Struct::cast(right->get<Object *>(desc));
    7.40 +            if (!Struct::Copy(zone, leftStruct, rightStruct))
    7.41 +                return false;
    7.42 +        } else if (desc->type()->isArray()) {
    7.43 +            leftArray = Array::cast(left->get<Object *>(desc));
    7.44 +            rightArray = Array::cast(right->get<Object *>(desc));
    7.45 +            if (!Array::ShallowCopy(zone, leftArray, rightArray))
    7.46 +                return false;
    7.47 +        } else if (desc->type()->isTraceable()) {
    7.48 +            Object *obj = right->get<Object *>(desc);
    7.49 +            left->set(zone, desc, obj);
    7.50 +        } else {
    7.51 +            switch (desc->type()->pod()) {
    7.52 +              case PrimitiveType_Int32:
    7.53 +              case PrimitiveType_Char:
    7.54 +              case PrimitiveType_Bool:
    7.55 +                left->set(desc, right->get<int>(desc));
    7.56 +                break;
    7.57 +
    7.58 +              case PrimitiveType_Float:
    7.59 +                left->set(desc, right->get<float>(desc));
    7.60 +                break;
    7.61 +                
    7.62 +              default:
    7.63 +                assert(false);
    7.64 +            }
    7.65 +        }
    7.66 +    }
    7.67 +
    7.68 +    return true;
    7.69 +}
    7.70 \ No newline at end of file
     8.1 --- a/src/Structures.h	Sat Dec 22 23:18:57 2012 -0800
     8.2 +++ b/src/Structures.h	Mon Dec 24 02:49:20 2012 -0800
     8.3 @@ -158,6 +158,8 @@
     8.4    public:
     8.5      static Struct *New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
     8.6  
     8.7 +    static bool Copy(Zone *zone, Handle<Struct> dest, Handle<Struct> src);
     8.8 +
     8.9      size_t objSize() {
    8.10          return sizeof(Struct) + map()->structureSize();
    8.11      }
    8.12 @@ -169,11 +171,12 @@
    8.13          return reinterpret_cast<Address>(this) + offsetOfSlotOffset(desc->offset());
    8.14      }
    8.15  
    8.16 -    // This must NOT be used with any Object * type!
    8.17      template <typename T> T get(Descriptor *desc) {
    8.18          return *reinterpret_cast<T *>(ref(desc));
    8.19      }
    8.20  
    8.21 +    // This must NOT be used with any Object * type!
    8.22 +    // :TODO: prevent with type system
    8.23      template <typename T> void set(Descriptor *desc, const T &t) {
    8.24          *reinterpret_cast<T *>(ref(desc)) = t;
    8.25      }
     9.1 --- a/src/TypeManager.cpp	Sat Dec 22 23:18:57 2012 -0800
     9.2 +++ b/src/TypeManager.cpp	Mon Dec 24 02:49:20 2012 -0800
     9.3 @@ -53,6 +53,8 @@
     9.4          return false;
     9.5      if ((primitiveTypes_[PrimitiveType_Bool] = Type::NewPrimitive(zone_, PrimitiveType_Bool)) == NULL)
     9.6          return false;
     9.7 +    if ((primitiveTypes_[PrimitiveType_String] = Type::NewPrimitive(zone_, PrimitiveType_String)) == NULL)
     9.8 +        return false;
     9.9  
    9.10      Local<Type> type(zone_);
    9.11      for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
    10.1 --- a/src/Types.h	Sat Dec 22 23:18:57 2012 -0800
    10.2 +++ b/src/Types.h	Mon Dec 24 02:49:20 2012 -0800
    10.3 @@ -57,6 +57,9 @@
    10.4      // on 64-bit systems), and does not exist in language semantics.
    10.5      PrimitiveType_Native,
    10.6  
    10.7 +    // Internal string object.
    10.8 +    PrimitiveType_String,
    10.9 +
   10.10      PrimitiveTypes_Total
   10.11  };
   10.12  
   10.13 @@ -144,7 +147,7 @@
   10.14          return primitive_;
   10.15      }
   10.16      bool isPod() {
   10.17 -        return isPrimitive() || isEnum() || isUnchecked();
   10.18 +        return (isPrimitive() && !isString()) || isEnum() || isUnchecked();
   10.19      }
   10.20      PrimitiveType pod() {
   10.21          assert(isPod());
   10.22 @@ -169,11 +172,18 @@
   10.23      bool isBool() {
   10.24          return isPrimitive() && primitive() == PrimitiveType_Bool;
   10.25      }
   10.26 +    bool isString() {
   10.27 +        return isPrimitive() && primitive() == PrimitiveType_String;
   10.28 +    }
   10.29      bool isExternalArray() {
   10.30          return kind() == EXTERNAL_ARRAY;
   10.31      }
   10.32      bool isTraceable() {
   10.33 -        return !isPrimitive();
   10.34 +        return (isPrimitive() && primitive() == PrimitiveType_String) ||
   10.35 +               isReference() ||
   10.36 +               isArray() ||
   10.37 +               isStruct() ||
   10.38 +               isFunction();
   10.39      }
   10.40      bool isConst() {
   10.41          assert(isPrimitive() ||
   10.42 @@ -250,7 +260,6 @@
   10.43      static ArrayType *NewExternal(Zone *zone, Handle<Type> contained);
   10.44  
   10.45      Type *innermost() {
   10.46 -        assert(isArray());
   10.47          Type *temp = contained();
   10.48          while (temp->isArray())
   10.49              temp = ArrayType::cast(temp)->contained();
   10.50 @@ -261,7 +270,6 @@
   10.51          return contained_;
   10.52      }
   10.53      bool isFixedLength() {
   10.54 -        assert(isArray());
   10.55          return elements_ > 0;
   10.56      }
   10.57      bool isCharArray() {
   10.58 @@ -273,12 +281,9 @@
   10.59          return elements_;
   10.60      }
   10.61      unsigned levels() {
   10.62 -        assert(isArray());
   10.63          return levels_;
   10.64      }
   10.65      bool hasInlineElements() {
   10.66 -        assert(isArray());
   10.67 -
   10.68          // We don't allocate traceable elements inline, since there's no
   10.69          // point to the optimization; we're going to be allocating lots of
   10.70          // objects anyway (in theory).
    11.1 --- a/src/compiler/AST.h	Sat Dec 22 23:18:57 2012 -0800
    11.2 +++ b/src/compiler/AST.h	Mon Dec 24 02:49:20 2012 -0800
    11.3 @@ -332,18 +332,18 @@
    11.4  
    11.5  class StringLiteral : public Expression
    11.6  {
    11.7 -    ScopedRoot<ByteArray> string_;
    11.8 +    ScopedRoot<String> string_;
    11.9  
   11.10    public:
   11.11 -    StringLiteral(const SourcePosition &pos, ByteArray *array)
   11.12 +    StringLiteral(const SourcePosition &pos, String *string)
   11.13        : Expression(pos),
   11.14 -        string_(array)
   11.15 +        string_(string)
   11.16      {
   11.17      }
   11.18  
   11.19      DECLARE_NODE(StringLiteral);
   11.20  
   11.21 -    ByteArray *string() const {
   11.22 +    String *string() const {
   11.23          return string_;
   11.24      }
   11.25  };
    12.1 --- a/src/compiler/BytecodeEmitter.h	Sat Dec 22 23:18:57 2012 -0800
    12.2 +++ b/src/compiler/BytecodeEmitter.h	Mon Dec 24 02:49:20 2012 -0800
    12.3 @@ -188,9 +188,10 @@
    12.4              maxStackDepth_ = oopMap_.length();
    12.5      }
    12.6      void writeObject(Object *obj) {
    12.7 +        assert(obj);
    12.8 +
    12.9          writeUint32(objects_.length());
   12.10 -        ScopedRoot<Object> root(obj);
   12.11 -        if (!objects_.append(root))
   12.12 +        if (!objects_.append(obj))
   12.13              oom_ = true;
   12.14      }
   12.15  
   12.16 @@ -528,11 +529,17 @@
   12.17          }
   12.18      }
   12.19      void object(Handle<Object> obj) {
   12.20 +        assert(obj);
   12.21 +
   12.22          ensure(OP_OBJECT_LENGTH);
   12.23          writeOp(OP_OBJECT);
   12.24          writeObject(obj);
   12.25          markOop(1);
   12.26      }
   12.27 +    void duparray() {
   12.28 +        singleByteOp(OP_DUPARRAY);
   12.29 +        markOop(1);
   12.30 +    }
   12.31      void copyarray() {
   12.32          singleByteOp(OP_COPYARRAY);
   12.33          markOop(1);
    13.1 --- a/src/compiler/HIR.cpp	Sat Dec 22 23:18:57 2012 -0800
    13.2 +++ b/src/compiler/HIR.cpp	Mon Dec 24 02:49:20 2012 -0800
    13.3 @@ -19,6 +19,7 @@
    13.4  #include "AST.h"
    13.5  #include "HIR.h"
    13.6  #include "BytecodeEmitter.h"
    13.7 +#include "../Strings.h"
    13.8  #include "../Heap-inl.h"
    13.9  #include "../Handles-inl.h"
   13.10  
   13.11 @@ -39,6 +40,7 @@
   13.12  
   13.13      void visitFloat(HFloat *hir);
   13.14      void visitInteger(HInteger *hir);
   13.15 +    void visitArray(HArray *hir);
   13.16      void visitCall(HCall *call);
   13.17      void visitStore(HStore *store);
   13.18      void visitBinary(HBinary *binary);
   13.19 @@ -69,6 +71,18 @@
   13.20  }
   13.21  
   13.22  void
   13.23 +HIRTranslator::visitArray(HArray *hir)
   13.24 +{
   13.25 +    __ object(hir->array());
   13.26 +
   13.27 +    if (!hir->type()->isConst()) {
   13.28 +        // If the type isn't const, we have to assume a consumer may modify
   13.29 +        // the array, and therefore we have to duplicate it here.
   13.30 +        __ duparray(); 
   13.31 +    }
   13.32 +}
   13.33 +
   13.34 +void
   13.35  HIRTranslator::visitCall(HCall *call)
   13.36  {
   13.37      Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
    14.1 --- a/src/compiler/HIR.h	Sat Dec 22 23:18:57 2012 -0800
    14.2 +++ b/src/compiler/HIR.h	Mon Dec 24 02:49:20 2012 -0800
    14.3 @@ -29,6 +29,8 @@
    14.4      _(Call)                             \
    14.5      _(Integer)                          \
    14.6      _(Float)                            \
    14.7 +    _(String)                           \
    14.8 +    _(Array)                            \
    14.9      _(Store)                            \
   14.10      _(ToRef)                            \
   14.11      /* Special LValue types */          \
   14.12 @@ -48,6 +50,7 @@
   14.13  class HIRVisitor;
   14.14  class AstNode;
   14.15  class HLValue;
   14.16 +class Array;
   14.17  
   14.18  class HIR : public PoolObject
   14.19  {
   14.20 @@ -142,6 +145,42 @@
   14.21      int value_;
   14.22  };
   14.23  
   14.24 +class HString : public HIR
   14.25 +{
   14.26 +  public:
   14.27 +    HString(AstNode *node, Type *type, String *string)
   14.28 +      : HIR(node, type),
   14.29 +        string_(string)
   14.30 +    {
   14.31 +    }
   14.32 +
   14.33 +    DEFINE_HIR(String);
   14.34 +    Handle<String> string() const {
   14.35 +        return string_;
   14.36 +    }
   14.37 +
   14.38 +  private:
   14.39 +    ScopedRoot<String> string_;
   14.40 +};
   14.41 +
   14.42 +class HArray : public HIR
   14.43 +{
   14.44 +  public:
   14.45 +    HArray(AstNode *node, Type *type, Array *array)
   14.46 +      : HIR(node, type),
   14.47 +        array_(array)
   14.48 +    {
   14.49 +    }
   14.50 +
   14.51 +    DEFINE_HIR(Array);
   14.52 +    Handle<Array> array() const {
   14.53 +        return array_;
   14.54 +    }
   14.55 +
   14.56 +  private:
   14.57 +    ScopedRoot<Array> array_;
   14.58 +};
   14.59 +
   14.60  class HConvert : public HIR
   14.61  {
   14.62    public:
    15.1 --- a/src/compiler/Parser.cpp	Sat Dec 22 23:18:57 2012 -0800
    15.2 +++ b/src/compiler/Parser.cpp	Mon Dec 24 02:49:20 2012 -0800
    15.3 @@ -122,11 +122,8 @@
    15.4        case TOK_STRING_LITERAL:
    15.5        {
    15.6          scanner_.scan();
    15.7 -        Local<ByteArray> array(zone_, ByteArray::New(zone_, scanner_.literal_length() + 1));
    15.8 -        if (!array)
    15.9 -            return NULL;
   15.10 -        memcpy(array->raw(), scanner_.literal(), scanner_.literal_length() + 1);
   15.11 -        return new (pool_) StringLiteral(scanner_.begin(), array);
   15.12 +        Local<String> string(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
   15.13 +        return new (pool_) StringLiteral(scanner_.begin(), string);
   15.14        }
   15.15  
   15.16        default:
    16.1 --- a/src/compiler/SemanticAnalysis.cpp	Sat Dec 22 23:18:57 2012 -0800
    16.2 +++ b/src/compiler/SemanticAnalysis.cpp	Mon Dec 24 02:49:20 2012 -0800
    16.3 @@ -429,31 +429,31 @@
    16.4      PoolScope poolScope(zone_->pool());
    16.5      RootScope rootScope(zone_);
    16.6  
    16.7 +    Local<Type> type(zone_, node->sym()->type());
    16.8 +
    16.9      if (node->initialization()) {
   16.10          HIR *hir = NULL;
   16.11  
   16.12          if ((hir = eval(node->initialization())) == NULL)
   16.13              return;
   16.14 -        if ((hir = coerce(hir, node->sym()->type(), Coerce_Assign)) == NULL)
   16.15 +        if ((hir = coerce(hir, type, Coerce_Assign)) == NULL)
   16.16              return;
   16.17  
   16.18          discharge(hir);
   16.19      } else {
   16.20 -        if (node->sym()->type()->isInt32() ||
   16.21 -            node->sym()->type()->isEnum() ||
   16.22 -            node->sym()->type()->isChar() ||
   16.23 -            node->sym()->type()->isBool())
   16.24 +        if (type->isInt32() || type->isEnum() ||
   16.25 +            type->isChar() || type->isBool())
   16.26          {
   16.27              __ int_(0);
   16.28 -        } else if (node->sym()->type()->isFloat()) {
   16.29 +        } else if (type->isFloat()) {
   16.30              __ float_(0);
   16.31 -        } else if (node->sym()->type()->isArray()) {
   16.32 -            Local<ArrayType> type(zone_, ArrayType::cast(node->sym()->type()));
   16.33 -            Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
   16.34 +        } else if (type->isArray()) {
   16.35 +            Local<ArrayType> atype(zone_, ArrayType::cast(type));
   16.36 +            Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, atype));
   16.37              if (!map)
   16.38                  return;
   16.39  
   16.40 -            if (type->isFixedLength()) {
   16.41 +            if (atype->isFixedLength()) {
   16.42                  __ newarray(OP_NEWFIXED, map, InferTenure(node->sym()));
   16.43              } else if (node->dims()) {
   16.44                  assert(false);
   16.45 @@ -461,11 +461,15 @@
   16.46              } else {
   16.47                  __ newarray(OP_NEWEMPTY, map, InferTenure(node->sym()));
   16.48              }
   16.49 +        } else {
   16.50 +            assert(false);
   16.51          }
   16.52      }
   16.53  
   16.54 -    if (!__ allocate(node->sym()))
   16.55 -        return;
   16.56 +    if (node->sym()->scope()->kind() != Scope::GLOBAL) {
   16.57 +        if (!__ allocate(node->sym()))
   16.58 +            return;
   16.59 +    }
   16.60  
   16.61      set(node->sym());
   16.62      __ pop();
   16.63 @@ -613,6 +617,13 @@
   16.64  }
   16.65  
   16.66  void
   16.67 +SemanticAnalysis::visitStringLiteral(StringLiteral *node)
   16.68 +{
   16.69 +    Type *type = zone_->types()->getPrimitive(PrimitiveType_String);
   16.70 +    hir_ = new (pool_) HString(node, type, node->string());
   16.71 +}
   16.72 +
   16.73 +void
   16.74  SemanticAnalysis::visitCallExpression(CallExpression *node)
   16.75  {
   16.76      HIR *callee = eval(node->callee());
   16.77 @@ -804,15 +815,55 @@
   16.78      return left->type();
   16.79  }
   16.80  
   16.81 -bool
   16.82 +HIR *
   16.83  SemanticAnalysis::typeCheckArray(const SourcePosition &pos,
   16.84 -                                 Handle<Type> argGiven,
   16.85 +                                 HIR *from,
   16.86                                   Handle<Type> argActual,
   16.87                                   CoercionKind kind)
   16.88  {
   16.89 +    Local<Type> argGiven(zone_, from->type());
   16.90 +
   16.91 +    // Special case: if we receive a string literal, and this is a char array,
   16.92 +    // we allow a coercion.
   16.93 +    if (from->isString() &&
   16.94 +        argGiven->isString() &&
   16.95 +        argActual->isArray() &&
   16.96 +        ArrayType::cast(argActual)->isCharArray())
   16.97 +    {
   16.98 +        HString *hir = from->toString();
   16.99 +        Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
  16.100 +
  16.101 +        // If assigning or returning, and the desired type is fixed length,
  16.102 +        // make sure there is enough room.
  16.103 +        if ((kind == Coerce_Return || kind == Coerce_Assign) && actual->isFixedLength()) {
  16.104 +            if (hir->string()->length() + 1 > actual->fixedLength()) {
  16.105 +                cc_.reportError(pos, Message_ArrayAssignmentTooBig);
  16.106 +                return NULL;
  16.107 +            }
  16.108 +        }
  16.109 +
  16.110 +        // Transform the string literal into an array literal. We give it the
  16.111 +        // type of the left-hand side. The constness of the destination type
  16.112 +        // will determine whether HArray duplicates it or not.
  16.113 +        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, actual));
  16.114 +        if (!map)
  16.115 +            return NULL;
  16.116 +
  16.117 +        Local<Array> array(zone_);
  16.118 +        array = Array::NewString(zone_,
  16.119 +                                 map,
  16.120 +                                 hir->string()->chars(),
  16.121 +                                 hir->string()->length(),
  16.122 +                                 Heap::Tenure_Old);
  16.123 +        if (!array)
  16.124 +            return NULL;
  16.125 +
  16.126 +        return new (pool_) HArray(hir->node(), actual, array);
  16.127 +    }
  16.128 +
  16.129      if (!argGiven->isArray()) {
  16.130          cc_.reportError(pos, Message_ExpectedArray);
  16.131 -        return false;
  16.132 +        return NULL;
  16.133      }
  16.134  
  16.135      Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
  16.136 @@ -820,7 +871,7 @@
  16.137  
  16.138      if (actual->levels() != given->levels()) {
  16.139          cc_.reportError(pos, Message_ArrayDimensionsMismatch);
  16.140 -        return false;
  16.141 +        return NULL;
  16.142      }
  16.143  
  16.144      unsigned level = 1;
  16.145 @@ -829,19 +880,19 @@
  16.146              if (kind == Coerce_Return || kind == Coerce_Assign) {
  16.147                  if (!given->isFixedLength()) {
  16.148                      cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
  16.149 -                    return false;
  16.150 +                    return NULL;
  16.151                  }
  16.152  
  16.153                  if (actual->isCharArray()) {
  16.154                      // String assignment can have a truncated |given|.
  16.155                      if (given->fixedLength() > actual->fixedLength()) {
  16.156                          cc_.reportError(pos, Message_ArrayAssignmentTooBig);
  16.157 -                        return false;
  16.158 +                        return NULL;
  16.159                      }
  16.160                  } else {
  16.161                      if (given->fixedLength() != actual->fixedLength()) {
  16.162                          cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
  16.163 -                        return false;
  16.164 +                        return NULL;
  16.165                      }
  16.166                  }
  16.167              }
  16.168 @@ -863,7 +914,7 @@
  16.169              // Now |x[0]| contains a 3-length array.
  16.170              if (level > 1) {
  16.171                  cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
  16.172 -                return false;
  16.173 +                return NULL;
  16.174              }
  16.175          }
  16.176  
  16.177 @@ -882,7 +933,7 @@
  16.178          return false;
  16.179      }
  16.180  
  16.181 -    return true;
  16.182 +    return from;
  16.183  }
  16.184  
  16.185  HIR *
  16.186 @@ -897,21 +948,18 @@
  16.187  HIR *
  16.188  SemanticAnalysis::coerce(HIR *hir, Handle<Type> to, CoercionKind kind)
  16.189  {
  16.190 -    Handle<Type> from = hir->type();
  16.191 +    Local<Type> from(zone_, hir->type());
  16.192  
  16.193      if (from->isInt32() && to->isFloat())
  16.194          return new (pool_) HConvert(hir->node(), to, OP_CVT_I2F, hir);
  16.195      if (from->isInt32() && to->isBool())
  16.196          return new (pool_) HConvert(hir->node(), to, OP_CVT_I2B, hir);
  16.197  
  16.198 -    if (to->isEnum() && from != to)
  16.199 +    if (to->isEnum() && *from != to)
  16.200          return typeFailure(hir->node()->pos(), from, to);
  16.201      
  16.202 -    if (to->isArray()) {
  16.203 -        if (!typeCheckArray(SourcePosition(), from, to, kind))
  16.204 -            return NULL;
  16.205 -        return hir;
  16.206 -    }
  16.207 +    if (to->isArray())
  16.208 +        return typeCheckArray(SourcePosition(), hir, to, kind);
  16.209      
  16.210      return hir;
  16.211  }
  16.212 @@ -1003,7 +1051,7 @@
  16.213              hir = eval(expr->toUnaryExpression()->expression());
  16.214          if (!hir)
  16.215              return;
  16.216 -        if ((hir = coerce(hir, boolType, Coerce_Assign)) == NULL)
  16.217 +        if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
  16.218              return;
  16.219  
  16.220          discharge(hir);
  16.221 @@ -1033,7 +1081,7 @@
  16.222      HIR *hir = binary(bin, bin->token(), left, right);
  16.223      if (!hir)
  16.224          return;
  16.225 -    if ((hir = coerce(hir, boolType, Coerce_Assign)) == NULL)
  16.226 +    if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
  16.227          return;
  16.228  
  16.229      discharge(hir);
    17.1 --- a/src/compiler/SemanticAnalysis.h	Sat Dec 22 23:18:57 2012 -0800
    17.2 +++ b/src/compiler/SemanticAnalysis.h	Mon Dec 24 02:49:20 2012 -0800
    17.3 @@ -64,13 +64,13 @@
    17.4      void visitIfStatement(IfStatement *node);
    17.5      void visitIndexExpression(IndexExpression *node);
    17.6      void visitIncDecExpression(IncDecExpression *node);
    17.7 +    void visitStringLiteral(StringLiteral *node);
    17.8  #if 0
    17.9      void visitFunctionTypeStatement(FunctionTypeStatement *node);
   17.10      void visitImportStatement(ImportStatement *node);
   17.11      void visitStructureStatement(StructureStatement *node);
   17.12      void visitSwitchStatement(SwitchStatement *node);
   17.13  
   17.14 -    void visitStringLiteral(StringLiteral *node);
   17.15      void visitUnaryExpression(UnaryExpression *node);
   17.16      void visitTernaryExpression(TernaryExpression *node);
   17.17      void visitBooleanLiteral(BooleanLiteral *node);
   17.18 @@ -180,8 +180,8 @@
   17.19      void discharge(HIR *hir);
   17.20      HIR *typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to);
   17.21  
   17.22 -    bool typeCheckArray(const SourcePosition &pos,
   17.23 -                        Handle<Type> argGiven,
   17.24 +    HIR *typeCheckArray(const SourcePosition &pos,
   17.25 +                        HIR *from,
   17.26                          Handle<Type> argActual,
   17.27                          CoercionKind kind);
   17.28  
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tests/basic/string-lit-1.out	Mon Dec 24 02:49:20 2012 -0800
    18.3 @@ -0,0 +1,1 @@
    18.4 +101121
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tests/basic/string-lit-1.sp	Mon Dec 24 02:49:20 2012 -0800
    19.3 @@ -0,0 +1,9 @@
    19.4 +native PrintNum(num);
    19.5 +
    19.6 +public main()
    19.7 +{
    19.8 +    new char:str1[] = "hello";
    19.9 +    new char:str2[4] = "bye";
   19.10 +    PrintNum(str1[1]);
   19.11 +    PrintNum(str2[1]);
   19.12 +}