100 Helloslanguages
Home / Languages / WebAssembly Text

WebAssembly Text

2017fraglet
webimperativestack-based.wat.wast
docker run --rm --platform="linux/amd64" 100hellos/wat:latest

MCP + fragletc

MCP
This language supports code execution via MCP and the fragletc CLI.
Install fragletc →

WAT (WebAssembly Text Format) is the human-readable text representation of WebAssembly bytecode. While WebAssembly is typically generated by compiling high-level languages like C, C++, or Rust, WAT allows developers to write WebAssembly modules directly in a text-based S-expression format.

Language Features

WAT provides direct access to WebAssembly's low-level capabilities:

  • Stack-based virtual machine: Operations work on an implicit stack
  • Linear memory model: Manages memory as a contiguous array of bytes
  • Type safety: Strict typing prevents many runtime errors
  • Sandboxed execution: WebAssembly runs in a secure, isolated environment
  • WASI support: WebAssembly System Interface enables interaction with the host system

Hello World Explanation

The WAT implementation uses WASI (WebAssembly System Interface) to interact with the host system:

(module
  ;; Import WASI functions for system interaction
  (import "wasi_snapshot_preview1" "fd_write" ...)

  ;; Define linear memory for string storage
  (memory 1)

  ;; Store "Hello World!" string at memory address 0
  (data (i32.const 0) "Hello World!")

  ;; Main function sets up I/O vector and calls fd_write
  (func $main (export "_start") ...)
)

Interesting Facts

  • S-expression syntax: WAT uses Lisp-like parenthesized expressions
  • Compilation target: WAT compiles to binary WebAssembly (.wasm) format
  • Cross-platform: Runs on any system with a WebAssembly runtime
  • Performance: Near-native execution speed in modern browsers and runtimes
  • Security: Capability-based security model with explicit imports

Runtime

This implementation uses Wasmtime, a standalone WebAssembly runtime that supports WASI for system interactions.

Further Exploration

  • Try modifying the string or adding more WASI functions
  • Explore WebAssembly's instruction set architecture
  • Learn about WebAssembly's role in modern web development
  • Investigate other WebAssembly runtimes like Wasmer or Node.js

Hello World

#!/usr/bin/env sh

# If this file is present, this is the file that runs when you add the
# RUN=1 option.
#
# Otherwise, the default behavior is to run the first file in the
# directory that matches the pattern `hello-world.*``.

# Build it
# Run it

# Run the WebAssembly Text format file using wasmtime
wasmtime /hello-world/hello-world.wat "$@"

Coding Guide

Language Version

WebAssembly Text Format (WAT) 1.0 Executed via wasmtime (Alpine edge testing repository)

Execution Model

  • Text format for WebAssembly (WASM)
  • Compiled and executed by wasmtime runtime
  • Uses WASI (WebAssembly System Interface) for I/O
  • Stack-based virtual machine

Key Characteristics

  • S-expression syntax (parentheses-based)
  • Stack-based operations (push/pop)
  • Linear memory model
  • Type system: i32, i64, f32, f64
  • Case-sensitive
  • Comments: ;; for single-line

Fragment Authoring

Write valid WAT module-level code. Your fragment should contain:

  • Data segments at module level (not inside functions)
  • The $main function with (export "_start")
  • WASI imports ($proc_exit, $fd_write)
  • Memory setup (1 page, exported as "memory")
  • Stack-based execution model

Important: Your fragment must include:

  • Data segment(s) at module level for strings
  • Function definition: (func $main (export "_start") ...)
  • iovec structure setup for fd_write
  • fd_write call
  • proc_exit call

Available Imports

WASI snapshot preview1 imports are available:

  • wasi_snapshot_preview1.proc_exit - Exit with status code
  • wasi_snapshot_preview1.fd_write - Write to file descriptor

Memory Layout

  • Memory is 1 page (64KB) and exported as "memory"
  • String data can be placed at any offset
  • iovec structure: 8 bytes (4 bytes buf pointer, 4 bytes length)

Common Patterns

Writing a String

;; Store string data in memory
(data (i32.const 0) "Hello, World!\n")

;; Set up iovec at offset 16
(i32.store (i32.const 16) (i32.const 0))  ;; buf pointer
(i32.store (i32.const 20) (i32.const 14)) ;; length (14 bytes)

;; Call fd_write(stdout=1, iovec_ptr=16, iovec_count=1, result_ptr=24)
(call $fd_write (i32.const 1) (i32.const 16) (i32.const 1) (i32.const 24))
drop

;; Exit
(call $proc_exit (i32.const 0))

Multiple Strings

