erlang: spawn/1 + self/0 + is_pid (+13 tests)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled

This commit is contained in:
2026-04-24 19:50:09 +00:00
parent bc1a69925e
commit 266693a2f6
4 changed files with 133 additions and 4 deletions

View File

@@ -208,3 +208,68 @@
(define
er-proc-mailbox-size
(fn (pid) (er-q-len (er-proc-field pid :mailbox))))
;; ── process BIFs ────────────────────────────────────────────────
(define
er-bif-is-pid
(fn (vs) (er-bool (er-pid? (er-bif-arg1 vs "is_pid")))))
(define
er-bif-self
(fn
(vs)
(if
(not (= (len vs) 0))
(error "Erlang: self/0: arity")
(let
((pid (er-sched-current-pid)))
(if
(= pid nil)
(error "Erlang: self/0: no current process")
pid)))))
(define
er-bif-spawn
(fn
(vs)
(cond
(= (len vs) 1) (er-spawn-fun (nth vs 0))
(= (len vs) 3) (error
"Erlang: spawn/3: module-based spawn deferred to Phase 5 (modules)")
:else (error "Erlang: spawn: wrong arity"))))
(define
er-spawn-fun
(fn
(fv)
(if
(not (er-fun? fv))
(error "Erlang: spawn/1: not a fun")
(let
((proc (er-proc-new! (er-env-new))))
(dict-set! proc :initial-fun fv)
(get proc :pid)))))
;; ── scheduler loop ──────────────────────────────────────────────
;; Drain all runnable processes to completion. Synchronous — each
;; spawned process runs its :initial-fun front-to-back with no yielding.
;; receive-driven suspension arrives in the next roadmap step.
(define
er-sched-drain!
(fn
()
(let
((pid (er-sched-next-runnable!)))
(when
(not (= pid nil))
(er-sched-set-current! pid)
(er-proc-set! pid :state "running")
(let
((fv (er-proc-field pid :initial-fun)))
(when
(not (= fv nil))
(er-apply-fun fv (list))))
(er-proc-set! pid :state "dead")
(er-proc-set! pid :exit-reason (er-mk-atom "normal"))
(er-sched-set-current! nil)
(er-sched-drain!)))))

View File

@@ -285,6 +285,48 @@
(do (er-io-flush!) (ev "io:format(\"50~~\")") (er-io-buffer-content))
"50~")
;; ── processes: self/0, spawn/1, is_pid ──────────────────────────
(er-eval-test "self tag"
(get (ev "self()") :tag) "pid")
(er-eval-test "is_pid self"
(nm (ev "is_pid(self())")) "true")
(er-eval-test "is_pid number"
(nm (ev "is_pid(42)")) "false")
(er-eval-test "is_pid atom"
(nm (ev "is_pid(ok)")) "false")
(er-eval-test "self equals self"
(nm (ev "Pid = self(), Pid =:= Pid")) "true")
(er-eval-test "self =:= self expr"
(nm (ev "self() == self()")) "true")
(er-eval-test "spawn returns pid"
(get (ev "spawn(fun () -> ok end)") :tag) "pid")
(er-eval-test "is_pid spawn"
(nm (ev "is_pid(spawn(fun () -> ok end))")) "true")
(er-eval-test "spawn new pid distinct"
(nm (ev "P1 = self(), P2 = spawn(fun () -> ok end), P1 =:= P2"))
"false")
(er-eval-test "two spawns distinct"
(nm (ev "P1 = spawn(fun () -> ok end), P2 = spawn(fun () -> ok end), P1 =:= P2"))
"false")
(er-eval-test "spawn then drain io"
(do
(er-io-flush!)
(ev "spawn(fun () -> io:format(\"child~n\") end), io:format(\"parent~n\")")
(er-io-buffer-content))
"parent\nchild\n")
(er-eval-test "multiple spawn ordering"
(do
(er-io-flush!)
(ev "spawn(fun () -> io:format(\"a~n\") end), spawn(fun () -> io:format(\"b~n\") end), io:format(\"main~n\")")
(er-io-buffer-content))
"main\na\nb\n")
(er-eval-test "child self is its own pid"
(do
(er-io-flush!)
(ev "P = spawn(fun () -> io:format(\"~p\", [is_pid(self())]) end), io:format(\"~p;\", [is_pid(P)])")
(er-io-buffer-content))
"true;true")
(define
er-eval-test-summary
(str "eval " er-eval-test-pass "/" er-eval-test-count))

View File

@@ -61,8 +61,23 @@
(let
((st (er-state-make (er-tokenize src))))
(let
((body (er-parse-body st)) (env (er-env-new)))
(er-eval-body body env)))))
((body (er-parse-body st)))
(er-sched-init!)
(let
((main (er-proc-new! (er-env-new))))
(er-sched-next-runnable!)
(er-sched-set-current! (get main :pid))
(er-proc-set! (get main :pid) :state "running")
(let
((result (er-eval-body body (get main :env))))
(er-proc-set! (get main :pid) :state "dead")
(er-proc-set!
(get main :pid)
:exit-reason
(er-mk-atom "normal"))
(er-sched-set-current! nil)
(er-sched-drain!)
result))))))
(define
er-eval-body
@@ -347,6 +362,7 @@
(fn (i) (er-equal? (nth ea i) (nth eb i)))
(range 0 (len ea)))))
(and (= (type-of a) "string") (= (type-of b) "string")) (= a b)
(and (er-pid? a) (er-pid? b)) (= (get a :id) (get b :id))
:else false)))
;; Exact equality: 1 =/= 1.0 in Erlang.
@@ -380,7 +396,8 @@
(er-nil? v) 3
(er-cons? v) 3
(= (type-of v) "string") 4
:else 5)))
(er-pid? v) 5
:else 6)))
(define
er-list-append
@@ -535,6 +552,9 @@
(= name "tuple_size") (er-bif-tuple-size vs)
(= name "atom_to_list") (er-bif-atom-to-list vs)
(= name "list_to_atom") (er-bif-list-to-atom vs)
(= name "is_pid") (er-bif-is-pid vs)
(= name "self") (er-bif-self vs)
(= name "spawn") (er-bif-spawn vs)
:else (error
(str "Erlang: undefined function '" name "/" (len vs) "'")))))
@@ -863,6 +883,7 @@
(er-cons? v) (str "[" (er-format-list-elems v) "]")
(er-tuple? v) (str "{" (er-format-tuple-elems (get v :elements)) "}")
(er-fun? v) "#Fun"
(er-pid? v) (str "<pid:" (get v :id) ">")
:else (str v))))
(define