Interface.mesa
last modified by Satterthwaite, May 12, 1983 5:16 pm
Last Edited by: Maxwell, September 14, 1983 3:15 pm
Last Edited by: Paul Rovner, December 4, 1983 11:57 am
DIRECTORY
Ascii: TYPE USING [Lower],
BasicTime: TYPE USING [GMT, Now, Period, ToNSTime],
Commander: TYPE USING [Handle, Register],
CommandUtil: TYPE USING [
PairList, Echo, Failed, GetNth, GetRootName, ListLength, Parse, SetExtension],
CompilerOps: TYPE USING [
LetterSwitches, StreamId, Transaction,
AppendHerald, DefaultSwitches, DoTransaction, Punt, Start, Stop],
FileParms: TYPE USING [BindingProc, nullActual],
FileParmOps: TYPE USING [ClearAList, Finalize, Initialize, SetAList],
FileViewerOps: TYPE USING [ShowLog, WaitUntilSaved],
FS: TYPE USING [nullOpenFile, OpenFile, StreamOpen, FileInfo, Error, Delete],
IO: TYPE USING [Close, Error, int, Put, PutChar, PutRope, rope, STREAM, time, RIS],
Process: TYPE USING [GetPriority, Priority, priorityBackground, SetPriority],
ProcessExtras: TYPE USING [CheckForAbort],
Resource: TYPE USING [AbortProc, Acquire, Release],
Rope: TYPE USING [Cat, Fetch, Length, ROPE],
TimeStamp: TYPE USING [Null],
UserProfile: TYPE USING [Boolean, Token];
Interface: PROGRAM
IMPORTS
Ascii, BasicTime, Commander, CommandUtil, CompilerOps, FileParmOps, FileViewerOps, FS,
IO, Process, ProcessExtras, Resource, Rope, UserProfile
= {
Outcome: TYPE = {ok, warnings, errors, aborted};
parms: REF CompilerOps.Transaction = NEW[CompilerOps.Transaction];
standardDefaults: CompilerOps.LetterSwitches = CompilerOps.DefaultSwitches[];
switchDefaults: CompilerOps.LetterSwitches;
sourceName, objectName, errorName, rootName: Rope.ROPENIL;
sourceStream, objectStream, errorStream: IO.STREAM ← NIL;
useLog: BOOL;  -- use compiler.log for error reporting
log: IO.STREAM ← NIL;
Compile: SAFE PROC [cmd: Commander.Handle]
RETURNS [result: REFNIL, msg: Rope.ROPENIL] ~ TRUSTED {
userAbort: BOOLFALSE; -- set by ^DEL, STOP
errors, warnings: BOOLFALSE;
priority: Process.Priority = Process.GetPriority[];
compilerStartTime, moduleStartTime: BasicTime.GMT;
moduleCount: CARDINAL ← 0;
compilerSwitches: Rope.ROPE ← UserProfile.Token["Compiler.Switches"];
cmdStream: IO.STREAM;
IF UserProfile.Boolean["Compiler.SeparateLogs", FALSE]
THEN compilerSwitches ← Rope.Cat[compilerSwitches, "-g"];
IF compilerSwitches.Length[] # 0
THEN {
cmd.commandLine ← Rope.Cat["/", compilerSwitches, " ", cmd.commandLine];
};
cmdStream ← IO.RIS[cmd.commandLine];
acquire the compiler's resource lock; await success
{
otherOwner: Rope.ROPE;
success: BOOLFALSE;
abortProc: Resource.AbortProc = TRUSTED{
-- PROC [data: REF ANY] RETURNS[abort: BOOL];
abort ← FALSE;
ProcessExtras.CheckForAbort[! ABORTED => {abort ← TRUE; CONTINUE}];
};
[success, otherOwner] ← Resource.Acquire[
resource: $Compiler, owner: "Compiler", waitForIt: FALSE];
IF NOT success THEN {
cmd.out.PutRope[Rope.Cat["Waiting for ", otherOwner, " to finish..."]];
[success, ] ← Resource.Acquire
[resource: $Compiler, owner: "Compiler", waitForIt: TRUE, abortProc: abortProc];
IF NOT success
THEN RETURN[$Failure, "ABORTED"]
ELSE cmd.out.PutRope["proceeding\n"];
};
};
do the compilation
Process.SetPriority[Process.priorityBackground];
BEGIN ENABLE UNWIND => {Process.SetPriority[priority]; [] ← Resource.Release[$Compiler]};
StartPass: PROC [pass: CARDINAL] RETURNS [goOn: BOOL] = {
userAbort ← FALSE;
ProcessExtras.CheckForAbort[! ABORTED => {userAbort ← TRUE; CONTINUE}];
cmd.out.PutRope[" ." ! ABORTED => {userAbort ← TRUE; CONTINUE}];
IF userAbort THEN cmd.out.PutRope[" aborted."];
RETURN [~userAbort]};
compilerStartTime ← BasicTime.Now[];
switchDefaults ← CompilerOps.DefaultSwitches[];
parms.fileParms ← FileParmOps.Initialize[];
{ ENABLE UNWIND => FileParmOps.Finalize[];
CompilerOps.Start[];
{ ENABLE UNWIND => CompilerOps.Stop[];
IF log = NIL THEN log ← FS.StreamOpen[fileName: "Compiler.log", accessOptions: $create];
{ ENABLE UNWIND => {log.Close[]; log ← NIL};
WriteHerald[log, NIL];
DO
first: BOOL;
args, results: CommandUtil.PairList;
switches: Rope.ROPENIL;
localPause: BOOL;
sense: BOOL;
BEGIN -- for EXITS clause
parms.switches ← switchDefaults; parms.switches['p] ← FALSE;
parms.debugPass ← CARDINAL.LAST;
parms.getStream ← GetStream; parms.startPass ← StartPass;
parms.objectBytes ← 0; parms.objectFrameSize ← 0; parms.linkCount ← 0;
parms.nErrors ← 0; parms.nWarnings ← 0;
parms.sourceTokens ← 0;
[sourceName, args, results, switches] ←
CommandUtil.Parse[cmdStream ! CommandUtil.Failed => GOTO badSyntax];
IF sourceName = NIL AND switches = NIL THEN EXIT;
IO.PutRope[log, "\nCommand: "];
CommandUtil.Echo[log, sourceName, args, results, switches];
IF CommandUtil.ListLength[results] > 1 THEN GOTO badSemantics;
IF sourceName = NIL THEN GOTO globalSwitches;
rootName ← CommandUtil.GetRootName[IF CommandUtil.ListLength[results] = 1
THEN CommandUtil.GetNth[results, 0]
ELSE sourceName];
IF switches # NIL THEN {
sense ← TRUE;
FOR i: INT IN [0..switches.Length[]) DO
c: CHAR = switches.Fetch[i];
SELECT c FROM
'-, '~ => sense ← ~sense;
IN ['a..'z], IN ['A..'Z] => {parms.switches[Ascii.Lower[c]] ← sense; sense ← TRUE};
IN ['1..'5] => {parms.debugPass ← c-'0; sense ← TRUE};
ENDCASE;
ENDLOOP;
};
sourceName ← CommandUtil.SetExtension[sourceName, "mesa"];
FileViewerOps.WaitUntilSaved[sourceName, cmd.out
! ABORTED => {userAbort ← TRUE; GOTO truncateList}];
parms.source.locator ← sourceName;
IF CommandUtil.ListLength[results] # 0
THEN {
objectName ← CommandUtil.GetNth[list: results, n: 0, delete: TRUE];
results ← NIL;
}
ELSE objectName ← rootName;
parms.objectName ← CommandUtil.SetExtension[objectName, "bcd"];
parms.objectFile ← FS.nullOpenFile;
moduleCount ← moduleCount + 1;
feedback to user
IF beginItem # NIL THEN IF beginItem[sourceName, out] THEN LOOP;
cmd.out.Put[IO.rope["Compiling: "], IO.rope[rootName]];
first ← TRUE;
FOR c: CHAR IN ['a..'z] DO
sd: BOOL = (IF c = 'p THEN FALSE ELSE standardDefaults[c]);
IF parms.switches[c] # sd THEN {
IF first THEN {first ← FALSE; cmd.out.PutChar['/]};
IF sd THEN cmd.out.PutChar['-];
cmd.out.PutChar[c]};
ENDLOOP;
useLog ← parms.switches['g]; parms.switches['g] ← FALSE;
localPause ← parms.switches['p]; parms.switches['p] ← FALSE;
main line code
Initialize[ ! FS.Error => GOTO noSource];
{ ENABLE UNWIND => Finalize[userAbort];
FileParmOps.SetAList[args];
{ ENABLE UNWIND => FileParmOps.ClearAList[];
BindPattern: FileParms.BindingProc = {
parms.pattern ← actual;
parms.op ← IF actual = FileParms.nullActual THEN compile ELSE replace};
parms.fileParms.Binding[formalId: "$", formalType: NIL, binder: BindPattern];
NewLogLine[];
moduleStartTime ← BasicTime.Now[];
CompilerOps.DoTransaction[parms
!
CompilerOps.Punt => {
FileParmOps.ClearAList[];
Finalize[userAbort];
GOTO punt;
};
ABORTED => {
userAbort ← TRUE;
FileParmOps.ClearAList[];
Finalize[userAbort];
GOTO truncateList;
};
];
}; -- end ENABLE UNWIND => FileParmOps.ClearAList[];
FileParmOps.ClearAList[];
}; -- end ENABLE UNWIND => Finalize[];
Finalize[userAbort];
SELECT WriteResults[cmd.out, moduleStartTime ! IO.Error => CONTINUE] FROM
errors => errors ← TRUE;
warnings => warnings ← TRUE;
ENDCASE;
IF endItem # NIL THEN endItem[sourceName, out, outcome];
EXITS
globalSwitches => {
objectName ← NIL;
sense ← TRUE;
FOR i: INT IN [0..switches.Length[]) DO
c: CHAR = switches.Fetch[i];
SELECT c FROM
'-, '~ => sense ← ~sense;
IN ['a..'z] => {switchDefaults[c] ← sense; sense ← TRUE};
IN ['A..'Z] => {
switchDefaults[VAL['a.ORD+(c.ORD-'A.ORD)]] ← sense; sense ← TRUE};
ENDCASE => EXIT;
ENDLOOP;
};
noSource => {
log.Put[IO.rope[" -- source not found\n"], IO.time[]];
errors ← TRUE; parms.nErrors ← 1;
args ← NIL;
};
badSemantics => {
objectName ← NIL; errors ← TRUE;
log.PutRope[" -- Illegal command"];
};
END;
Here after completion of subcommand
NewLogLine[];
IF userAbort THEN {log.PutRope["\n... command aborted\n"]; GOTO truncateList};
IF (errors OR warnings) AND localPause THEN GOTO truncateList;
REPEAT
badSyntax => {IO.PutRope[log, "\n-- Illegal syntax"]; errors ← TRUE};
truncateList => switchDefaults['p] ← TRUE;
punt => {-- was Finalize[]; , but this is done by new UNWIND catch phrase
errors ← TRUE;
[] ← WriteResults[cmd.out, moduleStartTime ! IO.Error => CONTINUE];
NewLogLine[];
};
ENDLOOP;
Here after completion of all subcommands
}; -- end ENABLE UNWIND => log.Close[]
}; -- end ENABLE UNWIND => CompilerOps.Stop[]
CompilerOps.Stop[];
}; -- end ENABLE UNWIND => FileParmOps.Finalize[]
FileParmOps.Finalize[];
WriteClosing[cmd.out, compilerStartTime, moduleCount];
log.Close[]; log ← NIL;
IF userAbort OR errors OR warnings THEN result ← $Failure ELSE result ← $Success;
FileViewerOps.ShowLog[
fileName: "Compiler.log",
destroyIt: result # $Failure,
createIconic: UserProfile.Boolean["Compiler.IconicLogs", FALSE],
blinkIfIconic: UserProfile.Boolean["Compiler.BlinkLogs", TRUE]
];
END; -- end catch phrase to release the resource and reset the process priority
Process.SetPriority[priority];
[] ← Resource.Release[$Compiler];
}; -- end Compile
compiler sequencing
Initialize: PROC = {
sourceStream ← FS.StreamOpen[sourceName];
parms.sourceStream ← sourceStream;
parms.source.version ← TimeStamp.Null;
parms.source.version.time ← BasicTime.ToNSTime[FS.FileInfo[sourceName].created]};
Finalize: PROC [userAbort: BOOL] = {
IF objectStream # NIL THEN IO.Close[objectStream ! IO.Error => CONTINUE];
IF sourceStream # NIL THEN IO.Close[sourceStream ! IO.Error => CONTINUE];
IF errorStream # NIL AND errorStream # log THEN IO.Close[errorStream ! IO.Error => CONTINUE];
objectStream ← sourceStream ← errorStream ← NIL;
IF userAbort OR parms.nErrors # 0 THEN {
IF objectName # NIL THEN {
DO
FS.Delete[objectName ! FS.Error => IF error.code = $unknownFile THEN EXIT];
ENDLOOP;
};
};
IF errorName = NIL THEN {
errorName ← CommandUtil.SetExtension[rootName, "errlog"];
DO
FS.Delete[errorName ! FS.Error => IF error.code = $unknownFile THEN EXIT];
ENDLOOP;
};
};
WriteHerald: PROC [s: IO.STREAM, id: Rope.ROPE] = {
CompilerOps.AppendHerald[s];
IO.PutRope[s, " (Cedar 5 Version)\n"];
IF id # NIL THEN {IO.Put[s, IO.rope[id], IO.rope[" -- "]]};
IO.Put[s, IO.time[], IO.rope["\n"]]};
WriteResults: PROC [out: IO.STREAM, startTime: BasicTime.GMT]
RETURNS[outcome: Outcome] = {
OPEN IO;
elapsed: INT;
log.Put[rope[sourceName], rope[" -- "]];
elapsed ← BasicTime.Period[from: startTime, to: BasicTime.Now[]];
IF parms.nErrors # 0 THEN {
log.Put[rope["aborted, "], int[parms.nErrors], rope[" errors"]];
IF parms.nWarnings # 0 THEN {
log.Put[rope[" and "], int[parms.nWarnings], rope[" warnings"]]};
IF ~useLog THEN log.Put[IO.rope[" on "], IO.rope[errorName]];
log.Put[rope[", seconds: "], int[elapsed]]}
ELSE {
log.Put[rope["source tokens: "], int[parms.sourceTokens]];
log.Put[rope[", seconds: "], int[elapsed]];
IF parms.objectBytes # 0 THEN {
log.Put[rope["\n code bytes: "], int[parms.objectBytes]];
log.Put[rope[", links: "], int[parms.linkCount]];
log.Put[rope[", frame size: "], int[parms.objectFrameSize]];
IF parms.matched THEN PutChar[log, '.]};
IF parms.nWarnings # 0 THEN {
NewLogLine[];
log.Put[int[parms.nWarnings], rope[" warnings"]];
IF log # NIL AND ~useLog THEN log.Put[IO.rope[" on "], IO.rope[errorName]]}};
write to the Commander output file
out.PutRope[" "];
IF parms.nErrors = 0
THEN out.PutRope["no errors"]
ELSE out.Put[IO.int[parms.nErrors], IO.rope[" errors"]];
IF parms.nWarnings # 0
THEN out.Put[IO.rope[", "], IO.int[parms.nWarnings], IO.rope[" warnings"]];
out.PutRope[".\n"];
RETURN[SELECT TRUE FROM
parms.nErrors # 0 => errors,
parms.nWarnings # 0 => warnings,
ENDCASE => ok]};
WriteClosing: PROC [out: IO.STREAM, startTime: BasicTime.GMT, moduleCount: CARDINAL] = {
elapsed: INT;
out.PutRope["End of compilation\n"];
elapsed ← BasicTime.Period[from: startTime, to: BasicTime.Now[]];
IF moduleCount > 1 THEN
IO.Put[log, IO.rope["\nTotal elapsed seconds: "], IO.int[elapsed]];
NewLogLine[]};
NewLogLine: PROC = {log.PutRope["\n"]};
special output stream control
GetStream: PROC [id: CompilerOps.StreamId] RETURNS [s: IO.STREAM] = {
SELECT id FROM
source => RETURN[sourceStream];
object => {
IF objectStream = NIL THEN objectStream ← NewOutputStream[objectName];
RETURN[objectStream];
};
log => {IF errorStream = NIL THEN ErrorInit[]; RETURN[errorStream]};
ENDCASE => ERROR;
};
NewOutputStream: PROC [fileName: Rope.ROPE] RETURNS [stream: IO.STREAM] = {
stream ← FS.StreamOpen[fileName: fileName, accessOptions: $create]};
ErrorInit: PROC = {
IF errorStream = NIL THEN
IF useLog THEN errorStream ← log
ELSE {
errorName ← CommandUtil.SetExtension[rootName, "errlog"];
errorStream ← FS.StreamOpen[fileName: errorName, accessOptions: $create];
WriteHerald[errorStream, errorName];
errorStream.PutChar['\n]}};
START HERE
Commander.Register["Compiler", Compile, "Compile a list of cedar modules."];
}.