ludic/examples/library/http.ludic
Orkuncakilkaya 3df6640fa5
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 19s
ci / build-and-test (push) Successful in 1m26s
commit-lint / conventional-commits (push) Successful in 5s
docs / build-and-deploy (push) Successful in 21s
feat(http): Http.* poll-based HTTP/HTTPS client over a native NSURLConnection backend (#6)
Adds the Http.* namespace and its transport, the HTTP client from #6. The JSON
companion the proposal called for already shipped as Json.* (#44).

- runtime/native/http.ll: the macOS transport — NSURLConnection driven through
  the objc runtime C ABI (no ObjC/C source), run on a detached pthread so the
  frame never blocks; TLS is the system's, on by default. A fixed slot pool holds
  each in-flight request; the worker publishes status/body/response behind an
  atomic done flag (release/acquire). Spliced + Foundation linked only when a
  program uses Http.*.
- runtime/native/http.ludic: the Http.* runtime — get/post/request, the
  open/set/body/send builder, poll/status/ok/text/body_len/header/free, plus a
  pure-Ludic response parser (Http.parse + case-insensitive header lookup) that
  is transport-independent and portable.
- compiler: Http.* dispatch, g_uses_http splice, hs_* transport intrinsics +
  declarations, the conditional Foundation link, and a new \r string/char escape
  the protocol needs.
- docs: a full docs/language/http section (16 pages); check-impl/check-docs green.
- test: examples/library/http.ludic self-asserts the parser offline (Darwin-gated
  build via the canonical path, since it links Foundation).

Verified end to end against real endpoints: HTTPS GET (200 + headers + body) and
POST (body + custom header). HTTP is out-of-band and never feeds the
deterministic sim. Reseeded; suites green (81 + 29).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-31 18:10:53 +03:00

39 lines
1.7 KiB
Text

# http.ludic — the Http.* standard library (#6). A poll-based HTTP/HTTPS client:
#
# let h = Http.get("https://api.example.com/scores?level=3")
# handler Update { # each frame, never blocking
# let st = Http.poll(h) # -1 pending, 0 error, else HTTP status
# if st > 0 {
# if Http.ok(h) { let body = Http.text(h) } # pair with Json.parse(...) (#44)
# Http.free(h)
# }
# }
#
# TLS is the system's, on by default, so https:// just works. HTTP is out-of-band
# and must never feed the deterministic sim (like Net.* and Time.now).
#
# The transport runs on a background thread (macOS backend, http.ll) so it can't
# be driven deterministically here; the response PARSER is pure Ludic, so this
# self-checking run exercises Http.parse / status / ok / body / headers offline:
# bin/ludic examples/library/http.ludic -> 200 1 5 hello 42 text/plain 404 0
program HttpDemo {
function bi(b: bool) -> int { if b { return 1 }; return 0 }
entry {
let raw = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nX-Answer: 42\r\n\r\nhello"
let h = Http.parse(raw, Text.length(raw))
print(Http.status(h)) # 200
print(bi(Http.ok(h))) # 1 — 2xx
print(Http.body_len(h)) # 5
print(Http.text(h)) # hello
print(Http.header(h, "X-Answer")) # 42
print(Http.header(h, "content-type")) # text/plain — header lookup is case-insensitive
Http.free(h)
let nf = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"
let h2 = Http.parse(nf, Text.length(nf))
print(Http.status(h2)) # 404
print(bi(Http.ok(h2))) # 0 — not 2xx
Http.free(h2)
}
}