commit 2b261fe5af25ffbc44dd42d850d5854398bd9196 Author: Madeleine Sydney Ĺšlaga Date: Thu Jul 16 16:19:23 2026 -0600 init diff --git a/wat.el b/wat.el new file mode 100644 index 0000000..b438f34 --- /dev/null +++ b/wat.el @@ -0,0 +1,253 @@ +;;; 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)