Implement dependent char arrays.
authorDavid Anderson <dvander@alliedmods.net>
Fri Dec 28 17:13:51 2012 -0800 (2012-12-28)
changeset 2477721042bdb67
parent 246 f9c4371d59d4
child 248 372adeda3b22
Implement dependent char arrays.
src/Array.cpp
src/Array.h
src/Interpreter.cpp
src/ObjectVisitor.h
src/Objects.h
src/Opcodes.cpp
src/Opcodes.tbl
src/TypeManager.cpp
src/Types.h
src/compiler/AST.h
src/compiler/BytecodeEmitter.h
src/compiler/HIR.cpp
src/compiler/HIR.h
src/compiler/NameBinding.cpp
src/compiler/Parser.cpp
src/compiler/SemanticAnalysis.cpp
tests/basic/dependent-strings.out
tests/basic/dependent-strings.sp
     1.1 --- a/src/Array.cpp	Thu Dec 27 21:07:03 2012 -0800
     1.2 +++ b/src/Array.cpp	Fri Dec 28 17:13:51 2012 -0800
     1.3 @@ -39,6 +39,18 @@
     1.4  }
     1.5  
     1.6  ArrayMap *
     1.7 +ArrayMap::NewDependent(Zone *zone, Handle<ArrayType> type)
     1.8 +{
     1.9 +    Local<Map> obj(zone, zone->allocateMap(MapKind_DependentArray, sizeof(ArrayMap), MapKind_MetaArray));
    1.10 +    if (!obj)
    1.11 +        return NULL;
    1.12 +
    1.13 +    Local<ArrayMap> map(zone, ArrayMap::cast(obj));
    1.14 +    map->type_ = type;
    1.15 +    return map;
    1.16 +}
    1.17 +
    1.18 +ArrayMap *
    1.19  ArrayMap::Attach(Zone *zone, Handle<ArrayType> type)
    1.20  {
    1.21      if (type->newMap())
    1.22 @@ -339,3 +351,49 @@
    1.23  
    1.24      return dest;
    1.25  }
    1.26 +
    1.27 +Array *
    1.28 +DependentArray::New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index)
    1.29 +{
    1.30 +    Local<ArrayType> sourcetype(zone, source->type());
    1.31 +
    1.32 +    // Right now we only support char arrays, to avoid nasty deep cloning
    1.33 +    // and to maybe cut off this feature as far as we can.
    1.34 +    assert(sourcetype->isCharArray());
    1.35 +    assert(map->type()->isCharArray());
    1.36 +
    1.37 +    // We allow taking 0-length dependent strings. It's safe because any reads
    1.38 +    // or writes will fail.
    1.39 +    assert(index <= source->length());
    1.40 +
    1.41 +    unsigned newlen = source->length() - index;
    1.42 +    unsigned eltsize = SizeForElement(sourcetype);
    1.43 +    
    1.44 +    if (!sourcetype->isFixedLength()) {
    1.45 +        // Simple case, just copy the array.
    1.46 +        Local<ArrayMap> map(zone, sourcetype->newMap());
    1.47 +        
    1.48 +        Local<Array> dest(zone, Array::NewRaw(zone, map, newlen, Heap::Tenure_Default));
    1.49 +        if (!dest)
    1.50 +            return NULL;
    1.51 +
    1.52 +        memcpy(dest->bytes(),
    1.53 +               (Address)source->bytes() + (index * eltsize),
    1.54 +               newlen * eltsize);
    1.55 +        return dest;
    1.56 +    }
    1.57 +
    1.58 +    Local<DependentArray> array(zone, DependentArray::cast(zone->allocate(map, sizeof(DependentArray), Heap::Tenure_Default)));
    1.59 +    if (!array)
    1.60 +        return NULL;
    1.61 +
    1.62 +    // :GC: This is currently not safe for moving GC! Although we will mark
    1.63 +    // the object owning the interior pointer, the interior pointer could be
    1.64 +    // moved later. We will eventually need some way of dealing with this.
    1.65 +    Address elements = Address(source->bytes()) + (index * eltsize);
    1.66 +
    1.67 +    array->root_ = source;
    1.68 +    array->length_ = newlen;
    1.69 +    array->elements_ = elements - ByteArray::offsetToElements();
    1.70 +    return array;
    1.71 +}
     2.1 --- a/src/Array.h	Thu Dec 27 21:07:03 2012 -0800
     2.2 +++ b/src/Array.h	Fri Dec 28 17:13:51 2012 -0800
     2.3 @@ -32,6 +32,7 @@
     2.4  {
     2.5      friend class ArrayMap;
     2.6  
     2.7 +  protected:
     2.8      // Note: we do not write barrier |elements_|, since it can be set to
     2.9      // arbitrary pointers.
    2.10      uint32 length_;
    2.11 @@ -40,7 +41,7 @@
    2.12          Object *objelements_;
    2.13      };
    2.14  
    2.15 -  private:
    2.16 +  protected:
    2.17      void updateLengthAndElements(Zone *zone, unsigned length, Object *array) {
    2.18          length_ = length;
    2.19          write(zone, &objelements_, array);
    2.20 @@ -134,19 +135,50 @@
    2.21      // End GC Descriptor.
    2.22  
    2.23      static Array *cast(Object *obj) {
    2.24 -        assert(!obj || obj->is(MapKind_Array));
    2.25 +        assert(!obj ||
    2.26 +               obj->is(MapKind_Array) ||
    2.27 +               obj->is(MapKind_DependentArray));
    2.28          return reinterpret_cast<Array *>(obj);
    2.29      }
    2.30  };
    2.31  
    2.32 +class DependentArray : public Array
    2.33 +{
    2.34 +    Barriered<Array> root_;
    2.35 +
    2.36 +  public:
    2.37 +    static Array *New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index);
    2.38 +
    2.39 +    // GC Descriptor.
    2.40 +    static inline size_t offsetOfRoot() {
    2.41 +        return offsetof(DependentArray, root_);
    2.42 +    }
    2.43 +    // End GC Descriptor.
    2.44 +
    2.45 +    static DependentArray *cast(Object *obj) {
    2.46 +        assert(!obj || obj->is(MapKind_DependentArray));
    2.47 +        return reinterpret_cast<DependentArray *>(obj);
    2.48 +    }
    2.49 +};
    2.50 +
    2.51  class ArrayMap : public Map
    2.52  {
    2.53      Barriered<ArrayType> type_;
    2.54  
    2.55    public:
    2.56 +    // The way array maps work is kind of clownshoes. In the future, these
    2.57 +    // should be created immediately (or lazily) on the Type directly, and not
    2.58 +    // manually created via ::Attach. :TODO: do this when we begin caching
    2.59 +    // array types.
    2.60      static ArrayMap *New(Zone *zone, Handle<ArrayType> type);
    2.61      static ArrayMap *Attach(Zone *zone, Handle<ArrayType> type);
    2.62  
    2.63 +    // DependentArray maps are never attached, and are just free-floating,
    2.64 +    // rooted ultimately by the bytecode. A :TODO: that we might need to
    2.65 +    // cache these, or attach them somewhere saner like ArrayType, which
    2.66 +    // itself will eventually be cached.
    2.67 +    static ArrayMap *NewDependent(Zone *zone, Handle<ArrayType> type);
    2.68 +
    2.69      ArrayType *type() {
    2.70          return type_;
    2.71      }
    2.72 @@ -169,6 +201,7 @@
    2.73      assert(!type()->contained()->isTraceable());
    2.74      assert(type()->hasInlineElements() ||
    2.75             type()->isExternalArray() ||
    2.76 +           is(MapKind_DependentArray) ||
    2.77             !length() ||
    2.78             ByteArray::cast((Object *)elements_));
    2.79  
     3.1 --- a/src/Interpreter.cpp	Thu Dec 27 21:07:03 2012 -0800
     3.2 +++ b/src/Interpreter.cpp	Fri Dec 28 17:13:51 2012 -0800
     3.3 @@ -986,6 +986,26 @@
     3.4      break;
     3.5  }
     3.6  
     3.7 +case OP_DEPARRAY:
     3.8 +{
     3.9 +    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->object(READ_UINT32(top.pc))));
    3.10 +    Local<Array> array(zone, Array::cast(top.sp[-2].obj));
    3.11 +    int index = top.sp[-1].i32;
    3.12 +
    3.13 +    // We allow taking 0-length dependent arrays.
    3.14 +    if (index < 0 || unsigned(index) > array->length()) {
    3.15 +        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
    3.16 +        goto error;
    3.17 +    }
    3.18 +
    3.19 +    top.sp[-2].obj = DependentArray::New(zone, array, map, index);
    3.20 +    if (!top.sp[-2].obj)
    3.21 +        goto error;
    3.22 +
    3.23 +    top.sp--;
    3.24 +    break;
    3.25 +}
    3.26 +
    3.27  default:
    3.28      assert(false);
    3.29      return false;
     4.1 --- a/src/ObjectVisitor.h	Thu Dec 27 21:07:03 2012 -0800
     4.2 +++ b/src/ObjectVisitor.h	Fri Dec 28 17:13:51 2012 -0800
     4.3 @@ -148,6 +148,11 @@
     4.4          return array->objSize(map);
     4.5      }
     4.6  
     4.7 +    size_t iterateDependentArray(Object *array) {
     4.8 +        visitField(array, DependentArray::offsetOfRoot());
     4.9 +        return sizeof(DependentArray);
    4.10 +    }
    4.11 +
    4.12      size_t iterateBox(Box *obj) {
    4.13          visitField(obj, Box::offsetOfType());
    4.14          if (obj->type()->isTraceable())
    4.15 @@ -248,7 +253,10 @@
    4.16              return iterateString(obj);
    4.17  
    4.18            case MapKind_Array:
    4.19 -            return Align(iterateArray(Array::cast(obj), ArrayMap::cast(map)), kObjectAlignment);
    4.20 +            return iterateArray(Array::cast(obj), ArrayMap::cast(map));
    4.21 +
    4.22 +          case MapKind_DependentArray:
    4.23 +            return iterateDependentArray(obj);
    4.24  
    4.25            case MapKind_Box:
    4.26              return iterateBox(Box::cast(obj));
    4.27 @@ -340,7 +348,10 @@
    4.28          return sizeof(Native);
    4.29  
    4.30        case MapKind_Array:
    4.31 -        return Align(Array::cast(obj)->objSize(ArrayMap::cast(map)), kObjectAlignment);
    4.32 +        return Array::cast(obj)->objSize(ArrayMap::cast(map));
    4.33 +
    4.34 +       case MapKind_DependentArray:
    4.35 +        return sizeof(DependentArray), kObjectAlignment;
    4.36  
    4.37        case MapKind_Box:
    4.38          return sizeof(Box);
     5.1 --- a/src/Objects.h	Thu Dec 27 21:07:03 2012 -0800
     5.2 +++ b/src/Objects.h	Fri Dec 28 17:13:51 2012 -0800
     5.3 @@ -60,6 +60,7 @@
     5.4  
     5.5      // These do not have canonical maps.
     5.6      MapKind_Array,
     5.7 +    MapKind_DependentArray,
     5.8      MapKind_Struct,
     5.9  
    5.10      // These represent special Map subclasses that require special tracing.
     6.1 --- a/src/Opcodes.cpp	Thu Dec 27 21:07:03 2012 -0800
     6.2 +++ b/src/Opcodes.cpp	Fri Dec 28 17:13:51 2012 -0800
     6.3 @@ -210,6 +210,7 @@
     6.4            case OP_PUBLIC:
     6.5            case OP_LEAVELOOP:
     6.6            case OP_DUPARRAY:
     6.7 +          case OP_DEPARRAY:
     6.8              break;
     6.9  
    6.10            case OP_ENTERLOOP:
     7.1 --- a/src/Opcodes.tbl	Thu Dec 27 21:07:03 2012 -0800
     7.2 +++ b/src/Opcodes.tbl	Fri Dec 28 17:13:51 2012 -0800
     7.3 @@ -259,4 +259,10 @@
     7.4  //
     7.5  // If the second byte to ENTERLOOP is 0, then no LIFO region is needed.
     7.6  OPDEF(OP_ENTERLOOP,     "enterloop",    2,      0, 0)
     7.7 -OPDEF(OP_LEAVELOOP,     "leaveloop",    1,      0, 0)
     7.8 \ No newline at end of file
     7.9 +OPDEF(OP_LEAVELOOP,     "leaveloop",    1,      0, 0)
    7.10 +
    7.11 +// Create a new dependent array. The type to use is encoded as an index.
    7.12 +//  index = POP()
    7.13 +//  base = POP()
    7.14 +//  PUSH(array)
    7.15 +OPDEF(OP_DEPARRAY,      "deparray",     5,      2, 1)
    7.16 \ No newline at end of file
     8.1 --- a/src/TypeManager.cpp	Thu Dec 27 21:07:03 2012 -0800
     8.2 +++ b/src/TypeManager.cpp	Fri Dec 28 17:13:51 2012 -0800
     8.3 @@ -2,19 +2,19 @@
     8.4   *
     8.5   * Copyright (C) 2012 David Anderson
     8.6   *
     8.7 - * This file is part of JITCraft.
     8.8 + * This file is part of SourcePawn.
     8.9   *
    8.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    8.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
    8.12   * the terms of the GNU General Public License as published by the Free
    8.13   * Software Foundation, either version 3 of the License, or (at your option)
    8.14   * any later version.
    8.15   * 
    8.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    8.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    8.18   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    8.19   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    8.20   *
    8.21   * You should have received a copy of the GNU General Public License along with
    8.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    8.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
    8.24   */
    8.25  #include <string.h>
    8.26  #include "Types.h"
     9.1 --- a/src/Types.h	Thu Dec 27 21:07:03 2012 -0800
     9.2 +++ b/src/Types.h	Fri Dec 28 17:13:51 2012 -0800
     9.3 @@ -297,6 +297,12 @@
     9.4          return temp;
     9.5      }
     9.6  
     9.7 +    bool isDynamic() {
     9.8 +        return elements_ == DYNAMIC_ARRAY_SIZE;
     9.9 +    }
    9.10 +    bool isExtensible() {
    9.11 +        return isDynamic() && !(quals_ & TypeQual_Const);
    9.12 +    }
    9.13      Type *contained() {
    9.14          return contained_;
    9.15      }
    9.16 @@ -435,6 +441,10 @@
    9.17          assert(isNative());
    9.18          return variadicNative_;
    9.19      }
    9.20 +    void setVariadic() {
    9.21 +        assert(isNative());
    9.22 +        variadicNative_ = true;
    9.23 +    }
    9.24      void setReturnType(Handle<Type> returnType) {
    9.25          assert(!returnType_);
    9.26          returnType_ = returnType;
    10.1 --- a/src/compiler/AST.h	Thu Dec 27 21:07:03 2012 -0800
    10.2 +++ b/src/compiler/AST.h	Fri Dec 28 17:13:51 2012 -0800
    10.3 @@ -708,12 +708,14 @@
    10.4  {
    10.5      StatementList *statements_;
    10.6      Scope *scope_;
    10.7 +    TokenKind type_;
    10.8  
    10.9    public:
   10.10 -    BlockStatement(const SourcePosition &pos, StatementList *statements)
   10.11 +    BlockStatement(const SourcePosition &pos, StatementList *statements, TokenKind kind)
   10.12        : Statement(pos),
   10.13          statements_(statements),
   10.14 -        scope_(NULL)
   10.15 +        scope_(NULL),
   10.16 +        type_(kind)
   10.17      {
   10.18      }
   10.19  
   10.20 @@ -728,6 +730,9 @@
   10.21      void setScope(Scope *scope) {
   10.22          scope_ = scope;
   10.23      }
   10.24 +    TokenKind type() const {
   10.25 +        return type_;
   10.26 +    }
   10.27  };
   10.28  
   10.29  typedef PoolList<Parameter *> ParameterList;
    11.1 --- a/src/compiler/BytecodeEmitter.h	Thu Dec 27 21:07:03 2012 -0800
    11.2 +++ b/src/compiler/BytecodeEmitter.h	Fri Dec 28 17:13:51 2012 -0800
    11.3 @@ -494,6 +494,13 @@
    11.4          writeObject(map);
    11.5          markOop(1);
    11.6      }
    11.7 +    void deparray(ArrayMap *map) {
    11.8 +        recordOops();
    11.9 +        ensure(OP_DEPARRAY_LENGTH);
   11.10 +        writeOp(OP_DEPARRAY);
   11.11 +        writeObject(map);
   11.12 +        markOop(1);
   11.13 +    }
   11.14      void savelifo(unsigned slot) {
   11.15          ensure(OP_SAVELIFO_LENGTH);
   11.16          writeOp(OP_SAVELIFO);
    12.1 --- a/src/compiler/HIR.cpp	Thu Dec 27 21:07:03 2012 -0800
    12.2 +++ b/src/compiler/HIR.cpp	Fri Dec 28 17:13:51 2012 -0800
    12.3 @@ -52,6 +52,7 @@
    12.4      void visitIndex(HIndex *index);
    12.5      void visitPostIncDec(HPostIncDec *hir);
    12.6      void visitToRef(HToRef *hir);
    12.7 +    void visitNewDependentArray(HNewDependentArray *hir);
    12.8  
    12.9    private:
   12.10      Zone *zone_;
   12.11 @@ -438,6 +439,10 @@
   12.12      unary->in()->accept(this);
   12.13  
   12.14      switch (unary->token()) {
   12.15 +      case TOK_TILDE:
   12.16 +        __ bitnot();
   12.17 +        break;
   12.18 +
   12.19        case TOK_MINUS:
   12.20          if (unary->type()->isFloat())
   12.21              __ neg_f();
   12.22 @@ -474,6 +479,27 @@
   12.23  }
   12.24  
   12.25  void
   12.26 +HIRTranslator::visitNewDependentArray(HNewDependentArray *hir)
   12.27 +{
   12.28 +    hir->base()->accept(this);
   12.29 +    hir->index()->accept(this);
   12.30 +
   12.31 +    Local<ArrayType> type(zone_, ArrayType::cast(hir->type()));
   12.32 +
   12.33 +    // Attach an actual map to the dependent type, in case it's a new
   12.34 +    // type.
   12.35 +    if (!ArrayMap::Attach(zone_, type))
   12.36 +        return;
   12.37 +
   12.38 +    // The dependent map is used for the opcode, but is not attached.
   12.39 +    Local<ArrayMap> map(zone_, ArrayMap::NewDependent(zone_, type));
   12.40 +    if (!map)
   12.41 +        return;
   12.42 +
   12.43 +    __ deparray(map);
   12.44 +}
   12.45 +
   12.46 +void
   12.47  ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
   12.48  {
   12.49      HIRTranslator translator(zone, emitter);
    13.1 --- a/src/compiler/HIR.h	Thu Dec 27 21:07:03 2012 -0800
    13.2 +++ b/src/compiler/HIR.h	Fri Dec 28 17:13:51 2012 -0800
    13.3 @@ -34,6 +34,7 @@
    13.4      _(Array)                            \
    13.5      _(Store)                            \
    13.6      _(ToRef)                            \
    13.7 +    _(NewDependentArray)                \
    13.8      /* Special LValue types */          \
    13.9      _(Index)                            \
   13.10      _(Local)                            \
   13.11 @@ -306,6 +307,13 @@
   13.12      void load(BytecodeEmitter &emitter_);
   13.13      bool ref(BytecodeEmitter &emitter_);
   13.14  
   13.15 +    HIR *base() const {
   13.16 +        return left_;
   13.17 +    }
   13.18 +    HIR *index() const {
   13.19 +        return right_;
   13.20 +    }
   13.21 +
   13.22    private:
   13.23      HIR *left_;
   13.24      HIR *right_;
   13.25 @@ -515,6 +523,30 @@
   13.26      HIR *in_;
   13.27  };
   13.28  
   13.29 +class HNewDependentArray : public HIR
   13.30 +{
   13.31 +  public:
   13.32 +    HNewDependentArray(AstNode *node, Type *type, HIR *base, HIR *index)
   13.33 +      : HIR(node, type),
   13.34 +        base_(base),
   13.35 +        index_(index)
   13.36 +    {
   13.37 +    }
   13.38 +
   13.39 +    DEFINE_HIR(NewDependentArray);
   13.40 +
   13.41 +    HIR *base() const {
   13.42 +        return base_;
   13.43 +    }
   13.44 +    HIR *index() const {
   13.45 +        return index_;
   13.46 +    }
   13.47 +
   13.48 +  private:
   13.49 +    HIR *base_;
   13.50 +    HIR *index_;
   13.51 +};
   13.52 +
   13.53  #undef DEFINE_HIR
   13.54  
   13.55  void EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir);
    14.1 --- a/src/compiler/NameBinding.cpp	Thu Dec 27 21:07:03 2012 -0800
    14.2 +++ b/src/compiler/NameBinding.cpp	Fri Dec 28 17:13:51 2012 -0800
    14.3 @@ -335,12 +335,26 @@
    14.4          node->setScope(env.scope());
    14.5      }
    14.6      void visitBlockStatement(BlockStatement *node) {
    14.7 -        SymbolEnv env(&env_);
    14.8 +        if (node->type() == TOK_NEW) {
    14.9 +            // Don't create a symbol environment for this block, since it
   14.10 +            // was created solely to house multiple variable decls.
   14.11 +            for (size_t i = 0; i < node->statements()->length(); i++)
   14.12 +                node->statements()->at(i)->accept(this);
   14.13 +        } else {
   14.14 +            assert(node->type() == TOK_LBRACE);
   14.15 +
   14.16 +            SymbolEnv env(&env_);
   14.17  
   14.18 -        for (size_t i = 0; i < node->statements()->length(); i++)
   14.19 -            node->statements()->at(i)->accept(this);
   14.20 +            for (size_t i = 0; i < node->statements()->length(); i++)
   14.21 +                node->statements()->at(i)->accept(this);
   14.22 +        
   14.23 +            if (node->type() == TOK_NEW) {
   14.24 +                assert(!env.scope());
   14.25 +                return;
   14.26 +            }
   14.27  
   14.28 -        node->setScope(env.scope());
   14.29 +            node->setScope(env.scope());
   14.30 +        }
   14.31      }
   14.32      void visitIntegerLiteral(IntegerLiteral *node) {
   14.33      }
   14.34 @@ -856,6 +870,9 @@
   14.35              fun->setReturnType(type);
   14.36          }
   14.37  
   14.38 +        if (sig.variadic())
   14.39 +            fun->setVariadic();
   14.40 +
   14.41          Local<FixedArray> params(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
   14.42          if (!params)
   14.43              return false;
    15.1 --- a/src/compiler/Parser.cpp	Thu Dec 27 21:07:03 2012 -0800
    15.2 +++ b/src/compiler/Parser.cpp	Fri Dec 28 17:13:51 2012 -0800
    15.3 @@ -920,7 +920,7 @@
    15.4      }
    15.5  
    15.6      // Create a fake-o block with no scope to create a statement list.
    15.7 -    return new (pool_) BlockStatement(decl->pos(), statements);
    15.8 +    return new (pool_) BlockStatement(decl->pos(), statements, TOK_NEW);
    15.9  }
   15.10  
   15.11  Statement *
   15.12 @@ -970,7 +970,7 @@
   15.13              return NULL;
   15.14      }
   15.15  
   15.16 -    BlockStatement *block = new (pool_) BlockStatement(pos, statements);
   15.17 +    BlockStatement *block = new (pool_) BlockStatement(pos, statements, TOK_LBRACE);
   15.18      return block;
   15.19  }
   15.20  
    16.1 --- a/src/compiler/SemanticAnalysis.cpp	Thu Dec 27 21:07:03 2012 -0800
    16.2 +++ b/src/compiler/SemanticAnalysis.cpp	Fri Dec 28 17:13:51 2012 -0800
    16.3 @@ -694,13 +694,66 @@
    16.4          } else {
    16.5              Local<Type> actual(zone_, fun->parameterAt(i));
    16.6  
    16.7 -            if (expression->isIndexExpression()) {
    16.8 -                // Temporarily disabled.
    16.9 -                assert(!actual->isArray());
   16.10 +
   16.11 +            if (expression->isIndexExpression() && arg->isIndex()) {
   16.12 +                // If the expression is the form x[y], and this produced a
   16.13 +                // normal array indexing operation, then we apply some 
   16.14 +                // special rules.
   16.15 +
   16.16                  if (actual->isReference()) {
   16.17 +                    // Disabled, since this doesn't have easily definable or
   16.18 +                    // sensible semantics with SP2 arrays, but we don't want
   16.19 +                    // to silently break SP1 semantics.
   16.20                      cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
   16.21                      return;
   16.22                  }
   16.23 +
   16.24 +                // As a special rule to account for SP1 semantics, we allow x[y]
   16.25 +                // to automatically compute a sliced, read-only array view if
   16.26 +                // the desired type is an array of one more dimension than x[y]
   16.27 +                // would return.
   16.28 +                //
   16.29 +                // As an additional restriction, this is only allowed for
   16.30 +                // one-level char arrays, to minimize potential issues until
   16.31 +                // we determine whether more compatibility is needed.
   16.32 +                //
   16.33 +                // Internally, for sanity, the dependent array operation does
   16.34 +                // not necessarily create a dependent array. For extensible
   16.35 +                // arrays, we instead create a duplicate arrary of just the
   16.36 +                // sliced portion, rather than deal with the complexity of the
   16.37 +                // source array being resized.
   16.38 +                //
   16.39 +                // Note that we don't really know whether a dependent array
   16.40 +                // will be dependent at compile-time, so the dependent type's
   16.41 +                // just inherits from the source.
   16.42 +                if (actual->isArray()) {
   16.43 +                    HIndex *index = arg->toIndex();
   16.44 +                    Local<ArrayType> basetype(zone_, ArrayType::cast(index->base()->type()));
   16.45 +                    Local<ArrayType> atype(zone_, ArrayType::cast(actual));
   16.46 +
   16.47 +                    if (atype->isCharArray() && basetype->isCharArray()) {
   16.48 +                        // There is no possible way this will type check, so
   16.49 +                        // it's safe to just try something completely
   16.50 +                        // different.
   16.51 +                        Local<Type> slicetype(zone_);
   16.52 +                        if (basetype->isFixedLength()) {
   16.53 +                            // If the base type is fixed length, we need to
   16.54 +                            // compute a new dynamic array type based on the
   16.55 +                            // fixed array's contents and qualifiers.
   16.56 +                            Local<Type> contained(zone_, basetype->contained());
   16.57 +                            slicetype = zone_->types()->newArray(contained, ArrayType::DYNAMIC_ARRAY_SIZE);
   16.58 +                            if (!slicetype)
   16.59 +                                return;
   16.60 +                            slicetype = zone_->types()->qualify(slicetype, basetype->quals());
   16.61 +                            if (!slicetype)
   16.62 +                                return;
   16.63 +                        } else {
   16.64 +                            slicetype = basetype;
   16.65 +                        }
   16.66 +                        arg = new (pool_) HNewDependentArray(expression, slicetype, index->base(), index->index());
   16.67 +                        given = arg->type();
   16.68 +                    }
   16.69 +                }
   16.70              }
   16.71  
   16.72              if (actual->isReference()) {
   16.73 @@ -830,10 +883,17 @@
   16.74  Type *
   16.75  SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right)
   16.76  {
   16.77 -    Handle<Type> l = left->type();
   16.78 -    Handle<Type> r = right->type();
   16.79 +    Local<Type> l(zone_, left->type());
   16.80 +    Local<Type> r(zone_, right->type());
   16.81  
   16.82 -    if (token >= TOK_PLUS && token <= TOK_SLASH) {
   16.83 +    if (l->isPod())
   16.84 +        l = l->unqualified();
   16.85 +    if (r->isPod())
   16.86 +        r = r->unqualified();
   16.87 +
   16.88 +    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
   16.89 +        (token >= TOK_EQUALS && token <= TOK_GE))
   16.90 +    {
   16.91          // We allow: [float|int32] + [float|int32]
   16.92          if (l->isFloat() && r->isInt32())
   16.93              return l;
   16.94 @@ -841,6 +901,11 @@
   16.95              return r;
   16.96          if (l->isInt32() && r->isInt32())
   16.97              return l;
   16.98 +
   16.99 +        if (l->isChar() && r->isInt32())
  16.100 +             return r;
  16.101 +        if (l->isInt32() && r->isChar())
  16.102 +            return l;
  16.103      }
  16.104  
  16.105      // :TODO: remove
  16.106 @@ -1097,23 +1162,36 @@
  16.107          return;
  16.108  
  16.109      switch (node->token()) {
  16.110 +      case TOK_TILDE:
  16.111 +      {
  16.112 +        if (!hir->type()->isInt32() && !hir->type()->isEnum()) {
  16.113 +            char name[255];
  16.114 +            cc_.reportError(node->pos(), Message_InvalidUnaryType,
  16.115 +                            "~",
  16.116 +                            GetTypeName(hir->type(), name, sizeof(name)));
  16.117 +        }
  16.118 +        Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
  16.119 +        hir_ = new (pool_) HUnary(node, hir->type(), TOK_TILDE, hir);
  16.120 +        return;
  16.121 +      }
  16.122 +
  16.123        case TOK_MINUS:
  16.124        {
  16.125 -          if (hir->type()->isInt32() || hir->type()->isEnum()) {
  16.126 -              Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
  16.127 -              hir_ = new (pool_) HUnary(node, type, TOK_MINUS, hir);
  16.128 -              return;
  16.129 -          }
  16.130 -          if (hir->type()->isFloat()) {
  16.131 -              hir_ = new (pool_) HUnary(node, hir->type(), TOK_MINUS, hir);
  16.132 -              return;
  16.133 -          }
  16.134 +        if (hir->type()->isInt32() || hir->type()->isEnum()) {
  16.135 +            Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
  16.136 +            hir_ = new (pool_) HUnary(node, type, TOK_MINUS, hir);
  16.137 +            return;
  16.138 +        }
  16.139 +        if (hir->type()->isFloat()) {
  16.140 +            hir_ = new (pool_) HUnary(node, hir->type(), TOK_MINUS, hir);
  16.141 +            return;
  16.142 +        }
  16.143  
  16.144 -          char name[255];
  16.145 -          cc_.reportError(node->pos(), Message_InvalidUnaryType,
  16.146 -                          "-",
  16.147 -                          GetTypeName(hir->type(), name, sizeof(name)));
  16.148 -          break;
  16.149 +        char name[255];
  16.150 +        cc_.reportError(node->pos(), Message_InvalidUnaryType,
  16.151 +                        "-",
  16.152 +                        GetTypeName(hir->type(), name, sizeof(name)));
  16.153 +        break;
  16.154        }
  16.155  
  16.156        default:
  16.157 @@ -1195,8 +1273,13 @@
  16.158  
  16.159      BinaryExpression *bin = expr->toBinaryExpression();
  16.160      if (token == TOK_AND || token == TOK_OR) {
  16.161 -        assert(false);
  16.162 -        //visitForLogicTest(expr, trueBranch, falseBranch, fallthrough);
  16.163 +        Label next;
  16.164 +        if (token == TOK_AND)
  16.165 +            visitForTest(bin->left(), &next, falseBranch, &next);
  16.166 +        else
  16.167 +            visitForTest(bin->left(), trueBranch, &next, &next);
  16.168 +        __ bind(&next);
  16.169 +        visitForTest(bin->right(), trueBranch, falseBranch, fallthrough);
  16.170          return;
  16.171      }
  16.172  
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/tests/basic/dependent-strings.out	Fri Dec 28 17:13:51 2012 -0800
    17.3 @@ -0,0 +1,2 @@
    17.4 +Pab
    17.5 +ake
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tests/basic/dependent-strings.sp	Fri Dec 28 17:13:51 2012 -0800
    18.3 @@ -0,0 +1,17 @@
    18.4 +native PrintString(const char:text[]);
    18.5 +
    18.6 +f(char:str[])
    18.7 +{
    18.8 +    str[0] = 80;
    18.9 +}
   18.10 +
   18.11 +public main()
   18.12 +{
   18.13 +    new char:fixed[100] = "crab\n";
   18.14 +    new char:dynamo[] = "cake\n";
   18.15 +    f(fixed[1]);
   18.16 +    f(dynamo[1]);
   18.17 +    PrintString(fixed[1]);
   18.18 +    PrintString(dynamo[1]);
   18.19 +}
   18.20 +