DIRECTORY
Atom USING [GetPName],
CreateNode USING [SpanInfo],
FileWriter USING [blockSize, BumpWriter, Ref, WriteChar, WriteRope],
NameSymbolTable USING [RopeFromName],
NodeProps USING [GetProp, MapProps, GetSpecs],
OutputStructure,
Rope USING [ROPE],
RopeEdit USING [Size],
RopeReader USING [FreeRopeReader, GetRopeReader, GetString, Ref, SetPosition],
RunReader USING [FreeRunReader, GetRunReader, MergedGet, Ref, SetPosition],
T2FileOps,
TiogaLooks USING [Look, Looks, noLooks, Runs],
TiogaLooksOps USING [CountRuns],
TiogaBasicClass USING [BasicClass],
TiogaBranchClass USING [BranchClass, branchChildrenAtom, branchContentsAtom, defaultBranchClass],
TiogaItemClass USING [ItemClass],
TiogaNode USING [Name, nullName, Offset, Ref, RefBasicNode, RefBoxNode, RefBranchNode, RefItemNode, RefListNode, RefTextNode],
TiogaNodeOps USING [FetchBasicClass, FetchItemClass, IsBranch];
Output:
PUBLIC
PROC [
ctrl, data: FileWriter.Ref, node: TiogaNode.Ref,
contents: TiogaNode.Ref ← NIL, children: TiogaNode.RefBranchNode ← NIL]
RETURNS [flags: CHAR] = {
NoOfRuns:
PROCEDURE [runs: TiogaLooks.Runs, size:
INT]
RETURNS [n:
INT] =
INLINE {
IF runs=NIL THEN RETURN [0];
[n, ,] ← TiogaLooksOps.CountRuns[runs, 0, size] };
Output32:
PROC [len: TiogaNode.Offset, forwards:
BOOLEAN] = {
first, second, fourth: T2FileOps.LengthByte;
third: T2FileOps.ThirdByte;
lenBytes: T2FileOps.IntBytes ← LOOPHOLE[len];
IF lenBytes.fourth # 0
THEN {
fourth.data ← lenBytes.fourth;
first.others ← second.others ← third.others ← TRUE };
IF lenBytes.thirdTop # 0
OR lenBytes.thirdBottom # 0
THEN {
third.dataTop ← lenBytes.thirdTop;
third.dataBottom ← lenBytes.thirdBottom;
first.others ← second.others ← TRUE };
IF lenBytes.second # 0
THEN {
second.data ← lenBytes.second; first.others ← TRUE };
first.data ← lenBytes.first;
The bytes are in the right place now write them out in the appropriate order
IF forwards
THEN {
WriteChar[LOOPHOLE[first], ctrl];
IF first.others
THEN {
WriteChar[LOOPHOLE[second], ctrl];
IF second.others
THEN {
WriteChar[LOOPHOLE[third], ctrl];
IF third.others THEN WriteChar[LOOPHOLE[fourth], ctrl] }}}
ELSE {
IF first.others
THEN {
IF second.others
THEN {
IF third.others THEN WriteChar[LOOPHOLE[fourth], ctrl];
WriteChar[LOOPHOLE[third], ctrl] };
WriteChar[LOOPHOLE[second], ctrl] };
WriteChar[LOOPHOLE[first], ctrl] }};
OutputAtom: PROC [atom: ATOM] = INLINE { OutputControlRope[Atom.GetPName[atom]] };
OutputB32: PROCEDURE [len: TiogaNode.Offset] = INLINE { Output32[len, FALSE] };
OutputTemplateInfo:
PROCEDURE [node: TiogaNode.Ref] =
INLINE {
SELECT node.templateInfo
FROM
normal => NULL;
application => FileWriter.WriteChar[T2FileOps.APPLICATION, ctrl];
formal => FileWriter.WriteChar[T2FileOps.FORMAL, ctrl];
ENDCASE => ERROR };
wholeTreeLevel: NAT = 3;
PushBranchData:
PROC [ctrlLen, dataLen:
INT] = {
top: NAT;
IF (top ← branchIOStack.top)=branchIOStack.length
THEN {
-- make it bigger
new: REF BranchIOStack ← NEW[BranchIOStack[top*2]];
FOR i: NAT ← 0, i+1 UNTIL i=top DO new[i] ← branchIOStack[i]; ENDLOOP;
FreeBranchIOStack[branchIOStack];
branchIOStack ← new };
branchIOStack[top].ctrlLen ← ctrlLen;
branchIOStack[top].dataLen ← dataLen;
branchIOStack.top ← top+1 };
OutputBranch:
PROCEDURE [
branch: TiogaNode.RefBranchNode, level: NAT, pushData: BOOL,
contents: TiogaNode.Ref ← NIL, children: TiogaNode.RefBranchNode ← NIL] = {
IF branch.deleted THEN ERROR;
IF branch.externalRepValid
THEN {
brInfo: CreateNode.SpanInfo ← NARROW[NodeProps.GetProp[branch, $BranchInfo]];
FileWriter.WriteRope[
brInfo.externalRepRope, brInfo.charsLen, data, externRopeReader, brInfo.charsStart];
FileWriter.WriteRope[
brInfo.externalRepRope, brInfo.ctrlLen, ctrl, externRopeReader, brInfo.ctrlStart];
IF pushData THEN PushBranchData[brInfo.ctrlLen, brInfo.charsLen] }
ELSE {
WriterPos:
PROC [writer: FileWriter.Ref]
RETURNS [len:
INT] =
INLINE {
RETURN [writer.blockCount*LONG[FileWriter.blockSize]+writer.block.length] };
doClass, doFormat: BOOL ← FALSE;
op: T2FileOps.Op ← T2FileOps.branch;
start: NAT;
specs: Rope.ROPE;
classInfo: TiogaBranchClass.BranchClass;
startCtrlLoc, startDataLoc: INT;
IF branch.hasbranchclass
THEN
classInfo ← NARROW[NodeProps.GetProp[branch, $BranchClass]];
IF classInfo=NIL THEN classInfo ← TiogaBranchClass.defaultBranchClass;
IF pushData
THEN {
start ← branchIOStack.top; startCtrlLoc ← WriterPos[ctrl]; startDataLoc ← WriterPos[data] };
IF classInfo.flavor # $Branch THEN { op ← op + T2FileOps.classBit; doClass ← TRUE };
IF branch.format#TiogaNode.nullName THEN { op ← op + T2FileOps.formatBit; doFormat ← TRUE };
IF branch.comment THEN op ← op + T2FileOps.commentBit;
WriteChar[op, ctrl];
IF doClass THEN OutputAtom[classInfo.flavor];
IF doFormat THEN OutputControlRope[NameSymbolTable.RopeFromName[branch.format]];
OutputTemplateInfo[branch];
IF branch.hasPropList THEN OutputProps[branch];
IF contents=NIL THEN contents ← branch.contents;
IF (contents=
NIL
AND branch.hasbranchclass
AND
(specs ← NARROW[NodeProps.GetProp[branch, TiogaBranchClass.branchContentsAtom]])#NIL)
OR (classInfo.getContents#
NIL
AND (specs ← classInfo.getContents[branch])#
NIL)
THEN {
WriteChar[T2FileOps.BRANCHCONTENTSPECS, ctrl]; OutputControlRope[specs] }
ELSE IF contents # NIL THEN OutputContentsList[contents];
IF children=NIL THEN children ← branch.child;
IF (children=
NIL
AND branch.hasbranchclass
AND
(specs ← NARROW[NodeProps.GetProp[branch, TiogaBranchClass.branchChildrenAtom]])#NIL)
OR (classInfo.getChildren#
NIL
AND (specs ← classInfo.getChildren[branch])#
NIL)
THEN {
WriteChar[T2FileOps.CHILDSPECS, ctrl]; OutputControlRope[specs] }
ELSE IF children=NIL THEN WriteChar[T2FileOps.NOCHILD, ctrl]
ELSE {
-- output the children branches
count: NAT ← 0; -- number of children
childLevel: NAT ← level+1;
childrenPush: BOOL ← childLevel < wholeTreeLevel;
IF ~childrenPush THEN WriteChar[T2FileOps.STARTC, ctrl]
ELSE FileWriter.WriteChar[T2FileOps.ENDITEMS, ctrl];
FOR b: TiogaNode.RefBranchNode ← children,
NARROW[b.next]
DO
OutputBranch[b, childLevel, childrenPush];
count ← count+1;
IF b.last THEN EXIT;
ENDLOOP;
WriteChar[T2FileOps.ENDC, ctrl];
IF childrenPush
THEN {
-- write lengths and number of children
IF count # branchIOStack.top-start THEN ERROR; -- children should have pushed info
UNTIL branchIOStack.top=start
DO
-- pop and write ctrlLen and dataLen
item: NAT ← branchIOStack.top-1;
OutputB32[branchIOStack[item].ctrlLen];
OutputB32[branchIOStack[item].dataLen];
branchIOStack.top ← item;
ENDLOOP;
OutputB32[count] }};
IF pushData THEN PushBranchData[WriterPos[ctrl]-startCtrlLoc, WriterPos[data]-startDataLoc] }};
OutputControlRope:
PROC [r: Rope.
ROPE] =
INLINE {
len: INT ← RopeEdit.Size[r];
OutputF32[len];
FileWriter.WriteRope[r, len, ctrl, externRopeReader];
};
OutputCountRopeCR:
PROC [r: Rope.
ROPE, writer: FileWriter.Ref] =
INLINE {
Output a rope onto a given stream, preceeded its length and followed by a CR
OutputF32[RopeEdit.Size[r]];
OutputRope[r, writer];
};
OutputF32:
PROCEDURE [len: TiogaNode.Offset] =
INLINE {
FORWARD32 : : = 1..4 RECORD [more: BOOL, data: [0..127]]
Output32[len, TRUE];
};
OutputContentsList:
PROCEDURE [ref: TiogaNode.Ref] = {
IF ref=NIL THEN RETURN;
DO
WITH ref
SELECT
FROM
t: TiogaNode.RefTextNode => OutputTI[t];
br: TiogaNode.RefBranchNode => OutputBranch[br, wholeTreeLevel, FALSE];
ENDCASE => OutputOther[ref];
IF ref.last THEN RETURN;
ref ← ref.next;
ENDLOOP };
OutputProperty:
PROC [name:
ATOM, value:
REF]
RETURNS [
BOOL] = {
specs: Rope.ROPE ← NodeProps.GetSpecs[name, value, node]; -- node argument set by caller
IF specs=NIL AND (specs ← NarrowToRope[value])=NIL THEN RETURN [FALSE];
WriteChar[T2FileOps.PROPERTY, ctrl];
OutputAtom[name];
OutputControlRope[specs];
RETURN [FALSE] };
OutputRope:
PROC [r: Rope.
ROPE, writer: FileWriter.Ref] =
INLINE {
Output a rope to the given stream followed by a CR
FileWriter.WriteRope[r, RopeEdit.Size[r], writer, externRopeReader];
WriteChar[15C, writer] };
OutputRuns:
PROCEDURE [runs: TiogaLooks.Runs, noOfRuns: TiogaNode.Offset]
RETURNS [loc: TiogaNode.Offset ← 0] = {
cnt: TiogaNode.Offset ← 0;
RunReader.SetPosition[runReader, runs, 0];
OutputF32[noOfRuns];
WHILE (cnt𡤌nt+1) <= noOfRuns
DO
-- Process each run descriptor
looks: TiogaLooks.Looks;
len: TiogaNode.Offset;
[len, looks] ← RunReader.MergedGet[runReader];
IF looks=TiogaLooks.noLooks THEN WriteChar[T2FileOps.NOLOOKS, ctrl]
ELSE {
-- write op's to set the bits; one op per bit that is set
last: CHAR;
initial: BOOL ← TRUE;
FOR c:
CHAR
IN TiogaLooks.Look
DO
IF ~looks[c] THEN LOOP;
IF initial THEN { last ← c; initial ← FALSE } -- save the first one to write out last
ELSE WriteChar[T2FileOps.addLooksFirst+(c-FIRST[TiogaLooks.Look]), ctrl];
ENDLOOP;
WriteChar[T2FileOps.lastLooksFirst+(last-FIRST[TiogaLooks.Look]), ctrl] };
OutputF32[len];
loc ← loc+len;
ENDLOOP };
OutputTI:
PROCEDURE [t: TiogaNode.RefTextNode] = {
ropeSize: TiogaNode.Offset ← RopeEdit.Size[t.rope];
noOfRuns: TiogaNode.Offset ← NoOfRuns[t.runs, ropeSize];
op: T2FileOps.Op;
doClass, doFormat, doProps, doRuns: BOOL ← FALSE;
classInfo: TiogaItemClass.ItemClass ← TiogaNodeOps.FetchItemClass[t.class];
op ← T2FileOps.text;
IF t.hasPropList OR t.templateInfo # normal THEN { op ← op + T2FileOps.propsBit; doProps ← TRUE };
IF classInfo.flavor # $Text THEN { op ← op + T2FileOps.classBit; doClass ← TRUE };
IF t.format#TiogaNode.nullName THEN { op ← op + T2FileOps.formatBit; doFormat ← TRUE };
IF noOfRuns # 0 THEN { op ← op + T2FileOps.runsBit; doRuns ← TRUE };
IF t.comment THEN op ← op + T2FileOps.commentBit;
WriteChar[op, ctrl];
IF doClass THEN OutputAtom[classInfo.flavor];
IF doFormat THEN OutputControlRope[NameSymbolTable.RopeFromName[t.format]];
IF doRuns AND OutputRuns[t.runs, noOfRuns] # ropeSize THEN ERROR;
OutputCountRopeCR[t.rope, IF t.comment THEN ctrl ELSE data];
IF doProps THEN { OutputTemplateInfo[t]; OutputProps[t]; WriteChar[T2FileOps.ENDPROPS, ctrl] }};
NarrowToRope:
PROC [x:
REF]
RETURNS [Rope.
ROPE] = {
IF x=NIL THEN RETURN [NIL];
WITH x SELECT FROM r: Rope.ROPE => RETURN [r]; ENDCASE;
RETURN [NIL] };
OutputProps:
PROC [t: TiogaNode.Ref] =
INLINE {
IF t.hasPropList THEN { node ← t; [] ← NodeProps.MapProps[t, OutputProperty, FALSE, FALSE] }};
OutputOther:
PROCEDURE [t: TiogaNode.Ref, contents: TiogaNode.Ref ←
NIL] = {
doFormat, doClass: BOOL ← FALSE;
op: T2FileOps.Op;
flavor: ATOM;
classData, contentSpecs: Rope.ROPE;
WITH t
SELECT
FROM
bs: TiogaNode.RefBasicNode => {
classInfo: TiogaBasicClass.BasicClass ← TiogaNodeOps.FetchBasicClass[bs.class];
op ← T2FileOps.basic;
IF (flavor ← classInfo.flavor) # $Basic THEN { doClass ← TRUE; op ← op + T2FileOps.classBit };
IF bs.data#NIL AND classInfo.get#NIL THEN classData ← NARROW[classInfo.get[bs, $Save]]
ELSE classData ← NarrowToRope[bs.data] };
bx: TiogaNode.RefBoxNode => {
classInfo: TiogaItemClass.ItemClass ← TiogaNodeOps.FetchItemClass[bx.class];
op ← T2FileOps.box;
IF (flavor ← classInfo.flavor) # $Box THEN { doClass ← TRUE; op ← op + T2FileOps.classBit };
IF contents=NIL THEN contents ← bx.contents;
IF (contents=NIL AND bx.hasPropList AND
(contentSpecs ← NARROW[NodeProps.GetProp[bx, TiogaItemClass.itemContentsAtom]])#NIL)
THEN NULL
ELSE IF contents#NIL AND classInfo.getContents#NIL THEN
contentSpecs ← classInfo.getContents[bx];
IF bx.data#NIL AND classInfo.get#NIL THEN classData ← NARROW[classInfo.get[bx, $Save]]
ELSE classData ← NarrowToRope[bx.data] };
ls: TiogaNode.RefListNode => {
classInfo: TiogaItemClass.ItemClass ← TiogaNodeOps.FetchItemClass[ls.class];
op ← T2FileOps.list;
IF (flavor ← classInfo.flavor) # $List THEN { doClass ← TRUE; op ← op + T2FileOps.classBit };
IF contents=NIL THEN contents ← ls.contents;
IF (contents=NIL AND ls.hasPropList AND
(contentSpecs ← NARROW[NodeProps.GetProp[ls, TiogaItemClass.itemContentsAtom]])#NIL)
THEN NULL
ELSE IF contents#NIL AND classInfo.getContents#NIL THEN
contentSpecs ← classInfo.getContents[ls];
IF ls.data#NIL AND classInfo.get#NIL THEN classData ← NARROW[classInfo.get[ls, $Save]]
ELSE classData ← NarrowToRope[ls.data] };
ENDCASE => ERROR;
IF t.format#TiogaNode.nullName THEN { op ← op + T2FileOps.formatBit; doFormat ← TRUE };
IF t.comment
THEN op ← op + T2FileOps.commentBit;
WriteChar[op, ctrl];
IF doClass THEN OutputAtom[flavor];
IF doFormat THEN OutputControlRope[NameSymbolTable.RopeFromName[t.format]];
OutputTemplateInfo[t]; OutputProps[t];
IF contents=NIL THEN NULL
ELSE
IF contentSpecs#
NIL
THEN {
WriteChar[T2FileOps.ITEMCONTENTSPECS, ctrl]; OutputControlRope[contentSpecs] }
ELSE {
IF TiogaNodeOps.IsBranch[contents] THEN WriteChar[T2FileOps.STARTBR, ctrl];
OutputContentsList[contents] };
IF classData=NIL THEN WriteChar[T2FileOps.NODATA, ctrl]
ELSE { WriteChar[T2FileOps.CLASSDATA, ctrl]; OutputControlRope[classData] }};
WriteChar: PROC [c: CHAR, writer: FileWriter.Ref] = INLINE { FileWriter.WriteChar[c, writer] };
branchIOStack: REF BranchIOStack ← GetBranchIOStack[];
externRopeReader: RopeReader.Ref ← RopeReader.GetRopeReader[];
runReader: RunReader.Ref ← RunReader.GetRunReader[];
flags ← 0C;
WITH node
SELECT
FROM
t: TiogaNode.RefTextNode => OutputTI[t];
br: TiogaNode.RefBranchNode => {
flags ← flags + T2FileOps.isBranchFlagBit; OutputBranch[br, 0, FALSE, contents, children] };
ENDCASE => OutputOther[node, contents];
RunReader.FreeRunReader[runReader];
RopeReader.FreeRopeReader[externRopeReader];
FreeBranchIOStack[branchIOStack] };