-- TexNode.mesa

-- implementation of procedures in TexNodeDefs
-- last written by Doug Wyatt, December 18, 1979  6:37 PM

DIRECTORY
	TexDefs: FROM "TexDefs",
	TexErrorDefs: FROM "TexErrorDefs" USING[Confusion],
	TexGlueDefs: FROM "TexGlueDefs"
		USING[GluePtr,AddGlueLink,DelGlueLink,zeroGlueSet,FlexSumsPtr],
	TexMemDefs: FROM "TexMemDefs" USING[AllocMem,FreeMem],
	TexNodeDefs: FROM "TexNodeDefs",
	TexTokenDefs: FROM "TexTokenDefs" USING[TokenListPtr,DelRCLink],
	InlineDefs: FROM "InlineDefs" USING[COPY];

TexNode: PROGRAM
IMPORTS TexErrorDefs,TexGlueDefs,TexMemDefs,TexNodeDefs,TexTokenDefs,
	InlineDefs
EXPORTS TexNodeDefs =
BEGIN OPEN TexGlueDefs,TexDefs,TexNodeDefs;

-- eventually, most of these procedures should be made INLINE
-- and moved to TexNodeDefs

AllocHead: PROCEDURE RETURNS[NodeListPtr] = INLINE
	BEGIN RETURN[TexMemDefs.AllocMem[SIZE[listhead Node]]] END;
FreeHead: PROCEDURE[p: NodeListPtr] = INLINE
	BEGIN TexMemDefs.FreeMem[p,SIZE[listhead Node]] END;

InitNodeList: PUBLIC PROCEDURE RETURNS[NodeListPtr] =
	BEGIN
	list: NodeListPtr←AllocHead[];
	list↑←[link: NIL, body: listhead[last: list]]; RETURN[list];
	END;

MakeNodeList: PUBLIC PROCEDURE[p: NodePtr] RETURNS[NodeListPtr] =
	BEGIN
	list: NodeListPtr←AllocHead[];
	list↑←[link: p, body: listhead[last: NIL]]; RETURN[list];
	END;

FinishNodeList: PUBLIC PROCEDURE[list: NodeListPtr] RETURNS[NodePtr] =
	BEGIN
	p: NodePtr←list.link;
	FreeHead[list]; RETURN[p];
	END;

StoreNode: PUBLIC PROCEDURE[list: NodeListPtr, p: NodePtr] =
	BEGIN list.last.link←p; list.last←p END;

InsertNode: PUBLIC PROCEDURE[list: NodeListPtr, p: NodePtr] =
	BEGIN
	-- inserts node p at the front of list
	IF (p.link←list.link)=NIL THEN list.last←p; list.link←p;
	END;

RemoveNode: PUBLIC PROCEDURE[list: NodeListPtr] RETURNS[NodePtr] =
	BEGIN
	-- removes the node at the front of list
	p: NodePtr;
	IF (p←list.link)=NIL THEN RETURN[NIL];
	IF (list.link←p.link)=NIL THEN list.last←list ELSE p.link←NIL;
	RETURN[p];
	END;

InsertNodeList: PUBLIC PROCEDURE[list, inslist: NodeListPtr] =
	BEGIN
	-- inserts inslist at the front of list; destroys inslist's list head
	IF inslist.link#NIL THEN
		BEGIN
		-- link the lists together and update list.last if list was empty
		IF (inslist.last.link←list.link)=NIL THEN list.last←inslist.last;
		list.link←inslist.link;
		END;
	FreeHead[inslist];
	END;

AppendNodeList: PUBLIC PROCEDURE[list, applist: NodeListPtr] =
	BEGIN
	-- appends applist at the back of list; destroys applist's list head
	IF applist.link#NIL THEN
		BEGIN
		list.last.link←applist.link; -- link the lists together
		list.last←applist.last; -- tail of the new list is tail of applist
		END;
	FreeHead[applist];
	END;

RemoveNodeList: PUBLIC PROCEDURE[list: NodeListPtr, p: NodePtr]
	RETURNS[NodeListPtr] =
	BEGIN
	-- removes nodes up to and including p from the front of list;
	-- makes and returns a new list
	remlist: NodeListPtr←AllocHead[];
	remlist↑←[link: list.link, body: listhead[last: p]];
	IF (list.link←p.link)=NIL THEN list.last←list ELSE p.link←NIL;
	RETURN[remlist];
	END;

FreeNode: PROCEDURE[p: NodePtr, size: CARDINAL] = INLINE
	BEGIN TexMemDefs.FreeMem[p,size] END;

DsNode: PUBLIC PROCEDURE[p: NodePtr] =
	BEGIN
	WITH pp:p SELECT FROM
		char,disc => FreeNode[p,SIZE[char Node]];
		string => FreeNode[p,StringNodeSize[pp.length]];
		box => BEGIN DsNodeList[pp.head]; FreeNode[p,SIZE[box Node]] END;
		rule => FreeNode[p,SIZE[rule Node]];
		glue => BEGIN DelGlueLink[pp.g]; FreeNode[p,SIZE[glue Node]] END;
		space,kern => FreeNode[p,SIZE[space Node]];
		leader => BEGIN DsNodeList[pp.p]; FreeNode[p,SIZE[leader Node]] END;
		hyph => FreeNode[p,SIZE[hyph Node]];
		penalty => FreeNode[p,SIZE[penalty Node]];
		eject => FreeNode[p,SIZE[eject Node]];
		mark =>
			BEGIN
			TexTokenDefs.DelRCLink[pp.t];
			FreeNode[p,SIZE[mark Node]];
			END;
		ins =>
			BEGIN
			DsNodeList[pp.vlist]; DelGlueLink[pp.glue];
			FreeNode[p,SIZE[ins Node]];
			END;
		unset =>
			BEGIN
			DsNode[pp.box];
			FreeNode[p,SIZE[unset Node]];
			END;
		listhead => ERROR TexErrorDefs.Confusion;
		ENDCASE => ERROR; -- bad node type
	END;

