-- File [Ivy]<Nelson>Lupine>LupineDeclareUtilityImpl.mesa.
-- Last edited by BZM on March 18, 1982 10:56 AM.
-- This module cooperates with LupineDeclare*Impl to export LupineDeclare.
DIRECTORY
CWF USING [SWF2, WF1, WFC],
LongString USING [EqualStrings, EquivalentStrings],
LupineDeclare USING [
DirectoryItem, DirectoryList, DispatcherType,
EmptyDirectoryList, InterfaceUse, ModuleNameList ],
LupineDeclarePrivate USING [GetString, StringConstantType],
LupineManagerPrivate USING [
AllocString, Error, Indent, IsNull, Language,
MaxIdentifierLength, ModuleName,
Nest, Options, String, StringNIL,
WFL, WFL1, WFLL, WFS, WFS1, WFSL ],
LupineSymbolTable USING [
DirectoryProcedure, EnumerateDirectory, EnumerateTransfers,
IsAnonymous, PutTypeName, SymbolHandle, SymbolID,
SymbolName, SymbolType, SymbolUniqueID,
TransferProcedure, TypeHandle ];
LupineDeclareUtilityImpl: PROGRAM
IMPORTS
CWF, LongString, LupineManagerPrivate,
Private: LupineDeclarePrivate, ST: LupineSymbolTable
EXPORTS LupineDeclare, LupineDeclarePrivate
= BEGIN OPEN LupineManagerPrivate, LupineDeclare;
-- General symbol and type routines.
TransferName: PUBLIC PROCEDURE [transfer: ST.SymbolHandle, nameString: String]
RETURNS[name: String] =
BEGIN
IF ST.IsAnonymous[transfer]
THEN ERROR
ELSE RETURN[ST.SymbolName[transfer, nameString]];
END;
WriteTransferName: PUBLIC PROCEDURE [transfer: ST.SymbolHandle] =
BEGIN
name: AllocString = [MaxIdentifierLength];
WFS1[TransferName[transfer, name]];
END;
ParameterName: PUBLIC PROCEDURE [parameter: ST.SymbolHandle,
parameterNumber: INTEGER, nameString: String]
RETURNS [name: String] =
BEGIN
IF ST.IsAnonymous[parameter]
THEN BEGIN
paramID: LONG CARDINAL --ST.SymbolID-- ← ST.SymbolUniqueID[parameter];
CWF.SWF2[nameString, "anonP%Did%LU"L, @parameterNumber, @paramID];
RETURN[nameString];
END
ELSE RETURN[ST.SymbolName[parameter, nameString]];
END;
WriteParameterName: PUBLIC PROCEDURE [
parameter: ST.SymbolHandle, parameterNumber: INTEGER] =
BEGIN
name: AllocString = [MaxIdentifierLength];
WFS1[ParameterName[parameter, parameterNumber, name]];
END;
WriteSymbolName: PUBLIC PROCEDURE [symbol: ST.SymbolHandle] =
BEGIN
name: AllocString = [MaxIdentifierLength];
IF ST.IsAnonymous[symbol]
THEN Error[AnonymousIdentifier]
ELSE WFS1[ST.SymbolName[symbol, name]];
END;
WriteSymbolType: PUBLIC PROCEDURE [symbol: ST.SymbolHandle] =
BEGIN
WriteTypeName[ST.SymbolType[symbol]];
END;
WriteTypeName: PUBLIC PROCEDURE [
type: ST.TypeHandle, includeReadonly: BOOLEAN←TRUE ] =
BEGIN
ST.PutTypeName[
putProc: CWF.WFC,
type: type,
includeReadonly: includeReadonly,
rootInterfaceOpenName: ModuleName[openedInterface] ];
END;
-- Directory and interface manipulation routines.
Directory: PUBLIC PROCEDURE [
includeInterfaceDirectory: BOOLEAN←TRUE,
extraDirectories: DirectoryList←EmptyDirectoryList,
options: Options,
nest: Nest←0 ] =
BEGIN
printedOne: BOOLEAN←FALSE;
maxExtraDirLength: INTEGER = 6*16;
duplicate: PACKED ARRAY [0..maxExtraDirLength) OF BOOLEAN ← ALL[FALSE];
PrintDirItem: PROCEDURE [dirItem: DirectoryItem, file: String←StringNIL] =
BEGIN
hasFileName: BOOLEAN =
~IsNull[file] AND ~LongString.EquivalentStrings[dirItem.module, file];
IF ~dirItem.forLanguage[options.targetLanguage] OR IsNull[dirItem.module]
THEN RETURN;
IF printedOne
THEN WFS[",*N"L, Indent[nest+1]]
ELSE BEGIN
WFSL["*N*N"L, Indent[nest], "DIRECTORY*N"L, Indent[nest+1]];
printedOne ← TRUE;
END;
WFS[dirItem.module];
IF hasFileName THEN WFS[": FROM """L, file, """"L];
SELECT TRUE FROM
dirItem.usingAll # StringNIL =>
WFS[" USING ["L, dirItem.usingAll, "]"L];
dirItem.usingSome # StringNIL =>
WFS[" --USING SOME OF ["L, dirItem.usingSome, "]--"L];
ENDCASE => NULL;
END; -- PrintDirItem.
IF LENGTH[extraDirectories] > maxExtraDirLength THEN ERROR;
IF includeInterfaceDirectory
THEN BEGIN
PrintInterfaceDirItem: ST.DirectoryProcedure =
BEGIN
FOR dir: CARDINAL IN [0..LENGTH[extraDirectories]) DO
IF LongString.EqualStrings[extraDirectories[dir].module, moduleName]
THEN {duplicate[dir] ← TRUE; EXIT};
ENDLOOP;
PrintDirItem[dirItem: [module: moduleName], file: fileName];
END; -- PrintInterfaceDirItem.
[] ← ST.EnumerateDirectory[PrintInterfaceDirItem];
END;
FOR dir: CARDINAL IN [0..LENGTH[extraDirectories]) DO
-- Must do this list second so that USING conflicts are avoided.
IF ~duplicate[dir] THEN PrintDirItem[dirItem: extraDirectories[dir]];
ENDLOOP;
IF printedOne THEN WFS1[";*N"L];
END;
ModuleHead: PUBLIC PROCEDURE [
moduleNames: ModuleNameList,
moduleType: String,
interfaceList: DirectoryList←EmptyDirectoryList,
options: Options,
nest: Nest←0 ] =
BEGIN
UseKeywords: ARRAY InterfaceUse OF RECORD [begin, end: String] = [
imports: ["IMPORTS "L, "*N"L], exports: ["EXPORTS "L, "*N"L],
shares: ["SHARES "L, "*N"L], beginOpen: ["= BEGIN OPEN "L, ";*N"L] ];
hasThisUse: ARRAY InterfaceUse OF BOOLEAN ← ALL[FALSE];
IF LENGTH[moduleNames]=0 OR IsNull[moduleType] THEN ERROR;
FOR item: CARDINAL IN [0..LENGTH[interfaceList]) DO
FOR use: InterfaceUse IN InterfaceUse DO
IF interfaceList[item].usedIn[use] THEN hasThisUse[use] ← TRUE;
ENDLOOP;
ENDLOOP;
WFS["*N*N"L, Indent[nest]];
FOR name: CARDINAL IN [0..LENGTH[moduleNames]) DO
IF name > 0 THEN WFS1[", "L];
WFS[moduleNames[name]];
ENDLOOP;
WFS[": "L, moduleType, "*N"L];
FOR use: InterfaceUse IN InterfaceUse DO
IF hasThisUse[use] THEN
InterfaceList [ nest: nest+1,
use: use,
targetSystem: options.targetLanguage,
interfaceList: interfaceList,
beginText: UseKeywords[use].begin,
endText: UseKeywords[use].end ];
ENDLOOP;
IF ~hasThisUse[beginOpen] THEN WFL1[nest+1, "= BEGIN"L];
END;
InterfaceList: PUBLIC PROCEDURE [
use: InterfaceUse,
targetSystem: Language,
interfaceList: DirectoryList,
beginText, endText: String←StringNIL,
nest: Nest ] =
BEGIN
printedOne: BOOLEAN←FALSE;
WFS[Indent[nest], beginText];
FOR item: CARDINAL IN [0..LENGTH[interfaceList]) DO
interface: DirectoryItem = interfaceList[item];
IF ~interface.usedIn[use]
OR ~interface.forLanguage[targetSystem]
OR IsNull[interface.module]
THEN LOOP;
IF printedOne THEN WFS1[", "L] ELSE printedOne ← TRUE;
IF use=beginOpen OR (use=imports AND ~interface.usedIn[beginOpen])
THEN IF ~IsNull[interface.openName] THEN WFS[interface.openName, ": "L];
WFS[interface.module];
ENDLOOP;
WFS1[endText];
END;
-- Other code generation routines.
LastLupineTransferIndex: INTEGER = 3B;
ProcedureIndex: PUBLIC PROCEDURE [nest: Nest←1] =
BEGIN
TransferEnumeration[ nest: nest,
enumerationName: Private.GetString[procedureIndex],
procs: TRUE ];
END;
SignalIndex: PUBLIC PROCEDURE [nest: Nest←1] =
BEGIN
TransferEnumeration[ nest: nest,
enumerationName: Private.GetString[signalIndex],
exceptions: TRUE ];
END;
TransferEnumeration: PROCEDURE [
enumerationName: String,
procs, exceptions: BOOLEAN ← FALSE,
nest: Nest ] =
BEGIN
index: INTEGER ← LastLupineTransferIndex;
WriteIndex: PROC =
{CWF.WF1[" (%D)"L, @index]; index ← index + 1};
NameList: ST.TransferProcedure =
BEGIN
WFS1[IF transferIndex=1 THEN ",*B"L ELSE ", "L];
WriteTransferName[transfer]; WriteIndex;
END;
WFSL["*N"L, Indent[nest], enumerationName,
": PRIVATE TYPE = MACHINE DEPENDENT {*B"L,
"LupineUnusedIndex (0), LupineLastIndex"L ];
WriteIndex;
[] ← ST.EnumerateTransfers[
proc: NameList, procs: procs, errors: exceptions, signals: exceptions ];
WFS1["};*N"L];
END;
DispatcherHead: PUBLIC PROCEDURE [type: DispatcherType, nest: Nest] =
BEGIN
WFS1["*N"L];
WFLL[nest, DispatcherName[type], ": --"L,
Private.GetString[dispatcherDeclaration], "-- RpcPrivate.Dispatcher ="L];
WFL1[nest+1, "BEGIN"L];
END;
DispatcherSelect: PUBLIC PROCEDURE [type: DispatcherType, nest: Nest] =
BEGIN
WFL[nest+1, "SELECT LOOPHOLE[pkt.data[0], RpcControl."L,
(SELECT type FROM
server => Private.GetString[procedureIndex],
client => Private.GetString[signalIndex],
ENDCASE => ERROR),
"] FROM"L];
END;
DispatcherTail: PUBLIC PROCEDURE [type: DispatcherType, nest: Nest] =
BEGIN
WFL1[nest+2, "ENDCASE => RETURN[Lupine.DispatchingError[]];*N"L];
WFL[nest+1, "END; -- "L, DispatcherName[type]];
END;
-- Routines private to LupineDeclare*Impl via LupineDeclarePrivate.
DispatcherName: PUBLIC PROCEDURE [type: DispatcherType] RETURNS [String] =
BEGIN
RETURN[ SELECT type FROM
none => StringNIL,
client => GetString[clientDispatcher],
server => GetString[serverDispatcher],
callback => GetString[callbackDispatcher],
ENDCASE => ERROR ];
END;
StringConstants: PACKED ARRAY Private.StringConstantType OF STRING = [
clientDispatcher: "ClientDispatcher",
serverDispatcher: "ServerDispatcher",
callbackDispatcher: "CallbackDispatcher",
procedureIndex: "ProcedureIndex",
signalIndex: "SignalIndex",
dispatcherDeclaration: "PROCEDURE [pkt: RPCPkt, callLength: DataLength, lastPkt: BOOLEAN, localConversation: Conversation] RETURNS [returnLength: DataLength]",
dispatcherArgs: "pkt: pkt, callLength: callLength, lastPkt: lastPkt, localConversation: localConversation",
dispatcherResults: "returnLength: returnLength",
dispatcherPkt: "pkt",
dispatcherConversation: "localConversation",
dispatcherReturnLength: "returnLength" ];
GetString: PUBLIC PROCEDURE [type: Private.StringConstantType]
RETURNS [--string:-- String] =
BEGIN RETURN[StringConstants[type]] END;
END. -- LupineDeclareUtilityImpl.