about summary refs log tree commit diff
path: root/compilation/top-level.e
diff options
context:
space:
mode:
Diffstat (limited to 'compilation/top-level.e')
-rw-r--r--compilation/top-level.e237
1 files changed, 237 insertions, 0 deletions
diff --git a/compilation/top-level.e b/compilation/top-level.e
new file mode 100644
index 0000000..959711b
--- /dev/null
+++ b/compilation/top-level.e
@@ -0,0 +1,237 @@
+~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~ ~~ Top-level executable builders ~~
+~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~
+~   Although it's perfectly possible to manually invoke the pieces of the
+~ compiler, it's inconvenient to do so. This file has helper words which kick
+~ off the process of compilation from the top level.
+~
+~   The two most important words in the top-level facility are "enchant",
+~ which produces an executable binary, and "inscribe", which produces a
+~ commented hex dump corresponding to that same binary.
+~
+~   Significant effort has been expended to make sure that the interfaces to
+~ "enchant" and "inscribe" are the same, despite them notionally existing at
+~ different levels of abstraction.
+
+
+~   This accepts a pointer to an existing buffer for file contents to be
+~ appended to, and another pointer to the start of a packed list of filenames.
+~ The filename list consists of null-terminated strings, all directly abutting
+~ each other in memory, terminated by a zero-length string (which can also
+~ be thought of as a freestanding null byte).
+~
+~   It reads the contents of the named files into the buffer, with no
+~ separation between them, and returns a pointer to the end of the contents.
+~
+~ (buffer point, filename list point -- buffer point)
+: read-inputs-from-filename-list
+  ~ (buffer point, filename list point)
+  { dup 8@ } {
+    dup 3roll swap pack-file-contents swap
+    dup stringlen 1+ +
+  } while drop ;
+
+
+~ (static source filename list, dynamic source filename list, boot source
+~  filename list -- source to precompile, source to copy to log,
+~  source to copy textually)
+: read-inputs
+  here @ dup
+  ~ (static source filename list, dynamic source filename list,
+  ~  boot source filename list, source to precompile, buffer point)
+  4 pick read-inputs-from-filename-list
+  0 pack8 8 packalign here !
+  ~ (static source filename list, dynamic source filename list,
+  ~  boot source filename list, source to precompile)
+
+  here @ dup
+  ~ (static source filename list, dynamic source filename list,
+  ~  boot source filename list, source to precompile, source to copy to log,
+  ~  buffer point)
+  5 pick read-inputs-from-filename-list
+  4 pick read-inputs-from-filename-list
+  0 pack8 8 packalign here !
+  ~ (static source filename list, dynamic source filename list,
+  ~  boot source filename list, source to precompile, source to copy to log)
+
+  here @ dup
+  ~ (static source filename list, dynamic source filename list,
+  ~  boot source filename list, source to precompile, source to copy to log,
+  ~  source to copy textually, buffer point)
+  4 pick read-inputs-from-filename-list
+  0 pack8 8 packalign here !
+  ~ (static source filename list, dynamic source filename list,
+  ~  boot source filename list, source to precompile, source to copy to log,
+  ~  source to copy textually)
+
+  4 roll drop 4 roll drop 4 roll drop ;
+
+
+~ (output memory start, current output point,
+~  compile-header execution token, compile-footer execution token,
+~  source to precompile, source to copy to log, source to include textually
+~  -- output memory start, current output point)
+: output-contents
+  7 roll 7 roll
+  ~ (compile-header execution token, compile-footer execution token,
+  ~  source to precompile, source to copy to log, source to include textually,
+  ~  output memory start, current output point)
+
+  ~ Invoke the provided header callback.
+  7 roll execute
+  ~ (compile-footer execution token, source to precompile,
+  ~  source to copy to log, source to include textually, output memory start,
+  ~  current output point)
+
+  elf-file-header
+  elf-program-header
+
+  output-cold-start
+
+  ~ Warm start and the log-loaded source.
+  output-warm-start-header
+  4 roll log-load-transform
+  ~ (compile-footer execution token, source to precompile,
+  ~  source to include textually, output memory start, current output point)
+  output-warm-start-post-log-load-transform
+  output-warm-start-attach-boot-source
+  output-warm-start-footer
+
+  ~ The label-transformed source.
+  4 roll label-transform
+  ~ (compile-footer execution token, source to include textually,
+  ~  output memory start, current output point, final entry pointer)
+
+  ~ The boot source.
+  4 roll output-boot-source
+  ~ (compile-footer execution token, output memory start,
+  ~  current output point)
+
+  ~ Invoke the provided footer callback.
+  3roll execute
+  ~ (output memory start, current output point)
+  ;
+
+
+~   Given a description of an executable, compile and output that executable
+~ as runnable binary, to standard output.
+~
+~ (static source filename list, dynamic source filename list,
+~  boot source filename list, compile-header word name,
+~  compile-footer word name --)
+: enchant-from-description
+  5 roll 5 roll 5 roll read-inputs
+  ~ (compile-header word name, compile-footer word name, source to precompile,
+  ~  source to copy to log, source to copy textually)
+
+  ~   We need an execution token to pass to label-loop. There's no reason to
+  ~ create a dictionary entry for it; we just allocate space for the
+  ~ executable word body directly.
+  here @
+  docol ,
+  6 roll find entry-to-execution-token literal
+  5 roll find entry-to-execution-token literal
+  4 roll literal
+  3 roll literal
+  swap literal
+  ' output-contents entry-to-execution-token ,
+  ' exit entry-to-execution-token ,
+
+  label-loop
+  1 3unroll sys-write
+  bye ;
+
+
+~   Given a filename containing the top-level source of an executable, compile
+~ and output that executable as runnable binary, to standard output.
+~
+~ (top-level source filename --)
+: enchant
+  include drop
+  s" latest-executable-data" find entry-to-execution-token execute
+  enchant-from-description ;
+
+
+~   Given a filename containing the top-level source of an executable, compile
+~ and output that executable as a commented hex dump, to standard output.
+~ Processing the hex dump through "hex" will give an identical binary to what
+~ "enchant" would have produced, with the same inputs.
+~
+~   Please notice that if the thing we're compiling is "evoke" and its list
+~ of source files has changed, we'll be working with the new list, not
+~ the old list. This is the same as what "enchant" does, and it's strictly
+~ preferable behavior. We match the behavior of enchant as closely as
+~ possible in terms of what's taken from the host compiler vs. the compiler
+~ being compiled; see the description of "enchant", above, for more details
+~ and discussion of the implications.
+~
+~ (top-level source filename --)
+: inscribe
+  dup here @ = { allocate-string } if
+  dup include drop
+  s" latest-executable-data" find entry-to-execution-token execute
+  ~ (top-level source filename, static source filename list,
+  ~  dynamic source filename list, boot source filename list,
+  ~  compile-header word name, compile-footer word name --)
+
+  ~   We begin by constructing the full text of all the source that will be
+  ~ run inside the scope of the hex transform. That necessarily includes not
+  ~ only the compilation machinery, but the transformation system. Notably
+  ~ it does not need to include "inscribe", but does need to include
+  ~ "enchant", and having a stray unused copy of inscribe is harmless, so we
+  ~ don't try to exclude it.
+  here @ dup
+  ~ (top-level source filename, static source filename list,
+  ~  dynamic source filename list, boot source filename list,
+  ~  compile-header word name, compile-footer word name,
+  ~  hex-transformed source pointer, output point)
+
+  6 pick read-inputs-from-filename-list
+  5 pick read-inputs-from-filename-list
+  4 pick read-inputs-from-filename-list
+  8 roll pack-file-contents
+
+  ~   We need to create a call to "enchant" in the code under transformation.
+  ~ That call doesn't need to be arrived at in exactly the same way as an
+  ~ independent call would be, since it doesn't become part of the output, it
+  ~ only needs to have the same effect.
+  ~
+  ~   So, we can take the filename list pointers that will become parameters
+  ~ to "enchant" and pass them in directly, heedless of the fact they
+  ~ reference locations in the outer log.
+  s"  0x" pack-raw-string 7 roll pack-hex64
+  s"  0x" pack-raw-string 6 roll pack-hex64
+  s"  0x" pack-raw-string 5 roll pack-hex64
+  ~ (compile-header word name, compile-footer word name,
+  ~  hex-transformed source pointer, output point)
+
+  ~   We do not have that luxury with the two compile hooks; we need copies of
+  ~ them that are under the hex transform. We produce code that looks them up
+  ~ by name. Notice that this is possible because we included the top-level
+  ~ source in our full source text.
+  ~
+  ~   Outputting quotation marks is, as always, a pain.
+  s"  s" pack-raw-string 0x22 pack8 s"  " pack-raw-string
+  4 roll pack-raw-string
+  0x22 pack8
+  s"  allocate-string" pack-raw-string
+
+  s"  s" pack-raw-string 0x22 pack8 s"  " pack-raw-string
+  3roll pack-raw-string
+  0x22 pack8
+  s"  allocate-string" pack-raw-string
+  ~ (hex-transformed source pointer, output point)
+
+  s"  enchant-from-description" pack-raw-string
+  ~ (hex-transformed source pointer, output point)
+  0 pack8 8 packalign here !
+
+  ~ (hex-transformed source pointer)
+  1024 1024 4 * * allocate
+  1024 1024 8 * * allocate
+  ~ (hex-transformed source pointer, binary buffer pointer,
+  ~  metadata buffer pointer)
+
+  swap dup 4 roll hex-transform bye ;
+