DsNodeList: PUBLIC PROCEDURE[p: NodePtr] =
	BEGIN
	q: NodePtr←p;
	next: NodePtr; -- holds q.link
	WHILE q#NIL DO next←q.link; DsNode[q]; q←next ENDLOOP;
	END;


MakeBoxNode: PUBLIC PROCEDURE[dir: Direction, head: NodePtr, h,d,w: Dimn]
	RETURNS[b: BoxNodePtr] =
	BEGIN
	b←TexMemDefs.AllocMem[SIZE[box Node]];
	b↑←[link: NIL, body: box[
		 dir: dir, altered: FALSE, encloses: TRUE, head: head,
		 width: w, depth: d, height: h, shiftamt: 0, glueset: zeroGlueSet]];
	END;

NullBox: PUBLIC PROCEDURE RETURNS[b: BoxNodePtr] =
	BEGIN
	b←TexMemDefs.AllocMem[SIZE[box Node]];
	b↑←[link: NIL, body: box[
		 dir: hlist, altered: FALSE, encloses: TRUE, head: NIL,
		 width: 0, depth: 0, height: 0, shiftamt: 0, glueset: zeroGlueSet]];
	END;

MakeCharNode: PUBLIC PROCEDURE[c: FChar] RETURNS[p: CharNodePtr] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[char Node]];
	p↑←[link: NIL, body: char[c]];
	END;

MakeDiscNode: PUBLIC PROCEDURE[c: FChar] RETURNS[p: POINTER TO disc Node] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[disc Node]];
	p↑←[link: NIL, body: disc[c]];
	END;

MakeEjectNode: PUBLIC PROCEDURE RETURNS[p: POINTER TO eject Node] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[eject Node]];
	p↑←[link: NIL, body: eject[]];
	END;

MakeGlueNode: PUBLIC PROCEDURE[g: GluePtr]
	RETURNS[p: GlueNodePtr] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[glue Node]];
	p↑←[link: NIL, body: glue[g]];
	AddGlueLink[g]; -- increment reference count of GlueSpec
	END;

MakeHyphNode: PUBLIC PROCEDURE[h: HyphControl]
	RETURNS[p: POINTER TO hyph Node] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[hyph Node]];
	p↑←[link: NIL, body: hyph[h]];
	END;

MakeInsNode: PUBLIC PROCEDURE[tb: TopBotType, dir: Direction,
	hd: NodePtr, g: GluePtr] RETURNS[p: InsNodePtr] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[ins Node]];
	p↑←[link: NIL, body: ins[where: tb, dir: dir, vlist: hd, glue: g]];
	END;

MakeKernNode: PUBLIC PROCEDURE[k: Dimn]
	RETURNS[p: POINTER TO kern Node] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[kern Node]];
	p↑←[link: NIL, body: kern[k]];
	END;

MakeLeaderNode: PUBLIC PROCEDURE[q: NodePtr]
	RETURNS[p: POINTER TO leader Node] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[leader Node]];
	p↑←[link: NIL, body: leader[q]];
	END;

MakeMarkNode: PUBLIC PROCEDURE[t: TexTokenDefs.TokenListPtr]
	RETURNS[p: POINTER TO mark Node] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[mark Node]];
	p↑←[link: NIL, body: mark[t]];
	END;

MakePenaltyNode: PUBLIC PROCEDURE[pen: Penalty]
	RETURNS[p: POINTER TO penalty Node] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[penalty Node]];
	p↑←[link: NIL, body: penalty[pen]];
	END;

MakeRuleNode: PUBLIC PROCEDURE[width,height,depth: Dimn]
	RETURNS[p: RuleNodePtr] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[rule Node]];
	p↑←[link: NIL, body: rule[width: width, height: height, depth: depth]];
	END;

MakeSpace: PUBLIC PROCEDURE[s: Dimn]
	RETURNS[p: POINTER TO space Node] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[space Node]];
	p↑←[link: NIL, body: space[s]];
	END;

MakeStringNode: PUBLIC PROCEDURE[f: Font, s: STRING]
	RETURNS[p: POINTER TO string Node] =
	BEGIN
	len: CARDINAL←s.length;
	p←TexMemDefs.AllocMem[StringNodeSize[len]];
	p↑←[link: NIL, body: string[font: f, length: len, text: ]];
	InlineDefs.COPY[from: @s.text, to: @p.text, nwords: (len+1)/2];
	END;

MakeUnsetNode: PUBLIC PROCEDURE[box: BoxNodePtr,fPtr: FlexSumsPtr]
	RETURNS[p: UnsetNodePtr] =
	BEGIN
	p←TexMemDefs.AllocMem[SIZE[unset Node]];
	p↑←[link: NIL, body: unset[box,fPtr↑]];
	END;

END.