Added initial String: support.
authorDavid Anderson <dvander@alliedmods.net>
Sun Jul 01 14:52:57 2012 -0700 (2012-07-01)
changeset 21af5d8e985502
parent 20 e020a14e21be
child 22 765ab1b672a3
Added initial String: support.
jitcraft/AST.h
jitcraft/Array.cpp
jitcraft/Array.h
jitcraft/BytecodeCompiler.cpp
jitcraft/BytecodeCompiler.h
jitcraft/BytecodeEmitter.h
jitcraft/Code.h
jitcraft/FixedArray.h
jitcraft/Interpreter.cpp
jitcraft/NameBinding.cpp
jitcraft/Opcodes.cpp
jitcraft/Opcodes.tbl
jitcraft/Parser.cpp
jitcraft/Scanner.cpp
jitcraft/Scanner.h
jitcraft/SemanticAnalysis.cpp
jitcraft/SemanticAnalysis.h
jitcraft/Token.h
jitcraft/TypeManager.cpp
jitcraft/Types.cpp
jitcraft/Types.h
jitcraft/main.cpp
tests/prototype/string-1.sp
     1.1 --- a/jitcraft/AST.h	Sun Jul 01 11:25:36 2012 -0700
     1.2 +++ b/jitcraft/AST.h	Sun Jul 01 14:52:57 2012 -0700
     1.3 @@ -31,6 +31,7 @@
     1.4      _(ReturnStatement)          \
     1.5      _(IntegerLiteral)           \
     1.6      _(FloatLiteral)             \
     1.7 +    _(StringLiteral)            \
     1.8      _(BinaryExpression)         \
     1.9      _(BlockStatement)           \
    1.10      _(Assignment)               \
    1.11 @@ -273,6 +274,27 @@
    1.12      }
    1.13  };
    1.14  
    1.15 +class StringLiteral : public Expression
    1.16 +{
    1.17 +    ByteArray *string_;
    1.18 +
    1.19 +  public:
    1.20 +    StringLiteral(ByteArray *array)
    1.21 +      : string_(array)
    1.22 +    {
    1.23 +    }
    1.24 +
    1.25 +    Kind kind() const {
    1.26 +        return kStringLiteral;
    1.27 +    }
    1.28 +    ByteArray *string() const {
    1.29 +        return string_;
    1.30 +    }
    1.31 +    void accept(AstVisitor *visitor) {
    1.32 +        visitor->visit(this);
    1.33 +    }
    1.34 +};
    1.35 +
    1.36  class BinaryExpression : public Expression
    1.37  {
    1.38      Expression *left_;
     2.1 --- a/jitcraft/Array.cpp	Sun Jul 01 11:25:36 2012 -0700
     2.2 +++ b/jitcraft/Array.cpp	Sun Jul 01 14:52:57 2012 -0700
     2.3 @@ -43,6 +43,8 @@
     2.4          return sizeof(Array) + elements * sizeof(jc::Object *);
     2.5      if (type->contained()->isInt32())
     2.6          return sizeof(Array) + elements * sizeof(int);
     2.7 +    if (type->contained()->primitive() == PrimitiveType_Char)
     2.8 +        return sizeof(Array) + elements * sizeof(char);
     2.9      assert(type->contained()->isFloat());
    2.10      return sizeof(Array) + elements * sizeof(float);
    2.11  }
     3.1 --- a/jitcraft/Array.h	Sun Jul 01 11:25:36 2012 -0700
     3.2 +++ b/jitcraft/Array.h	Sun Jul 01 14:52:57 2012 -0700
     3.3 @@ -32,11 +32,6 @@
     3.4      uint32 nelements_;
     3.5      void *elements_;
     3.6  
     3.7 -  private:
     3.8 -    void *vec() {
     3.9 -        return elements_;
    3.10 -    }
    3.11 -
    3.12    public:
    3.13      static Array *New(Zone *zone, ArrayMap *map, uint32 elements,
    3.14                        Heap::Tenure = Heap::Tenure_Default);
    3.15 @@ -44,9 +39,17 @@
    3.16      uint32 nelements() {
    3.17          return nelements_;
    3.18      }
    3.19 +    void *vec() {
    3.20 +        return elements_;
    3.21 +    }
    3.22 +
    3.23      inline int *int32Vec();
    3.24      inline float *floatVec();
    3.25      inline Object **objVec();
    3.26 +    inline char *chars();
    3.27 +
    3.28 +    inline Type *type();
    3.29 +    inline size_t elementSize();
    3.30  
    3.31      int readInt32(size_t index) {
    3.32          assert(index < nelements());
    3.33 @@ -56,6 +59,14 @@
    3.34          assert(index < nelements());
    3.35          int32Vec()[index] = i;
    3.36      }
    3.37 +    char readChar(size_t index) {
    3.38 +        assert(index < nelements());
    3.39 +        return chars()[index];
    3.40 +    }
    3.41 +    void writeChar(size_t index, char c) {
    3.42 +        assert(index < nelements());
    3.43 +        chars()[index] = c;
    3.44 +    }
    3.45      float readFloat(size_t index) {
    3.46          assert(index < nelements());
    3.47          return floatVec()[index];
    3.48 @@ -104,35 +115,65 @@
    3.49  inline int *
    3.50  Array::int32Vec()
    3.51  {
    3.52 -    assert(ArrayMap::cast(map())->type()->levels() == 1);
    3.53 -    assert(ArrayMap::cast(map())->type()->contained()->isInt32());
    3.54 +    assert(type()->levels() == 1);
    3.55 +    assert(type()->contained()->isInt32());
    3.56      return reinterpret_cast<int *>(vec());
    3.57  }
    3.58  
    3.59  inline float *
    3.60  Array::floatVec()
    3.61  {
    3.62 -    assert(ArrayMap::cast(map())->type()->levels() == 1);
    3.63 -    assert(ArrayMap::cast(map())->type()->contained()->isFloat());
    3.64 +    assert(type()->levels() == 1);
    3.65 +    assert(type()->contained()->isFloat());
    3.66      return reinterpret_cast<float *>(vec());
    3.67  }
    3.68  
    3.69  inline Object **
    3.70  Array::objVec()
    3.71  {
    3.72 -    assert(ArrayMap::cast(map())->type()->levels() > 1);
    3.73 +    assert(type()->levels() > 1);
    3.74      return reinterpret_cast<Object **>(vec());
    3.75  }
    3.76  
    3.77  inline void *
    3.78  Array::slotPtr(size_t index)
    3.79  {
    3.80 -    assert(ArrayMap::cast(map())->type()->contained()->primitive() == PrimitiveType_Int32 ||
    3.81 -           ArrayMap::cast(map())->type()->contained()->primitive() == PrimitiveType_Float);
    3.82 +    assert(type()->contained()->primitive() == PrimitiveType_Int32 ||
    3.83 +           type()->contained()->primitive() == PrimitiveType_Float);
    3.84      assert(index < nelements());
    3.85      return reinterpret_cast<int *>(vec()) + index;
    3.86  }
    3.87  
    3.88 +inline char *
    3.89 +Array::chars()
    3.90 +{
    3.91 +    assert(type()->levels() == 1);
    3.92 +    assert(type()->contained()->primitive() == PrimitiveType_Char);
    3.93 +    return reinterpret_cast<char *>(vec());
    3.94 +}
    3.95 +
    3.96 +inline Type *
    3.97 +Array::type()
    3.98 +{
    3.99 +    return ArrayMap::cast(map())->type();
   3.100 +}
   3.101 +
   3.102 +inline size_t
   3.103 +Array::elementSize()
   3.104 +{
   3.105 +    if (type()->isArray())
   3.106 +        return sizeof(Object *);
   3.107 +    switch (type()->contained()->primitive()) {
   3.108 +      case PrimitiveType_Float:
   3.109 +        return sizeof(float);
   3.110 +      case PrimitiveType_Int32:
   3.111 +        return sizeof(int);
   3.112 +      default:
   3.113 +        assert(type()->contained()->primitive() == PrimitiveType_Char);
   3.114 +        return sizeof(char);
   3.115 +    }
   3.116 +}
   3.117 +
   3.118  }
   3.119  
   3.120  #endif // _include_jitcraft_array_h_
     4.1 --- a/jitcraft/BytecodeCompiler.cpp	Sun Jul 01 11:25:36 2012 -0700
     4.2 +++ b/jitcraft/BytecodeCompiler.cpp	Sun Jul 01 14:52:57 2012 -0700
     4.3 @@ -173,15 +173,39 @@
     4.4  void
     4.5  BytecodeCompiler::visit(Assignment *node)
     4.6  {
     4.7 +    // First compute the left-hand side.
     4.8      if (node->lvalue()->isNameProxy()) {
     4.9          NameProxy *proxy = node->lvalue()->toNameProxy();
    4.10          Variable *var = proxy->binding()->toVariable();
    4.11  
    4.12          // Make sure to bind the left-hand side first.
    4.13 -        if (var->type()->isReference())
    4.14 +        if (var->type()->isReference() || var->type()->isArray())
    4.15              __ get(var);
    4.16  
    4.17          node->expression()->accept(this);
    4.18 +    } else if (node->lvalue()->isIndexExpression()) {
    4.19 +        IndexExpression *index = node->lvalue()->toIndexExpression();
    4.20 +
    4.21 +        // Note: Eventually, watch out for a whole here. An expression like:
    4.22 +        //
    4.23 +        //   (a[4] = (5, a = []))
    4.24 +        //
    4.25 +        // Could shrink array, so we need to either bind a[i] to a Reference,
    4.26 +        // or keep the bounds check near the set. This is just a semantic
    4.27 +        // decision.
    4.28 +        index->left()->accept(this);
    4.29 +        index->right()->accept(this);
    4.30 +        node->expression()->accept(this);
    4.31 +    }
    4.32 +
    4.33 +    // Emit the store.
    4.34 +    if (node->expression()->type()->isArray()) {
    4.35 +        // Unlike references, which can only be computed from a NamePRoxy,
    4.36 +        // arrays can be computed from multiple lvalue types.
    4.37 +        __ arraycopy();
    4.38 +    } else if (node->lvalue()->isNameProxy()) {
    4.39 +        NameProxy *proxy = node->lvalue()->toNameProxy();
    4.40 +        Variable *var = proxy->binding()->toVariable();
    4.41  
    4.42          if (var->type()->isReference()) {
    4.43              if (var->type()->contained()->isFloat()) {
    4.44 @@ -193,19 +217,10 @@
    4.45          } else {
    4.46              __ set(var);
    4.47          }
    4.48 -    } else if (node->lvalue()->isIndexExpression()) {
    4.49 +    } else {
    4.50          IndexExpression *index = node->lvalue()->toIndexExpression();
    4.51 -
    4.52 -        index->left()->accept(this);
    4.53 -        index->right()->accept(this);
    4.54          __ bounds();
    4.55 -        node->expression()->accept(this);
    4.56 -        if (index->left()->type()->contained()->isFloat()) {
    4.57 -            __ setarray_f();
    4.58 -        } else {
    4.59 -            assert(index->left()->type()->contained()->isInt32());
    4.60 -            __ setarray_i();
    4.61 -        }
    4.62 +        __ setarray(index->left()->type()->contained()->primitive());
    4.63      }
    4.64  }
    4.65  
    4.66 @@ -236,14 +251,10 @@
    4.67      node->right()->accept(this);
    4.68      __ bounds();
    4.69  
    4.70 -    if (node->type()->isArray()) {
    4.71 +    if (node->type()->isArray())
    4.72          __ getarray_o();
    4.73 -    } else if (node->type()->isFloat()) {
    4.74 -        __ getarray_f();
    4.75 -    } else {
    4.76 -        __ getarray_i();
    4.77 -        assert(node->type()->isInt32());
    4.78 -    }
    4.79 +    else
    4.80 +        __ getarray(node->type()->primitive());
    4.81  }
    4.82  
    4.83  void
    4.84 @@ -400,6 +411,24 @@
    4.85  }
    4.86  
    4.87  void
    4.88 +BytecodeCompiler::visit(StringLiteral *node)
    4.89 +{
    4.90 +    // :TODO: use Local
    4.91 +    ArrayMap *map = BuildArrayMap(ZONE(), node->type());
    4.92 +    if (!map)
    4.93 +        return;
    4.94 +
    4.95 +    Array *array = Array::New(ZONE(), map, node->string()->length(), Heap::Tenure_Old);
    4.96 +    if (!array)
    4.97 +        return;
    4.98 +
    4.99 +    assert(array->nelements() >= node->string()->length());
   4.100 +    memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
   4.101 +
   4.102 +    __ object(array);
   4.103 +}
   4.104 +
   4.105 +void
   4.106  BytecodeCompiler::visit(VariableDeclaration *node)
   4.107  {
   4.108      Variable *var = node->variable();
   4.109 @@ -410,6 +439,11 @@
   4.110          // :TODO: use Local
   4.111          ArrayMap *map = BuildArrayMap(ZONE(), type);
   4.112          __ newarray_lifo(map);
   4.113 +
   4.114 +        if (node->initialization()) {
   4.115 +            node->initialization()->accept(this);
   4.116 +            __ arraycopy();
   4.117 +        }
   4.118      } else {
   4.119          if (node->initialization()) {
   4.120              node->initialization()->accept(this);
   4.121 @@ -535,14 +569,14 @@
   4.122      for (size_t i = 0; i < node->scope()->maxContainedLocals(); i++)
   4.123          assert(locals_->at(i));
   4.124  
   4.125 -    FixedArray *maps = FixedArray::New(ZONE(), __ maps()->size(), Heap::Tenure_Old);
   4.126 -    if (!maps)
   4.127 +    FixedArray *objects = FixedArray::New(ZONE(), __ objects()->size(), Heap::Tenure_Old);
   4.128 +    if (!objects)
   4.129          return NULL;
   4.130  
   4.131 -    for (size_t i = 0; i < __ maps()->size(); i++)
   4.132 -        maps->set(ZONE(), i, __ maps()->at(i));
   4.133 +    for (size_t i = 0; i < __ objects()->size(); i++)
   4.134 +        objects->set(ZONE(), i, __ objects()->at(i));
   4.135  
   4.136 -    Code *code = Code::New(ZONE(), bytes, locals_, args, maps, __ maxStackDepth(), module_);
   4.137 +    Code *code = Code::New(ZONE(), bytes, locals_, args, objects, __ maxStackDepth(), module_);
   4.138      return code;
   4.139  }
   4.140  
     5.1 --- a/jitcraft/BytecodeCompiler.h	Sun Jul 01 11:25:36 2012 -0700
     5.2 +++ b/jitcraft/BytecodeCompiler.h	Sun Jul 01 14:52:57 2012 -0700
     5.3 @@ -113,6 +113,7 @@
     5.4      void visit(VariableDeclaration *node);
     5.5      void visit(IntegerLiteral *node);
     5.6      void visit(FloatLiteral *node);
     5.7 +    void visit(StringLiteral *node);
     5.8      void visit(ExpressionStatement *node);
     5.9      void visit(FunctionStatement *node);
    5.10      void visit(CallExpression *node);
     6.1 --- a/jitcraft/BytecodeEmitter.h	Sun Jul 01 11:25:36 2012 -0700
     6.2 +++ b/jitcraft/BytecodeEmitter.h	Sun Jul 01 14:52:57 2012 -0700
     6.3 @@ -38,7 +38,7 @@
     6.4      bool oom_;
     6.5      unsigned maxStackDepth_;
     6.6      unsigned stackDepth_;
     6.7 -    std::vector<Map *> maps_;
     6.8 +    std::vector<Object *> objects_;
     6.9  
    6.10    private:
    6.11      static const size_t MAX_LENGTH = INT_MAX / 2;
    6.12 @@ -78,9 +78,9 @@
    6.13          if (stackDepth_ > maxStackDepth_)
    6.14              maxStackDepth_ = stackDepth_;
    6.15      }
    6.16 -    void writeMap(Map *map) {
    6.17 -        writeUint32(maps_.size());
    6.18 -        maps_.push_back(map);
    6.19 +    void writeObject(Object *obj) {
    6.20 +        writeUint32(objects_.size());
    6.21 +        objects_.push_back(obj);
    6.22      }
    6.23  
    6.24      int position() const {
    6.25 @@ -106,8 +106,8 @@
    6.26      unsigned maxStackDepth() const {
    6.27          return maxStackDepth_;
    6.28      }
    6.29 -    const std::vector<Map *> *maps() const {
    6.30 -        return &maps_;
    6.31 +    const std::vector<Object *> *objects() const {
    6.32 +        return &objects_;
    6.33      }
    6.34  
    6.35    public:
    6.36 @@ -268,17 +268,33 @@
    6.37  
    6.38          stackDepth_ -= nargs;
    6.39      }
    6.40 -    void getarray_i() {
    6.41 -        singleByteOp(OP_GETARRAY_I);
    6.42 -    }
    6.43 -    void setarray_i() {
    6.44 -        singleByteOp(OP_SETARRAY_I);
    6.45 +    void getarray(PrimitiveType type) {
    6.46 +        switch (type) {
    6.47 +          case PrimitiveType_Float:
    6.48 +            singleByteOp(OP_GETARRAY_F);
    6.49 +            break;
    6.50 +          case PrimitiveType_Int32:
    6.51 +            singleByteOp(OP_GETARRAY_I);
    6.52 +            break;
    6.53 +          default:
    6.54 +            assert(type == PrimitiveType_Char);
    6.55 +            singleByteOp(OP_GETARRAY_C);
    6.56 +            break;
    6.57 +        }
    6.58      }
    6.59 -    void getarray_f() {
    6.60 -        singleByteOp(OP_GETARRAY_F);
    6.61 -    }
    6.62 -    void setarray_f() {
    6.63 -        singleByteOp(OP_SETARRAY_F);
    6.64 +    void setarray(PrimitiveType type) {
    6.65 +        switch (type) {
    6.66 +          case PrimitiveType_Float:
    6.67 +            singleByteOp(OP_SETARRAY_F);
    6.68 +            break;
    6.69 +          case PrimitiveType_Int32:
    6.70 +            singleByteOp(OP_SETARRAY_I);
    6.71 +            break;
    6.72 +          default:
    6.73 +            assert(type == PrimitiveType_Char);
    6.74 +            singleByteOp(OP_SETARRAY_C);
    6.75 +            break;
    6.76 +        }
    6.77      }
    6.78      void getarray_o() {
    6.79          singleByteOp(OP_GETARRAY_O);
    6.80 @@ -297,7 +313,7 @@
    6.81      void newarray_lifo(Map *map) {
    6.82          ensure(OP_NEWARRAY_LIFO_LENGTH);
    6.83          writeOp(OP_NEWARRAY_LIFO);
    6.84 -        writeMap(map);
    6.85 +        writeObject(map);
    6.86      }
    6.87      void savelifo(unsigned slot) {
    6.88          ensure(OP_SAVELIFO_LENGTH);
    6.89 @@ -355,6 +371,14 @@
    6.90      void setref_f() {
    6.91          singleByteOp(OP_SETREF_F);
    6.92      }
    6.93 +    void object(Object *obj) {
    6.94 +        ensure(OP_OBJECT_LENGTH);
    6.95 +        writeOp(OP_OBJECT);
    6.96 +        writeObject(obj);
    6.97 +    }
    6.98 +    void arraycopy() {
    6.99 +        singleByteOp(OP_ARRAYCOPY);
   6.100 +    }
   6.101  };
   6.102  
   6.103  }
     7.1 --- a/jitcraft/Code.h	Sun Jul 01 11:25:36 2012 -0700
     7.2 +++ b/jitcraft/Code.h	Sun Jul 01 14:52:57 2012 -0700
     7.3 @@ -38,13 +38,13 @@
     7.4      Unbarriered<ByteArray> bytecode_;
     7.5      Unbarriered<FixedArray> locals_;
     7.6      Unbarriered<FixedArray> args_;
     7.7 -    Unbarriered<FixedArray> maps_;
     7.8 +    Unbarriered<FixedArray> objects_;
     7.9      unsigned maxStackDepth_;
    7.10  
    7.11    public:
    7.12      // :TODO: use handles
    7.13      static Code *New(Zone *zone, ByteArray *bytecode, FixedArray *locals, FixedArray *args,
    7.14 -                     FixedArray *maps, unsigned maxStackDepth, Module *module);
    7.15 +                     FixedArray *objects, unsigned maxStackDepth, Module *module);
    7.16  
    7.17      Module *module() {
    7.18          return module_;
    7.19 @@ -71,7 +71,10 @@
    7.20          return maxStackDepth_;
    7.21      }
    7.22      Map *map(size_t index) {
    7.23 -        return Map::cast(maps_->at(index));
    7.24 +        return Map::cast(objects_->at(index));
    7.25 +    }
    7.26 +    Object *object(size_t index) {
    7.27 +        return objects_->at(index);
    7.28      }
    7.29  
    7.30      static Code *cast(Object *obj) {
     8.1 --- a/jitcraft/FixedArray.h	Sun Jul 01 11:25:36 2012 -0700
     8.2 +++ b/jitcraft/FixedArray.h	Sun Jul 01 14:52:57 2012 -0700
     8.3 @@ -68,7 +68,7 @@
     8.4      }
     8.5  
     8.6    public:
     8.7 -    static ByteArray *New(Zone *zone, unsigned length, Heap::Tenure tenure);
     8.8 +    static ByteArray *New(Zone *zone, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
     8.9  
    8.10      unsigned length() {
    8.11          return length_;
     9.1 --- a/jitcraft/Interpreter.cpp	Sun Jul 01 11:25:36 2012 -0700
     9.2 +++ b/jitcraft/Interpreter.cpp	Sun Jul 01 14:52:57 2012 -0700
     9.3 @@ -102,6 +102,20 @@
     9.4      return array;
     9.5  }
     9.6  
     9.7 +static bool
     9.8 +CopyArray(Zone *zone, Array *source, Array *dest)
     9.9 +{
    9.10 +    assert(source->type()->levels() == 1);
    9.11 +    assert(dest->type()->levels() == 1);
    9.12 +    assert(source->type()->contained()->primitive() ==
    9.13 +           dest->type()->contained()->primitive());
    9.14 +    assert(source->nelements() >= dest->nelements());
    9.15 +    assert(dest->elementSize() == source->elementSize());
    9.16 +
    9.17 +    memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
    9.18 +    return true;
    9.19 +}
    9.20 +
    9.21  bool
    9.22  jc::Interpret(Frame *frame, LocalSlot *result)
    9.23  {
    9.24 @@ -400,6 +414,15 @@
    9.25      break;
    9.26  }
    9.27  
    9.28 +case OP_GETARRAY_C:
    9.29 +{
    9.30 +    Array *array = top.sp[-2].array;
    9.31 +    int index = top.sp[-1].i32;
    9.32 +    top.sp[-2].i32 = array->readChar(index);
    9.33 +    top.sp--;
    9.34 +    break;
    9.35 +}
    9.36 +
    9.37  case OP_SETARRAY_I:
    9.38  {
    9.39      Array *array = top.sp[-3].array;
    9.40 @@ -420,6 +443,16 @@
    9.41      break;
    9.42  }
    9.43  
    9.44 +case OP_SETARRAY_C:
    9.45 +{
    9.46 +    Array *array = top.sp[-3].array;
    9.47 +    int index = top.sp[-2].i32;
    9.48 +    array->writeChar(index, top.sp[-1].i32);
    9.49 +    top.sp[-3] = top.sp[-1];
    9.50 +    top.sp -= 2;
    9.51 +    break;
    9.52 +}
    9.53 +
    9.54  case OP_GETARRAY_O:
    9.55  {
    9.56      Array *array = top.sp[-2].array;
    9.57 @@ -534,6 +567,25 @@
    9.58      break;
    9.59  }
    9.60  
    9.61 +case OP_OBJECT:
    9.62 +{
    9.63 +    top.sp->obj = frame->code()->object(READ_UINT32(top.pc));
    9.64 +    top.sp++;
    9.65 +    break;
    9.66 +}
    9.67 +
    9.68 +case OP_ARRAYCOPY:
    9.69 +{
    9.70 +    // Note for this assignment opcode, we return the left-hand side, not the
    9.71 +    // right, since in this case the result of the expression could be different.
    9.72 +    if (!CopyArray(ZONE(), top.sp[-2].array, top.sp[-1].array)) {
    9.73 +        assert(false);
    9.74 +        return false;
    9.75 +    }
    9.76 +    top.sp--;
    9.77 +    break;
    9.78 +}
    9.79 +
    9.80  default:
    9.81      assert(false);
    9.82      return false;
    10.1 --- a/jitcraft/NameBinding.cpp	Sun Jul 01 11:25:36 2012 -0700
    10.2 +++ b/jitcraft/NameBinding.cpp	Sun Jul 01 14:52:57 2012 -0700
    10.3 @@ -21,7 +21,8 @@
    10.4  
    10.5  BoundName::BoundName(Scope *scope, Name *name)
    10.6    : scope_(scope),
    10.7 -    name_(name)
    10.8 +    name_(name),
    10.9 +    type_(NULL)
   10.10  {
   10.11  }
   10.12  
    11.1 --- a/jitcraft/Opcodes.cpp	Sun Jul 01 11:25:36 2012 -0700
    11.2 +++ b/jitcraft/Opcodes.cpp	Sun Jul 01 14:52:57 2012 -0700
    11.3 @@ -34,7 +34,7 @@
    11.4  
    11.5  Code *
    11.6  Code::New(Zone *zone, ByteArray *bytecode, FixedArray *locals, FixedArray *args,
    11.7 -          FixedArray *maps, unsigned maxStackDepth, Module *module)
    11.8 +          FixedArray *objects, unsigned maxStackDepth, Module *module)
    11.9  {
   11.10      Object *obj = zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old);
   11.11      if (!obj)
   11.12 @@ -44,7 +44,7 @@
   11.13      code->bytecode_ = bytecode;
   11.14      code->locals_ = locals;
   11.15      code->args_ = args;
   11.16 -    code->maps_ = maps;
   11.17 +    code->objects_ = objects;
   11.18      code->maxStackDepth_ = maxStackDepth;
   11.19      code->module_ = module;
   11.20      return code;
   11.21 @@ -86,6 +86,8 @@
   11.22            case OP_SETARRAY_I:
   11.23            case OP_GETARRAY_F:
   11.24            case OP_SETARRAY_F:
   11.25 +          case OP_GETARRAY_C:
   11.26 +          case OP_SETARRAY_C:
   11.27            case OP_GETARRAY_O:
   11.28            case OP_BOUNDS:
   11.29            case OP_SHL:
   11.30 @@ -100,6 +102,8 @@
   11.31            case OP_SETREF_F:
   11.32            case OP_SLOTREF_LIFO:
   11.33            case OP_ARRAYREF_LIFO:
   11.34 +          case OP_OBJECT:
   11.35 +          case OP_ARRAYCOPY:
   11.36              break;
   11.37  
   11.38            case OP_STOP:
    12.1 --- a/jitcraft/Opcodes.tbl	Sun Jul 01 11:25:36 2012 -0700
    12.2 +++ b/jitcraft/Opcodes.tbl	Sun Jul 01 14:52:57 2012 -0700
    12.3 @@ -92,14 +92,16 @@
    12.4  OPDEF(OP_SETARRAY_I,    24,         "setarray.i",   1,      3,  1)
    12.5  OPDEF(OP_GETARRAY_F,    25,         "getarray.f",   1,      2,  1)
    12.6  OPDEF(OP_SETARRAY_F,    26,         "setarray.f",   1,      3,  1)
    12.7 -OPDEF(OP_GETARRAY_O,    27,         "getarray.o",   1,      2,  1)
    12.8 +OPDEF(OP_GETARRAY_C,    27,         "getarray.c",   1,      2,  1)
    12.9 +OPDEF(OP_SETARRAY_C,    28,         "setarray.c",   1,      3,  1)
   12.10 +OPDEF(OP_GETARRAY_O,    29,         "getarray.o",   1,      2,  1)
   12.11  
   12.12  // Allocate an array, info LIFO space if possible. The ArrayMap to use is
   12.13  // specified as an index into the script's Map table.
   12.14  //
   12.15  // Format:
   12.16  //  [u8 op] [u32 index]
   12.17 -OPDEF(OP_NEWARRAY_LIFO, 28,         "newarray.lifo", 5,     0,  1)
   12.18 +OPDEF(OP_NEWARRAY_LIFO, 30,         "newarray.lifo", 5,     0,  1)
   12.19  
   12.20  // Performs a bounds check on an unsafe array.
   12.21  //
   12.22 @@ -107,41 +109,51 @@
   12.23  // array = pop()
   12.24  // push(array)
   12.25  // push(index)
   12.26 -OPDEF(OP_BOUNDS,        29,         "bounds",       1,      2,  2)
   12.27 +OPDEF(OP_BOUNDS,        31,         "bounds",       1,      2,  2)
   12.28  
   12.29  // Pushes a 32-bit IEEE-754 floating point immediate onto the stack.
   12.30 -OPDEF(OP_FLOAT,         30,         "float",        5,      0,  1)
   12.31 +OPDEF(OP_FLOAT,         32,         "float",        5,      0,  1)
   12.32  
   12.33  // Converts an integer to a 32-bit IEEE-754 floating point immediate.
   12.34 -OPDEF(OP_CVT_I2F,       31,         "cvt.i2f",      1,      1,  1)
   12.35 +OPDEF(OP_CVT_I2F,       33,         "cvt.i2f",      1,      1,  1)
   12.36  
   12.37  // Stack transitions for these binary operators:
   12.38  // rhs = pop()
   12.39  // lhs = pop()
   12.40  // push(lhs OP rhs)
   12.41 -OPDEF(OP_ADD_F,         32,         "add.f",        1,      2,  1)
   12.42 -OPDEF(OP_SUB_F,         33,         "sub.f",        1,      2,  1)
   12.43 -OPDEF(OP_MUL_F,         34,         "mul.f",        1,      2,  1)
   12.44 -OPDEF(OP_DIV_F,         35,         "div.f",        1,      2,  1)
   12.45 +OPDEF(OP_ADD_F,         34,         "add.f",        1,      2,  1)
   12.46 +OPDEF(OP_SUB_F,         35,         "sub.f",        1,      2,  1)
   12.47 +OPDEF(OP_MUL_F,         36,         "mul.f",        1,      2,  1)
   12.48 +OPDEF(OP_DIV_F,         37,         "div.f",        1,      2,  1)
   12.49  
   12.50  // Bitwise operators.
   12.51 -OPDEF(OP_SHL,           36,         "shl",          1,      2,  1)
   12.52 -OPDEF(OP_SHR,           37,         "shr",          1,      2,  1)
   12.53 -OPDEF(OP_USHR,          38,         "ushr",         1,      2,  1)
   12.54 -OPDEF(OP_BITAND,        39,         "bitand",       1,      2,  1)
   12.55 -OPDEF(OP_BITOR,         40,         "bitor",        1,      2,  1)
   12.56 -OPDEF(OP_BITXOR,        41,         "bitxor",       1,      2,  1)
   12.57 +OPDEF(OP_SHL,           38,         "shl",          1,      2,  1)
   12.58 +OPDEF(OP_SHR,           39,         "shr",          1,      2,  1)
   12.59 +OPDEF(OP_USHR,          40,         "ushr",         1,      2,  1)
   12.60 +OPDEF(OP_BITAND,        41,         "bitand",       1,      2,  1)
   12.61 +OPDEF(OP_BITOR,         42,         "bitor",        1,      2,  1)
   12.62 +OPDEF(OP_BITXOR,        43,         "bitxor",       1,      2,  1)
   12.63  
   12.64  // Saves or restores the position of the LIFO heap to/from a local slot.
   12.65 -OPDEF(OP_SAVELIFO,      42,         "savelifo",     5,      0,  0)
   12.66 -OPDEF(OP_UNWINDLIFO,    43,         "unwindlifo",   5,      0,  0)
   12.67 +OPDEF(OP_SAVELIFO,      44,         "savelifo",     5,      0,  0)
   12.68 +OPDEF(OP_UNWINDLIFO,    45,         "unwindlifo",   5,      0,  0)
   12.69  
   12.70  // Composes a variable reference to a stack slot or argument.
   12.71 -OPDEF(OP_VARREF_LIFO,   44,         "varref.lifo",  5,      0,  1)
   12.72 -OPDEF(OP_ARGREF_LIFO,   45,         "argref.lifo",  5,      0,  1)
   12.73 -OPDEF(OP_SLOTREF_LIFO,  46,         "slotref.lifo", 1,      1,  1)
   12.74 -OPDEF(OP_ARRAYREF_LIFO, 47,         "arrayref.lifo",1,      2,  1)
   12.75 -OPDEF(OP_GETREF_I,      48,         "getref.i",     1,      1,  1)
   12.76 -OPDEF(OP_SETREF_I,      49,         "setref.i",     1,      2,  1)
   12.77 -OPDEF(OP_GETREF_F,      50,         "getref.f",     1,      1,  1)
   12.78 -OPDEF(OP_SETREF_F,      51,         "setref.f",     1,      2,  1)
   12.79 +OPDEF(OP_VARREF_LIFO,   46,         "varref.lifo",  5,      0,  1)
   12.80 +OPDEF(OP_ARGREF_LIFO,   47,         "argref.lifo",  5,      0,  1)
   12.81 +OPDEF(OP_SLOTREF_LIFO,  48,         "slotref.lifo", 1,      1,  1)
   12.82 +OPDEF(OP_ARRAYREF_LIFO, 49,         "arrayref.lifo",1,      2,  1)
   12.83 +OPDEF(OP_GETREF_I,      50,         "getref.i",     1,      1,  1)
   12.84 +OPDEF(OP_SETREF_I,      51,         "setref.i",     1,      2,  1)
   12.85 +OPDEF(OP_GETREF_F,      52,         "getref.f",     1,      1,  1)
   12.86 +OPDEF(OP_SETREF_F,      53,         "setref.f",     1,      2,  1)
   12.87 +
   12.88 +// Pushes an object reference onto the stack.
   12.89 +OPDEF(OP_OBJECT,        54,         "object",       5,      0,  1)
   12.90 +
   12.91 +// Performs an array-to-array assignment.
   12.92 +//   Left = pop()
   12.93 +//   Right = pop()
   12.94 +//   copy(Left, Right)
   12.95 +//   push(Left)
   12.96 +OPDEF(OP_ARRAYCOPY,     55,         "arraycopy",    1,      2,  1)
    13.1 --- a/jitcraft/Parser.cpp	Sun Jul 01 11:25:36 2012 -0700
    13.2 +++ b/jitcraft/Parser.cpp	Sun Jul 01 14:52:57 2012 -0700
    13.3 @@ -17,6 +17,9 @@
    13.4   */
    13.5  #include "Zone.h"
    13.6  #include "Parser.h"
    13.7 +#include "FixedArray.h"
    13.8 +#include "Heap.h"
    13.9 +#include "Heap-inl.h"
   13.10  
   13.11  using namespace jc;
   13.12  
   13.13 @@ -112,6 +115,18 @@
   13.14          return new (pool_) IntegerLiteral(value);
   13.15        }
   13.16  
   13.17 +      case TOK_STRING_LITERAL:
   13.18 +      {
   13.19 +        // :TODO: Local
   13.20 +        scanner_.scan();
   13.21 +        ByteArray *array = ByteArray::New(ZONE(), scanner_.literal_length());
   13.22 +        if (!array)
   13.23 +            return NULL;
   13.24 +        memcpy(array->raw(), scanner_.literal(), scanner_.literal_length());
   13.25 +
   13.26 +        return new (pool_) StringLiteral(array);
   13.27 +      }
   13.28 +
   13.29        default:
   13.30        {
   13.31          fprintf(stderr, "error: expected expression!\n");
   13.32 @@ -497,10 +512,8 @@
   13.33  Parser::expressionStatement()
   13.34  {
   13.35      Expression *left = primary();
   13.36 -    if (!left) {
   13.37 -        fprintf(stderr, "expected expression or statement\n");
   13.38 +    if (!left)
   13.39          return NULL;
   13.40 -    }
   13.41  
   13.42      if (match(TOK_ASSIGN)) {
   13.43          Expression *expr = expression();
   13.44 @@ -604,7 +617,8 @@
   13.45  
   13.46      switch (scanner_.peek()) {
   13.47          case TOK_NEW:
   13.48 -          statement = variableDeclaration();
   13.49 +          if ((statement = variableDeclaration()) == NULL)
   13.50 +              return NULL;
   13.51            break;
   13.52  
   13.53          case TOK_FOR:
   13.54 @@ -629,11 +643,13 @@
   13.55            break;
   13.56  
   13.57          case TOK_RETURN:
   13.58 -          statement = returnStatement();
   13.59 +          if ((statement = returnStatement()) == NULL)
   13.60 +              return NULL;
   13.61            break;
   13.62  
   13.63          case TOK_ENUM:
   13.64 -          statement = enum_();
   13.65 +          if ((statement = enum_()) == NULL)
   13.66 +              return NULL;
   13.67            break;
   13.68  
   13.69          case TOK_IF:
   13.70 @@ -979,6 +995,10 @@
   13.71          prefix();
   13.72          fprintf(fp_, "[ ContinueStatement\n");
   13.73      }
   13.74 +    void visit(StringLiteral *node) {
   13.75 +        prefix();
   13.76 +        fprintf(fp_, "[ StringLiteral\n");
   13.77 +    }
   13.78  };
   13.79  
   13.80  void
    14.1 --- a/jitcraft/Scanner.cpp	Sun Jul 01 11:25:36 2012 -0700
    14.2 +++ b/jitcraft/Scanner.cpp	Sun Jul 01 14:52:57 2012 -0700
    14.3 @@ -137,6 +137,114 @@
    14.4      return number;
    14.5  }
    14.6  
    14.7 +static inline bool
    14.8 +IsHexDigit(char c)
    14.9 +{
   14.10 +    return IsDigit(c) ||
   14.11 +           (c >= 'a' && c <= 'f') ||
   14.12 +           (c >= 'A' && c <= 'F');
   14.13 +}
   14.14 +
   14.15 +// Based on the logic for litchar() in sc2.c.
   14.16 +int
   14.17 +Scanner::readEscapeCode()
   14.18 +{
   14.19 +    char c = getChar();
   14.20 +    if (c == '\\')
   14.21 +        return c;
   14.22 +
   14.23 +    switch (c) {
   14.24 +      case 'a':
   14.25 +        return '\a';
   14.26 +      case 'b':
   14.27 +        return '\b';
   14.28 +      case 'e':
   14.29 +        return 27;          // Apparently \e is non-standard.
   14.30 +      case 'f':
   14.31 +        return '\f';
   14.32 +      case 'n':
   14.33 +        return '\n';
   14.34 +      case 'r':
   14.35 +        return '\r';
   14.36 +      case 't':
   14.37 +        return '\t';
   14.38 +      case '\v':
   14.39 +        return '\v';
   14.40 +
   14.41 +      case 'x':
   14.42 +      {
   14.43 +          unsigned digits = 0;
   14.44 +          char r = 0;
   14.45 +  
   14.46 +          c = getChar();
   14.47 +          while (IsHexDigit(c) && digits < 2) {
   14.48 +              if (IsDigit(c))
   14.49 +                  c = (c << 4) + (c - '0');
   14.50 +              else
   14.51 +                  c = (c << 4) + (tolower(c) - 'a' + 10);
   14.52 +              digits++;
   14.53 +              c = getChar();
   14.54 +           }
   14.55 +                
   14.56 +          // Swallow a trailing ';'
   14.57 +          if (c != ';')
   14.58 +              putChar(c);
   14.59 +  
   14.60 +          return r;
   14.61 +      }
   14.62 +
   14.63 +      case '\'':
   14.64 +      case '\"':
   14.65 +      case '%':
   14.66 +        return c;
   14.67 +
   14.68 +      default:
   14.69 +      {
   14.70 +        if (IsDigit(c)) {
   14.71 +            // \ddd
   14.72 +            char r = 0;
   14.73 +            while (IsDigit(c)) {
   14.74 +                r = r * 10 + (c - '0');
   14.75 +                c = getChar();
   14.76 +            }
   14.77 +
   14.78 +            // Swallow a trailing ;
   14.79 +            if (c != ';')
   14.80 +                putChar(c);
   14.81 +
   14.82 +            return r;
   14.83 +        }
   14.84 +        assert(false);
   14.85 +        return INT_MAX;
   14.86 +      }
   14.87 +    }
   14.88 +}
   14.89 +
   14.90 +TokenKind
   14.91 +Scanner::stringLiteral()
   14.92 +{
   14.93 +    literal_.clear();
   14.94 +
   14.95 +    for (;;) {
   14.96 +        char c = getChar();
   14.97 +        if (c == '\"')
   14.98 +            break;
   14.99 +        if (c == '\r' || c == '\n' || c == '\0') {
  14.100 +            assert(false);
  14.101 +            return TOK_ERROR;
  14.102 +        }
  14.103 +        if (c == '\\') {
  14.104 +            int code = readEscapeCode();
  14.105 +            if (code == INT_MAX)
  14.106 +                return TOK_ERROR;
  14.107 +            c = char(code);
  14.108 +        }
  14.109 +        literal_ += c;
  14.110 +    }
  14.111 +
  14.112 +    return TOK_STRING_LITERAL;
  14.113 +}
  14.114 +
  14.115  TokenKind
  14.116  Scanner::numberLiteral(char first)
  14.117  {
  14.118 @@ -335,6 +443,9 @@
  14.119            case '\n':
  14.120              break;
  14.121  
  14.122 +          case '"':
  14.123 +            return stringLiteral();
  14.124 +
  14.125            default:
  14.126              if (c >= '0' && c <= '9')
  14.127                  return numberLiteral(c);
    15.1 --- a/jitcraft/Scanner.h	Sun Jul 01 11:25:36 2012 -0700
    15.2 +++ b/jitcraft/Scanner.h	Sun Jul 01 14:52:57 2012 -0700
    15.3 @@ -38,6 +38,8 @@
    15.4      void putChar(char c);
    15.5      void eatSingleLine();
    15.6      bool eatComment();
    15.7 +    int readEscapeCode();
    15.8 +    TokenKind stringLiteral();
    15.9      TokenKind numberLiteral(char first);
   15.10      TokenKind identifier(char first);
   15.11  
   15.12 @@ -54,9 +56,13 @@
   15.13          return lastToken_;
   15.14      }
   15.15  
   15.16 +    // Note: the literal may have embedded NUL characters.
   15.17      const char *literal() const {
   15.18          return literal_.c_str();
   15.19      }
   15.20 +    size_t literal_length() const {
   15.21 +        return literal_.size() + 1;
   15.22 +    }
   15.23  };
   15.24  
   15.25  } // namespace jc
    16.1 --- a/jitcraft/SemanticAnalysis.cpp	Sun Jul 01 11:25:36 2012 -0700
    16.2 +++ b/jitcraft/SemanticAnalysis.cpp	Sun Jul 01 14:52:57 2012 -0700
    16.3 @@ -120,10 +120,15 @@
    16.4  SemanticAnalysis::visitForLoad(Expression *expression)
    16.5  {
    16.6      expression->accept(this);
    16.7 -    if (expression->type()) {
    16.8 -        // :TODO: use Local
    16.9 -        Type *type = expression->type();
   16.10 -        if (type->isArray() || type->isReference())
   16.11 +    if (!expression->type())
   16.12 +        return NULL;
   16.13 +
   16.14 +    // :TODO: use Local
   16.15 +    Type *type = expression->type();
   16.16 +    if (type->isReference()) {
   16.17 +        expression->setType(type->contained());
   16.18 +    } else if (expression->isIndexExpression()) {
   16.19 +        if (type->isArray())
   16.20              expression->setType(type->contained());
   16.21      }
   16.22      return expression->type();
   16.23 @@ -151,6 +156,39 @@
   16.24      return false;
   16.25  }
   16.26  
   16.27 +static inline bool
   16.28 +TypeCheckAssignment(Type *left, Type *right)
   16.29 +{
   16.30 +    if (!left || !right)
   16.31 +        return false;
   16.32 +
   16.33 +    if (left->isPrimitive()) {
   16.34 +        if (!right->isPrimitive())
   16.35 +            return false;
   16.36 +        return left->primitive() == right->primitive();
   16.37 +    }
   16.38 +
   16.39 +    if (left->isArray() != right->isArray())
   16.40 +        return false;
   16.41 +
   16.42 +    if (left->levels() != 1 || right->levels() != 1)
   16.43 +        return false;
   16.44 +
   16.45 +    if (left->elements() == -1 || right->elements() == -1)
   16.46 +        return false;
   16.47 +
   16.48 +    if (!TypeCheckAssignment(left->contained(), right->contained()))
   16.49 +        return false;
   16.50 +
   16.51 +    if (left->elements() != right->elements()) {
   16.52 +        if (left->isCharArray() && (left->elements() >= right->elements()))
   16.53 +            return true;
   16.54 +        return false;
   16.55 +    }
   16.56 +
   16.57 +    return false;
   16.58 +}
   16.59 +
   16.60  void
   16.61  SemanticAnalysis::visit(Assignment *node)
   16.62  {
   16.63 @@ -167,13 +205,16 @@
   16.64          }
   16.65  
   16.66          Variable *var = proxy->binding()->toVariable();
   16.67 +        if (!var->type())
   16.68 +            return;
   16.69 +
   16.70          if  (var->type()->isReference())
   16.71              node->setType(var->type()->contained());
   16.72          else
   16.73              node->setType(var->type());
   16.74      }
   16.75  
   16.76 -    assert(TypeCheck(node->type(), node->expression()->type()));
   16.77 +    assert(TypeCheckAssignment(node->type(), node->expression()->type()));
   16.78  }
   16.79  
   16.80  
   16.81 @@ -260,11 +301,24 @@
   16.82          return;
   16.83  
   16.84      if (node->postDimensions()) {
   16.85 +        Type *init = NULL;
   16.86 +        if (node->initialization()) {
   16.87 +            node->initialization()->accept(this);
   16.88 +            if ((init = node->initialization()->type()) == NULL)
   16.89 +                return;
   16.90 +        }
   16.91 +
   16.92          if (node->postDimensions()->size() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
   16.93              error();
   16.94              return;
   16.95          }
   16.96  
   16.97 +        // If we have an initializer, make sure it's the same type.
   16.98 +        if (init) {
   16.99 +            assert(init->levels() == node->postDimensions()->size());
  16.100 +        }
  16.101 +
  16.102 +        Type *check = init;
  16.103          for (size_t i = node->postDimensions()->size() - 1; i < node->postDimensions()->size(); i--) {
  16.104              Expression *expr = node->postDimensions()->at(i);
  16.105              visitForLoad(expr);
  16.106 @@ -285,9 +339,28 @@
  16.107                      error();
  16.108                      return;
  16.109                  }
  16.110 +            } else {
  16.111 +                assert(false);
  16.112              }
  16.113  
  16.114              type = ZONE()->types()->unsafeArray(type, size);
  16.115 +
  16.116 +            if (check) {
  16.117 +                assert(check->elements() != -1);
  16.118 +                assert(size != -1);
  16.119 +                    
  16.120 +                // If we're assigning a string, we're allowed to pad with
  16.121 +                // zeroes.
  16.122 +                if (check->isCharArray()) {
  16.123 +                    assert(type->isCharArray());
  16.124 +                    assert(type->elements() >= check->elements());
  16.125 +                } else {
  16.126 +                    assert(false);
  16.127 +                }
  16.128 +            }
  16.129 +
  16.130 +            if (check)
  16.131 +                check = check->contained();
  16.132          }
  16.133  
  16.134          // Right now, any array is allowed on the LIFO heap. In case the
  16.135 @@ -299,6 +372,10 @@
  16.136              Type *right = visitForLoad(node->initialization());
  16.137              assert(TypeCheck(type, right));
  16.138          }
  16.139 +        if (type->primitive() == PrimitiveType_Char) {
  16.140 +            assert(false);
  16.141 +            return;
  16.142 +        }
  16.143      }
  16.144  
  16.145      node->variable()->setType(type);
  16.146 @@ -477,6 +554,20 @@
  16.147  }
  16.148  
  16.149  void
  16.150 +SemanticAnalysis::visit(StringLiteral *node)
  16.151 +{
  16.152 +    Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Char);
  16.153 +    if (!type)
  16.154 +        return;
  16.155 +
  16.156 +    type = Type::NewArray(ZONE(), type, node->string()->length() + 1, true);
  16.157 +    if (!type)
  16.158 +        return;
  16.159 +
  16.160 +    node->setType(type);
  16.161 +}
  16.162 +
  16.163 +void
  16.164  SemanticAnalysis::visit(FloatLiteral *node)
  16.165  {
  16.166      Type *type = ZONE()->types()->getPrimitive(PrimitiveType_Float);
    17.1 --- a/jitcraft/SemanticAnalysis.h	Sun Jul 01 11:25:36 2012 -0700
    17.2 +++ b/jitcraft/SemanticAnalysis.h	Sun Jul 01 14:52:57 2012 -0700
    17.3 @@ -63,6 +63,7 @@
    17.4      void visit(WhileStatement *node);
    17.5      void visit(BreakStatement *node);
    17.6      void visit(ContinueStatement *node);
    17.7 +    void visit(StringLiteral *node);
    17.8  };
    17.9  
   17.10  } // namespace jc
    18.1 --- a/jitcraft/Token.h	Sun Jul 01 11:25:36 2012 -0700
    18.2 +++ b/jitcraft/Token.h	Sun Jul 01 14:52:57 2012 -0700
    18.3 @@ -28,6 +28,7 @@
    18.4      _(NAME,               "<name>")                     \
    18.5      _(INTEGER_LITERAL,    "<integer>")                  \
    18.6      _(FLOAT_LITERAL,      "<float>")                    \
    18.7 +    _(STRING_LITERAL,     "<string>")                   \
    18.8      _(IF,                 "<if>")                       \
    18.9      _(ELSE,               "<else>")                     \
   18.10      _(ENUM,               "<enum>")                     \
    19.1 --- a/jitcraft/TypeManager.cpp	Sun Jul 01 11:25:36 2012 -0700
    19.2 +++ b/jitcraft/TypeManager.cpp	Sun Jul 01 14:52:57 2012 -0700
    19.3 @@ -36,6 +36,8 @@
    19.4          return false;
    19.5      if ((primitiveTypes_[PrimitiveType_Native] = Type::NewPrimitive(zone_, PrimitiveType_Native)) == NULL)
    19.6          return false;
    19.7 +    if ((primitiveTypes_[PrimitiveType_Char] = Type::NewPrimitive(zone_, "String")) == NULL)
    19.8 +        return false;
    19.9  
   19.10      for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
   19.11          if ((referenceTypes_[i] = Type::NewReference(zone_, primitiveTypes_[i])) == NULL)
   19.12 @@ -52,7 +54,8 @@
   19.13          return getPrimitive(PrimitiveType_Int32);
   19.14      if (strcmp(tag, "Float") == 0)
   19.15          return getPrimitive(PrimitiveType_Float);
   19.16 -    assert(!"tag cache");
   19.17 +    if (strcmp(tag, "String") == 0)
   19.18 +        return getPrimitive(PrimitiveType_Char);
   19.19      return NULL;
   19.20  }
   19.21  
   19.22 @@ -60,7 +63,7 @@
   19.23  TypeManager::unsafeArray(Type *contained, int elements)
   19.24  {
   19.25      // :TODO: cache this.
   19.26 -    return Type::NewUnsafeArray(zone_, contained, elements);
   19.27 +    return Type::NewArray(zone_, contained, elements, false);
   19.28  }
   19.29  
   19.30  Type *
    20.1 --- a/jitcraft/Types.cpp	Sun Jul 01 11:25:36 2012 -0700
    20.2 +++ b/jitcraft/Types.cpp	Sun Jul 01 14:52:57 2012 -0700
    20.3 @@ -35,6 +35,8 @@
    20.4  
    20.5      if (tag && strcmp(tag, "Float") == 0)
    20.6          type->primitive_ = PrimitiveType_Float;
    20.7 +    else if (tag && strcmp(tag, "String") == 0)
    20.8 +        type->primitive_ = PrimitiveType_Char;
    20.9      else
   20.10          type->primitive_ = PrimitiveType_Int32;
   20.11      return type;
   20.12 @@ -56,7 +58,7 @@
   20.13  }
   20.14  
   20.15  Type *
   20.16 -Type::NewUnsafeArray(Zone *zone, Type *contained, int elements)
   20.17 +Type::NewArray(Zone *zone, Type *contained, int elements, bool isConst)
   20.18  {
   20.19      Object *obj = zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old);
   20.20      if (!obj)
   20.21 @@ -71,6 +73,7 @@
   20.22          type->levels_ = 1;
   20.23      else
   20.24          type->levels_ = contained->levels() + 1;
   20.25 +    type->const_ = isConst;
   20.26      return type;
   20.27  }
   20.28  
    21.1 --- a/jitcraft/Types.h	Sun Jul 01 11:25:36 2012 -0700
    21.2 +++ b/jitcraft/Types.h	Sun Jul 01 14:52:57 2012 -0700
    21.3 @@ -27,7 +27,7 @@
    21.4  
    21.5  enum PrimitiveType
    21.6  {
    21.7 -    PrimitiveType_Int8,         // signed, 8-bit character
    21.8 +    PrimitiveType_Char,         // signed, 8-bit character
    21.9      PrimitiveType_Int32,        // signed, 32-bit integer
   21.10      PrimitiveType_Float,        // 32-bit IEEE-754 float
   21.11      PrimitiveType_Native,       // native-sized word
   21.12 @@ -40,8 +40,7 @@
   21.13          PRIMITIVE,
   21.14          ARRAY,
   21.15          REFERENCE,
   21.16 -        FUNCTION,
   21.17 -        CHAR
   21.18 +        FUNCTION
   21.19      };
   21.20  
   21.21    private:
   21.22 @@ -56,7 +55,7 @@
   21.23      // :TODO: use handles
   21.24      static Type *NewPrimitive(Zone *zone, Name *tag);
   21.25      static Type *NewPrimitive(Zone *zone, PrimitiveType type);
   21.26 -    static Type *NewUnsafeArray(Zone *zone, Type *contained, int elements);
   21.27 +    static Type *NewArray(Zone *zone, Type *contained, int elements, bool isConst);
   21.28      static Type *NewReference(Zone *zone, Type *contained);
   21.29      static Type *NewFunction(Zone *zone, Type *returnType, FixedArray *parameters);
   21.30  
   21.31 @@ -110,6 +109,15 @@
   21.32      bool isInt32() {
   21.33          return isPrimitive() && primitive() == PrimitiveType_Int32;
   21.34      }
   21.35 +    bool isCharArray() {
   21.36 +        return isArray() &&
   21.37 +               contained()->isPrimitive() &&
   21.38 +               contained()->primitive() == PrimitiveType_Char;
   21.39 +    }
   21.40 +    bool isConst() {
   21.41 +        assert(isArray());
   21.42 +        return const_;
   21.43 +    }
   21.44      Type *returnType() {
   21.45          assert(isFunction());
   21.46          return returnType_;
   21.47 @@ -127,6 +135,7 @@
   21.48      // Arrays only.
   21.49      int32 elements_;
   21.50      unsigned levels_;
   21.51 +    bool const_;
   21.52  
   21.53      // Arrays and references only.
   21.54      Barriered<Type> contained_;
    22.1 --- a/jitcraft/main.cpp	Sun Jul 01 11:25:36 2012 -0700
    22.2 +++ b/jitcraft/main.cpp	Sun Jul 01 14:52:57 2012 -0700
    22.3 @@ -80,12 +80,12 @@
    22.4  
    22.5      printf("\n ------------ \n\n");
    22.6  
    22.7 -    Disassemble(module->getFunction(1), stdout);
    22.8 +    Disassemble(module->getFunction(0), stdout);
    22.9      //Disassemble(module->getFunction(1), stdout);
   22.10  
   22.11      printf("\n ------------ \n\n");
   22.12  
   22.13 -    Code *main = module->getFunction(1);
   22.14 +    Code *main = module->getFunction(0);
   22.15  
   22.16      Top top = ZONE()->stack().begin();
   22.17      LocalTop localTop(top);
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/tests/prototype/string-1.sp	Sun Jul 01 14:52:57 2012 -0700
    23.3 @@ -0,0 +1,6 @@
    23.4 +main()
    23.5 +{
    23.6 +    new String:buffer[100] = "clam";
    23.7 +    buffer = "hedgehog";
    23.8 +    return buffer[3];
    23.9 +}