Skip to content

Instantly share code, notes, and snippets.

@fkettelhoit
Created March 7, 2025 15:53
Show Gist options
  • Select an option

  • Save fkettelhoit/ec640ffcddc4cb4ec6b1af362d8f8a28 to your computer and use it in GitHub Desktop.

Select an option

Save fkettelhoit/ec640ffcddc4cb4ec6b1af362d8f8a28 to your computer and use it in GitHub Desktop.
Simple Static Site Generator in a Minimal Lambda Calculus Language + Effects
loop map = f => xs =>
if xs is Cons(x, xs)
Cons(f(x), map(f, xs))
else
xs
let reverse = xs =>
loop reverse = xs => rest =>
if xs is Cons(x, xs)
reverse(xs, Cons(x, rest))
else
rest
reverse(xs, Nil)
let read-lines = _ =>
loop split-lines = curr => lines =>
let c = read-char!()
if c is ()
Cons(curr, lines)
else if c is "\n"
split-lines(Nil, Cons(curr, lines))
else
split-lines(Cons(c, curr), lines)
let lines = map(reverse, split-lines(Nil, Nil))
reverse(lines)
loop append = xs => ys =>
if xs is Cons(x, xs)
Cons(x, append(xs, ys))
else
ys
loop wrap = pre => l => post =>
let pre = Cons(pre, Nil)
let post = Cons(post, Nil)
append(pre, append(l, post))
let is-empty = xs =>
if xs is Cons(x, xs)
False
else
True
let is-heading = l =>
if l is Cons(x, l')
if l' is Cons(y, l'')
if x is "#"
if y is " "
Heading(l'')
else
Nil
else
Nil
else
Nil
else
Nil
let is-code-block = l =>
if l is Cons(a, l')
if l' is Cons(b, l'')
if l'' is Cons(c, l''')
if a is "`"
if b is "`"
if c is "`"
if l''' is Nil
True
else
False
else
False
else
False
else
False
else
False
else
False
else
False
loop inline-to-html = l => style =>
if l is Cons(c, l)
if c is "_"
if style is Em
Cons("</em>", inline-to-html(l, None))
else
Cons("<em>", inline-to-html(l, Em))
else
Cons(c, inline-to-html(l, style))
else
l
let line-to-html = l =>
if is-empty(l) is True
Nil
else if is-heading(l) is Heading(l)
wrap("<h1>", l, "</h1>\n")
else
wrap("<p>", inline-to-html(l, None), "</p>\n")
loop md-to-html = ls => style =>
if ls is Cons(l, ls)
if style is Code
if is-code-block(l) is True
Cons(Cons("\n</code></pre>\n", Nil), md-to-html(ls, None))
else
Cons(Cons("\n", l), md-to-html(ls, style))
else if is-code-block(l) is True
Cons(Cons("<pre><code>", Nil), md-to-html(ls, Code))
else
Cons(line-to-html(l), md-to-html(ls, style))
else
ls
loop flatten = xs =>
if xs is Cons(x, xs)
append(x, flatten(xs))
else
xs
let html5 = title => body =>
let pre =
wrap(
"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<title>",
title,
"</title>\n<link rel=\"stylesheet\" href=\"styles/style.css\" />\n</head>\n"
)
let body = wrap("<body>\n", flatten(body), "</body>\n")
append(pre, append(body, Cons("</html>", Nil)))
let lines = read-lines()
loop title = ls =>
if ls is Cons(l, ls)
if is-heading(l) is Heading(l)
l
else
title(ls)
else
Cons((), Nil)
let title = title(lines)
let body = md-to-html(lines, None)
let html = html5(title, body)
write-strs!(html)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment