commit 602a59d9deda0b87d23dac8403305bc861227249
parent 20b90492c047e3b99f894691d4e596dfa74c5713
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sat, 25 Apr 2026 14:32:55 -0700
scheme1: red-green tests for R7RS record API surface
Targeting R7RS-small define-record-type: only the constructor,
predicate, accessors, and mutators are user-bound; type name and
%record-* primitives are not.
- 38 rewritten to assert %make-record-td is unbound at user level
(red until the %record-* rows are removed from prim_table).
- 39 added to lock in that the type name itself stays unbound
after define-record-type runs (green; regression guard).
Diffstat:
6 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/tests/scheme1/38-record-internal-prims.expected b/tests/scheme1/38-record-internal-prims.expected
@@ -0,0 +1 @@
+scheme1: unbound variable
diff --git a/tests/scheme1/38-record-internal-prims.expected-exit b/tests/scheme1/38-record-internal-prims.expected-exit
@@ -1 +1 @@
-33
+1
diff --git a/tests/scheme1/38-record-internal-prims.scm b/tests/scheme1/38-record-internal-prims.scm
@@ -1,7 +1,10 @@
-; Internal record primitives are accessible directly: build a TD, build
-; a record, ref/set/predicate via %record-*.
-(define td (%make-record-td 'foo 2))
-(define r (%make-record td 11 22))
-(sys-exit (if (%record-is-a? r td)
- (+ (%record-ref r 0) (%record-ref r 1))
- 999))
+; Internal record primitives are not part of the user-facing API
+; (R7RS records bind only the constructor / predicate / accessors /
+; mutators introduced by define-record-type). Calling %make-record-td
+; from user code must abort with "scheme1: unbound variable".
+;
+; This test is RED until the %record-* rows are removed from
+; prim_table; today it would otherwise return 33 from the old
+; through-public-binding path.
+(%make-record-td 'foo 2)
+(sys-exit 0)
diff --git a/tests/scheme1/39-record-typename-unbound.expected b/tests/scheme1/39-record-typename-unbound.expected
@@ -0,0 +1 @@
+scheme1: unbound variable
diff --git a/tests/scheme1/39-record-typename-unbound.expected-exit b/tests/scheme1/39-record-typename-unbound.expected-exit
@@ -0,0 +1 @@
+1
diff --git a/tests/scheme1/39-record-typename-unbound.scm b/tests/scheme1/39-record-typename-unbound.scm
@@ -0,0 +1,22 @@
+; In R7RS-small, the type name introduced by define-record-type is
+; purely syntactic. After the form runs, only the constructor /
+; predicate / accessors / mutators have runtime bindings; the type
+; name itself (`point`) does not. A bare reference must abort with
+; "scheme1: unbound variable".
+;
+; Today this test is green — the impl never bound the name. It exists
+; to lock in that R7RS behavior against any future change that would
+; expose the TD as a value (e.g. a generated <point-td> binding).
+(define-record-type point
+ (make-point x y)
+ point?
+ (x point-x)
+ (y point-y))
+
+; Touch a generated binding to prove the form ran.
+(define p (make-point 1 2))
+(if (point? p) 0 (sys-exit 99))
+
+; Bare reference to the type name -> unbound -> abort.
+point
+(sys-exit 0)