feat(launcher): Process.*, Http.save_to/received/expected, App.window_hide/show

Process.spawn/poll/kill/free - non-blocking child processes with no shell: posix_spawn on
macOS (process.ll), CreateProcessW with MSVC-quoted arguments and no console window on
Windows (process_win.ll), linked only when a program uses Process.*.

Http.save_to streams a response body into a file (NSURLSession with a run-time delegate
class on macOS, the WinHTTP read loop on Windows); Http.received / Http.expected report
progress while it is pending. Freeing a pending request cancels it and parks the slot
until the worker has finished.

App.window_hide / App.window_show take the game's window off the screen and back without
closing it; the run goes on while hidden. Docs, examples, tests and a changeset.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-17 13:32:23 +03:00
parent c1db0d71ed
commit 43d5eb5b88
31 changed files with 89274 additions and 86727 deletions

View file

@ -258,6 +258,14 @@ function emit_ns_call(ns: pointer, meth: pointer, e: Node) -> Val {
if g_windowed { emit(` call void @lp_app_icon(ptr {ip})\n`) }
return val("0", "void")
}
if (meth == "window_hide") or (meth == "window_show") {
# Hide / show the game's own window (not the splash) without tearing down its
# GL / Vulkan surface - a launcher steps aside while the game it started runs.
# Headless there is no window, and the call lowers to nothing.
use_pak()
if g_windowed { emit(` call void @app_{meth}()\n`) }
return val("0", "void")
}
perr(`unknown builtin App.{meth}`)
}
if (ns == "Pool") {
@ -516,6 +524,9 @@ function emit_ns_call(ns: pointer, meth: pointer, e: Node) -> Val {
if (meth == "header") { bare = "http_header_of"; push(labels, "handle"); push(labels, "name") }
if (meth == "free") { bare = "http_close"; push(labels, "handle") }
if (meth == "parse") { bare = "http_parse"; push(labels, "bytes"); push(labels, "len") }
if (meth == "save_to") { bare = "http_save_to"; push(labels, "handle"); push(labels, "path") }
if (meth == "received") { bare = "http_received"; push(labels, "handle") }
if (meth == "expected") { bare = "http_expected"; push(labels, "handle") }
}
# Udp.* — polled IPv4 datagrams (runtime/native/udp.ludic + udp.ll / udp_win.ll).
# Out-of-band like Http.*: the transport under a game's own netcode.
@ -532,6 +543,14 @@ function emit_ns_call(ns: pointer, meth: pointer, e: Node) -> Val {
if (meth == "ip") { bare = "udp_ip"; push(labels, "text") }
if (meth == "ip_text") { bare = "udp_ip_text"; push(labels, "ip") }
}
# Process.* — child processes, started and polled (runtime/native/process.ludic +
# process.ll / process_win.ll). Out-of-band, like Http.*.
if (ns == "Process") {
if (meth == "spawn") { bare = "process_spawn"; push(labels, "path"); push(labels, "args") }
if (meth == "poll") { bare = "process_poll"; push(labels, "handle") }
if (meth == "kill") { bare = "process_kill"; push(labels, "handle") }
if (meth == "free") { bare = "process_free"; push(labels, "handle") }
}
# Phase 3: the bare reflection / networking / process builtins, namespaced.
# Each is a pure alias — the callee is rewritten to the bare name below.
if (ns == "World") {