Tweak the embedding docs a bit.

This commit is contained in:
Bob Nystrom
2015-10-02 21:25:55 -07:00
parent d61d7fd5b4
commit e41d9eac7c

View File

@ -2,8 +2,8 @@
^category reference
Wren is designed to be a scripting language, so the embedding API is as
important as any of its language features. There are two (well, three) ways to get Wren into
your application:
important as any of its language features. There are two (well, three) ways to
get Wren into your application:
1. **Link to static or dynamic library.** When you [build Wren][build], it
generates both shared and static libraries in `lib` that you can link to.
@ -15,15 +15,15 @@ your application:
[build]: getting-started.html
You also want to add `src/include` to your include path so you can get to the
[public header for Wren][wren.h]:
In either case, you also want to add `src/include` to your include path so you
can get to the [public header for Wren][wren.h]:
[wren.h]: https://github.com/munificent/wren/blob/master/src/include/wren.h
:::c
#include "wren.h"
## Hosting a Wren VM
## Creating a Wren VM
Once you've integrated the code into your executable, you need to create a
virtual machine. To do that, you first fill in a `WrenConfiguration`:
@ -32,24 +32,34 @@ virtual machine. To do that, you first fill in a `WrenConfiguration`:
WrenConfiguration config;
wrenInitConfiguration(&config);
This gives you a basic configuration that has reasonable defaults for
everything. If you don't need to tweak stuff, you can leave it at that. If you
do want to turn some knobs and dials, it exposes some fields you can set:
:::c
config.reallocateFn = ...;
config.loadModuleFn = ...;
config.bindForeignMethodFn = ...;
config.bindForeignClassFn = ...;
config.initialHeapSize = ...;
config.minHeapSize = ...;
config.heapGrowthPercent = ...;
The `reallocateFn` is a callback you can provide to control how Wren allocates
and frees memory. If you leave that to the default, it uses `malloc()` and
`free()`.
The next three callbacks are how Wren talks back to your program. We'll cover
those in detail later. Then there a few fields to let you tune how the garbage
collector runs. You can tweak these if you want, but the defaults are usually
fine.
:::c
config.loadModuleFn = ...;
config.bindForeignMethodFn = ...;
config.bindForeignClassFn = ...;
Now you can create a VM:
These three callbacks are how Wren talks back to your program. We'll cover
them in detail later.
:::c
config.initialHeapSize = ...;
config.minHeapSize = ...;
config.heapGrowthPercent = ...;
These let you tune how the garbage collector runs. You can tweak these if you
want, but the defaults are usually fine.
With this ready, you can create the VM:
:::c
WrenVM* vm = wrenNewVM(&config);
@ -72,18 +82,28 @@ You can tell the VM to execute a string of Wren source code like so:
"<where>",
"System.print(\"Hi!\")");
The first string parameter is a "source path". It's just an arbitrary string that describes where the source code is from. It's what shows up in stack traces if a runtime error occurs in the code. It can be whatever you want as long as it's not `NULL`.
The first string parameter is a "source path". It's just an arbitrary string
that describes where the source code is from. It's what shows up in stack traces
if a runtime error occurs in the code. It can be whatever you want as long as
it's not `NULL`.
The other string is the chunk of code to executea series of one or more
The other string is the chunk of code to execute&mdash;a series of one or more
statements separated by newlines. Wren runs this code in a special "main"
module. Each time you call this, the code is run in the same module. This way,
top-level names defined in one call can be accessed in later ones.
When you call `wrenInterpret()`, Wren first compiles your source to bytecode. If an error occurs here, it returns immediately with `WREN_RESULT_COMPILE_ERROR`. Otherwise, Wren spins up a new [fiber][] and executes the code in that. Your code can in turn spawn whatever other fibers it wants. It keeps running fibers until they all complete.
When you call `wrenInterpret()`, Wren first compiles your source to bytecode. If
an error occurs here, it returns immediately with `WREN_RESULT_COMPILE_ERROR`.
Otherwise, Wren spins up a new [fiber][] and executes the code in that. Your
code can in turn spawn whatever other fibers it wants. It keeps running fibers
until they all complete.
[fiber]: fibers.html
If a [runtime error][] occurs (and another fiber doesn't catch it), it will abort fibers all the way back to the main one and then return `WREN_RESULT_RUNTIME_ERROR`. Otherwise, when the last fiber successfully returns, it returns `WREN_RESULT_SUCCESS`.
If a [runtime error][] occurs (and another fiber doesn't catch it), it will
abort fibers all the way back to the main one and then return
`WREN_RESULT_RUNTIME_ERROR`. Otherwise, when the last fiber successfully
returns, it returns `WREN_RESULT_SUCCESS`.
[runtime error]: error-handling.html
@ -105,11 +125,15 @@ If a [runtime error][] occurs (and another fiber doesn't catch it), it will abor
## Shutting down a VM
Once the party is over and you're ready to end your relationship with a VM, you need to free any memory it allocated. You do that like so:
Once the party is over and you're ready to end your relationship with a VM, you
need to free any memory it allocated. You do that like so:
:::c
wrenFreeVM(vm);
After calling that, you obviously cannot use the `WrenVM*` you passed to it again. It's dead.
After calling that, you obviously cannot use the `WrenVM*` you passed to it
again. It's dead.
Note that Wren will yell at you if you still have any live `WrenValue` or `WrenMethod` 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 been freed.
Note that Wren will yell at you if you still have any live `WrenValue` 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 been freed.