<> <> <> <> <> <> <> <> DIRECTORY IO USING [PutFR], LupineDeclare USING [ ParameterName, WriteParameterName, WriteTypeName ], LupineManagerPrivate USING [ Indent, Nest, Options, ParamPassingMethod, String, StringNIL, WF1, 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, OperationProc, ParentInfo, ParentInfoNull, Passing, SubStrings, WriteNEW ], LupineSymbolTable USING [GetTypeInfo, TypeHandle, TypeInfo, Types], Rope USING [ROPE]; LupineMarshalTypeManagerImpl: PROGRAM IMPORTS IO, Declare: LupineDeclare, LupineManagerPrivate, Private: LupineMarshalPrivate, ST: LupineSymbolTable EXPORTS LupineMarshal, LupineMarshalPrivate SHARES LupineManagerPrivate = BEGIN OPEN LupineManagerPrivate, LupineMarshal; <> ParentInfo: TYPE = Private.ParentInfo; MarshalInfo: TYPE = Private.MarshalInfo; <> ParameterProtocolVersions: PUBLIC PROCEDURE RETURNS [oldestSupported, newestSupported: Version] = {RETURN [ oldestSupported: 1, newestSupported: 1 ]}; <> ToPacket: PUBLIC PROCEDURE [ paramInfo: ParamInfo, overlayHandling: OverlayHandling, varNames: VariableNames, nest: Nest, options: Options ] = 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; <> 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 marshalInfo.paramFieldInfo _ paramFieldInfo; MarshalType[ nest: nest, name: Declare.ParameterName[paramName, paramIndex], type: paramType, parentInfo: Private.ParentInfoNull, marshalInfo: marshalInfo, options: options ]; END; -- MarshalFrameParam. Private.EnumerateFrameParams[paramInfo, MarshalFrameParam]; END; -- Move the remaining nonoverlay params. END; FromPacket: PUBLIC PROCEDURE [ paramInfo: ParamInfo, overlayHandling: OverlayHandling, varNames: VariableNames, nest: Nest, options: Options ] = 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 marshalInfo.paramFieldInfo _ paramFieldInfo; MarshalType[ nest: nest, name: Declare.ParameterName[paramName, paramIndex], type: paramType, parentInfo: Private.ParentInfoNull, marshalInfo: marshalInfo, options: options ]; 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] = <> <> INLINE {RETURN[ paramInfo.adrInfo.hasAddresses OR paramInfo.adrInfo.hasDynamics OR ~paramInfo.alwaysOnePkt ]}; WFSL[Indent[nest], "Lupine.CheckPktLength[pkt: ", varNames.pkt, ", pktLength: "]; IF HasInFrameParams[paramInfo] THEN WFS1[varNames.pktLength] ELSE WF1["%g", [integer[paramInfo.sizeOf.overlayParamRecord]]]; WFS1["];\n"]; END; END; <> OperationInfo: TYPE = RECORD [ canMarshal: BOOLEAN _ TRUE, newBlock: BOOLEAN _ TRUE] _ []; MarshalOpInfo: PACKED ARRAY ST.Types OF OperationInfo = [ <> Pointer: [newBlock: TRUE], Ref: [newBlock: TRUE], List: [newBlock: TRUE], Descriptor: [newBlock: TRUE], <> Null: [newBlock: FALSE], Basic: [newBlock: FALSE], Transfer: [newBlock: FALSE], VariantPart: [newBlock: FALSE], RelativePtr: [newBlock: FALSE], Zone: [newBlock: FALSE], Opaque: [newBlock: FALSE], <> Definition: [canMarshal: FALSE, newBlock: FALSE], Any: [canMarshal: FALSE, newBlock: FALSE], Other: [canMarshal: FALSE, newBlock: FALSE] ]; MarshalType: PUBLIC Private.OperationProc = { <> <> <> 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; newBlock: BOOL _ MarshalOpInfo[typeInfo.type].newBlock; marshalInfo.depth _ marshalInfo.depth + 1; IF newBlock THEN { 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; }; IF MarshalOpInfo[typeInfo.type].canMarshal THEN SELECT passingMethod FROM Handle, InterMds => { <> IF marshalInfo.depth # 1 THEN ERROR; Private.CopyUninterpreted[ nest: nest, variableName: name, variableInfo: typeInfo, parentInfo: parentInfo, marshalInfo: marshalInfo ]; }; Var, Value, Result => SELECT TRUE FROM (passingMethod = Result OR passingMethod = Var) AND Private.ContainsEmbeddedPtrs[type] => <> Private.Error[code: EmbeddedRESULT, type: type]; Private.IsExplicitHandle[typeInfo] => <> Private.CopyUninterpreted[ nest: nest, variableName: name, variableInfo: typeInfo, parentInfo: parentInfo, marshalInfo: marshalInfo ]; ENDCASE => { marshalName: String = StartReadonly[ nest: nest, name: name, typeInfo: typeInfo, marshalInfo: marshalInfo ]; WITH typeInfo: typeInfo SELECT FROM Null, Basic, RelativePtr, Opaque => <> Private.CopyType[ nest: nest, variableName: marshalName, variableInfo: typeInfo, parentInfo: parentInfo, marshalInfo: marshalInfo ]; Transfer => Private.MarshalTransfer[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; Record => Private.MarshalRecord[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; VariantPart => Private.MarshalVariantPart[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; Pointer => Private.MarshalPointer[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; Ref => Private.MarshalRef[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; List => Private.MarshalList[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; String => MarshalString[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; Rope => MarshalRope[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; Atom => MarshalAtom[ marshalName, typeInfo, parentInfo, marshalInfo, nest]; StringBody => MarshalStringBody[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; Text => MarshalText[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; Array => Private.MarshalArray[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; Descriptor => Private.MarshalDescriptor[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; Sequence => Private.MarshalSequence[ marshalName, typeInfo, parentInfo, marshalInfo, nest, options]; 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 ]; }; ENDCASE => ERROR ELSE Private.Error[code: UnimplementedMarshaling, type: type]; IF newBlock THEN WFLL[nest, "END; -- "--L--, Explain[verb][marshalInfo.direction], " "--L--, name, "."--L-- ]; marshalInfo.depth _ marshalInfo.depth - 1; }; <> MarshalString: PROCEDURE [ name: String, stringInfo: String ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest, options: Options ] = INLINE BEGIN MarshalStringTypes[ nest: nest, stringInfo: stringInfo, parentInfo: [name, stringInfo], marshalInfo: marshalInfo, options: options ]; END; MarshalStringBody: PROCEDURE [ name: String, stringBodyInfo: StringBody ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest, options: Options ] = INLINE BEGIN MarshalStringTypes[ nest: nest, stringInfo: stringBodyInfo, parentInfo: parentInfo, marshalInfo: marshalInfo, options: options ]; END; MarshalText: PROCEDURE [ name: String, textInfo: Text ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest, options: Options ] = INLINE BEGIN MarshalStringTypes[ nest: nest, stringInfo: textInfo, parentInfo: parentInfo, marshalInfo: marshalInfo, options: options ]; END; MarshalStringTypes: PROCEDURE [ stringInfo: ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, options: Options, nest: Nest ] = BEGIN DotMaxLength: String = SELECT stringInfo.type FROM String, StringBody => ".maxlength", Text => ".maxLength", ENDCASE => ERROR; TextBase: Private.SubStrings = SELECT stringInfo.type FROM String, StringBody => ["BASE[", parentInfo.name, ".text]"], Text => ["BASE[DESCRIPTOR[", parentInfo.name, ".text]]"], 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"], marshalInfo: marshalInfo ]; WFL[nest, "IF ", parentInfo.name, " # NIL"]; WFL1[nest+1, "THEN BEGIN"]; WFL1[nest+2, "stringHeader: Lupine.StringHeader = ["]; WFLL[nest+3, "Lengths[length: ", parentInfo.name, ".length, maxLength: ", parentInfo.name, DotMaxLength, "]];" ]; IF Private.IsShortString[stringInfo.self] THEN BEGIN WFL[nest+2, "IF stringHeader.length > RpcPrivate.maxShortStringLength"]; WFL1[nest+3, "THEN Lupine.MarshalingError;"]; END; Private.CopyTwo[ nest: nest+2, wordsNeeded: 0, value: ["stringHeader.all"], marshalInfo: marshalInfo ]; IF Private.Passing[Result, argument, marshalInfo] THEN WFL1[nest+2, "NULL; -- Call by result, send header only."] ELSE Private.CopyCharacters[ nest: nest+2, textName: TextBase, numCharsName: "stringHeader.length", marshalInfo: marshalInfo ]; WFL[nest+2, "END; -- IF ", parentInfo.name, " # NIL."]; END; fromPkt => BEGIN WFL1[nest, "stringIsNIL: Lupine.NilHeader;"]; Private.CopyOne[ nest: nest, wordsNeeded: 3, value: ["stringIsNIL"], marshalInfo: marshalInfo ]; IF Private.Passing[Result, result, marshalInfo] OR Private.Passing[Var,result,marshalInfo] THEN WFL[nest, "IF stringIsNIL # (", parentInfo.name, "=NIL) THEN Lupine.UnmarshalingError;"]; WFL1[nest, "IF stringIsNIL"]; WFL[nest+1, "THEN ", parentInfo.name, " _ NIL"]; WFL1[nest+1, "ELSE BEGIN"]; WFL1[nest+2, "stringHeader: Lupine.StringHeader;"]; Private.CopyTwo[ nest: nest+2, wordsNeeded: 0, value: ["stringHeader.all"], marshalInfo: marshalInfo ]; IF Private.IsShortString[stringInfo.self] THEN BEGIN WFL[nest+2, "IF stringHeader.length > RpcPrivate.maxShortStringLength"]; WFL1[nest+3, "THEN Lupine.UnmarshalingError;"]; END; IF Private.Passing[Result, result, marshalInfo] OR Private.Passing[Var,result,marshalInfo] THEN BEGIN WFLL[nest+2, "IF stringHeader.maxLength # ", parentInfo.name, DotMaxLength, " THEN Lupine.UnmarshalingError;" ]; WFL1[nest+2, "NULL; -- Call by var or result, use existing string."]; END ELSE BEGIN WFS[Indent[nest+2], parentInfo.name, " _ ("]; [] _ Private.WriteNEW[ptrInfo: parentInfo.typeInfo, marshalInfo: marshalInfo, options: options]; WFS1["["]; SELECT stringInfo.type FROM String => WFS1["StringBody"]; ENDCASE => Declare.WriteTypeName[stringInfo.self]; WFS1["[stringHeader.maxLength]]);\n"]; END; IF Private.Passing[Result, argument, marshalInfo] THEN WFL1[nest+2, "NULL; -- Call by result, use uninitialized body."] ELSE BEGIN WFL[nest+2, parentInfo.name, ".length _ stringHeader.length;"]; Private.CopyCharacters[ nest: nest+2, textName: TextBase, numCharsName: "stringHeader.length", marshalInfo: marshalInfo ]; END; WFL[nest+2, "END; -- IF stringIsNIL."]; END; ENDCASE => ERROR; END; MarshalRope: PROCEDURE [ name: String, ropeInfo: Rope ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest ] = BEGIN inlineRopeMarshal: BOOL=marshalInfo.paramInfo.options.inlineRopeMarshal; VerifyPassingMethods[value: TRUE, handle: TRUE, marshalInfo: marshalInfo]; SELECT marshalInfo.direction FROM toPkt => IF ~inlineRopeMarshal THEN WFLL[nest, "pktLength _ Lupine.MarshalRope[", name, ", pkt, pktLength, ", (IF Private.IsShortString[ropeInfo.self] THEN "TRUE" ELSE "FALSE"), "];"] ELSE BEGIN Private.CopyOne[ nest: nest, wordsNeeded: 2, value: [name, "=NIL"], marshalInfo: marshalInfo ]; WFL[nest, "IF ", name, " # NIL"]; WFL1[nest+1, "THEN BEGIN"]; WFL[nest+2, "textRope: Rope.Text = Rope.InlineFlatten[r: ", name, "];"]; IF Private.IsShortString[ropeInfo.self] THEN BEGIN WFL1[nest+2, "IF textRope.length > RpcPrivate.maxShortStringLength"]; WFL1[nest+3, "THEN Lupine.MarshalingError;"]; END; Private.CopyOne[ nest: nest+2, wordsNeeded: 0, value: ["textRope.length"], marshalInfo: marshalInfo ]; Private.CopyCharacters[ nest: nest+2, textName: ["BASE[DESCRIPTOR[textRope.text]]"], numCharsName: "textRope.length", marshalInfo: marshalInfo ]; WFL[nest+2, "END; -- IF ", name, " # NIL."]; END; fromPkt => IF ~inlineRopeMarshal THEN WFLL[nest, "[", name, ", pktLength] _ Lupine.UnmarshalRope[pkt, pktLength, ", (IF Private.IsShortString[ropeInfo.self] THEN "TRUE" ELSE "FALSE"), "];"] ELSE BEGIN WFL1[nest, "ropeIsNIL: Lupine.NilHeader;"]; Private.CopyOne[ nest: nest, wordsNeeded: 2, value: ["ropeIsNIL"], marshalInfo: marshalInfo ]; WFL1[nest, "IF ropeIsNIL"]; WFL[nest+1, "THEN ", name, " _ NIL"]; WFL1[nest+1, "ELSE BEGIN"]; WFL1[nest+2, "ropeLength: Lupine.RopeHeader;"]; WFL1[nest+2, "textRope: Rope.Text;"]; Private.CopyOne[ nest: nest+2, wordsNeeded: 0, value: ["ropeLength"], marshalInfo: marshalInfo ]; WFL[nest+2, "IF ropeLength > ", (IF Private.IsShortString[ropeInfo.self] THEN "RpcPrivate.maxShortStringLength" ELSE "LAST[NAT]") ]; WFL1[nest+3, "THEN Lupine.UnmarshalingError;"]; WFL[nest+2, name, " _ textRope _ Rope.NewText[size: ropeLength];"]; Private.CopyCharacters[ nest: nest+2, textName: ["BASE[DESCRIPTOR[textRope.text]]"], numCharsName: "ropeLength", marshalInfo: marshalInfo ]; WFL[nest+2, "END; -- IF ropeIsNIL."]; END; ENDCASE => ERROR; END; MarshalAtom: PROCEDURE [ name: String, atomInfo: Atom ST.TypeInfo, parentInfo: ParentInfo, marshalInfo: MarshalInfo, nest: Nest ] = BEGIN inlineRopeMarshal: BOOL=marshalInfo.paramInfo.options.inlineRopeMarshal; VerifyPassingMethods[value: TRUE, handle: TRUE, marshalInfo: marshalInfo]; SELECT marshalInfo.direction FROM toPkt => IF ~inlineRopeMarshal THEN WFL[nest, "pktLength _ Lupine.MarshalAtom[", name, ", pkt, pktLength];"] ELSE BEGIN WFL[nest, "pNameOfAtom: Rope.Text = Atom.GetPName[atom: ", name, "];"]; MarshalRope[ nest: nest, name: "pNameOfAtom", ropeInfo: ST.TypeInfo[self: atomInfo.self, info: Rope[]], parentInfo: parentInfo, marshalInfo: marshalInfo ]; END; fromPkt => IF ~inlineRopeMarshal THEN WFL[nest, "[", name, ", pktLength] _ Lupine.UnmarshalAtom[pkt, pktLength];"] ELSE BEGIN WFL1[nest, "pNameOfAtom: Rope.ROPE;"]; MarshalRope[ nest: nest, name: "pNameOfAtom", ropeInfo: ST.TypeInfo[self: atomInfo.self, info: Rope[]], parentInfo: parentInfo, marshalInfo: marshalInfo ]; WFL[nest, name, " _ Atom.MakeAtom[--pName:-- pNameOfAtom];"]; END; ENDCASE => ERROR; END; <> VerifyPassingMethods: PUBLIC PROCEDURE [ var, value, result, handle, all: BOOLEAN _ FALSE, marshalInfo: MarshalInfo ] = BEGIN <> <> < 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, suffix: String _ StringNIL, marshalInfo: MarshalInfo ] RETURNS [nameString: String] = BEGIN nameString _ IO.PutFR["%g%g%g", [rope[root]], [integer[marshalInfo.depth]], [rope[suffix]]]; END; StartReadonly: PROCEDURE [ name: String, typeInfo: ST.TypeInfo, 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 marshalName _ UniqueName[ root: "writeOk", marshalInfo: marshalInfo ]; WFL1[nest, "-- Declare readwrite pointer for marshaling readonly pointer."]; SELECT marshalInfo.direction FROM toPkt => BEGIN WFS[Indent[nest], marshalName, ": "]; Declare.WriteTypeName[type: typeInfo.self, includeReadonly: FALSE]; WFS[" = LOOPHOLE[", name, "];\n"]; END; fromPkt => BEGIN WFS[Indent[nest], marshalName, ": "]; Declare.WriteTypeName[type: typeInfo.self, includeReadonly: FALSE]; WFS1[";\n"]; 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, " _ ", marshalName, ";"]; ENDCASE => ERROR; ENDCASE => IF typeInfo.readonly THEN ERROR; END; END. -- LupineMarshalTypeManagerImpl.