Better embedding API support (and tests!) for strings with null bytes.

- Test that a foreign method can return strings.
- Test that a foreign method can return a string with null bytes.
- Test wrenCall().
- Allow passing NULL for "v" to wrenCall().
- Allow "a" for passing an explicit length byte array to wrenCall().
This commit is contained in:
Bob Nystrom
2015-09-24 08:02:31 -07:00
parent a944ead5b4
commit f757c9efac
11 changed files with 159 additions and 14 deletions
+3 -3
View File
@@ -172,7 +172,7 @@ static void initVM()
static void freeVM()
{
schedulerReleaseMethods();
uv_loop_close(loop);
free(loop);
@@ -259,8 +259,8 @@ uv_loop_t* getLoop()
return loop;
}
void setForeignCallbacks(
WrenBindForeignMethodFn bindMethod, WrenBindForeignClassFn bindClass)
void setTestCallbacks(WrenBindForeignMethodFn bindMethod,
WrenBindForeignClassFn bindClass)
{
bindMethodFn = bindMethod;
bindClassFn = bindClass;
+2 -2
View File
@@ -22,7 +22,7 @@ uv_loop_t* getLoop();
//
// Used by the API test executable to let it wire up its own foreign functions.
// This must be called before calling [createVM()].
void setForeignCallbacks(WrenBindForeignMethodFn bindMethod,
WrenBindForeignClassFn bindClass);
void setTestCallbacks(WrenBindForeignMethodFn bindMethod,
WrenBindForeignClassFn bindClass);
#endif
+14 -4
View File
@@ -213,8 +213,15 @@ WrenValue* wrenGetMethod(WrenVM* vm, const char* module, const char* variable,
// will allocate its own string and copy the characters from this, so
// you don't have to worry about the lifetime of the string you pass to
// Wren.
// - "a" - An array of bytes converted to a Wren String. This requires two
// consecutive arguments in the argument list: `const char*` pointing
// to the array of bytes, followed by an `int` defining the length of
// the array. This is used when the passed string may contain null
// bytes, or just to avoid the implicit `strlen()` call of "s" if you
// happen to already know the length.
// - "v" - A previously acquired WrenValue*. Passing this in does not implicitly
// release the value.
// release the value. If the passed argument is NULL, this becomes a
// Wren NULL.
//
// [method] must have been created by a call to [wrenGetMethod]. If [result] is
// not `NULL`, the return value of the method will be stored in a new
@@ -302,9 +309,12 @@ void wrenReturnDouble(WrenVM* vm, double value);
// Provides a string return value for a foreign call.
//
// The [text] will be copied to a new string within Wren's heap, so you can
// free memory used by it after this is called. If [length] is non-zero, Wren
// will copy that many bytes from [text]. If it is -1, then the length of
// [text] will be calculated using `strlen()`.
// free memory used by it after this is called.
//
// If [length] is non-zero, Wren copies that many bytes from [text], including
// any null bytes. If it is -1, then the length of [text] is calculated using
// `strlen()`. If the string may contain any null bytes in the middle, then you
// must pass an explicit length.
void wrenReturnString(WrenVM* vm, const char* text, int length);
// Provides the return value for a foreign call.
+15 -3
View File
@@ -1334,17 +1334,29 @@ WrenInterpretResult wrenCall(WrenVM* vm, WrenValue* method, WrenValue** result,
Value value = NULL_VAL;
switch (*argType)
{
case 'a':
{
const char* bytes = va_arg(argList, const char*);
int length = va_arg(argList, int);
value = wrenNewString(vm, bytes, (size_t)length);
break;
}
case 'b': value = BOOL_VAL(va_arg(argList, int)); break;
case 'd': value = NUM_VAL(va_arg(argList, double)); break;
case 'i': value = NUM_VAL((double)va_arg(argList, int)); break;
case 'n': value = NULL_VAL; va_arg(argList, void*); break;
case 's':
{
value = wrenStringFormat(vm, "$", va_arg(argList, const char*));
break;
}
case 'v': value = va_arg(argList, WrenValue*)->value; break;
case 'v':
{
// Allow a NULL value pointer for Wren null.
WrenValue* wrenValue = va_arg(argList, WrenValue*);
if (wrenValue != NULL) value = wrenValue->value;
break;
}
default:
ASSERT(false, "Unknown argument type.");