erlang: -module/M:F cross-module calls (+10 tests)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled

This commit is contained in:
2026-04-25 04:01:14 +00:00
parent 882205aa70
commit 424b5ca472
6 changed files with 152 additions and 7 deletions

View File

@@ -742,3 +742,75 @@
(er-proc-set! target :exit-result nil)
(er-proc-set! target :continuation nil)
(er-propagate-exit! target reason)))
;; ── module registry ─────────────────────────────────────────────
;; Global mutable dict from module name -> module env (which itself
;; binds each function name to a fun value capturing the same env, so
;; sibling functions can call each other recursively).
(define er-modules (list {}))
(define er-modules-get (fn () (nth er-modules 0)))
(define er-modules-reset! (fn () (set-nth! er-modules 0 {})))
;; Load an Erlang module declaration. Source must start with
;; `-module(Name).` and contain function definitions. Functions
;; sharing a name (different arities) get their clauses concatenated
;; into a single fun value — `er-apply-fun-clauses` already filters
;; by arity, so multi-arity dispatch falls out for free.
(define
erlang-load-module
(fn
(src)
(let
((module-ast (er-parse-module src)))
(let
((mod-name (get module-ast :name))
(functions (get module-ast :functions))
(mod-env (er-env-new))
(by-name {}))
(for-each
(fn
(i)
(let
((f (nth functions i)))
(let
((name (get f :name)) (clauses (get f :clauses)))
(if
(dict-has? by-name name)
(let
((existing (get by-name name)))
(for-each
(fn (j) (append! existing (nth clauses j)))
(range 0 (len clauses))))
(let
((init (list)))
(for-each
(fn (j) (append! init (nth clauses j)))
(range 0 (len clauses)))
(dict-set! by-name name init))))))
(range 0 (len functions)))
(for-each
(fn
(k)
(let
((all-clauses (get by-name k)))
(er-env-bind! mod-env k (er-mk-fun all-clauses mod-env))))
(keys by-name))
(dict-set! (er-modules-get) mod-name mod-env)
(er-mk-atom mod-name)))))
(define
er-apply-user-module
(fn
(mod name vs)
(let
((mod-env (get (er-modules-get) mod)))
(if
(not (dict-has? mod-env name))
(raise
(er-mk-error-marker
(er-mk-tuple
(list
(er-mk-atom "undef")
(er-mk-atom mod)
(er-mk-atom name)))))
(er-apply-fun (get mod-env name) vs)))))