-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a tutorial on Juvix module to JS interop via Wasm
- Loading branch information
1 parent
c496aa7
commit 557ca1d
Showing
5 changed files
with
116 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
- [[./nodejs-interop.md][NodeJS Interop]] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
* NodeJS Interop | ||
|
||
A Juvix module can be compiled to a Wasm module. When a Wasm module is | ||
instantiated by a host, functions from the host can be injected into a Wasm | ||
module and functions from the Wasm module can be called by the host. | ||
|
||
In this tutorial you will see how to call host functions in Juvix and call Juvix | ||
functions from the host using the Wasm mechanism. | ||
|
||
** The Juvix module | ||
|
||
The following Juvix module has two functions. | ||
|
||
The function =hostDisplayString= is an =axiom= with no corresponding =compile= | ||
block that implements it. We will inject an implementation for this function | ||
when we instantiate the module from NodeJS. | ||
|
||
The function =juvixRender= is a normal Juvix function. We will call this from | ||
NodeJS. | ||
|
||
#+begin_src | ||
-- NodeJsInterop.juvix | ||
module NodeJsInterop; | ||
|
||
open import Stdlib.Prelude; | ||
|
||
axiom hostDisplayString : String → IO; | ||
|
||
juvixRender : IO; | ||
juvixRender ≔ hostDisplayString "Hello World from Juvix!"; | ||
|
||
end; | ||
#+end_src | ||
|
||
** Compiling the Juvix module | ||
|
||
The Juvix module can be compiled using the following command: | ||
|
||
#+begin_src | ||
juvix compile -r standalone NodeJsInterop.juvix | ||
#+end_src | ||
|
||
This will create a file containing a Wasm module called =NodeJsInterop.wasm=. | ||
|
||
** The NodeJS module | ||
|
||
The following NodeJS module demonstrates both calling a Juvix function from | ||
NodeJS and injecting a NodeJS function into a Juvix module. | ||
|
||
The NodeJS function =hostDisplayString= is passed to the Wasm module | ||
=NodeJSInterop.wasm= when it is instantiated. After instantiation the Juvix | ||
function =juvixRender= is called. | ||
|
||
The functions =ptrToCstr= and =cstrlen= are necessary to convert the =char= | ||
pointer passed from Juvix to a JS =String=. | ||
|
||
#+begin_src | ||
-- NodeJSInterop.js | ||
const fs = require('fs'); | ||
let wasmModule = null; | ||
|
||
function cstrlen(mem, ptr) { | ||
let len = 0; | ||
while (mem[ptr] != 0) { | ||
len++; | ||
ptr++; | ||
} | ||
return len; | ||
} | ||
|
||
function ptrToCstr(ptr) { | ||
const wasmMemory = wasmModule.instance.exports.memory.buffer; | ||
const mem = new Uint8Array(wasmMemory); | ||
const len = cstrlen(mem, ptr); | ||
const bytes = new Uint8Array(wasmMemory, ptr, len); | ||
return new TextDecoder().decode(bytes); | ||
} | ||
|
||
function hostDisplayString(strPtr) { | ||
const text = ptrToCstr(strPtr); | ||
console.log(text); | ||
} | ||
|
||
const wasmBuffer = fs.readFileSync("NodeJsInterop.wasm"); | ||
WebAssembly.instantiate(wasmBuffer, { | ||
env: { | ||
hostDisplayString, | ||
} | ||
}).then((w) => { | ||
wasmModule = w; | ||
wasmModule.instance.exports.juvixRender(); | ||
}); | ||
#+end_src | ||
|
||
** Running the Wasm module | ||
|
||
Now you should have the files =NodeJsInterop.wasm= and =NodeJsInterop.js= in the | ||
same directory. Run the following command to execute the module: | ||
|
||
#+begin_src | ||
node NodeJsInterop.js | ||
#+end_src | ||
|
||
You should see the following output: | ||
|
||
#+begin_src | ||
Hello World from Juvix! | ||
#+end_src |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters