feat: add 'a' format specifier and null-value support to wrenCall, plus tests for strings with null bytes
Add a new 'a' format specifier to wrenCall that accepts an explicit byte array and length, enabling callers to pass strings containing null bytes without truncation. Also allow passing NULL for 'v' specifier arguments to produce a Wren NULL value. Rename setForeignCallbacks to setTestCallbacks for clarity. Extend the test suite with a new call.c test file that exercises all argument types including 'a' and 'v' with NULL, and add returnString/returnBytes foreign methods to verify wrenReturnString handles both null-terminated and explicit-length strings correctly.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "call.h"
|
||||
#include "vm.h"
|
||||
|
||||
static void runTests(WrenVM* vm)
|
||||
{
|
||||
WrenValue* noParams = wrenGetMethod(vm, "main", "Api", "noParams");
|
||||
WrenValue* zero = wrenGetMethod(vm, "main", "Api", "zero()");
|
||||
WrenValue* one = wrenGetMethod(vm, "main", "Api", "one(_)");
|
||||
WrenValue* two = wrenGetMethod(vm, "main", "Api", "two(_,_)");
|
||||
|
||||
// Different arity.
|
||||
wrenCall(vm, noParams, NULL, "");
|
||||
wrenCall(vm, zero, NULL, "");
|
||||
wrenCall(vm, one, NULL, "i", 1);
|
||||
wrenCall(vm, two, NULL, "ii", 1, 2);
|
||||
|
||||
WrenValue* getValue = wrenGetMethod(vm, "main", "Api", "getValue(_)");
|
||||
|
||||
// Returning a value.
|
||||
WrenValue* value = NULL;
|
||||
wrenCall(vm, getValue, &value, "v", NULL);
|
||||
|
||||
// Different argument types.
|
||||
wrenCall(vm, two, NULL, "bb", true, false);
|
||||
wrenCall(vm, two, NULL, "dd", 1.2, 3.4);
|
||||
wrenCall(vm, two, NULL, "ii", 3, 4);
|
||||
wrenCall(vm, two, NULL, "ss", "string", "another");
|
||||
wrenCall(vm, two, NULL, "vv", NULL, value);
|
||||
|
||||
// Truncate a string, or allow null bytes.
|
||||
wrenCall(vm, two, NULL, "aa", "string", 3, "b\0y\0t\0e", 7);
|
||||
|
||||
wrenReleaseValue(vm, noParams);
|
||||
wrenReleaseValue(vm, zero);
|
||||
wrenReleaseValue(vm, one);
|
||||
wrenReleaseValue(vm, two);
|
||||
wrenReleaseValue(vm, getValue);
|
||||
wrenReleaseValue(vm, value);
|
||||
}
|
||||
|
||||
|
||||
WrenForeignMethodFn callBindMethod(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.runTests()") == 0) return runTests;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn callBindMethod(const char* signature);
|
||||
@@ -0,0 +1,45 @@
|
||||
class Api {
|
||||
static noParams {
|
||||
System.print("noParams")
|
||||
}
|
||||
|
||||
static zero() {
|
||||
System.print("zero")
|
||||
}
|
||||
|
||||
static one(one) {
|
||||
System.print("one " + one.toString)
|
||||
}
|
||||
|
||||
static two(one, two) {
|
||||
// Don't print null bytes.
|
||||
if (two is String && two.bytes.contains(0)) {
|
||||
two = two.bytes.toList
|
||||
}
|
||||
|
||||
System.print("two " + one.toString + " " + two.toString)
|
||||
}
|
||||
|
||||
static getValue(value) {
|
||||
// Return a new value if we aren't given one.
|
||||
if (value == null) return ["a", "b"]
|
||||
|
||||
// Otherwise print it.
|
||||
System.print(value)
|
||||
}
|
||||
|
||||
foreign static runTests()
|
||||
}
|
||||
|
||||
Api.runTests()
|
||||
// expect: noParams
|
||||
// expect: zero
|
||||
// expect: one 1
|
||||
// expect: two 1 2
|
||||
|
||||
// expect: two true false
|
||||
// expect: two 1.2 3.4
|
||||
// expect: two 3 4
|
||||
// expect: two string another
|
||||
// expect: two null [a, b]
|
||||
// expect: two str [98, 0, 121, 0, 116, 0, 101]
|
||||
+3
-2
@@ -4,6 +4,7 @@
|
||||
#include "vm.h"
|
||||
#include "wren.h"
|
||||
|
||||
#include "call.h"
|
||||
#include "foreign_class.h"
|
||||
#include "returns.h"
|
||||
#include "value.h"
|
||||
@@ -35,6 +36,7 @@ static WrenForeignMethodFn bindForeignMethod(
|
||||
strcat(fullName, ".");
|
||||
strcat(fullName, signature);
|
||||
|
||||
REGISTER_METHOD(call, call);
|
||||
REGISTER_METHOD(foreign_class, foreignClass);
|
||||
REGISTER_METHOD(returns, returns);
|
||||
REGISTER_METHOD(value, value);
|
||||
@@ -56,7 +58,6 @@ static WrenForeignClassMethods bindForeignClass(
|
||||
return methods;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
@@ -73,7 +74,7 @@ int main(int argc, const char* argv[])
|
||||
strcat(testPath, testName);
|
||||
strcat(testPath, ".wren");
|
||||
|
||||
setForeignCallbacks(bindForeignMethod, bindForeignClass);
|
||||
setTestCallbacks(bindForeignMethod, bindForeignClass);
|
||||
runFile(testPath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,16 @@ static void returnFalse(WrenVM* vm)
|
||||
wrenReturnBool(vm, false);
|
||||
}
|
||||
|
||||
static void returnString(WrenVM* vm)
|
||||
{
|
||||
wrenReturnString(vm, "a string", -1);
|
||||
}
|
||||
|
||||
static void returnBytes(WrenVM* vm)
|
||||
{
|
||||
wrenReturnString(vm, "a\0b\0c", 5);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn returnsBindMethod(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.implicitNull") == 0) return implicitNull;
|
||||
@@ -34,6 +44,8 @@ WrenForeignMethodFn returnsBindMethod(const char* signature)
|
||||
if (strcmp(signature, "static Api.returnFloat") == 0) return returnFloat;
|
||||
if (strcmp(signature, "static Api.returnTrue") == 0) return returnTrue;
|
||||
if (strcmp(signature, "static Api.returnFalse") == 0) return returnFalse;
|
||||
if (strcmp(signature, "static Api.returnString") == 0) return returnString;
|
||||
if (strcmp(signature, "static Api.returnBytes") == 0) return returnBytes;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ class Api {
|
||||
|
||||
foreign static returnTrue
|
||||
foreign static returnFalse
|
||||
|
||||
foreign static returnString
|
||||
foreign static returnBytes
|
||||
}
|
||||
|
||||
System.print(Api.implicitNull == null) // expect: true
|
||||
@@ -15,3 +18,6 @@ System.print(Api.returnFloat) // expect: 123.456
|
||||
|
||||
System.print(Api.returnTrue) // expect: true
|
||||
System.print(Api.returnFalse) // expect: false
|
||||
|
||||
System.print(Api.returnString) // expect: a string
|
||||
System.print(Api.returnBytes.bytes.toList) // expect: [97, 0, 98, 0, 99]
|
||||
|
||||
Reference in New Issue
Block a user