Skip to content

Commit

Permalink
#14 Iterator support for collections of references
Browse files Browse the repository at this point in the history
Fixes #14
  • Loading branch information
SanderMertens committed Mar 23, 2015
1 parent acfb9e6 commit a1ae49a
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 86 deletions.
16 changes: 11 additions & 5 deletions dev/src/cx_ic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -589,17 +591,21 @@ 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));
cx_icStorage_init((cx_icStorage)result, program, line, CX_STORAGE_ELEMENT, name, 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);
}

Expand Down
131 changes: 73 additions & 58 deletions dev/src/cx_ic_assemble.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions interface/fast/src/Fast_DynamicInitializer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
16 changes: 11 additions & 5 deletions interface/fast/src/Fast_Initializer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
Expand Down Expand Up @@ -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++;
}
Expand Down
5 changes: 4 additions & 1 deletion interface/fast/src/Fast_Object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions interface/fast/src/Fast_StaticInitializer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 7 additions & 7 deletions interface/fast/src/Fast_Unary.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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),
Expand Down
35 changes: 25 additions & 10 deletions test/language/tc_iterator01.cx
Original file line number Diff line number Diff line change
@@ -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"
34 changes: 34 additions & 0 deletions test/language/tc_iterator02.cx
Original file line number Diff line number Diff line change
@@ -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"

0 comments on commit a1ae49a

Please sign in to comment.