-- SMFIImpl.mesa, June 17, 1983 9:50 am -- last edit by Schmidt May 24, 1983 11:11 am -- last edit by Satterthwaite, August 11, 1983 2:36 pm DIRECTORY Atom: TYPE USING [MakeAtom], BcdDefs: TYPE USING [ Base, EXPIndex, FTIndex, IMPIndex, MTIndex, Namee, NameRecord, NullName], BcdOps: TYPE USING [ BcdBase, EXPHandle, IMPHandle, MTHandle, NameString, FindName, ProcessExports, ProcessImports, ProcessModules], CS: TYPE USING [CardFromRope, EndsIn, RopeFromStamp, StampFromRope, z], CtoSP1: TYPE --P1-- USING [InstallParseTable, Parse], CtoSParseData: TYPE, Directory: TYPE USING [Error, ignore, Lookup], File: TYPE USING [Capability, nullCapability], FileIO: TYPE USING [Open, OpenFailed], FileSegment: TYPE USING [], FileStream: TYPE USING [GetLeaderPropertiesForCapability], IO: TYPE USING [ card, Close, Put, PutF, rope, string, STREAM, UserAbort, UserAborted], Rope: TYPE USING [Cat, Equal, Fetch, Flatten, FromProc, Length, Lower, ROPE, Text], Runtime: TYPE USING [GetTableBase], SMEval: TYPE USING [Eval], SMFI: TYPE USING [BcdFileInfo, BcdFileInfoRecord, SrcFileInfo, SrcFileInfoRecord], SMFIOps: TYPE USING [], SMOps: TYPE USING [MS], SMTree: TYPE Tree USING [Link, null], SMTreeOps: TYPE USING [PopTree], SMTypeCons: TYPE USING [ MkArrow, MkControlType, MkCrossReverse, MkCross2, MkDeclElem, MkDeclReverse, MkInterfaceType, MkStampType], SMUtil: TYPE USING [PrintSubTree], Space: TYPE USING [ Create, CreateUniformSwapUnits, Delete, Handle, LongPointer, MakeReadOnly, Map, virtualMemory], TimeStamp: TYPE USING [Null, Stamp], UECP: TYPE USING [Argv, Parse], UserExec: TYPE USING [CommandProc, GetStreams, RegisterCommand]; SMFIImpl: CEDAR MONITOR IMPORTS Atom, BcdOps, CS, CtoSP1, CtoSParseData, Directory, FileIO, FileStream, IO, Rope, Runtime, SMEval, SMTreeOps, SMTypeCons, SMUtil, Space, UECP, UserExec EXPORTS SMFIOps ~ { OPEN Tree~~SMTree; -- code in this module updates the FI tables -- therefore most PUBLIC procedures acquire the monitor lock -- MDS usage -- these data structures are protected by the monitor lock srcFiList: SMFI.SrcFileInfo ← NIL; bcdFiList: SMFI.BcdFileInfo ← NIL; -- endof MDS -- code to manipulate the FI's Flush: PUBLIC ENTRY PROC ~ { ENABLE UNWIND => {NULL}; srcFiList ← NIL; bcdFiList ← NIL}; Reset: PUBLIC ENTRY PROC ~ { ENABLE UNWIND => {NULL}; FOR srcFi: SMFI.SrcFileInfo ← srcFiList, srcFi.link UNTIL srcFi = NIL DO srcFi.capability ← File.nullCapability; srcFi.state ← MAX[srcFi.state, $analyzed]; ENDLOOP; FOR bcdFi: SMFI.BcdFileInfo ← bcdFiList, bcdFi.link UNTIL bcdFi = NIL DO bcdFi.capability ← File.nullCapability; bcdFi.state ← MAX[bcdFi.state, $analyzed]; ENDLOOP; }; FindSource: PUBLIC ENTRY PROC[create: LONG CARDINAL←0] RETURNS[fi: SMFI.SrcFileInfo] ~ { ENABLE UNWIND => {NULL}; IF create # 0 THEN FOR srcFi: SMFI.SrcFileInfo ← srcFiList, srcFi.link UNTIL srcFi = NIL DO IF srcFi.create = create THEN RETURN[srcFi] ENDLOOP; fi ← (CS.z).NEW[SMFI.SrcFileInfoRecord ← [create~create, state~$empty, link~srcFiList]]; srcFiList ← fi}; NewestSource: PUBLIC PROC[srcFileName: Rope.Text] RETURNS[fi: SMFI.SrcFileInfo] ~ TRUSTED { cap: File.Capability; none: BOOL ← FALSE; cap ← Directory.Lookup[fileName~LOOPHOLE[srcFileName], permissions~Directory.ignore ! Directory.Error => {none ← TRUE; CONTINUE}]; RETURN[FindSource[IF none THEN 0 ELSE CreateFromCap[cap]]]}; FindBcd: PUBLIC ENTRY PROC[stamp: TimeStamp.Stamp←TimeStamp.Null] RETURNS[fi: SMFI.BcdFileInfo] ~ { ENABLE UNWIND => {NULL}; IF stamp # TimeStamp.Null THEN FOR bcdFi: SMFI.BcdFileInfo ← bcdFiList, bcdFi.link UNTIL bcdFi = NIL DO IF bcdFi.stamp = stamp THEN RETURN[bcdFi] ENDLOOP; fi ← (CS.z).NEW[SMFI.BcdFileInfoRecord ← [stamp~stamp, state~$empty, link~bcdFiList]]; bcdFiList ← fi}; FindBcdByName: PUBLIC PROC[bcdFileName: Rope.Text] RETURNS[fi: SMFI.BcdFileInfo] ~ { FOR bcdFi: SMFI.BcdFileInfo ← bcdFiList, bcdFi.link UNTIL bcdFi = NIL DO IF bcdFileName.Equal[bcdFi.localName, FALSE] THEN RETURN[bcdFi] ENDLOOP; RETURN[NIL]}; PrintFileInfo: ENTRY UserExec.CommandProc ~ TRUSTED { ENABLE UNWIND => {NULL}; argv: UECP.Argv ~ UECP.Parse[event.commandLine]; in, out: IO.STREAM; [in, out] ← UserExec.GetStreams[exec]; FOR i: CARDINAL IN [1 .. argv.argc) DO PrintEntries[argv[i].Flatten[], in, out]; ENDLOOP; IF argv.argc = 1 THEN PrintEntries[NIL, in, out]}; -- no args -- prints all if rope = NIL PrintEntries: PROC[rope: Rope.Text, in, out: IO.STREAM] ~ { FOR srcFi: SMFI.SrcFileInfo ← srcFiList, srcFi.link UNTIL srcFi = NIL DO IF rope = NIL OR rope.Equal[srcFi.shortName, FALSE] THEN { out.PutF["Entry: %s!(%t)", IO.rope[srcFi.localName], IO.card[srcFi.create]]; IF srcFi.state = $opened THEN out.Put[IO.string[", present"L]]; out.Put[IO.string["\n type:"L]]; SMUtil.PrintSubTree[out, srcFi.type, 4]; out.Put[IO.string["\n\n"L]]; IF in.UserAbort THEN ERROR IO.UserAborted[NIL, NIL]}; ENDLOOP; FOR bcdFi: SMFI.BcdFileInfo ← bcdFiList, bcdFi.link UNTIL bcdFi = NIL DO IF rope = NIL OR rope.Equal[bcdFi.shortName, FALSE] THEN { out.PutF[ "Entry: %s!%s", IO.rope[bcdFi.localName], IO.rope[CS.RopeFromStamp[bcdFi.stamp]]]; IF bcdFi.state = $opened THEN out.Put[IO.string[", present"L]]; out.Put[IO.string["\n type:"L]]; SMUtil.PrintSubTree[out, bcdFi.type, 4]; out.Put[IO.string["\n\n"L]]; IF in.UserAbort[] THEN ERROR IO.UserAborted[NIL, NIL]}; ENDLOOP; }; -- code to read in and analyze files -- each inner procedure acquires ML EvaluateUnitId: PUBLIC PROC[ms: SMOps.MS, unitId, version: Rope.ROPE] RETURNS[value: SMTree.Link] ~ { ENABLE UNWIND => {NULL}; shortName: Rope.Text ~ unitId.Flatten[]; -- for now IF CS.EndsIn[shortName, ".mesa"] THEN { fi: SMFI.SrcFileInfo ~ IF Ambiguous[version] THEN NewestSource[shortName] ELSE FindSource[CS.CardFromRope[version]]; IF fi.state >= $analyzed THEN RETURN[fi]; fi.host ← fi.directory ← NIL; fi.shortName ← shortName; fi.version ← 0; FillSource[fi]; IF fi.state = $opened THEN AddCedarInfo[ms, fi]; RETURN[fi]} ELSE IF CS.EndsIn[shortName, ".bcd"] THEN { fi: SMFI.BcdFileInfo; IF Ambiguous[version] THEN { fi ← FindBcdByName[shortName]; IF fi = NIL THEN fi ← FindBcd[TimeStamp.Null]} ELSE fi ← FindBcd[CS.StampFromRope[version]]; IF fi.state >= $analyzed THEN RETURN[fi]; fi.host ← fi.directory ← NIL; fi.shortName ← shortName; fi.version ← 0; FillBcd[ms, fi]; RETURN[fi]} ELSE IF CS.EndsIn[shortName, ".model"] THEN { ERROR} -- do nothing for now ELSE ERROR}; Ambiguous: PUBLIC PROC[version: Rope.ROPE] RETURNS[BOOL] ~ { RETURN[version = NIL OR (version.Length = 1 AND Rope.Lower[version.Fetch[0]] = 'h)]}; -- fills in src for .mesa FillSource: PUBLIC ENTRY PROC[fi: SMFI.SrcFileInfo] ~ TRUSTED { cap: File.Capability; failed: BOOL ← FALSE; fi.localName ← fi.shortName; RetrieveRemoteSrcFile[fi]; -- place holder cap ← Directory.Lookup[ fileName~LOOPHOLE[fi.localName], permissions~Directory.ignore ! Directory.Error => {failed ← TRUE; CONTINUE}]; IF ~failed THEN { create: LONG CARDINAL ~ CreateFromCap[cap]; IF fi.create = 0 THEN fi.create ← create ELSE IF fi.create # create THEN failed ← TRUE}; IF failed THEN {fi.capability ← File.nullCapability; fi.state ← MAX[fi.state, $analyzed]} ELSE {fi.capability ← cap; fi.state ← $opened}}; -- fills in bcd for .bcd in model FillBcd: ENTRY PROC[ms: SMOps.MS, fi: SMFI.BcdFileInfo] ~ TRUSTED { rn: Rope.Text ~ GetRootName[fi.shortName]; failed: BOOL ← FALSE; fi.localName ← rn.Cat[".bcd"].Flatten[]; RetrieveRemoteBcdFile[fi]; -- place holder fi.capability ← Directory.Lookup[ fileName~LOOPHOLE[fi.localName], permissions~Directory.ignore ! Directory.Error => {failed ← TRUE; CONTINUE}]; -- note that version stamp is not validated here IF failed THEN fi.state ← MAX[fi.state, $analyzed] ELSE IF fi.state = $analyzed THEN fi.state ← $opened -- stamp not verified ELSE IF AddBcdInfo[ms, fi].success THEN fi.state ← $opened}; -- stamp verified GetRootName: PROC[name: Rope.Text] RETURNS[root: Rope.Text] ~ { i: CARDINAL ← name.Length - 1; WHILE i > 0 AND name.Fetch[i] ~= '. DO i ← i-1 ENDLOOP; root ← IF i > 0 THEN name.Flatten[0, i] ELSE name; RETURN}; CreateFromCap: PROC[cap: File.Capability] RETURNS[LONG CARDINAL] ~ TRUSTED { RETURN[FileStream.GetLeaderPropertiesForCapability[cap].create]}; RetrieveRemoteSrcFile: PROC[fi: SMFI.SrcFileInfo] ~ {}; RetrieveRemoteBcdFile: PROC[fi: SMFI.BcdFileInfo] ~ {}; -- code to analyze bcds and srcs -- for Mesas AddCedarInfo: ENTRY PROC[ms: SMOps.MS, fi: SMFI.SrcFileInfo] ~ { in: IO.STREAM ← NIL; in ← FileIO.Open[fi.shortName ! FileIO.OpenFailed => {CONTINUE}]; IF in = NIL THEN fi.type ← Tree.null ELSE { complete: BOOL; nTokens, nErrors: NAT; TRUSTED {[complete, nTokens, nErrors] ← CtoSP1.Parse[ms, in]}; fi.type ← IF complete --AND nErrors = 0-- THEN SMEval.Eval[ms, (ms.tm).PopTree, NIL] ELSE Tree.null; IF nErrors # 0 THEN { (ms.out).PutF["%s was not parsed successfully\n", IO.rope[fi.shortName]]; fi.type ← Tree.null}; in.Close[]} }; -- for Bcds -- imports and exports are partially uncheckable (not enough info in Bcd) AddBcdInfo: PROC[ms: SMOps.MS, fi: SMFI.BcdFileInfo] RETURNS[success: BOOL]~ TRUSTED { LinkList: TYPE ~ LIST OF Tree.Link; d, m, r: LinkList ← NIL; range: Tree.Link; bcdBase: BcdOps.BcdBase ← NIL; nameString: BcdOps.NameString; ftb: BcdDefs.Base; sgb: BcdDefs.Base; UnitList: PROC[l: LIST OF Tree.Link] RETURNS[BOOL] ~ CHECKED INLINE { RETURN[l # NIL AND l.first = NIL]}; NameToRope: PROC[name: BcdDefs.NameRecord] RETURNS[Rope.Text] ~ TRUSTED { i: CARDINAL ← 0; EachChar: PROC RETURNS[c: CHAR] ~ TRUSTED { c ← nameString.string.text[name+i]; i ← i+1; RETURN}; RETURN[Rope.FromProc[nameString.size[name], EachChar].Flatten]}; NameeToRope: PROC[namee: BcdDefs.Namee] RETURNS[Rope.Text] ~ TRUSTED { name: BcdDefs.NameRecord ~ BcdOps.FindName[bcdBase, namee]; RETURN[IF name = BcdDefs.NullName THEN NIL ELSE NameToRope[name]]}; { space: Space.Handle; ForEachModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS[stop: BOOL←FALSE] ~ TRUSTED { name: ATOM ~ Atom.MakeAtom[NameToRope[mth.name]]; type: Tree.Link ~ SMTypeCons.MkInterfaceType[ms.tm, name]; IF bcdBase.definitions THEN r ← (ms.z).CONS[type, r] ELSE { m ← (ms.z).CONS[SMTypeCons.MkDeclElem[ms.tm, name, type], m]; -- for cross2 r ← (ms.z).CONS[name, r]}; -- programs export instances }; ForEachImport: PROC[ith: BcdOps.IMPHandle, iti: BcdDefs.IMPIndex] RETURNS[stop: BOOL←FALSE] ~ TRUSTED { name: ATOM ~ Atom.MakeAtom[ IF ith.namedInstance THEN NameeToRope[[import[iti]]] ELSE NameToRope[ith.name].Cat["Impl"]]; type: Tree.Link ~ SMTypeCons.MkStampType[ms.tm, ftb[ith.file].version]; d ← (ms.z).CONS[SMTypeCons.MkDeclElem[ms.tm, name, type], d]}; ForEachExport: PROC[eth: BcdOps.EXPHandle, eti: BcdDefs.EXPIndex] RETURNS[stop: BOOL←FALSE] ~ TRUSTED { r ← (ms.z).CONS[SMTypeCons.MkStampType[ms.tm, ftb[eth.file].version], r]}; [space, bcdBase] ← LoadUpBcd[fi.capability]; success ← (fi.stamp = bcdBase.version OR fi.stamp = TimeStamp.Null); IF success THEN { nameString ← LOOPHOLE[bcdBase + bcdBase.ssOffset]; ftb ← LOOPHOLE[bcdBase, BcdDefs.Base] + bcdBase.ftOffset; sgb ← LOOPHOLE[bcdBase, BcdDefs.Base] + bcdBase.sgOffset; fi.stamp ← bcdBase.version; [] ← BcdOps.ProcessModules[bcdBase, ForEachModule]; [] ← BcdOps.ProcessImports[bcdBase, ForEachImport]; [] ← BcdOps.ProcessExports[bcdBase, ForEachExport]; IF ~bcdBase.definitions THEN { -- implementors export a variable of type CONTROL as well r ← (ms.z).CONS[SMTypeCons.MkControlType[ms.tm], r]}; range ← IF UnitList[r] THEN r.first ELSE SMTypeCons.MkCrossReverse[ms.tm, r]; IF ~bcdBase.definitions THEN { range ← SMTypeCons.MkCross2[ tm~ms.tm, decl~SMTypeCons.MkDeclReverse[ms.tm, m], type~range]; }; fi.type ← SMEval.Eval[ ms, SMTypeCons.MkArrow[ tm~ms.tm, domain~SMTypeCons.MkDeclReverse[ms.tm, d], range~range], NIL]; }; Space.Delete[space]}}; LoadUpBcd: PROC[cap: File.Capability] RETURNS[space: Space.Handle, bcdBase: BcdOps.BcdBase] ~ TRUSTED { nPages: CARDINAL ← 10; IF cap = File.nullCapability THEN ERROR; DO space ← Space.Create[size~nPages, parent~Space.virtualMemory]; space.Map[window~[file~cap, base~1]]; bcdBase ← space.LongPointer; IF bcdBase.nPages <= nPages THEN EXIT; nPages ← bcdBase.nPages; Space.Delete[space]; ENDLOOP; Space.CreateUniformSwapUnits[parent~space, size~8]; -- good idea? space.MakeReadOnly}; InitModule: PROC ~ { TRUSTED {CtoSP1.InstallParseTable[Runtime.GetTableBase[LOOPHOLE[CtoSParseData]]]}; UserExec.RegisterCommand["YFIPrint", PrintFileInfo]}; InitModule[]; }.