The path was ceremony. Under [flan dev] the daemon already decides where it wants to talk to the program and writes it into FLAN_AGENT_SOCKET, which the C side has always honoured over whatever the source named — so the argument was a value nothing read. Outside the daemon any path will do as long as the program says which one it picked. So [start] becomes a macro over two functions: no argument picks the daemon's socket if there is one and otherwise /tmp/flan-agent-<pid>-<clock>.sock, announced on stderr because a socket nobody can name is a socket nobody can connect to. The explicit form stays for a program that wants a fixed path. Extra arguments are spliced into [start-at] rather than dropped, so the arity refusal is still the checker's, at the call site. And the socket is removed on the way out. The bind stashes the path it bound and registers an atexit; the two paths that leave by _exit — the break loop's [abort] and the orphan handler — unlink it by hand, as the orphan handler already did for its own copy of the path. Nothing else takes it away: under the daemon it sits in a temp directory that is still never removed (FIX.org), and outside there is no daemon at all. test/programs/dev-loop.flan now names no socket, which puts the whole daemon block in test_dev.ml behind the zero-argument form; agent-auto.flan is the standalone half, reached only through the line the program printed, and it pins the second (agent/start) as a no-op and the socket as gone at exit.
38 lines
1.3 KiB
Plaintext
38 lines
1.3 KiB
Plaintext
;;;; What [flan dev] launches: a program with a loop, a function to redefine,
|
|
;;;; and a way to stop.
|
|
;;;;
|
|
;;;; It names no socket. Under [flan dev] the daemon has already decided where
|
|
;;;; it wants to talk to this program and says so in FLAN_AGENT_SOCKET — which
|
|
;;;; overrode whatever the source named anyway — so the argument was only ever
|
|
;;;; a value nothing read. This is the shape a program should be written in,
|
|
;;;; and the whole daemon block in test_dev.ml runs against it, so a delivery
|
|
;;;; landing there is the zero-argument form working end to end.
|
|
(import agent "vendor:agent")
|
|
|
|
(defvar ticks i64)
|
|
|
|
;;; A condition and something that signals it, so that a body typed in later
|
|
;;; can establish a handler and transfer past this frame — spec-conditions.md
|
|
;;; §6. It is here rather than in the evaluated form on purpose: the guard that
|
|
;;; forwards the transfer has to be one the *host* was compiled with.
|
|
(defstruct Missing [id i32])
|
|
|
|
(defn probe [] i64
|
|
(signal (Missing {.id 1}))
|
|
0)
|
|
|
|
(defn step [] i64
|
|
(set ticks (+ ticks 1))
|
|
ticks)
|
|
|
|
(defn main [] i32
|
|
(agent/start)
|
|
(print (step)) (println "")
|
|
(while (= (agent/wait 100) 0) 0)
|
|
(print (step)) (println "")
|
|
(while (= (agent/wait 100) 0) 0)
|
|
(print (step)) (println "")
|
|
(while (= (agent/wait 100) 0) 0)
|
|
(print (step)) (println "")
|
|
0)
|