<> <> DIRECTORY Atom, CIFS, ConvertUnsafe, Directory, FileIO, IO, Juniper, OrderedSymbolTableRef, PutGet, Rope, RoseTranslateTypes, RoseTranslateInsides, ShowTime, System, TextNode, TiogaFileOps, TiogaOps, UserExec, ViewerClasses, ViewerOps, Volume; RoseTranslateSymbols: CEDAR PROGRAM IMPORTS Atom, CIFS, ConvertUnsafe, Directory, FileIO, IO, Juniper, OSTR: OrderedSymbolTableRef, Rope, System, RoseTranslateInsides, UserExec, Volume EXPORTS RoseTranslateInsides = BEGIN OPEN RoseTranslateTypes, RoseTranslateInsides; AddSymbols: PUBLIC PROC [job: Job, rootName: ROPE] = BEGIN error: BOOLEAN _ FALSE; IF job.libbed.Lookup[rootName] # NIL THEN RETURN; job.libbed.Insert[rootName]; IF job.type = UpdateJob THEN error _ Update[job.exec, rootName, job.path].error; IF NOT error THEN [] _ DigestSymbols[job, rootName]; END; Update: PROC [exec: UserExec.ExecHandle, rootName: ROPE, pathIn: LIST OF ROPE] RETURNS [error, changed: BOOLEAN] = BEGIN DirtyDown: PROC = CHECKED BEGIN check _ Atom.MakeAtom[rootName]; IF Atom.GetProp[atom: check, prop: $roseTranslateCheck] # NIL THEN BEGIN viewerLog.PutF["Circularity detected at %g", IO.refAny[path]]; ERROR Circularity; END; Atom.PutProp[atom: check, prop: $roseTranslateCheck, val: check]; END; check: ATOM; CleanUp: PROC = CHECKED {Atom.PutProp[atom: check, prop: $roseTranslateCheck, val: NIL]}; sourceName: ROPE _ rootName.Concat[".Rose"]; depsName: ROPE _ rootName.Concat[".RoseDeps"]; symbolsName: ROPE _ rootName.Concat[".RoseSymbols"]; mesaName: ROPE _ rootName.Concat[".Mesa"]; sourceOK, depsOK, symbolsOK, mesaExists, autoOK: BOOLEAN _ TRUE; path: LIST OF ROPE _ CONS[rootName, pathIn]; dSource, dMesa, dSymbols, dDeps: LONG CARDINAL; newer: BOOLEAN _ FALSE; imps: RopeList _ NIL; [sourceOK, dSource] _ GetTime[sourceName]; [depsOK, dDeps] _ GetTime[depsName]; [symbolsOK, dSymbols] _ GetTime[symbolsName]; [mesaExists, dMesa] _ GetTime[mesaName]; autoOK _ depsOK AND symbolsOK AND mesaExists; newer _ (dSource > dDeps) OR (dSource > dSymbols) OR (dSource > dMesa); DirtyDown[]; BEGIN ENABLE UNWIND => CleanUp[]; IF sourceOK AND (IF autoOK THEN newer ELSE TRUE) THEN BEGIN error _ Translate[exec, rootName, pathIn, UpdateJob] > 0; changed _ TRUE; END ELSE IF depsOK THEN BEGIN [error, changed] _ News[exec, rootName, path]; IF (changed OR NOT symbolsOK) AND sourceOK AND NOT error THEN error _ Translate[exec, rootName, pathIn, TranslateJob] > 0; END ELSE BEGIN viewerLog.PutF["no source or dependancies for %g!\n", IO.rope[rootName]]; error _ FALSE; changed _ FALSE; END; END; CleanUp[]; IF NOT error THEN BEGIN bcdName: ROPE _ rootName.Concat[".bcd"]; bcdExists, want: BOOLEAN _ FALSE; dBCD: LONG CARDINAL; [mesaExists, dMesa] _ GetTime[mesaName]; [bcdExists, dBCD] _ GetTime[bcdName]; IF NOT mesaExists THEN want _ FALSE ELSE IF NOT bcdExists THEN want _ TRUE ELSE IF dMesa > dBCD THEN want _ TRUE ELSE BEGIN mc: BOOLEAN; [error, mc, want] _ MesaNews[rootName, dBCD]; END; IF want THEN UserExec.DoIt[Rope.Cat["compile ", rootName], exec]; END; END; RopeList: TYPE = LIST OF ROPE; MesaNews: PROC [rootName: ROPE, dParent: LONG CARDINAL] RETURNS [error, missingChild, news: BOOLEAN] = BEGIN depFile: IO.STREAM; depList: RopeList _ NIL; storing: BOOLEAN _ FALSE; error _ missingChild _ news _ FALSE; depFile _ FileIO.Open[rootName.Concat[".RoseDeps"] !FileIO.OpenFailed, Juniper.Error, CIFS.Error, Volume.InsufficientSpace => BEGIN error _ TRUE; CONTINUE; END]; IF error THEN RETURN; depFile.SkipOver[IO.WhiteSpace]; WHILE NOT depFile.EndOf[] DO name: ROPE _ depFile.GetToken[MyBreak]; IF storing THEN depList _ CONS[name, depList] ELSE IF name.Equal[";"] THEN storing _ TRUE; depFile.SkipOver[IO.WhiteSpace]; ENDLOOP; depFile.Close[]; WHILE depList # NIL DO childExists: BOOLEAN; dChild: LONG CARDINAL; [childExists, dChild] _ GetTime[depList.first.Concat[".bcd"]]; IF NOT childExists THEN missingChild _ TRUE ELSE IF dChild > dParent THEN news _ TRUE; depList _ depList.rest; ENDLOOP; END; News: PROC [exec: UserExec.ExecHandle, rootName: ROPE, path: LIST OF ROPE] RETURNS [error, news: BOOLEAN] = BEGIN depFile: IO.STREAM _ FileIO.Open[rootName.Concat[".RoseDeps"]]; depList: RopeList _ NIL; depFile.SkipOver[IO.WhiteSpace]; WHILE NOT depFile.EndOf[] DO name: ROPE _ depFile.GetToken[MyBreak]; IF name.Equal[";"] THEN EXIT; depList _ CONS[name, depList]; depFile.SkipOver[IO.WhiteSpace]; ENDLOOP; depFile.Close[]; error _ news _ FALSE; WHILE depList # NIL DO e, n: BOOLEAN; [e, n] _ Update[exec, depList.first, path]; IF n THEN news _ TRUE; IF e THEN RETURN [TRUE, news]; depList _ depList.rest; ENDLOOP; END; GetTime: PROC [fileName: ROPE] RETURNS [exists: BOOLEAN, sinceEpoch: LONG CARDINAL] = TRUSTED BEGIN s: LONG STRING _ [256]; temp: LONG STRING _ [256]; t: System.GreenwichMeanTime; exists _ TRUE; ConvertUnsafe.AppendRope[s, fileName]; t _ Directory.GetProps[Directory.Lookup[s !Directory.Error => {exists _ FALSE; CONTINUE}], temp].createDate; IF exists THEN sinceEpoch _ System.SecondsSinceEpoch[t]; END; DigestSymbols: PROC [parent: Job, rootName: ROPE] RETURNS [error: BOOLEAN] = BEGIN job: Job _ NEW [JobRep _ [ exec: parent.exec, rootName: rootName, from: NIL, things: parent.things, type: TranslateJob, log: parent.log]]; job.from _ FileIO.Open[rootName.Concat[".RoseSymbols"] !FileIO.OpenFailed, Juniper.Error, CIFS.Error, Volume.InsufficientSpace => BEGIN Whimper[parent, "Unable to open %g.RoseSymbols", IO.rope[rootName]]; job.from _ NIL; CONTINUE; END]; IF job.from = NIL THEN RETURN [TRUE]; job.log.PutF["Reading symbols from %g.RoseSymbols...\n", IO.rope[rootName]]; job.from.SkipOver[IO.WhiteSpace]; WHILE NOT job.from.EndOf[] DO className: ROPE _ job.from.GetToken[MyBreak]; definer: ROPE _ job.from.GetToken[MyBreak]; bits: CARDINAL _ job.from.GetInt[]; defaultInitExpr: ROPE _ NARROW[job.from.GetRefAny[]]; asAny: REF ANY; stoppedOn: ROPE; cce: ccEntry _ NEW [SymbolTableEntryRep[cellClass] _ [name: className, value: cellClass[definedIn: rootName, cd: NEW [CellDefRep _ [defaultInitExprGiven: (bits MOD 2) > 0, initializerGiven: (bits MOD 4) > 1, initDataGiven: (bits MOD 8) > 3, defaultInitExpr: defaultInitExpr]] ]]]; iel: InterfaceEltList; [asAny, stoppedOn] _ ParseExpression[job, TRUE]; IF NOT stoppedOn.Equal["!!"] THEN BEGIN [] _ Complain[job, "Not terminated properly"]; job.log.PutRope["Done reading symbols\n"]; RETURN [TRUE]; END; IF asAny = NIL THEN iel _ NIL ELSE WITH asAny SELECT FROM sb: SquareBracketed => iel _ sb.iel; ENDCASE => BEGIN [] _ Complain[job, "Bad interface: %g", IO.refAny[asAny]]; job.log.PutRope["Done reading symbols\n"]; RETURN [TRUE]; END; IF (cce.cd.interface _ DigestInterface[job, iel]) = NIL THEN BEGIN job.log.PutRope["Done reading symbols\n"]; RETURN [TRUE]; END; AddCellClass[job, cce]; job.from.SkipOver[IO.WhiteSpace]; ENDLOOP; job.log.PutRope["Done reading symbols\n"]; END; AddCellClass: PUBLIC PROC [job: Job, cce: ccEntry] = BEGIN ste: SymbolTableEntry _ NARROW[job.things.Lookup[cce.name]]; complain: BOOLEAN _ ste # NIL; IF complain THEN WITH ste SELECT FROM oldCCE: ccEntry => IF oldCCE.definedIn = NIL AND cce.definedIn # NIL THEN BEGIN oldCCE.definedIn _ cce.definedIn; oldCCE.cd _ cce.cd; RETURN; END; ENDCASE; IF complain THEN BEGIN Whimper[job, "Multiple definition of cell class %g", IO.rope[cce.name]]; END ELSE job.things.Insert[cce]; END; DigestInterface: PUBLIC PROC [context: REF ANY, iel: InterfaceEltList] RETURNS [di: DigestedInterface] = BEGIN di _ NEW [DigestedInterfaceRep _ [ asTable: OSTR.CreateTable[CompareInterfaceElts], asList: iel]]; FOR iel _ iel, iel.rest WHILE iel # NIL DO IF di.asTable.Lookup[iel.first.name] # NIL THEN BEGIN [] _ Complain[context, "Multiple def of %g in interface %g", IO.rope[iel.first.name], IO.refAny[di]]; RETURN [NIL]; END; di.asTable.Insert[iel.first]; ENDLOOP; END; CompareInterfaceElts: OSTR.CompareProc = BEGIN s1, s2: ROPE; s1 _ WITH r1 SELECT FROM r: ROPE => r, ie: InterfaceElt => ie.name, ENDCASE => ERROR; s2 _ WITH r2 SELECT FROM r: ROPE => r, ie: InterfaceElt => ie.name, ENDCASE => ERROR; RETURN [s1.Compare[s2, FALSE]]; END; UpdateCmd: UserExec.CommandProc = BEGIN event.commandLineStream.SkipOver[IO.WhiteSpace]; WHILE NOT event.commandLineStream.EndOf[] DO name: ROPE _ event.commandLineStream.GetToken[IO.IDProc]; error: BOOLEAN _ TRUE; error _ NOT Update[exec, name, NIL !Circularity => CONTINUE].error; IF error THEN ok _ FALSE; event.commandLineStream.SkipOver[IO.WhiteSpace]; ENDLOOP; END; UserExec.RegisterCommand["RoseUpdate", UpdateCmd, "Ensures Rosemary translations are up to date", "Syntax: \"RoseUpdate *\". Recursively called on what each root depends on"]; END.