Files
2026-07-16 17:09:40 -06:00

254 lines
12 KiB
EmacsLisp

;;; wat.el -*- lexical-binding: t; -*-
;; based on Emacs' scheme-mode.
(eval-when-compile (require 'rx))
(eval-when-compile (require 'cl-macs))
(require 'lisp-mode)
;;; font-lock
(defconst wat-font-lock-keyword-rx
(rx bow
(or "module" "table" "elem" "param" "result" "func"
"global" "type" "export" "import" "memory" "local" "start"
"offset" "data" "field"
"sub" "rec")
eow))
(defconst wat-font-lock-type-rx
(rx bow
(or "i32" "i64" "f32" "f64"
"mut" "ref" "array" "struct" "null"
"funcref" "anyref" "eq" "eqref")
eow))
(defconst wat-font-lock-instr-rx
(rx bow
(or "unreachable" "nop" "block" "loop" "if" "else" "throw"
"throw_ref" "end" "br" "br_if" "br_table" "return" "call"
"call_indirect" "return_call" "return_call_indirect"
"call_ref" "return_call_ref" "drop" "select" "select"
"try_table" "local.get" "local.set" "local.tee" "global.get"
"global.set" "table.get" "table.set" "i32.load" "i64.load"
"f32.load" "f64.load" "i32.load8_s" "i32.load8_u"
"i32.load16_s" "i32.load16_u" "i64.load8_s" "i64.load8_u"
"i64.load16_s" "i64.load16_u" "i64.load32_s" "i64.load32_u"
"i32.store" "i64.store" "f32.store" "f64.store" "i32.store8"
"i32.store16" "i64.store8" "i64.store16" "i64.store32"
"memory.size" "memory.grow" "i32.const" "i64.const"
"f32.const" "f64.const" "i32.eqz" "i32.eq" "i32.ne" "i32.lt_s"
"i32.lt_u" "i32.gt_s" "i32.gt_u" "i32.le_s" "i32.le_u"
"i32.ge_s" "i32.ge_u" "i64.eqz" "i64.eq" "i64.ne" "i64.lt_s"
"i64.lt_u" "i64.gt_s" "i64.gt_u" "i64.le_s" "i64.le_u"
"i64.ge_s" "i64.ge_u" "f32.eq" "f32.ne" "f32.lt" "f32.gt"
"f32.le" "f32.ge" "f64.eq" "f64.ne" "f64.lt" "f64.gt" "f64.le"
"f64.ge" "i32.clz" "i32.ctz" "i32.popcnt" "i32.add" "i32.sub"
"i32.mul" "i32.div_s" "i32.div_u" "i32.rem_s" "i32.rem_u"
"i32.and" "i32.or" "i32.xor" "i32.shl" "i32.shr_s" "i32.shr_u"
"i32.rotl" "i32.rotr" "i64.clz" "i64.ctz" "i64.popcnt"
"i64.add" "i64.sub" "i64.mul" "i64.div_s" "i64.div_u"
"i64.rem_s" "i64.rem_u" "i64.and" "i64.or" "i64.xor" "i64.shl"
"i64.shr_s" "i64.shr_u" "i64.rotl" "i64.rotr" "f32.abs"
"f32.neg" "f32.ceil" "f32.floor" "f32.trunc" "f32.nearest"
"f32.sqrt" "f32.add" "f32.sub" "f32.mul" "f32.div" "f32.min"
"f32.max" "f32.copysign" "f64.abs" "f64.neg" "f64.ceil"
"f64.floor" "f64.trunc" "f64.nearest" "f64.sqrt" "f64.add"
"f64.sub" "f64.mul" "f64.div" "f64.min" "f64.max"
"f64.copysign" "i32.wrap_i64" "i32.trunc_f32_s"
"i32.trunc_f32_u" "i32.trunc_f64_s" "i32.trunc_f64_u"
"i64.extend_i32_s" "i64.extend_i32_u" "i64.trunc_f32_s"
"i64.trunc_f32_u" "i64.trunc_f64_s" "i64.trunc_f64_u"
"f32.convert_i32_s" "f32.convert_i32_u" "f32.convert_i64_s"
"f32.convert_i64_u" "f32.demote_f64" "f64.convert_i32_s"
"f64.convert_i32_u" "f64.convert_i64_s" "f64.convert_i64_u"
"f64.promote_f32" "i32.reinterpret_f32" "i64.reinterpret_f64"
"f32.reinterpret_i32" "f64.reinterpret_i64" "i32.extend8_s"
"i32.extend16_s" "i64.extend8_s" "i64.extend16_s"
"i64.extend32_s" "ref.null" "ref.is_null" "ref.func" "ref.eq"
"ref.as_non_null" "br_on_null" "br_on_non_null" "struct.new"
"struct.new_default" "struct.get" "struct.get_s"
"struct.get_u" "struct.set" "array.new" "array.new_default"
"array.new_fixed" "array.new_data" "array.new_elem"
"array.get" "array.get_s" "array.get_u" "array.set"
"array.len" "array.fill" "array.copy" "array.init_data"
"array.init_elem" "ref.test" "ref.test" "ref.cast" "ref.cast"
"br_on_cast" "br_on_cast_fail" "any.convert_extern"
"extern.convert_any" "ref.i31" "i31.get_s" "i31.get_u"
"i32.trunc_sat_f32_s" "i32.trunc_sat_f32_u"
"i32.trunc_sat_f64_s" "i32.trunc_sat_f64_u"
"i64.trunc_sat_f32_s" "i64.trunc_sat_f32_u"
"i64.trunc_sat_f64_s" "i64.trunc_sat_f64_u" "memory.init"
"data.drop" "memory.copy" "memory.fill" "table.init"
"elem.drop" "table.copy" "table.grow" "table.size"
"table.fill" "v128.load" "v128.load8x8_s" "v128.load8x8_u"
"v128.load16x4_s" "v128.load16x4_u" "v128.load32x2_s"
"v128.load32x2_u" "v128.load8_splat" "v128.load16_splat"
"v128.load32_splat" "v128.load64_splat" "v128.store"
"v128.const" "i8x16.shuffle" "i8x16.swizzle" "i8x16.splat"
"i16x8.splat" "i32x4.splat" "i64x2.splat" "f32x4.splat"
"f64x2.splat" "i8x16.extract_lane_s" "i8x16.extract_lane_u"
"i8x16.replace_lane" "i16x8.extract_lane_s"
"i16x8.extract_lane_u" "i16x8.replace_lane"
"i32x4.extract_lane" "i32x4.replace_lane" "i64x2.extract_lane"
"i64x2.replace_lane" "f32x4.extract_lane" "f32x4.replace_lane"
"f64x2.extract_lane" "f64x2.replace_lane" "i8x16.eq"
"i8x16.ne" "i8x16.lt_s" "i8x16.lt_u" "i8x16.gt_s" "i8x16.gt_u"
"i8x16.le_s" "i8x16.le_u" "i8x16.ge_s" "i8x16.ge_u" "i16x8.eq"
"i16x8.ne" "i16x8.lt_s" "i16x8.lt_u" "i16x8.gt_s" "i16x8.gt_u"
"i16x8.le_s" "i16x8.le_u" "i16x8.ge_s" "i16x8.ge_u" "i32x4.eq"
"i32x4.ne" "i32x4.lt_s" "i32x4.lt_u" "i32x4.gt_s" "i32x4.gt_u"
"i32x4.le_s" "i32x4.le_u" "i32x4.ge_s" "i32x4.ge_u" "f32x4.eq"
"f32x4.ne" "f32x4.lt" "f32x4.gt" "f32x4.le" "f32x4.ge"
"f64x2.eq" "f64x2.ne" "f64x2.lt" "f64x2.gt" "f64x2.le"
"f64x2.ge" "v128.not" "v128.and" "v128.andnot" "v128.or"
"v128.xor" "v128.bitselect" "v128.any_true" "v128.load8_lane"
"v128.load16_lane" "v128.load32_lane" "v128.load64_lane"
"v128.store8_lane" "v128.store16_lane" "v128.store32_lane"
"v128.store64_lane" "v128.load32_zero" "v128.load64_zero"
"f32x4.demote_f64x2_zero" "f64x2.promote_low_f32x4"
"i8x16.abs" "i8x16.neg" "i8x16.popcnt" "i8x16.all_true"
"i8x16.bitmask" "i8x16.narrow_i16x8_s" "i8x16.narrow_i16x8_u"
"f32x4.ceil" "f32x4.floor" "f32x4.trunc" "f32x4.nearest"
"i8x16.shl" "i8x16.shr_s" "i8x16.shr_u" "i8x16.add"
"i8x16.add_sat_s" "i8x16.add_sat_u" "i8x16.sub"
"i8x16.sub_sat_s" "i8x16.sub_sat_u" "f64x2.ceil" "f64x2.floor"
"i8x16.min_s" "i8x16.min_u" "i8x16.max_s" "i8x16.max_u"
"f64x2.trunc" "i8x16.avgr_u" "i16x8.extadd_pairwise_i8x16_s"
"i16x8.extadd_pairwise_i8x16_u"
"i32x4.extadd_pairwise_i16x8_s"
"i32x4.extadd_pairwise_i16x8_u" "i16x8.abs" "i16x8.neg"
"i16x8.q15mulr_sat_s" "i16x8.all_true" "i16x8.bitmask"
"i16x8.narrow_i32x4_s" "i16x8.narrow_i32x4_u"
"i16x8.extend_low_i8x16_s" "i16x8.extend_high_i8x16_s"
"i16x8.extend_low_i8x16_u" "i16x8.extend_high_i8x16_u"
"i16x8.shl" "i16x8.shr_s" "i16x8.shr_u" "i16x8.add"
"i16x8.add_sat_s" "i16x8.add_sat_u" "i16x8.sub"
"i16x8.sub_sat_s" "i16x8.sub_sat_u" "f64x2.nearest"
"i16x8.mul" "i16x8.min_s" "i16x8.min_u" "i16x8.max_s"
"i16x8.max_u" "i16x8.avgr_u" "i16x8.extmul_low_i8x16_s"
"i16x8.extmul_high_i8x16_s" "i16x8.extmul_low_i8x16_u"
"i16x8.extmul_high_i8x16_u" "i32x4.abs" "i32x4.neg"
"i32x4.all_true" "i32x4.bitmask" "i32x4.extend_low_i16x8_s"
"i32x4.extend_high_i16x8_s" "i32x4.extend_low_i16x8_u"
"i32x4.extend_high_i16x8_u" "i32x4.shl" "i32x4.shr_s"
"i32x4.shr_u" "i32x4.add" "i32x4.sub" "i32x4.mul"
"i32x4.min_s" "i32x4.min_u" "i32x4.max_s" "i32x4.max_u"
"i32x4.dot_i16x8_s" "i32x4.extmul_low_i16x8_s"
"i32x4.extmul_high_i16x8_s" "i32x4.extmul_low_i16x8_u"
"i32x4.extmul_high_i16x8_u" "i64x2.abs" "i64x2.neg"
"i64x2.all_true" "i64x2.bitmask" "i64x2.extend_low_i32x4_s"
"i64x2.extend_high_i32x4_s" "i64x2.extend_low_i32x4_u"
"i64x2.extend_high_i32x4_u" "i64x2.shl" "i64x2.shr_s"
"i64x2.shr_u" "i64x2.add" "i64x2.sub" "i64x2.mul" "i64x2.eq"
"i64x2.ne" "i64x2.lt_s" "i64x2.gt_s" "i64x2.le_s" "i64x2.ge_s"
"i64x2.extmul_low_i32x4_s" "i64x2.extmul_high_i32x4_s"
"i64x2.extmul_low_i32x4_u" "i64x2.extmul_high_i32x4_u"
"f32x4.abs" "f32x4.neg" "f32x4.sqrt" "f32x4.add" "f32x4.sub"
"f32x4.mul" "f32x4.div" "f32x4.min" "f32x4.max" "f32x4.pmin"
"f32x4.pmax" "f64x2.abs" "f64x2.neg" "f64x2.sqrt" "f64x2.add"
"f64x2.sub" "f64x2.mul" "f64x2.div" "f64x2.min" "f64x2.max"
"f64x2.pmin" "f64x2.pmax" "i32x4.trunc_sat_f32x4_s"
"i32x4.trunc_sat_f32x4_u" "f32x4.convert_i32x4_s"
"f32x4.convert_i32x4_u" "i32x4.trunc_sat_f64x2_s_zero"
"i32x4.trunc_sat_f64x2_u_zero" "f64x2.convert_low_i32x4_s"
"f64x2.convert_low_i32x4_u" "i8x16.relaxed_swizzle"
"i32x4.relaxed_trunc_f32x4_s" "i32x4.relaxed_trunc_f32x4_u"
"i32x4.relaxed_trunc_f64x2_s" "i32x4.relaxed_trunc_f64x2_u"
"f32x4.relaxed_madd" "f32x4.relaxed_nmadd"
"f64x2.relaxed_madd" "f64x2.relaxed_nmadd"
"i8x16.relaxed_laneselect" "i16x8.relaxed_laneselect"
"i32x4.relaxed_laneselect" "i64x2.relaxed_laneselect"
"f32x4.relaxed_min" "f32x4.relaxed_max" "f64x2.relaxed_min"
"f64x2.relaxed_max" "i16x8.relaxed_q15mulr_s"
"i16x8.relaxed_dot_i8x16_i7x16_s"
"i32x4.relaxed_dot_i8x16_i7x16_add_s")
eow))
(defconst wat-font-lock-ident-rx
(rx "$" (+ (any "0-9" "a-z" "A-Z" "-!#$%'*+-./:<=>\\?@^_`|~"))))
(defconst wat-font-lock-keywords-1
(list
(cons wat-font-lock-keyword-rx 'font-lock-keyword-face)))
(defconst wat-font-lock-keywords-2
(append
wat-font-lock-keywords-1
(list (cons wat-font-lock-instr-rx 'font-lock-builtin-face)
(cons wat-font-lock-type-rx 'font-lock-type-face)
(cons wat-font-lock-ident-rx 'font-lock-variable-name-face))))
(defvar wat-font-lock-keywords wat-font-lock-keywords-2)
;;; syntax table
(defvar wat-mode-syntax-table
(let ((table (make-syntax-table lisp-mode-syntax-table)))
(dolist (c (list ?! ?# ?$ ?% ?\' ?* ?+ ?- ?. ?\/ ?:
?- ?< ?= ?> ?\\ ?? ?@ ?^ ?_ ?\` ?| ?~))
(modify-syntax-entry c "w" table))
(modify-syntax-entry ?\( "()1nb" table)
(modify-syntax-entry ?\) ")(4nb" table)
(modify-syntax-entry ?\; "< 123" table)
(modify-syntax-entry ?\n ">b" table)
table)
"Syntax table for `wat-mode'.")
;;; indentation
(defun wat-indent-function (indent-point state)
(lisp-indent-function indent-point state))
(defun wat-mode-variables ()
(set-syntax-table wat-mode-syntax-table)
;; (setq local-abbrev-table scheme-mode-abbrev-table)
(setq-local paragraph-start (concat "$\\|" page-delimiter))
(setq-local paragraph-separate paragraph-start)
(setq-local paragraph-ignore-fill-prefix t)
(setq-local fill-paragraph-function 'lisp-fill-paragraph)
;; Adaptive fill mode gets in the way of auto-fill, and should make
;; no difference for explicit fill because lisp-fill-paragraph
;; should do the job.
(setq-local adaptive-fill-mode nil)
(setq-local indent-line-function 'lisp-indent-line)
(setq-local parse-sexp-ignore-comments t)
(setq-local outline-regexp ";;; \\|(....")
;; (setq-local add-log-current-defun-function #'lisp-current-defun-name)
(setq-local comment-start ";")
(setq-local comment-add 1)
(setq-local comment-start-skip ";+[ \t]*")
(setq-local comment-use-syntax t)
(setq-local comment-column 40)
(setq-local lisp-indent-function 'wat-indent-function)
;; (setq-local imenu-case-fold-search t)
;; (setq-local imenu-generic-expression scheme-imenu-generic-expression)
(setq-local imenu-syntax-alist '(("+-*/.<>=?!$%_&~^:" . "w")))
;; (setq-local syntax-propertize-function #'scheme-syntax-propertize)
(setq font-lock-defaults
'((wat-font-lock-keywords
wat-font-lock-keywords-1 wat-font-lock-keywords-2)
nil t (("+-*/.<>=!?$%_&~^:" . "w") (?#. "w 14"))
beginning-of-defun
(font-lock-mark-block-function . mark-defun)))
;; (setq-local prettify-symbols-alist lisp-prettify-symbols-alist)
)
;;;###autoload
(define-derived-mode wat-mode prog-mode "WebAssembly"
"Major mode for editing the WebAssembly text format."
(wat-mode-variables))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.wat\\'" . wat-mode))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.wast\\'" . wat-mode))
(provide 'wat)