Skip to content

Commit

Permalink
Add object getters to obtain keys, values and pairs
Browse files Browse the repository at this point in the history
  • Loading branch information
James-Livesey committed Jul 1, 2024
1 parent 6d57843 commit 8ccd2b3
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 20 deletions.
95 changes: 85 additions & 10 deletions dist/libvoxel.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ voxel_ObjectItem* voxel_getObjectItem(voxel_Thing* thing, voxel_Thing* key);
VOXEL_ERRORABLE voxel_setObjectItem(voxel_Context* context, voxel_Thing* thing, voxel_Thing* key, voxel_Thing* value);
VOXEL_ERRORABLE voxel_removeObjectItem(voxel_Context* context, voxel_Thing* thing, voxel_Thing* key);
voxel_ObjectItemDescriptor* voxel_ensureObjectItemDescriptor(voxel_Context* context, voxel_ObjectItem* objectItem);
VOXEL_ERRORABLE voxel_addPrototypedObjectKeys(voxel_Context* context, voxel_Thing* thing, voxel_Thing* list, voxel_Count traverseDepth);
VOXEL_ERRORABLE voxel_getObjectKeys(voxel_Context* context, voxel_Thing* thing, voxel_Count traverseDepth);
voxel_Count voxel_getObjectLength(voxel_Thing* thing);
voxel_Thing* voxel_getObjectPrototypes(voxel_Context* context, voxel_Thing* thing);
voxel_Bool voxel_checkWhetherObjectInherits(voxel_Thing* thing, voxel_Thing* target, voxel_Count traverseDepth);
Expand Down Expand Up @@ -1308,6 +1310,27 @@ void voxel_builtins_core_getObjectLength(voxel_Executor* executor) {
voxel_unreferenceThing(executor->context, object);
}

void voxel_builtins_core_getObjectKeys(voxel_Executor* executor) {
voxel_Int argCount = voxel_popNumberInt(executor);
voxel_Thing* object = voxel_pop(executor);

if (!object || object->type != VOXEL_TYPE_OBJECT) {
return;
}

VOXEL_ERRORABLE keysResult = voxel_getObjectKeys(executor->context, object, VOXEL_MAX_PROTOTYPE_TRAVERSE_DEPTH);

if (VOXEL_IS_ERROR(keysResult)) {
return;
}

voxel_Thing* keys = keysResult.value;

voxel_push(executor, keys);

voxel_unreferenceThing(executor->context, object);
}

