-- File [Ivy]Lupine>LupineMarshalTypeManagerImpl.mesa. -- Last edited by BZM on 11-May-82 16:20:51. -- This module cooperates with LupineMarshal*Impl to export LupineMarshal. DIRECTORY CWF USING [SWF3, WF1], LupineDeclare USING [ ParameterName, WriteParameterName, WriteTypeName ], LupineManagerPrivate USING [ AllocString, Indent, MaxIdentifierLength, Nest, ParamPassingMethod, String, StringNIL, WFS, WFS1, WFSL, WFL, WFL1, WFLL ], LupineMarshal USING [ FieldInfo, ParamIndex, ParamInfo, ParamProcedure, ParamRecordKind, OverlayHandling, OverlayParamType, VariableNames, Version ], LupineMarshalPrivate USING [ ContainsEmbeddedPtrs, CopyCharacters, CopyOne, CopyTwo, CopyType, CopyUninterpreted, Direction, EnumerateFrameParams, EnumerateOverlayParams, Error, IsExplicitHandle, IsShortString, MarshalInfo, MarshalInfoObject, MarshalArray, MarshalDescriptor, MarshalList, MarshalPointer, MarshalRecord, MarshalRef, MarshalSequence, MarshalTransfer,MarshalVariantPart, MaxGeneratedIdLength, OperationProc, ParentInfo, ParentInfoNull, Passing, SubStrings, UniqueName, WriteNEW ], LupineSymbolTable USING [GetTypeInfo, TypeHandle, TypeInfo, Types]; LupineMarshalTypeManagerImpl: PROGRAM IMPORTS Declare: LupineDeclare, LupineManagerPrivate, Private: LupineMarshalPrivate, ST: LupineSymbolTable EXPORTS LupineMarshal, LupineMarshalPrivate = BEGIN OPEN LupineManagerPrivate, LupineMarshal; -- Types from the internal LupineManagerPrivate interface. ParentInfo: TYPE = Private.ParentInfo; MarshalInfo: TYPE = Private.MarshalInfo; -- Parameter protocol versions: ParameterProtocolVersions: PUBLIC PROCEDURE RETURNS [oldestSupported, newestSupported: Version] = {RETURN [ oldestSupported: 1, newestSupported: 1 ]}; -- NOTE: -- The string constants in recursively-callable routines within this -- this module have intentionally been put into the global frame. This -- is necessary because putting the literals into the local frames gives -- them sizes in the 100-600 word range, which causes the deep calls -- to get frame faults. When the amount of frame space increases, just -- substitute "L for "-'-L-'-. -- These routines generate marshaling code for top-level parameters. ToPacket: PUBLIC PROCEDURE [ paramInfo: ParamInfo, overlayHandling: OverlayHandling, varNames: VariableNames, nest: Nest ] = BEGIN overlayNeedsMoving: BOOLEAN _ FALSE; construct: BOOLEAN _ TRUE; -- Assign, not construct, when FALSE. FOR overlayType: OverlayParamType IN [FIRST[OverlayParamType]..PRED[LAST[OverlayParamType]]] DO IF paramInfo.hasOverlayParamType[overlayType] THEN SELECT overlayHandling[overlayType] FROM copyToPkt => overlayNeedsMoving _ TRUE; ENDCASE => construct _ FALSE; -- Must use assignment when whole record can't be constructed. ENDLOOP; IF overlayNeedsMoving THEN BEGIN -- Move some overlay params from local frame to pkt. printedOne: BOOLEAN _ FALSE; MoveOverlayParam: ParamProcedure = BEGIN SELECT overlayHandling[paramFieldInfo.overlayParamType] FROM alreadyInPkt => NULL; copyToPkt => BEGIN IF construct THEN {IF printedOne THEN WFS1[", "--L--] ELSE printedOne _ TRUE} ELSE WFS[Indent[nest], varNames.overlayPtr, "."--L--]; Declare.WriteParameterName[paramName, paramIndex]; WFS1[IF construct THEN ": "--L-- ELSE " _ "--L--]; Declare.WriteParameterName[paramName, paramIndex]; IF ~construct THEN WFS1[";*N"--L--]; END; ENDCASE => ERROR; END; -- MoveOverlayParam. IF construct THEN WFS[Indent[nest], varNames.overlayPtr, "^ _ ["--L--]; Private.EnumerateOverlayParams[paramInfo, MoveOverlayParam]; IF construct THEN WFS1["];*N"--L--]; END; -- Move the overlay params. BEGIN -- Move remaining nonoverlay params from local frame to pkt. marshalInfoObject: Private.MarshalInfoObject _ [ paramInfo: paramInfo, paramFieldInfo: NULL, varNames: varNames, direction: toPkt ]; marshalInfo: MarshalInfo = @marshalInfoObject; MarshalFrameParam: ParamProcedure = BEGIN nameString: AllocString = [MaxIdentifierLength]; marshalInfo.paramFieldInfo _ paramFieldInfo; MarshalType[ nest: nest, name: Declare.ParameterName[paramName, paramIndex, nameString], type: paramType, parentInfo: Private.ParentInfoNull, marshalInfo: marshalInfo ]; END; -- MarshalFrameParam. Private.EnumerateFrameParams[paramInfo, MarshalFrameParam]; END; -- Move the remaining nonoverlay params. END; FromPacket: PUBLIC PROCEDURE [ paramInfo: ParamInfo, overlayHandling: OverlayHandling, varNames: VariableNames, nest: Nest ] = BEGIN overlayNeedsMoving: BOOLEAN _ FALSE; FOR overlayType: OverlayParamType IN OverlayParamType DO IF paramInfo.hasOverlayParamType[overlayType] AND overlayHandling[overlayType] IN [copyToFrame..justCopyToFrame] THEN {overlayNeedsMoving _ TRUE; EXIT}; ENDLOOP; IF overlayNeedsMoving THEN BEGIN -- Move some overlay params from pkt to local frame. printedOne: BOOLEAN _ FALSE; ExtractOverlayParam: ParamProcedure = BEGIN SELECT overlayHandling[paramFieldInfo.overlayParamType] FROM leaveInPkt => NULL; copyToFrame, justCopyToFrame => BEGIN IF printedOne THEN WFS1[", "--L--] ELSE printedOne _ TRUE; Declare.WriteParameterName[paramName, paramIndex]; WFS1[": "--L--]; Declare.WriteParameterName[paramName, paramIndex]; END; ENDCASE => ERROR; END; -- ExtractOverlayParam. WFS[Indent[nest], "["--L--]; Private.EnumerateOverlayParams[paramInfo, ExtractOverlayParam]; WFS["] _ "--L--, varNames.overlayPtr, "^;*N"--L--]; END; -- Move the overlay params. FOR overlayType: OverlayParamType IN OverlayParamType DO IF overlayHandling[overlayType] = justCopyToFrame THEN RETURN; ENDLOOP; BEGIN -- Move remaining nonoverlay params from local frame to pkt. marshalInfoObject: Private.MarshalInfoObject _ [ paramInfo: paramInfo, paramFieldInfo: NULL, varNames: varNames, direction: fromPkt ]; marshalInfo: MarshalInfo = @marshalInfoObject; MarshalFrameParam: ParamProcedure = BEGIN nameString: AllocString = [MaxIdentifierLength]; marshalInfo.paramFieldInfo _ paramFieldInfo; MarshalType[ nest: nest, name: Declare.ParameterName[paramName, paramIndex, nameString], type: paramType, parentInfo: Private.ParentInfoNull, marshalInfo: marshalInfo ]; END; -- MarshalFrameParam. Private.EnumerateFrameParams[paramInfo, MarshalFrameParam]; END; -- Move the remaining nonoverlay params. BEGIN -- Check that the correct amount of pkt.data was unmarshaled. HasInFrameParams: PROC [paramInfo: ParamInfo] RETURNS [BOOLEAN] = -- This routine is used to perform constant folding on "pktLength". -- See LupineDeclareStubsImpl.PacketLength. INLINE {RETURN[ paramInfo.adrInfo.hasAddresses OR paramInfo.adrInfo.hasDynamics OR ~paramInfo.alwaysOnePkt ]}; WFSL[Indent[nest], "Lupine.CheckPktLength[pkt: "L, varNames.pkt, ", pktLength: "L]; IF HasInFrameParams[paramInfo] THEN WFS1[varNames.pktLength] ELSE CWF.WF1["%LD"L, @paramInfo.sizeOf.overlayParamRecord]; WFS1["];*N"L]; END; END; -- General type marshaling routine. OperationInfo: TYPE = RECORD [ canMarshal: BOOLEAN _ TRUE, newBlock: BOOLEAN _ TRUE] _ []; MarshalOpInfo: PACKED ARRAY ST.Types OF OperationInfo = [ -- These four must have a block because of Start/StopReadonly. Pointer: [newBlock: TRUE], Ref: [newBlock: TRUE], List: [newBlock: TRUE], Descriptor: [newBlock: TRUE], -- These are simple and don't need a block. Null: [newBlock: FALSE], Basic: [newBlock: FALSE], Transfer: [newBlock: FALSE], VariantPart: [newBlock: FALSE], RelativePtr: [newBlock: FALSE], Zone: [newBlock: FALSE], Opaque: [newBlock: FALSE], -- These guys cannot be marshaled. Definition: [canMarshal: FALSE, newBlock: FALSE], Any: [canMarshal: FALSE, newBlock: FALSE], Other: [canMarshal: FALSE, newBlock: FALSE] ]; MarshalType: PUBLIC Private.OperationProc = BEGIN -- Each marshaling routine for which MarshalOpInfo.newBlock is TRUE can -- generate multiple statements because BEGIN-END is written here. -- Otherwise the routine must generate exactly one statement. Explain: ARRAY {verb, adverb} OF ARRAY Private.Direction OF STRING = [ verb: [toPkt: "Marshal"--L--, fromPkt: "Unmarshal"--L--], adverb: [toPkt: "to"--L--, fromPkt: "from"--L--] ]; typeInfo: ST.TypeInfo = ST.GetTypeInfo[type: type]; passingMethod: ParamPassingMethod = marshalInfo.paramFieldInfo.passingMethod; marshalInfo.depth _ marshalInfo.depth + 1; IF MarshalOpInfo[typeInfo.type].newBlock THEN BEGIN WFSL[ Indent[nest], "BEGIN -- "--L--, Explain[verb][marshalInfo.direction], " "--L--, name, ": "--L-- ]; Declare.WriteTypeName[type]; WFSL[ " "--L--, Explain[adverb][marshalInfo.direction], " "--L--, marshalInfo.varNames.pkt, ".data["--L--, marshalInfo.varNames.pktLength, "].*N"--L-- ]; nest _ nest + 1; END; IF MarshalOpInfo[typeInfo.type].canMarshal THEN SELECT passingMethod FROM Handle, InterMds => BEGIN -- Handle and InterMds should only happen at the top (param) level. IF marshalInfo.depth # 1 THEN ERROR; Private.CopyUninterpreted[ nest: nest, variableName: name, variableInfo: typeInfo, parentInfo: parentInfo, marshalInfo: marshalInfo ]; END; Var, Value, Result => SELECT TRUE FROM (passingMethod = Result OR passingMethod = Var) AND Private.ContainsEmbeddedPtrs[type] => -- Exactly one pointer depth is permitted in VAR and RESULT. Private.Error[code: EmbeddedRESULT, type: type]; Private.IsExplicitHandle[typeInfo] => -- A handle embedded in something else still a handle. Private.CopyUninterpreted[ nest: nest, variableName: name, variableInfo: typeInfo, parentInfo: parentInfo, marshalInfo: marshalInfo ]; ENDCASE => BEGIN marshalNameString: AllocString = [Private.MaxGeneratedIdLength]; marshalName: String = StartReadonly[ nest: nest, name: name, typeInfo: typeInfo, marshalNameString: marshalNameString, marshalInfo: marshalInfo ]; WITH typeInfo: typeInfo SELECT FROM Null, Basic, RelativePtr, Opaque => -- These basic types just need copying. Private.CopyType[ nest: nest, variableName: marshalName, variableInfo: typeInfo, parentInfo: parentInfo, marshalInfo: marshalInfo ]; Transfer => Private.MarshalTransfer[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Record => Private.MarshalRecord[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; VariantPart => Private.MarshalVariantPart[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Pointer => Private.MarshalPointer[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Ref => Private.MarshalRef[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; List => Private.MarshalList[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; String => MarshalString[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Rope => MarshalRope[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Atom => MarshalAtom[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; StringBody => MarshalStringBody[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Text => MarshalText[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Array => Private.MarshalArray[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Descriptor => Private.MarshalDescriptor[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Sequence => Private.MarshalSequence[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Zone => -- Zones must be handles. Private.Error[code: ImproperPassingMethod, type: type]; Definition, Any, Other => ERROR; -- Unimplemented marshalings should be caught above. ENDCASE => ERROR; StopReadonly[ nest: nest, name: name, typeInfo: typeInfo, marshalName: marshalName, marshalInfo: marshalInfo ]; END; ENDCASE => ERROR ELSE Private.Error[code: UnimplementedMarshaling, type: type]; IF MarshalOpInfo[typeInfo.type].newBlock THEN WFLL[nest, "END; -- "--L--, Explain[verb][marshalInfo.direction], " "--L--, name, "."--L-- ]; marshalInfo.depth _ marshalInfo.depth - 1; END; -- Marshaling routines for nontrivial builtin types (e.g., strings). MarshalString: PROCEDURE [ name: String, stringInfo: String ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest ] = INLINE BEGIN MarshalStringTypes[ nest: nest, stringInfo: stringInfo, parentInfo: [name, stringInfo], marshalInfo: marshalInfo ]; END; MarshalStringBody: PROCEDURE [ name: String, stringBodyInfo: StringBody ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest ] = INLINE BEGIN MarshalStringTypes[ nest: nest, stringInfo: stringBodyInfo, parentInfo: parentInfo, marshalInfo: marshalInfo ]; END; MarshalText: PROCEDURE [ name: String, textInfo: Text ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest ] = INLINE BEGIN MarshalStringTypes[ nest: nest, stringInfo: textInfo, parentInfo: parentInfo, marshalInfo: marshalInfo ]; END; MarshalStringTypes: PROCEDURE [ stringInfo: ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest ] = BEGIN DotMaxLength: String = SELECT stringInfo.type FROM String, StringBody => ".maxlength"L, Text => ".maxLength"L, ENDCASE => ERROR; TextBase: Private.SubStrings = SELECT stringInfo.type FROM String, StringBody => ["BASE["L, parentInfo.name, ".text]"L], Text => ["BASE[DESCRIPTOR["L, parentInfo.name, ".text]]"L], ENDCASE => ERROR; VerifyPassingMethods[all: TRUE, marshalInfo: marshalInfo]; SELECT parentInfo.typeInfo.type FROM String, Pointer, Ref => NULL; ENDCASE => ERROR; SELECT marshalInfo.direction FROM toPkt => BEGIN Private.CopyOne[ nest: nest, wordsNeeded: 3, value: [parentInfo.name, "=NIL"L], marshalInfo: marshalInfo ]; WFL[nest, "IF "L, parentInfo.name, " # NIL"L]; WFL1[nest+1, "THEN BEGIN"L]; WFL1[nest+2, "stringHeader: Lupine.StringHeader = ["L]; WFLL[nest+3, "Lengths[length: "L, parentInfo.name, ".length, maxLength: "L, parentInfo.name, DotMaxLength, "]];"L ]; IF Private.IsShortString[stringInfo.self] THEN BEGIN WFL[nest+2, "IF stringHeader.length > RpcPrivate.maxShortStringLength"L]; WFL1[nest+3, "THEN Lupine.MarshalingError;"L]; END; Private.CopyTwo[ nest: nest+2, wordsNeeded: 0, value: ["stringHeader.all"L], marshalInfo: marshalInfo ]; IF Private.Passing[Result, argument, marshalInfo] THEN WFL1[nest+2, "NULL; -- Call by result, send header only."L] ELSE Private.CopyCharacters[ nest: nest+2, textName: TextBase, numCharsName: "stringHeader.length"L, marshalInfo: marshalInfo ]; WFL[nest+2, "END; -- IF "L, parentInfo.name, " # NIL."L]; END; fromPkt => BEGIN WFL1[nest, "stringIsNIL: Lupine.NilHeader;"L]; Private.CopyOne[ nest: nest, wordsNeeded: 3, value: ["stringIsNIL"L], marshalInfo: marshalInfo ]; IF Private.Passing[Result, result, marshalInfo] OR Private.Passing[Var,result,marshalInfo] THEN WFL[nest, "IF stringIsNIL # ("L, parentInfo.name, "=NIL) THEN Lupine.UnmarshalingError;"L]; WFL1[nest, "IF stringIsNIL"L]; WFL[nest+1, "THEN "L, parentInfo.name, " _ NIL"L]; WFL1[nest+1, "ELSE BEGIN"L]; WFL1[nest+2, "stringHeader: Lupine.StringHeader;"L]; Private.CopyTwo[ nest: nest+2, wordsNeeded: 0, value: ["stringHeader.all"L], marshalInfo: marshalInfo ]; IF Private.IsShortString[stringInfo.self] THEN BEGIN WFL[nest+2, "IF stringHeader.length > RpcPrivate.maxShortStringLength"L]; WFL1[nest+3, "THEN Lupine.UnmarshalingError;"L]; END; IF Private.Passing[Result, result, marshalInfo] OR Private.Passing[Var,result,marshalInfo] THEN BEGIN WFLL[nest+2, "IF stringHeader.maxLength # "L, parentInfo.name, DotMaxLength, " THEN Lupine.UnmarshalingError;"L ]; WFL1[nest+2, "NULL; -- Call by var or result, use existing string."L]; END ELSE BEGIN WFS[Indent[nest+2], parentInfo.name, " _ ("L]; Private.WriteNEW[ptrInfo: parentInfo.typeInfo, marshalInfo: marshalInfo]; WFS1["["L]; SELECT stringInfo.type FROM String => WFS1["StringBody"L]; ENDCASE => Declare.WriteTypeName[stringInfo.self]; WFS1["[stringHeader.maxLength]]);*N"L]; END; IF Private.Passing[Result, argument, marshalInfo] THEN WFL1[nest+2, "NULL; -- Call by result, use uninitialized body."L] ELSE BEGIN WFL[nest+2, parentInfo.name, ".length _ stringHeader.length;"L]; Private.CopyCharacters[ nest: nest+2, textName: TextBase, numCharsName: "stringHeader.length"L, marshalInfo: marshalInfo ]; END; WFL[nest+2, "END; -- IF stringIsNIL."L]; END; ENDCASE => ERROR; END; MarshalRope: PROCEDURE [ name: String, ropeInfo: Rope ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest ] = BEGIN VerifyPassingMethods[value: TRUE, handle: TRUE, marshalInfo: marshalInfo]; SELECT marshalInfo.direction FROM toPkt => BEGIN Private.CopyOne[ nest: nest, wordsNeeded: 2, value: [name, "=NIL"L], marshalInfo: marshalInfo ]; WFL[nest, "IF "L, name, " # NIL"L]; WFL1[nest+1, "THEN BEGIN"L]; WFL[nest+2, "textRope: Rope.Text = RopeInline.InlineFlatten[r: "L, name, "];"L]; IF Private.IsShortString[ropeInfo.self] THEN BEGIN WFL1[nest+2, "IF textRope.length > RpcPrivate.maxShortStringLength"L]; WFL1[nest+3, "THEN Lupine.MarshalingError;"L]; END; Private.CopyOne[ nest: nest+2, wordsNeeded: 0, value: ["textRope.length"L], marshalInfo: marshalInfo ]; Private.CopyCharacters[ nest: nest+2, textName: ["BASE[DESCRIPTOR[textRope.text]]"L], numCharsName: "textRope.length"L, marshalInfo: marshalInfo ]; WFL[nest+2, "END; -- IF "L, name, " # NIL."L]; END; fromPkt => BEGIN WFL1[nest, "ropeIsNIL: Lupine.NilHeader;"L]; Private.CopyOne[ nest: nest, wordsNeeded: 2, value: ["ropeIsNIL"L], marshalInfo: marshalInfo ]; WFL1[nest, "IF ropeIsNIL"L]; WFL[nest+1, "THEN "L, name, " _ NIL"L]; WFL1[nest+1, "ELSE BEGIN"L]; WFL1[nest+2, "ropeLength: Lupine.RopeHeader;"L]; WFL1[nest+2, "textRope: Rope.Text;"L]; Private.CopyOne[ nest: nest+2, wordsNeeded: 0, value: ["ropeLength"L], marshalInfo: marshalInfo ]; WFL[nest+2, "IF ropeLength > "L, (IF Private.IsShortString[ropeInfo.self] THEN "RpcPrivate.maxShortStringLength"L ELSE "LAST[NAT]"L) ]; WFL1[nest+3, "THEN Lupine.UnmarshalingError;"L]; WFL[nest+2, name, " _ textRope _ RopeInline.NewText[size: ropeLength];"L]; Private.CopyCharacters[ nest: nest+2, textName: ["BASE[DESCRIPTOR[textRope.text]]"L], numCharsName: "ropeLength"L, marshalInfo: marshalInfo ]; WFL[nest+2, "END; -- IF ropeIsNIL."L]; END; ENDCASE => ERROR; END; MarshalAtom: PROCEDURE [ name: String, atomInfo: Atom ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest ] = BEGIN VerifyPassingMethods[value: TRUE, handle: TRUE, marshalInfo: marshalInfo]; SELECT marshalInfo.direction FROM toPkt => BEGIN WFL[nest, "pNameOfAtom: Rope.Text = Atom.GetPName[atom: "L, name, "];"L]; MarshalRope[ nest: nest, name: "pNameOfAtom"L, ropeInfo: ST.TypeInfo[self: atomInfo.self, info: Rope[]], parentInfo: parentInfo, marshalInfo: marshalInfo ]; END; fromPkt => BEGIN WFL1[nest, "pNameOfAtom: Rope.ROPE;"L]; MarshalRope[ nest: nest, name: "pNameOfAtom"L, ropeInfo: ST.TypeInfo[self: atomInfo.self, info: Rope[]], parentInfo: parentInfo, marshalInfo: marshalInfo ]; WFL[nest, name, " _ Atom.MakeAtom[--pName:-- pNameOfAtom];"L]; END; ENDCASE => ERROR; END; -- Marshaling utility routines. VerifyPassingMethods: PUBLIC PROCEDURE [ var, value, result, handle, all: BOOLEAN _ FALSE, marshalInfo: MarshalInfo ] = BEGIN -- VerifyPassingMethods double checks that Lupine's -- type checker (LupineMarshalInfoImpl.DeterminePassingMethod) -- and code generators (the Marshal routines) are in agreement. IF marshalInfo.depth = 1 AND NOT (all OR (SELECT marshalInfo.paramFieldInfo.passingMethod FROM Var => var, Value => value, Result => result, Handle => handle, InterMds => TRUE, ENDCASE => ERROR) ) THEN ERROR; END; UniqueName: PUBLIC PROCEDURE [ root: String, nameString: --VAR-- String, suffix: String _ StringNIL, marshalInfo: MarshalInfo ] = BEGIN CWF.SWF3[nameString, "%LS%D%LS"L, root, @marshalInfo.depth, suffix]; END; StartReadonly: PROCEDURE [ name: String, typeInfo: ST.TypeInfo, marshalNameString: --VAR-- String, marshalInfo: MarshalInfo, nest: Nest ] RETURNS [marshalName: String] = BEGIN marshalName _ name; -- Usually no new name is needed. SELECT typeInfo.type FROM Pointer, Ref, List, Descriptor => IF typeInfo.readonly THEN BEGIN Private.UniqueName[ root: "writeOk"L, nameString: marshalNameString, marshalInfo: marshalInfo ]; marshalName _ marshalNameString; WFL1[nest, "-- Declare readwrite pointer for marshaling readonly pointer."L]; SELECT marshalInfo.direction FROM toPkt => BEGIN WFS[Indent[nest], marshalName, ": "L]; Declare.WriteTypeName[type: typeInfo.self, includeReadonly: FALSE]; WFS[" = LOOPHOLE["L, name, "];*N"L]; END; fromPkt => BEGIN WFS[Indent[nest], marshalName, ": "L]; Declare.WriteTypeName[type: typeInfo.self, includeReadonly: FALSE]; WFS1[";*N"L]; END; ENDCASE => ERROR; END; ENDCASE => IF typeInfo.readonly THEN ERROR; END; StopReadonly: PROCEDURE [ name: String, typeInfo: ST.TypeInfo, marshalName: String, marshalInfo: MarshalInfo, nest: Nest ] = BEGIN SELECT typeInfo.type FROM Pointer, Ref, List, Descriptor => IF typeInfo.readonly THEN SELECT marshalInfo.direction FROM toPkt => NULL; fromPkt => WFLL[nest, name, " _ "L, marshalName, ";"L]; ENDCASE => ERROR; ENDCASE => IF typeInfo.readonly THEN ERROR; END; END. -- LupineMarshalTypeManagerImpl.