-- 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 }}.