void voxel_builtins_core_getObjectPrototypes(voxel_Executor* executor) {
voxel_Int argCount = voxel_popNumberInt(executor);
voxel_Thing* object = voxel_pop(executor);
Expand Down Expand Up @@ -1945,6 +1968,7 @@ void voxel_builtins_core(voxel_Context* context) {
voxel_defineBuiltin(context, ".Ogs", &voxel_builtins_core_getObjectItemSetter);
voxel_defineBuiltin(context, ".Oss", &voxel_builtins_core_setObjectItemSetter);
voxel_defineBuiltin(context, ".Ol", &voxel_builtins_core_getObjectLength);
voxel_defineBuiltin(context, ".Ok", &voxel_builtins_core_getObjectKeys);
voxel_defineBuiltin(context, ".Op", &voxel_builtins_core_getObjectPrototypes);

voxel_defineBuiltin(context, ".L", &voxel_builtins_core_newList);
Expand Down Expand Up @@ -2416,13 +2440,8 @@ void voxel_lockThing(voxel_Thing* thing) {
thing->isLocked = VOXEL_TRUE;

switch (thing->type) {
case VOXEL_TYPE_OBJECT:
voxel_lockObject(thing);
break;

case VOXEL_TYPE_LIST:
voxel_lockList(thing);
break;
case VOXEL_TYPE_OBJECT: voxel_lockObject(thing); break;
case VOXEL_TYPE_LIST: voxel_lockList(thing); break;
}
}

Expand Down Expand Up @@ -3645,7 +3664,7 @@ voxel_ObjectItem* voxel_getPrototypedObjectItem(voxel_Thing* thing, voxel_Thing*

voxel_Thing* prototypesThing = object->prototypes;

if (prototypesThing == VOXEL_NULL) {
if (!prototypesThing) {
return VOXEL_NULL;
}

Expand Down Expand Up @@ -3795,10 +3814,66 @@ voxel_ObjectItemDescriptor* voxel_ensureObjectItemDescriptor(voxel_Context* cont
return descriptor;
}

voxel_Count voxel_getObjectLength(voxel_Thing* thing) {
VOXEL_ERRORABLE voxel_addPrototypedObjectKeys(voxel_Context* context, voxel_Thing* thing, voxel_Thing* list, voxel_Count traverseDepth) {
voxel_Object* object = (voxel_Object*)thing->value;
voxel_ObjectItem* currentItem = object->firstItem;

// TODO: Maybe include lengths of prototypes as part of total returned length
while (currentItem) {
voxel_List* listValue = (voxel_List*)list->value;
voxel_ListItem* currentListItem = listValue->firstItem;
voxel_Bool shouldPush = VOXEL_TRUE;

while (currentListItem) {
if (voxel_compareThings(currentListItem->value, currentItem->key)) {
shouldPush = VOXEL_FALSE;

break;
}

currentListItem = currentListItem->nextItem;
}

if (shouldPush) {
VOXEL_MUST(voxel_pushOntoList(context, list, currentItem->key));
}

currentItem = currentItem->nextItem;
}

if (traverseDepth == 0) {
return VOXEL_OK;
}

voxel_Thing* prototypesThing = object->prototypes;

if (!prototypesThing) {
return VOXEL_OK;
}

voxel_List* prototypesList = (voxel_List*)prototypesThing->value;
voxel_ListItem* currentPrototypeListItem = prototypesList->lastItem;

while (currentPrototypeListItem) {
VOXEL_MUST(voxel_addPrototypedObjectKeys(context, currentPrototypeListItem->value, list, traverseDepth - 1));

currentPrototypeListItem = currentPrototypeListItem->previousItem;
}

return VOXEL_OK;
}

VOXEL_ERRORABLE voxel_getObjectKeys(voxel_Context* context, voxel_Thing* thing, voxel_Count traverseDepth) {
voxel_Thing* list = voxel_newList(context);

voxel_addPrototypedObjectKeys(context, thing, list, traverseDepth);

list->isLocked = VOXEL_TRUE; // Shallow only

return VOXEL_OK_RET(list);
}

voxel_Count voxel_getObjectLength(voxel_Thing* thing) {
voxel_Object* object = (voxel_Object*)thing->value;

return object->length;
}
Expand Down
1 change: 1 addition & 0 deletions src/builtins/core/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ void voxel_builtins_core(voxel_Context* context) {
voxel_defineBuiltin(context, ".Ogs", &voxel_builtins_core_getObjectItemSetter);
voxel_defineBuiltin(context, ".Oss", &voxel_builtins_core_setObjectItemSetter);
voxel_defineBuiltin(context, ".Ol", &voxel_builtins_core_getObjectLength);
voxel_defineBuiltin(context, ".Ok", &voxel_builtins_core_getObjectKeys);
voxel_defineBuiltin(context, ".Op", &voxel_builtins_core_getObjectPrototypes);

voxel_defineBuiltin(context, ".L", &voxel_builtins_core_newList);
Expand Down
21 changes: 21 additions & 0 deletions src/builtins/core/objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,27 @@ void voxel_builtins_core_getObjectLength(voxel_Executor* executor) {
voxel_unreferenceThing(executor->context, object);
}

void voxel_builtins_core_getObjectKeys(voxel_Executor* executor) {
voxel_Int argCount = voxel_popNumberInt(executor);
voxel_Thing* object = voxel_pop(executor);

if (!object || object->type != VOXEL_TYPE_OBJECT) {
return;
}

VOXEL_ERRORABLE keysResult = voxel_getObjectKeys(executor->context, object, VOXEL_MAX_PROTOTYPE_TRAVERSE_DEPTH);

if (VOXEL_IS_ERROR(keysResult)) {
return;
}

voxel_Thing* keys = keysResult.value;

voxel_push(executor, keys);

voxel_unreferenceThing(executor->context, object);
}

void voxel_builtins_core_getObjectPrototypes(voxel_Executor* executor) {
voxel_Int argCount = voxel_popNumberInt(executor);
voxel_Thing* object = voxel_pop(executor);
Expand Down
2 changes: 2 additions & 0 deletions src/declarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ voxel_ObjectItem* voxel_getObjectItem(voxel_Thing* thing, voxel_Thing* key);
VOXEL_ERRORABLE voxel_setObjectItem(voxel_Context* context, voxel_Thing* thing, voxel_Thing* key, voxel_Thing* value);
VOXEL_ERRORABLE voxel_removeObjectItem(voxel_Context* context, voxel_Thing* thing, voxel_Thing* key);
voxel_ObjectItemDescriptor* voxel_ensureObjectItemDescriptor(voxel_Context* context, voxel_ObjectItem* objectItem);
VOXEL_ERRORABLE voxel_addPrototypedObjectKeys(voxel_Context* context, voxel_Thing* thing, voxel_Thing* list, voxel_Count traverseDepth);
VOXEL_ERRORABLE voxel_getObjectKeys(voxel_Context* context, voxel_Thing* thing, voxel_Count traverseDepth);
voxel_Count voxel_getObjectLength(voxel_Thing* thing);
voxel_Thing* voxel_getObjectPrototypes(voxel_Context* context, voxel_Thing* thing);
voxel_Bool voxel_checkWhetherObjectInherits(voxel_Thing* thing, voxel_Thing* target, voxel_Count traverseDepth);
Expand Down
62 changes: 59 additions & 3 deletions src/objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ voxel_ObjectItem* voxel_getPrototypedObjectItem(voxel_Thing* thing, voxel_Thing*

voxel_Thing* prototypesThing = object->prototypes;

if (prototypesThing == VOXEL_NULL) {
if (!prototypesThing) {
return VOXEL_NULL;
}

Expand Down Expand Up @@ -319,10 +319,66 @@ voxel_ObjectItemDescriptor* voxel_ensureObjectItemDescriptor(voxel_Context* cont
return descriptor;
}

voxel_Count voxel_getObjectLength(voxel_Thing* thing) {
VOXEL_ERRORABLE voxel_addPrototypedObjectKeys(voxel_Context* context, voxel_Thing* thing, voxel_Thing* list, voxel_Count traverseDepth) {
voxel_Object* object = (voxel_Object*)thing->value;
voxel_ObjectItem* currentItem = object->firstItem;

while (currentItem) {
voxel_List* listValue = (voxel_List*)list->value;
voxel_ListItem* currentListItem = listValue->firstItem;
voxel_Bool shouldPush = VOXEL_TRUE;

while (currentListItem) {
if (voxel_compareThings(currentListItem->value, currentItem->key)) {
shouldPush = VOXEL_FALSE;

break;
}

currentListItem = currentListItem->nextItem;
}

if (shouldPush) {
VOXEL_MUST(voxel_pushOntoList(context, list, currentItem->key));
}

currentItem = currentItem->nextItem;
}

if (traverseDepth == 0) {
return VOXEL_OK;
}

voxel_Thing* prototypesThing = object->prototypes;

// TODO: Maybe include lengths of prototypes as part of total returned length
if (!prototypesThing) {
return VOXEL_OK;
}

voxel_List* prototypesList = (voxel_List*)prototypesThing->value;
voxel_ListItem* currentPrototypeListItem = prototypesList->lastItem;

while (currentPrototypeListItem) {
VOXEL_MUST(voxel_addPrototypedObjectKeys(context, currentPrototypeListItem->value, list, traverseDepth - 1));

currentPrototypeListItem = currentPrototypeListItem->previousItem;
}

return VOXEL_OK;
}

VOXEL_ERRORABLE voxel_getObjectKeys(voxel_Context* context, voxel_Thing* thing, voxel_Count traverseDepth) {
voxel_Thing* list = voxel_newList(context);

voxel_addPrototypedObjectKeys(context, thing, list, traverseDepth);

list->isLocked = VOXEL_TRUE; // Shallow only

return VOXEL_OK_RET(list);
}

voxel_Count voxel_getObjectLength(voxel_Thing* thing) {
voxel_Object* object = (voxel_Object*)thing->value;

return object->length;
}
Expand Down
9 changes: 2 additions & 7 deletions src/things.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,8 @@ void voxel_lockThing(voxel_Thing* thing) {
thing->isLocked = VOXEL_TRUE;

switch (thing->type) {
case VOXEL_TYPE_OBJECT:
voxel_lockObject(thing);
break;

case VOXEL_TYPE_LIST:
voxel_lockList(thing);
break;
case VOXEL_TYPE_OBJECT: voxel_lockObject(thing); break;
case VOXEL_TYPE_LIST: voxel_lockList(thing); break;
}
}

Expand Down
36 changes: 36 additions & 0 deletions stdlib/core.vxl
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,42 @@ function getProperty(thing, property) {
return syscall Ol(thing);
}

if (#usedprop(keys) &&& property == #prop(keys) &&& value == null) {
return syscall Ok(thing);
}

if (#usedprop(values) &&& property == #prop(values) &&& value == null) {
var values = [];
var keys = syscall Ok(thing);
var length = syscall Ll(keys);

for (var i = 0; i < length; i++) {
syscall Lu(thing[keys[i]], values);
}

syscall io_out(values);
syscall io_out("\n");

return values;
}

if (#usedprop(pairs) &&& property == #prop(pairs) &&& value == null) {
var pairs = [];
var keys = syscall Ok(thing);
var length = syscall Ll(keys);

for (var i = 0; i < length; i++) {
var key = keys[i];

syscall Lu({key: key, value: thing[key]}, pairs);
}

syscall io_out(pairs);
syscall io_out("\n");

return pairs;
}

if (#usedprop(prototypes) &&& property == #prop(prototypes) &&& value == null) {
return syscall Op(thing);
}
Expand Down
5 changes: 5 additions & 0 deletions test/objects/expected.log
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ Set existing property value: {"key":456,"nestedObject":{"key1":"value1","key2":"
Set new property value: {"key":456,"nestedObject":{"key1":"value1","key2":"value2","anotherNestedObject":{"key":"value"}},"list":["a","b","c"],"quoted key value":true,"newKey":789}
Set existing property value using property accessor: {"key":321,"nestedObject":{"key1":"value1","key2":"value2","anotherNestedObject":{"key":"value"}},"list":["a","b","c"],"quoted key value":true,"newKey":789}
Get object length: 5
Get object keys: key,nestedObject,list,quoted key value,newKey
Get object values: 321,{"key1":"value1","key2":"value2","anotherNestedObject":{"key":"value"}},a,b,c,true,789
321,{"key1":"value1","key2":"value2","anotherNestedObject":{"key":"value"}},a,b,c,true,789
Get object pairs: {"key":"key","value":321},{"key":"nestedObject","value":{"key1":"value1","key2":"value2","anotherNestedObject":{"key":"value"}}},{"key":"list","value":["a","b","c"]},{"key":"quoted key value","value":true},{"key":"newKey","value":789}
{"key":"key","value":321},{"key":"nestedObject","value":{"key1":"value1","key2":"value2","anotherNestedObject":{"key":"value"}}},{"key":"list","value":["a","b","c"]},{"key":"quoted key value","value":true},{"key":"newKey","value":789}
Removing nested object: {"key":321,"list":["a","b","c"],"quoted key value":true,"newKey":789}
Get value using property accessor on mangled object: key = 123
Set value using property accessor on mangled object: key = 456
Expand Down
14 changes: 14 additions & 0 deletions test/objects/main.vxl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ syscall io_out("Get object length: ");
syscall io_out(object.length);
syscall io_out("\n");

syscall io_out("Get object keys: ");
syscall io_out(object.keys);
syscall io_out("\n");

syscall io_out("Get object values: ");
syscall io_out(object.values);
syscall io_out("\n");

{retain key: null, retain value: null};

syscall io_out("Get object pairs: ");
syscall io_out(object.pairs);
syscall io_out("\n");

syscall Or(object, "nestedObject");

syscall io_out("Removing nested object: ");
Expand Down

0 comments on commit 8ccd2b3

Please sign in to comment.