-- File [Ivy]<Nelson>Lupine>LupineUserInterfaceImpl.mesa.
-- Last edited by BZM on 2-May-82 23:18:33.
-- This interface uses a standard command interpreter called the Commander,
-- which is also used by the Lister. While its teletype style of interaction
-- is poor compared to the tools paradigm, it has the great advantage of
-- being called from the command line, therefore making Lupine easily
-- useable from command files. Keep this in mind before discarding the
-- Commander for something else. All anticipated clients intend to use
-- Lupine via command files.
DIRECTORY
CWF USING [SetWriteProcedure, SWF1, WF0, WF1, WF2, WFCR],
CommanderDefs USING [
AddCommand, CommandBlockHandle, InitCommander, WaitCommands],
Exec USING [AddCommand, w],
LongString USING [EquivalentStrings],
LupineManager USING [
ErrorHandlerProc, Language, ParamPassingMethod,
String, TranslateRemoteInterface],
Runtime USING [CallDebugger, GetBcdTime],
System USING [GreenwichMeanTime],
TTY USING [PutChar, ResetUserAbort, UserAbort];
LupineUserInterfaceImpl: PROGRAM
IMPORTS
CommanderDefs, CWF, Exec, LongString, LupineManager, Runtime, TTY
= BEGIN
-- Initialization and command procedures.
herald: STRING = [100];
PutLogChar: PROC [char: CHARACTER] = {TTY.PutChar[Exec.w, char]};
StartLupine: PROCEDURE =
BEGIN
buildTime: System.GreenwichMeanTime ← Runtime.GetBcdTime[];
CWF.SWF1[herald,
"*NLupine 1 of %LT: Cedar's RPC Stub Translator."L, @buildTime ];
CommanderDefs.InitCommander[herald];
AddLupineCommands;
[] ← CWF.SetWriteProcedure[PutLogChar];
Exec.AddCommand["Lupine.~"L, RunLupine];
END;
RunLupine: PROCEDURE = {SetCommandDefaults; CommanderDefs.WaitCommands[]};
CheckAbort: PROCEDURE =
-- IF ControlDEL then cause process ABORT thru Commander to Executive.
-- The Exec will catch it and UNWIND us, and then the Commander too.
BEGIN
IF TTY.UserAbort[] THEN {TTY.ResetUserAbort; ERROR ABORTED};
END;
-- Command definitions for the Commander.
AddLupineCommands: PROCEDURE =
-- The Commander does not make copies of these strings and
-- expects them to last forever (e.g., live in a global frame).
BEGIN OPEN CommanderDefs;
cmd: CommandBlockHandle;
cmd ← AddCommand["TranslateInterface", LOOPHOLE[TranslateInterface], 1];
cmd.params[0] ←
[type: string, prompt: "Filename of compiled remote interface"];
cmd ← AddCommand[ "TargetLanguage", LOOPHOLE[SetTargetLanguage], 1];
cmd.params[0] ←
[type: string,
prompt: "Target language for RPC modules (Cedar, Mesa) [Cedar]"];
cmd ← AddCommand[
"DefaultParameterPassing", LOOPHOLE[SetParameterPassing], 1];
cmd.params[0] ←
[type: string,
prompt: "Default passing method (VAR, VALUE, RESULT, HANDLE) [VALUE]"];
cmd ← AddCommand["InterMdsCalls", LOOPHOLE[SetInterMdsCalls], 1];
cmd.params[0] ←
[type: boolean,
prompt: "Translate interfaces to handle interMDS calls only [FALSE]"];
cmd←AddCommand["FreeServerArguments", LOOPHOLE[SetFreeServerArgs], 1];
cmd.params[0] ←
[type: boolean,
prompt: "Automatically deallocate all server heap arguments [TRUE]"];
cmd ← AddCommand["InlineDispatcherStubs", LOOPHOLE[SetInlineStubs], 1];
cmd.params[0] ←
[type: boolean,
prompt: "Use INLINE stubs in the RpcServerImpl's dispatcher [TRUE]"];
cmd←AddCommand["DynamicHeapNEWs", LOOPHOLE[SetDynamicHeapNEWs], 2];
cmd.params[0] ←
[type: numeric,
prompt: "Maximum number of dynamic heap NEWs per call [50]"];
cmd.params[1] ←
[type: numeric,
prompt: "Maximum number of dynamic MDS NEWs per call [50]"];
cmd ← AddCommand["LineLength", LOOPHOLE[SetLineLength], 1];
cmd.params[0] ←
[type: numeric, prompt: "Desired line length of output files [82]"];
cmd ← AddCommand["Spy", LOOPHOLE[CallSpy], 0];
cmd ← AddCommand["CallDebugger", LOOPHOLE[SetCallDebugger], 1];
cmd.params[0] ←
[type: boolean,
prompt: "For wizards only: Call debugger on user errors [FALSE]"];
END; -- AddLupineCommands.
-- Individual command processors.
targetLanguage: LupineManager.Language;
defaultParamPassing: LupineManager.ParamPassingMethod;
interMdsCalls: BOOLEAN;
freeServerArgs: BOOLEAN;
inlineDispatcherStubs: BOOLEAN;
maxHeapAllocs, maxMdsAllocs: LONG INTEGER;
lineLength: LONG INTEGER;
callDebugger: BOOLEAN;
SetCommandDefaults: PROCEDURE =
INLINE BEGIN
targetLanguage ← Cedar;
defaultParamPassing ← Value;
interMdsCalls ← FALSE;
freeServerArgs ← TRUE;
inlineDispatcherStubs ← TRUE;
maxHeapAllocs ← maxMdsAllocs ← 50;
lineLength ← 82;
callDebugger ← FALSE;
END;
TranslateInterface: PROCEDURE [interfaceFile: STRING] =
BEGIN OPEN CWF;
aborted, errors, warnings: BOOLEAN ← FALSE;
HandleError: LupineManager.ErrorHandlerProc =
-- PROCEDURE [type: ErrorType, code: ErrorCode,
-- codeExplanation: String,
-- outputFileName: String←StringNIL,
-- outputFileCharPosition: LONG INTEGER,
-- problemCausingText: String←NIL ]
-- RETURNS [abortTranslation: BOOLEAN←FALSE];
BEGIN
CheckAbort;
SELECT type FROM
abort => { aborted ← TRUE; WF0["*NFatal error"L] };
error => { errors ← TRUE; WF0["*NError"L] };
warning => { warnings ← TRUE; WF0["*NWarning"L] };
ENDCASE => NULL;
IF outputFileName # NIL
THEN WF2[" at %S[%LD]"L, outputFileName, @outputFileCharPosition];
WF1[":*N %S*N"L, codeExplanation];
IF problemCausingText # NIL
THEN WF1[
" Problem-causing file, module, identifier, or type: %S*N"L,
problemCausingText ];
IF callDebugger THEN Runtime.CallDebugger["Tracking a Lupine problem..."L];
RETURN [abortTranslation: FALSE];
END; -- HandleError.
CheckAbort;
LupineManager.TranslateRemoteInterface [
interfaceBcdFilename: interfaceFile,
errorHandler: HandleError,
options: [
targetLanguage: targetLanguage,
defaultParamPassing:
(IF interMdsCalls THEN InterMds ELSE defaultParamPassing),
freeServerArguments: freeServerArgs,
inlineServerDispatcherStubs: inlineDispatcherStubs,
maxHeapAllocations: maxHeapAllocs,
maxMdsAllocations: maxMdsAllocs ],
desiredLineLength: lineLength ];
IF aborted OR errors OR warnings THEN WFCR;
WF2["Translation of %S %S.*N*N"L, interfaceFile,
(SELECT TRUE FROM
aborted => "aborted"L,
errors => "finished with errors"L,
warnings => "finished with warnings"L,
ENDCASE => "complete"L) ];
END; -- TranslateInterface.
SetTargetLanguage: PROCEDURE [language: STRING] =
BEGIN OPEN LongString;
SELECT TRUE FROM
EquivalentStrings[language, "Cedar"L] => targetLanguage ← Cedar;
EquivalentStrings[language, "Mesa"L] => targetLanguage ← Mesa;
ENDCASE => CWF.WF0[" Invalid language--no change made!*N"L];
END;
SetParameterPassing: PROCEDURE [kind: STRING] =
BEGIN OPEN LongString;
SELECT TRUE FROM
EquivalentStrings[kind, "VAR"L] => defaultParamPassing ← Var;
EquivalentStrings[kind, "VALUE"L] => defaultParamPassing ← Value;
EquivalentStrings[kind, "RESULT"L] => defaultParamPassing ← Result;
EquivalentStrings[kind, "HANDLE"L] => defaultParamPassing ← Handle;
ENDCASE => CWF.WF0[" Invalid passing method--no change made!*N"L];
END;
SetInterMdsCalls: PROCEDURE [onOff: BOOLEAN] = {interMdsCalls ← onOff};
SetFreeServerArgs: PROCEDURE [onOff: BOOLEAN] =
BEGIN freeServerArgs ← onOff END;
SetInlineStubs: PROCEDURE [onOff: BOOLEAN] =
BEGIN inlineDispatcherStubs ← onOff END;
SetDynamicHeapNEWs: PROCEDURE [heap, mds: CARDINAL] =
BEGIN maxHeapAllocs ← heap; maxMdsAllocs ← mds END;
SetLineLength: PROCEDURE [length: CARDINAL] = {lineLength ← length};
SetCallDebugger: PROCEDURE [onOff: BOOLEAN] = {callDebugger ← onOff};
CallSpy: PROCEDURE = {Runtime.CallDebugger["Do some spying..."L]};
-- Module Initialization.
StartLupine;
END.