diff options
| -rw-r--r-- | evoke.e | 4 | ||||
| -rw-r--r-- | execution.e | 3 | ||||
| -rw-r--r-- | transform.e | 173 |
3 files changed, 71 insertions, 109 deletions
diff --git a/evoke.e b/evoke.e index c1ee096..9209efc 100644 --- a/evoke.e +++ b/evoke.e @@ -10,7 +10,7 @@ s" source-to-precompile" variable 1024 read-to-buffer : foo 4 . ; pyrzqxgl -s" source-to-heap-copy" variable +s" source-to-copy-to-log" variable ~ (output memory start, current output point ~ -- output memory start, current output point) @@ -25,7 +25,7 @@ s" source-to-heap-copy" variable elf-file-header elf-program-header output-cold-start - source-to-heap-copy output-warm-start + source-to-copy-to-log output-warm-start output-docol output-exit source-to-precompile label-transform diff --git a/execution.e b/execution.e index 6af9e2c..daacddb 100644 --- a/execution.e +++ b/execution.e @@ -486,8 +486,7 @@ current-offset L!' warm-start 3roll - ~ log-load-transform - drop + log-load-transform ~ TODO this is tied to the specific example in evoke ~ L@' happy-path L@' origin + pack64 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 |