-- DesModSupImpl.mesa
-- last edit by Schmidt, April 27, 1982 2:24 pm
-- last edit by Satterthwaite, February 1, 1983 10:02 am

DIRECTORY
  CWF: TYPE USING [SWF1, SWF2, WF0, WF1],
  DesModSup: TYPE USING [],
  Dir: TYPE USING [FileInfo],
  LongString: TYPE USING [CompareStrings, EqualString, EquivalentString],
  MDModel: TYPE USING [AddToEndOfList, After, APPLSymbol, CkType, GetFileInfo, 
  	HasAStringName, IsOnList, LETSymbol, LISTSymbol, LOCSymbol, LookForInstSource,
  	LookForInstBcd, LookForTypeSource, LookForTypeBcd, MergeIntoList, 
	MODELSymbol, NarrowToAPPL, NarrowToLET, NarrowToLIST, NarrowToLOC,
	NarrowToPROC, NarrowToTYPE, NewSymAPPL, NewSymLIST,
	NewSymLOC, NewSymMODEL, NewSymOPEN, NewSymPROC, NewSymTYPE,
	OPENSymbol, PROCSymbol, RemoveFromList, SpliceBefore, Sym, 
	Symbol, SymbolSeq, TraverseAndRemove, TraverseList, TYPESymbol, ZeroOut],
  Process: TYPE USING [Yield],
  Runtime: TYPE USING [CallDebugger],
  Subr: TYPE USING [AbortMyself, CopyString, debugflg, EndsIn, strcpy],
  TimeStamp: TYPE USING [Null, Stamp],
  UserExec: TYPE USING[ExecHandle, UserAbort];
					
