1 //: Ordering transforms is a well-known hard problem when building compilers. 2 //: In our case we also have the additional notion of layers. The ordering of 3 //: layers can have nothing in common with the ordering of transforms when 4 //: SubX is tangled and run. This can be confusing for readers, particularly 5 //: if later layers start inserting transforms at arbitrary points between 6 //: transforms introduced earlier. Over time adding transforms can get harder 7 //: and harder, having to meet the constraints of everything that's come 8 //: before. It's worth thinking about organization up-front so the ordering is 9 //: easy to hold in our heads, and it's obvious where to add a new transform. 10 //: Some constraints: 11 //: 12 //: 1. Layers force us to build SubX bottom-up; since we want to be able to 13 //: build and run SubX after stopping loading at any layer, the overall 14 //: organization has to be to introduce primitives before we start using 15 //: them. 16 //: 17 //: 2. Transforms usually need to be run top-down, converting high-level 18 //: representations to low-level ones so that low-level layers can be 19 //: oblivious to them. 20 //: 21 //: 3. When running we'd often like new representations to be checked before 22 //: they are transformed away. The whole reason for new representations is 23 //: often to add new kinds of automatic checking for our machine code 24 //: programs. 25 //: 26 //: Putting these constraints together, we'll use the following broad 27 //: organization: 28 //: 29 //: a) We'll divide up our transforms into "levels", each level consisting 30 //: of multiple transforms, and dealing in some new set of representational 31 //: ideas. Levels will be added in reverse order to the one their transforms 32 //: will be run in. 33 //: 34 //: To run all transforms: 35 //: Load transforms for level n 36 //: Load transforms for level n-1 37 //: ... 38 //: Load transforms for level 2 39 //: Run code at level 1 40 //: 41 //: b) *Within* a level we'll usually introduce transforms in the order 42 //: they're run in. 43 //: 44 //: To run transforms for level n: 45 //: Perform transform of layer l 46 //: Perform transform of layer l+1 47 //: ... 48 //: 49 //: c) Within a level it's often most natural to introduce a new 50 //: representation by showing how it's transformed to the level below. To 51 //: make such exceptions more obvious checks usually won't be first-class 52 //: transforms; instead code that keeps the program unmodified will run 53 //: within transforms before they mutate the program. As an example: 54 //: 55 //: Layer l introduces a transform 56 //: Layer l+1 adds precondition checks for the transform 57 //: 58 //: This may all seem abstract, but will hopefully make sense over time. The 59 //: goals are basically to always have a working program after any layer, to 60 //: have the order of layers make narrative sense, and to order transforms 61 //: correctly at runtime. 62 63 :(before "End One-time Setup") 64 // Begin Transforms 65 // End Transforms