Implement dependent char arrays.
Implement dependent char arrays.
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 +