summary refs log tree commit diff
path: root/transform.e
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-05-16 15:30:35 -0700
committerIrene Knapp <ireneista@irenes.space>2026-05-16 15:30:35 -0700
commit4f1a07da9c87a1560da34b8a96a9de4cdc90f1fc (patch)
tree31360b5f2acf4fe1b870cb04a2bfd58fb35ba1eb /transform.e
parentfe3de0772dac094b94f8de89efbb815a62b1a2fa (diff)
the skeleton of the log-load transform is in place now
it doesn't actually output anything, but it all runs without crashing

Force-Push: yes
Change-Id: I48f2e647044df0ae3db961c747cee31a8826ecf3
Diffstat (limited to 'transform.e')
-rw-r--r--transform.e173
1 files changed, 68 insertions, 105 deletions
diff --git a/transform.e b/transform.e
index ac85e14..5ddac78 100644
--- a/transform.e
+++ b/transform.e
@@ -109,6 +109,20 @@
 ~ versions of certain immediate words used in word definition. Also like the
 ~ label transform, it provides its own copies of "here" and "latest".
 ~
+~   The log-load transform provides alternates for a significantly broader set
+~ of words than the label transform, including all the flow-control words such
+~ as if-else. It runs its own alternates immediately, but unlike the label
+~ transform, immediate execution for the log-load transform is not actually
+~ immediate; it is compiled into words which will have those immediate effects
+~ at the time the generated routine is run. The generated routine can itself
+~ be thought of as a compilation process, producing its output on the log, so
+~ doing things later for us still means doing them immediately during the
+~ routine.
+~
+~   The log-load transform does impose a no-forward-references requirement,
+~ though it is applied at the time the routine is run, rather than at the time
+~ of the transformation.
+~
 ~   The log-load transformation and its alternates rely on the following
 ~ labels, all of which must be defined elsewhere: TODO
 
