Functions for operating on Maps from C (#725)

new API functions for maps:
wrenSetSlotNewMap
wrenGetMapCount
wrenGetMapContainsKey
wrenGetMapValue
wrenSetMapValue
wrenRemoveMapValue
This commit is contained in:
Aviv Beeri
2020-06-14 22:45:23 +01:00
committed by GitHub
parent 344d3432b3
commit de6a312868
19 changed files with 374 additions and 7 deletions

View File

@ -121,6 +121,7 @@ OBJECTS += $(OBJDIR)/get_variable.o
OBJECTS += $(OBJDIR)/handle.o
OBJECTS += $(OBJDIR)/lists.o
OBJECTS += $(OBJDIR)/main.o
OBJECTS += $(OBJDIR)/maps.o
OBJECTS += $(OBJDIR)/new_vm.o
OBJECTS += $(OBJDIR)/reset_stack_after_call_abort.o
OBJECTS += $(OBJDIR)/reset_stack_after_foreign_construct.o
@ -219,6 +220,9 @@ $(OBJDIR)/handle.o: ../../test/api/handle.c
$(OBJDIR)/lists.o: ../../test/api/lists.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/maps.o: ../../test/api/maps.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/new_vm.o: ../../test/api/new_vm.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"

View File

@ -129,6 +129,7 @@ OBJECTS += $(OBJDIR)/get_variable.o
OBJECTS += $(OBJDIR)/handle.o
OBJECTS += $(OBJDIR)/lists.o
OBJECTS += $(OBJDIR)/main.o
OBJECTS += $(OBJDIR)/maps.o
OBJECTS += $(OBJDIR)/new_vm.o
OBJECTS += $(OBJDIR)/reset_stack_after_call_abort.o
OBJECTS += $(OBJDIR)/reset_stack_after_foreign_construct.o
@ -227,6 +228,9 @@ $(OBJDIR)/handle.o: ../../test/api/handle.c
$(OBJDIR)/lists.o: ../../test/api/lists.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/maps.o: ../../test/api/maps.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/new_vm.o: ../../test/api/new_vm.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"

View File

@ -121,6 +121,7 @@ OBJECTS += $(OBJDIR)/get_variable.o
OBJECTS += $(OBJDIR)/handle.o
OBJECTS += $(OBJDIR)/lists.o
OBJECTS += $(OBJDIR)/main.o
OBJECTS += $(OBJDIR)/maps.o
OBJECTS += $(OBJDIR)/new_vm.o
OBJECTS += $(OBJDIR)/reset_stack_after_call_abort.o
OBJECTS += $(OBJDIR)/reset_stack_after_foreign_construct.o
@ -219,6 +220,9 @@ $(OBJDIR)/handle.o: ../../test/api/handle.c
$(OBJDIR)/lists.o: ../../test/api/lists.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/maps.o: ../../test/api/maps.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/new_vm.o: ../../test/api/new_vm.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"

Binary file not shown.

View File

@ -265,6 +265,7 @@
<ClInclude Include="..\..\test\api\get_variable.h" />
<ClInclude Include="..\..\test\api\handle.h" />
<ClInclude Include="..\..\test\api\lists.h" />
<ClInclude Include="..\..\test\api\maps.h" />
<ClInclude Include="..\..\test\api\new_vm.h" />
<ClInclude Include="..\..\test\api\reset_stack_after_call_abort.h" />
<ClInclude Include="..\..\test\api\reset_stack_after_foreign_construct.h" />
@ -284,6 +285,7 @@
<ClCompile Include="..\..\test\api\get_variable.c" />
<ClCompile Include="..\..\test\api\handle.c" />
<ClCompile Include="..\..\test\api\lists.c" />
<ClCompile Include="..\..\test\api\maps.c" />
<ClCompile Include="..\..\test\api\new_vm.c" />
<ClCompile Include="..\..\test\api\reset_stack_after_call_abort.c" />
<ClCompile Include="..\..\test\api\reset_stack_after_foreign_construct.c" />

View File

@ -36,6 +36,9 @@
<ClInclude Include="..\..\test\api\lists.h">
<Filter>api</Filter>
</ClInclude>
<ClInclude Include="..\..\test\api\maps.h">
<Filter>api</Filter>
</ClInclude>
<ClInclude Include="..\..\test\api\new_vm.h">
<Filter>api</Filter>
</ClInclude>
@ -87,6 +90,9 @@
<ClCompile Include="..\..\test\api\lists.c">
<Filter>api</Filter>
</ClCompile>
<ClCompile Include="..\..\test\api\maps.c">
<Filter>api</Filter>
</ClCompile>
<ClCompile Include="..\..\test\api\new_vm.c">
<Filter>api</Filter>
</ClCompile>

View File

@ -265,6 +265,7 @@
<ClInclude Include="..\..\test\api\get_variable.h" />
<ClInclude Include="..\..\test\api\handle.h" />
<ClInclude Include="..\..\test\api\lists.h" />
<ClInclude Include="..\..\test\api\maps.h" />
<ClInclude Include="..\..\test\api\new_vm.h" />
<ClInclude Include="..\..\test\api\reset_stack_after_call_abort.h" />
<ClInclude Include="..\..\test\api\reset_stack_after_foreign_construct.h" />
@ -284,6 +285,7 @@
<ClCompile Include="..\..\test\api\get_variable.c" />
<ClCompile Include="..\..\test\api\handle.c" />
<ClCompile Include="..\..\test\api\lists.c" />
<ClCompile Include="..\..\test\api\maps.c" />
<ClCompile Include="..\..\test\api\new_vm.c" />
<ClCompile Include="..\..\test\api\reset_stack_after_call_abort.c" />
<ClCompile Include="..\..\test\api\reset_stack_after_foreign_construct.c" />

View File

@ -36,6 +36,9 @@
<ClInclude Include="..\..\test\api\lists.h">
<Filter>api</Filter>
</ClInclude>
<ClInclude Include="..\..\test\api\maps.h">
<Filter>api</Filter>
</ClInclude>
<ClInclude Include="..\..\test\api\new_vm.h">
<Filter>api</Filter>
</ClInclude>
@ -87,6 +90,9 @@
<ClCompile Include="..\..\test\api\lists.c">
<Filter>api</Filter>
</ClCompile>
<ClCompile Include="..\..\test\api\maps.c">
<Filter>api</Filter>
</ClCompile>
<ClCompile Include="..\..\test\api\new_vm.c">
<Filter>api</Filter>
</ClCompile>

View File

@ -14,6 +14,7 @@
31D07E222B367F941ED1DC62 /* test.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B2F762A1E7AFF5C394BCC6A /* test.c */; };
47E53E839E72A8F576EBBCC3 /* call.c in Sources */ = {isa = PBXBuildFile; fileRef = 2F776B0B32E83D3DB454E14B /* call.c */; };
4D8AE463A8CC37D57C2682A3 /* handle.c in Sources */ = {isa = PBXBuildFile; fileRef = 069BFCEB1DAE981D0DCA932B /* handle.c */; };
4EA04F0DA52DB97F7DA6CD4D /* maps.c in Sources */ = {isa = PBXBuildFile; fileRef = 3AEABBF53E5B8E27BFC83235 /* maps.c */; };
59615B339DB000A5DFD73973 /* resolution.c in Sources */ = {isa = PBXBuildFile; fileRef = 535262BB751E0FEDB1D338FB /* resolution.c */; };
78667B8C71CC7CFE6567D9CC /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 6E0F7DF4115B07262C2BD434 /* main.c */; };
7CCD7163EDF01255A3B6BFA3 /* api_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = 21B810EB49F2C99D318E572B /* api_tests.c */; };
@ -58,6 +59,7 @@
30E3DEE9D44B0C9BEB80C529 /* reset_stack_after_foreign_construct.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = reset_stack_after_foreign_construct.h; path = ../../test/api/reset_stack_after_foreign_construct.h; sourceTree = "<group>"; };
310165BFD4689371EB9E4BFF /* reset_stack_after_foreign_construct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = reset_stack_after_foreign_construct.c; path = ../../test/api/reset_stack_after_foreign_construct.c; sourceTree = "<group>"; };
33526D1DD64093CF6566735D /* slots.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = slots.c; path = ../../test/api/slots.c; sourceTree = "<group>"; };
3AEABBF53E5B8E27BFC83235 /* maps.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = maps.c; path = ../../test/api/maps.c; sourceTree = "<group>"; };
3E23E7FBE1120EAD7037EE3B /* lists.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = lists.h; path = ../../test/api/lists.h; sourceTree = "<group>"; };
41058591E3F3AC4373198BD1 /* lists.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lists.c; path = ../../test/api/lists.c; sourceTree = "<group>"; };
50338489786E3D3B6009CAC9 /* benchmark.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = benchmark.c; path = ../../test/api/benchmark.c; sourceTree = "<group>"; };
@ -73,6 +75,7 @@
9C375BF5B349F727A365F235 /* handle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = handle.h; path = ../../test/api/handle.h; sourceTree = "<group>"; };
A415E4D5A786B70728F35B15 /* call.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = call.h; path = ../../test/api/call.h; sourceTree = "<group>"; };
ABEF15744F3A9EA66A0B6BB4 /* test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = test.h; path = ../../test/test.h; sourceTree = "<group>"; };
AF8935BFB2FA07F13466ABFF /* maps.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = maps.h; path = ../../test/api/maps.h; sourceTree = "<group>"; };
B0175F83D8521835BFEDA5C3 /* user_data.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = user_data.c; path = ../../test/api/user_data.c; sourceTree = "<group>"; };
B0267C45D1F229770EA75285 /* resolution.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = resolution.h; path = ../../test/api/resolution.h; sourceTree = "<group>"; };
B1B12E89FA506CBB1D7C24C9 /* reset_stack_after_call_abort.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = reset_stack_after_call_abort.c; path = ../../test/api/reset_stack_after_call_abort.c; sourceTree = "<group>"; };
@ -128,6 +131,8 @@
9C375BF5B349F727A365F235 /* handle.h */,
41058591E3F3AC4373198BD1 /* lists.c */,
3E23E7FBE1120EAD7037EE3B /* lists.h */,
3AEABBF53E5B8E27BFC83235 /* maps.c */,
AF8935BFB2FA07F13466ABFF /* maps.h */,
C22EBF6BD9415A9DC95D55AB /* new_vm.c */,
57CA1E756EDCB9A75EF8B4B5 /* new_vm.h */,
B1B12E89FA506CBB1D7C24C9 /* reset_stack_after_call_abort.c */,
@ -259,6 +264,7 @@
E21864B54F40732750D362F5 /* get_variable.c in Sources */,
4D8AE463A8CC37D57C2682A3 /* handle.c in Sources */,
1C5491694BE6605B26F39FA9 /* lists.c in Sources */,
4EA04F0DA52DB97F7DA6CD4D /* maps.c in Sources */,
29C70EE3850862555862AD23 /* new_vm.c in Sources */,
BD0CC4E181C21B533630C321 /* reset_stack_after_call_abort.c in Sources */,
8F510F77A173C5697A74FDB7 /* reset_stack_after_foreign_construct.c in Sources */,

