Skip to content

Instantly share code, notes, and snippets.

@dkaraush
Last active December 3, 2025 02:21
Show Gist options
  • Select an option

  • Save dkaraush/02a1e5878cf539cfd5fd36ab4fa002e8 to your computer and use it in GitHub Desktop.

Select an option

Save dkaraush/02a1e5878cf539cfd5fd36ab4fa002e8 to your computer and use it in GitHub Desktop.
(module
(import "sys" "open" (func $open (param i32 i32 i32 i32) (result i32)))
(import "sys" "close" (func $close (param i32)))
(import "sys" "read" (func $read (param i32 i32 i32) (result i32)))
(import "sys" "write" (func $write (param i32 i32 i32) (result i32)))
(memory (export "memory") 1)
(data (i32.const 0) "input.txt")
(global $fd (mut i32) (i32.const 0)) ;; 4 bytes
(global $char_ptr i32 (i32.const 16)) ;; 1 byte
(global $num_ptr i32 (i32.const 17)) ;; 4 bytes
(global $num_str_ptr i32 (i32.const 64)) ;; 64 bytes
(func $read_char (result i32)
global.get $fd
global.get $char_ptr
i32.const 1
call $read
i32.const 0
i32.le_s
(if (result i32)
(then
i32.const 0
)
(else
global.get $char_ptr
i32.load
)
)
)
(func $print_char (param $char i32)
global.get $char_ptr
local.get $char
i32.store8
i32.const 1 ;; stdout
global.get $char_ptr
i32.const 1 ;; len
call $write
drop
)
(func $read_number (result i64)
(local $acc i64)
(block $break
(loop $loop
call $read_char
i32.const 48 ;; '0'
i32.lt_s
(if (then br $break))
global.get $char_ptr
i32.load
i32.const 57 ;; '9'
i32.gt_s
(if (then br $break))
;; acc *= 10
local.get $acc
i64.const 10
i64.mul
;; acc += (c - '0')
global.get $char_ptr
i32.load
i32.const 48
i32.sub
i64.extend_i32_u
i64.add
local.set $acc
br $loop
)
)
local.get $acc
)
(func $print_number (param $num i64)
(local $end i32)
(local $start i32)
local.get $num
i64.eqz
(if (then
i32.const 48 ;; '0'
call $print_char
return
))
local.get $num
i64.const 0
i64.lt_s
(if (then
i32.const 45 ;; '-'
call $print_char
i64.const 0
local.get $num
i64.sub
local.set $num
))
global.get $num_str_ptr
i32.const 64
i32.add
local.tee $end
local.set $start
(block $break
(loop $loop
local.get $num
i64.eqz
br_if $break
local.get $start
i32.const -1
i32.add
local.tee $start
local.get $num
i64.const 10
i64.rem_u
i64.const 48
i64.add
i32.wrap_i64
i32.store8
local.get $num
i64.const 10
i64.div_u
local.set $num
br $loop
)
)
i32.const 1 ;; stdout
local.get $start ;; ptr
local.get $end ;; len = end - start
local.get $start
i32.sub
call $write
drop
)
(func $log10 (param $num i64) (result i64)
(local $exp i64)
i64.const 0
local.set $exp
(block (loop
local.get $num
i64.eqz
br_if 1
local.get $num
i64.const 10
i64.div_u
local.set $num
local.get $exp
i64.const 1
i64.add
local.set $exp
br 0
))
local.get $exp
)
(func $pow10 (param $exp i64) (result i64)
(local $result i64)
i64.const 1
local.set $result
(block (loop
local.get $exp
i64.eqz
br_if 1
local.get $result
i64.const 10
i64.mul
local.set $result
local.get $exp
i64.const 1
i64.sub
local.set $exp
br 0
))
local.get $result
)
(func $is_invalid_id_1 (param $num i64) (result i32)
(local $len i64)
(local $div i64)
;; len = ceil(log10(num))
local.get $num
call $log10
local.tee $len
;; len & 1 != 0 (not divisable by 2)
i64.const 1
i64.and
i64.const 0
i64.ne
(if (then
i32.const 0
return
))
;; len /= 2
local.get $len
i64.const 2
i64.div_u
local.tee $len
;; div = pow10(len) + 1
call $pow10
i64.const 1
i64.add
local.set $div
;; return num % div == 0
local.get $num
local.get $div
i64.rem_u
i64.eqz
)
(func $is_invalid_id_2 (param $num i64) (result i32)
(local $len i64)
(local $i i64)
(local $j i64)
(local $n i64)
(local $div i64)
local.get $num
call $log10
local.tee $len
local.set $i
;; for (long i = len; i > 1; --i)
(block (loop
local.get $i
i64.const 1
i64.le_u
br_if 1
;; len % i == 0
local.get $len
local.get $i
i64.rem_u
i64.eqz
(if (then
;; n = len / i
local.get $len
local.get $i
i64.div_u
local.set $n
local.get $i
i64.const 1
i64.sub
local.set $j
;; div = 1
i64.const 1
local.set $div
;; for (long j = i - 1; j > 0; --j)
(block (loop
local.get $j
i64.eqz
br_if 1
;; div = div * pow10(n) + 1
local.get $n
call $pow10
local.get $div
i64.mul
i64.const 1
i64.add
local.set $div
;; --j
local.get $j
i64.const 1
i64.sub
local.set $j
br 0
))
;; num % div == 0
local.get $num
local.get $div
i64.rem_u
i64.eqz
(if (then
i32.const 1
return
))
))
;; --i
local.get $i
i64.const 1
i64.sub
local.set $i
br 0
))
i32.const 0
)
(func (export "_start")
(local $result1 i64)
(local $result2 i64)
(local $from i64)
(local $to i64)
(local $i i64)
;; fd = open("input.txt", 2, 0)
i32.const 0
i32.const 9
i32.const 2
i32.const 0
call $open
global.set $fd
i64.const 0
local.tee $result1
local.set $result2
(block (loop
call $read_number
local.tee $from
i64.const 0
i64.eq
br_if 1
call $read_number
local.set $to
;; for (long i = from; i <= to; ++i)
local.get $from
local.set $i
(block (loop
local.get $i
local.get $to
i64.gt_u
br_if 1
;; if (is_invalid_id_1(i)) result1 += i
local.get $i
call $is_invalid_id_1
i32.const 1
i32.eq
(if (then
local.get $result1
local.get $i
i64.add
local.set $result1
))
;; if (is_invalid_id_2(i)) result2 += i
local.get $i
call $is_invalid_id_2
i32.const 1
i32.eq
(if (then
local.get $result2
local.get $i
i64.add
local.set $result2
))
;; ++i
local.get $i
i64.const 1
i64.add
local.set $i
br 0
))
br 0
))
;; close(fd)
global.get $fd
call $close
local.get $result1
call $print_number
i32.const 32 ;; ' '
call $print_char
local.get $result2
call $print_number
i32.const 10 ;; '\n'
call $print_char
)
)
#!/usr/bin/env node
import * as fs from 'fs'
import { resolve } from 'path'
if (!process.argv[2]) {
console.error(`Usage: node loader.js module.wasm`)
process.exit(1)
}
const wasmBytes = fs.readFileSync(resolve(process.argv[2]))
let memory
const module = await WebAssembly.compile(wasmBytes)
const instance = await WebAssembly.instantiate(module, { sys: {
open: (pathPtr, pathLen, flags, mode) =>
fs.openSync(
Buffer.from(memory.buffer, pathPtr, pathLen).toString('utf-8'),
flags,
mode >>> 0
),
close: (fd) =>
fs.closeSync(fd),
read: (fd, bufPtr, bufLen) =>
fs.readSync(fd, Buffer.from(memory.buffer, bufPtr, bufLen)),
write: (fd, bufPtr, bufLen) =>
fs.writeSync(fd, Buffer.from(memory.buffer, bufPtr, bufLen))
} })
memory = instance.exports.memory;
if (!memory) {
console.error(`WASM: module must export memory as "memory"`);
process.exit(1);
}
if (instance.exports._start) {
instance.exports._start();
} else if (instance.exports.main) {
instance.exports.main();
} else {
console.error(`WASM: No _start or main export found`);
process.exit(1);
}
wat2wasm 2025aoc2.wat -o 2025aoc2.wasm
node run.js 2025aoc2.wasm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment