From a1ae49a4e268ebb553e2a9d474b93560a6896cda Mon Sep 17 00:00:00 2001 From: SanderMertens Date: Sun, 22 Mar 2015 23:41:23 -0400 Subject: [PATCH] #14 Iterator support for collections of references Fixes #14 --- dev/src/cx_ic.c | 16 ++- dev/src/cx_ic_assemble.c | 131 +++++++++++-------- interface/fast/src/Fast_DynamicInitializer.c | 3 + interface/fast/src/Fast_Initializer.c | 16 ++- interface/fast/src/Fast_Object.c | 5 +- interface/fast/src/Fast_StaticInitializer.c | 3 + interface/fast/src/Fast_Unary.c | 14 +- test/language/tc_iterator01.cx | 35 +++-- test/language/tc_iterator02.cx | 34 +++++ 9 files changed, 171 insertions(+), 86 deletions(-) create mode 100644 test/language/tc_iterator02.cx diff --git a/dev/src/cx_ic.c b/dev/src/cx_ic.c index 5cda261a..af1c444b 100644 --- a/dev/src/cx_ic.c +++ b/dev/src/cx_ic.c @@ -570,12 +570,14 @@ cx_icAccumulator cx_icAccumulator__create(cx_icProgram program, cx_uint32 line, cx_icMember cx_icMember__create(cx_icProgram program, cx_uint32 line, cx_icStorage base, cx_member member) { cx_icMember result; cx_id name; + cx_type t; sprintf(name, "%s.%s", base->name, cx_nameof(member)); + t = member->type; if (!(result = (cx_icMember)cx_icProgram_lookupStorage(program, name, TRUE))) { result = cx_calloc(sizeof(cx_icMember_s)); - cx_icStorage_init((cx_icStorage)result, program, line, CX_STORAGE_MEMBER, name, member->type); + cx_icStorage_init((cx_icStorage)result, program, line, CX_STORAGE_MEMBER, name, t); result->base = base; result->member = member; cx_llAppend(program->scope->storages, result); @@ -589,9 +591,13 @@ cx_icElement cx_icElement__create(cx_icProgram program, cx_uint32 line, cx_type cx_id name; cx_string elemStr; - elemStr = cx_icValue_toString(index, NULL); - sprintf(name, "%s[%s]", base->name, elemStr); - cx_dealloc(elemStr); + if (index) { + elemStr = cx_icValue_toString(index, NULL); + sprintf(name, "%s[%s]", base->name, elemStr); + cx_dealloc(elemStr); + } else { + sprintf(name, "*%s", base->name); + } if (!(result = (cx_icElement)cx_icProgram_lookupStorage(program, name, TRUE))) { result = cx_calloc(sizeof(cx_icElement_s)); @@ -599,7 +605,7 @@ cx_icElement cx_icElement__create(cx_icProgram program, cx_uint32 line, cx_type result->base = base; result->index = index; result->collectionType = (cx_collection)base->type; - result->dynamic = !(index->_parent.kind == CX_IC_LITERAL); + result->dynamic = !index || !(index->_parent.kind == CX_IC_LITERAL); cx_llAppend(program->scope->storages, result); } diff --git a/dev/src/cx_ic_assemble.c b/dev/src/cx_ic_assemble.c index 2223e09c..f02c761b 100644 --- a/dev/src/cx_ic_assemble.c +++ b/dev/src/cx_ic_assemble.c @@ -444,8 +444,13 @@ static cx_ic_vmStorage *cx_ic_vmStorageNew(cx_ic_vmProgram *program, cx_icStorag if (element->base) { result->base = cx_ic_vmStorageGet(program, element->base); + /* Iterator elements are a special case throuhg which access to the current member + * is granted */ + if (element->base->type->kind == CX_ITERATOR) { + result->dynamic = TRUE; + /* If element is an array and index-expression is a literal, offset is determined at compile-time. */ - if (element->index->_parent.kind == CX_IC_LITERAL) { + } else if (element->index->_parent.kind == CX_IC_LITERAL) { if (element->collectionType->kind == CX_ARRAY) { cx_uint32 index = ((cx_icLiteral)element->index)->value.is.literal.v._unsigned_integer; result->offset = index * cx_type_sizeof(element->collectionType->elementType); @@ -464,7 +469,7 @@ static cx_ic_vmStorage *cx_ic_vmStorageNew(cx_ic_vmProgram *program, cx_icStorag result->offset += result->base->offset; - if (!result->base->dynamic && result->base->base) { + if (!result->base->dynamic && result->base->base) { result->base = result->base->base; } } @@ -1154,45 +1159,53 @@ OPS_EXP_EXT(GETOP, TYPE,) static cx_vmOp *cx_ic_vmStorageAssembleElement(cx_icStorage storage, cx_ic_vmProgram *program, cx_vmOp *vmOp, cx_icStorage topLevelStorage) { - cx_ic_vmOperand indexKind; - cx_icValue icElementSize; - cx_collection type = cx_collection(((cx_icElement)storage)->base->type); /* Obtain collectiontype */ - cx_value elementSizeValue; - cx_uint64 elementSize; + cx_type type = ((cx_icElement)storage)->base->type; /* Obtain kind for index */ - indexKind = cx_ic_getVmOperand(program, CX_IC_DEREF_VALUE, ((cx_icElement)storage)->index); - - /* Create value for elementSize */ - elementSize = cx_type_sizeof(type->elementType); - cx_valueLiteralInit(&elementSizeValue, CX_LITERAL_UNSIGNED_INTEGER, &elementSize); - icElementSize = (cx_icValue)cx_icLiteral__create(program->icProgram, ((cx_ic)storage)->line, elementSizeValue, (cx_type)cx_uint32_o); - - switch(type->kind) { - case CX_ARRAY: - vmOp->op = cx_ic_getVmELEMA(cx_type(type), CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); - cx_ic_vmSetOp3Addr(program, vmOp, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, CX_IC_VMOPERAND_V, (cx_icValue)topLevelStorage, ((cx_icElement)storage)->index, icElementSize); - break; - case CX_SEQUENCE: - vmOp->op = cx_ic_getVmELEMS(cx_type(type), CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); - cx_ic_vmSetOp3Addr(program, vmOp, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, CX_IC_VMOPERAND_V, (cx_icValue)topLevelStorage, ((cx_icElement)storage)->index, icElementSize); - break; - case CX_LIST: - if (cx_collection_elementRequiresAlloc(type)) { - vmOp->op = cx_ic_getVmELEML(cx_type(type), CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); - } else { - vmOp->op = cx_ic_getVmELEMLX(cx_type(type), CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); - } - cx_ic_vmSetOp2Addr(program, vmOp, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, (cx_icValue)topLevelStorage, ((cx_icElement)storage)->index); - break; - case CX_MAP: - if (cx_collection_elementRequiresAlloc(type)) { - vmOp->op = cx_ic_getVmELEMM(cx_type(type), CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); - } else { - vmOp->op = cx_ic_getVmELEMMX(cx_type(type), CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); + if (type->kind == CX_ITERATOR) { + cx_ic_vmOperand baseKind = cx_ic_getVmOperand(program, CX_IC_DEREF_VALUE, (cx_icValue)((cx_icElement)storage)->base); + vmOp->op = cx_ic_getVmSET(type, CX_IC_VMTYPE_D, CX_IC_VMOPERAND_R, baseKind, 0); + cx_ic_vmSetOp2Addr(program, vmOp, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, baseKind, + (cx_icValue)topLevelStorage, (cx_icValue)((cx_icElement)storage)->base); + + }else if (type->kind == CX_COLLECTION) { + cx_icValue icElementSize; + cx_value elementSizeValue; + cx_uint64 elementSize; + cx_collection collection = cx_collection(type); + cx_ic_vmOperand indexKind = cx_ic_getVmOperand(program, CX_IC_DEREF_VALUE, ((cx_icElement)storage)->index); + + /* Create value for elementSize */ + elementSize = cx_type_sizeof(collection->elementType); + cx_valueLiteralInit(&elementSizeValue, CX_LITERAL_UNSIGNED_INTEGER, &elementSize); + icElementSize = (cx_icValue)cx_icLiteral__create(program->icProgram, ((cx_ic)storage)->line, elementSizeValue, (cx_type)cx_uint32_o); + + switch(collection->kind) { + case CX_ARRAY: + vmOp->op = cx_ic_getVmELEMA(type, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); + cx_ic_vmSetOp3Addr(program, vmOp, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, CX_IC_VMOPERAND_V, (cx_icValue)topLevelStorage, ((cx_icElement)storage)->index, icElementSize); + break; + case CX_SEQUENCE: + vmOp->op = cx_ic_getVmELEMS(type, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); + cx_ic_vmSetOp3Addr(program, vmOp, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, CX_IC_VMOPERAND_V, (cx_icValue)topLevelStorage, ((cx_icElement)storage)->index, icElementSize); + break; + case CX_LIST: + if (cx_collection_elementRequiresAlloc(collection)) { + vmOp->op = cx_ic_getVmELEML(type, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); + } else { + vmOp->op = cx_ic_getVmELEMLX(type, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); + } + cx_ic_vmSetOp2Addr(program, vmOp, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, (cx_icValue)topLevelStorage, ((cx_icElement)storage)->index); + break; + case CX_MAP: + if (cx_collection_elementRequiresAlloc(collection)) { + vmOp->op = cx_ic_getVmELEMM(type, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); + } else { + vmOp->op = cx_ic_getVmELEMMX(type, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, 0); + } + cx_ic_vmSetOp2Addr(program, vmOp, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, (cx_icValue)topLevelStorage, ((cx_icElement)storage)->index); + break; } - cx_ic_vmSetOp2Addr(program, vmOp, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, indexKind, (cx_icValue)topLevelStorage, ((cx_icElement)storage)->index); - break; } return cx_vmProgram_addOp(program->program, ((cx_ic)storage)->line); @@ -1257,30 +1270,32 @@ static cx_vmOp *cx_ic_vmStorageAssembleNested(cx_icStorage icStorage, cx_ic_vmPr * is dynamic the address will be calculated at runtime. */ if (storage->dynamic || cx_ic_isReference(storage->base->accumulator)) { /* If the base is an object store the address in the accumulator */ - if (base->kind == CX_STORAGE_OBJECT) { - vmOp->op = sizeof(intptr_t) == 4 ? CX_VM_SET_LRV : CX_VM_SET_DRV; - cx_ic_vmStorageAddReferee(program, topLevelStorage, &vmOp->ic.b._1); - vmOp->lo.w = (intptr_t)((cx_icObject)base)->ptr; - if (storage->offset) { - vmOp->lo.w += storage->offset; - } - vmOp = cx_vmProgram_addOp(program->program, ((cx_ic)icStorage)->line); - - /* If the base is a local store the address of the local in the accumulator */ - } else if (base->kind == CX_STORAGE_LOCAL) { - if (!cx_ic_isReference(storage->base->accumulator)) { - vmOp->op = cx_ic_getVmSETX(NULL, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, CX_IC_VMOPERAND_R, 0); + if (base->type->kind != CX_ITERATOR) { + if (base->kind == CX_STORAGE_OBJECT) { + vmOp->op = sizeof(intptr_t) == 4 ? CX_VM_SET_LRV : CX_VM_SET_DRV; cx_ic_vmStorageAddReferee(program, topLevelStorage, &vmOp->ic.b._1); - vmOp->ic.b._2 = storage->base->addr; + vmOp->lo.w = (intptr_t)((cx_icObject)base)->ptr; if (storage->offset) { - vmOp->ic.b._2 += storage->offset; + vmOp->lo.w += storage->offset; } vmOp = cx_vmProgram_addOp(program->program, ((cx_ic)icStorage)->line); - } else { - vmOp->op = sizeof(intptr_t) == 4 ? CX_VM_SET_LRR : CX_VM_SET_DRR; - cx_ic_vmStorageAddReferee(program, topLevelStorage, &vmOp->ic.b._1); - vmOp->ic.b._2 = storage->base->addr; - vmOp = cx_vmProgram_addOp(program->program, ((cx_ic)icStorage)->line); + + /* If the base is a local store the address of the local in the accumulator */ + } else if (base->kind == CX_STORAGE_LOCAL) { + if (!cx_ic_isReference(storage->base->accumulator)) { + vmOp->op = cx_ic_getVmSETX(NULL, CX_IC_VMTYPE_W, CX_IC_VMOPERAND_R, CX_IC_VMOPERAND_R, 0); + cx_ic_vmStorageAddReferee(program, topLevelStorage, &vmOp->ic.b._1); + vmOp->ic.b._2 = storage->base->addr; + if (storage->offset) { + vmOp->ic.b._2 += storage->offset; + } + vmOp = cx_vmProgram_addOp(program->program, ((cx_ic)icStorage)->line); + } else { + vmOp->op = sizeof(intptr_t) == 4 ? CX_VM_SET_LRR : CX_VM_SET_DRR; + cx_ic_vmStorageAddReferee(program, topLevelStorage, &vmOp->ic.b._1); + vmOp->ic.b._2 = storage->base->addr; + vmOp = cx_vmProgram_addOp(program->program, ((cx_ic)icStorage)->line); + } } } diff --git a/interface/fast/src/Fast_DynamicInitializer.c b/interface/fast/src/Fast_DynamicInitializer.c index 486b7194..9da8a885 100644 --- a/interface/fast/src/Fast_DynamicInitializer.c +++ b/interface/fast/src/Fast_DynamicInitializer.c @@ -49,6 +49,9 @@ Fast_Expression Fast_Initializer_expr(Fast_DynamicInitializer _this, cx_uint8 va case CX_PRIMITIVE: result = base; break; + case CX_ITERATOR: + result = base; + break; case CX_COMPOSITE: if (fp) { Fast_String memberString = Fast_String__create(cx_nameof(thisFrame->member)); diff --git a/interface/fast/src/Fast_Initializer.c b/interface/fast/src/Fast_Initializer.c index 15fce50a..558482fe 100644 --- a/interface/fast/src/Fast_Initializer.c +++ b/interface/fast/src/Fast_Initializer.c @@ -130,7 +130,8 @@ cx_type Fast_Parser_initGetType(Fast_Initializer _this, cx_member *m_out) { } else { if (m_out) { cx_id id; - Fast_Parser_error(yparser(), "too many elements for non-composite\\collection type '%s'", Fast_Parser_id(t, id)); + Fast_Parser_error(yparser(), + "too many elements for non-composite\\collection type '%s'", Fast_Parser_id(t, id)); result = NULL; } } @@ -181,7 +182,8 @@ cx_int16 Fast_Initializer_construct(Fast_Initializer _this) { #ifdef CX_INIT_DEBUG { cx_id id, id2; - printf("%*s%d[%s %p]: construct (type=%s)\n", indent, " ", yparser()->line, Fast_Parser_id(cx_typeof(_this), id), _this, Fast_Parser_id(t, id2)); + printf("%*s%d[%s %p]: construct (type=%s)\n", + indent, " ", yparser()->line, Fast_Parser_id(cx_typeof(_this), id), _this, Fast_Parser_id(t, id2)); indent++; } #endif @@ -319,7 +321,8 @@ cx_int16 Fast_Initializer_next_v(Fast_Initializer _this) { { cx_id id, id2; printf("%*s%d[%s %p]: next(fp=%d, location=%d, type=%s, member=%s)\n", - indent, " ", yparser()->line, Fast_Parser_id(cx_typeof(_this), id), _this, _this->fp, _this->frames[_this->fp].location, + indent, " ", yparser()->line, Fast_Parser_id(cx_typeof(_this), id), _this, _this->fp, + _this->frames[_this->fp].location, _this->frames[_this->fp].type?Fast_Parser_id(_this->frames[_this->fp].type, id2):NULL, _this->frames[_this->fp].member?cx_nameof(_this->frames[_this->fp].member):NULL); } @@ -340,7 +343,9 @@ cx_int8 Fast_Initializer_pop_v(Fast_Initializer _this) { { cx_id id; indent--; - printf("%*s%d[%s %p]: pop(fp=%d, location=%d)\n", indent, " ", yparser()->line, Fast_Parser_id(cx_typeof(_this), id), _this, _this->fp, _this->frames[_this->fp].location); + printf("%*s%d[%s %p]: pop(fp=%d, location=%d)\n", + indent, " ", yparser()->line, + Fast_Parser_id(cx_typeof(_this), id), _this, _this->fp, _this->frames[_this->fp].location); } #endif Fast_Initializer_next(_this); @@ -373,7 +378,8 @@ cx_int16 Fast_Initializer_push_v(Fast_Initializer _this) { cx_id id, id2; printf("%*s%d[%s %p]: push(fp=%d, location=%d, type=%s, member=%s)\n", indent, " ", yparser()->line, Fast_Parser_id(cx_typeof(_this), id), _this, _this->fp, - _this->frames[_this->fp].location, _this->frames[_this->fp].type?Fast_Parser_id(_this->frames[_this->fp].type, id2):NULL, + _this->frames[_this->fp].location, + _this->frames[_this->fp].type ? Fast_Parser_id(_this->frames[_this->fp].type, id2) : NULL, _this->frames[_this->fp].member?cx_nameof(_this->frames[_this->fp].member):NULL); indent++; } diff --git a/interface/fast/src/Fast_Object.c b/interface/fast/src/Fast_Object.c index 3027ecff..84f08ba0 100644 --- a/interface/fast/src/Fast_Object.c +++ b/interface/fast/src/Fast_Object.c @@ -66,7 +66,10 @@ cx_int16 Fast_Object_serialize(Fast_Object _this, cx_type dstType, cx_word dst) dstIsDelegate = TRUE; } - if (dstIsDelegate) { + /* Handle iterators */ + if ((dstType->kind == CX_ITERATOR) && (srcType->kind == CX_COLLECTION)) { + cx_iterator_set((void*)dst, obj, cx_collection(srcType)); + } else if (dstIsDelegate) { if (srcIsDelegate) { cx_value vDst, vSrc; cx_valueValueInit(&vDst, NULL, cx_type(dstType), (void *)dst); diff --git a/interface/fast/src/Fast_StaticInitializer.c b/interface/fast/src/Fast_StaticInitializer.c index c2bb3e5d..38b240cd 100644 --- a/interface/fast/src/Fast_StaticInitializer.c +++ b/interface/fast/src/Fast_StaticInitializer.c @@ -46,6 +46,9 @@ cx_word Fast_Initializer_offset(Fast_StaticInitializer _this, cx_uint32 variable result = base; } break; + case CX_ITERATOR: + result = base; + break; case CX_COLLECTION: { if (fp) { cx_uint32 elementSize = cx_type_sizeof(cx_collection(frame->type)->elementType); diff --git a/interface/fast/src/Fast_Unary.c b/interface/fast/src/Fast_Unary.c index fc2cb144..aacf8151 100644 --- a/interface/fast/src/Fast_Unary.c +++ b/interface/fast/src/Fast_Unary.c @@ -62,6 +62,7 @@ cx_ic Fast_Unary_toIc_v(Fast_Unary _this, cx_icProgram program, cx_icStorage sto cx_icStorage result; cx_ic lvalue; cx_icOp op; + cx_type lvalueType = Fast_Expression_getType(_this->lvalue); CX_UNUSED(stored); if (storage) { @@ -85,14 +86,13 @@ cx_ic Fast_Unary_toIc_v(Fast_Unary _this, cx_icProgram program, cx_icStorage sto cx_icProgram_addIc(program, (cx_ic)op); result = (cx_icStorage)lvalue; break; - case CX_MUL: - op = cx_icOp__create( - program, Fast_Node(_this)->line, CX_IC_SET, - NULL, (cx_icValue)result, (cx_icValue)lvalue); - cx_icProgram_addIc(program, (cx_ic)op); - op->s2Deref = CX_IC_DEREF_ADDRESS; - ((cx_icStorage)result)->isReference = TRUE; + case CX_MUL: { + /* Create an element with the iterator as base */ + result = + (cx_icStorage)cx_icElement__create( + program, Fast_Node(_this)->line, cx_iterator(lvalueType)->elementType, (cx_icStorage)lvalue, NULL); break; + } default: op = cx_icOp__create( program, Fast_Node(_this)->line, cx_icOpKindFromOperator(_this->operator), diff --git a/test/language/tc_iterator01.cx b/test/language/tc_iterator01.cx index 02edcc7d..06309067 100644 --- a/test/language/tc_iterator01.cx +++ b/test/language/tc_iterator01.cx @@ -1,17 +1,32 @@ -// Iterator assignments - -bool result : true +bool result: true void fail(string msg): "tc_iterator01: FAIL: $msg" result = false -array sarray: string, 1 -sarray array1: "a" +array{int32, 3} intArray: 1, 2, 3 +sequence{int32} intSeq: 2, 3, 4 +list{int32} intList: 3, 4, 5 + +iterator{int32} a : intArray +iterator{int32} b : intSeq +iterator{int32} c : intList + +var int32 total +while a++: total += *a +if total != 6: fail("total != 6 (array)") + +total = 0 +while b++: total += *b +if total != 9: fail("total != 9 (sequence)") -iterator siter: string -siter iter1 -iter1 = array1 +total = 0 +while c++: total += *c +if total != 12: fail("total != 12 (list)") -iter1++ +// Reassign iterator +a = intSeq +total = 0 +while a++: total += *a +if total != 9: fail("total != 6 (sequence #2)") -if result: "$testname: OK" +if result: "tc_iterator01: OK" diff --git a/test/language/tc_iterator02.cx b/test/language/tc_iterator02.cx new file mode 100644 index 00000000..3a1ac603 --- /dev/null +++ b/test/language/tc_iterator02.cx @@ -0,0 +1,34 @@ +bool result: true +void fail(string msg): + "tc_iterator02: FAIL: $msg" + result = false + +struct Point:: x, y: int32 + +array{Point, 3} pArray: {1, 2}, {3, 4}, {5, 6} +sequence{Point} pSeq: {3, 4}, {5, 6}, {7, 8} +list{Point} pList: {5, 6}, {7, 8}, {9, 10} + +iterator{Point} a : pArray +iterator{Point} b : pSeq +iterator{Point} c : pList + +var Point total +while a++: total[x, y] += *a[x, y] +if total[x, y] != (9, 12): fail("total[x, y] != (9, 12) (array)") + +total = {0, 0} +while b++: total[x, y] += *b[x, y] +if total[x, y] != (15, 18): fail("total[x, y] != (15, 18) (sequence)") + +total = {0, 0} +while c++: total[x, y] += *c[x, y] +if total[x, y] != (21, 24): fail("total[x, y] != (21, 24) (list)") + +// Reassign iterator +a = pSeq +total = {0, 0} +while a++: total[x, y] += *a[x, y] +if total[x, y] != (15, 18): fail("total[x, y] != (15, 18) (sequence #2)") + +if result: "tc_iterator02: OK"