-- NodeStyleExtraImpl.mesa
-- Written by Bill Paxton, January 1981
-- Last changed by Bill Paxton, 3-Jun-81 13:43:44
DIRECTORY
NodeStyleExtra,
NodeStyle,
TextNode,
TextLooks,
TiogaJaM,
Inline,
JaMFnsDefs,
JaMOtherDefs;
NodeStyleExtraImpl: PROGRAM
IMPORTS TiogaJaM, JaMFnsDefs, JaMOtherDefs,
NodeStyle, NodeStyleExtra, Inline
EXPORTS NodeStyle, NodeStyleExtra =
BEGIN
OPEN NodeStyle, NodeStyleExtra, JaMFnsDefs,
tjI:TiogaJaM,
nodeI:TextNode,
looksI:TextLooks,
jamI:JaMOtherDefs;
-- Style Name
styleName: nodeI.StyleName ← nodeI.nullStyleName; -- the current style name
CurrentStyle: PUBLIC PROC RETURNS [nodeI.StyleName] =
{ RETURN [styleName] };
SetStyle: PUBLIC PROC [name: nodeI.StyleName] = {
IF name = styleName THEN RETURN;
IF styleName # nodeI.nullStyleName THEN ExecuteCommand[end];
PushObject[GetStyleDict[name]];
ExecuteCommand[begin];
styleName ← name;
};
-- Load style procedures
LoadStyle: PUBLIC PROC [name: nodeI.StyleName] = { [] ← GetStyleDict[name] };
GetStyleDict: PROC [name: nodeI.StyleName] RETURNS [d: Object] = {
found: BOOLEAN;
[d, found] ← CheckStyleDict[name];
IF found THEN RETURN;
d ← CreateStyleDict[name];
RunStyle[d, name, ".tes", TRUE];
EnterStyleDict[name, d];
};
ReloadStyle: PUBLIC PROC [name: nodeI.StyleName] = {
d: Object;
found: BOOLEAN;
[d, found] ← CheckStyleDict[name];
IF found THEN {
PushObject[d]; ExecuteCommand[clrdict];
PushObject[d]; ExecuteCommand[detachall] }
ELSE d ← CreateStyleDict[name];
RunStyle[d, name, ".tes", TRUE];
IF ~found THEN EnterStyleDict[name, d];
ClearLooksCache[]; ClearRuleCache[]};
CreateStyleDict: PROC [name: nodeI.StyleName] RETURNS [d: Object] = {
-- creates dict for style and enters it in stylesDict
PushInteger[20];
ExecuteCommand[dict];
d ← PopObject[]};
EnterStyleDict: PROC [name: nodeI.StyleName, d: Object] = {
PushObject[stylesDict];
PushName[tjI.StyleToJaM[name]];
PushObject[d];
ExecuteCommand[put];
};
CheckStyleDict: PROC [name: nodeI.StyleName]
RETURNS [d: Object, found: BOOLEAN] = {
PushObject[stylesDict];
PushName[tjI.StyleToJaM[name]];
ExecuteCommand[known];
IF (found ← PopBoolean[]) THEN {
PushObject[stylesDict]; PushName[tjI.StyleToJaM[name]];
ExecuteCommand[get]; d ← PopObject[] };
};
RunStyle: PROC
[d: Object, name: nodeI.StyleName, ext: REF TEXT, go: BOOLEAN] = {
txt: REF TEXT ← NEW[TEXT[64]];
txtlen: NAT;
jamI.TextForName[LOOPHOLE[txt], LOOPHOLE[name] !
jamI.TextOverflow =>
RESUME[LOOPHOLE[txt ← NEW[TEXT[txt.maxLength*2]]]]];
txtlen ← txt.length;
FOR i:NAT IN [0..ext.length) DO txt[txtlen+i] ← ext[i]; ENDLOOP;
txt.length ← txtlen+ext.length;
PushCommand[end];
PushCommand[run];
PushName[MakeName[txt]];
PushCommand[begin];
PushObject[d];
IF go THEN jamI.Go[];
};
Apply: PUBLIC PROC
[ref: Ref, name, alt: nodeI.TypeName ← nodeI.nullTypeName] = {
initloc, loc: NAT;
input: Body;
IF name = nodeI.nullTypeName THEN RETURN;
loc ← initloc ←
Inline.BITXOR[LOOPHOLE[name,CARDINAL],Hash[ref]] MOD ruleCacheSize;
DO -- search cache
SELECT ruleCacheNames[loc] FROM
name => IF ruleCacheInputs[loc] = ref↑ THEN
{ ref↑ ← ruleCacheResults[loc]; RETURN };
nodeI.nullTypeName => EXIT; -- this is an unused entry
ENDCASE;
SELECT (loc ← loc+1) FROM
ruleCacheSize => IF (loc ← 0)=initloc THEN EXIT;
initloc => EXIT;
ENDCASE;
ENDLOOP;
IF ruleCacheCount = ruleCacheMax THEN {
loc ← initloc; ClearRuleCache[] };
SetStyle[ref.styleName]; -- make style current
style ← ref; -- make it current
input ← ref↑;
IF ExecuteName[tjI.TypeToJaM[name]] THEN { -- save results in cache
ruleCacheCount ← ruleCacheCount+1;
ruleCacheInputs[loc] ← input;
ruleCacheResults[loc] ← ref↑;
ruleCacheNames[loc] ← name }
ELSE IF alt # nodeI.nullTypeName THEN [] ← ExecuteName[tjI.TypeToJaM[alt]];
};
ruleCacheSize: NAT = 128; -- should be a power of 2
ruleCacheMax: NAT = (ruleCacheSize*2)/3; -- don't fill too full
ruleCacheCount: NAT; -- number of entries currently in use
RuleCacheNames: TYPE = ARRAY [0..ruleCacheSize) OF nodeI.TypeName;
ruleCacheNames: REF RuleCacheNames ← NEW[RuleCacheNames];
RuleCacheBodies: TYPE = ARRAY [0..ruleCacheSize) OF Body;
ruleCacheInputs: REF RuleCacheBodies ← NEW[RuleCacheBodies];
ruleCacheResults: REF RuleCacheBodies ← NEW[RuleCacheBodies];
ClearRuleCache: PROC = {
ruleCacheCount ← 0;
FOR i: NAT IN [0..ruleCacheSize) DO
ruleCacheNames[i] ← nodeI.nullTypeName; ENDLOOP;
};
Hash: PROC [ref: Ref] RETURNS [CARDINAL] = INLINE { RETURN [
LOOPHOLE[
Inline.BITXOR[LOOPHOLE[ref.styleName,CARDINAL],
Inline.BITXOR[LOOPHOLE[ref.fontFamily,CARDINAL],
Inline.BITXOR[Inline.LowHalf[ref.fontSize],
Inline.BITXOR[Inline.LowHalf[ref.leftIndent],
Inline.LowHalf[ref.leading]]]]],CARDINAL]] };
ApplyLooks: PUBLIC PROC [ref: Ref, looks: looksI.Looks] = {
initloc, loc: NAT;
IF looks = looksI.noLooks THEN RETURN;
loc ← initloc ←
Inline.BITXOR[LOOPHOLE[looks, looksI.LooksBytes].byte0,
Inline.BITXOR[LOOPHOLE[looks, looksI.LooksBytes].byte1,
Inline.BITXOR[LOOPHOLE[looks, looksI.LooksBytes].byte2,
Hash[ref]]]] MOD looksCacheSize;
DO -- search cache
SELECT looksCacheLooks[loc] FROM
looks => IF looksCacheInputs[loc] = ref↑ THEN
{ ref↑ ← looksCacheResults[loc]; RETURN };
looksI.noLooks => EXIT; -- this is an unused entry
ENDCASE;
SELECT (loc ← loc+1) FROM
looksCacheSize => IF (loc ← 0)=initloc THEN EXIT;
initloc => EXIT;
ENDCASE;
ENDLOOP;
IF looksCacheCount = looksCacheMax THEN {
loc ← initloc; ClearLooksCache[] };
SetStyle[ref.styleName]; -- make style current
style ← ref; -- make it current
looksCacheLooks[loc] ← looks;
looksCacheInputs[loc] ← ref↑;
FOR c: CHARACTER IN looksI.Look DO
IF looks[c] THEN [] ← ExecuteName[lookNames[c]]
ENDLOOP;
looksCacheResults[loc] ← ref↑;
looksCacheCount ← looksCacheCount+1;
};
looksCacheSize: NAT = 128; -- should be a power of 2
looksCacheMax: NAT = (looksCacheSize*2)/3; -- don't fill too full
looksCacheCount: NAT; -- number of entries currently in use
LooksCacheLooks: TYPE = ARRAY [0..looksCacheSize) OF looksI.Looks;
looksCacheLooks: REF LooksCacheLooks ← NEW[LooksCacheLooks];
LooksCacheBodies: TYPE = ARRAY [0..looksCacheSize) OF Body;
looksCacheInputs: REF LooksCacheBodies ← NEW[LooksCacheBodies];
looksCacheResults: REF LooksCacheBodies ← NEW[LooksCacheBodies];
ClearLooksCache: PROC = {
looksCacheCount ← 0;
FOR i: NAT IN [0..looksCacheSize) DO
looksCacheLooks[i] ← looksI.noLooks; ENDLOOP;
};
-- Registered commands
StyleDefOp: PROC = { -- does bindingDict .abind .cvx .def
PushObject[bindingDict];
ExecuteCommand[abind];
ExecuteCommand[cvx];
ExecuteCommand[def];
};
SubStyleOp: PROC = { -- expects opstk to contain style name
found: BOOLEAN;
name: nodeI.StyleName ← tjI.JaMToStyle[PopName[]];
d: Object;
[d, found] ← CheckStyleDict[name];
IF ~found THEN d ← CreateStyleDict[name];
PushObject[d]; ExecuteCommand[attachdict];
IF ~found THEN {
PushName[tjI.StyleToJaM[name]]; PushObject[d];
PushCommand[finishSubStyle];
RunStyle[d, name, ".tes", FALSE] };
};
FinishSubStyle: PROC = { -- .run finished successfully
d: Object ← PopObject[];
EnterStyleDict[tjI.JaMToStyle[PopName[]], d] };
BadFileName: PROC = { -- ???? what should we do ????
-- this comes from giving .run a file name it cannot open
ERROR StyleError };
-- Dimensions
Points: PROC = { }; -- no change needed to convert to points
PointsPerPica: REAL = 12.0;
Picas: PROC = { PushReal[PopReal[]*PointsPerPica] };
PointsPerInch: REAL = 1.0/0.0138370; -- 72.27
Inches: PROC = { PushReal[PopReal[]*PointsPerInch] };
PointsPerCentimeter: REAL = PointsPerInch/2.540;
Centimeters: PROC = { PushReal[PopReal[]*PointsPerCentimeter] };
PointsPerMillimeter: REAL = PointsPerCentimeter/10;
Millimeters: PROC = { PushReal[PopReal[]*PointsPerMillimeter] };
PointsPerDidot: REAL = PointsPerCentimeter/26.60;
DidotPoints: PROC = { PushReal[PopReal[]*PointsPerDidot] };
Ems: PROC = { PushReal[PopReal[]*style.fontSize] };
-- should really be width of "M" in current font
-- use font size as an approximation for now
-- Initialization
lookNames: ARRAY looksI.Look OF tjI.JaMName;
stylesDictName, bindingDictName: tjI.JaMName;
stylesDict, bindingDict: Object;
StyleCommand: PUBLIC PROC [text: REF TEXT, proc: PROC] = {
name: tjI.JaMName ← MakeName[text];
jamI.RegisterCommand[LOOPHOLE[text], proc];
-- add it to the binding dictionary
PushObject[bindingDict];
PushName[name];
PushName[name];
ExecuteCommand[load];
ExecuteCommand[cvx];
ExecuteCommand[put]};
StyleLiteral: PUBLIC PROC [text: REF TEXT] RETURNS [name: tjI.JaMName] = {
name ← MakeName[text];
-- add it to the binding dictionary
PushObject[bindingDict];
PushName[name];
PushName[name];
ExecuteCommand[cvlit];
ExecuteCommand[put];
-- add it to the current dictionary
PushName[name];
PushName[name];
ExecuteCommand[cvlit];
ExecuteCommand[def]};
InitStylesDict: PROC = {
stylesDictName ← MakeName["TiogaEditorStylesDictionary"];
PushName[stylesDictName];
ExecuteCommand[where];
IF PopBoolean[] THEN {
PushName[stylesDictName]; ExecuteCommand[get];
stylesDict ← PopObject[] }
ELSE {
PushInteger[20]; ExecuteCommand[dict];
stylesDict ← PopObject[];
PushName[stylesDictName]; PushObject[stylesDict];
ExecuteCommand[def] }};
InitBindingDict: PROC = {
bindingDictName ← MakeName["TiogaEditorBindingDictionary"];
PushName[bindingDictName];
ExecuteCommand[where];
IF PopBoolean[] THEN {
PushName[bindingDictName]; ExecuteCommand[get];
bindingDict ← PopObject[];
PushObject[bindingDict]; ExecuteCommand[clrdict] }
ELSE {
PushInteger[100]; ExecuteCommand[dict];
bindingDict ← PopObject[];
PushName[bindingDictName]; PushObject[bindingDict];
ExecuteCommand[def];
PushObject[bindingDict] }};
InitLookNames: PROC = {
-- names are "aLook", "bLook", "cLook", etc.
txt: REF TEXT ← NEW[TEXT[5]];
txt[1] ← 'L; txt[2] ← txt[3] ← 'o; txt[4] ← 'k; txt.length ← 5;
FOR c: CHARACTER IN looksI.Look DO
txt[0] ← c; lookNames[c] ← MakeName[txt]; ENDLOOP};
cvlit, cvx, def, put, get, dict, attachdict, detachall, abind,
begin, end, run, load, clrdict, where, known, assign, finishSubStyle:
PUBLIC Command;
GetCommand: PUBLIC PROC [name: tjI.JaMName] RETURNS [c: Command] = {
flag: BOOLEAN;
[c, flag] ← jamI.TryToGetCommand[LOOPHOLE[name]];
IF ~flag THEN ERROR };
StartExtra: PUBLIC PROCEDURE =
BEGIN
cvlit ← GetCommand[MakeName[".cvlit"]];
cvx ← GetCommand[MakeName[".cvx"]];
def ← GetCommand[MakeName[".def"]];
put ← GetCommand[MakeName[".put"]];
get ← GetCommand[MakeName[".get"]];
dict ← GetCommand[MakeName[".dict"]];
attachdict ← GetCommand[MakeName[".attachdict"]];
detachall ← GetCommand[MakeName[".detachall"]];
abind ← GetCommand[MakeName[".abind"]];
where ← GetCommand[MakeName[".where"]];
begin ← GetCommand[MakeName[".begin"]];
end ← GetCommand[MakeName[".end"]];
run ← GetCommand[MakeName[".run"]];
load ← GetCommand[MakeName[".load"]];
clrdict ← GetCommand[MakeName[".clrdict"]];
known ← GetCommand[MakeName[".known"]];
assign ← GetCommand[MakeName[".assign"]];
InitStylesDict[]; InitBindingDict[]; InitLookNames[];
JaMFnsDefs.Register[LOOPHOLE["FinishSubStyle"],FinishSubStyle];
finishSubStyle ← GetCommand[MakeName["FinishSubStyle"]];
StyleCommand[".badfilename",BadFileName];
StyleCommand["StyleDef",StyleDefOp];
StyleCommand["SubStyle",SubStyleOp];
StyleCommand["pt",Points];
StyleCommand["pc",Picas];
StyleCommand["in",Inches];
StyleCommand["cm",Centimeters];
StyleCommand["mm",Millimeters];
StyleCommand["dd",DidotPoints];
StyleCommand["em",Ems];
ClearLooksCache[]; ClearRuleCache[];
END;
END.