Skip to content

Commit

Permalink
[interpreter] Build wast.js with Js_of_ocaml (#1507)
Browse files Browse the repository at this point in the history
  • Loading branch information
takikawa authored Aug 4, 2022
1 parent 8159541 commit 40dca73
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 129 deletions.
11 changes: 11 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ jobs:
- run: opam install --yes ocamlbuild.0.14.0
- run: cd interpreter && opam exec make all

ref-interpreter-js-library:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup OCaml
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: 4.12.x
- run: opam install --yes ocamlbuild.0.14.0 ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0
- run: cd interpreter && opam exec make wast.js

build-js-api-spec:
runs-on: ubuntu-latest
steps:
Expand Down
24 changes: 13 additions & 11 deletions interpreter/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# package manager to build. However, Opam package management is available
# optionally through the check/install/uninstall targets.
#
# The $(JSLIB) target requires node.js and BuckleScript.
# The $(JSLIB).js target requires Js_of_ocaml (using ocamlfind).
#
# See README.me for instructions.

Expand All @@ -14,14 +14,15 @@ UNOPT = $(NAME).debug
OPT = $(NAME)
LIB = $(NAME)
ZIP = $(NAME).zip
JSLIB = wast.js
JSLIB = wast
WINMAKE = winmake.bat

DIRS = util syntax binary text valid runtime exec script host main tests
LIBS = bigarray
FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45-70 -warn-error +a-3'
OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %)
OCB = $(OCBA) $(LIBS:%=-libs %)
JSO = js_of_ocaml -q --opt 3
JS = # set to JS shell command to run JS tests


Expand All @@ -35,7 +36,7 @@ opt: $(OPT)
unopt: $(UNOPT)
libopt: _build/$(LIB).cmx _build/$(LIB).cmxa
libunopt: _build/$(LIB).cmo _build/$(LIB).cma
jslib: $(JSLIB)
jslib: $(JSLIB).js
all: unopt opt libunopt libopt test
land: $(WINMAKE) all
zip: $(ZIP)
Expand Down Expand Up @@ -108,14 +109,15 @@ _build/$(LIB).cmxa: $(FILES) $(LIB).mllib _tags Makefile
# Building JavaScript library
.PHONY: $(JSLIB)
$(JSLIB): $(UNOPT)
mkdir -p _build/jslib/src
cp meta/jslib/* _build/jslib
cp $(DIRS:%=_build/%/*.ml*) meta/jslib/*.ml _build/jslib/src
rm _build/jslib/src/*.ml[^i]
(cd _build/jslib; ./build.sh ../../$@)
JSLIB_DIR = meta/jslib
JSLIB_FLAGS = -I $(JSLIB_DIR) -use-ocamlfind -pkg js_of_ocaml -pkg js_of_ocaml-ppx
.INTERMEDIATE: $(JSLIB).byte
$(JSLIB).byte: $(JSLIB_DIR)/$(JSLIB).ml
$(OCBA) $(JSLIB_FLAGS) $@
$(JSLIB).js: $(JSLIB).byte
$(JSO) $<
# Building Windows build file
Expand Down Expand Up @@ -181,7 +183,7 @@ $(ZIP): $(WINMAKE)
git archive --format=zip --prefix=$(NAME)/ -o $@ HEAD
clean:
rm -rf _build/jslib $(LIB).mlpack _tags
rm -rf _build/jslib $(LIB).mlpack _tags $(JSLIB).js
$(OCB) -clean
Expand Down
23 changes: 20 additions & 3 deletions interpreter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ The Makefile also provides a target to compile (parts of) the interpreter into a
```
make wast.js
```
Building this target requires node.js and BuckleScript.
Building this target requires `js_of_ocaml`, which can be installed with OPAM:
```
opam install js_of_ocaml js_of_ocaml-ppx
```


## Synopsis
Expand Down Expand Up @@ -139,7 +142,7 @@ WebAssemblyText.encode(source)
```
which turns a module in S-expression syntax into a WebAssembly binary, and
```
WebAssemblyText.decode(binary, width = 80)
WebAssemblyText.decode(binary, width)
```
which pretty-prints a binary back into a canonicalised S-expression string.

Expand All @@ -151,7 +154,7 @@ let binary = WebAssemblyText.encode(source)
(new WebAssembly.Instance(new WebAssembly.Module(binary))).exports.f(3, 4)
// => 7
WebAssemblyText.decode(binary)
WebAssemblyText.decode(binary, 80)
// =>
// (module
// (type $0 (func (param i32 i32) (result i32)))
Expand All @@ -160,6 +163,20 @@ WebAssemblyText.decode(binary)
// )
```

Depending on how you load the library, the object may be accessed in different ways. For example, using `require` in node.js:

```
let wast = require("./wast.js");
let binary = wast.WebAssemblyText.encode("(module)");
```

Or using `load` from a JavaScript shell:

```
load("./wast.js");
let binary = WebAssemblyText.encode("(module)");
```


## S-Expression Syntax

Expand Down
5 changes: 2 additions & 3 deletions interpreter/dune
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
(name wasm)
; The 'main' module shall not be part of the library, as it would start the
; Wasm REPL every time in all the dependencies.
; We also need to exclude the 'wasm' module as it overlaps with the library
; name.
; We exclude the 'wast' module as it is only used for the JS build.
; 'smallint' is a separate test module.
(modules :standard \ main wasm smallint))
(modules :standard \ main smallint wast))

(executable
(name main)
Expand Down
6 changes: 0 additions & 6 deletions interpreter/meta/jslib/bsconfig.json

This file was deleted.

97 changes: 0 additions & 97 deletions interpreter/meta/jslib/build.sh

This file was deleted.

9 changes: 0 additions & 9 deletions interpreter/meta/jslib/wasm.ml

This file was deleted.

26 changes: 26 additions & 0 deletions interpreter/meta/jslib/wast.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
(* Implements a wrapper library that allows the use of the reference
* interpreter's encode/decode functionality in JavaScript.
*)
open Js_of_ocaml

let _ =
Js.export "WebAssemblyText"
(object%js (_self)

method encode (s : Js.js_string Js.t) : (Typed_array.arrayBuffer Js.t) =
let def = Parse.string_to_module (Js.to_string s) in
let bs =
match def.Source.it with
| Script.Textual m -> (Encode.encode m)
| Script.Encoded (_, bs) -> bs
| Script.Quoted (_, _) -> failwith "Unsupported" in
let buf = new%js Typed_array.arrayBuffer (String.length bs) in
let u8arr = new%js Typed_array.uint8Array_fromBuffer buf in
String.iteri (fun i c -> Typed_array.set u8arr i (int_of_char c)) bs; buf

method decode (buf : Typed_array.arrayBuffer Js.t) width : (Js.js_string Js.t) =
let s = Typed_array.String.of_uint8Array (new%js Typed_array.uint8Array_fromBuffer buf) in
let m = Decode.decode "(decode)" s in
Js.string (Sexpr.to_string width (Arrange.module_ m))

end)

0 comments on commit 40dca73

Please sign in to comment.