mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-12 14:48:40 +01:00
316 lines
14 KiB
HTML
316 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
|
|
<title>Embedding – Wren</title>
|
|
<script type="application/javascript" src="../prism.js" data-manual></script>
|
|
<script type="application/javascript" src="../wren.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="../prism.css" />
|
|
<link rel="stylesheet" type="text/css" href="../style.css" />
|
|
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
|
|
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
|
|
the viewport. -->
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
|
|
</head>
|
|
<body id="top" class="embedding">
|
|
<header>
|
|
<div class="page">
|
|
<div class="main-column">
|
|
<h1><a href="../">wren</a></h1>
|
|
<h2>a classy little scripting language</h2>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
<div class="page">
|
|
<nav class="big">
|
|
<a href="../"><img src="../wren.svg" class="logo"></a>
|
|
<ul>
|
|
<li><a href="../">Back to Wren</a></li>
|
|
</ul>
|
|
<section>
|
|
<h2>embedding</h2>
|
|
<ul>
|
|
<li><a href="./">Introduction</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-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="configuring-the-vm.html">Configuring the VM</a></li>
|
|
</ul>
|
|
</section>
|
|
</nav>
|
|
<nav class="small">
|
|
<table>
|
|
<tr>
|
|
<td><h2>embedding</h2></td>
|
|
<td><h2>?</h2></td>
|
|
<td><h2>?</h2></td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<ul>
|
|
<li><a href="./">Introduction</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-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="configuring-the-vm.html">Configuring the VM</a></li>
|
|
</ul>
|
|
</td>
|
|
<td>
|
|
<ul>
|
|
</ul>
|
|
</td>
|
|
<td>
|
|
<ul>
|
|
</ul>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</nav>
|
|
<main>
|
|
<h1>Embedding</h1>
|
|
<p>Wren is designed to be a scripting language that lives inside a host
|
|
application, so the embedding API is as important as any of its language
|
|
features. Designing this API well requires satisfying several constraints:</p>
|
|
<ol>
|
|
<li>
|
|
<p><strong>Wren is dynamically typed, but C is not.</strong> A variable can hold a value of
|
|
any type in Wren, but that’s definitely not the case in C unless you define
|
|
some sort of variant type, which ultimately just kicks the problem down the
|
|
road. Eventually, we have to move data across the boundary between statically and dynamically typed code.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>Wren uses garbage collection, but C manages memory manually.</strong> GC adds a
|
|
few constraints on the API. The VM must be able to find every Wren object
|
|
that is still usable, even if that object is being referenced from native C
|
|
code. Otherwise, Wren could free an object that’s still in use.</p>
|
|
<p>Also, we ideally don’t want to let native C code see a bare pointer to a
|
|
chunk of memory managed by Wren. Many garbage collection strategies involve
|
|
<a href="https://en.wikipedia.org/wiki/Tracing_garbage_collection#Copying_vs._mark-and-sweep_vs._mark-and-don.27t-sweep">moving objects</a> in memory. If we allow C code to point directly to an
|
|
object, that pointer will be left dangling when the object moves. Wren’s GC
|
|
doesn’t move objects today, but we would like to keep that option for the
|
|
future.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>The embedding API needs to be fast.</strong> Users may add layers of abstraction
|
|
on top of the API to make it more pleasant to work with, but the base API
|
|
defines the <em>maximum</em> performance you can get out of the system. It’s the
|
|
bottom of the stack, so there’s no way for a user to optimize around it if
|
|
it’s too slow. There is no lower level alternative.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>We want the API to be pleasant to use.</strong> This is the last constraint
|
|
because it’s the softest. Of course, we want a beautiful, usable API. But we
|
|
really <em>need</em> to handle the above, so we’re willing to make things a bit more
|
|
of a chore to reach the first three goals.</p>
|
|
</li>
|
|
</ol>
|
|
<p>Fortunately, we aren’t the first people to tackle this. If you’re familiar with
|
|
<a href="https://www.lua.org/pil/24.html">Lua’s C API</a>, you’ll find Wren’s similar.</p>
|
|
<h3>Performance and safety <a href="#performance-and-safety" name="performance-and-safety" class="header-anchor">#</a></h3>
|
|
<p>When code is safely snuggled within the confines of the VM, it’s pretty safe.
|
|
Method calls are dynamically checked and generate runtime errors which can be
|
|
caught and handled. The stack grows if it gets close to overflowing. In general,
|
|
when you’re within Wren code, it tries very hard to avoid crashing and burning.</p>
|
|
<p>This is why you use a high level language after all—it’s safer and more
|
|
productive than C. C, meanwhile, really assumes you know what you’re doing. You
|
|
can cast pointers in invalid ways, misinterpret bits, use memory after freeing
|
|
it, etc. What you get in return is blazing performance. Many of the reasons C is
|
|
fast are because it takes all the governors and guardrails off.</p>
|
|
<p>Wren’s embedding API defines the border between those worlds, and takes on some
|
|
of the characteristics of C. When you call any of the embedding API functions,
|
|
it assumes you are calling them correctly. If you invoke a Wren method from C
|
|
that expects three arguments, it trusts that you gave it three arguments.</p>
|
|
<p>In debug builds, Wren has assertions to check as many things as it can, but in
|
|
release builds, Wren expects you to do the right thing. This means you need to
|
|
take care when using the embedding API, just like you do in all C code you
|
|
write. In return, you get an API that is quite fast.</p>
|
|
<h2>Including Wren <a href="#including-wren" name="including-wren" class="header-anchor">#</a></h2>
|
|
<p>There are two (well, three) ways to get the Wren VM into your program:</p>
|
|
<ol>
|
|
<li>
|
|
<p><strong>Link to the static or dynamic library.</strong> When you <a href="../getting-started.html">build Wren</a>, it
|
|
generates both shared and static libraries in <code>lib</code> that you can link to.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>Include the source directly in your application.</strong> If you want to include
|
|
the source directly in your program, you don’t need to run any build steps.
|
|
Just add the source files in <code>src/vm</code> to your project. They should compile
|
|
cleanly as C99 or C++98 or anything later.</p>
|
|
</li>
|
|
</ol>
|
|
<p>In either case, you also want to add <code>src/include</code> to your include path so you
|
|
can find the <a href="https://github.com/wren-lang/wren/blob/main/src/include/wren.h">public header for Wren</a>:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
#include "wren.h"
|
|
</pre>
|
|
|
|
<p>Wren depends only on the C standard library, so you don’t usually need to link
|
|
to anything else. On some platforms (at least BSD and Linux) some of the math
|
|
functions in <code>math.h</code> are implemented in a separate library, <a href="https://en.wikipedia.org/wiki/C_mathematical_functions#libm">libm</a>, that you
|
|
have to explicitly link to.</p>
|
|
<p>If your program is in C++ but you are linking to the Wren library compiled as C,
|
|
this header handles the differences in calling conventions between C and C++:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
#include "wren.hpp"
|
|
</pre>
|
|
|
|
<h2>Creating a Wren VM <a href="#creating-a-wren-vm" name="creating-a-wren-vm" class="header-anchor">#</a></h2>
|
|
<p>Once you’ve integrated the code into your executable, you need to create a
|
|
virtual machine. To do that, you create a <code>WrenConfiguration</code> object and
|
|
initialize it.</p>
|
|
<pre class="snippet" data-lang="c">
|
|
WrenConfiguration config;
|
|
wrenInitConfiguration(&config);
|
|
</pre>
|
|
|
|
<p>This gives you a basic configuration that has reasonable defaults for
|
|
everything. We’ll <a href="configuring-the-vm.html">learn more</a> about what you can configure later,
|
|
but for now we’ll just add the <code>writeFn</code>, so that we can print text.</p>
|
|
<p>First we need a function that will do something with the output
|
|
that Wren sends us from <code>System.print</code> (or <code>System.write</code>). <em>Note that it doesn’t
|
|
include a newline in the output.</em></p>
|
|
<pre class="snippet" data-lang="c">
|
|
void writeFn(WrenVM* vm, const char* text) {
|
|
printf("%s", text);
|
|
}
|
|
</pre>
|
|
|
|
<p>And then, we update the configuration to point to it.</p>
|
|
<pre class="snippet" data-lang="c">
|
|
WrenConfiguration config;
|
|
wrenInitConfiguration(&config);
|
|
config.writeFn = &writeFn;
|
|
</pre>
|
|
|
|
<p>With this ready, you can create the VM:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
WrenVM* vm = wrenNewVM(&config);
|
|
</pre>
|
|
|
|
<p>This allocates memory for a new VM and initializes it. The Wren C implementation
|
|
has no global state, so every single bit of data Wren uses is bundled up inside
|
|
a WrenVM. You can have multiple Wren VMs running independently of each other
|
|
without any problems, even concurrently on different threads.</p>
|
|
<p><code>wrenNewVM()</code> stores its own copy of the configuration, so after calling it, you
|
|
can discard the WrenConfiguration struct you filled in. Now you have a live
|
|
VM, waiting to run some code!</p>
|
|
<h2>Executing Wren code <a href="#executing-wren-code" name="executing-wren-code" class="header-anchor">#</a></h2>
|
|
<p>You execute a string of Wren source code like so:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
WrenInterpretResult result = wrenInterpret(
|
|
vm,
|
|
"my_module",
|
|
"System.print(\"I am running in a VM!\")");
|
|
</pre>
|
|
|
|
<p>The string is a series of one or more statements separated by newlines. Wren
|
|
copies the string, so you can free it after calling this. When you call
|
|
<code>wrenInterpret()</code>, Wren first compiles your source to bytecode. If an error
|
|
occurs, it returns immediately with <code>WREN_RESULT_COMPILE_ERROR</code>.</p>
|
|
<p>Otherwise, Wren spins up a new <a href="../concurrency.html">fiber</a> 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 or one <a href="../modules/core/fiber.html#fiber.suspend()">suspends</a>.</p>
|
|
<p>If a <a href="../error-handling.html">runtime error</a> occurs (and another fiber doesn’t handle it), Wren aborts
|
|
fibers all the way back to the main one and returns <code>WREN_RESULT_RUNTIME_ERROR</code>.
|
|
Otherwise, when the last fiber successfully returns, it returns
|
|
<code>WREN_RESULT_SUCCESS</code>.</p>
|
|
<p>All code passed to <code>wrenInterpret()</code> runs in a special “main” module. That way,
|
|
top-level names defined in one call can be accessed in later ones. It’s similar
|
|
to a REPL session.</p>
|
|
<h2>Shutting down a VM <a href="#shutting-down-a-vm" name="shutting-down-a-vm" class="header-anchor">#</a></h2>
|
|
<p>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:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
wrenFreeVM(vm);
|
|
</pre>
|
|
|
|
<p>After calling that, you obviously cannot use the <code>WrenVM*</code> you passed to it
|
|
again. It’s dead.</p>
|
|
<p>Note that Wren will yell at you if you still have any live <a href="slots-and-handles.html#handles">WrenHandle</a>
|
|
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.</p>
|
|
<h2>A complete example <a href="#a-complete-example" name="a-complete-example" class="header-anchor">#</a></h2>
|
|
<p>Below is a complete example of the above.
|
|
You can find this file in the <a href="https://github.com/wren-lang/wren/blob/main/example/embedding/main.c">example</a> folder.</p>
|
|
<pre class="snippet" data-lang="c">
|
|
//For more details, visit https://wren.io/embedding/
|
|
|
|
#include <stdio.h>
|
|
#include "wren.h"
|
|
|
|
static void writeFn(WrenVM* vm, const char* text)
|
|
{
|
|
printf("%s", text);
|
|
}
|
|
|
|
void errorFn(WrenVM* vm, WrenErrorType errorType,
|
|
const char* module, const int line,
|
|
const char* msg)
|
|
{
|
|
switch (errorType)
|
|
{
|
|
case WREN_ERROR_COMPILE:
|
|
{
|
|
printf("[%s line %d] [Error] %s\n", module, line, msg);
|
|
} break;
|
|
case WREN_ERROR_STACK_TRACE:
|
|
{
|
|
printf("[%s line %d] in %s\n", module, line, msg);
|
|
} break;
|
|
case WREN_ERROR_RUNTIME:
|
|
{
|
|
printf("[Runtime Error] %s\n", msg);
|
|
} break;
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
|
|
WrenConfiguration config;
|
|
wrenInitConfiguration(&config);
|
|
config.writeFn = &writeFn;
|
|
config.errorFn = &errorFn;
|
|
WrenVM* vm = wrenNewVM(&config);
|
|
|
|
const char* module = "main";
|
|
const char* script = "System.print(\"I am running in a VM!\")";
|
|
|
|
WrenInterpretResult result = wrenInterpret(vm, module, script);
|
|
|
|
switch (result) {
|
|
case WREN_RESULT_COMPILE_ERROR:
|
|
{ printf("Compile Error!\n"); } break;
|
|
case WREN_RESULT_RUNTIME_ERROR:
|
|
{ printf("Runtime Error!\n"); } break;
|
|
case WREN_RESULT_SUCCESS:
|
|
{ printf("Success!\n"); } break;
|
|
}
|
|
|
|
wrenFreeVM(vm);
|
|
|
|
}
|
|
</pre>
|
|
|
|
<p>Next, we’ll learn to make that VM do useful stuff…</p>
|
|
<p><a class="right" href="slots-and-handles.html">Slots and Handles →</a></p>
|
|
</main>
|
|
</div>
|
|
<footer>
|
|
<div class="page">
|
|
<div class="main-column">
|
|
<p>Wren lives
|
|
<a href="https://github.com/wren-lang/wren">on GitHub</a>
|
|
— Made with ❤ by
|
|
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
|
|
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
|
|
</p>
|
|
<div class="main-column">
|
|
</div>
|
|
</footer>
|
|
</body>
|
|
</html>
|