From d0d0ea8e8418646105f84b31c6aa29e2806a6a95 Mon Sep 17 00:00:00 2001 From: alex-eg Date: Wed, 16 Sep 2026 01:11:53 +0300 Subject: [PATCH] process imported forms as toplevel, not as text 1. register imported types 2. protect against multiple imports (diamond, circular) --- semen.scm | 14 +++----------- sex-modules.scm | 10 +++++++++- tests/modules/Makefile | 6 +++++- tests/modules/greet-app.sex | 5 +++++ tests/modules/greet.sex | 10 ++++++++++ 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/semen.scm b/semen.scm index 7daaf91..422999f 100644 --- a/semen.scm +++ b/semen.scm @@ -93,17 +93,9 @@ (else (sex-error sex-form "unknown top level form" sex-form)))) (define (process-imports module-public-forms acc) - ;; Recursively process imports: register public macros, cons all - ;; other public things to our acc - (if (null? module-public-forms) acc - (match (car module-public-forms) - (('defmacro . rest) - (defmacro rest) - (process-imports (cdr module-public-forms) acc)) - (else - (process-imports (cdr module-public-forms) - (cons (car module-public-forms) - acc)))))) + ;; consume (import ...) form and process imports so + ;; data types end up in types db + (fold match-sex-form acc module-public-forms)) (define (macro-expand form) "Walk the form recursively and expand all macros, until none is left." diff --git a/sex-modules.scm b/sex-modules.scm index 48dace6..cc63809 100644 --- a/sex-modules.scm +++ b/sex-modules.scm @@ -14,6 +14,10 @@ (define +persistent-module-paths+ (list)) +;;; for guarding against multiple imports (sort of mandatory #pragma +;;; once) +(define +imported-modules+ (list)) + (define (get-modules-public-forms module-list) ;; Module list is a list of symbols ;; How Sex handles modules: @@ -29,7 +33,11 @@ (let ((module-path (locate-module name))) (assert module-path (fmt #f "Failed to find module " name " in " (get-module-paths))) - (read-public-interface module-path))) + (if (member module-path +imported-modules+) + (list) + (begin + (set! +imported-modules+ (cons module-path +imported-modules+)) + (read-public-interface module-path))))) (define (get-module-paths) (cons (current-directory) diff --git a/tests/modules/Makefile b/tests/modules/Makefile index d3d604c..5091e44 100644 --- a/tests/modules/Makefile +++ b/tests/modules/Makefile @@ -7,10 +7,14 @@ # module's object survives being passed after `--'. Get any of them # wrong and this fails to link -- or, in the `pub var' case, links and # quietly counts into a private copy. +# +# It also checks what only a second translation unit can check: that an +# imported type reaches the type database, by expanding a macro that +# reads the imported struct's fields. SEXC ?= ../../sexc -EXPECTED = hello, world\nhello, sex\n2 greetings +EXPECTED = hello, world\nhello, sex\n2 greetings\ntext times check: @$(SEXC) greet.sex -c -o greet.o diff --git a/tests/modules/greet-app.sex b/tests/modules/greet-app.sex index 4ecf5f0..0f1a6ec 100644 --- a/tests/modules/greet-app.sex +++ b/tests/modules/greet-app.sex @@ -7,6 +7,9 @@ ;;; as a prototype and `greet-count' as an extern. Both keep external ;;; linkage, so they refer to the one definition in greet.o rather than ;;; to private copies. +;;; +;;; Also check that import populates type-database, by means of +;;; describe-fields macro, which should work on imported type. (include stdio.h) @@ -16,4 +19,6 @@ (greet "world") (greet "sex") (printf "%d greetings\n" greet-count) + (describe-fields greeting) + (printf "\n") (return 0)) diff --git a/tests/modules/greet.sex b/tests/modules/greet.sex index 094333a..e97386a 100644 --- a/tests/modules/greet.sex +++ b/tests/modules/greet.sex @@ -9,6 +9,16 @@ (pub var greet-count int 0) +(pub struct greeting ((text (* const char)) (times int))) + +;;; Compile-time reflection across the module boundary: both the macro +;;; and the struct it asks about are exported, and the importing unit +;;; has to know the struct's fields to expand this. +(pub defmacro (describe-fields type) + `(do ,@(map-fields type + (lambda (name field-type) + `(printf "%s " ,(symbol->string name)))))) + (pub fn greet ((name (* const char))) void (++ greet-count) (printf "hello, %s\n" name))