DesModSupImpl: PROGRAM
IMPORTS CWF, LongString, MDModel, Runtime, Process, Subr, UserExec
EXPORTS DesModSup = {
					

-- raised by EnterType and EnterInstAndLoc
-- when moduleName = NIL and can't find a type that it can use
-- so it must have a moduleName
NeedModuleName: PUBLIC SIGNAL = CODE;

-- take a list of Appls and Lets and TYPEs, and put a Model: PROC
-- header in front of them
-- also moves all undefined Appls to the Model parameter list
-- then puts a single list node in front of the PROC node
FixupExterior: PUBLIC PROC[symbolseq: MDModel.SymbolSeq, modelname: STRING] = {
spm: MDModel.PROCSymbol;
spa: MDModel.APPLSymbol;
spl: MDModel.LISTSymbol;

	
spm ← MDModel.NewSymPROC[symbolseq];
spm.procsym ← Subr.CopyString[modelname];
spm.procval ← symbolseq.toploc.nestedmodel.model;
spm.procparm ← NIL;
spm.procret ← NIL;
symbolseq.toploc.nestedmodel.model ← MDModel.NewSymLIST[symbolseq];
symbolseq.toploc.nestedmodel.model.first ← spm;
symbolseq.toploc.nestedmodel.model.rest ← NIL;
-- MDModel.TraverseTree[spm.procval, symbolseq, SeeIfUndefined];
spl ← MDModel.NarrowToLIST[spm.procval];
-- move type information to the parameter field
WHILE spl ~= NIL DO
	MDModel.CkType[spl, typeLIST];
	IF spl.first.stype = typeAPPL THEN {
		spa ← MDModel.NarrowToAPPL[spl.first];
		IF spa.applval = NIL THEN { 
			sptype: MDModel.TYPESymbol;
			sploc: MDModel.LOCSymbol;
			sptemp: MDModel.LISTSymbol;
			stemp: STRING ← [100];
			-- SpliceType[symbolseq, spa.appltype];
			spm.procparm ← MDModel.AddToEndOfList[spm.procparm, 
				spa.appltype, normal, symbolseq];
			sptemp ← MDModel.NarrowToLIST[spm.procval];
			[newlist: spm.procval] ← 
				MDModel.RemoveFromList[spa.appltype, sptemp];
			sptype ← MDModel.NarrowToTYPE[spa.appltype];
			sploc ← MDModel.NarrowToLOC[sptype.typeval];
			CWF.SWF2[stemp, "%s.%s"L, sploc.tail, sploc.sext];
			};
		};
	spl ← spl.rest;
	ENDLOOP;
-- now move instance information to the parameter field
{
	AddIt: PROC[spa1: MDModel.Symbol] RETURNS[remove: BOOL] = {
	IF spa1.stype = typeAPPL 
	AND MDModel.NarrowToAPPL[spa1].applval = NIL THEN {
		spm.procparm ← MDModel.AddToEndOfList[spm.procparm, 
			spa1, normal, symbolseq];
		RETURN[TRUE];
		};
	IF spa1.stype = typeLET THEN {
		splet: MDModel.LETSymbol;
		splet ← MDModel.NarrowToLET[spa1];
		IF splet.letval = NIL AND splet.letgrp.rest = NIL THEN {
			spappl: MDModel.APPLSymbol;
			spappl ← MDModel.NarrowToAPPL[splet.letgrp.first];
			spappl.letparent ← NIL;
			spm.procparm ← MDModel.AddToEndOfList[spm.procparm, 
				spappl, normal, symbolseq];
			RETURN[TRUE];
			};
		};
	RETURN[FALSE];
	};
	
spm.procval ← MDModel.TraverseAndRemove[MDModel.NarrowToLIST[spm.procval],
	 AddIt];
}};

EnterType: PUBLIC PROC[bcdFileName, moduleName: LONG STRING, bcdVers: TimeStamp.Stamp,
	symbolseq: MDModel.SymbolSeq, spmodel: MDModel.MODELSymbol] 
	RETURNS[sptype: MDModel.TYPESymbol] ={
bcdfilename: STRING ← [200];
sptypeloc: MDModel.LOCSymbol;
spproc: MDModel.PROCSymbol ← NIL;
plist: LONG POINTER TO MDModel.LISTSymbol ← NIL;

IF bcdVers = TimeStamp.Null THEN
	[sptype, sptypeloc, spproc] ← MDModel.LookForTypeSource[bcdFileName, moduleName, symbolseq, spmodel]
ELSE [sptype, sptypeloc, spproc] ← MDModel.LookForTypeBcd[bcdFileName, bcdVers, symbolseq, spmodel];
Subr.strcpy[bcdfilename, bcdFileName];
IF Subr.EndsIn[bcdfilename, ".bcd"L] THEN 
	bcdfilename.length ← bcdfilename.length - 4;
IF sptype = NIL OR sptypeloc = NIL THEN {
	IF sptypeloc = NIL THEN {
		fi: Dir.FileInfo;
		sptypeloc ← MDModel.NewSymLOC[symbolseq];
		sptypeloc.tail ← Subr.CopyString[bcdfilename];
		sptypeloc.sext ← Subr.CopyString["bcd"L];
		sptypeloc.createtime ← 0;
		fi ← MDModel.GetFileInfo[sptypeloc];
		fi.bcdVers ← bcdVers;
		};
	IF sptype = NIL THEN {
		sptype ← MDModel.NewSymTYPE[symbolseq];
		IF moduleName = NIL OR moduleName.length = 0 THEN ERROR NeedModuleName;
		sptype.typesym ← Subr.CopyString[
			IF LongString.EquivalentString[bcdFileName, moduleName] 
				OR bcdVers ~= TimeStamp.Null THEN moduleName 
			ELSE bcdFileName];
		sptype.typeName ← Subr.CopyString[moduleName];
		sptype.typeval ← sptypeloc;
		plist ← IF spproc = NIL THEN @spmodel.model 
			ELSE LOOPHOLE[@spproc.procval];
		plist↑ ← MDModel.AddToEndOfList[plist↑, sptype, 
			normal, symbolseq];
		}
	ELSE {
		MDModel.CkType[sptype, typeTYPE];
		sptype.typeval ← sptypeloc;
		};
	};
RETURN[sptype];
};

-- spimpl is either APPL or LET
-- if sptype is not NIL, then use sptype as the type of the instance
-- bcdVers should not be 0 when moduleName = NIL
EnterInstAndLoc: PUBLIC PROC[bcdFileName, moduleName: LONG STRING, 
	bcdVers: TimeStamp.Stamp, symbolseq: MDModel.SymbolSeq,
	spmodel: MDModel.MODELSymbol, sptype: MDModel.TYPESymbol] 
	RETURNS[spappl: MDModel.APPLSymbol] ={
spproc: MDModel.PROCSymbol ← NIL;

IF sptype = NIL THEN
	[sptype] ← EnterType[bcdFileName, moduleName, bcdVers, 
		symbolseq, spmodel];
MDModel.CkType[sptype, typeTYPE];
IF bcdVers = TimeStamp.Null THEN 
	[spappl, sptype, spproc] ← MDModel.LookForInstSource[bcdFileName, moduleName, 
		symbolseq, spmodel, sptype]
ELSE [spappl, sptype, spproc] ← MDModel.LookForInstBcd[bcdFileName, bcdVers, 
	symbolseq, spmodel, sptype];
IF spappl = NIL THEN {
	plist: LONG POINTER TO MDModel.LISTSymbol;
	splist: MDModel.LISTSymbol;
	intname: STRING ← [100];
	CWF.SWF1[intname, "%sImpl"L, IF moduleName = NIL THEN bcdFileName ELSE moduleName];
	spappl ← MDModel.NewSymAPPL[symbolseq];
	spappl.applsym ← Subr.CopyString[intname];
	spappl.appltype ← sptype;
	spappl.applval ← NIL;
	spappl.letparent ← NIL;
	IF spproc = NIL THEN {
		splist ← spmodel.model;
		WHILE splist ~= NIL DO
			IF splist.first.stype = typePROC THEN {
				spproc ← MDModel.NarrowToPROC[splist.first];
				EXIT;
				};
			splist ← splist.rest;
			ENDLOOP;
		};
	plist ← IF spproc = NIL THEN @spmodel.model 
		ELSE LOOPHOLE[@spproc.procval];
	plist↑ ← MDModel.AddToEndOfList[plist↑, spappl, normal, symbolseq];
	RETURN[spappl];
	}
ELSE {
	spappl.appltype ← sptype;
	};
RETURN[spappl];
};

-- makes the root be a list with constant
-- defs files and then the Model
-- assumes symbolseq.toploc.nestedmodel.model is a LIST of one element, 
-- which is a PROC
MoveTypesToFront: PUBLIC PROC[symbolseq: MDModel.SymbolSeq] = {
spmain: MDModel.PROCSymbol;
changes: BOOL ← TRUE;

	-- move elements to outermost list
	-- sp comes from spmain.procparm
	ListProcMove: PROC[sp: MDModel.Symbol] = {
	IF sp.stype ~= typeTYPE THEN RETURN;
	IF NOT MDModel.IsOnList[sp, symbolseq.toploc.nestedmodel.model] THEN { 
		symbolseq.toploc.nestedmodel.model ← 
			MDModel.AddToEndOfList[symbolseq.toploc.nestedmodel.model,
				sp, normal, symbolseq];
		changes ← TRUE;
		};
	};

	-- move elements it depends on to outermost list
	-- sp comes from symbolseq.toploc.nestedmodel.model
	ListProcMoveAgain: PROC[sp: MDModel.Symbol] = {
	spl: MDModel.LOCSymbol;
	sptype: MDModel.TYPESymbol;
	IF sp.stype = typeAPPL THEN RETURN;
	sptype ← MDModel.NarrowToTYPE[sp];
	IF sptype.typeval ~= NIL THEN {
		spl ← MDModel.NarrowToLOC[sptype.typeval];
		MDModel.TraverseList[spl.parmlist, ListProcMove];
		};
	};

	-- delete elements on either list if we've moved it
	-- sp comes from symbolseq.toploc.nestedmodel.model
	ListProcDelete: PROC[sp: MDModel.Symbol] = {
	spl: MDModel.LISTSymbol;
	IF MDModel.IsOnList[sp, spmain.procparm] THEN
		[newlist: spmain.procparm] ← 
			MDModel.RemoveFromList[sp, spmain.procparm];
	IF spmain.procval = NIL THEN RETURN;
	spl ← MDModel.NarrowToLIST[spmain.procval];
	IF MDModel.IsOnList[sp, spl] THEN {
		[newlist: spmain.procval] ← MDModel.RemoveFromList[sp, spl];
		};
	};

-- symbolseq.toploc.nestedmodel.model starts off as a list of one element
spmain ← MDModel.NarrowToPROC[symbolseq.toploc.nestedmodel.model.first];
symbolseq.toploc.nestedmodel.model ← NIL;
-- copy the parms to the outer list
-- this will make symbolseq.toploc.nestedmodel.model be a list of many elements
MDModel.TraverseList[spmain.procparm, ListProcMove];
-- now move any they depend on
WHILE changes DO
	changes ← FALSE;
	MDModel.TraverseList[symbolseq.toploc.nestedmodel.model, ListProcMoveAgain];
	ENDLOOP;
-- now delete them from the rest
MDModel.TraverseList[symbolseq.toploc.nestedmodel.model, ListProcDelete];
-- this will append the PROC body; or what's left of it
symbolseq.toploc.nestedmodel.model ← MDModel.AddToEndOfList[
	symbolseq.toploc.nestedmodel.model, spmain, 
		normal, symbolseq];
};


-- reorder the list in a logical order
-- topologically so those that depend on things come afterwards 
-- alternatively use a procedure to look down the list for before-ness
-- returns a new list
ReorganizeInOrder: PUBLIC PROC[symbolseq: MDModel.SymbolSeq, 
	oldlist: MDModel.LISTSymbol, exec: UserExec.ExecHandle]
	RETURNS[newlist: MDModel.LISTSymbol] = {
splist: MDModel.LISTSymbol;
spa: MDModel.Symbol;
changes: BOOL ← TRUE;
nloops: CARDINAL;

	-- spa is passed in
	AnalProc: PROC[sploc1: MDModel.Symbol] = {
	nelem: CARDINAL ← 0;
	spparm: MDModel.LISTSymbol;
	sploc: MDModel.LOCSymbol;
	IF sploc1.stype ~= typeLOC THEN RETURN;
	sploc ← MDModel.NarrowToLOC[sploc1];
	spparm ← sploc.parmlist;
	WHILE spparm ~= NIL DO
		MDModel.CkType[spparm, typeLIST];
		nelem ← nelem + 1;
		IF nelem > 100 THEN ERROR;	-- cycling
		MoveOneElement[spparm.first];
		spparm ← spparm.rest;
		ENDLOOP;
	RETURN;
	};
	
	-- spa is passed in
	MoveOneElement: PROC[element: MDModel.Symbol] = {
	IF MDModel.IsOnList[element, newlist] THEN {
		IF NOT element.recursive 
		AND MDModel.After[element, spa, newlist] THEN { 
			newlist ← MDModel.SpliceBefore[symbolseq,
				element, splist, newlist];
			changes ← TRUE;
			};
		}	
	ELSE {	-- not on list may be a LET node
		splet: MDModel.LETSymbol;
		splet ← (IF element.stype = typeTYPE THEN
				MDModel.NarrowToTYPE[element].letparent
			ELSE IF element.stype = typeAPPL THEN
				MDModel.NarrowToAPPL[element].letparent
			ELSE NIL);
		IF splet ~= NIL 
		AND NOT spa.recursive
		AND NOT splet.recursive
		AND MDModel.After[splet, spa, newlist] THEN {
			newlist ← MDModel.SpliceBefore[symbolseq,
				splet, splist, newlist];
			changes ← TRUE;
			};
		};
	};
			
	-- this moves the type of each APPL in a LET list
	ForEachType: PROC[sp: MDModel.Symbol] = {
	spappl: MDModel.APPLSymbol;
	IF sp.stype ~= typeAPPL THEN RETURN;
	spappl ← MDModel.NarrowToAPPL[sp];
	MoveOneElement[spappl.appltype];
	};
	
newlist ← oldlist;
FOR nloops IN [1..30] DO
	changes ← FALSE;
	splist ← newlist;
	WHILE splist ~= NIL DO
		Process.Yield[];	-- let others run
		IF UserExec.UserAbort[exec] THEN SIGNAL Subr.AbortMyself[];
		MDModel.CkType[splist, typeLIST];
		spa ← splist.first;
		WITH spa1: spa SELECT FROM
		typeAPPL => {
			SetRecursiveBitsAppl[symbolseq, 
				MDModel.NarrowToAPPL[spa]];
			IF spa1.applval ~= NIL THEN {
				IF spa1.applval.stype = typeLIST THEN
					MDModel.TraverseList[
					MDModel.NarrowToLIST[spa1.applval], AnalProc]
				ELSE AnalProc[spa1.applval];
				};
			};
		typeLET =>  {
			SetRecursiveBitsLet[symbolseq, MDModel.NarrowToLET[spa]];
			IF spa1.letval.stype = typeLIST THEN
				MDModel.TraverseList[
					MDModel.NarrowToLIST[spa1.letval], AnalProc]
			ELSE AnalProc[spa1.letval];
			MDModel.TraverseList[spa1.letgrp, ForEachType];
			};
		typeTYPE => {
			IF spa1.typeval.stype = typeLIST THEN
				MDModel.TraverseList[
					MDModel.NarrowToLIST[spa1.typeval], AnalProc]
			ELSE AnalProc[spa1.typeval];
			};
		ENDCASE => NULL;
		splist ← splist.rest;
		ENDLOOP;
	IF NOT changes THEN {
		CWF.WF1["(%u loops.)\n"L, @nloops];
		EXIT;
		};
	IF nloops = 26 AND Subr.debugflg THEN 
		Runtime.CallDebugger["Looks like looping (Hit p CR to proceed.)"L];
	REPEAT
	FINISHED => CWF.WF0["Note- loop exhausted.\n"L];
	ENDLOOP;
RETURN[newlist];
};

MAXLIST: CARDINAL = 100;

SortListOfSymbols: PUBLIC PROC[symbolseq: MDModel.SymbolSeq, oldlist: MDModel.LISTSymbol] 
	RETURNS[newlist: MDModel.LISTSymbol, nsyms: CARDINAL] = {
syms: ARRAY[0 .. MAXLIST) OF MDModel.Symbol;
spi, spj: MDModel.Symbol;

	RemoveIt: PROC[sp: MDModel.Symbol] RETURNS[remove: BOOL] = {
	IF sp.stype IN MDModel.HasAStringName 
	AND MDModel.Sym[sp] ~= NIL
	AND nsyms < LENGTH[syms] 
	THEN {
		syms[nsyms] ← sp;
		nsyms ← nsyms + 1;
		RETURN[TRUE];
		};
	RETURN[FALSE];
	};
	
nsyms ← 0;
newlist ← MDModel.TraverseAndRemove[oldlist, RemoveIt];
IF nsyms = 0 THEN RETURN;
-- now sort it
FOR i: CARDINAL IN [0 .. nsyms - 1) DO
	spi ← syms[i];
	FOR j: CARDINAL IN [i + 1 .. nsyms) DO
		spj ← syms[j];
		-- this puts TYPES before APPLs
		IF (spj.stype = typeTYPE AND spi.stype = typeAPPL)
		OR LongString.CompareStrings[MDModel.Sym[spj], 
		    MDModel.Sym[spi]] < 0 THEN {
			syms[i] ← spj;
			syms[j] ← spi;
			spi ← spj;
			};
		ENDLOOP;
	ENDLOOP;
-- now add them
FOR i: CARDINAL IN [0 .. nsyms) DO
	newlist ← MDModel.AddToEndOfList[newlist, syms[i], normal, symbolseq];
	ENDLOOP;
};
	
	

-- removes standard Mesa TYPEs, replacing them with an open
ProcessForStandardOpen: PUBLIC PROC[symbolseq: MDModel.SymbolSeq] = {
newlist: MDModel.LISTSymbol;
somestd: BOOL ← FALSE;
thrownaway: MDModel.LISTSymbol;
[newlist, somestd, thrownaway] ← ListStandardOpen[
	symbolseq.toploc.nestedmodel.model, symbolseq];
symbolseq.toploc.nestedmodel.model ← NIL;
IF somestd THEN {
	sploc: MDModel.LOCSymbol;
	spopen: MDModel.OPENSymbol;
	sploc ← MDModel.NewSymLOC[symbolseq];
	sploc.host ← Subr.CopyString["Ivy"L];
	sploc.path ← Subr.CopyString["Schmidt>Pilot"L];
	sploc.tail ← Subr.CopyString["StandardPilot"L];
	sploc.sext ← Subr.CopyString["Model"L];
	sploc.nestedmodel ← MDModel.NewSymMODEL[symbolseq];
	sploc.nestedmodel.model ← thrownaway;
	spopen ← MDModel.NewSymOPEN[symbolseq];
	spopen.open ← sploc;
	symbolseq.toploc.nestedmodel.model ← 
		MDModel.AddToEndOfList[NIL, spopen, normal, symbolseq];
	};
symbolseq.toploc.nestedmodel.model ← MDModel.NarrowToLIST[
	MDModel.MergeIntoList[symbolseq.toploc.nestedmodel.model, newlist, 
		symbolseq, normal]];
};

ListStandardOpen: PROC[oldlist: MDModel.LISTSymbol, symbolseq: MDModel.SymbolSeq] 
	RETURNS[newlist: MDModel.LISTSymbol, somestd: BOOL,
		thrownaway: MDModel.LISTSymbol] = {
original: MDModel.LISTSymbol;
original ← oldlist;
somestd ← FALSE;
thrownaway ← newlist ← NIL;
WHILE oldlist ~= NIL DO
	{
	IF oldlist.first.stype = typePROC THEN {
		spp: MDModel.PROCSymbol ← MDModel.NarrowToPROC[oldlist.first];
		IF spp.procval ~= NIL AND spp.procval.stype = typeLIST THEN {
			newstd: BOOL;
			throw: MDModel.LISTSymbol;
			[spp.procval, newstd, throw] ← ListStandardOpen[
				MDModel.NarrowToLIST[spp.procval], symbolseq];
			IF throw ~= NIL THEN
				thrownaway ← MDModel.NarrowToLIST[
					MDModel.MergeIntoList[thrownaway, throw,
			 			symbolseq, normal]];
			somestd ← somestd OR newstd;
			};
		}
	ELSE IF oldlist.first.stype = typeTYPE 
	AND AlreadyInStandard[MDModel.NarrowToTYPE[oldlist.first]] THEN {
		IF Subr.debugflg THEN 
			CWF.WF1["Removing %s since it is in standard.\n"L, 
				MDModel.NarrowToTYPE[oldlist.first].typesym];
		somestd ← TRUE;
		thrownaway ← MDModel.AddToEndOfList[thrownaway, oldlist.first,
			 normal, symbolseq];
		GOTO next;
		};
	-- add to new list
	newlist ← MDModel.AddToEndOfList[newlist, oldlist.first, normal, symbolseq];
	GOTO next;
	EXITS
	next => oldlist ← oldlist.rest;
	};
	ENDLOOP;
FreeListHeaders[original];
};

AlreadyInStandard: PROC[sptype: MDModel.TYPESymbol] RETURNS[standard: BOOL] = {
std: ARRAY [0 .. 65) OF RECORD[
	modulename: STRING,
	createtime: LONG CARDINAL
	-- createtime is either the create time of the file listed in the model
	--	or is the time part of the functional time stamp
	] ← [
	["Ascii"L, 		2513637266],
	["BitBlt"L, 		2527465195],
	["CmFile"L, 		2514424598],
	["Compatibility"L, 	2527806666],
	["Cursor"L, 		2509385386],
	["Date"L, 		2513895850],
	["DCSFileTypes"L, 	2475178361],
	["Directory"L, 		2517693769],
	["Environment"L, 	2527465960],
	["Event"L, 		2508881119],
	["Exec"L, 		2527816258],
	["ExecOps"L, 		2522691244],
	["File"L, 		2508166537],
	["FileStream"L, 	2511989735],
	["FileSW"L, 		2509387464],
	["FileTypes"L, 		2527608841],
	["Format"L, 		2526835204],
	["FormSW"L, 		2508885370],
	["Heap"L, 		2512678088],
	["HeapString"L, 	2527806717],
	["Inline"L, 		2527466277],
	["Keys"L, 		2527463501],
	["KeyStations"L, 	2527695385],
	["LongString"L, 	2522357869],
	["Menu"L, 		2527806675],
	["MiscAlpha"L, 		2527466367],
	["Mopcodes"L, 		2527463862],
	["MsgSW"L, 		0],
	["PieceSource"L, 	0],
	["PrincOps"L, 		2527524542],
	["Process"L, 		2527016599],
	["Profile"L, 		2504449015],
	["Put"L, 		2513029493],
	["Runtime"L, 		2514412201],
	["RuntimeInternal"L, 	2529858042],
	["SDDefs"L, 		2527463578],
	["Segments"L, 		2527547640],
	["Space"L, 		2511801733],
	["SpecialSystem"L, 	2514239895],
	["Storage"L, 		2510096576],
	["STP"L, 		2516889925],
	["STPOps"L, 		2530729409],
	["Stream"L, 		2512514215],
	["Streams"L, 		2516815806],
	["String"L, 		2505079728],
	["Strings"L, 		2525300545],
	["StringSW"L, 		2527806730],
	["System"L, 		2527032238],
	["SystemInternal"L, 	2508165980],
	["TajoMisc"L, 		2527806732],
	["TextDisplay"L, 	2527806677],
	["TextSource"L, 	2527806670],
	["TextSW"L, 		2508891169],
	["Time"L, 		2511811906],
	["TimeStamp"L, 		2527463438],
	["Tool"L, 		2508882495],
	["ToolWindow"L, 	2505782260],
	["Transaction"L, 	2508440429],
	["TTY"L, 		2527614966],
	["TTYSW"L, 		2508885779],
	["UserInput"L, 		2508878121],
	["UserTerminal"L, 	2514232875],
	["Volume"L, 		2512677128],
	["Window"L, 		2512633822],
	["WindowFont"L, 	2527806664]
	];

sploc: MDModel.LOCSymbol;
fi: Dir.FileInfo;
standard ← FALSE;
IF sptype.typeval = NIL OR sptype.typeval.stype ~= typeLOC THEN RETURN[FALSE];
sploc ← MDModel.NarrowToLOC[sptype.typeval];
fi ← MDModel.GetFileInfo[sploc];
IF sploc.createtime = 0 AND fi.bcdVers = TimeStamp.Null THEN RETURN[FALSE];
FOR i: CARDINAL IN [0 .. LENGTH[std]) DO
	IF (sploc.createtime = std[i].createtime 
	   OR fi.bcdVers.time = std[i].createtime)
	AND LongString.EqualString[sptype.typesym, std[i].modulename] THEN
		RETURN[TRUE];
	ENDLOOP;
RETURN[FALSE];
};

-- free the nodes of type LIST, but not the things
-- they point to as they may be used elsewhere
FreeListHeaders: PROC[splist: MDModel.LISTSymbol] = {
spnext: MDModel.LISTSymbol;
WHILE splist ~= NIL DO
	MDModel.CkType[splist, typeLIST];
	spnext ← splist.rest;
	MDModel.ZeroOut[splist];
	splist ← spnext;
	ENDLOOP;
};



-- the recursive bits stuff
SetRecursiveBitsAppl: PROC[symbolseq: MDModel.SymbolSeq, 
	spappl: MDModel.APPLSymbol] = {
rec: BOOL;
sploc: MDModel.LOCSymbol;
splist: MDModel.LISTSymbol;
spa: MDModel.APPLSymbol;
IF spappl.recursive 
OR spappl.applval = NIL 
OR spappl.applval.stype ~= typeLOC 
	THEN RETURN;
sploc ← MDModel.NarrowToLOC[spappl.applval];
splist ← sploc.parmlist;
WHILE splist ~= NIL DO
	IF splist.first.stype ~= typeAPPL THEN {
		splist ← splist.rest;
		LOOP;
		};
	spa ← MDModel.NarrowToAPPL[splist.first];
	IF spa.applval ~= NIL AND spa.applval.stype = typeLOC THEN {
		rec ← LookFor[MDModel.NarrowToLOC[spa.applval], spappl];
		IF rec THEN spappl.recursive ← spa.recursive ← TRUE;
		}
	ELSE IF spa.letparent ~= NIL THEN 
		CheckForRecursiveImportsAndExports[spa.letparent, spappl, symbolseq];
	splist ← splist.rest;
	ENDLOOP;
};
 
-- discover which nodes are recursive
SetRecursiveBitsLet: PROC[symbolseq: MDModel.SymbolSeq, 
	splet: MDModel.LETSymbol] = {
splist: MDModel.LISTSymbol;
nlist: CARDINAL ← 0;
splist ← splet.letgrp;
WHILE splist ~= NIL DO
	nlist ← nlist + 1;
	IF nlist > 100 THEN ERROR;		-- cycling
	IF splist.first.stype = typeAPPL THEN
		CheckForRecursiveImportsAndExports[splet, 
			MDModel.NarrowToAPPL[splist.first], symbolseq];
	splist ← splist.rest
	ENDLOOP;
};

-- look for recursion in LET[] stmts
-- look and see if spappl is referenced in splet.letval
CheckForRecursiveImportsAndExports: PROC[splet: MDModel.LETSymbol, 
	spappl: MDModel.APPLSymbol, symbolseq: MDModel.SymbolSeq] = {
rec: BOOL;
IF splet.letval = NIL THEN RETURN;
IF splet.letval.stype = typeLOC THEN {
	rec ← LookFor[MDModel.NarrowToLOC[splet.letval], spappl];
	IF rec THEN splet.recursive ← rec;
	}
ELSE {
	spl: MDModel.LISTSymbol;
	spa1: MDModel.APPLSymbol;
	spl ← MDModel.NarrowToLIST[splet.letval];
	WHILE spl ~= NIL DO
		IF spl.first.stype ~= typeAPPL THEN {
			spl ← spl.rest;
			LOOP;	-- this is an error, but better to ignore for now
			};
		spa1 ← MDModel.NarrowToAPPL[spl.first];
		rec ← LookFor[MDModel.NarrowToLOC[spa1.applval], spappl];
		IF rec THEN splet.recursive ← rec;
		spl ← spl.rest;
		ENDLOOP;
	};
};

LookFor: PROC[sp: MDModel.LOCSymbol, spappl: MDModel.Symbol] RETURNS[rec: BOOL] = {
splist: MDModel.LISTSymbol;
rec ← FALSE;
splist ← sp.parmlist;
WHILE splist ~= NIL DO
	IF splist.first = spappl THEN {
		spappl.recursive ← TRUE;
		rec ← TRUE;
		};
	splist ← splist.rest;
	ENDLOOP;
};

}.