View File

@ -263,6 +263,7 @@ typedef enum
WREN_TYPE_NUM,
WREN_TYPE_FOREIGN,
WREN_TYPE_LIST,
WREN_TYPE_MAP,
WREN_TYPE_NULL,
WREN_TYPE_STRING,
@ -440,6 +441,9 @@ void* wrenSetSlotNewForeign(WrenVM* vm, int slot, int classSlot, size_t size);
// Stores a new empty list in [slot].
void wrenSetSlotNewList(WrenVM* vm, int slot);
// Stores a new empty map in [slot].
void wrenSetSlotNewMap(WrenVM* vm, int slot);
// Stores null in [slot].
void wrenSetSlotNull(WrenVM* vm, int slot);
@ -470,6 +474,26 @@ void wrenGetListElement(WrenVM* vm, int listSlot, int index, int elementSlot);
// an element, use `-1` for the index.
void wrenInsertInList(WrenVM* vm, int listSlot, int index, int elementSlot);
// Returns the number of entries in the map stored in [slot].
int wrenGetMapCount(WrenVM* vm, int slot);
// Returns true if the key in [keySlot] is found in the map placed in [mapSlot].
bool wrenGetMapContainsKey(WrenVM* vm, int mapSlot, int keySlot);
// Retrieves a value with the key in [keySlot] from the map in [mapSlot] and
// stores it in [valueSlot].
void wrenGetMapValue(WrenVM* vm, int mapSlot, int keySlot, int valueSlot);
// Takes the value stored at [valueSlot] and inserts it into the map stored
// at [mapSlot] with key [keySlot].
void wrenSetMapValue(WrenVM* vm, int mapSlot, int keySlot, int valueSlot);
// Removes a value from the map in [mapSlot], with the key from [keySlot],
// and place it in [removedValueSlot]. If not found, [removedValueSlot] is
// set to null, the same behaviour as the Wren Map API.
void wrenRemoveMapValue(WrenVM* vm, int mapSlot, int keySlot,
int removedValueSlot);
// Looks up the top level variable with [name] in resolved [module] and stores
// it in [slot].
void wrenGetVariable(WrenVM* vm, const char* module, const char* name,

View File

@ -76,6 +76,7 @@
#define IS_FOREIGN(value) (wrenIsObjType(value, OBJ_FOREIGN)) // ObjForeign
#define IS_INSTANCE(value) (wrenIsObjType(value, OBJ_INSTANCE)) // ObjInstance
#define IS_LIST(value) (wrenIsObjType(value, OBJ_LIST)) // ObjList
#define IS_MAP(value) (wrenIsObjType(value, OBJ_MAP)) // ObjMap
#define IS_RANGE(value) (wrenIsObjType(value, OBJ_RANGE)) // ObjRange
#define IS_STRING(value) (wrenIsObjType(value, OBJ_STRING)) // ObjString

View File

@ -6,6 +6,7 @@
#include "wren_compiler.h"
#include "wren_core.h"
#include "wren_debug.h"
#include "wren_primitive.h"
#include "wren_vm.h"
#if WREN_OPT_META
@ -1596,6 +1597,7 @@ WrenType wrenGetSlotType(WrenVM* vm, int slot)
if (IS_NUM(vm->apiStack[slot])) return WREN_TYPE_NUM;
if (IS_FOREIGN(vm->apiStack[slot])) return WREN_TYPE_FOREIGN;
if (IS_LIST(vm->apiStack[slot])) return WREN_TYPE_LIST;
if (IS_MAP(vm->apiStack[slot])) return WREN_TYPE_MAP;
if (IS_NULL(vm->apiStack[slot])) return WREN_TYPE_NULL;
if (IS_STRING(vm->apiStack[slot])) return WREN_TYPE_STRING;
@ -1694,6 +1696,11 @@ void wrenSetSlotNewList(WrenVM* vm, int slot)
setSlot(vm, slot, OBJ_VAL(wrenNewList(vm, 0)));
}
void wrenSetSlotNewMap(WrenVM* vm, int slot)
{
setSlot(vm, slot, OBJ_VAL(wrenNewMap(vm)));
}
void wrenSetSlotNull(WrenVM* vm, int slot)
{
setSlot(vm, slot, NULL_VAL);
@ -1748,6 +1755,81 @@ void wrenInsertInList(WrenVM* vm, int listSlot, int index, int elementSlot)
wrenListInsert(vm, list, vm->apiStack[elementSlot], index);
}
int wrenGetMapCount(WrenVM* vm, int slot)
{
validateApiSlot(vm, slot);
ASSERT(IS_MAP(vm->apiStack[slot]), "Slot must hold a map.");
ObjMap* map = AS_MAP(vm->apiStack[slot]);
return map->count;
}
bool wrenGetMapContainsKey(WrenVM* vm, int mapSlot, int keySlot)
{
validateApiSlot(vm, mapSlot);
validateApiSlot(vm, keySlot);
ASSERT(IS_MAP(vm->apiStack[mapSlot]), "Slot must hold a map.");
Value key = vm->apiStack[keySlot];
if (!validateKey(vm, key)) return false;
ObjMap* map = AS_MAP(vm->apiStack[mapSlot]);
Value value = wrenMapGet(map, key);
return !IS_UNDEFINED(value);
}
void wrenGetMapValue(WrenVM* vm, int mapSlot, int keySlot, int valueSlot)
{
validateApiSlot(vm, mapSlot);
validateApiSlot(vm, keySlot);
validateApiSlot(vm, valueSlot);
ASSERT(IS_MAP(vm->apiStack[mapSlot]), "Slot must hold a map.");
ObjMap* map = AS_MAP(vm->apiStack[mapSlot]);
Value value = wrenMapGet(map, vm->apiStack[keySlot]);
if (IS_UNDEFINED(value)) {
value = NULL_VAL;
}
vm->apiStack[valueSlot] = value;
}
void wrenSetMapValue(WrenVM* vm, int mapSlot, int keySlot, int valueSlot)
{
validateApiSlot(vm, mapSlot);
validateApiSlot(vm, keySlot);
validateApiSlot(vm, valueSlot);
ASSERT(IS_MAP(vm->apiStack[mapSlot]), "Must insert into a map.");
Value key = vm->apiStack[keySlot];
if (!validateKey(vm, key)) {
return;
}
Value value = vm->apiStack[valueSlot];
ObjMap* map = AS_MAP(vm->apiStack[mapSlot]);
wrenMapSet(vm, map, key, value);
}
void wrenRemoveMapValue(WrenVM* vm, int mapSlot, int keySlot,
int removedValueSlot)
{
validateApiSlot(vm, mapSlot);
validateApiSlot(vm, keySlot);
ASSERT(IS_MAP(vm->apiStack[mapSlot]), "Slot must hold a map.");
Value key = vm->apiStack[keySlot];
if (!validateKey(vm, key)) {
return;
}
ObjMap* map = AS_MAP(vm->apiStack[mapSlot]);
Value removed = wrenMapRemoveKey(vm, map, key);
setSlot(vm, removedValueSlot, removed);
}
void wrenGetVariable(WrenVM* vm, const char* module, const char* name,
int slot)
{

View File

@ -40,6 +40,9 @@ WrenForeignMethodFn APITest_bindForeignMethod(
method = listsBindMethod(fullName);
if (method != NULL) return method;
method = mapsBindMethod(fullName);
if (method != NULL) return method;
method = newVMBindMethod(fullName);
if (method != NULL) return method;

View File

@ -16,6 +16,7 @@
#include "foreign_class.h"
#include "handle.h"
#include "lists.h"
#include "maps.h"
#include "new_vm.h"
#include "reset_stack_after_call_abort.h"
#include "reset_stack_after_foreign_construct.h"

130
test/api/maps.c Normal file
View File

@ -0,0 +1,130 @@
#include <string.h>
#include "maps.h"
static void newMap(WrenVM* vm)
{
wrenSetSlotNewMap(vm, 0);
}
static void invalidInsert(WrenVM* vm)
{
wrenSetSlotNewMap(vm, 0);
wrenEnsureSlots(vm, 3);
// Foreign Class is in slot 1
wrenSetSlotString(vm, 2, "England");
wrenSetMapValue(vm, 0, 1, 2); // expect this to cause errors
}
static void insert(WrenVM* vm)
{
wrenSetSlotNewMap(vm, 0);
wrenEnsureSlots(vm, 3);
// Insert String
wrenSetSlotString(vm, 1, "England");
wrenSetSlotString(vm, 2, "London");
wrenSetMapValue(vm, 0, 1, 2);
// Insert Double
wrenSetSlotDouble(vm, 1, 1.0);
wrenSetSlotDouble(vm, 2, 42.0);
wrenSetMapValue(vm, 0, 1, 2);
// Insert Boolean
wrenSetSlotBool(vm, 1, false);
wrenSetSlotBool(vm, 2, true);
wrenSetMapValue(vm, 0, 1, 2);
// Insert Null
wrenSetSlotNull(vm, 1);
wrenSetSlotNull(vm, 2);
wrenSetMapValue(vm, 0, 1, 2);
// Insert List
wrenSetSlotString(vm, 1, "Empty");
wrenSetSlotNewList(vm, 2);
wrenSetMapValue(vm, 0, 1, 2);
}
static void remove(WrenVM* vm)
{
wrenEnsureSlots(vm, 3);
wrenSetSlotString(vm, 2, "key");
wrenRemoveMapValue(vm, 1, 2, 0);
}
static void countWren(WrenVM* vm)
{
int count = wrenGetMapCount(vm, 1);
wrenSetSlotDouble(vm, 0, count);
}
static void countAPI(WrenVM* vm)
{
insert(vm);
int count = wrenGetMapCount(vm, 0);
wrenSetSlotDouble(vm, 0, count);
}
static void containsWren(WrenVM* vm)
{
bool result = wrenGetMapContainsKey(vm, 1, 2);
wrenSetSlotBool(vm, 0, result);
}
static void containsAPI(WrenVM* vm)
{
insert(vm);
wrenEnsureSlots(vm, 1);
wrenSetSlotString(vm, 1, "England");
bool result = wrenGetMapContainsKey(vm, 0, 1);
wrenSetSlotBool(vm, 0, result);
}
static void containsAPIFalse(WrenVM* vm)
{
insert(vm);
wrenEnsureSlots(vm, 1);
wrenSetSlotString(vm, 1, "DefinitelyNotARealKey");
bool result = wrenGetMapContainsKey(vm, 0, 1);
wrenSetSlotBool(vm, 0, result);
}
WrenForeignMethodFn mapsBindMethod(const char* signature)
{
if (strcmp(signature, "static Maps.newMap()") == 0) return newMap;
if (strcmp(signature, "static Maps.insert()") == 0) return insert;
if (strcmp(signature, "static Maps.remove(_)") == 0) return remove;
if (strcmp(signature, "static Maps.count(_)") == 0) return countWren;
if (strcmp(signature, "static Maps.count()") == 0) return countAPI;
if (strcmp(signature, "static Maps.contains()") == 0) return containsAPI;
if (strcmp(signature, "static Maps.containsFalse()") == 0) return containsAPIFalse;
if (strcmp(signature, "static Maps.contains(_,_)") == 0) return containsWren;
if (strcmp(signature, "static Maps.invalidInsert(_)") == 0) return invalidInsert;
return NULL;
}
void foreignAllocate(WrenVM* vm) {
wrenSetSlotNewForeign(vm, 0, 0, 0);
}
void mapBindClass(
const char* className, WrenForeignClassMethods* methods)
{
if (strcmp(className, "ForeignClass") == 0)
{
methods->allocate = foreignAllocate;
return;
}
}

5
test/api/maps.h Normal file
View File

@ -0,0 +1,5 @@
#include "wren.h"
WrenForeignMethodFn mapsBindMethod(const char* signature);
void mapBindClass(
const char* className, WrenForeignClassMethods* methods);

68
test/api/maps.wren Normal file
View File

@ -0,0 +1,68 @@
class ForeignClass {
construct new() {}
}
class Maps {
foreign static newMap()
foreign static insert()
foreign static contains(map, key)
foreign static contains()
foreign static containsFalse()
foreign static count()
foreign static count(map)
foreign static remove(map)
foreign static invalidInsert(obj)
}
// map new + get/set API
var map = Maps.newMap()
System.print(map is Map) // expect: true
System.print(map.count) // expect: 0
var data = Maps.insert()
System.print(data["England"]) // expect: London
System.print(data["Empty"]) // expect: []
System.print(data[1.0]) // expect: 42
System.print(data[false]) // expect: true
System.print(data[null]) // expect: null
// remove API
var removed = Maps.remove({ "key":"value", "other":"data" })
System.print(removed) // expect: value
var removedNone = Maps.remove({})
System.print(removedNone) // expect: null
// count API
var countMap = { "key":"value", "other":"data", 4:"number key" }
System.print(Maps.count(countMap)) // expect: 3
Maps.remove(countMap) //remove using API
System.print(Maps.count(countMap)) // expect: 2
countMap.remove("other") //remove wren side
System.print(Maps.count(countMap)) // expect: 1
var countAPI = Maps.count()
System.print(countAPI) // expect: 5
//contains key API
var containsMap = { "key":"value", "other":"data", 4:"number key" }
System.print(Maps.contains(containsMap, "key")) // expect: true
System.print(Maps.contains(containsMap, "fake")) // expect: false
System.print(Maps.contains(containsMap, "other")) // expect: true
Maps.remove(containsMap) //remove using API
System.print(Maps.contains(containsMap, "key")) // expect: false
containsMap.remove("other") //remove wren side
System.print(Maps.contains(containsMap, "other")) // expect: false
System.print(Maps.contains()) // expect: true
System.print(Maps.containsFalse()) // expect: false
//
Maps.invalidInsert(ForeignClass.new()) // expect runtime error: Key must be a value type.

View File

@ -82,10 +82,11 @@ static void slotTypes(WrenVM* vm)
wrenGetSlotType(vm, 1) == WREN_TYPE_BOOL &&
wrenGetSlotType(vm, 2) == WREN_TYPE_FOREIGN &&
wrenGetSlotType(vm, 3) == WREN_TYPE_LIST &&
wrenGetSlotType(vm, 4) == WREN_TYPE_NULL &&
wrenGetSlotType(vm, 5) == WREN_TYPE_NUM &&
wrenGetSlotType(vm, 6) == WREN_TYPE_STRING &&
wrenGetSlotType(vm, 7) == WREN_TYPE_UNKNOWN;
wrenGetSlotType(vm, 4) == WREN_TYPE_MAP &&
wrenGetSlotType(vm, 5) == WREN_TYPE_NULL &&
wrenGetSlotType(vm, 6) == WREN_TYPE_NUM &&
wrenGetSlotType(vm, 7) == WREN_TYPE_STRING &&
wrenGetSlotType(vm, 8) == WREN_TYPE_UNKNOWN;
wrenSetSlotBool(vm, 0, result);
}
@ -166,16 +167,22 @@ static void getListElement(WrenVM* vm)
wrenGetListElement(vm, 1, index, 0);
}
static void getMapValue(WrenVM* vm)
{
wrenGetMapValue(vm, 1, 2, 0);
}
WrenForeignMethodFn slotsBindMethod(const char* signature)
{
if (strcmp(signature, "static Slots.noSet") == 0) return noSet;
if (strcmp(signature, "static Slots.getSlots(_,_,_,_,_)") == 0) return getSlots;
if (strcmp(signature, "static Slots.setSlots(_,_,_,_,_)") == 0) return setSlots;
if (strcmp(signature, "static Slots.slotTypes(_,_,_,_,_,_,_)") == 0) return slotTypes;
if (strcmp(signature, "static Slots.slotTypes(_,_,_,_,_,_,_,_)") == 0) return slotTypes;
if (strcmp(signature, "static Slots.ensure()") == 0) return ensure;
if (strcmp(signature, "static Slots.ensureOutsideForeign()") == 0) return ensureOutsideForeign;
if (strcmp(signature, "static Slots.getListCount(_)") == 0) return getListCount;
if (strcmp(signature, "static Slots.getListElement(_,_)") == 0) return getListElement;
if (strcmp(signature, "static Slots.getMapValue(_,_)") == 0) return getMapValue;
return NULL;
}

