mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 06:08:41 +01:00
WrenValue -> WrenHandle.
This commit is contained in:
@ -40,11 +40,15 @@ It would be a shame if calling a method from C didn't have that same speed benef
|
|||||||
First, we create a handle that represents a "compiled" method signature. You do that using this:
|
First, we create a handle that represents a "compiled" method signature. You do that using this:
|
||||||
|
|
||||||
:::c
|
:::c
|
||||||
WrenValue* wrenMakeCallHandle(WrenVM* vm, const char* signature);
|
WrenHandle* wrenMakeCallHandle(WrenVM* vm, const char* signature);
|
||||||
|
|
||||||
That takes a method signature as a string and gives you back an opaque handle that represents the compiled method symbol. Now you have a *reusable* handle that can be used to very quickly call a certain method given a receiver and some arguments.
|
That takes a method signature as a string and gives you back an opaque handle that represents the compiled method symbol. Now you have a *reusable* handle that can be used to very quickly call a certain method given a receiver and some arguments.
|
||||||
|
|
||||||
This is just a regular WrenValue, which means you can hold onto it as long as you like. Typically, you'd call this once outside of your applications performance critical loops and reuse it as long as you need. Then, it is us up to you to release it when you no longer need it by calling `wrenReleaseValue()`.
|
This is just a regular WrenHandle, which means you can hold onto it as long as
|
||||||
|
you like. Typically, you'd call this once outside of your applications
|
||||||
|
performance critical loops and reuse it as long as you need. Then, it is us up
|
||||||
|
to you to release it when you no longer need it by calling
|
||||||
|
`wrenReleaseHandle()`.
|
||||||
|
|
||||||
### Setting up a receiver
|
### Setting up a receiver
|
||||||
|
|
||||||
@ -52,7 +56,7 @@ OK, we have a method, but who are we calling it on? We need a receiver, and as y
|
|||||||
|
|
||||||
Any object you store in that slot can be used as a receiver. You could even call `+` on a number by storing a number in there if you felt like it.
|
Any object you store in that slot can be used as a receiver. You could even call `+` on a number by storing a number in there if you felt like it.
|
||||||
|
|
||||||
[last section]: slots-and-values.html
|
[last section]: slots-and-handles.html
|
||||||
|
|
||||||
*Needing* to pick some kind of receiver from C might feel strange. C is procedural, so it's natural to want to just invoke a bare *function* from Wren, but Wren isn't procedural. Instead, if you want to define some executable operation that isn't logically tied to a specific object, the natural way is to define a static method on an appropriate class.
|
*Needing* to pick some kind of receiver from C might feel strange. C is procedural, so it's natural to want to just invoke a bare *function* from Wren, but Wren isn't procedural. Instead, if you want to define some executable operation that isn't logically tied to a specific object, the natural way is to define a static method on an appropriate class.
|
||||||
|
|
||||||
@ -69,7 +73,7 @@ So, very often, when you call a method from C, you'll be calling a static method
|
|||||||
|
|
||||||
Assuming you declared that class at the top level, the C API [gives you a way to look it up][variable].
|
Assuming you declared that class at the top level, the C API [gives you a way to look it up][variable].
|
||||||
|
|
||||||
[variable]: slots-and-values.html#looking-up-variables
|
[variable]: slots-and-handles.html#looking-up-variables
|
||||||
|
|
||||||
We can get a handle to the above class like so:
|
We can get a handle to the above class like so:
|
||||||
|
|
||||||
@ -84,12 +88,12 @@ We could do this every time we call `update()`, but, again, that's kind of slow
|
|||||||
// Load the class into slot 0.
|
// Load the class into slot 0.
|
||||||
wrenEnsureSlots(vm, 1);
|
wrenEnsureSlots(vm, 1);
|
||||||
wrenGetVariable(vm, "main", "GameEngine", 0);
|
wrenGetVariable(vm, "main", "GameEngine", 0);
|
||||||
WrenValue* gameEngine = wrenGetSlotValue(vm, 0);
|
WrenHandle* gameEngine = wrenGetSlotHandle(vm, 0);
|
||||||
|
|
||||||
Now, each time we want to call a method on GameEngine, we store that value back in slot zero:
|
Now, each time we want to call a method on GameEngine, we store that value back in slot zero:
|
||||||
|
|
||||||
:::c
|
:::c
|
||||||
wrenSetSlotValue(vm, 0, gameEngine);
|
wrenSetSlotHandle(vm, 0, gameEngine);
|
||||||
|
|
||||||
Just like we hoisted `wrenMakeCallHandle()` out of our performance critical loop, we can hoist the call to `wrenGetVariable()` out. Of course, if your code isn't performance critical, you don't have to do this.
|
Just like we hoisted `wrenMakeCallHandle()` out of our performance critical loop, we can hoist the call to `wrenGetVariable()` out. Of course, if your code isn't performance critical, you don't have to do this.
|
||||||
|
|
||||||
@ -105,7 +109,7 @@ We've got a receiver in slot zero now, next we need to pass in any other argumen
|
|||||||
We have all of the data in place, so all that's left is to pull the trigger and tell the VM to start running some code. There's one more function to call:
|
We have all of the data in place, so all that's left is to pull the trigger and tell the VM to start running some code. There's one more function to call:
|
||||||
|
|
||||||
:::c
|
:::c
|
||||||
WrenInterpretResult wrenCall(WrenVM* vm, WrenValue* method);
|
WrenInterpretResult wrenCall(WrenVM* vm, WrenHandle* method);
|
||||||
|
|
||||||
It takes the method handle we created using `wrenMakeCallHandle()`. It assumes you have already set up the receiver and arguments in the slot array. Critically, it assumes you have as many arguments as the method signature defines. If you call a method like `takeThree(_,_,_)` and don't put three arguments in the slot array, bad things we'll happen.
|
It takes the method handle we created using `wrenMakeCallHandle()`. It assumes you have already set up the receiver and arguments in the slot array. Critically, it assumes you have as many arguments as the method signature defines. If you call a method like `takeThree(_,_,_)` and don't put three arguments in the slot array, bad things we'll happen.
|
||||||
|
|
||||||
@ -122,4 +126,4 @@ When `wrenCall()` returns, it leaves the slot array in place. In slot zero, you
|
|||||||
This is how you drive Wren from C, but how do you put control in Wren's hands? For that, you'll need the next section...
|
This is how you drive Wren from C, but how do you put control in Wren's hands? For that, you'll need the next section...
|
||||||
|
|
||||||
<a class="right" href="calling-c-from-wren.html">Calling C From Wren →</a>
|
<a class="right" href="calling-c-from-wren.html">Calling C From Wren →</a>
|
||||||
<a href="slots-and-values.html">← Slots and Values</a>
|
<a href="slots-and-handles.html">← Slots and Handles</a>
|
||||||
|
|||||||
@ -169,41 +169,13 @@ need to free any memory it allocated. You do that like so:
|
|||||||
After calling that, you obviously cannot use the `WrenVM*` you passed to it
|
After calling that, you obviously cannot use the `WrenVM*` you passed to it
|
||||||
again. It's dead.
|
again. It's dead.
|
||||||
|
|
||||||
Note that Wren will yell at you if you still have any live [WrenValue][value]
|
Note that Wren will yell at you if you still have any live [WrenHandle][handle]
|
||||||
objects when you call this. This makes sure you haven't lost track of any of
|
objects when you call this. This makes sure you haven't lost track of any of
|
||||||
them (which leaks memory) and you don't try to use any of them after the VM has
|
them (which leaks memory) and you don't try to use any of them after the VM has
|
||||||
been freed.
|
been freed.
|
||||||
|
|
||||||
[value]: slots-and-values.html#values
|
[handle]: slots-and-handles.html#handles
|
||||||
|
|
||||||
Next, we'll learn to make that VM do useful stuff...
|
Next, we'll learn to make that VM do useful stuff...
|
||||||
|
|
||||||
<a class="right" href="slots-and-values.html">Slots and Values →</a>
|
<a class="right" href="slots-and-handles.html">Slots and Handles →</a>
|
||||||
|
|
||||||
<!--
|
|
||||||
- configuration
|
|
||||||
- each field and what it means
|
|
||||||
- preprocessor option
|
|
||||||
- WREN_NAN_TAGGING
|
|
||||||
- WREN_COMPUTED_GOTO
|
|
||||||
- WREN_OPT_META
|
|
||||||
- WREN_OPT_RANDOM
|
|
||||||
- WREN_DEBUG_GC_STRESS 0
|
|
||||||
- WREN_DEBUG_TRACE_MEMORY 0
|
|
||||||
- WREN_DEBUG_TRACE_GC 0
|
|
||||||
- WREN_DEBUG_DUMP_COMPILED_CODE 0
|
|
||||||
- WREN_DEBUG_TRACE_INSTRUCTIONS 0
|
|
||||||
- calling wren from c
|
|
||||||
|
|
||||||
Often a host application wants to load a bunch of Wren code into the VM and
|
|
||||||
then periodically call a method. For example, a game engine might load all
|
|
||||||
of the entity scripts into Wren. Then, each tick of the game loop, it calls
|
|
||||||
Wren to tell all of the entities to update.
|
|
||||||
|
|
||||||
- calling c from wren
|
|
||||||
- storing c data in wren objects
|
|
||||||
- fibers and scheduling
|
|
||||||
- app lifecycle, wren in charge
|
|
||||||
- app lifecycle, c in charge
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
^title Slots and Values
|
^title Slots and Handles
|
||||||
|
|
||||||
With `wrenInterpret()`, we can execute code, but that code can't do anything
|
With `wrenInterpret()`, we can execute code, but that code can't do anything
|
||||||
particularly interesting. Out of the box, the VM is very isolated from the rest
|
particularly interesting. Out of the box, the VM is very isolated from the rest
|
||||||
@ -8,7 +8,7 @@ laptop into a lap warmer, but that's about it.
|
|||||||
To make our Wren code *useful*, the VM needs to communicate with the outside
|
To make our Wren code *useful*, the VM needs to communicate with the outside
|
||||||
world. Wren uses a single unified set of functions for passing data into and out
|
world. Wren uses a single unified set of functions for passing data into and out
|
||||||
of the VM. These functions are based on two fundamental concepts: **slots** and
|
of the VM. These functions are based on two fundamental concepts: **slots** and
|
||||||
**values**.
|
**handles**.
|
||||||
|
|
||||||
## The Slot Array
|
## The Slot Array
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ hash the name and look it up in the module's string table. You might want to
|
|||||||
avoid calling this in the middle of a hot loop where performance is critical.
|
avoid calling this in the middle of a hot loop where performance is critical.
|
||||||
|
|
||||||
Instead, it's faster to look up the variable once outside the loop and store a
|
Instead, it's faster to look up the variable once outside the loop and store a
|
||||||
reference to the object using a [WrenValue](#values).
|
reference to the object using a [WrenHandle](#handles).
|
||||||
|
|
||||||
### Working with lists
|
### Working with lists
|
||||||
|
|
||||||
@ -197,7 +197,7 @@ the list. This is kind of tedious, but it lets us use the same set of functions
|
|||||||
for moving values into slots of each primitive type. Otherwise, we'd need
|
for moving values into slots of each primitive type. Otherwise, we'd need
|
||||||
`wrenInsertInListDouble()`, `wrenInsertInListBool()`, etc.
|
`wrenInsertInListDouble()`, `wrenInsertInListBool()`, etc.
|
||||||
|
|
||||||
## Values
|
## Handles
|
||||||
|
|
||||||
Slots are pretty good for shuttling primitive data between C and Wren, but they
|
Slots are pretty good for shuttling primitive data between C and Wren, but they
|
||||||
have two limitations:
|
have two limitations:
|
||||||
@ -211,53 +211,51 @@ have two limitations:
|
|||||||
that aren't simple primitive ones. If you want to grab a reference to,
|
that aren't simple primitive ones. If you want to grab a reference to,
|
||||||
say, an instance of some class, how do you do it?
|
say, an instance of some class, how do you do it?
|
||||||
|
|
||||||
To address those, we have WrenValue. A WrenValue is a handle that wraps a
|
To address those, we have WrenHandle. A WrenHandle wraps a reference to an
|
||||||
reference to an object of any kind—strings, numbers, instances of classes,
|
object of any kind—strings, numbers, instances of classes, collections,
|
||||||
collections, whatever.
|
whatever.
|
||||||
|
|
||||||
*(Note: WrenValue will probably be renamed to WrenHandle soon.)*
|
You create a WrenHandle using this:
|
||||||
|
|
||||||
You create a WrenValue using this:
|
|
||||||
|
|
||||||
:::c
|
:::c
|
||||||
WrenValue* wrenGetSlotValue(WrenVM* vm, int slot);
|
WrenHandle* wrenGetSlotHandle(WrenVM* vm, int slot);
|
||||||
|
|
||||||
This takes the object stored in the given slot, creates a new WrenValue to wrap
|
This takes the object stored in the given slot, creates a new WrenHandle to wrap
|
||||||
it, and returns a pointer to it back to you.
|
it, and returns a pointer to it back to you.
|
||||||
|
|
||||||
You can send that wrapped object back to Wren by calling:
|
You can send that wrapped object back to Wren by calling:
|
||||||
|
|
||||||
:::c
|
:::c
|
||||||
void wrenSetSlotValue(WrenVM* vm, int slot, WrenValue* value);
|
void wrenSetSlotHandle(WrenVM* vm, int slot, WrenHandle* handle);
|
||||||
|
|
||||||
Note that this doesn't invalidate your WrenValue. You can still keep using it.
|
Note that this doesn't invalidate your WrenHandle. You can still keep using it.
|
||||||
|
|
||||||
### Retaining and releasing values
|
### Retaining and releasing handles
|
||||||
|
|
||||||
A WrenValue is an opaque wrapper around an object of any type, but just as
|
A WrenHandle is an opaque wrapper around an object of any type, but just as
|
||||||
important, it's a *persistent* one. When Wren gives you a pointer to a
|
important, it's a *persistent* one. When Wren gives you a pointer to a
|
||||||
WrenValue, it guarantees that that pointer remains valid. You can keep it
|
WrenHandle, it guarantees that that pointer remains valid. You can keep it
|
||||||
around as long as you want. Even if a garbage collection occurs, Wren will
|
around as long as you want. Even if a garbage collection occurs, Wren will
|
||||||
ensure all of the WrenValues and the objects they wrap are kept safely in
|
ensure all of the WrenHandles and the objects they wrap are kept safely in
|
||||||
memory.
|
memory.
|
||||||
|
|
||||||
Internally, Wren keeps a list of all of the WrenValues that have been created.
|
Internally, Wren keeps a list of all of the WrenHandles that have been created.
|
||||||
That way, during garbage collection, it can find them all and make sure their
|
That way, during garbage collection, it can find them all and make sure their
|
||||||
objects aren't freed.
|
objects aren't freed.
|
||||||
|
|
||||||
But what if you don't want it to be kept around any more? Since C relies on
|
But what if you don't want it to be kept around any more? Since C relies on
|
||||||
manual memory management, WrenValue does too. When you are done with one, you
|
manual memory management, WrenHandle does too. When you are done with one, you
|
||||||
must explicitly release it by calling:
|
must explicitly release it by calling:
|
||||||
|
|
||||||
:::c
|
:::c
|
||||||
void wrenReleaseValue(WrenVM* vm, WrenValue* value);
|
void wrenReleaseHandle(WrenVM* vm, WrenHandle* handle);
|
||||||
|
|
||||||
This does not immediately delete the wrapped object—after all, there may
|
This does not immediately delete the wrapped object—after all, there may
|
||||||
be other references to the same object in the program. It just invalidates the
|
be other references to the same object in the program. It just invalidates the
|
||||||
WrenValue wrapper itself. After you call this, you cannot use that pointer
|
WrenHandle wrapper itself. After you call this, you cannot use that pointer
|
||||||
again.
|
again.
|
||||||
|
|
||||||
You must release every WrenValue you've created before shutting down the VM.
|
You must release every WrenHandle you've created before shutting down the VM.
|
||||||
Wren warns you if you don't, since it implies you've probably leaked a resource
|
Wren warns you if you don't, since it implies you've probably leaked a resource
|
||||||
somewhere.
|
somewhere.
|
||||||
|
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<h2>embedding</h2>
|
<h2>embedding</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="./">Introduction</a></li>
|
<li><a href="./">Introduction</a></li>
|
||||||
<li><a href="slots-and-values.html">Slots and Values</a></li>
|
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
|
||||||
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
|
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
|
||||||
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
|
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
|
||||||
<li><a href="storing-c-data.html">Storing C Data</a></li>
|
<li><a href="storing-c-data.html">Storing C Data</a></li>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="./">Introduction</a></li>
|
<li><a href="./">Introduction</a></li>
|
||||||
<li><a href="slots-and-values.html">Slots and Values</a></li>
|
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
|
||||||
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
|
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
|
||||||
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
|
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
|
||||||
<li><a href="storing-c-data.html">Storing C Data</a></li>
|
<li><a href="storing-c-data.html">Storing C Data</a></li>
|
||||||
|
|||||||
@ -14,9 +14,9 @@ typedef struct WrenVM WrenVM;
|
|||||||
// A handle to a Wren object.
|
// A handle to a Wren object.
|
||||||
//
|
//
|
||||||
// This lets code outside of the VM hold a persistent reference to an object.
|
// This lets code outside of the VM hold a persistent reference to an object.
|
||||||
// After a value is acquired, and until it is released, this ensures the
|
// After a handle is acquired, and until it is released, this ensures the
|
||||||
// garbage collector will not reclaim it.
|
// garbage collector will not reclaim the object it references.
|
||||||
typedef struct WrenValue WrenValue;
|
typedef struct WrenHandle WrenHandle;
|
||||||
|
|
||||||
// A generic allocation function that handles all explicit memory management
|
// A generic allocation function that handles all explicit memory management
|
||||||
// used by Wren. It's used like so:
|
// used by Wren. It's used like so:
|
||||||
@ -246,8 +246,8 @@ WrenInterpretResult wrenInterpret(WrenVM* vm, const char* source);
|
|||||||
// code using [wrenCall].
|
// code using [wrenCall].
|
||||||
//
|
//
|
||||||
// When you are done with this handle, it must be released using
|
// When you are done with this handle, it must be released using
|
||||||
// [wrenReleaseValue].
|
// [wrenReleaseHandle].
|
||||||
WrenValue* wrenMakeCallHandle(WrenVM* vm, const char* signature);
|
WrenHandle* wrenMakeCallHandle(WrenVM* vm, const char* signature);
|
||||||
|
|
||||||
// Calls [method], using the receiver and arguments previously set up on the
|
// Calls [method], using the receiver and arguments previously set up on the
|
||||||
// stack.
|
// stack.
|
||||||
@ -259,17 +259,17 @@ WrenValue* wrenMakeCallHandle(WrenVM* vm, const char* signature);
|
|||||||
// signature.
|
// signature.
|
||||||
//
|
//
|
||||||
// After this returns, you can access the return value from slot 0 on the stack.
|
// After this returns, you can access the return value from slot 0 on the stack.
|
||||||
WrenInterpretResult wrenCall(WrenVM* vm, WrenValue* method);
|
WrenInterpretResult wrenCall(WrenVM* vm, WrenHandle* method);
|
||||||
|
|
||||||
// Releases the reference stored in [value]. After calling this, [value] can no
|
// Releases the reference stored in [handle]. After calling this, [handle] can
|
||||||
// longer be used.
|
// no longer be used.
|
||||||
void wrenReleaseValue(WrenVM* vm, WrenValue* value);
|
void wrenReleaseHandle(WrenVM* vm, WrenHandle* handle);
|
||||||
|
|
||||||
// The following functions are intended to be called from foreign methods or
|
// The following functions are intended to be called from foreign methods or
|
||||||
// finalizers. The interface Wren provides to a foreign method is like a
|
// finalizers. The interface Wren provides to a foreign method is like a
|
||||||
// register machine: you are given a numbered array of slots that values can be
|
// register machine: you are given a numbered array of slots that values can be
|
||||||
// read from and written to. Values always live in a slot (unless explicitly
|
// read from and written to. Values always live in a slot (unless explicitly
|
||||||
// captured using wrenGetSlotValue(), which ensures the garbage collector can
|
// captured using wrenGetSlotHandle(), which ensures the garbage collector can
|
||||||
// find them.
|
// find them.
|
||||||
//
|
//
|
||||||
// When your foreign function is called, you are given one slot for the receiver
|
// When your foreign function is called, you are given one slot for the receiver
|
||||||
@ -357,8 +357,8 @@ const char* wrenGetSlotString(WrenVM* vm, int slot);
|
|||||||
// Creates a handle for the value stored in [slot].
|
// Creates a handle for the value stored in [slot].
|
||||||
//
|
//
|
||||||
// This will prevent the object that is referred to from being garbage collected
|
// This will prevent the object that is referred to from being garbage collected
|
||||||
// until the handle is released by calling [wrenReleaseValue()].
|
// until the handle is released by calling [wrenReleaseHandle()].
|
||||||
WrenValue* wrenGetSlotValue(WrenVM* vm, int slot);
|
WrenHandle* wrenGetSlotHandle(WrenVM* vm, int slot);
|
||||||
|
|
||||||
// The following functions provide the return value for a foreign method back
|
// The following functions provide the return value for a foreign method back
|
||||||
// to Wren. Like above, they may only be called during a foreign call invoked
|
// to Wren. Like above, they may only be called during a foreign call invoked
|
||||||
@ -406,10 +406,10 @@ void wrenSetSlotNull(WrenVM* vm, int slot);
|
|||||||
// should use [wrenSetSlotBytes()] instead.
|
// should use [wrenSetSlotBytes()] instead.
|
||||||
void wrenSetSlotString(WrenVM* vm, int slot, const char* text);
|
void wrenSetSlotString(WrenVM* vm, int slot, const char* text);
|
||||||
|
|
||||||
// Stores the value captured in [value] in [slot].
|
// Stores the value captured in [handle] in [slot].
|
||||||
//
|
//
|
||||||
// This does not release the handle for the value.
|
// This does not release the handle for the value.
|
||||||
void wrenSetSlotValue(WrenVM* vm, int slot, WrenValue* value);
|
void wrenSetSlotHandle(WrenVM* vm, int slot, WrenHandle* handle);
|
||||||
|
|
||||||
// Takes the value stored at [elementSlot] and inserts it into the list stored
|
// Takes the value stored at [elementSlot] and inserts it into the list stored
|
||||||
// at [listSlot] at [index].
|
// at [listSlot] at [index].
|
||||||
|
|||||||
@ -28,20 +28,20 @@
|
|||||||
|
|
||||||
typedef struct sFileRequestData
|
typedef struct sFileRequestData
|
||||||
{
|
{
|
||||||
WrenValue* fiber;
|
WrenHandle* fiber;
|
||||||
uv_buf_t buffer;
|
uv_buf_t buffer;
|
||||||
} FileRequestData;
|
} FileRequestData;
|
||||||
|
|
||||||
static const int stdinDescriptor = 0;
|
static const int stdinDescriptor = 0;
|
||||||
|
|
||||||
// Handle to the Stat class object.
|
// Handle to the Stat class object.
|
||||||
static WrenValue* statClass = NULL;
|
static WrenHandle* statClass = NULL;
|
||||||
|
|
||||||
// Handle to the Stdin class object.
|
// Handle to the Stdin class object.
|
||||||
static WrenValue* stdinClass = NULL;
|
static WrenHandle* stdinClass = NULL;
|
||||||
|
|
||||||
// Handle to an onData_() method call. Called when libuv provides data on stdin.
|
// Handle to an onData_() method call. Called when libuv provides data on stdin.
|
||||||
static WrenValue* stdinOnData = NULL;
|
static WrenHandle* stdinOnData = NULL;
|
||||||
|
|
||||||
// The stream used to read from stdin. Initialized on the first read.
|
// The stream used to read from stdin. Initialized on the first read.
|
||||||
static uv_stream_t* stdinStream = NULL;
|
static uv_stream_t* stdinStream = NULL;
|
||||||
@ -61,13 +61,13 @@ static void shutdownStdin()
|
|||||||
|
|
||||||
if (stdinClass != NULL)
|
if (stdinClass != NULL)
|
||||||
{
|
{
|
||||||
wrenReleaseValue(getVM(), stdinClass);
|
wrenReleaseHandle(getVM(), stdinClass);
|
||||||
stdinClass = NULL;
|
stdinClass = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stdinOnData != NULL)
|
if (stdinOnData != NULL)
|
||||||
{
|
{
|
||||||
wrenReleaseValue(getVM(), stdinOnData);
|
wrenReleaseHandle(getVM(), stdinOnData);
|
||||||
stdinOnData = NULL;
|
stdinOnData = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ void ioShutdown()
|
|||||||
|
|
||||||
if (statClass != NULL)
|
if (statClass != NULL)
|
||||||
{
|
{
|
||||||
wrenReleaseValue(getVM(), statClass);
|
wrenReleaseHandle(getVM(), statClass);
|
||||||
statClass = NULL;
|
statClass = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ static bool handleRequestError(uv_fs_t* request)
|
|||||||
if (request->result >= 0) return false;
|
if (request->result >= 0) return false;
|
||||||
|
|
||||||
FileRequestData* data = (FileRequestData*)request->data;
|
FileRequestData* data = (FileRequestData*)request->data;
|
||||||
WrenValue* fiber = (WrenValue*)data->fiber;
|
WrenHandle* fiber = (WrenHandle*)data->fiber;
|
||||||
|
|
||||||
schedulerResumeError(fiber, uv_strerror((int)request->result));
|
schedulerResumeError(fiber, uv_strerror((int)request->result));
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ static bool handleRequestError(uv_fs_t* request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocates a new request that resumes [fiber] when it completes.
|
// Allocates a new request that resumes [fiber] when it completes.
|
||||||
uv_fs_t* createRequest(WrenValue* fiber)
|
uv_fs_t* createRequest(WrenHandle* fiber)
|
||||||
{
|
{
|
||||||
uv_fs_t* request = (uv_fs_t*)malloc(sizeof(uv_fs_t));
|
uv_fs_t* request = (uv_fs_t*)malloc(sizeof(uv_fs_t));
|
||||||
|
|
||||||
@ -119,10 +119,10 @@ uv_fs_t* createRequest(WrenValue* fiber)
|
|||||||
// Releases resources used by [request].
|
// Releases resources used by [request].
|
||||||
//
|
//
|
||||||
// Returns the fiber that should be resumed after [request] completes.
|
// Returns the fiber that should be resumed after [request] completes.
|
||||||
WrenValue* freeRequest(uv_fs_t* request)
|
WrenHandle* freeRequest(uv_fs_t* request)
|
||||||
{
|
{
|
||||||
FileRequestData* data = (FileRequestData*)request->data;
|
FileRequestData* data = (FileRequestData*)request->data;
|
||||||
WrenValue* fiber = data->fiber;
|
WrenHandle* fiber = data->fiber;
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
uv_fs_req_cleanup(request);
|
uv_fs_req_cleanup(request);
|
||||||
@ -154,7 +154,7 @@ static void directoryListCallback(uv_fs_t* request)
|
|||||||
void directoryList(WrenVM* vm)
|
void directoryList(WrenVM* vm)
|
||||||
{
|
{
|
||||||
const char* path = wrenGetSlotString(vm, 1);
|
const char* path = wrenGetSlotString(vm, 1);
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 2));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 2));
|
||||||
|
|
||||||
// TODO: Check return.
|
// TODO: Check return.
|
||||||
uv_fs_scandir(getLoop(), request, path, 0, directoryListCallback);
|
uv_fs_scandir(getLoop(), request, path, 0, directoryListCallback);
|
||||||
@ -189,7 +189,7 @@ static void fileDeleteCallback(uv_fs_t* request)
|
|||||||
void fileDelete(WrenVM* vm)
|
void fileDelete(WrenVM* vm)
|
||||||
{
|
{
|
||||||
const char* path = wrenGetSlotString(vm, 1);
|
const char* path = wrenGetSlotString(vm, 1);
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 2));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 2));
|
||||||
|
|
||||||
// TODO: Check return.
|
// TODO: Check return.
|
||||||
uv_fs_unlink(getLoop(), request, path, fileDeleteCallback);
|
uv_fs_unlink(getLoop(), request, path, fileDeleteCallback);
|
||||||
@ -227,7 +227,7 @@ void fileOpen(WrenVM* vm)
|
|||||||
{
|
{
|
||||||
const char* path = wrenGetSlotString(vm, 1);
|
const char* path = wrenGetSlotString(vm, 1);
|
||||||
int flags = (int)wrenGetSlotDouble(vm, 2);
|
int flags = (int)wrenGetSlotDouble(vm, 2);
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 3));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 3));
|
||||||
|
|
||||||
// TODO: Allow controlling access.
|
// TODO: Allow controlling access.
|
||||||
uv_fs_open(getLoop(), request, path, mapFileFlags(flags), S_IRUSR | S_IWUSR,
|
uv_fs_open(getLoop(), request, path, mapFileFlags(flags), S_IRUSR | S_IWUSR,
|
||||||
@ -248,7 +248,7 @@ static void fileSizeCallback(uv_fs_t* request)
|
|||||||
void fileSizePath(WrenVM* vm)
|
void fileSizePath(WrenVM* vm)
|
||||||
{
|
{
|
||||||
const char* path = wrenGetSlotString(vm, 1);
|
const char* path = wrenGetSlotString(vm, 1);
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 2));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 2));
|
||||||
uv_fs_stat(getLoop(), request, path, fileSizeCallback);
|
uv_fs_stat(getLoop(), request, path, fileSizeCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ void fileClose(WrenVM* vm)
|
|||||||
// Mark it closed immediately.
|
// Mark it closed immediately.
|
||||||
*foreign = -1;
|
*foreign = -1;
|
||||||
|
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 1));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 1));
|
||||||
uv_fs_close(getLoop(), request, fd, fileCloseCallback);
|
uv_fs_close(getLoop(), request, fd, fileCloseCallback);
|
||||||
wrenSetSlotBool(vm, 0, false);
|
wrenSetSlotBool(vm, 0, false);
|
||||||
}
|
}
|
||||||
@ -307,7 +307,7 @@ static void fileReadBytesCallback(uv_fs_t* request)
|
|||||||
|
|
||||||
void fileReadBytes(WrenVM* vm)
|
void fileReadBytes(WrenVM* vm)
|
||||||
{
|
{
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 3));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 3));
|
||||||
|
|
||||||
int fd = *(int*)wrenGetSlotForeign(vm, 0);
|
int fd = *(int*)wrenGetSlotForeign(vm, 0);
|
||||||
// TODO: Assert fd != -1.
|
// TODO: Assert fd != -1.
|
||||||
@ -336,7 +336,7 @@ static void realPathCallback(uv_fs_t* request)
|
|||||||
void fileRealPath(WrenVM* vm)
|
void fileRealPath(WrenVM* vm)
|
||||||
{
|
{
|
||||||
const char* path = wrenGetSlotString(vm, 1);
|
const char* path = wrenGetSlotString(vm, 1);
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 2));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 2));
|
||||||
uv_fs_realpath(getLoop(), request, path, realPathCallback);
|
uv_fs_realpath(getLoop(), request, path, realPathCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,11 +353,11 @@ static void statCallback(uv_fs_t* request)
|
|||||||
if (statClass == NULL)
|
if (statClass == NULL)
|
||||||
{
|
{
|
||||||
wrenGetVariable(vm, "io", "Stat", 0);
|
wrenGetVariable(vm, "io", "Stat", 0);
|
||||||
statClass = wrenGetSlotValue(vm, 0);
|
statClass = wrenGetSlotHandle(vm, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a foreign Stat object to store the stat struct.
|
// Create a foreign Stat object to store the stat struct.
|
||||||
wrenSetSlotValue(vm, 2, statClass);
|
wrenSetSlotHandle(vm, 2, statClass);
|
||||||
wrenSetSlotNewForeign(vm, 2, 2, sizeof(uv_stat_t));
|
wrenSetSlotNewForeign(vm, 2, 2, sizeof(uv_stat_t));
|
||||||
|
|
||||||
// Copy the stat data.
|
// Copy the stat data.
|
||||||
@ -371,14 +371,14 @@ static void statCallback(uv_fs_t* request)
|
|||||||
void fileStat(WrenVM* vm)
|
void fileStat(WrenVM* vm)
|
||||||
{
|
{
|
||||||
int fd = *(int*)wrenGetSlotForeign(vm, 0);
|
int fd = *(int*)wrenGetSlotForeign(vm, 0);
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 1));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 1));
|
||||||
uv_fs_fstat(getLoop(), request, fd, statCallback);
|
uv_fs_fstat(getLoop(), request, fd, statCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fileSize(WrenVM* vm)
|
void fileSize(WrenVM* vm)
|
||||||
{
|
{
|
||||||
int fd = *(int*)wrenGetSlotForeign(vm, 0);
|
int fd = *(int*)wrenGetSlotForeign(vm, 0);
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 1));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 1));
|
||||||
uv_fs_fstat(getLoop(), request, fd, fileSizeCallback);
|
uv_fs_fstat(getLoop(), request, fd, fileSizeCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,12 +398,12 @@ void fileWriteBytes(WrenVM* vm)
|
|||||||
int length;
|
int length;
|
||||||
const char* bytes = wrenGetSlotBytes(vm, 1, &length);
|
const char* bytes = wrenGetSlotBytes(vm, 1, &length);
|
||||||
size_t offset = (size_t)wrenGetSlotDouble(vm, 2);
|
size_t offset = (size_t)wrenGetSlotDouble(vm, 2);
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 3));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 3));
|
||||||
|
|
||||||
FileRequestData* data = (FileRequestData*)request->data;
|
FileRequestData* data = (FileRequestData*)request->data;
|
||||||
|
|
||||||
data->buffer.len = length;
|
data->buffer.len = length;
|
||||||
// TODO: Instead of copying, just create a WrenValue for the byte string and
|
// TODO: Instead of copying, just create a WrenHandle for the byte string and
|
||||||
// hold on to it in the request until the write is done.
|
// hold on to it in the request until the write is done.
|
||||||
// TODO: Handle allocation failure.
|
// TODO: Handle allocation failure.
|
||||||
data->buffer.base = (char*)malloc(length);
|
data->buffer.base = (char*)malloc(length);
|
||||||
@ -416,7 +416,7 @@ void fileWriteBytes(WrenVM* vm)
|
|||||||
void statPath(WrenVM* vm)
|
void statPath(WrenVM* vm)
|
||||||
{
|
{
|
||||||
const char* path = wrenGetSlotString(vm, 1);
|
const char* path = wrenGetSlotString(vm, 1);
|
||||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 2));
|
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 2));
|
||||||
uv_fs_stat(getLoop(), request, path, statCallback);
|
uv_fs_stat(getLoop(), request, path, statCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,7 +556,7 @@ static void stdinReadCallback(uv_stream_t* stream, ssize_t numRead,
|
|||||||
{
|
{
|
||||||
wrenEnsureSlots(vm, 1);
|
wrenEnsureSlots(vm, 1);
|
||||||
wrenGetVariable(vm, "io", "Stdin", 0);
|
wrenGetVariable(vm, "io", "Stdin", 0);
|
||||||
stdinClass = wrenGetSlotValue(vm, 0);
|
stdinClass = wrenGetSlotHandle(vm, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stdinOnData == NULL)
|
if (stdinOnData == NULL)
|
||||||
@ -568,7 +568,7 @@ static void stdinReadCallback(uv_stream_t* stream, ssize_t numRead,
|
|||||||
if (numRead == UV_EOF)
|
if (numRead == UV_EOF)
|
||||||
{
|
{
|
||||||
wrenEnsureSlots(vm, 2);
|
wrenEnsureSlots(vm, 2);
|
||||||
wrenSetSlotValue(vm, 0, stdinClass);
|
wrenSetSlotHandle(vm, 0, stdinClass);
|
||||||
wrenSetSlotNull(vm, 1);
|
wrenSetSlotNull(vm, 1);
|
||||||
wrenCall(vm, stdinOnData);
|
wrenCall(vm, stdinOnData);
|
||||||
|
|
||||||
@ -582,7 +582,7 @@ static void stdinReadCallback(uv_stream_t* stream, ssize_t numRead,
|
|||||||
// embedding API supported a way to *give* it bytes that were previously
|
// embedding API supported a way to *give* it bytes that were previously
|
||||||
// allocated using Wren's own allocator.
|
// allocated using Wren's own allocator.
|
||||||
wrenEnsureSlots(vm, 2);
|
wrenEnsureSlots(vm, 2);
|
||||||
wrenSetSlotValue(vm, 0, stdinClass);
|
wrenSetSlotHandle(vm, 0, stdinClass);
|
||||||
wrenSetSlotBytes(vm, 1, buffer->base, numRead);
|
wrenSetSlotBytes(vm, 1, buffer->base, numRead);
|
||||||
wrenCall(vm, stdinOnData);
|
wrenCall(vm, stdinOnData);
|
||||||
|
|
||||||
|
|||||||
@ -8,16 +8,16 @@
|
|||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
// A handle to the "Scheduler" class object. Used to call static methods on it.
|
// A handle to the "Scheduler" class object. Used to call static methods on it.
|
||||||
static WrenValue* schedulerClass;
|
static WrenHandle* schedulerClass;
|
||||||
|
|
||||||
// This method resumes a fiber that is suspended waiting on an asynchronous
|
// This method resumes a fiber that is suspended waiting on an asynchronous
|
||||||
// operation. The first resumes it with zero arguments, and the second passes
|
// operation. The first resumes it with zero arguments, and the second passes
|
||||||
// one.
|
// one.
|
||||||
static WrenValue* resume1;
|
static WrenHandle* resume1;
|
||||||
static WrenValue* resume2;
|
static WrenHandle* resume2;
|
||||||
static WrenValue* resumeError;
|
static WrenHandle* resumeError;
|
||||||
|
|
||||||
static void resume(WrenValue* method)
|
static void resume(WrenHandle* method)
|
||||||
{
|
{
|
||||||
WrenInterpretResult result = wrenCall(getVM(), method);
|
WrenInterpretResult result = wrenCall(getVM(), method);
|
||||||
|
|
||||||
@ -34,20 +34,20 @@ void schedulerCaptureMethods(WrenVM* vm)
|
|||||||
{
|
{
|
||||||
wrenEnsureSlots(vm, 1);
|
wrenEnsureSlots(vm, 1);
|
||||||
wrenGetVariable(vm, "scheduler", "Scheduler", 0);
|
wrenGetVariable(vm, "scheduler", "Scheduler", 0);
|
||||||
schedulerClass = wrenGetSlotValue(vm, 0);
|
schedulerClass = wrenGetSlotHandle(vm, 0);
|
||||||
|
|
||||||
resume1 = wrenMakeCallHandle(vm, "resume_(_)");
|
resume1 = wrenMakeCallHandle(vm, "resume_(_)");
|
||||||
resume2 = wrenMakeCallHandle(vm, "resume_(_,_)");
|
resume2 = wrenMakeCallHandle(vm, "resume_(_,_)");
|
||||||
resumeError = wrenMakeCallHandle(vm, "resumeError_(_,_)");
|
resumeError = wrenMakeCallHandle(vm, "resumeError_(_,_)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void schedulerResume(WrenValue* fiber, bool hasArgument)
|
void schedulerResume(WrenHandle* fiber, bool hasArgument)
|
||||||
{
|
{
|
||||||
WrenVM* vm = getVM();
|
WrenVM* vm = getVM();
|
||||||
wrenEnsureSlots(vm, 2 + (hasArgument ? 1 : 0));
|
wrenEnsureSlots(vm, 2 + (hasArgument ? 1 : 0));
|
||||||
wrenSetSlotValue(vm, 0, schedulerClass);
|
wrenSetSlotHandle(vm, 0, schedulerClass);
|
||||||
wrenSetSlotValue(vm, 1, fiber);
|
wrenSetSlotHandle(vm, 1, fiber);
|
||||||
wrenReleaseValue(vm, fiber);
|
wrenReleaseHandle(vm, fiber);
|
||||||
|
|
||||||
// If we don't need to wait for an argument to be stored on the stack, resume
|
// If we don't need to wait for an argument to be stored on the stack, resume
|
||||||
// it now.
|
// it now.
|
||||||
@ -59,7 +59,7 @@ void schedulerFinishResume()
|
|||||||
resume(resume2);
|
resume(resume2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void schedulerResumeError(WrenValue* fiber, const char* error)
|
void schedulerResumeError(WrenHandle* fiber, const char* error)
|
||||||
{
|
{
|
||||||
schedulerResume(fiber, true);
|
schedulerResume(fiber, true);
|
||||||
wrenSetSlotString(getVM(), 2, error);
|
wrenSetSlotString(getVM(), 2, error);
|
||||||
@ -72,8 +72,8 @@ void schedulerShutdown()
|
|||||||
if (schedulerClass == NULL) return;
|
if (schedulerClass == NULL) return;
|
||||||
|
|
||||||
WrenVM* vm = getVM();
|
WrenVM* vm = getVM();
|
||||||
wrenReleaseValue(vm, schedulerClass);
|
wrenReleaseHandle(vm, schedulerClass);
|
||||||
wrenReleaseValue(vm, resume1);
|
wrenReleaseHandle(vm, resume1);
|
||||||
wrenReleaseValue(vm, resume2);
|
wrenReleaseHandle(vm, resume2);
|
||||||
wrenReleaseValue(vm, resumeError);
|
wrenReleaseHandle(vm, resumeError);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,10 +10,10 @@
|
|||||||
// on the stack and then call [schedulerFinishResume] to complete the call.
|
// on the stack and then call [schedulerFinishResume] to complete the call.
|
||||||
//
|
//
|
||||||
// Otherwise, the call resumes immediately. Releases [fiber] when called.
|
// Otherwise, the call resumes immediately. Releases [fiber] when called.
|
||||||
void schedulerResume(WrenValue* fiber, bool hasArgument);
|
void schedulerResume(WrenHandle* fiber, bool hasArgument);
|
||||||
|
|
||||||
void schedulerFinishResume();
|
void schedulerFinishResume();
|
||||||
void schedulerResumeError(WrenValue* fiber, const char* error);
|
void schedulerResumeError(WrenHandle* fiber, const char* error);
|
||||||
|
|
||||||
void schedulerShutdown();
|
void schedulerShutdown();
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ static void timerCloseCallback(uv_handle_t* handle)
|
|||||||
// Called by libuv when the timer has completed.
|
// Called by libuv when the timer has completed.
|
||||||
static void timerCallback(uv_timer_t* handle)
|
static void timerCallback(uv_timer_t* handle)
|
||||||
{
|
{
|
||||||
WrenValue* fiber = (WrenValue*)handle->data;
|
WrenHandle* fiber = (WrenHandle*)handle->data;
|
||||||
|
|
||||||
// Tell libuv that we don't need the timer anymore.
|
// Tell libuv that we don't need the timer anymore.
|
||||||
uv_close((uv_handle_t*)handle, timerCloseCallback);
|
uv_close((uv_handle_t*)handle, timerCloseCallback);
|
||||||
@ -28,7 +28,7 @@ static void timerCallback(uv_timer_t* handle)
|
|||||||
void timerStartTimer(WrenVM* vm)
|
void timerStartTimer(WrenVM* vm)
|
||||||
{
|
{
|
||||||
int milliseconds = (int)wrenGetSlotDouble(vm, 1);
|
int milliseconds = (int)wrenGetSlotDouble(vm, 1);
|
||||||
WrenValue* fiber = wrenGetSlotValue(vm, 2);
|
WrenHandle* fiber = wrenGetSlotHandle(vm, 2);
|
||||||
|
|
||||||
// Store the fiber to resume when the timer completes.
|
// Store the fiber to resume when the timer completes.
|
||||||
uv_timer_t* handle = (uv_timer_t*)malloc(sizeof(uv_timer_t));
|
uv_timer_t* handle = (uv_timer_t*)malloc(sizeof(uv_timer_t));
|
||||||
|
|||||||
@ -99,7 +99,7 @@ void wrenFreeVM(WrenVM* vm)
|
|||||||
// Tell the user if they didn't free any handles. We don't want to just free
|
// Tell the user if they didn't free any handles. We don't want to just free
|
||||||
// them here because the host app may still have pointers to them that they
|
// them here because the host app may still have pointers to them that they
|
||||||
// may try to use. Better to tell them about the bug early.
|
// may try to use. Better to tell them about the bug early.
|
||||||
ASSERT(vm->valueHandles == NULL, "All values have not been released.");
|
ASSERT(vm->handles == NULL, "All handles have not been released.");
|
||||||
|
|
||||||
wrenSymbolTableClear(vm, &vm->methodNames);
|
wrenSymbolTableClear(vm, &vm->methodNames);
|
||||||
|
|
||||||
@ -138,12 +138,12 @@ void wrenCollectGarbage(WrenVM* vm)
|
|||||||
// The current fiber.
|
// The current fiber.
|
||||||
wrenGrayObj(vm, (Obj*)vm->fiber);
|
wrenGrayObj(vm, (Obj*)vm->fiber);
|
||||||
|
|
||||||
// The value handles.
|
// The handles.
|
||||||
for (WrenValue* value = vm->valueHandles;
|
for (WrenHandle* handle = vm->handles;
|
||||||
value != NULL;
|
handle != NULL;
|
||||||
value = value->next)
|
handle = handle->next)
|
||||||
{
|
{
|
||||||
wrenGrayValue(vm, value->value);
|
wrenGrayValue(vm, handle->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any object the compiler is using (if there is one).
|
// Any object the compiler is using (if there is one).
|
||||||
@ -1195,7 +1195,7 @@ static WrenInterpretResult runInterpreter(WrenVM* vm, register ObjFiber* fiber)
|
|||||||
#undef READ_SHORT
|
#undef READ_SHORT
|
||||||
}
|
}
|
||||||
|
|
||||||
WrenValue* wrenMakeCallHandle(WrenVM* vm, const char* signature)
|
WrenHandle* wrenMakeCallHandle(WrenVM* vm, const char* signature)
|
||||||
{
|
{
|
||||||
ASSERT(signature != NULL, "Signature cannot be NULL.");
|
ASSERT(signature != NULL, "Signature cannot be NULL.");
|
||||||
|
|
||||||
@ -1231,7 +1231,7 @@ WrenValue* wrenMakeCallHandle(WrenVM* vm, const char* signature)
|
|||||||
|
|
||||||
// Wrap the function in a closure and then in a handle. Do this here so it
|
// Wrap the function in a closure and then in a handle. Do this here so it
|
||||||
// doesn't get collected as we fill it in.
|
// doesn't get collected as we fill it in.
|
||||||
WrenValue* value = wrenCaptureValue(vm, OBJ_VAL(fn));
|
WrenHandle* value = wrenMakeHandle(vm, OBJ_VAL(fn));
|
||||||
value->value = OBJ_VAL(wrenNewClosure(vm, fn));
|
value->value = OBJ_VAL(wrenNewClosure(vm, fn));
|
||||||
|
|
||||||
wrenByteBufferWrite(vm, &fn->code, (uint8_t)(CODE_CALL_0 + numParams));
|
wrenByteBufferWrite(vm, &fn->code, (uint8_t)(CODE_CALL_0 + numParams));
|
||||||
@ -1245,7 +1245,7 @@ WrenValue* wrenMakeCallHandle(WrenVM* vm, const char* signature)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
WrenInterpretResult wrenCall(WrenVM* vm, WrenValue* method)
|
WrenInterpretResult wrenCall(WrenVM* vm, WrenHandle* method)
|
||||||
{
|
{
|
||||||
ASSERT(method != NULL, "Method cannot be NULL.");
|
ASSERT(method != NULL, "Method cannot be NULL.");
|
||||||
ASSERT(IS_CLOSURE(method->value), "Method must be a method handle.");
|
ASSERT(IS_CLOSURE(method->value), "Method must be a method handle.");
|
||||||
@ -1266,42 +1266,42 @@ WrenInterpretResult wrenCall(WrenVM* vm, WrenValue* method)
|
|||||||
return runInterpreter(vm, vm->fiber);
|
return runInterpreter(vm, vm->fiber);
|
||||||
}
|
}
|
||||||
|
|
||||||
WrenValue* wrenCaptureValue(WrenVM* vm, Value value)
|
WrenHandle* wrenMakeHandle(WrenVM* vm, Value value)
|
||||||
{
|
{
|
||||||
if (IS_OBJ(value)) wrenPushRoot(vm, AS_OBJ(value));
|
if (IS_OBJ(value)) wrenPushRoot(vm, AS_OBJ(value));
|
||||||
|
|
||||||
// Make a handle for it.
|
// Make a handle for it.
|
||||||
WrenValue* wrappedValue = ALLOCATE(vm, WrenValue);
|
WrenHandle* handle = ALLOCATE(vm, WrenHandle);
|
||||||
wrappedValue->value = value;
|
handle->value = value;
|
||||||
|
|
||||||
if (IS_OBJ(value)) wrenPopRoot(vm);
|
if (IS_OBJ(value)) wrenPopRoot(vm);
|
||||||
|
|
||||||
// Add it to the front of the linked list of handles.
|
// Add it to the front of the linked list of handles.
|
||||||
if (vm->valueHandles != NULL) vm->valueHandles->prev = wrappedValue;
|
if (vm->handles != NULL) vm->handles->prev = handle;
|
||||||
wrappedValue->prev = NULL;
|
handle->prev = NULL;
|
||||||
wrappedValue->next = vm->valueHandles;
|
handle->next = vm->handles;
|
||||||
vm->valueHandles = wrappedValue;
|
vm->handles = handle;
|
||||||
|
|
||||||
return wrappedValue;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wrenReleaseValue(WrenVM* vm, WrenValue* value)
|
void wrenReleaseHandle(WrenVM* vm, WrenHandle* handle)
|
||||||
{
|
{
|
||||||
ASSERT(value != NULL, "Value cannot be NULL.");
|
ASSERT(handle != NULL, "Handle cannot be NULL.");
|
||||||
|
|
||||||
// Update the VM's head pointer if we're releasing the first handle.
|
// Update the VM's head pointer if we're releasing the first handle.
|
||||||
if (vm->valueHandles == value) vm->valueHandles = value->next;
|
if (vm->handles == handle) vm->handles = handle->next;
|
||||||
|
|
||||||
// Unlink it from the list.
|
// Unlink it from the list.
|
||||||
if (value->prev != NULL) value->prev->next = value->next;
|
if (handle->prev != NULL) handle->prev->next = handle->next;
|
||||||
if (value->next != NULL) value->next->prev = value->prev;
|
if (handle->next != NULL) handle->next->prev = handle->prev;
|
||||||
|
|
||||||
// Clear it out. This isn't strictly necessary since we're going to free it,
|
// Clear it out. This isn't strictly necessary since we're going to free it,
|
||||||
// but it makes for easier debugging.
|
// but it makes for easier debugging.
|
||||||
value->prev = NULL;
|
handle->prev = NULL;
|
||||||
value->next = NULL;
|
handle->next = NULL;
|
||||||
value->value = NULL_VAL;
|
handle->value = NULL_VAL;
|
||||||
DEALLOCATE(vm, value);
|
DEALLOCATE(vm, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
WrenInterpretResult wrenInterpret(WrenVM* vm, const char* source)
|
WrenInterpretResult wrenInterpret(WrenVM* vm, const char* source)
|
||||||
@ -1555,10 +1555,10 @@ const char* wrenGetSlotString(WrenVM* vm, int slot)
|
|||||||
return AS_CSTRING(vm->apiStack[slot]);
|
return AS_CSTRING(vm->apiStack[slot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
WrenValue* wrenGetSlotValue(WrenVM* vm, int slot)
|
WrenHandle* wrenGetSlotHandle(WrenVM* vm, int slot)
|
||||||
{
|
{
|
||||||
validateApiSlot(vm, slot);
|
validateApiSlot(vm, slot);
|
||||||
return wrenCaptureValue(vm, vm->apiStack[slot]);
|
return wrenMakeHandle(vm, vm->apiStack[slot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stores [value] in [slot] in the foreign call stack.
|
// Stores [value] in [slot] in the foreign call stack.
|
||||||
@ -1616,11 +1616,11 @@ void wrenSetSlotString(WrenVM* vm, int slot, const char* text)
|
|||||||
setSlot(vm, slot, wrenNewString(vm, text, strlen(text)));
|
setSlot(vm, slot, wrenNewString(vm, text, strlen(text)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void wrenSetSlotValue(WrenVM* vm, int slot, WrenValue* value)
|
void wrenSetSlotHandle(WrenVM* vm, int slot, WrenHandle* handle)
|
||||||
{
|
{
|
||||||
ASSERT(value != NULL, "Value cannot be NULL.");
|
ASSERT(handle != NULL, "Handle cannot be NULL.");
|
||||||
|
|
||||||
setSlot(vm, slot, value->value);
|
setSlot(vm, slot, handle->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wrenInsertInList(WrenVM* vm, int listSlot, int index, int elementSlot)
|
void wrenInsertInList(WrenVM* vm, int listSlot, int index, int elementSlot)
|
||||||
@ -1639,8 +1639,6 @@ void wrenInsertInList(WrenVM* vm, int listSlot, int index, int elementSlot)
|
|||||||
wrenListInsert(vm, list, vm->apiStack[elementSlot], index);
|
wrenListInsert(vm, list, vm->apiStack[elementSlot], index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Maybe just have this always return a WrenValue* instead of having to
|
|
||||||
// deal with slots?
|
|
||||||
void wrenGetVariable(WrenVM* vm, const char* module, const char* name,
|
void wrenGetVariable(WrenVM* vm, const char* module, const char* name,
|
||||||
int slot)
|
int slot)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -20,12 +20,12 @@ typedef enum
|
|||||||
// A handle to a value, basically just a linked list of extra GC roots.
|
// A handle to a value, basically just a linked list of extra GC roots.
|
||||||
//
|
//
|
||||||
// Note that even non-heap-allocated values can be stored here.
|
// Note that even non-heap-allocated values can be stored here.
|
||||||
struct WrenValue
|
struct WrenHandle
|
||||||
{
|
{
|
||||||
Value value;
|
Value value;
|
||||||
|
|
||||||
WrenValue* prev;
|
WrenHandle* prev;
|
||||||
WrenValue* next;
|
WrenHandle* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WrenVM
|
struct WrenVM
|
||||||
@ -80,9 +80,9 @@ struct WrenVM
|
|||||||
|
|
||||||
int numTempRoots;
|
int numTempRoots;
|
||||||
|
|
||||||
// Pointer to the first node in the linked list of active value handles or
|
// Pointer to the first node in the linked list of active handles or NULL if
|
||||||
// NULL if there are no handles.
|
// there are none.
|
||||||
WrenValue* valueHandles;
|
WrenHandle* handles;
|
||||||
|
|
||||||
// Pointer to the bottom of the range of stack slots available for use from
|
// Pointer to the bottom of the range of stack slots available for use from
|
||||||
// the C API. During a foreign method, this will be in the stack of the fiber
|
// the C API. During a foreign method, this will be in the stack of the fiber
|
||||||
@ -128,8 +128,8 @@ void* wrenReallocate(WrenVM* vm, void* memory, size_t oldSize, size_t newSize);
|
|||||||
// Invoke the finalizer for the foreign object referenced by [foreign].
|
// Invoke the finalizer for the foreign object referenced by [foreign].
|
||||||
void wrenFinalizeForeign(WrenVM* vm, ObjForeign* foreign);
|
void wrenFinalizeForeign(WrenVM* vm, ObjForeign* foreign);
|
||||||
|
|
||||||
// Creates a new [WrenValue] for [value].
|
// Creates a new [WrenHandle] for [value].
|
||||||
WrenValue* wrenCaptureValue(WrenVM* vm, Value value);
|
WrenHandle* wrenMakeHandle(WrenVM* vm, Value value);
|
||||||
|
|
||||||
// Executes [source] in the context of [module].
|
// Executes [source] in the context of [module].
|
||||||
WrenInterpretResult wrenInterpretInModule(WrenVM* vm, const char* module,
|
WrenInterpretResult wrenInterpretInModule(WrenVM* vm, const char* module,
|
||||||
|
|||||||
@ -32,11 +32,11 @@ static void call(WrenVM* vm)
|
|||||||
|
|
||||||
wrenInterpret(otherVM, testScript);
|
wrenInterpret(otherVM, testScript);
|
||||||
|
|
||||||
WrenValue* method = wrenMakeCallHandle(otherVM, "method(_,_,_,_)");
|
WrenHandle* method = wrenMakeCallHandle(otherVM, "method(_,_,_,_)");
|
||||||
|
|
||||||
wrenEnsureSlots(otherVM, 1);
|
wrenEnsureSlots(otherVM, 1);
|
||||||
wrenGetVariable(otherVM, "main", "Test", 0);
|
wrenGetVariable(otherVM, "main", "Test", 0);
|
||||||
WrenValue* testClass = wrenGetSlotValue(otherVM, 0);
|
WrenHandle* testClass = wrenGetSlotHandle(otherVM, 0);
|
||||||
|
|
||||||
double startTime = (double)clock() / CLOCKS_PER_SEC;
|
double startTime = (double)clock() / CLOCKS_PER_SEC;
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ static void call(WrenVM* vm)
|
|||||||
for (int i = 0; i < iterations; i++)
|
for (int i = 0; i < iterations; i++)
|
||||||
{
|
{
|
||||||
wrenEnsureSlots(otherVM, 5);
|
wrenEnsureSlots(otherVM, 5);
|
||||||
wrenSetSlotValue(otherVM, 0, testClass);
|
wrenSetSlotHandle(otherVM, 0, testClass);
|
||||||
wrenSetSlotDouble(otherVM, 1, 1.0);
|
wrenSetSlotDouble(otherVM, 1, 1.0);
|
||||||
wrenSetSlotDouble(otherVM, 2, 2.0);
|
wrenSetSlotDouble(otherVM, 2, 2.0);
|
||||||
wrenSetSlotDouble(otherVM, 3, 3.0);
|
wrenSetSlotDouble(otherVM, 3, 3.0);
|
||||||
@ -57,8 +57,8 @@ static void call(WrenVM* vm)
|
|||||||
|
|
||||||
double elapsed = (double)clock() / CLOCKS_PER_SEC - startTime;
|
double elapsed = (double)clock() / CLOCKS_PER_SEC - startTime;
|
||||||
|
|
||||||
wrenReleaseValue(otherVM, testClass);
|
wrenReleaseHandle(otherVM, testClass);
|
||||||
wrenReleaseValue(otherVM, method);
|
wrenReleaseHandle(otherVM, method);
|
||||||
wrenFreeVM(otherVM);
|
wrenFreeVM(otherVM);
|
||||||
|
|
||||||
if (result == (1.0 + 2.0 + 3.0 + 4.0) * iterations)
|
if (result == (1.0 + 2.0 + 3.0 + 4.0) * iterations)
|
||||||
|
|||||||
@ -7,117 +7,117 @@ void callRunTests(WrenVM* vm)
|
|||||||
{
|
{
|
||||||
wrenEnsureSlots(vm, 1);
|
wrenEnsureSlots(vm, 1);
|
||||||
wrenGetVariable(vm, "main", "Call", 0);
|
wrenGetVariable(vm, "main", "Call", 0);
|
||||||
WrenValue* callClass = wrenGetSlotValue(vm, 0);
|
WrenHandle* callClass = wrenGetSlotHandle(vm, 0);
|
||||||
|
|
||||||
WrenValue* noParams = wrenMakeCallHandle(vm, "noParams");
|
WrenHandle* noParams = wrenMakeCallHandle(vm, "noParams");
|
||||||
WrenValue* zero = wrenMakeCallHandle(vm, "zero()");
|
WrenHandle* zero = wrenMakeCallHandle(vm, "zero()");
|
||||||
WrenValue* one = wrenMakeCallHandle(vm, "one(_)");
|
WrenHandle* one = wrenMakeCallHandle(vm, "one(_)");
|
||||||
WrenValue* two = wrenMakeCallHandle(vm, "two(_,_)");
|
WrenHandle* two = wrenMakeCallHandle(vm, "two(_,_)");
|
||||||
WrenValue* unary = wrenMakeCallHandle(vm, "-");
|
WrenHandle* unary = wrenMakeCallHandle(vm, "-");
|
||||||
WrenValue* binary = wrenMakeCallHandle(vm, "-(_)");
|
WrenHandle* binary = wrenMakeCallHandle(vm, "-(_)");
|
||||||
WrenValue* subscript = wrenMakeCallHandle(vm, "[_,_]");
|
WrenHandle* subscript = wrenMakeCallHandle(vm, "[_,_]");
|
||||||
WrenValue* subscriptSet = wrenMakeCallHandle(vm, "[_,_]=(_)");
|
WrenHandle* subscriptSet = wrenMakeCallHandle(vm, "[_,_]=(_)");
|
||||||
|
|
||||||
// Different arity.
|
// Different arity.
|
||||||
wrenEnsureSlots(vm, 1);
|
wrenEnsureSlots(vm, 1);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenCall(vm, noParams);
|
wrenCall(vm, noParams);
|
||||||
|
|
||||||
wrenEnsureSlots(vm, 1);
|
wrenEnsureSlots(vm, 1);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenCall(vm, zero);
|
wrenCall(vm, zero);
|
||||||
|
|
||||||
wrenEnsureSlots(vm, 2);
|
wrenEnsureSlots(vm, 2);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotDouble(vm, 1, 1.0);
|
wrenSetSlotDouble(vm, 1, 1.0);
|
||||||
wrenCall(vm, one);
|
wrenCall(vm, one);
|
||||||
|
|
||||||
wrenEnsureSlots(vm, 3);
|
wrenEnsureSlots(vm, 3);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotDouble(vm, 1, 1.0);
|
wrenSetSlotDouble(vm, 1, 1.0);
|
||||||
wrenSetSlotDouble(vm, 2, 2.0);
|
wrenSetSlotDouble(vm, 2, 2.0);
|
||||||
wrenCall(vm, two);
|
wrenCall(vm, two);
|
||||||
|
|
||||||
// Operators.
|
// Operators.
|
||||||
wrenEnsureSlots(vm, 1);
|
wrenEnsureSlots(vm, 1);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenCall(vm, unary);
|
wrenCall(vm, unary);
|
||||||
|
|
||||||
wrenEnsureSlots(vm, 2);
|
wrenEnsureSlots(vm, 2);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotDouble(vm, 1, 1.0);
|
wrenSetSlotDouble(vm, 1, 1.0);
|
||||||
wrenCall(vm, binary);
|
wrenCall(vm, binary);
|
||||||
|
|
||||||
wrenEnsureSlots(vm, 3);
|
wrenEnsureSlots(vm, 3);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotDouble(vm, 1, 1.0);
|
wrenSetSlotDouble(vm, 1, 1.0);
|
||||||
wrenSetSlotDouble(vm, 2, 2.0);
|
wrenSetSlotDouble(vm, 2, 2.0);
|
||||||
wrenCall(vm, subscript);
|
wrenCall(vm, subscript);
|
||||||
|
|
||||||
wrenEnsureSlots(vm, 4);
|
wrenEnsureSlots(vm, 4);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotDouble(vm, 1, 1.0);
|
wrenSetSlotDouble(vm, 1, 1.0);
|
||||||
wrenSetSlotDouble(vm, 2, 2.0);
|
wrenSetSlotDouble(vm, 2, 2.0);
|
||||||
wrenSetSlotDouble(vm, 3, 3.0);
|
wrenSetSlotDouble(vm, 3, 3.0);
|
||||||
wrenCall(vm, subscriptSet);
|
wrenCall(vm, subscriptSet);
|
||||||
|
|
||||||
// Returning a value.
|
// Returning a value.
|
||||||
WrenValue* getValue = wrenMakeCallHandle(vm, "getValue()");
|
WrenHandle* getValue = wrenMakeCallHandle(vm, "getValue()");
|
||||||
wrenEnsureSlots(vm, 1);
|
wrenEnsureSlots(vm, 1);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenCall(vm, getValue);
|
wrenCall(vm, getValue);
|
||||||
WrenValue* value = wrenGetSlotValue(vm, 0);
|
WrenHandle* value = wrenGetSlotHandle(vm, 0);
|
||||||
|
|
||||||
// Different argument types.
|
// Different argument types.
|
||||||
wrenEnsureSlots(vm, 3);
|
wrenEnsureSlots(vm, 3);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotBool(vm, 1, true);
|
wrenSetSlotBool(vm, 1, true);
|
||||||
wrenSetSlotBool(vm, 2, false);
|
wrenSetSlotBool(vm, 2, false);
|
||||||
wrenCall(vm, two);
|
wrenCall(vm, two);
|
||||||
|
|
||||||
wrenEnsureSlots(vm, 3);
|
wrenEnsureSlots(vm, 3);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotDouble(vm, 1, 1.2);
|
wrenSetSlotDouble(vm, 1, 1.2);
|
||||||
wrenSetSlotDouble(vm, 2, 3.4);
|
wrenSetSlotDouble(vm, 2, 3.4);
|
||||||
wrenCall(vm, two);
|
wrenCall(vm, two);
|
||||||
|
|
||||||
wrenEnsureSlots(vm, 3);
|
wrenEnsureSlots(vm, 3);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotString(vm, 1, "string");
|
wrenSetSlotString(vm, 1, "string");
|
||||||
wrenSetSlotString(vm, 2, "another");
|
wrenSetSlotString(vm, 2, "another");
|
||||||
wrenCall(vm, two);
|
wrenCall(vm, two);
|
||||||
|
|
||||||
wrenEnsureSlots(vm, 3);
|
wrenEnsureSlots(vm, 3);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotNull(vm, 1);
|
wrenSetSlotNull(vm, 1);
|
||||||
wrenSetSlotValue(vm, 2, value);
|
wrenSetSlotHandle(vm, 2, value);
|
||||||
wrenCall(vm, two);
|
wrenCall(vm, two);
|
||||||
|
|
||||||
// Truncate a string, or allow null bytes.
|
// Truncate a string, or allow null bytes.
|
||||||
wrenEnsureSlots(vm, 3);
|
wrenEnsureSlots(vm, 3);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
wrenSetSlotBytes(vm, 1, "string", 3);
|
wrenSetSlotBytes(vm, 1, "string", 3);
|
||||||
wrenSetSlotBytes(vm, 2, "b\0y\0t\0e", 7);
|
wrenSetSlotBytes(vm, 2, "b\0y\0t\0e", 7);
|
||||||
wrenCall(vm, two);
|
wrenCall(vm, two);
|
||||||
|
|
||||||
// Call ignores with extra temporary slots on stack.
|
// Call ignores with extra temporary slots on stack.
|
||||||
wrenEnsureSlots(vm, 10);
|
wrenEnsureSlots(vm, 10);
|
||||||
wrenSetSlotValue(vm, 0, callClass);
|
wrenSetSlotHandle(vm, 0, callClass);
|
||||||
for (int i = 1; i < 10; i++)
|
for (int i = 1; i < 10; i++)
|
||||||
{
|
{
|
||||||
wrenSetSlotDouble(vm, i, i * 0.1);
|
wrenSetSlotDouble(vm, i, i * 0.1);
|
||||||
}
|
}
|
||||||
wrenCall(vm, one);
|
wrenCall(vm, one);
|
||||||
|
|
||||||
wrenReleaseValue(vm, callClass);
|
wrenReleaseHandle(vm, callClass);
|
||||||
wrenReleaseValue(vm, noParams);
|
wrenReleaseHandle(vm, noParams);
|
||||||
wrenReleaseValue(vm, zero);
|
wrenReleaseHandle(vm, zero);
|
||||||
wrenReleaseValue(vm, one);
|
wrenReleaseHandle(vm, one);
|
||||||
wrenReleaseValue(vm, two);
|
wrenReleaseHandle(vm, two);
|
||||||
wrenReleaseValue(vm, getValue);
|
wrenReleaseHandle(vm, getValue);
|
||||||
wrenReleaseValue(vm, value);
|
wrenReleaseHandle(vm, value);
|
||||||
wrenReleaseValue(vm, unary);
|
wrenReleaseHandle(vm, unary);
|
||||||
wrenReleaseValue(vm, binary);
|
wrenReleaseHandle(vm, binary);
|
||||||
wrenReleaseValue(vm, subscript);
|
wrenReleaseHandle(vm, subscript);
|
||||||
wrenReleaseValue(vm, subscriptSet);
|
wrenReleaseHandle(vm, subscriptSet);
|
||||||
}
|
}
|
||||||
|
|||||||
24
test/api/handle.c
Normal file
24
test/api/handle.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "handle.h"
|
||||||
|
|
||||||
|
static WrenHandle* handle;
|
||||||
|
|
||||||
|
static void setValue(WrenVM* vm)
|
||||||
|
{
|
||||||
|
handle = wrenGetSlotHandle(vm, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void getValue(WrenVM* vm)
|
||||||
|
{
|
||||||
|
wrenSetSlotHandle(vm, 0, handle);
|
||||||
|
wrenReleaseHandle(vm, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
WrenForeignMethodFn handleBindMethod(const char* signature)
|
||||||
|
{
|
||||||
|
if (strcmp(signature, "static Handle.value=(_)") == 0) return setValue;
|
||||||
|
if (strcmp(signature, "static Handle.value") == 0) return getValue;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
3
test/api/handle.h
Normal file
3
test/api/handle.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "wren.h"
|
||||||
|
|
||||||
|
WrenForeignMethodFn handleBindMethod(const char* signature);
|
||||||
11
test/api/handle.wren
Normal file
11
test/api/handle.wren
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
class Handle {
|
||||||
|
foreign static value=(value)
|
||||||
|
foreign static value
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle.value = ["list", "of", "strings"]
|
||||||
|
|
||||||
|
// Make sure the handle lives through a GC.
|
||||||
|
System.gc()
|
||||||
|
|
||||||
|
System.print(Handle.value) // expect: [list, of, strings]
|
||||||
@ -8,10 +8,10 @@
|
|||||||
#include "call.h"
|
#include "call.h"
|
||||||
#include "get_variable.h"
|
#include "get_variable.h"
|
||||||
#include "foreign_class.h"
|
#include "foreign_class.h"
|
||||||
|
#include "handle.h"
|
||||||
#include "lists.h"
|
#include "lists.h"
|
||||||
#include "new_vm.h"
|
#include "new_vm.h"
|
||||||
#include "slots.h"
|
#include "slots.h"
|
||||||
#include "value.h"
|
|
||||||
|
|
||||||
// The name of the currently executing API test.
|
// The name of the currently executing API test.
|
||||||
const char* testName;
|
const char* testName;
|
||||||
@ -42,6 +42,9 @@ static WrenForeignMethodFn bindForeignMethod(
|
|||||||
method = foreignClassBindMethod(fullName);
|
method = foreignClassBindMethod(fullName);
|
||||||
if (method != NULL) return method;
|
if (method != NULL) return method;
|
||||||
|
|
||||||
|
method = handleBindMethod(fullName);
|
||||||
|
if (method != NULL) return method;
|
||||||
|
|
||||||
method = listsBindMethod(fullName);
|
method = listsBindMethod(fullName);
|
||||||
if (method != NULL) return method;
|
if (method != NULL) return method;
|
||||||
|
|
||||||
@ -50,9 +53,6 @@ static WrenForeignMethodFn bindForeignMethod(
|
|||||||
|
|
||||||
method = slotsBindMethod(fullName);
|
method = slotsBindMethod(fullName);
|
||||||
if (method != NULL) return method;
|
if (method != NULL) return method;
|
||||||
|
|
||||||
method = valueBindMethod(fullName);
|
|
||||||
if (method != NULL) return method;
|
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Unknown foreign method '%s' for test '%s'\n", fullName, testName);
|
"Unknown foreign method '%s' for test '%s'\n", fullName, testName);
|
||||||
|
|||||||
@ -22,13 +22,13 @@ static void getSlots(WrenVM* vm)
|
|||||||
if (wrenGetSlotDouble(vm, 3) != 12.34) result = false;
|
if (wrenGetSlotDouble(vm, 3) != 12.34) result = false;
|
||||||
if (strcmp(wrenGetSlotString(vm, 4), "str") != 0) result = false;
|
if (strcmp(wrenGetSlotString(vm, 4), "str") != 0) result = false;
|
||||||
|
|
||||||
WrenValue* value = wrenGetSlotValue(vm, 5);
|
WrenHandle* handle = wrenGetSlotHandle(vm, 5);
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
// Otherwise, return the value so we can tell if we captured it correctly.
|
// Otherwise, return the value so we can tell if we captured it correctly.
|
||||||
wrenSetSlotValue(vm, 0, value);
|
wrenSetSlotHandle(vm, 0, handle);
|
||||||
wrenReleaseValue(vm, value);
|
wrenReleaseHandle(vm, handle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -39,7 +39,7 @@ static void getSlots(WrenVM* vm)
|
|||||||
|
|
||||||
static void setSlots(WrenVM* vm)
|
static void setSlots(WrenVM* vm)
|
||||||
{
|
{
|
||||||
WrenValue* value = wrenGetSlotValue(vm, 1);
|
WrenHandle* handle = wrenGetSlotHandle(vm, 1);
|
||||||
|
|
||||||
wrenSetSlotBool(vm, 1, true);
|
wrenSetSlotBool(vm, 1, true);
|
||||||
wrenSetSlotBytes(vm, 2, "by\0te", 5);
|
wrenSetSlotBytes(vm, 2, "by\0te", 5);
|
||||||
@ -64,8 +64,8 @@ static void setSlots(WrenVM* vm)
|
|||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
// Move the value into the return position.
|
// Move the value into the return position.
|
||||||
wrenSetSlotValue(vm, 0, value);
|
wrenSetSlotHandle(vm, 0, handle);
|
||||||
wrenReleaseValue(vm, value);
|
wrenReleaseHandle(vm, handle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "value.h"
|
|
||||||
|
|
||||||
static WrenValue* value;
|
|
||||||
|
|
||||||
static void setValue(WrenVM* vm)
|
|
||||||
{
|
|
||||||
value = wrenGetSlotValue(vm, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void getValue(WrenVM* vm)
|
|
||||||
{
|
|
||||||
wrenSetSlotValue(vm, 0, value);
|
|
||||||
wrenReleaseValue(vm, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
WrenForeignMethodFn valueBindMethod(const char* signature)
|
|
||||||
{
|
|
||||||
if (strcmp(signature, "static Value.value=(_)") == 0) return setValue;
|
|
||||||
if (strcmp(signature, "static Value.value") == 0) return getValue;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
#include "wren.h"
|
|
||||||
|
|
||||||
WrenForeignMethodFn valueBindMethod(const char* signature);
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
class Value {
|
|
||||||
foreign static value=(value)
|
|
||||||
foreign static value
|
|
||||||
}
|
|
||||||
|
|
||||||
Value.value = ["list", "of", "strings"]
|
|
||||||
|
|
||||||
// Do some stuff to trigger a GC (at least when GC stress testing enabled).
|
|
||||||
var s = "string"
|
|
||||||
for (i in 1...10) {
|
|
||||||
s = s + " more"
|
|
||||||
}
|
|
||||||
|
|
||||||
System.print(Value.value) // expect: [list, of, strings]
|
|
||||||
@ -55,7 +55,7 @@
|
|||||||
29DC14AA1BBA3032008A8274 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009A61B7E3993000CE58C /* main.c */; };
|
29DC14AA1BBA3032008A8274 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009A61B7E3993000CE58C /* main.c */; };
|
||||||
29DC14AB1BBA3038008A8274 /* foreign_class.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009A81B7E39A8000CE58C /* foreign_class.c */; };
|
29DC14AB1BBA3038008A8274 /* foreign_class.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009A81B7E39A8000CE58C /* foreign_class.c */; };
|
||||||
29DC14AC1BBA303D008A8274 /* slots.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009AA1B7E39A8000CE58C /* slots.c */; };
|
29DC14AC1BBA303D008A8274 /* slots.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009AA1B7E39A8000CE58C /* slots.c */; };
|
||||||
29DC14AD1BBA3040008A8274 /* value.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009AC1B7E39A8000CE58C /* value.c */; };
|
29DC14AD1BBA3040008A8274 /* handle.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009AC1B7E39A8000CE58C /* handle.c */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
@ -133,8 +133,8 @@
|
|||||||
29D009A91B7E39A8000CE58C /* foreign_class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = foreign_class.h; path = ../../test/api/foreign_class.h; sourceTree = "<group>"; };
|
29D009A91B7E39A8000CE58C /* foreign_class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = foreign_class.h; path = ../../test/api/foreign_class.h; sourceTree = "<group>"; };
|
||||||
29D009AA1B7E39A8000CE58C /* slots.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = slots.c; path = ../../test/api/slots.c; sourceTree = "<group>"; };
|
29D009AA1B7E39A8000CE58C /* slots.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = slots.c; path = ../../test/api/slots.c; sourceTree = "<group>"; };
|
||||||
29D009AB1B7E39A8000CE58C /* slots.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = slots.h; path = ../../test/api/slots.h; sourceTree = "<group>"; };
|
29D009AB1B7E39A8000CE58C /* slots.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = slots.h; path = ../../test/api/slots.h; sourceTree = "<group>"; };
|
||||||
29D009AC1B7E39A8000CE58C /* value.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = value.c; path = ../../test/api/value.c; sourceTree = "<group>"; };
|
29D009AC1B7E39A8000CE58C /* handle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = handle.c; path = ../../test/api/handle.c; sourceTree = "<group>"; };
|
||||||
29D009AD1B7E39A8000CE58C /* value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = value.h; path = ../../test/api/value.h; sourceTree = "<group>"; };
|
29D009AD1B7E39A8000CE58C /* handle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handle.h; path = ../../test/api/handle.h; sourceTree = "<group>"; };
|
||||||
29D025E01C19CD1000A3BB28 /* process.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = process.c; path = ../../src/module/process.c; sourceTree = "<group>"; };
|
29D025E01C19CD1000A3BB28 /* process.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = process.c; path = ../../src/module/process.c; sourceTree = "<group>"; };
|
||||||
29D025E11C19CD1000A3BB28 /* process.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = process.h; path = ../../src/module/process.h; sourceTree = "<group>"; };
|
29D025E11C19CD1000A3BB28 /* process.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = process.h; path = ../../src/module/process.h; sourceTree = "<group>"; };
|
||||||
29D025E21C19CD1000A3BB28 /* process.wren.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = process.wren.inc; path = ../../src/module/process.wren.inc; sourceTree = "<group>"; };
|
29D025E21C19CD1000A3BB28 /* process.wren.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = process.wren.inc; path = ../../src/module/process.wren.inc; sourceTree = "<group>"; };
|
||||||
@ -270,14 +270,14 @@
|
|||||||
29D009A91B7E39A8000CE58C /* foreign_class.h */,
|
29D009A91B7E39A8000CE58C /* foreign_class.h */,
|
||||||
2949AA8B1C2F14F000B106BA /* get_variable.c */,
|
2949AA8B1C2F14F000B106BA /* get_variable.c */,
|
||||||
2949AA8C1C2F14F000B106BA /* get_variable.h */,
|
2949AA8C1C2F14F000B106BA /* get_variable.h */,
|
||||||
|
29D009AC1B7E39A8000CE58C /* handle.c */,
|
||||||
|
29D009AD1B7E39A8000CE58C /* handle.h */,
|
||||||
29932D521C210F8D00099DEE /* lists.c */,
|
29932D521C210F8D00099DEE /* lists.c */,
|
||||||
29932D531C210F8D00099DEE /* lists.h */,
|
29932D531C210F8D00099DEE /* lists.h */,
|
||||||
29C946961C88F14F00B4A4F3 /* new_vm.c */,
|
29C946961C88F14F00B4A4F3 /* new_vm.c */,
|
||||||
29C946971C88F14F00B4A4F3 /* new_vm.h */,
|
29C946971C88F14F00B4A4F3 /* new_vm.h */,
|
||||||
29D009AA1B7E39A8000CE58C /* slots.c */,
|
29D009AA1B7E39A8000CE58C /* slots.c */,
|
||||||
29D009AB1B7E39A8000CE58C /* slots.h */,
|
29D009AB1B7E39A8000CE58C /* slots.h */,
|
||||||
29D009AC1B7E39A8000CE58C /* value.c */,
|
|
||||||
29D009AD1B7E39A8000CE58C /* value.h */,
|
|
||||||
);
|
);
|
||||||
name = api_test;
|
name = api_test;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -409,7 +409,7 @@
|
|||||||
29A427351BDBE435001E6E22 /* wren_opt_meta.c in Sources */,
|
29A427351BDBE435001E6E22 /* wren_opt_meta.c in Sources */,
|
||||||
29DC14AB1BBA3038008A8274 /* foreign_class.c in Sources */,
|
29DC14AB1BBA3038008A8274 /* foreign_class.c in Sources */,
|
||||||
29DC14AC1BBA303D008A8274 /* slots.c in Sources */,
|
29DC14AC1BBA303D008A8274 /* slots.c in Sources */,
|
||||||
29DC14AD1BBA3040008A8274 /* value.c in Sources */,
|
29DC14AD1BBA3040008A8274 /* handle.c in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user