RulesTabCount:
PUBLIC
PROC [stop: RulesTabStop]
RETURNS [count:
INTEGER] = {
RETURN [stop.array.length/2] };
RulesTabInfo:
PUBLIC
PROC [stop: RulesTabStop, num:
INTEGER]
RETURNS [weight, vshift: REAL] = TRUSTED {
For num in [0..RulesTabCount), returns the weight and vshift values for that rule.
ObjectToReal:
PROC [ob: JaMBasic.Object]
RETURNS [Real] =
TRUSTED {
WITH ob:ob
SELECT
FROM
integer => RETURN[ob.ivalue];
real => RETURN[ob.rvalue];
ENDCASE => ERROR };
weight ← ObjectToReal[JaMOps.AGet[stop.array, num*2]];
vshift ← ObjectToReal[JaMOps.AGet[stop.array, num*2+1]] };
RulesTabInfoI:
PUBLIC
PROC [stop: RulesTabStop, num:
INTEGER]
RETURNS [weight, vshift: INTEGER] = TRUSTED {
ObjectToInteger:
PROC [ob: JaMBasic.Object]
RETURNS [
INTEGER] =
TRUSTED {
WITH ob:ob
SELECT
FROM
integer => RETURN[ob.ivalue];
real => RETURN[R.RoundI[ob.rvalue]];
ENDCASE => ERROR };
weight ← ObjectToInteger[JaMOps.AGet[stop.array, num*2]];
vshift ← ObjectToInteger[JaMOps.AGet[stop.array, num*2+1]] };
Real table overflow for tab reals
GetTabRealCode:
PROC [ref: Ref, stop: TabStop, which: TabRealParam, value: Real]
RETURNS [code: RealCode] = {
code ← EnterReal[value ! realTableOverflow => {
code ← overflow;
ref.dataList ← qZone.
NEW[DataEntry ← [
ref.dataList, tab[stop, which, value, IntegerValue[value]]]];
CONTINUE }] };
GetTabOverflow:
PUBLIC
PROC [ref: Ref, stop: TabStop, which: TabRealParam]
RETURNS [value: Real] = {
FOR x: DataList ← ref.dataList, x.next
UNTIL x=
NIL
DO
xx: REF DataEntry.tab = NARROW[x];
IF xx.tabStop=stop AND xx.which=which THEN RETURN [xx.value];
ENDLOOP;
ERROR -- failed to find it on the data list -- };
GetTabIntOverflow:
PUBLIC
PROC [ref: Ref, stop: TabStop, which: TabRealParam]
RETURNS [value: INTEGER] = {
FOR x: DataList ← ref.dataList, x.next
UNTIL x=
NIL
DO
xx: REF DataEntry.tab = NARROW[x];
IF xx.tabStop=stop AND xx.which=which THEN RETURN [xx.valueI];
ENDLOOP;
ERROR -- failed to find it on the data list -- };
Miscellaneous commands
RelativeTabStopsOp:
PUBLIC
PROC [frame: Frame] = {
ref: Ref ← StyleForFrame[frame];
name: Name;
ok: BOOLEAN;
[name, ok] ← TryToPopName[frame];
IF ~ok
THEN {
-- restore name to stack and return default
PushText[frame,"illegal value for tabStops: should be fixed or relative"];
StyleError[frame,1] };
SELECT name
FROM
fixed => ref.fixedTabs ← TRUE;
relative => ref.fixedTabs ← FALSE;
ENDCASE => {
-- restore name to stack and return default
PushName[frame, name];
PushText[frame,"illegal value for tabStops: should be fixed or relative"];
StyleError[frame,2] }};
DefaultTabStopsOp:
PUBLIC
PROC [frame: Frame] = {
ref: Ref ← StyleForFrame[frame];
tabStop: TabStop ← TabSpec[ref, frame];
tabStop.loc ← GetTabRealCode[ref, tabStop, loc, PopReal[frame]];
ref.defaultTabStops ← tabStop };
Parsing tab specs
TabStopOp:
PUBLIC
PROC [frame: Frame] = {
ref: Ref ← StyleForFrame[frame];
tabStop: TabStop ← TabSpec[ref, frame];
loc: Real;
tabStop.loc ← GetTabRealCode[ref, tabStop, loc, PopReal[frame]];
Insert in list of tab stops. kept sorted by decreasing location, i.e., from right to left on page
this may result in a slight decrease in efficiency for the formatters, but it substantially reduces allocations during the creation of the list since styles tend to define tab stops in increasing order, so can add to start of list and list additions must be non-destructive of the previous list
loc ← GetTabLoc[tabStop, ref];
ref.numTabStops ← ref.numTabStops+1;
IF ref.tabStops =
NIL
OR GetTabLoc[ref.tabStops.first, ref] <= loc
THEN
ref.tabStops ← TextNode.pZone.CONS[tabStop, ref.tabStops]
ELSE {
-- copy list up to first with smaller loc
old: LIST OF TabStop ← ref.tabStops;
new: LIST OF TabStop ← TextNode.pZone.CONS[old.first, NIL];
ref.tabStops ← new;
FOR lst:
LIST
OF TabStop ← old.rest, lst.rest
DO
IF lst=
NIL
OR GetTabLoc[lst.first, ref] <= loc
THEN {
-- insert here
new.rest ← TextNode.pZone.CONS[tabStop, lst]; EXIT };
new.rest ← TextNode.pZone.CONS[lst.first, NIL];
new ← new.rest;
ENDLOOP }};
TabSpec:
PROC [ref: Ref, frame: Frame]
RETURNS [tabStop: TabStop] = {
-- parse tab specs
looks: TextLooks.Looks ← TabLooksSpec[frame];
breakIfPast: BOOL ← TabPastSpec[frame];
tabStop ← TabPattern[ref, frame];
tabStop.looks ← looks;
tabStop.breakIfPast ← breakIfPast;
TabAlign[tabStop, frame] };
TabLooksSpec:
PROC [frame: Frame]
RETURNS [lks: TextLooks.Looks] =
TRUSTED {
name: Name;
ok: BOOLEAN;
SetLookBit:
PROC [look:
CHAR]
RETURNS [quit:
BOOL] =
TRUSTED {
look ← Rope.Lower[look];
IF look IN ['a..'z] THEN lks[look] ← TRUE;
RETURN [FALSE] };
lks ← TextLooks.noLooks;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN RETURN;
IF name # looks THEN { PushName[frame, name]; RETURN };
JaMOps.StringForAll[JaMOps.PopString[frame.opstk], SetLookBit];
};
TabPastSpec:
PROC [frame: Frame]
RETURNS [break:
BOOL] = {
name: Name;
ok: BOOLEAN;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN RETURN;
SELECT name
FROM
breakIfPast => break ← TRUE;
spaceIfPast => break ← FALSE;
ENDCASE => {
-- restore name to stack and return default
PushName[frame, name];
break ← FALSE }};
TabPattern:
PROC [ref: Ref, frame: Frame]
RETURNS [tabStop: TabStop] = {
name: Name;
ok: BOOLEAN;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN { tabStop ← TextNode.pZone.NEW[blank TabStopRec]; RETURN };
SELECT name FROM
blank => tabStop ← TextNode.pZone.NEW[blank TabStopRec];
leaders => {
leaderChar: BOOL ← FALSE;
string: string JaMBasic.Object;
value: Real;
SetLeaderChar:
PROC [c:
CHAR]
RETURNS [quit:
BOOL] = {
IF leaderChar
THEN {
PushText[frame,"Cannot specify more than one character for tab leaders"];
StyleError[frame,1] };
leaderChar ← TRUE;
ldrStop.char ← c };
ldrStop: LeaderTabStop ← TextNode.pZone.NEW[leaders TabStopRec];
tabStop ← ldrStop;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN ldrStop.congruent ← TRUE
ELSE
SELECT name
FROM
centered => ldrStop.congruent ← FALSE;
congruent => ldrStop.congruent ← TRUE;
ENDCASE => {
PushName[frame,name];
PushText[frame,"is not legal as value for tab leaders: congruent or centered"];
StyleError[frame,2] };
[value, ok] ← TryToPopReal[frame];
ldrStop.spacing ← GetTabRealCode[ref, tabStop, spacing, IF ok THEN value ELSE 0.0];
[string, ok] ← TryToPopString[frame];
IF ok THEN TRUSTED {JaMOps.StringForAll[string, SetLeaderChar]}
ELSE {
PushText[frame,"Must specify character for leaders"];
StyleError[frame,1] }};
rule => {
ruleStop: RuleTabStop ← TextNode.pZone.NEW[rule TabStopRec];
tabStop ← ruleStop;
ruleStop.vshift ← GetTabRealCode[ref, tabStop, vshift, PopReal[frame]];
ruleStop.weight ← GetTabRealCode[ref, tabStop, weight, PopReal[frame]] };
rules => {
rulesStop: RulesTabStop ← TextNode.pZone.NEW[rules TabStopRec];
tabStop ← rulesStop;
TRUSTED {rulesStop.array ← JaMOps.PopArray[frame.opstk] }};
ENDCASE => {
-- restore name to stack and return default
PushName[frame, name];
tabStop ← TextNode.pZone.NEW[blank TabStopRec] }};
MissingChar:
PROC [frame: Frame] = {
PushText[frame,"Cannot specify more than one character for tab alignment"];
StyleError[frame,1] };
TabAlign:
PROC [tabStop: TabStop, frame: Frame] = {
name: Name;
ok: BOOLEAN;
[name, ok] ← TryToPopName[frame];
IF ~ok THEN { tabStop.alignment ← FlushLeft; RETURN };
SELECT name FROM
flushLeft => tabStop.alignment ← FlushLeft;
flushRight => tabStop.alignment ← FlushRight;
centered => tabStop.alignment ← Centered;
aligned => {
alignmentChar: BOOL ← FALSE;
string: string JaMBasic.Object;
SetAlignmentChar:
PROC [c:
CHAR]
RETURNS [quit:
BOOL] = {
IF alignmentChar
THEN {
PushText[frame,"Cannot specify more than one character for tab alignment"];
StyleError[frame,1] };
alignmentChar ← TRUE;
tabStop.alignmentChar ← c };
tabStop.alignment ← Character;
[string, ok] ← TryToPopString[frame];
IF ok THEN TRUSTED {JaMOps.StringForAll[string, SetAlignmentChar]}
ELSE {
PushText[frame,"Must specify character for tab alignment"];
StyleError[frame,1] }};
ENDCASE => {
PushName[frame, name];
tabStop.alignment ← FlushLeft }};