View File

@ -2,11 +2,12 @@ class Slots {
foreign static noSet
foreign static getSlots(bool, num, string, bytes, value)
foreign static setSlots(a, b, c, d, e)
foreign static slotTypes(bool, foreignObj, list, nullObj, num, string, unknown)
foreign static slotTypes(bool, foreignObj, list, map, nullObj, num, string, unknown)
foreign static ensure()
foreign static ensureOutsideForeign()
foreign static getListCount(list)
foreign static getListElement(list, index)
foreign static getMapValue(map, key)
}
foreign class ForeignType {
@ -24,7 +25,7 @@ System.print(Slots.getSlots(true, "by\0te", 1.5, "str", value) == value)
System.print(Slots.setSlots(value, 0, 0, 0, 0) == value)
// expect: true
System.print(Slots.slotTypes(false, ForeignType.new(), [], null, 1.2, "str", 1..2))
System.print(Slots.slotTypes(false, ForeignType.new(), [], {}, null, 1.2, "str", 1..2))
// expect: true
System.print(Slots.ensure())
@ -37,3 +38,14 @@ var ducks = ["Huey", "Dewey", "Louie"]
System.print(Slots.getListCount(ducks)) // expect: 3
System.print(Slots.getListElement(ducks, 0)) // expect: Huey
System.print(Slots.getListElement(ducks, 1)) // expect: Dewey
var capitals = {
"England": "London",
"Scotland": "Edinburgh",
"Wales": "Cardiff",
"N. Ireland": "Belfast"
}
System.print(Slots.getMapValue(capitals, "England")) // expect: London
System.print(Slots.getMapValue(capitals, "Wales")) // expect: Cardiff
System.print(Slots.getMapValue(capitals, "S. Ireland")) // expect: null