mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-16 20:28:04 +01:00
204 lines
8.3 KiB
HTML
204 lines
8.3 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
|
|
<title>Calling C from Wren – 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>Calling C from Wren</h1>
|
|
<p>When we are ensconced within the world of Wren, the external C world is
|
|
“foreign” to us. There are two reasons we might want to bring some foreign
|
|
flavor into our VM:</p>
|
|
<ul>
|
|
<li>We want to execute code written in C.</li>
|
|
<li>We want to store raw C data.</li>
|
|
</ul>
|
|
<p>Since Wren is object-oriented, behavior lives in methods, so for the former we
|
|
have <strong>foreign methods</strong>. Likewise, data lives in objects, so for the latter, we
|
|
define <strong>foreign classes</strong>. This page is about the first, foreign methods. The
|
|
<a href="/embedding/storing-c-data.html">next page</a> covers foreign classes.</p>
|
|
<p>A foreign method looks to Wren like a regular method. It is defined on a Wren
|
|
class, it has a name and signature, and calls to it are dynamically dispatched.
|
|
The only difference is that the <em>body</em> of the method is written in C.</p>
|
|
<p>A foreign method is declared in Wren like so:</p>
|
|
<pre class="snippet">
|
|
class Math {
|
|
foreign static add(a, b)
|
|
}
|
|
</pre>
|
|
|
|
<p>The <code>foreign</code> keyword tells Wren that the method <code>add()</code> is declared on <code>Math</code>,
|
|
but implemented in C. Both static and instance methods can be foreign.</p>
|
|
<h2>Binding Foreign Methods <a href="#binding-foreign-methods" name="binding-foreign-methods" class="header-anchor">#</a></h2>
|
|
<p>When you call a foreign method, Wren needs to figure out which C function to
|
|
execute. This process is called <em>binding</em>. Binding is performed on-demand by the
|
|
VM. When a class that declares a foreign method is executed – when the <code>class</code>
|
|
statement itself is evaluated – the VM asks the host application for the C
|
|
function that should be used for the foreign method.</p>
|
|
<p>It does this through the <code>bindForeignMethodFn</code> callback you give it when you
|
|
first <a href="configuring-the-vm.html">configure the VM</a>. This callback isn’t the foreign method itself.
|
|
It’s the binding function your app uses to <em>look up</em> foreign methods.</p>
|
|
<p>Its signature is:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
WrenForeignMethodFn bindForeignMethodFn(
|
|
WrenVM* vm,
|
|
const char* module,
|
|
const char* className,
|
|
bool isStatic,
|
|
const char* signature);
|
|
</pre>
|
|
|
|
<p>Every time a foreign method is first declared, the VM invokes this callback. It
|
|
passes in the module containing the class declaration, the name of the class
|
|
containing the method, the method’s signature, and whether or not it’s a static
|
|
method. In the above example, it would pass something like:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
bindForeignMethodFn(vm, "main", "Math", true, "add(_,_)");
|
|
</pre>
|
|
|
|
<p>When you configure the VM, you give it a C callback that looks up the
|
|
appropriate function for the given foreign method and returns a pointer to it.
|
|
Something like:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
WrenForeignMethodFn bindForeignMethod(
|
|
WrenVM* vm,
|
|
const char* module,
|
|
const char* className,
|
|
bool isStatic,
|
|
const char* signature)
|
|
{
|
|
if (strcmp(module, "main") == 0)
|
|
{
|
|
if (strcmp(className, "Math") == 0)
|
|
{
|
|
if (isStatic && strcmp(signature, "add(_,_)") == 0)
|
|
{
|
|
return mathAdd; // C function for Math.add(_,_).
|
|
}
|
|
// Other foreign methods on Math...
|
|
}
|
|
// Other classes in main...
|
|
}
|
|
// Other modules...
|
|
}
|
|
</pre>
|
|
|
|
<p>This implementation is pretty tedious, but you get the idea. Feel free to do
|
|
something more clever here in your host application.</p>
|
|
<p>The important part is that it returns a pointer to a C function to use for that
|
|
foreign method. Wren does this binding step <em>once</em> when the class definition is
|
|
first executed. It then keeps the function pointer you return and associates it
|
|
with that method. This way, <em>calls</em> to the foreign method are fast.</p>
|
|
<h2>Implementing a Foreign Method <a href="#implementing-a-foreign-method" name="implementing-a-foreign-method" class="header-anchor">#</a></h2>
|
|
<p>All C functions for foreign methods have the same signature:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
void foreignMethod(WrenVM* vm);
|
|
</pre>
|
|
|
|
<p>Arguments passed from Wren are not passed as C arguments, and the method’s
|
|
return value is not a C return value. Instead – you guessed it – we go through
|
|
the <a href="/embedding/slots-and-handles.html">slot array</a>.</p>
|
|
<p>When a foreign method is called from Wren, the VM sets up the slot array with
|
|
the receiver and arguments to the call. As in calling Wren from C, the receiver
|
|
object is in slot zero, and arguments are in consecutive slots after that.</p>
|
|
<p>You use the slot API to read those arguments, and then perform whatever work you
|
|
want to in C. If you want the foreign method to return a value, place it in slot
|
|
zero. Like so:</p>
|
|
<pre class="snippet" data-lang="c">
|
|
void mathAdd(WrenVM* vm)
|
|
{
|
|
double a = wrenGetSlotDouble(vm, 1);
|
|
double b = wrenGetSlotDouble(vm, 2);
|
|
wrenSetSlotDouble(vm, 0, a + b);
|
|
}
|
|
</pre>
|
|
|
|
<p>While your foreign method is executing, the VM is completely suspended. No other
|
|
fibers run until your foreign method returns. You should <em>not</em> try to resume the
|
|
VM from within a foreign method by calling <code>wrenCall()</code> or <code>wrenInterpret()</code>.
|
|
The VM is not re-entrant.</p>
|
|
<p>This covers foreign behavior, but what about foreign <em>state</em>? For that, we need
|
|
a foreign <em>class</em>…</p>
|
|
<p><a class="right" href="storing-c-data.html">Storing C Data →</a>
|
|
<a href="calling-wren-from-c.html">← Calling Wren from C</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>
|