@@ -475,10 +489,8 @@ allocate-transform-state s" transform-state" variable
     ~ It's a number.
     interpreter-flags @ 0x01 & {
       ~ We're in compile mode; append first "lit", then the number, to the
-      ~ heap. The version of "lit" we use is the one that's current when we
-      ~ ourselves are compiled, hardcoded; doing a dynamic lookup would
-      ~ require dealing with what happens if it's not found.
-      ~ TODO this is wrong
+      ~ heap. The version of "lit" we use is found by label, so it'll be the
+      ~ one that exists when this code is ultimately run.
       dropstring-with-result
 
       ~ We look up "lit" as a label.
@@ -657,129 +669,80 @@ allocate-transform-state s" transform-state" variable
   ~ (string)
   value@
 
+  dup emitstring newline
+
   ~ If it's the magic word, end the transformation.
   dup s" pyrzqxgl" stringcmp 0 = { drop dropstring 1 exit } if
 
   ~   Check whether it's one of the words we have alternates for, and look up
   ~ the alternate if so.
-  dup 0 swap
-  ~ (name as stack string, name pointer, placeholder, name pointer)
+  0 swap
+  ~ (name as stack string, placeholder, name pointer)
   dup s" create" stringcmp 0 = { swap drop ' log-load-create swap } if
   dup s" :" stringcmp 0 = { swap drop ' log-load: swap } if
   dup s" ;" stringcmp 0 = { swap drop ' log-load; swap } if
   dup s" ;asm" stringcmp 0 = { swap drop ' log-load;asm swap } if
-  drop swap
-  ~ (name as stack string, 0 or alternate entry pointer, name pointer)
-
-  ~   If an alternate was found, the alternate will be used in immediate mode.
-  ~ If not, we look up the word in the regular, non-transformed dictionary
-  ~ and use that for immediate mode.
-  over { dup
-         transform-state transform-state-saved-latest @ swap find-in
-         3roll drop swap } unless
-  ~ (name as stack string, immediate entry pointer, name pointer)
-
-  ~   In regular "interpret", we would check whether we found the word before
-  ~ checking the mode. However, we have three different places words could
-  ~ come from, so that's not a simple notion. So, we check the mode first.
-  interpreter-flags @ 0x01 & {
-    ~   If we're in compile mode, there's still a chance it's an immediate
-    ~ word. First check whether we have an immediate entry, then if so, check
-    ~ that entry's flags. Notice that this means the generated code can't
-    ~ override an immediate word with a non-immediate word of the same name.
-    over dup { entry-flags@ 0x01 & not } if
-
-    {
-      ~   Either there was no immediate entry, or the immediate entry wasn't
-      ~ flagged as an immediate word. So we check whether this could be a
-      ~ compilation.
-      ~
-      ~   To do this, we need to look the word up in the output buffer. We
-      ~ can't easily traverse the next-entry pointers in the output buffer's
-      ~ dictionary, so we check the label. Since we don't know the word's name
-      ~ statically, this is a rare scenario where we can't use the abbreviated
-      ~ label syntax, but that's easy enough.
-      ~
-      ~   Even though we've ruled out the possibility that the word is only
-      ~ ever used immediately, it is still possible that there's some reason
-      ~ the word doesn't exist. In particular, it could be an integer literal.
-      ~ If we were to call use-label first, that would count as a requirement
-      ~ that the label must eventually be set. We don't want to require that
-      ~ quite yet, so we call find-label.
-      ~
-      ~   This check is the means by which forward references are disallowed:
-      ~ On the very first pass, a forward-referenced label won't exist yet, so
-      ~ transform will give a "no such word" error, which in an ideal world
-      ~ would prevent there from being a subsequent pass, but at the very
-      ~ least it will ensure the output isn't a valid ELF.
-      dup
-      swap-transform-variables
-      find-label
-      swap-transform-variables
-      {
-        ~   It exists, so we declare our use of it (that's also the only way to
-        ~ get a value for it).
-        swap-transform-variables
-        intern-label use-label
-        swap-transform-variables
-
-        ~   Labels point to codewords (because that's what "Lcreate" does),
-        ~ which is already what we want to output.
-        ~
-        ~   An important caveat: Though it would require something weird to be
-        ~ happening, such as a forced forward reference, the label may be zero!
-        ~ We need to allow for that possibility by not examining the contents of
-        ~ a nonexistent entry.
-        ~
-        ~   Fortunately we don't have to look at it, just append it to the heap
-        ~ and clean up.
-        offset-to-target-address-space , drop dropstring 0 exit
-      } if
-    } if
-  } if
-  ~ (name as stack string, immediate entry pointer, name pointer)
-
-  ~   If we got here, one of three things is true: We're in interpret mode;
-  ~ the word is immediate; or no word was found. If the immediate entry
-  ~ pointer is non-zero, run it.
-  over {
-    drop dropstring-with-result entry-to-execution-token execute
+  drop
+  ~ (name as stack string, 0 or alternate entry pointer)
+
+  ~   If we have an alternate, we want to run that now, regardless of what
+  ~ mode we're in. They're all flagged as immediate, but we don't even bother
+  ~ checking, because it doesn't fully describe their behavior anyway. With
+  ~ this transform there's three potential times at which we might execute
+  ~ things, not two. The alternates are more immediate than immediate; they
+  ~ run NOW, during the transformation.
+  dup {
+    dropstring-with-result entry-to-execution-token execute
     0 exit
   } if
-
-  ~   If we're still here, it wasn't in the dictionary. Also, we don't need
-  ~ the immediate entry pointer, either.
-  drop drop
   ~ (name as stack string)
 
-  ~   If it's not in the dictionary, check whether it's an integer literal. As
-  ~ before, we get the stack address and use it as a string pointer.
+  ~   Now we might have a compiled word, an immediate word, or an integer
+  ~ literal. Recall that the word won't actually be looked up until the
+  ~ routine we're producing is run - that's the whole point - so there's no
+  ~ check we can perform now that will tell us whether the word we have exists
+  ~ in the eventual log. Instead, we invert the usual fallback order and
+  ~ check whether the word could be an integer literal. If it is, we'll
+  ~ handle that; if not, we'll assume it'll eventually exist.
+  ~
+  ~   This means that code that's run with the log-load transform can't
+  ~ shadow an integer literal with a word definition. Oh, so limiting.
   value@ read-integer 0 = {
     ~ It's a number.
-    interpreter-flags @ 0x01 & {
-      ~ We're in compile mode; append first "lit", then the number, to the
-      ~ heap. The version of "lit" we use is the one that's current when we
-      ~ ourselves are compiled, hardcoded; doing a dynamic lookup would
-      ~ require dealing with what happens if it's not found.
-      ~ TODO this is wrong
-      dropstring-with-result
+    dropstring-with-result
 
-      ~ We look up "lit" as a label.
-      swap-transform-variables L@' lit swap-transform-variables
-      offset-to-target-address-space
-      , ,
+    interpreter-flags @ 0x01 & {
+      ~ We're in compile mode, so we want to generate code which will compile
+      ~ the number.
+      ~ TODO
       0 exit
     } if
 
-    ~ We're in interpret mode; push the number to the stack. Or at least, that's
-    ~ what the code we're interpreting will see. Really it's already on the
-    ~ stack, just clean everything else up and leave it there.
-    dropstring-with-result
+    ~ We're in interpret mode, so we want to generate code which will push the
+    ~ number to the stack.
+    ~ TODO
     0 exit
   } if
+  drop
+  ~ (name as stack string)
 
-  ~ If it's neither in the dictionary nor a number, just print an error.
-  s" No such word: " emitstring value@ emitstring dropstring 0 ;
+  ~   We know it's a regular word, and we're assuming it will exist at
+  ~ runtime. We of course have no way to check what flags it will have, which
+  ~ means immediate words don't work with this transform. We still treat it
+  ~ differently based on whether we're in compile mode.
+  interpreter-flags @ 0x01 & {
+    ~ We're in compile mode. We compile code that compiles the word.
+    ~ TODO
+    dropstring 0 exit
+  } if
+  ~ (name as stack string)
+
+  ~ We're in immediate mode. We compile code that runs the word immediately.
+  ~ TODO
+
+  ~ There's no such thing as not finding the word, with this transform. So
+  ~ we just exit.
+  dropstring 0 ;
 
 
 ~   This implements the log-load transform for all words in a region given as