= Writing Wasm primitives

User-defined primitives can be implemented by writing Wasm modules.
These modules ({{{.wat}}} for text modules and {{{.wasm}}} for binary modules)
can be passed on the command-line.

With dune, use the option {{{(wasm_of_ocaml (wasm_files ...))}}} to specify
these runtime files.

It still makes sense to link JavaScript files to specify the possible
side-effects of some primitives (see <<a_manual chapter="linker"|JavaScript primitives>>),
or to implement some functionalities in JavaScript.
With dune, use {{{(wasm_of_ocaml (javascript_files ...))}}} to specify these files.

==@@id="data-representation"@@ Data representation

The type {{{(ref eq)}}} is used for all OCaml values.
Integers, chars, booleans, and constant constructors are mapped to {{{(ref i31)}}}.

The following types are used for blocks, strings (and bytes), floats,
float arrays, and JavaScript values. The first field of a block is its
tag, of type {{{(ref i31)}}}.

{{{
(type $block (array (mut (ref eq))))
(type $bytes (array (mut i8)))
(type $float (struct (field f64)))
(type $float_array (array (mut f64)))
(type $js (struct (ref null any)))
}}}

=== Int32, Int64, and Nativeint

Import these functions to access or allocate integers:

{{{
(import "env" "Int32_val"
   (func $Int32_val (param (ref eq)) (result i32)))
(import "env" "caml_copy_int32"
   (func $caml_copy_int32 (param i32) (result (ref eq))))
(import "env" "Nativeint_val"
   (func $Nativeint_val (param (ref eq)) (result i32)))
(import "env" "caml_copy_nativeint"
   (func $caml_copy_nativeint (param i32) (result (ref eq))))
(import "env" "Int64_val"
   (func $Int64_val (param (ref eq)) (result i64)))
(import "env" "caml_copy_int64"
   (func $caml_copy_int64 (param i64) (result (ref eq))))
}}}

==@@id="preprocessor"@@ Preprocessor

Wasm text files are passed through a preprocessor. You can run the
preprocessor manually:

{{{
wasm_of_ocaml pp test.wat
}}}

=== Conditional compilation

The preprocessor allows optional compilation based on the OCaml version:

{{{
(@if (>= ocaml_version (5 2 0))
   (@then ...)
   (@else ...))
}}}

Available operators:
* Comparisons: {{{=}}}, {{{>}}}, {{{>=}}}, {{{<}}}, {{{<=}}}, {{{<>}}}
* Boolean: {{{and}}}, {{{or}}}, {{{not}}}

=== Syntactic sugar

* **Strings**: {{{(@string "ab")}}} expands to {{{(array.new_fixed $bytes 2 (i32.const 97) (i32.const 98))}}}
* **String globals**: {{{(@string $s "ab")}}} is short for {{{(global $s (ref eq) (@string "ab"))}}}
* **Characters**: {{{(@char "a")}}} expands to {{{(i32.const 97)}}}
* **Function naming**: {{{(func (export "foo") ...)}}} expands to {{{(func $foo (export "foo") ...)}}} for better debugging

==@@id="implementing-primitives"@@ Implementing primitives

Define a primitive by exporting a Wasm function with parameters and return
value of type {{{(ref eq)}}}:

{{{
(func (export "input")
  (param $channel (ref eq))
  (param $buffer (ref eq))
  (param $offset (ref eq))
  (param $length (ref eq))
  (result (ref eq))
  ...
)
}}}

==@@id="linking-js"@@ Linking with JavaScript code

To use JavaScript functions in your Wasm primitives, import them using
the {{{js}}} namespace:

{{{
(import "js" "add" (func $add (param f64) (param f64) (result f64)))
}}}

The <<a_manual chapter="linker"|js_of_ocaml linker>> is used to include
them in the generated code.

==@@id="interfacing-js"@@ Interfacing with JavaScript

Functions defined in {{{runtime/wasm/jslib.wat}}} provide conversions
between JavaScript and OCaml values, as well as JavaScript operations
like property access and function calls:

{{{
(import "env" "caml_js_to_float"
   (func $caml_js_to_float (param (ref eq)) (result (ref eq))))
(import "env" "caml_js_get"
   (func $caml_js_get (param (ref eq)) (param (ref eq)) (result (ref eq))))
}}}

== See also

* <<a_manual chapter="wasm_overview"|Wasm_of_ocaml overview>> — General usage and features
* <<a_manual chapter="linker"|JavaScript primitives>> — Writing JavaScript primitives for js_of_ocaml
