about summary refs log tree commit diff stats
path: root/031transforms.cc
blob: a6e1250264b499d994d209d10be45a285aad2e1b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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. As an example:
//:
//:     Layer l introduces a transform
//:     Layer l+1 adds precondition checks for the transform
//:
//: 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