WebAssembly has the code in a binary format called WASM. You can also get the text format in WebAssembly and it is called WAT (WebAssembly Text format). As a developer you are not supposed to write code in WebAssembly, instead, you have to compile high-level languages like C, C++ and Rust to WebAssembly.
Let us write WAT code stepwise.
Step 1 − The starting point in a WAT is to declare the module.
Step 2 − Let us now, add some functionality to it in the form of function.
The function is declared as shown below −
(func <parameters/result> <local variables> <function body>)
The function starts with func keyword which is followed by parameters or result.
The parameters and the return value as a result.
The parameters can have the following type supported by wasm −
The params for the functions are written as given below −
The result will be written as follows −
The function with parameters and return value will be defined as follows −
(func (param i32) (param i32) (result i64) <function body>)
The local variables are those that you need in your function. A local value to the function will be defined as follows −
(func (param i32) (param i32) (local i32) (result i64) <function body>)
Function body is the logic to be performed. The final program will look like this −
(module (func (param i32) (param i32) (local i32) (result i64) <function body>) )
Step 3 − To read and set parameters and local variables.
To read the parameters and local variables, make use of get_local and set_local command.
(module (func (param i32) (param i32) (local i32) (result i64) get_local 0 get_local 1 get_local 2 ) )
As per the function signature,
get_local 0 will give the param i32
get_local 1 will give the next parameter param i32
get_local 2 will give local value i32
Instead of referring to the parameters and locals using numeric values like 0,1,2, you can also use the name before the parameters, prefixing the name with a dollar sign.
The following example shows, how to use the name with parameters and locals.
(module (func (param $a i32) (param $b i32) (local $c i32) (result i64) get_local $a get_local $b get_local $c ) )
Step 4 − Instruction in Function body and execution.
The execution in wasm follows the stack strategy. The instructions executed are sent one by one on the stack. For example, the instruction get_local $a will push the value, it reads on the stack.
The instruction like i32.add that will add the will pop the elements from the stack.
(func (param $a i32) (param $b i32) get_local $a get_local $b i32.add )
The instruction for i32.add is ($a+$b). The final value of i32.add, will be pushed on the stack and that will be assigned to the result.
If the function signature has a result declared, there should be one value in the stack at the end of the execution. If there is no result param, the stack has to be empty at the end.
So, the final code along with function body will be as follows −
(module (func (param $a i32) (param $b i32) (result i32) get_local $a get_local $b i32.add ) )
Step 5 − Making call to the function.
The final code with the function body is as shown in step 4. Now, to call the function, we need to export it.
To export the function, it can be done with index values like 0,1, but, we can also give names. The name will be prefixed by $ and it will be added after the func keyword.
(module (func $add (param $a i32) (param $b i32) (result i32) get_local $a get_local $b i32.add ) )
The function $add has to be exported, using export keyword as shown below −
(module (func $add (param $a i32) (param $b i32) (result i32) get_local $a get_local $b i32.add ) (export "add" (func $add)) )
To test the above code in the browser, you will have to convert it into binary form (.wasm). Refer to the next chapter that shows how to convert .WAT to .WASM.