diff --git a/source/toy_attributes.c b/source/toy_attributes.c index 42c10ab..c999af5 100644 --- a/source/toy_attributes.c +++ b/source/toy_attributes.c @@ -6,9 +6,12 @@ #include #include +//if set, used for delegating to user-defined code +static Toy_OpaqueAttributeHandler opaqueAttributeCallback = NULL; + //NOTE: there is no need to call 'Toy_freeValue' on the arguments, as the VM assumes you don't -Toy_Value handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { +Toy_Value Toy_private_handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "length", 6) == 0) { return TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_STRING(compound)->info.length); } @@ -144,7 +147,7 @@ static void attr_arraySort(Toy_VM* vm) { //URGENT: attr_arraySort } -Toy_Value handleArrayAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { +Toy_Value Toy_private_handleArrayAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "length", 6) == 0) { return TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_ARRAY(compound)->count); } @@ -220,23 +223,23 @@ static void attr_tableForEach(Toy_VM* vm) { //URGENT: attr_tableForEach } -Toy_Value handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { +Toy_Value Toy_private_handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "length", 6) == 0) { return TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_ARRAY(compound)->count); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "insert", 4) == 0) { + else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "insert", 6) == 0) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_tableInsert); return TOY_VALUE_FROM_FUNCTION(fn); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "hasKey", 4) == 0) { + else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "hasKey", 6) == 0) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_tableHasKey); return TOY_VALUE_FROM_FUNCTION(fn); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "remove", 4) == 0) { + else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "remove", 6) == 0) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_tableRemove); return TOY_VALUE_FROM_FUNCTION(fn); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "forEach", 4) == 0) { + else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "forEach", 7) == 0) { //BUG: compare the contents AND length of these strings Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_tableForEach); return TOY_VALUE_FROM_FUNCTION(fn); } @@ -246,4 +249,19 @@ Toy_Value handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attrib Toy_error(buffer); return TOY_VALUE_FROM_NULL(); } +} + +Toy_Value Toy_private_handleOpaqueAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { + if (opaqueAttributeCallback == NULL) { + char buffer[256]; + snprintf(buffer, 256, "Unknown attribute '%s' of type '%s' (did you set the opaque callbacks?)", TOY_VALUE_AS_STRING(attribute)->leaf.data, Toy_private_getValueTypeAsCString(compound.type)); + Toy_error(buffer); + return TOY_VALUE_FROM_NULL(); + } + + return opaqueAttributeCallback(vm, compound, attribute); +} + +void Toy_private_setOpaqueAttributeHandler(Toy_OpaqueAttributeHandler cb) { + opaqueAttributeCallback = cb; } \ No newline at end of file diff --git a/source/toy_attributes.h b/source/toy_attributes.h index 29502a3..f42a8a0 100644 --- a/source/toy_attributes.h +++ b/source/toy_attributes.h @@ -1,12 +1,10 @@ #pragma once +#include "toy_common.h" + #include "toy_value.h" #include "toy_vm.h" -Toy_Value handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute); -Toy_Value handleArrayAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute); -Toy_Value handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute); - // [x] string.length // [x] string.asUpper // [x] string.asLower @@ -20,3 +18,12 @@ Toy_Value handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attrib // [x] table.hasKey(x) // [x] table.remove(x) // [ ] table.forEach(fn) // fn(x,y) -> void + +TOY_API Toy_Value Toy_private_handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute); +TOY_API Toy_Value Toy_private_handleArrayAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute); +TOY_API Toy_Value Toy_private_handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute); +TOY_API Toy_Value Toy_private_handleOpaqueAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute); + +//plug-and-play attributes for custom objects +typedef Toy_Value (*Toy_OpaqueAttributeHandler)(Toy_VM* vm, Toy_Value compound, Toy_Value attribute); +TOY_API void Toy_private_setOpaqueAttributeHandler(Toy_OpaqueAttributeHandler cb); diff --git a/source/toy_value.c b/source/toy_value.c index d58bedc..37cb426 100644 --- a/source/toy_value.c +++ b/source/toy_value.c @@ -141,6 +141,9 @@ Toy_Value Toy_copyValue(Toy_Bucket** bucketHandle, Toy_Value value) { return TOY_VALUE_FROM_FUNCTION(Toy_copyFunction(bucketHandle, value.as.function)); case TOY_VALUE_OPAQUE: + //copy opaques by value + return value; + case TOY_VALUE_ANY: case TOY_VALUE_REFERENCE: case TOY_VALUE_UNKNOWN: @@ -650,7 +653,7 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) { case TOY_VALUE_OPAQUE: //dummy - return Toy_createStringLength(bucketHandle, "", 6); + return Toy_createStringLength(bucketHandle, "", 8); case TOY_VALUE_ANY: case TOY_VALUE_REFERENCE: diff --git a/source/toy_vm.c b/source/toy_vm.c index e0fcfdd..e765f85 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -428,13 +428,16 @@ static void processAttribute(Toy_VM* vm) { //type-based attributes if (TOY_VALUE_IS_STRING(compound)) { - result = handleStringAttributes(vm, compound, attribute); + result = Toy_private_handleStringAttributes(vm, compound, attribute); } else if (TOY_VALUE_IS_ARRAY(compound)) { - result = handleArrayAttributes(vm, compound, attribute); + result = Toy_private_handleArrayAttributes(vm, compound, attribute); } else if (TOY_VALUE_IS_TABLE(compound)) { - result = handleTableAttributes(vm, compound, attribute); + result = Toy_private_handleTableAttributes(vm, compound, attribute); + } + else if (TOY_VALUE_IS_OPAQUE(compound)) { + result = Toy_private_handleOpaqueAttributes(vm, compound, attribute); } else { char buffer[256];