-- CTIntImpl.Mesa, last edit May 19, 1983 7:33 pm DIRECTORY Buttons: TYPE USING [Button, ButtonProc], CompilerOps: TYPE USING [DefaultSwitches, LetterSwitches], Containers: TYPE USING [ChildXBound, ChildYBound, Container, Create], CS: TYPE USING [EndsIn, EquivalentRope, SetPFCodes], CT: TYPE USING[AppendExtension, DetermineCompilation, Global, GlobalRecord, LoadBcdsAndResolveImports, MI, MIRecord, ModuleList, SetPossiblyBadAndValid, StartAllControlBcds, UnLoad], Directory: TYPE USING[Lookup], File: TYPE USING[Capability], FileIO: TYPE USING[Open, OpenFailed], IO: TYPE USING[Close, EndOf, GetChar, Handle, noWhereStream, Put, PutChar, PutF, PutFR, PutRope, ResetUserAbort, rope, SetUserAbort, string, time, UserAborted], Labels: TYPE USING [Create, Label, Set], List: TYPE USING[DRemove, Reverse], Loader: TYPE USING[Instantiate, Start], MBQueue: TYPE USING[Create, CreateMenuEntry, CreateButton, Flush], Menus: TYPE USING [CreateEntry, CreateMenu, InsertMenuEntry, Menu, MenuProc], PrincOps: TYPE USING[ControlModule], Rope: TYPE USING[Cat, Fetch, Find, Flatten, FromChar, Length, Lower, ROPE, Text], RopeInline: TYPE USING[InlineFlatten], Rules: TYPE USING [Create, Rule], Runtime: TYPE USING[IsBound], Space: TYPE USING[nullHandle], TypeScript: TYPE USING[TS, Create], UserProfile: TYPE USING[Boolean, Token], ViewerClasses: TYPE USING [Viewer], ViewerEvents: TYPE USING[EventProc, EventRegistration, RegisterEventProc, UnRegisterEventProc], ViewerIO: TYPE USING[CreateViewerStreams], ViewerOps: TYPE USING [AddProp, CreateViewer, EstablishViewerPosition, FetchProp, PaintViewer, SetMenu, SetOpenHeight], ViewerTools: TYPE USING [GetContents, MakeNewTextViewer, SetContents, SetSelection]; CTIntImpl: CEDAR PROGRAM IMPORTS CompilerOps, Containers, CS, CT, Directory, FileIO, IO, Labels, List, Loader, MBQueue, Menus, Rope, RopeInline, Rules, Runtime, Space, TypeScript, UserProfile, ViewerEvents, ViewerOps, ViewerIO, ViewerTools = { -- MDS usage! makeDebuggingWindow: BOOL ← FALSE; -- only set once, not monitored globalList: LIST OF CT.Global; -- not properly monitored destroyEventRegistration: ViewerEvents.EventRegistration; -- end of MDS -- these are commands for the viewers world entryHeight: CARDINAL = 15; entryVSpace: CARDINAL = 7; entryHSpace: CARDINAL = 10; -- this is called by the Start code and also by the Another button BuildOuter: PROC RETURNS[g: CT.Global] = { ttyTypeScript, msgTypeScript, dTypeScript: TypeScript.TS; vName: Rope.ROPE ← IO.PutFR["Replacement Tool, started on %t", IO.time[]]; menu: Menus.Menu ← Menus.CreateMenu[lines: 2]; g ← NEW[CT.GlobalRecord ← [fakebcdspace: Space.nullHandle]]; g.container ← Containers.Create[info: [name: vName, iconic: FALSE, scrollable: FALSE]]; ViewerOps.AddProp[g.container, $CTGlobalRef, g]; g.q ← MBQueue.Create[]; -- first row of menu items Menus.InsertMenuEntry[menu, Menus.CreateEntry["Stop", StopProc, g], 0]; Menus.InsertMenuEntry[menu, MBQueue.CreateMenuEntry[g.q, "UnLoad", UnLoadProc, g], 0]; Menus.InsertMenuEntry[menu, MBQueue.CreateMenuEntry[g.q, "Continue", ContinueProc, g], 0]; Menus.InsertMenuEntry[menu, MBQueue.CreateMenuEntry[g.q, "Begin", BeginProc, g], 0]; Menus.InsertMenuEntry[menu, MBQueue.CreateMenuEntry[g.q, "Another", AnotherProc, g], 0]; -- second row of menu items Menus.InsertMenuEntry[menu, MBQueue.CreateMenuEntry[g.q, "FlushCache", FlushCacheProc, g], 1]; Menus.InsertMenuEntry[menu, MBQueue.CreateMenuEntry[g.q, "Start", StartProc, g], 1]; Menus.InsertMenuEntry[menu, MBQueue.CreateMenuEntry[g.q, "Load", LoadProc, g], 1]; Menus.InsertMenuEntry[menu, MBQueue.CreateMenuEntry[g.q, "Compile", CompileProc, g], 1]; -- ViewerOps.SetMenu[g.container, menu, FALSE]; [ttyTypeScript, msgTypeScript, dTypeScript] ← BuildUserInput[g]; -- kludge required for multiple rows in menus ViewerOps.EstablishViewerPosition[g.container, g.container.wx, g.container.wy, g.container.ww, g.container.wh]; ViewerOps.PaintViewer[g.container, all]; [in: g.ttyin, out: g.ttyout] ← ViewerIO.CreateViewerStreams[viewer: ttyTypeScript, name: NIL]; [out: g.msgout] ← ViewerIO.CreateViewerStreams[viewer: msgTypeScript, name: NIL]; IF makeDebuggingWindow THEN [out: g.dout] ← ViewerIO.CreateViewerStreams[viewer: dTypeScript, name: NIL] ELSE g.dout ← IO.noWhereStream; CS.SetPFCodes[g.ttyout]; CS.SetPFCodes[g.msgout]; CS.SetPFCodes[g.dout]; IF g.attachEditor THEN AttachSymbiote[g]; globalList ← CONS[g, globalList]; }; BuildUserInput: PROC[g: CT.Global] RETURNS[ttyTypeScript, msgTypeScript, dTypeScript: TypeScript.TS] = { heightSoFar: CARDINAL; l: ViewerClasses.Viewer; rule: Rules.Rule; CreateButton: PROC[bname, lname: Rope.Text, newLine: BOOL, drawRule: BOOL ← FALSE] RETURNS[button: Buttons.Button, label: Labels.Label] = { x: CARDINAL; IF newLine THEN { IF l = NIL THEN heightSoFar ← entryVSpace/2 ELSE heightSoFar ← heightSoFar + entryVSpace + l.wh; IF drawRule THEN { rule ← Rules.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]]; Containers.ChildXBound[g.container, rule]; heightSoFar ← heightSoFar + entryVSpace; }; x ← 0; } ELSE x ← l.wx + l.ww + entryHSpace; l ← button ← MBQueue.CreateButton[q: g.q, info: [name: bname, parent: g.container, border: FALSE, wx: x, wy: heightSoFar], proc: PushButton, clientData: g]; IF lname ~= NIL THEN l ← label ← Labels.Create[info: [name: lname, parent: g.container, wx: button.wx + button.ww + entryHSpace, wy: heightSoFar, border: TRUE]]; }; -- first line [g.compileButton, ] ← CreateButton["Compile:", NIL, TRUE]; l ← g.compileViewer ← ViewerTools.MakeNewTextViewer[info: [parent: g.container, wx: l.wx+l.ww+entryHSpace, wy: heightSoFar, ww: 100, wh: entryHeight, data: NIL, scrollable: FALSE, border: FALSE], paint: FALSE]; Containers.ChildXBound[g.container, g.compileViewer]; heightSoFar ← heightSoFar+--entryVSpace/2+--l.wh; -- -- second line [g.confirmButton, g.confirmViewer] ← CreateButton["ConfirmCompiles:", "FALSE", TRUE]; IF g.confirmCompiles THEN Labels.Set[g.confirmViewer, "TRUE"]; [g.attachEditorButton, g.attachEditorLabel] ← CreateButton["AttachEditor:", "FALSE", FALSE]; IF g.attachEditor THEN Labels.Set[g.attachEditorLabel, "TRUE"]; heightSoFar ← heightSoFar+ entryVSpace/2+l.wh; -- -- first the msg window -- now the line above the typescript rule ← Rules.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]]; Containers.ChildXBound[g.container, rule]; heightSoFar ← heightSoFar+entryVSpace/2; -- now the typescript msgTypeScript ← TypeScript.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 25, border: FALSE]]; Containers.ChildXBound[g.container, msgTypeScript]; heightSoFar ← heightSoFar + entryVSpace + 20; -- now the line above the typescript rule ← Rules.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]]; Containers.ChildXBound[g.container, rule]; heightSoFar ← heightSoFar+entryVSpace/2; -- now the typescript ttyTypeScript ← TypeScript.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 80, border: FALSE]]; -- 800 due to viewers bug heightSoFar ← heightSoFar + entryVSpace + 80; Containers.ChildXBound[g.container, ttyTypeScript]; IF makeDebuggingWindow THEN { -- now the line above the typescript rule ← Rules.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]]; Containers.ChildXBound[g.container, rule]; heightSoFar ← heightSoFar+entryVSpace/2; -- now the debugging typescript dTypeScript ← TypeScript.Create[info: [parent: g.container, wx: 0, wy: heightSoFar, ww: 0, wh: 800, border: FALSE]]; -- 800 due to viewers bug Containers.ChildXBound[g.container, dTypeScript]; Containers.ChildYBound[g.container, dTypeScript]; } ELSE Containers.ChildYBound[g.container, ttyTypeScript]; ViewerOps.SetOpenHeight[g.container, heightSoFar + 200]; }; PushButton: Buttons.ButtonProc = { g: CT.Global ← NARROW[clientData]; SELECT NARROW[parent, ViewerClasses.Viewer] FROM g.compileButton => ViewerTools.SetSelection[g.compileViewer, NIL]; g.confirmButton => { g.confirmCompiles ← NOT g.confirmCompiles; Labels.Set[g.confirmViewer, IF g.confirmCompiles THEN "TRUE" ELSE "FALSE"]; }; g.attachEditorButton => { g.attachEditor ← NOT g.attachEditor; Labels.Set[g.attachEditorLabel, IF g.attachEditor THEN "TRUE" ELSE "FALSE"]; IF g.attachEditor THEN AttachSymbiote[g] ELSE DetachSymbiote[g, TRUE]; }; ENDCASE => ERROR; }; AnotherProc: Menus.MenuProc = { [] ← BuildOuter[]; -- make another compiler tool }; BeginProc: Menus.MenuProc = { g: CT.Global ← NARROW[clientData]; { ENABLE ABORTED, IO.UserAborted => { g.ttyout.ResetUserAbort[]; g.ttyout.PutF["Begin Aborted\n"]; GOTO out; }; errors: BOOL; CT.UnLoad[g, TRUE]; g.moduleList ← NIL; g.noticeList ← NIL; errors ← ParseCompileList[g]; IF errors THEN GOTO badComp; errors ← CT.DetermineCompilation[g, FALSE]; IF errors THEN GOTO badComp; g.compiledOk ← TRUE; errors ← CT.LoadBcdsAndResolveImports[g, FALSE]; g.loadedOk ← errors; IF NOT errors THEN CT.StartAllControlBcds[g]; EXITS badComp => g.compiledOk ← FALSE; out => NULL; }}; ContinueProc: Menus.MenuProc = { g: CT.Global ← NARROW[clientData]; { ENABLE ABORTED, IO.UserAborted => { g.ttyout.ResetUserAbort[]; g.ttyout.PutF["Continue Aborted\n"]; GOTO out; }; errors: BOOL; UpdateNewFile[g]; errors ← CT.DetermineCompilation[g, TRUE]; IF NOT errors THEN errors ← CT.LoadBcdsAndResolveImports[g, TRUE]; EXITS out => NULL; }}; CompileProc: Menus.MenuProc = { g: CT.Global ← NARROW[clientData]; { ENABLE ABORTED, IO.UserAborted => { g.ttyout.ResetUserAbort[]; g.ttyout.PutF["Compilation Aborted\n"]; GOTO out; }; errors: BOOL; IF g.moduleList = NIL THEN { errors ← ParseCompileList[g]; IF errors THEN RETURN; }; errors ← CT.DetermineCompilation[g, g.fakebcdspace ~= Space.nullHandle]; g.compiledOk ← errors; EXITS out => NULL; }}; LoadProc: Menus.MenuProc = { g: CT.Global ← NARROW[clientData]; { ENABLE ABORTED, IO.UserAborted => { g.ttyout.ResetUserAbort[]; g.ttyout.PutF["Load Aborted\n"]; GOTO out; }; IF g.moduleList = NIL THEN g.ttyout.PutF["Error - must Compile before Loading.\n"] ELSE { errors: BOOL ← CT.LoadBcdsAndResolveImports[g, TRUE]; g.loadedOk ← NOT errors; }; EXITS out => NULL; }}; StartProc: Menus.MenuProc = { g: CT.Global ← NARROW[clientData]; { ENABLE ABORTED, IO.UserAborted => { g.ttyout.ResetUserAbort[]; g.ttyout.PutF["Start Aborted\n"]; GOTO out; }; IF g.loadedOk THEN CT.StartAllControlBcds[g] ELSE g.ttyout.PutF["Error - cannot load.\n"]; EXITS out => NULL; }}; UnLoadProc: Menus.MenuProc = { g: CT.Global ← NARROW[clientData]; { ENABLE ABORTED, IO.UserAborted => { g.ttyout.ResetUserAbort[]; g.ttyout.PutF["UnLoad Aborted\n"]; GOTO out; }; CT.UnLoad[g, TRUE]; g.moduleList ← NIL; EXITS out => NULL; }}; -- not on the queue StopProc: Menus.MenuProc = { g: CT.Global ← NARROW[clientData]; MBQueue.Flush[g.q]; g.ttyout.SetUserAbort[]; }; FlushCacheProc: Menus.MenuProc = { g: CT.Global ← NARROW[clientData]; g.bcdTabList ← NIL; }; ParseCompileList: PROC[g: CT.Global] RETURNS[errors: BOOL] = { errors ← ParseString[g, ViewerTools.GetContents[g.compileViewer]]; IF errors THEN RETURN; TRUSTED{g.moduleList ← LOOPHOLE[List.Reverse[LOOPHOLE[g.moduleList]]]}; g.msgout.PutChar['\n]; }; -- may call itself recursively ParseString: PROC[g: CT.Global, string: Rope.ROPE] RETURNS[errors: BOOL] = { ch: CHAR; mi: CT.MI; inx: CARDINAL ← 0; start: CARDINAL; slash: INT; srcName, bcdName, item: Rope.Text; switches: CompilerOps.LetterSwitches; controlModule, explicitSortSwitch, exportedInterface: BOOL; errors ← FALSE; WHILE inx < string.Length[] DO WHILE inx < string.Length[] DO ch ← string.Fetch[inx]; IF ch ~= ' AND ch ~= '\n THEN EXIT; g.msgout.PutChar[' ]; inx ← inx + 1; ENDLOOP; start ← inx; WHILE inx < string.Length[] DO ch ← string.Fetch[inx]; IF ch = ' OR ch = '\n THEN EXIT; inx ← inx + 1; ENDLOOP; IF inx = start THEN LOOP; item ← Rope.Flatten[string, start, inx-start]; IF item.Fetch[0] = '@ THEN { in: IO.Handle; fn, r: Rope.ROPE; fn ← Rope.Flatten[item, 1]; IF Rope.Find[fn, "."] = -1 THEN fn ← CT.AppendExtension[fn, ".cl"L]; in ← FileIO.Open[fn, read ! FileIO.OpenFailed => { g.ttyout.PutF["%s: cannot open\n", IO.rope[fn]]; GOTO badFile }]; WHILE NOT in.EndOf[] DO r ← r.Cat[Rope.FromChar[in.GetChar[]]]; ENDLOOP; in.Close[]; -- recursive call IF ParseString[g, r] THEN GOTO badFile; LOOP; }; g.msgout.PutRope[item]; IF item.Fetch[0] = '+ THEN { -- control module controlModule ← TRUE; item ← Rope.Flatten[item, 1]; } ELSE controlModule ← FALSE; IF item.Fetch[0] = '= THEN { -- export this interface exportedInterface ← TRUE; item ← Rope.Flatten[item, 1]; } ELSE exportedInterface ← FALSE; IF (slash ← Rope.Find[item, "/"]) >= 0 THEN { sstring: Rope.Text ← Rope.Flatten[item, slash+1]; item ← Rope.Flatten[item, 0, slash]; [switches, explicitSortSwitch] ← InterpolateSwitches[sstring]; } ELSE TRUSTED { switches ← CompilerOps.DefaultSwitches[]; explicitSortSwitch ← FALSE; }; IF NOT CS.EndsIn[item, ".bcd"L] THEN srcName ← CT.AppendExtension[item, ".Mesa"L] ELSE srcName ← NIL; bcdName ← CT.AppendExtension[item, ".Bcd"L]; mi ← NEW[CT.MIRecord ← [srcFileName: srcName, bcdFileName: bcdName, switches: switches, explicitSortSwitch: explicitSortSwitch, controlModule: controlModule, exportedInterface: exportedInterface]]; g.moduleList ← CONS[mi, g.moduleList]; ENDLOOP; EXITS badFile => RETURN[TRUE]; }; -- what to do about explicitSortSwitch? InterpolateSwitches: PROC[parms: Rope.Text] RETURNS[switches: CompilerOps.LetterSwitches, explicitSortSwitch: BOOL] = { i: CARDINAL ← 0; on: BOOL; ch: CHAR; -- set defaults TRUSTED{switches ← CompilerOps.DefaultSwitches[]}; -- switches['s] ← FALSE; the modeller defaults to /-s explicitSortSwitch ← FALSE; IF parms = NIL THEN RETURN; WHILE i < parms.Length[] DO on ← TRUE; IF parms.Fetch[i] = '- THEN { i ← i + 1; on ← FALSE; }; ch ← Rope.Lower[parms.Fetch[i]]; IF ch IN ['a .. 'z] THEN { switches[ch] ← on; IF ch = 's THEN explicitSortSwitch ← TRUE; }; i ← i + 1; ENDLOOP; }; LoadCompiler: PROC[out: IO.Handle] RETURNS[success: BOOL] = TRUSTED { cap: File.Capability; success ← TRUE; IF Runtime.IsBound[CompilerOps.DefaultSwitches] THEN RETURN[TRUE]; -- already loaded out.PutF["Loading Compiler ... "]; { ENABLE ANY => { out.PutF["failed.\n"]; GOTO out}; cm: PrincOps.ControlModule; cap ← Directory.Lookup["compiler.bcd"L]; [cm: cm] ← Loader.Instantiate[file: cap, offset: 1, codeLinks: TRUE]; Loader.Start[cm]; out.PutF["done.\n"]; EXITS out => success ← FALSE; }}; AttachSymbiote: PROC[g: CT.Global] = { IF g.attachEditorRef = NIL THEN g.attachEditorRef ← ViewerEvents.RegisterEventProc[CallProcedureForNotice, save]; g.msgout.Put[IO.string["Editor set to call this compile tool.\n"L]]; }; DetachSymbiote: PROC[g: CT.Global, print: BOOL] = { IF g.attachEditorRef ~= NIL THEN ViewerEvents.UnRegisterEventProc[g.attachEditorRef, save]; g.attachEditorRef ← NIL; IF print THEN g.msgout.Put[IO.string["Editor detached from this compile tool.\n"L]]; }; -- this is the procedure called by the editor -- can't print anything in this procedure CallProcedureForNotice: ViewerEvents.EventProc = { ENABLE ANY => GOTO out; flat: Rope.Text; IF viewer.file = NIL THEN RETURN; flat ← RopeInline.InlineFlatten[viewer.file]; FOR l: LIST OF CT.Global ← globalList, l.rest UNTIL l = NIL DO l.first.noticeList ← CONS[flat, l.first.noticeList]; ENDLOOP; EXITS out => NULL; }; UpdateNewFile: PROC[g: CT.Global] = { FOR l: LIST OF Rope.Text ← g.noticeList, l.rest UNTIL l = NIL DO FOR ml: CT.ModuleList ← g.moduleList, ml.rest UNTIL ml = NIL DO IF CS.EquivalentRope[l.first, ml.first.srcFileName] THEN { g.ttyout.PutF["Noticing edited version of %s.\n", IO.rope[l.first]]; ml.first.bcdValid ← FALSE; CT.SetPossiblyBadAndValid[ml.first]; EXIT; }; ENDLOOP; ENDLOOP; g.noticeList ← NIL; }; MyDestroy: ViewerEvents.EventProc = { g: CT.Global; IF event ~= destroy THEN RETURN; g ← NARROW[ViewerOps.FetchProp[viewer, $CTGlobalRef]]; IF g ~= NIL THEN DetachSymbiote[g, FALSE]; IF globalList = NIL THEN { ViewerEvents.UnRegisterEventProc[destroyEventRegistration, destroy]; destroyEventRegistration ← NIL; RETURN; }; FOR l: LIST OF CT.Global ← globalList, l.rest UNTIL l = NIL DO IF l.first.container = viewer THEN TRUSTED { globalList ← LOOPHOLE[List.DRemove[ref: l.first, list: LOOPHOLE[globalList]]]; RETURN; }; ENDLOOP; }; BeginProcFromUser: PROC[g: REF ANY] = { BeginProc[parent: NIL, clientData: g, mouseButton: red, shift: FALSE, control: FALSE]; }; { initialCL: Rope.ROPE; g: CT.Global; -- start code makeDebuggingWindow ← UserProfile.Boolean["CompileTool.Wizard", FALSE];-- default is false destroyEventRegistration ← ViewerEvents.RegisterEventProc[MyDestroy, destroy]; g ← BuildOuter[]; initialCL ← UserProfile.Token["CompileTool.AutoLoad", NIL]; IF initialCL ~= NIL THEN ViewerTools.SetContents[g.compileViewer, initialCL]; [] ← LoadCompiler[g.ttyout]; IF initialCL ~= NIL THEN -- this simulates the button push -- MBQueue.QueueClientAction[g.q, BeginProcFromUser, g]; BeginProcFromUser[g]; -- this is the actual call, above code doesn't work }}.