about summary refs log tree commit diff stats
path: root/subx/029transforms.cc
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-08-04 22:38:23 -0700
committerKartik Agaram <vc@akkartik.com>2018-08-04 22:38:23 -0700
commitaaf24db4aeca73e985437d065b36815677716694 (patch)
treec9dd0c57faefab8b468badf5bc29b36df9c68be7 /subx/029transforms.cc
parenta9985c33cbf9214c1a1de087b4491bf67f69f817 (diff)
downloadmu-aaf24db4aeca73e985437d065b36815677716694.tar.gz
4482
Diffstat (limited to 'subx/029transforms.cc')
-rw-r--r--subx/029transforms.cc65
1 files changed, 65 insertions, 0 deletions
diff --git a/subx/029transforms.cc b/subx/029transforms.cc
new file mode 100644
index 00000000..9546ea91
--- /dev/null
+++ b/subx/029transforms.cc
@@ -0,0 +1,65 @@
+//: Ordering transforms is a well-known hard problem when building compilers.
+//: In our case we also have the additional notion of layers. The ordering of
+//: layers can have nothing in common with the ordering of transforms when
+//: SubX is tangled and run. This can be confusing for readers, particularly
+//: if later layers start inserting transforms at arbitrary points between
+//: transforms introduced earlier. Over time adding transforms can get harder
+//: and harder, having to meet the constraints of everything that's come
+//: before. It's worth thinking about organization up-front so the ordering is
+//: easy to hold in our heads, and it's obvious where to add a new transform.
+//: Some constraints:
+//:
+//:   1. Layers force us to build SubX bottom-up; since we want to be able to
+//:   build and run SubX after stopping loading at any layer, the overall
+//:   organization has to be to introduce primitives before we start using
+//:   them.
+//:
+//:   2. Transforms usually need to be run top-down, converting high-level
+//:   representations to low-level ones so that low-level layers can be
+//:   oblivious to them.
+//:
+//:   3. When running we'd often like new representations to be checked before
+//:   they are transformed away. The whole reason for new representations is
+//:   often to add new kinds of automatic checking for our machine code
+//:   programs.
+//:
+//: Putting these constraints together, we'll use the following broad
+//: organization:
+//:
+//:   a) We'll divide up our transforms into "levels", each level consisting
+//:   of multiple transforms, and dealing in some new set of representational
+//:   ideas. Levels will be added in reverse order to the one their transforms
+//:   will be run in.
+//:
+//:     To run all transforms:
+//:       Load transforms for level n
+//:       Load transforms for level n-1
+//:       ...
+//:       Load transforms for level 2
+//:       Run code at level 1
+//:
+//:   b) *Within* a level we'll usually introduce transforms in the order
+//:   they're run in.
+//:
+//:     To run transforms for level n:
+//:       Perform transform of layer l
+//:       Perform transform of layer l+1
+//:       ...
+//:
+//:   c) Within a level it's often most natural to introduce a new
+//:   representation by showing how it's transformed to the level below. To
+//:   make such exceptions more obvious checks usually won't be first-class
+//:   transforms; instead code that keeps the program unmodified will run
+//:   within transforms before they mutate the program.
+//:
+//:     Level l transforms programs
+//:     Level l+1 inserts checks to run *before* the transform of level l runs
+//:
+//: This may all seem abstract, but will hopefully make sense over time. The
+//: goals are basically to always have a working program after any layer, to
+//: have the order of layers make narrative sense, and to order transforms
+//: correctly at runtime.
+
+:(before "End One-time Setup")
+// Begin Transforms
+// End Transforms