summary refs log tree commit diff
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-05-21 00:23:32 -0700
committerIrene Knapp <ireneista@irenes.space>2026-05-21 00:23:32 -0700
commit189f0c0de22150f944e067b686b4cfe81af5fcb8 (patch)
treee77213734e4260b3e9a33016d85ddcb233bd7912
parentd784695204db078a8f1731f93d12117f6e53c317 (diff)
okay, s" and ." work all-the-way in the log-load transform now
wow those were hard ones. it's very squirelly what happens when.  hopefully these new and reorganized docs will make it easier to understand next time...

Force-Push: yes
Change-Id: I8f3b86900ca1794afc3e607c2180dd05ea168cc7
-rw-r--r--log-load.e18
-rw-r--r--transform.e130
2 files changed, 122 insertions, 26 deletions
diff --git a/log-load.e b/log-load.e
index e496e04..4649403 100644
--- a/log-load.e
+++ b/log-load.e
@@ -355,3 +355,21 @@
   ~ (log address, output point, here)
   ! ;
 
+
+~   This is a helper used by log-load-string-alternate. It does the usual
+~ string packing thing, but at one layer of indirection more than usual. Its
+~ responsibility includes alignment, unlike packstring.
+~
+~ (log address, string pointer -- log address)
+: log-load-comma-string
+  swap log-load-here @ 3roll
+  ~ (log address, output point, string pointer)
+
+  packstring
+  8 packalign
+  ~ (log address, output point)
+
+  swap log-load-here 3roll swap
+  ~ (log address, output point, here)
+  ! ;
+
diff --git a/transform.e b/transform.e
index 236c031..a137c0c 100644
--- a/transform.e
+++ b/transform.e
@@ -829,10 +829,21 @@ allocate-transform-state s" transform-state" variable
 ~ code. If we don't provide an alternate for it, we get codeword pointers in
 ~ the host address space, which therefore don't work.
 : label-string-alternate
-  ~   Wrapping s" is surprisingly difficult; see log-load-string-alternate
-  ~ for detailed notes on how it works. This is pretty much the same
-  ~ implementation, except the label transform doesn't track user stack depth
-  ~ so we don't have to worry about that part.
+  ~   Something subtle here: s" is state-dependent. That is, it does different
+  ~ things depending on the interpreter flags. We would really rather know
+  ~ which version we're getting, and also it would be best if it didn't
+  ~ scribble on the output buffer. Fortunately we can achieve both of these,
+  ~ by coercing things into a known state while calling it.
+  ~
+  ~   We could choose either version of s", but the interpreted one is more
+  ~ convenient because it doesn't mess with a spurious litstring invocation,
+  ~ just scribbled into scratch space after "here". Of course, that raises the
+  ~ additional concern that we have the wrong "here", but we can just swap
+  ~ that around, too.
+  ~
+  ~   This is all worth it to avoid reimplementing s". If we had two
+  ~ implementations, they'd have to be kept in sync, and it's an important
+  ~ user-facing word with semantics that are likely to improve over time.
   interpreter-flags @
   ' s" entry-to-execution-token
   swap-transform-variables
@@ -842,12 +853,15 @@ allocate-transform-state s" transform-state" variable
   execute
   swap-transform-variables
   swap interpreter-flags !
+
   ~   Whew. What a mouthful.
-  ~ (string pointer)
+  ~
+  ~   Having done this, we have the string pointer on the stack at transform
+  ~ time, which with the label transform is the same as immediate time. If
+  ~ we're in immediate mode, therefore, we've left the string on the stack and
+  ~ that's all we wanted. If we're in compile mode, it's our job to output a
+  ~ litstring invocation.
 
