// mandelbrot — ASCII Mandelbrot set, printed via libc. // // What this proves: // 1. ww does f64 arithmetic (mul, add, sub, div) end to end. // 2. The @symbol FFI mechanism binds write() from libc.so.6. // 3. w6l's dynamic linker (PT_INTERP + PT_DYNAMIC + PLT/GOT) reaches // a real .so at runtime — `ldd mandelbrot` shows libc.so.6 as a // NEEDED entry. // // We use libc's `write` (a thin syscall wrapper) rather than `putchar` // because the runtime here doesn't call __libc_start_main, so stdio // state stays uninitialised and putchar's buffer is never flushed. // // Build: see ./Makefile. No cc — pure ww toolchain. @symbol("write") fn c_write(fd: i32, buf: *void, n: u64) i64; def W: i32 = 78; def H: i32 = 30; def MAXI: i32 = 80; // Number of iterations before |z| escapes |z|>2, capped at MAXI. fn iterate(cr: f64, ci: f64) i32 = { let zr: f64 = 0.0; let zi: f64 = 0.0; let i: i32 = 0; for (i < MAXI) { let zr2: f64 = zr * zr; let zi2: f64 = zi * zi; if (zr2 + zi2 > 4.0) { return i; }; let nz: f64 = zr2 - zi2 + cr; zi = (2.0 * zr) * zi + ci; zr = nz; i += 1; }; return MAXI; }; // Pick an ASCII glyph by escape iteration count. Inside the set // (n == MAXI) renders as space — the classic look. fn shade(n: i32) i32 = { if (n >= MAXI) { return ' ': i32; }; let chars: str = " .:-=+*#%@"; let idx: i32 = (n * chars.len) / MAXI; if (idx >= chars.len) { idx = chars.len - 1; }; return chars[idx]: i32; }; export fn main() i32 = { // Classic Mandelbrot window. The y range is squashed to W/H so // the picture looks roughly proportional in a terminal cell. // // XXX ww's compiler currently emits positive bit patterns for // negative f64 literals (the unary minus is dropped during // codegen). As a workaround we build negatives via 0.0 - x. let z: f64 = 0.0; let xmin: f64 = z - 2.5; let xmax: f64 = 1.0; let ymin: f64 = z - 1.1; let ymax: f64 = 1.1; let dx: f64 = (xmax - xmin) / (W: f64); let dy: f64 = (ymax - ymin) / (H: f64); // Compose the picture into a row buffer, then flush per row to // avoid one libc call per character. let row: [128]u8; let y: i32 = 0; for (y < H) { let ci: f64 = ymin + (y: f64) * dy; let x: i32 = 0; for (x < W) { let cr: f64 = xmin + (x: f64) * dx; let n: i32 = iterate(cr, ci); row[x] = (shade(n)): u8; x += 1; }; row[W] = 10u8; // '\n' c_write(1, row.ptr: *void, (W + 1): u64); y += 1; }; return 0; };