wat-mode is an Emacs major mode for WebAssembly’s text format based on lisp-mode. It currently supports:
- syntax highlighting for all core WebAssembly keywords including .wast, SIMD, and threading extensions
- s-expression indentation (from lisp-mode)
- an experimental macro assembler
wat-mode can be helpful to those writing WebAssembly by hand. It pairs well with the WebAssembly Binary Toolkit.
Put the contents of this directory somewhere on your load-path, i.e.,:
(add-to-list 'load-path "<path>/<to>/<wat-mode>/") ... (require 'wat-mode)
The intent is to distribute wat-mode via MELPA after a bit more testing.
To use wat-mode, visit any file with a .wat or .wast file extension.
wat-mode inherits the default indentation behavior of
lisp-mode. If you’d like to change it, you can
set-variable RET wat-mode-indent-offset RET value
RET
. wat-mode-indent-offset
is bound to lisp-indent-offset
under
the hood and its behavior is identical. See
Customizing Lisp Indentation of the Emacs Manual for details.
wat-mode supports syntax highlighting for all core WebAssembly keywords. Highlighting support comes in four levels with increasing coverage:
- wat-mode-font-lock-keywords-1: Only top-level keyords (e.g., module, table, func, etc).
- wat-mode-font-lock-keywords-2: level (1) plus support for all data types and instructions excluding memory and numerical instructions.
- wat-mode-font-lock-keywords-3: level (2) plus support for identifiers and both memory and numerical instructions. This includes support for the SIMD and threading extensions.
- wat-mode-font-lock-keywords-4: level (3) plus support for .wast keywords.
The active highlighting level is bound to
wat-mode-font-lock-keywords
. wat-mode-font-lock-keywords-4
is
used by default.
wat-mode introduces a single new keyword to WebAssembly syntax:
@
(pronounced “w-at”). @
allows the definition of macros
by leveraging the elisp runtime.
Say you’re writing an emulator for a particular register machine. You’d like to have shorthand for defining and operating on the virtual machine registers. In wat-mode, you might make a register constructor like
(@ define-register (name initial-value) (global ,name (mut i32) (i32.const ,initial-value)))
and then define register operations:
(@ op-reg (reg value op) (set_global ,reg (,op (get_global ,reg) ,value))) (@ reg.add (reg value) (op-reg ,reg ,value i32.add)) (@ reg.sub (reg value) (op-reg ,reg ,value i32.sub))
You could define these macros interactively using eval-last-sexp
(C-x C-e
) or define them in a separate file to be loaded with
before your .wat files.
Once defined and loaded, macros can be used like folded instructions in standard .wat files.
(define-register $W 0) ... (func $do-add (reg.add $W 2))
You can evaluate a macro interactively by placing point at the
start of the macro form and invoking wat-mode-macro-expand
(C-c 1
).
The expanded definition includes annotating information on the macro
that produced it – a primitive aid to debugging until something
better is written. Undoing the operation (C-x u
) will return the
macro to its unevaluated form.
Macro expansion is useful during program development. It can also be run in batch:
emacs -batch -L . -l ~/.emacs -l $(ROOT)/demo/regm.el $(ROOT)/demo/reg.wat -f wat-mode-macro-expand -f save-buffer
The expanded macro will be saved back to $(ROOT)/demo/reg.wat
with the
original module saved to $(ROOT)/demo/reg.wat~
.
Expect macro support to evolve or be removed entirely if it turns out to be a Bad Idea.
I made wat-mode for my own use. There’s loads or room for improvement. Have
ideas to make it better? M-x make-pull-request
!
wat-mode is licensed under GPLv3. See LICENSE.