-  ~   Now. If we are in immediate mode, we've left the string on the stack and
-  ~ that's all we wanted. If we're in compile mode, it's our job to output
-  ~ a litstring invocation.
   interpreter-flags @ 0x01 & {
     swap-transform-variables
     L@' litstring
@@ -1726,21 +1740,10 @@ allocate-transform-state s" transform-state" variable
 
 ~ Strings are important and must happen now, now, now.
 : log-load-string-alternate
-  ~   Something subtle here: s" is state-dependent. That is, it does different
-  ~ things depending on the interpreter flags. We would really rather know
-  ~ which version we're getting, and also it would be best if it didn't
-  ~ scribble on the output buffer. Fortunately we can achieve both of these,
-  ~ by coercing things into a known state while calling it.
-  ~
-  ~   We could choose either version of s", but the interpreted one is more
-  ~ convenient because it doesn't mess with a spurious litstring invocation,
-  ~ just scribbled into scratch space after "here". Of course, that raises the
-  ~ additional concern that we have the wrong "here", but we can just swap
-  ~ that around, too.
-  ~
-  ~   This is all worth it to avoid reimplementing s". If we had two
-  ~ implementations, they'd have to be kept in sync, and it's an important
-  ~ user-facing word with semantics that are likely to improve over time.
+  ~   Wrapping s" is surprisingly difficult; see label-string-alternate
+  ~ for detailed notes on how that works. Once we've finished the
+  ~ transform-time part, our implementations will diverge, but this first bit
+  ~ is the same.
   interpreter-flags @
   ' s" entry-to-execution-token
   swap-transform-variables
@@ -1750,8 +1753,24 @@ allocate-transform-state s" transform-state" variable
   execute
   swap-transform-variables
   swap interpreter-flags !
-  ~   Whew. What a mouthful.
-  ~ (string pointer)
+
+  ~   Nope, doing it twice didn't make that any less of a mouthful.
+  ~
+  ~   Having done this, we have the string pointer on the stack at transform
+  ~ time (not, mind you, at log-load time, as yet). Now it is our job to
+  ~ either compile it, or invoke it "immediately". Recall that the log-load
+  ~ transform's "immediate" time, which we also call log-load time, is
+  ~ analogous to the label transform's "compile" time. The log-load
+  ~ transform's "compile" time is an additional layer of indirection.
+  ~
+  ~   No matter which mode we're in, the first thing we want to do is get the
+  ~ string onto the value stack at log-load time. So we compile code to do
+  ~ that, first. We do that using the static "litstring", which we find by
+  ~ label.
+  ~
+  ~   If this is all too twisty, it might be helpful to go re-read the
+  ~ definition of log-load-compile-literal, which does a simpler version of
+  ~ this same task (because integers are easier than strings).
 
   swap-transform-variables
   L@' litstring
@@ -1760,8 +1779,65 @@ allocate-transform-state s" transform-state" variable
   offset-to-target-address-space ,     ~ litstring
   here @ swap packstring 8 packalign here !
 
-  ~   Now the string pointer is on the stack, so we apply a delta for it.
+  ~   Now the string pointer is on the stack at log-load time, so we apply a
+  ~ delta for it.
   1 transform-apply-stack-delta
+
+  ~   If we're in immediate mode, we're done! Yay! Putting the string on the
+  ~ stack at log-load time is what we wanted. If not...
+  interpreter-flags @ 0x01 & {
+    ~   We're in compile mode, so we need to look up the ultimate, dynamic,
+    ~ log-based, super-atomic space rocket copy of "litstring" and use that.
+    ~ We could call log-load-compile-dynamic-word here, but, as usual, it
+    ~ would produce some excessive rolling and unrolling, so we do its job
+    ~ ourselves instead.
+    log-load-roll-log-address
+
+    swap-transform-variables
+    ~ As usual, we do these in reverse.
+    L@' log-load-comma-string
+    L@' swap
+    L@' log-load-comma
+    L@' log-load-find-execution-token
+    L@' litstring
+    swap-transform-variables
+
+    ~ The overall stack delta of this sequence is 0.
+    offset-to-target-address-space ,     ~ litstring
+    here @ s" litstring" packstring 8 packalign here !
+    offset-to-target-address-space ,     ~ log-load-find-execution-token
+    offset-to-target-address-space ,     ~ log-load-comma
+    offset-to-target-address-space ,     ~ swap
+    offset-to-target-address-space ,     ~ log-load-comma-string
+
+    ~   We consumed the string pointer at log-load time, so we apply a delta
+    ~ for it.
+    ~
+    ~   Notice by the way how the nearby calls to log-load-unroll-log-address
+    ~ rely on this being split into two deltas like this, even though they
+    ~ net out to zero; we aren't doing it just for kicks.
+    -1 transform-apply-stack-delta
+
+    log-load-unroll-log-address ;
+  } if
+  ; make-immediate
+
+
+: log-load-dot-string-alternate
+  ' log-load-string-alternate entry-to-execution-token execute
+
+  interpreter-flags @ 0x01 & {
+    ~   Hey look, it's the one time we're doing something simple enough that
+    ~ we can actually benefit from log-load-compile-dynamic-word as something
+    ~ more than an example to start from. :)
+    s" emitstring" log-load-compile-dynamic-word
+  } {
+    swap-transform-variables
+    L@' emitstring
+    swap-transform-variables
+
+    offset-to-target-address-space ,     ~ emitstring
+  } if-else
   ; make-immediate
 
 
@@ -1865,6 +1941,8 @@ allocate-transform-state s" transform-state" variable
   ~ It is nontrivial to construct a string with a double-quote in it.
   dup ' s" entry-to-name stringcmp 0 = {
     swap drop ' log-load-string-alternate swap } if
+  dup ' ." entry-to-name stringcmp 0 = {
+    swap drop ' log-load-dot-string-alternate swap } if
   dup s" L@'" stringcmp 0 = { swap drop ' log-load-L@'-alternate swap } if
   dup s" L!'" stringcmp 0 = { swap drop ' log-load-L!'-alternate swap } if
   ~ (name as stack string, 0 or alternate entry pointer, name pointer)