;; First string at offset 0
(data (i32.const 0) "First line\n")
;; Second string at offset 11
(data (i32.const 11) "Second line\n")

;; Write first string
(i32.store (i32.const 16) (i32.const 0))
(i32.store (i32.const 20) (i32.const 11))
(call $fd_write (i32.const 1) (i32.const 16) (i32.const 1) (i32.const 24))
drop

;; Write second string
(i32.store (i32.const 16) (i32.const 11))
(i32.store (i32.const 20) (i32.const 12))
(call $fd_write (i32.const 1) (i32.const 16) (i32.const 1) (i32.const 24))
drop

(call $proc_exit (i32.const 0))

Arithmetic Operations

;; Store result string
(data (i32.const 0) "Sum: 15\n")

;; Set up iovec
(i32.store (i32.const 16) (i32.const 0))
(i32.store (i32.const 20) (i32.const 8))
(call $fd_write (i32.const 1) (i32.const 16) (i32.const 1) (i32.const 24))
drop

(call $proc_exit (i32.const 0))

Examples

Example 1: Simple Output

;; Store string
(data (i32.const 0) "Hello from fragment!\n")

;; WASI entry point
(func $main (export "_start")
  ;; Set up iovec
  (i32.store (i32.const 16) (i32.const 0))
  (i32.store (i32.const 20) (i32.const 20))
  (call $fd_write (i32.const 1) (i32.const 16) (i32.const 1) (i32.const 24))
  drop

  ;; Exit with status 0
  (call $proc_exit (i32.const 0))
)

Example 2: Multiple Lines

;; Store strings
(data (i32.const 0) "Line 1\n")
(data (i32.const 7) "Line 2\n")

;; WASI entry point
(func $main (export "_start")
  ;; Write first line
  (i32.store (i32.const 16) (i32.const 0))
  (i32.store (i32.const 20) (i32.const 7))
  (call $fd_write (i32.const 1) (i32.const 16) (i32.const 1) (i32.const 24))
  drop

  ;; Write second line
  (i32.store (i32.const 16) (i32.const 7))
  (i32.store (i32.const 20) (i32.const 7))
  (call $fd_write (i32.const 1) (i32.const 16) (i32.const 1) (i32.const 24))
  drop

  ;; Exit with status 0
  (call $proc_exit (i32.const 0))
)

Example 3: Longer Message

;; Store longer string
(data (i32.const 0) "This is a longer message with more content!\n")

;; WASI entry point
(func $main (export "_start")
  ;; Set up iovec
  (i32.store (i32.const 16) (i32.const 0))
  (i32.store (i32.const 20) (i32.const 45))
  (call $fd_write (i32.const 1) (i32.const 16) (i32.const 1) (i32.const 24))
  drop

  ;; Exit with status 0
  (call $proc_exit (i32.const 0))
)

Caveats and Limitations

  • Memory offsets: Be careful with memory offsets - strings must not overlap
  • String lengths: Count bytes carefully, including newline characters (\n = 1 byte)
  • iovec structure: Must be 8 bytes (4-byte pointer + 4-byte length)
  • Stack operations: WAT is stack-based - operations push/pop from the stack
  • Type system: All operations are strongly typed (i32, i64, f32, f64)
  • WASI imports: Only proc_exit and fd_write are available
  • No dynamic allocation: Memory size is fixed at module load time
  • Data segments: Must be placed at compile-time offsets

Tips

  • Use ;; comments liberally to document your code
  • Calculate string lengths carefully (including newlines)
  • Test memory offsets to avoid overlaps
  • The iovec structure is at offset 16, result storage at offset 24
  • Always end with proc_exit to cleanly terminate

Fraglet Scripts

Test

#!/usr/bin/env -S fragletc --vein=wat
  ;; String data: "Hello World!"
  (data (i32.const 0) "Hello World!\n")

  ;; WASI entry point
  (func $main (export "_start")
    ;; Set up iovec for fd_write
    ;; iovec.buf = 0 (pointer to string)
    (i32.store (i32.const 16) (i32.const 0))
    ;; iovec.len = 13 (length of "Hello World!\n")
    (i32.store (i32.const 20) (i32.const 13))

    ;; Call fd_write(1, 16, 1, 24)
    ;; 1 = stdout, 16 = pointer to iovec, 1 = number of iovecs, 24 = pointer to store result
    (call $fd_write (i32.const 1) (i32.const 16) (i32.const 1) (i32.const 24))
    drop

    ;; Exit with status 0
    (call $proc_exit (i32.const 0))
  )

Container Info

image100hellos/wat:latest
build scheduleSaturday
fragletenabled