diff options
Diffstat (limited to 'doc/design/s2_3')
-rw-r--r-- | doc/design/s2_3 | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/doc/design/s2_3 b/doc/design/s2_3 new file mode 100644 index 0000000..341ea74 --- /dev/null +++ b/doc/design/s2_3 @@ -0,0 +1,326 @@ +@SubSection + @Tag { objects } + @Title { Basic structural operators } +@Begin +@PP +A programming language may be considered complete when it attains the +power of a Turing machine, but no such criterion seems relevant to +document formatting. Instead, as the language develops and new +applications are attempted, deficiencies are exposed and the operator set is +revised to overcome them. +@PP +Lout has a repertoire of 23 primitive operators +(Figure {@NumberOf primitives}), + +@Figure + @Caption { The 23 primitive operators of Lout, in order of +increasing precedence. } + @Tag { primitives } +@Tab + vmargin { 0.5vx } + @Fmta { @Col @I A ! @Col B } +{ +@Rowa + A { object {@Code "/"}gap object } + B { Vertical concatenation with mark alignment } +@Rowa + A { object {@Code "//"}gap object } + B { Vertical concatenation with left justification } +@Rowa + A { object {@Code "|"}gap object } + B { Horizontal concatenation with mark alignment } +@Rowa + A { object {@Code "||"}gap object } + B { Horizontal concatenation with top-justification } +@Rowa + A { object {@Code "&"}gap object } + B { Horizontal concatenation within paragraphs } +@Rowa + A { {@Code "@OneCol"} object } + B { Hide all but one column mark of @I object } +@Rowa + A { {@Code "@OneRow"} object } + B { Hide all but one row mark of @I object } +@Rowa + A { font @Code "@Font" object } + B { Render @I object in nominated font } +@Rowa + A { breakstyle @Code "@Break" object} + B { Break paragraphs of @I object in nominated style } +@Rowa + A { spacestyle @Code "@Space" object } + B { Render spaces between words in nominated style } +@Rowa + A { length {@Code "@Wide"} object } + B { Render @I object to width @I length } +@Rowa + A { length {@Code "@High"} object } + B { Render @I object to height @I length } +@Rowa + A { {@Code "@HExpand"} object} + B { Expand horizontal gaps to fill available space } +@Rowa + A { {@Code "@VExpand"} object} + B { Expand vertical gaps to fill available space } +@Rowa + A { {@Code "@HScale"} object } + B { Horizontal geometrical scaling to fill available space } +@Rowa + A { {@Code "@VScale"} object } + B { Vertical geometrical scaling to fill available space } +@Rowa + A { angle {@Code "@Rotate"} object } + B { Rotate @I object by @I angle } +@Rowa + A { PostScript {@Code "@Graphic"} object } + B { Escape to graphics language } +@Rowa + A { @Code "@Next" object } + B { Add 1 to an object denoting a number } +@Rowa + A { object @Code "@Case" alternatives } + B { Select from a set of alternative objects } +@Rowa + A { identifier @Code "&&" object } + B { Cross reference } +@Rowa + A { cross-reference @Code "@Open" object } + B { Retrieve value from cross reference } +@Rowa + A { cross-reference @Code "@Tagged" object} + B { Attach cross referencing tag to object } +} + +which has proven adequate for a wide variety of features, including equations, +tables, and page layout, and so seems to be reasonably complete in this +pragmatic sense. In this section we introduce the eight concatenation and +mark-hiding operators. To them falls the basic task of assembling complex +objects from simple ones, and they were the first +to be designed and implemented. +@PP +Many of the operators of Eqn can be viewed as building small tables. A +built-up fraction, for example, has one column and three rows +(numerator, line, and denominator). Numerous investigations of this +kind convinced the author that operators capable of assembling the rows +and columns of tables would suffice for building all kinds of objects. +@PP +The simplest objects are empty objects and literal words like +{@Code metempsychosis}, which have one column mark and one row mark: +@ID { +@ShowMarks metempsychosis +} +To place two arbitrary objects side by side, we use the infix +operator {@Code "|"}, denoting horizontal concatenation. For +example, +@ID { +@Code "USA |0.2i Australia" +} +produces the object +@ID { +@ShowMarks USA |0.2i @ShowMarks Australia +} +The row marks are merged into one, fixing the vertical position of +the objects relative to each other; their horizontal separation is +determined by the @I gap attached to the operator, in this case 0.2 +inches. We think of the gap as part of the operator, although +strictly it is a third parameter. It may be omitted, defaulting to +{@Code "0i"}. +@PP +@I {Vertical concatenation} & , denoted by the infix operator {@Code "/"}, +is the same apart from the change of direction: +@ID { +@Code "Australia /0.1i USA" +} +produces the object +@ID { +@ShowMarks Australia /0.1i +@ShowMarks USA +} +with column marks merged and a 0.1 inch gap. +@PP +Consider now what happens when horizontal and vertical are combined: +@ID @OneRow @Code { + |1m "{" USA |1m "|0.2i" |1m Australia "}" +/1vx "/0.1i" | "{" Washington | "|" | Canberra "}" +} +The two parameters of @Code "/" now have two column marks each, and +they will be merged with the corresponding marks in the other +parameter, yielding the object + +@ID @OneRow { + @BackEnd @Case { + PostScript @Yield { + @ShowMarks USA & + { 0 ymark moveto xsize 10 pt add ymark lineto [ 3 pt ] 0 setdash stroke } + @Graphic {1c @Wide } + |0.2i @ShowMarks Australia +/0.1i @ShowMarks Washington | @ShowMarks Canberra + } + PDF @Yield { + @ShowMarks USA & + { [ __mul(3, __pt) ] 0 d 0 __ymark m __add(__xsize, __mul(10, __pt)) __ymark l S } + @Graphic {1c @Wide } + |0.2i @ShowMarks Australia +/0.1i @ShowMarks Washington | @ShowMarks Canberra + } + } +} +The @Code "0.2i" gap separates columns, not individual items in +columns, so a gap attached to the second @Code "|" would serve no +purpose; any such gap is ignored. If the number of marks to be merged +differs, empty columns are added at the right to equalize the number. The +four marks protruding from the result are all available for merging +with neighbouring marks by other concatenation operators. The precedence +of @Code "|" is higher than the precedence of {@Code "/"}, so the braces +could be omitted. +@PP +When lines of text are concatenated, it is conventional to measure +their separation from baseline to baseline (mark to mark in Lout), +rather than from edge to edge as above. This idea of different +reference points for measurement evolved over the years into a +system of six @I {gap modes} (Figure {@NumberOf gapmodes}), expressed +by appending a letter to the length. For example, @Code "|0.2i" is +an abbreviation for {@Code "|0.2ie"}, meaning 0.2 inches measured +from edge to edge; @Code "|0.3ix" +produces a 0.3 inch gap measured from mark to mark and widened if +necessary to prevent overstriking; and @Code "|2.5it" places its right +parameter 2.5 inches from the current left margin, irrespective of +the position of the left parameter. There is also a choice of +eleven units of measurement (inches, centimetres, multiples of the +current font size, etc.), the most interesting being +the @Code r unit: one @Code r is the column width minus the width of +the following object, so that @Code "|1rt" produces sufficient space +to right justify the following object, and @Code "|0.5rt" to center +it. These features implement spacings needed in practice rather +than suggested by theory. They work with all five concatenation +operators, horizontal and vertical. + +@Figure + @Tag { gapmodes } + @Caption { The six gap modes (@I length is any length). Hyphenation +mode has an extra property not shown here. } +@Fig { +{ /2.5vx Edge-to-edge |0.3i {@Code "|"} &1p {@I length} &1p {@Code e} + /4.2vx Hyphenation |0.3i {@Code "|"} &1p {@I length} &1p {@Code h} + /4.2vx Overstrike |0.3i {@Code "|"} &1p {@I length} &1p {@Code o} + /4.2vx Mark-to-mark |0.3i {@Code "|"} &1p {@I length} &1p {@Code x} + /4.2vx Kerning |0.3i {@Code "|"} &1p {@I length} &1p {@Code k} + /4.2vx Tabulation |0.3i {@Code "|"} &1p {@I length} &1p {@Code t} +} +||0.5i +@Box margin { 0c } 6c @Wide 14.5c @High 9p @Font +{ + @OneRow { + @At { 1c @Wide 0.5c @High } @Put { @LBox 0.2co } + @At { 4c @Wide 0.5c @High } @Put { @LBox 0.5co } + @At { 2.2c @Wide 1.4c @High } @Put { @DoubleArrow 1.8c } + @At { 2.2c @Wide 1.6c @High } @Put { 1.8c @Wide { &0.5rt @I length } } + } + //4vx + @OneRow { + @At { 1c @Wide 0.5c @High } @Put { @LBox 0.2co } + @At { 4c @Wide 0.5c @High } @Put { @LBox 0.5co } + @At { 2.2c @Wide 1.4c @High } @Put { @DoubleArrow 1.8c } + @At { 2.2c @Wide 1.6c @High } @Put { 1.8c @Wide { &0.5rt @I length } } + } + //4vx + @OneRow { + @At { 1c @Wide 0.5c @High } @Put { @LBox 0.2co } + @At { 4c @Wide 0.5c @High } @Put { @LBox 0.5co } + @At { 1.2c @Wide 1.5c @High } @Put { @DoubleArrow 3.3c } + @At { 1.2c @Wide 1.7c @High } @Put { 3.3c @Wide { &0.5rt @I length } } + } + //4vx + @OneRow { + @At { 1c @Wide 0.5c @High } @Put { @LBox 0.2co } + @At { 4c @Wide 0.5c @High } @Put { @LBox 0.5co } + @At { 1.2c @Wide 1.5c @High } @Put { @DoubleArrow 3.3c } + @At { 1.2c @Wide 1.7c @High } + @Put 3.3c @Wide { |0.5rt @Eq { max(length, a+b) } } + @At { 1.2c @Wide 0.4c @High } @Put { @DoubleArrow 1.0c } + @At { 1.2c @Wide 0.2c @High } @Put { 1.0c @Wide { &0.5rt @I a } } + @At { 4c @Wide 0.4c @High } @Put { @DoubleArrow 0.5c } + @At { 4c @Wide 0.2c @High } @Put { 0.5c @Wide { &0.5rt @I b } } + } + //4.5vx + @OneRow { + @At { 1c @Wide 0.5c @High } @Put { @LBox 0.2co } + @At { 4c @Wide 0.5c @High } @Put { @LBox 0.5co } + @At { 1.2c @Wide 1.5c @High } @Put { @DoubleArrow 3.3c } + @At { 1.2c @Wide 1.7c @High } + @Put { 3.3c @Wide { |0.5rt @Eq { max(length, a, b) } } } + @At { 1.2c @Wide 0.4c @High } @Put { @DoubleArrow 1.0c } + @At { 1.2c @Wide 0.2c @High } @Put { 1.0c @Wide { &0.5rt @I a } } + @At { 4c @Wide 0.4c @High } @Put { @DoubleArrow 0.5c } + @At { 4c @Wide 0.2c @High } @Put { 0.5c @Wide { &0.5rt @I b } } + } + //4vx + @OneRow { + @At { 1c @Wide 0.5c @High } @Put { @LBox 0.2co } + @At { 4c @Wide 0.5c @High } @Put { @LBox 0.5co } + @At { 0.0c @Wide 1.6c @High } @Put { @DoubleArrow 4.0c } + @At { 2.8c @Wide 1.8c @High } @Put { @I length } + } + //5vx + @DoubleArrow 6c + //0.1c |0.5rt @I { current bound } +} +} + +@PP +When we construct a built-up fraction, the result has three row marks, but +only the second should be visible outside the object: +@ID @Eq { @ShowMarks { X over Y } } +This is a common problem, and accordingly a @Code "@OneRow" operator was +introduced for hiding all but one of the row marks of its +parameter. Normally, the first mark is the survivor, but a later mark can +be chosen by prefixing @Code "^" to the preceding concatenation operator: +@ID @Code "@OneRow { X ^/2p @HLine /2p Y }" +has the desired result, where {@Code "2p"} is two points and @Code "@HLine" +is an easy combination of Lout's graphics operators. A similar operator, +{@Code "@OneCol"}, hides column marks. +@PP +A variant of @Code "/" called @Code "//" is provided which performs +vertical concatenation but ignores all column marks and simply +left-justifies its two parameters: +@ID @OneRow @Code { +"Heading //0.1i" +"A |0.2i B /0.1i" +"C | D" +} +has result +@ID { Heading //0.1i A |0.2i B /0.1i C | D } +showing that spanning columns in tables motivate the inclusion of this +operator. There is an analogous @Code "||" operator. The author +would have preferred to leave out these operators, since they +complicate the implementation, and it is interesting to examine the +prospects of doing so. +@PP +The @Code "//" operator is formally redundant, because in general +the expression @Code "x // y" can be replaced by +@ID @OneRow @Code { +"@OneCol { | x } /" +"@OneCol { | y }" +} +for any objects {@Code x} and {@Code y}. By concatenating an empty +object at the left of @Code x and hiding all but that empty object's +column mark, we effectively shift {@Code x}'s column mark to its left +edge. The same goes for {@Code y}, so the @Code "/" operator has just +one column mark to merge, at the extreme left, and its effect is +indistinguishable from {@Code "//"}. +@PP +Unfortunately, if @Code y consists of two rows separated by {@Code "/"}, +as in the example above, both rows must be placed inside the +{@Code "@OneCol"}, and the table cannot be entered in the simple +row-by-row manner that non-expert users naturally expect. Another +advantage of @Code "//" is that its left parameter can be printed +before its right parameter is known; this is important when the left +parameter is an entire page. +@PP +The fifth and final concatenation operator, {@Code "&"}, is an explicit +version of the horizontal concatenation operator interpolated when +objects are separated by white space. It is formally identical to +@Code "|" except for taking higher precedence and being subject to +replacement by @Code "//1vx" during paragraph breaking +(Section {@NumberOf style}). +@End @SubSection |