-- KipperCodeGenImpl.mesa: December 1, 1985 5:04:27 pm PST -- Sturgis, January 3, 1986 2:25:14 pm PST DIRECTORY Convert USING[RopeFromCard], FS USING[StreamOpen], IO USING[Close, PutF, rope, RopeFromROS, ROS, STREAM], KipperCodeGen USING[], KipperMain1Def USING[NameNode, TypeContextNode, TypeNode], Process USING[Pause, SecondsToTicks], Rope USING[Cat, ROPE], TypeGraphDef USING[BuildRopeName, BuiltInTypeCase, CreateHashTable, EnumerateHashTable, EqualNames, FindEntry, GenAllNamesForType, GenDefFileNames, GenEnumeratedElements, GenImplFileNames, GenNamedTypes, GenNamingNodeLeftNames, GenNamingNodeRightNames, GenRecordFields, GenRootTypeNames, GetBuiltInTypeCase, GetDefFileOfNamedType, GetListTypeValue, GetNameNodeInfo, GetNamedType, GetNamingNodeNamedNode, GetNamingNodePrimaryName, GetRecordCase, GetRefTypeTarget, GetSeqTypeCountName, GetSeqTypeCountType, GetSeqFieldType, GetSeqTypeFieldType, GetTypeNodeCase, GetTypeNodeTypeDefFile, GetTypeNodeFcnDefFile, GetTypeNodeFcnImplFile, GetTypeNodeName, HashTable, MakeEntry, TypeNodeCase]; KipperCodeGenImpl: CEDAR PROGRAM IMPORTS Convert, FS, IO, Process, Rope, TypeGraphDef EXPORTS KipperCodeGen = BEGIN OPEN KipperMain1Def, TypeGraphDef; <> <> <> <<>> <<>> <> PrintTypeNodeContext: PUBLIC PROC[context: TypeContextNode, on: IO.STREAM] = BEGIN SeeOneName: PROC[name: NameNode] = BEGIN nameText: Rope.ROPE _ GetNameNodeInfo[name].text; type: TypeNode _ GetNamedType[context, name]; from: NameNode _ GetDefFileOfNamedType[context, name]; fromText: Rope.ROPE _ GetNameNodeInfo[from].text; case: TypeNodeCase _ GetTypeNodeCase[type]; IO.PutF[on, "%g: Type%g = ", IO.rope[nameText], IO.rope[IF fromText = NIL THEN "" ELSE Rope.Cat[" From ", fromText]]]; PrintTypeNodeData[type, 3, on]; END; GenRootTypeNames[context, SeeOneName]; END; PrintTypeNodeData: PROC[type: TypeNode, indent: CARDINAL, on: IO.STREAM] = BEGIN case: TypeNodeCase _ GetTypeNodeCase[type]; SELECT case FROM naming => IO.PutF[on, "naming \"%g\"\N", IO.rope[FormNameRope[type]]]; enumerated => IO.PutF[on, "enumerated = {%g}\N", IO.rope[FormElementNames[type]]]; record => {IO.PutF[on, "record\N"]; PrintRecordFields[type, indent+3, on]}; ref => {IO.PutF[on, "ref "]; PrintTypeNodeData[GetRefTypeTarget[type], indent+3, on]}; any => IO.PutF[on, "any\N"]; list => {IO.PutF[on, "list of "]; PrintTypeNodeData[GetListTypeValue[type], indent+3, on]}; builtIn => IO.PutF[on, "builtIn\N"]; ENDCASE => ERROR; END; PrintRecordFields: PROC[type: TypeNode, indent: CARDINAL, on: IO.STREAM] = BEGIN PrintOneField: PROC[name: NameNode, type: TypeNode, last: BOOLEAN] = BEGIN PrintIndent[indent, on]; IO.PutF[on, "%g: ", IO.rope[GetNameNodeInfo[name].text]]; PrintTypeNodeData[type, indent+3, on]; END; GenRecordFields[type, PrintOneField]; END; FormNameRope: PROC[type: TypeNode] RETURNS[Rope.ROPE] = BEGIN rope: Rope.ROPE _ GetNameNodeInfo[GetNamingNodePrimaryName[type]].text; SeeRightName: PROC[name: NameNode] = {rope _ Rope.Cat[rope, ".", GetNameNodeInfo[name].text]}; SeeLeftName: PROC[name: NameNode] = {rope _ Rope.Cat[GetNameNodeInfo[name].text, " ", rope]}; GenNamingNodeRightNames[type, SeeRightName]; GenNamingNodeLeftNames[type, SeeLeftName]; RETURN[rope]; END; FormElementNames: PROC[type: TypeNode] RETURNS[Rope.ROPE] = BEGIN rope: Rope.ROPE _ NIL; SeeOneName: PROC[name: NameNode] = BEGIN IF rope # NIL THEN rope _ Rope.Cat[rope, ", "]; rope _ Rope.Cat[rope, GetNameNodeInfo[name].text]; END; GenEnumeratedElements[type, SeeOneName]; RETURN[rope]; END; PrintIndent: PROC[indent: CARDINAL, on: IO.STREAM] = {FOR I: CARDINAL IN [0..indent) DO IO.PutF[on, " "] ENDLOOP}; <> <> <<>> <> <<>> <> <<>> GeneratorContext: TYPE = REF GeneratorContextBody; GeneratorContextBody: TYPE = RECORD[ defFiles: HashTable, implFiles: HashTable, kipperedTypes: HashTable, functions: HashTable, workList: WorkCell, refAnyWorkCell: WorkCell]; KipperedTypeEntry: TYPE = REF KipperedTypeEntryBody; KipperedTypeEntryBody: TYPE = RECORD[ type: TypeNode, fnNames: ARRAY KipperContext OF RECORD[ kipperFunctionName: NameNode, unKipperFunctionName: NameNode]]; FunctionEntry: TYPE = REF FunctionEntryBody; FunctionEntryBody: TYPE = RECORD[ defFile: NameNode, implFile: NameNode]; WorkCell: TYPE = REF WorkCellBody; WorkCellBody: TYPE = RECORD[ type: TypeNode, mcontext: KipperContext, next: WorkCell]; KipperContext: TYPE = {self, refTarget, listTarget}; KipperUnKipper: TYPE = {kipper, unKipper}; FieldExpCase: TYPE = {localVal, ref, list, shortField, longField}; <> <> <> <> <> <> FormValExp: PROC[exp: Rope.ROPE, case: FieldExpCase] RETURNS[Rope.ROPE] = BEGIN RETURN[SELECT case FROM ref => Rope.Cat["(", exp, "^)"], list => ERROR, localVal, shortField, longField => exp, ENDCASE => ERROR]; END; <> FormSubFieldCase: PROC[case: FieldExpCase] RETURNS[FieldExpCase] = BEGIN RETURN[SELECT case FROM ref, list, longField => longField, shortField => shortField, localVal => ERROR, ENDCASE => ERROR]; END; BuildFilesFromContext: PUBLIC PROC[context: TypeContextNode, ReportStream: IO.STREAM] = BEGIN gContext: GeneratorContext _ NEW[GeneratorContextBody]; PrepareOneImplFile: PROC[fileName: NameNode] = BEGIN implFileCode: Code _ BuildEmptyCode[context, fileName, impl]; RecordCedarTypeUse[implFileCode, "RawBytes", "Basics"]; RecordCedarTypeUse[implFileCode, "STREAM", "IO"]; RecordCedarProcUse[implFileCode, "UnsafePutBlock", "IO"]; RecordCedarProcUse[implFileCode, "UnsafeGetBlock", "IO"]; RecordCedarTypeUse[implFileCode, "Kipperer", "KipperSupport"]; RecordCedarTypeUse[implFileCode, "UnKipperer", "KipperSupport"]; MakeEntry[gContext.implFiles, fileName, implFileCode]; END; PrepareOneDefFile: PROC[fileName: NameNode] = BEGIN defFileCode: Code _ BuildEmptyCode[context, fileName, def]; DeclareAType: PROC[type: TypeNode] = BEGIN IF EqualNames[GetTypeNodeTypeDefFile[type], fileName] THEN BEGIN case: TypeNodeCase _ GetTypeNodeCase[type]; SELECT case FROM ref, list, enumerated, record, naming => InstallNamedTypeDecl[defFileCode, type]; builtIn, any => NULL; ENDCASE => ERROR; END; END; RecordCedarTypeUse[defFileCode, "Kipperer", "KipperSupport"]; RecordCedarTypeUse[defFileCode, "UnKipperer", "KipperSupport"]; GenNamedTypes[context, DeclareAType]; MakeEntry[gContext.defFiles, fileName, defFileCode]; END; PutNamedRefOrListTypeOnWorkList: PROC[type: TypeNode] = BEGIN case: TypeNodeCase _ GetTypeNodeCase[type]; SELECT case FROM list, ref => [] _ AddTypeToWorkList[gContext, type, self, kipper]; naming, enumerated, builtIn, record => NULL; ENDCASE => ERROR; END; ConditionalPutRecordTypeOnOnWorkList: PROC[type: TypeNode] = BEGIN case: TypeNodeCase _ GetTypeNodeCase[type]; SELECT case FROM record => BEGIN name: NameNode _ GetTypeNodeName[type]; -- perhaps already covered by a named ref IF FindEntry[gContext.kipperedTypes, name] = NIL THEN BEGIN -- no, not already covered [] _ AddTypeToWorkList[gContext, type, refTarget, kipper]; END; END; naming, enumerated, builtIn, list, ref => NULL; ENDCASE => ERROR; END; -- initialize the generator context gContext.defFiles _ CreateHashTable[5]; gContext.implFiles _ CreateHashTable[5]; gContext.kipperedTypes _ CreateHashTable[5]; gContext.functions _ CreateHashTable[5]; gContext.workList _ NIL; -- now initialize code for the output files GenImplFileNames[context, PrepareOneImplFile]; GenDefFileNames[context, PrepareOneDefFile]; -- put named ref and list types on the work list GenNamedTypes[context, PutNamedRefOrListTypeOnWorkList]; -- now add named record types which are not the target of named ref types GenNamedTypes[context, ConditionalPutRecordTypeOnOnWorkList]; -- now do the work WHILE gContext.workList # NIL DO cell: WorkCell _ gContext.workList; gContext.workList _ cell.next; -- watch out for ref any, and do it last -- so that all ref types will be known IF GetTypeNodeCase[cell.type] = builtIn AND GetBuiltInTypeCase[cell.type] = Any THEN BEGIN IF gContext.refAnyWorkCell # NIL THEN ERROR; gContext.refAnyWorkCell _ cell; cell.next _ NIL; END ELSE GenCodeForOneProcPair[gContext, cell.type, cell.mcontext] ENDLOOP; IF gContext.refAnyWorkCell # NIL THEN GenCodeForOneProcPair[gContext, gContext.refAnyWorkCell.type, gContext.refAnyWorkCell.mcontext]; -- finally, its time to put out the files BEGIN PutOutOneDefFile: PROC[codeRef: REF ANY, name: NameNode] = BEGIN code: Code _ NARROW[codeRef]; fullFileNameText: Rope.ROPE _ Rope.Cat[GetNameNodeInfo[name].text, ".mesa"]; fileStream: IO.STREAM _ FS.StreamOpen[fullFileNameText, create]; ShowCode[code, fileStream]; IO.Close[fileStream]; IO.PutF[ReportStream, "\Ndefinitions written on %g\N", IO.rope[fullFileNameText]]; Process.Pause[Process.SecondsToTicks[2]]; -- make sure next not same create date END; PutOutOneImplFile: PROC[codeRef: REF ANY, name: NameNode] = BEGIN code: Code _ NARROW[codeRef]; fullFileNameText: Rope.ROPE _ Rope.Cat[GetNameNodeInfo[name].text, ".mesa"]; fileStream: IO.STREAM _ FS.StreamOpen[fullFileNameText, create]; ShowCode[code, fileStream]; IO.Close[fileStream]; IO.PutF[ReportStream, "\Nimplementation written on %g\N", IO.rope[fullFileNameText]]; Process.Pause[Process.SecondsToTicks[2]]; -- make sure next not same create date END; EnumerateHashTable[gContext.defFiles, PutOutOneDefFile]; EnumerateHashTable[gContext.implFiles, PutOutOneImplFile]; END; END; AddTypeToWorkList: PROC[gContext: GeneratorContext, type: TypeNode, mContext: KipperContext, mm: KipperUnKipper] RETURNS[NameNode] = BEGIN typeName: NameNode _ GetTypeNodeName[type]; kipperEntry: KipperedTypeEntry _ NARROW[FindEntry[gContext.kipperedTypes, typeName]]; IF kipperEntry = NIL THEN BEGIN kipperEntry _ NEW[KipperedTypeEntryBody]; kipperEntry.type _ type; MakeEntry[gContext.kipperedTypes, typeName, kipperEntry]; END; IF kipperEntry.fnNames[mContext].kipperFunctionName = NIL THEN BEGIN -- not currently on the work list final: Rope.ROPE _ SELECT mContext FROM self => "", refTarget => "Ref", listTarget => "List", ENDCASE => ERROR; cell: WorkCell _ NEW[WorkCellBody_[type, mContext, gContext.workList]]; kipperFnName: NameNode _ BuildRopeName[Rope.Cat["Kipper", GetNameNodeInfo[typeName].text, final]]; unKipperFnName: NameNode _ BuildRopeName[Rope.Cat["UnKipper", GetNameNodeInfo[typeName].text, final]]; defFileName: NameNode _ GetTypeNodeFcnDefFile[type]; implFileName: NameNode _ GetTypeNodeFcnImplFile[type]; kipperEntry.fnNames[mContext].kipperFunctionName _ kipperFnName; kipperEntry.fnNames[mContext].unKipperFunctionName _ unKipperFnName; gContext.workList _ cell; AddFunctionInfo[gContext, kipperFnName, defFileName, implFileName]; AddFunctionInfo[gContext, unKipperFnName, defFileName, implFileName]; END; RETURN[IF mm = kipper THEN kipperEntry.fnNames[mContext].kipperFunctionName ELSE kipperEntry.fnNames[mContext].unKipperFunctionName]; END; <> GenKipperedTypes: PROC[gContext: GeneratorContext, marshUnMarsh: KipperUnKipper, for: PROC[TypeNode, KipperContext, NameNode]] = BEGIN SeeOneKipperedType: PROC[ref: REF ANY, name: NameNode] = BEGIN entry: KipperedTypeEntry _ NARROW[ref]; FOR mc: KipperContext IN KipperContext DO IF entry.fnNames[mc].kipperFunctionName # NIL THEN SELECT marshUnMarsh FROM kipper => for[entry.type, mc, entry.fnNames[mc].kipperFunctionName]; unKipper => for[entry.type, mc, entry.fnNames[mc].unKipperFunctionName]; ENDCASE => ERROR; ENDLOOP; END; EnumerateHashTable[gContext.kipperedTypes, SeeOneKipperedType]; END; AddFunctionInfo: PROC[gContext: GeneratorContext, fnName: NameNode, defFile: NameNode, implFile: NameNode] = BEGIN entry: FunctionEntry _ NEW[FunctionEntryBody_[defFile, implFile]]; MakeEntry[gContext.functions, fnName, entry]; END; GetFunctionInfo: PROC[gContext: GeneratorContext, fnName: NameNode] RETURNS[defFile: NameNode, implFile: NameNode] = BEGIN entry: FunctionEntry _ NARROW[FindEntry[gContext.functions, fnName]]; RETURN[entry.defFile, entry.implFile]; END; GenCodeForOneProcPair: PROC[gContext: GeneratorContext, type: TypeNode, mContext: KipperContext] = BEGIN typeNameText: Rope.ROPE _ GetNameNodeInfo[GetTypeNodeName[type]].text; varName: Rope.ROPE _ SELECT mContext FROM self => Rope.Cat[typeNameText, "Val"], refTarget => Rope.Cat[typeNameText, "Ref"], listTarget => Rope.Cat[typeNameText, "List"], ENDCASE => ERROR; varType: Rope.ROPE _ SELECT mContext FROM self => typeNameText, refTarget => Rope.Cat["REF ", typeNameText], listTarget => Rope.Cat["LIST OF ", typeNameText] ENDCASE => ERROR; kipperEntry: KipperedTypeEntry _ NARROW[FindEntry[gContext.kipperedTypes, GetTypeNodeName[type]]]; kipperFnName: NameNode _ kipperEntry.fnNames[mContext].kipperFunctionName; unKipperFnName: NameNode _ kipperEntry.fnNames[mContext].unKipperFunctionName; defFileName: NameNode; implFileName: NameNode; defFileCode: Code; implFileCode: Code; [defFileName, implFileName] _ GetFunctionInfo[gContext, kipperFnName]; defFileCode _ NARROW[FindEntry[gContext.defFiles, defFileName]]; implFileCode _ NARROW[FindEntry[gContext.implFiles, implFileName]]; -- add the proc declarations to the def file AppendRopeCodeStatement[defFileCode, Rope.Cat[ Rope.Cat[ GetNameNodeInfo[kipperFnName].text, ": PROC[kipperer: Kipperer, ", varName], Rope.Cat[ ": ", varType, "];"]]]; AppendRopeCodeStatement[defFileCode, Rope.Cat[ Rope.Cat[ GetNameNodeInfo[unKipperFnName].text, ": PROC[unKipperer: UnKipperer] RETURNS[", varName], Rope.Cat[ ": ", varType, "];"]]]; -- now add the implementations to the impl file AppendOpenRopeCodeStatement[implFileCode, Rope.Cat[ Rope.Cat[ "\N\N", GetNameNodeInfo[kipperFnName].text, ": PUBLIC PROC[kipperer: Kipperer, ", varName], Rope.Cat[ ": ", varType, "] = TRUSTED"]]]; AppendRopeCodeStatement[implFileCode, "BEGIN"]; AppendNeededProcVars[implFileCode]; -- now generate the code body, except that the body of KipperANYRef must be treated special IF GetTypeNodeCase[type] = builtIn AND GetBuiltInTypeCase[type] = Any THEN BEGIN -- this is the KipperANYRef case IF mContext # refTarget THEN ERROR; KipperABuiltIn[gContext, implFileCode, type, varName, ref]; END ELSE BEGIN SELECT mContext FROM self => GenKipperCodeForAType[gContext, implFileCode, type, varName, localVal]; refTarget => KipperARef[gContext, implFileCode, type, varName, localVal]; listTarget => KipperAList[gContext, implFileCode, type, varName, localVal]; ENDCASE => ERROR; END; AppendClosingRopeCodeStatement[implFileCode, "END;"]; AppendOpenRopeCodeStatement[implFileCode, Rope.Cat[ Rope.Cat[ "\N\N", GetNameNodeInfo[unKipperFnName].text, ": PUBLIC PROC[unKipperer: UnKipperer] RETURNS[", varName], Rope.Cat[ ": ", varType, "] = TRUSTED"]]]; AppendRopeCodeStatement[implFileCode, "BEGIN"]; AppendNeededProcVars[implFileCode]; -- now generate the code body, except that the body of UnKipperANYRef must be treated special IF GetTypeNodeCase[type] = builtIn AND GetBuiltInTypeCase[type] = Any THEN BEGIN IF mContext # refTarget THEN ERROR; UnKipperABuiltIn[gContext, implFileCode, type, varName, ref]; END ELSE BEGIN SELECT mContext FROM self => GenUnKipperCodeForAType[gContext, implFileCode, type, varName, localVal]; refTarget => UnKipperARef[gContext, implFileCode, type, varName, localVal]; listTarget => UnKipperAList[gContext, implFileCode, type, varName, localVal]; ENDCASE => ERROR; END; AppendClosingRopeCodeStatement[implFileCode, "END;"]; -- finally, record info needed to construct file headers RecordNamedTypeUse[defFileCode, type]; RecordNamedTypeUse[implFileCode, type]; RecordFunctionExport[implFileCode, gContext, kipperFnName]; RecordFunctionExport[implFileCode, gContext, unKipperFnName]; END; <<>> InstallNamedTypeDecl: PROC[code: Code, type: TypeNode] = BEGIN someNamesSeen: BOOLEAN _ FALSE; nameRope: Rope.ROPE _ NIL; SeeOneName: PROC[name: NameNode] = BEGIN IF someNamesSeen THEN nameRope _ Rope.Cat[nameRope, ", "] ELSE someNamesSeen _ TRUE; nameRope _ Rope.Cat[nameRope, GetNameNodeInfo[name].text]; END; GenAllNamesForType[type, SeeOneName]; IF NOT someNamesSeen THEN ERROR; AppendRopeCodeStatement[code, Rope.Cat[nameRope, ": TYPE = "]]; InstallTypeConstDecl[code, type]; ExtendRopeCodeStatement[code, ";"]; END; InstallTypeConstDecl: PROC[code: Code, type: TypeNode] = BEGIN case: TypeNodeCase _ GetTypeNodeCase[type]; SELECT case FROM naming => -- WARNING has to be fixed up for variant records BEGIN targetType: TypeNode _ GetNamingNodeNamedNode[type]; ExtendRopeCodeStatement[code, GetNameNodeInfo[GetTypeNodeName[targetType]].text]; RecordNamedTypeUse[code, targetType]; -- ExtendRopeCodeStatement[code, Rope.Cat[" ",GetNameNodeInfo[GetNamingNodePrimaryName[type]].text]]; END; enumerated => BEGIN someElementsSeen: BOOLEAN _ FALSE; SeeOneElement: PROC[elementName: NameNode] = BEGIN IF someElementsSeen THEN ExtendRopeCodeStatement[code, ", "] ELSE someElementsSeen _ TRUE; ExtendRopeCodeStatement[code, GetNameNodeInfo[elementName].text]; END; ExtendRopeCodeStatement[code, "{"]; GenEnumeratedElements[type, SeeOneElement]; ExtendRopeCodeStatement[code, "}"]; END; record => BEGIN someFieldsSeen: BOOLEAN _ FALSE; SeeOneField: PROC[fieldName: NameNode, fieldType: TypeNode, last: BOOLEAN] = BEGIN IF someFieldsSeen THEN ExtendRopeCodeStatement[code, ","] ELSE someFieldsSeen _ TRUE; AppendRopeCodeStatement[code, Rope.Cat[GetNameNodeInfo[fieldName].text, ": "]]; InstallTypeConstDecl[code, fieldType]; END; ExtendOpenRopeCodeStatement[code, "RECORD["]; GenRecordFields[type, SeeOneField]; ExtendClosingRopeCodeStatement[code, "]"]; END; ref => BEGIN ExtendRopeCodeStatement[code, "REF "]; InstallTypeConstDecl[code, GetRefTypeTarget[type]]; END; any => ExtendRopeCodeStatement[code, "ANY"]; list => BEGIN ExtendRopeCodeStatement[code, "LIST OF "]; InstallTypeConstDecl[code, GetListTypeValue[type]]; END; seq => -- SEQUENCE field in a record constructor BEGIN ExtendRopeCodeStatement[code, "SEQUENCE "]; ExtendRopeCodeStatement[code, GetNameNodeInfo[GetSeqTypeCountName[type]].text]; ExtendRopeCodeStatement[code, ": "]; InstallTypeConstDecl[code, GetSeqTypeCountType[type]]; ExtendRopeCodeStatement[code, " OF "]; InstallTypeConstDecl[code, GetSeqTypeFieldType[type]]; END; builtIn => ERROR; ENDCASE => ERROR; END; InstallNameOrTypeConstructor: PROC[code: Code, type: TypeNode] = BEGIN name: NameNode _ GetTypeNodeName[type]; IF name # NIL THEN ExtendRopeCodeStatement[code, GetNameNodeInfo[name].text] ELSE InstallTypeConstDecl[code, type]; END; <<>> AppendNeededProcVars: PROC[code: Code] = BEGIN AppendRopeCodeStatement[code, ""]; AppendRopeCodeStatement[code, "word: CARDINAL _ 0;"]; AppendRopeCodeStatement[code, "doubleWord: LONG CARDINAL _ 0;"]; AppendRopeCodeStatement[code, "refAny: REF ANY _ NIL;"]; AppendRopeCodeStatement[code, "flag: BOOLEAN _ FALSE;"]; AppendRopeCodeStatement[code, ""]; END; GetUltimateTargetType: PROC[type: TypeNode] RETURNS[TypeNode] = BEGIN-- only valid for REF and LIST types case: TypeNodeCase _ GetTypeNodeCase[type]; targetType: TypeNode _ SELECT case FROM ref => GetRefTypeTarget[type], list => GetListTypeValue[type], ENDCASE => ERROR; WHILE GetTypeNodeCase[targetType] = naming DO targetType _ GetNamingNodeNamedNode[targetType] ENDLOOP; RETURN[targetType]; END; GetFinalNamedType: PROC[type: TypeNode] RETURNS[TypeNode] = BEGIN finalType: TypeNode _ type; WHILE GetTypeNodeCase[finalType] = naming DO finalType _ GetNamingNodeNamedNode[finalType] ENDLOOP; RETURN[finalType]; END; <> <> KipperAType: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN case: TypeNodeCase _ GetTypeNodeCase[type]; valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; SELECT case FROM naming => KipperAType[gContext, code, GetNamingNodeNamedNode[type], exp, fieldCase]; enumerated, builtIn, record => GenKipperCodeForAType[gContext, code, type, exp, fieldCase]; ref, list => BEGIN -- we would like to call a procedure for these guys if possible -- it is only possible if they are namable, or the target type is . IF GetTypeNodeName[type] # NIL THEN -- this one is namable BEGIN fnName: NameNode _ AddTypeToWorkList[gContext, type, self, kipper]; fnNameText: Rope.ROPE _ GetNameNodeInfo[fnName].text; AppendRopeCodeStatement[code, Rope.Cat[fnNameText, "[kipperer, ", valExp, "];"]]; RecordFunctionCall[code, gContext, fnName]; END ELSE -- can't be named, but perhaps the target type can be named or is ANY BEGIN targetType: TypeNode _ GetUltimateTargetType[type]; targetName: NameNode _ GetTypeNodeName[targetType]; IF GetTypeNodeCase[targetType] = builtIn AND GetBuiltInTypeCase[targetType] = Any THEN BEGIN -- we are handling REF ANY fnName: NameNode _ AddTypeToWorkList[gContext, targetType, refTarget, kipper]; fnNameText: Rope.ROPE _ GetNameNodeInfo[fnName].text; AppendRopeCodeStatement[code, Rope.Cat[fnNameText, "[kipperer, ", valExp, "];"]]; END ELSE IF targetName # NIL THEN BEGIN -- target can be named mContext: KipperContext _ SELECT case FROM ref => refTarget, list => listTarget, ENDCASE => ERROR; fnName: NameNode _ AddTypeToWorkList[gContext, targetType, mContext, kipper]; fnNameText: Rope.ROPE _ GetNameNodeInfo[fnName].text; AppendRopeCodeStatement[code, Rope.Cat[fnNameText, "[kipperer, ", valExp, "];"]]; RecordFunctionCall[code, gContext, fnName]; END ELSE <> <> GenKipperCodeForAType[gContext, code, type, exp, fieldCase]; END; END; any => ERROR; -- can't happen ENDCASE => ERROR; END; <> <> <> UnKipperAType: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN case: TypeNodeCase _ GetTypeNodeCase[type]; valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; SELECT case FROM naming => UnKipperAType[gContext, code, GetNamingNodeNamedNode[type], exp, fieldCase]; enumerated, builtIn, record => GenUnKipperCodeForAType[gContext, code, type, exp, fieldCase]; ref, list => BEGIN -- we would like to call a procedure for these guys if possible -- it is only possible if they are namable, or the target type either namable or ANY. IF GetTypeNodeName[type] # NIL THEN -- this one is namable BEGIN fnName: NameNode _ AddTypeToWorkList[gContext, type, self, unKipper]; fnNameText: Rope.ROPE _ GetNameNodeInfo[fnName].text; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ ", fnNameText, "[unKipperer];"]]; RecordFunctionCall[code, gContext, fnName]; END ELSE -- can't be named, but perhaps the target type can be named BEGIN targetType: TypeNode _ GetUltimateTargetType[type]; targetName: NameNode _ GetTypeNodeName[targetType]; IF GetTypeNodeCase[targetType] = builtIn AND GetBuiltInTypeCase[targetType] = Any THEN BEGIN -- we are handling REF ANY fnName: NameNode _ AddTypeToWorkList[gContext, targetType, refTarget, unKipper]; fnNameText: Rope.ROPE _ GetNameNodeInfo[fnName].text; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ ", fnNameText, "[unKipperer];"]]; END ELSE IF targetName # NIL THEN BEGIN -- target can be named mContext: KipperContext _ SELECT case FROM ref => refTarget, list => listTarget, ENDCASE => ERROR; fnName: NameNode _ AddTypeToWorkList[gContext, targetType, mContext, unKipper]; fnNameText: Rope.ROPE _ GetNameNodeInfo[fnName].text; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ ", fnNameText, "[unKipperer];"]]; RecordFunctionCall[code, gContext, fnName]; END ELSE <> <> GenUnKipperCodeForAType[gContext, code, type, exp, fieldCase]; END; END; any => ERROR; -- cant happen ENDCASE; END; <> GenKipperCodeForAType: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN case: TypeNodeCase _ GetTypeNodeCase[type]; SELECT case FROM ref => KipperARef[gContext, code, GetRefTypeTarget[type], exp, fieldCase]; list => KipperAList[gContext, code, GetListTypeValue[type], exp, fieldCase]; record => KipperARecord[gContext, code, type, exp, fieldCase]; enumerated => KipperAnEnumType[gContext, code, type, exp, fieldCase]; builtIn => KipperABuiltIn[gContext, code, type, exp, fieldCase]; naming => ERROR; -- can't happen ENDCASE => ERROR; END; <> GenUnKipperCodeForAType: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN case: TypeNodeCase _ GetTypeNodeCase[type]; SELECT case FROM ref => UnKipperARef[gContext, code, GetRefTypeTarget[type], exp, fieldCase]; list => UnKipperAList[gContext, code, GetListTypeValue[type], exp, fieldCase]; record => UnKipperARecord[gContext, code, type, exp, fieldCase]; enumerated => UnKipperAnEnumType[gContext, code, type, exp, fieldCase]; builtIn => UnKipperABuiltIn[gContext, code, type, exp, fieldCase]; naming => ERROR; -- can't happen ENDCASE => ERROR; END; KipperARecord: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN seq: BOOLEAN _ GetRecordCase[type] = seq; subFieldCase: FieldExpCase _ FormSubFieldCase[fieldCase]; OneField: PROC[fieldName: NameNode, fieldType: TypeNode, last: BOOLEAN] = BEGIN fieldTextName: Rope.ROPE _ GetNameNodeInfo[fieldName].text; IF seq AND last THEN KipperASeq[gContext, code, fieldType, exp, fieldCase, fieldTextName] ELSE KipperAType[gContext, code, fieldType, Rope.Cat["(", exp, ".", fieldTextName, ")"], subFieldCase]; END; GenRecordFields[type, OneField]; END; UnKipperARecord: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN seq: BOOLEAN _ GetRecordCase[type] = seq; subFieldCase: FieldExpCase _ FormSubFieldCase[fieldCase]; OneField: PROC[fieldName: NameNode, fieldType: TypeNode, last: BOOLEAN] = BEGIN fieldTextName: Rope.ROPE _ GetNameNodeInfo[fieldName].text; IF seq AND last THEN UnKipperASeq[gContext, code, fieldType, exp, fieldCase, fieldTextName] ELSE UnKipperAType[gContext, code, fieldType, Rope.Cat["(", exp, ".", fieldTextName, ")"], subFieldCase]; END; GenRecordFields[type, OneField]; END; KipperASeq: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase, fieldTextName: Rope.ROPE] = BEGIN -- exp defines the record containing the seq field subFieldCase: FieldExpCase _ FormSubFieldCase[fieldCase]; fieldExp: Rope.ROPE _ Rope.Cat["(", exp, ".", fieldTextName, "[I])"]; countFieldTextName: Rope.ROPE _ GetNameNodeInfo[GetSeqTypeCountName[type]].text; countExp: Rope.ROPE _ Rope.Cat["(", exp, ".", countFieldTextName, ")"]; countFieldType: TypeNode _ GetSeqTypeCountType[type]; fieldType: TypeNode _ GetSeqTypeFieldType[type]; AppendRopeCodeStatement[code, "FOR I: "]; InstallNameOrTypeConstructor[code, countFieldType]; ExtendOpenRopeCodeStatement[code, Rope.Cat[" IN[0..", countExp, ") DO"]]; KipperAType[gContext, code, fieldType, fieldExp, subFieldCase]; AppendClosingRopeCodeStatement[code, "ENDLOOP;"]; END; UnKipperASeq: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase, fieldTextName: Rope.ROPE] = BEGIN subFieldCase: FieldExpCase _ FormSubFieldCase[fieldCase]; fieldExp: Rope.ROPE _ Rope.Cat["(", exp, ".", fieldTextName, "[I])"]; countFieldTextName: Rope.ROPE _ GetNameNodeInfo[GetSeqTypeCountName[type]].text; countExp: Rope.ROPE _ Rope.Cat["(", exp, ".", countFieldTextName, ")"]; countFieldType: TypeNode _ GetSeqTypeCountType[type]; fieldType: TypeNode _ GetSeqTypeFieldType[type]; AppendRopeCodeStatement[code, "FOR I: "]; InstallNameOrTypeConstructor[code, countFieldType]; ExtendOpenRopeCodeStatement[code, Rope.Cat[" IN[0..", countExp, ") DO"]]; UnKipperAType[gContext, code, fieldType, fieldExp, subFieldCase]; AppendClosingRopeCodeStatement[code, "ENDLOOP;"]; END; <<>> KipperAnEnumType: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN <> valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; AppendRopeCodeStatement[code, Rope.Cat["word _ ORD[", valExp, "];"]]; KipperACardinal[gContext, code, "word", localVal]; END; UnKipperAnEnumType: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN <> valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; UnKipperACardinal[gContext, code, "word", localVal]; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ VAL[word];"]]; END; <> KipperARef: PROC[gContext: GeneratorContext, code: Code, targetType: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN <> <<0 for body follows -- this agrees with Lupine "ref=NIL", when ref is non NIL.>> <<1 for NIL -- this agrees with Lupine "ref=NIL", when ref is NIL.>> <<2 for encoding as INT follows, assumes same ref was seen earlier>> <<>> valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; -- REF ANY must be treated different from other refs, since ANY is not a kipperable type. finalTargetType: TypeNode _ GetFinalNamedType[targetType]; IF GetTypeNodeCase[finalTargetType] = builtIn AND GetBuiltInTypeCase[finalTargetType] = Any THEN BEGIN -- we are handling REF ANY -- generate a call on the global ref any kipper procedure fnName: NameNode _ AddTypeToWorkList[gContext, finalTargetType, refTarget, kipper]; fnNameText: Rope.ROPE _ GetNameNodeInfo[fnName].text; AppendRopeCodeStatement[code, Rope.Cat[fnNameText, "[kipperer, ", valExp, "];"]]; END ELSE BEGIN -- normal REF case. seq: BOOLEAN _ GetTypeNodeCase[finalTargetType] = record AND GetRecordCase[finalTargetType] = seq; AppendOpenRopeCodeStatement[code, Rope.Cat["IF KipperRef[kipperer, ", valExp, "] THEN "]]; AppendRopeCodeStatement[code, "BEGIN"]; IF seq THEN -- we must kipper the count BEGIN seqFieldCountType: TypeNode _ IF seq THEN GetSeqTypeCountType[GetSeqFieldType[finalTargetType]] ELSE NIL; seqFieldCountName: NameNode _ IF seq THEN GetSeqTypeCountName[GetSeqFieldType[finalTargetType]] ELSE NIL; SeqFieldCountNameText: Rope.ROPE _ GetNameNodeInfo[seqFieldCountName].text; AppendRopeCodeStatement[code, "count: "]; InstallNameOrTypeConstructor[code, seqFieldCountType]; ExtendRopeCodeStatement[code, Rope.Cat[" _ ", valExp, ".", SeqFieldCountNameText, ";"]]; KipperAType[gContext, code, seqFieldCountType, "count", localVal]; END; KipperAType[gContext, code, finalTargetType, valExp, ref]; AppendClosingRopeCodeStatement[code, "END;"]; RecordCedarProcUse[code, "KipperRef", "KipperSupport"]; END; END; <<>> <> UnKipperARef: PROC[gContext: GeneratorContext, code: Code, targetType: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN <> <<0 for body follows -- this agrees with Lupine "ref=NIL", when ref is non NIL.>> <<1 for NIL -- this agrees with Lupine "ref=NIL", when ref is NIL.>> <<2 for encoding as INT follows, assumes same ref was seen earlier>> <<>> <> <<>> <<>> valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; -- REF ANY must be treated different from other refs, since ANY is not a kipperable type. finalTargetType: TypeNode _ GetFinalNamedType[targetType]; IF GetTypeNodeCase[finalTargetType] = builtIn AND GetBuiltInTypeCase[finalTargetType] = Any THEN BEGIN -- we are handling REF ANY -- generate a call on the global ref any unkipper procedure fnName: NameNode _ AddTypeToWorkList[gContext, finalTargetType, refTarget, unKipper]; fnNameText: Rope.ROPE _ GetNameNodeInfo[fnName].text; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ ", fnNameText, "[unKipperer];"]]; END ELSE BEGIN -- normal REF case. seq: BOOLEAN _ GetTypeNodeCase[finalTargetType] = record AND GetRecordCase[finalTargetType] = seq; seqFieldCountType: TypeNode _ IF seq THEN GetSeqTypeCountType[GetSeqFieldType[finalTargetType]] ELSE NIL; AppendRopeCodeStatement[code, Rope.Cat["[flag, refAny] _ UnKipperRef[unKipperer];"]]; AppendOpenRopeCodeStatement[code, Rope.Cat["IF flag THEN"]]; AppendRopeCodeStatement[code, "BEGIN"]; IF seq THEN BEGIN -- we must get the count AppendRopeCodeStatement[code, "count: "]; InstallNameOrTypeConstructor[code, seqFieldCountType]; ExtendRopeCodeStatement[code, ";"]; UnKipperAType[gContext, code, seqFieldCountType, "count", localVal]; END; AppendRopeCodeStatement[code, Rope.Cat["refAny _ NEW["]]; InstallNameOrTypeConstructor[code, finalTargetType]; IF seq THEN {ExtendRopeCodeStatement[code, "[count]"]}; ExtendRopeCodeStatement[code, "];"]; AppendRopeCodeStatement[code, Rope.Cat["RecordUnKipperedRef[unKipperer, refAny];"]]; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ NARROW[refAny];"]]; UnKipperAType[gContext, code, finalTargetType, exp, ref]; AppendClosingRopeCodeStatement[code, "END"]; AppendOpenRopeCodeStatement[code, " ELSE"]; AppendClosingRopeCodeStatement[code, Rope.Cat[valExp, " _ NARROW[refAny];"]]; RecordCedarProcUse[code, "UnKipperRef", "KipperSupport"]; RecordCedarProcUse[code, "RecordUnKipperedRef", "KipperSupport"]; END; END; <> KipperAList: PROC[gContext: GeneratorContext, code: Code, valueType: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN <<>> <> <> <> <<0 for body follows>> <<1 for NIL>> valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; AppendOpenRopeCodeStatement[code, "FOR cell: LIST OF "]; InstallNameOrTypeConstructor[code, valueType]; ExtendRopeCodeStatement[code, Rope.Cat[" _ ", valExp, ", cell.rest WHILE cell # NIL DO"]]; AppendRopeCodeStatement[code, "word _ 0;"]; KipperACardinal[gContext, code, "word", localVal]; KipperAType[gContext, code, valueType, Rope.Cat["(cell.first)"], longField]; AppendClosingRopeCodeStatement[code, "ENDLOOP;"]; AppendRopeCodeStatement[code, "word _ 1;"]; KipperACardinal[gContext, code, "word", localVal]; END; <> UnKipperAList: PROC[gContext: GeneratorContext, code: Code, valueType: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN <> valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; ExtendOpenRopeCodeStatement[code, ""]; AppendRopeCodeStatement[code, "BEGIN"]; AppendRopeCodeStatement[code, "temp: "]; InstallNameOrTypeConstructor[code, valueType]; ExtendRopeCodeStatement[code, ";"]; AppendRopeCodeStatement[code, "first, last, current: LIST OF "]; InstallNameOrTypeConstructor[code, valueType]; ExtendRopeCodeStatement[code, " _ NIL;"]; UnKipperACardinal[gContext, code, "word", localVal]; AppendOpenRopeCodeStatement[code, "WHILE word = 0 DO"]; UnKipperAType[gContext, code, valueType, "temp", localVal]; AppendRopeCodeStatement[code, "current _ LIST[temp];"]; AppendRopeCodeStatement[code, "IF last = NIL THEN first _ current ELSE last.rest _ current;"]; AppendRopeCodeStatement[code, "last _ current;"]; UnKipperACardinal[gContext, code, "word", localVal]; AppendClosingRopeCodeStatement[code, "ENDLOOP;"]; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ first;"]]; AppendClosingRopeCodeStatement[code, "END;"]; END; KipperABuiltIn: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN case: BuiltInTypeCase _ GetBuiltInTypeCase[type]; SELECT case FROM Cardinal => KipperACardinal[gContext, code, exp, fieldCase]; Int => KipperAnInt[gContext, code, exp, fieldCase]; Boolean => KipperABoolean[gContext, code, exp, fieldCase]; Rope => KipperARope[gContext, code, exp, fieldCase]; Any => KipperAnAny[gContext, code, type, exp, fieldCase]; Bool => KipperABoolean[gContext, code, exp, fieldCase]; Char => KipperAChar[gContext, code, exp, fieldCase]; Character => KipperAChar[gContext, code, exp, fieldCase]; Integer => KipperAnInteger[gContext, code, exp, fieldCase]; Nat => KipperANat[gContext, code, exp, fieldCase]; Real => KipperAReal[gContext, code, exp, fieldCase]; Word => KipperAWord[gContext, code, exp, fieldCase]; Card => KipperACard[gContext, code, exp, fieldCase]; ENDCASE => ERROR; END; UnKipperABuiltIn: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN case: BuiltInTypeCase _ GetBuiltInTypeCase[type]; SELECT case FROM Cardinal => UnKipperACardinal[gContext, code, exp, fieldCase]; Int => UnKipperAnInt[gContext, code, exp, fieldCase]; Boolean => UnKipperABoolean[gContext, code, exp, fieldCase]; Rope => UnKipperARope[gContext, code, exp, fieldCase]; Any => UnKipperAnAny[gContext, code, type, exp, fieldCase]; Bool => UnKipperABoolean[gContext, code, exp, fieldCase]; Char => UnKipperAChar[gContext, code, exp, fieldCase]; Character => UnKipperAChar[gContext, code, exp, fieldCase]; Integer => UnKipperAnInteger[gContext, code, exp, fieldCase]; Nat => UnKipperANat[gContext, code, exp, fieldCase]; Real => UnKipperAReal[gContext, code, exp, fieldCase]; Word => UnKipperAWord[gContext, code, exp, fieldCase]; Card => UnKipperACard[gContext, code, exp, fieldCase]; ENDCASE => ERROR; END; <> KipperACardinal: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {KipperOneWord[gContext, code, exp, fieldCase]}; UnKipperACardinal: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {UnKipperOneWord[gContext, code, exp, fieldCase]}; <> KipperAnInt: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {KipperDoubleWord[gContext, code, exp, fieldCase]}; UnKipperAnInt: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {UnKipperDoubleWord[gContext, code, exp, fieldCase]}; <> KipperABoolean: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; AppendRopeCodeStatement[code, Rope.Cat["word _ IF", valExp, "THEN 1 ELSE 0;"]]; KipperOneWord[gContext, code, "word", localVal] END; UnKipperABoolean: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; UnKipperOneWord[gContext, code, "word", localVal]; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ (word=1);"]]; END; <> KipperARope: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; AppendRopeCodeStatement[code, Rope.Cat["KipperRope[kipperer, ", valExp, "];"]]; RecordCedarTypeUse[code, "ROPE", "Rope"]; RecordCedarProcUse[code, "KipperRope", "KipperSupport"]; END; UnKipperARope: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; AppendRopeCodeStatement[code, Rope.Cat[valExp, "_ UnKipperRope[unKipperer];"]]; RecordCedarTypeUse[code, "ROPE", "Rope"]; RecordCedarProcUse[code, "UnKipperRope", "KipperSupport"]; END; <> <> KipperAnAny: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN IF fieldCase # ref THEN ERROR; AppendOpenRopeCodeStatement[code, Rope.Cat["IF ", exp, " = NIL THEN"]]; AppendRopeCodeStatement[code, "BEGIN"]; AppendRopeCodeStatement[code, "word _ 1;"]; KipperACardinal[gContext, code, "word", localVal]; AppendClosingRopeCodeStatement[code, "END"]; AppendOpenRopeCodeStatement[code, Rope.Cat[" ELSE WITH ", exp, " SELECT FROM"]]; BEGIN index: CARDINAL _ 2; InstallOneEntry: PROC[varName, varTypeText, fnNameText: Rope.ROPE] = BEGIN AppendOpenRopeCodeStatement[code, Rope.Cat[varName, ": ", varTypeText, " => "]]; AppendRopeCodeStatement[code, "BEGIN"]; AppendRopeCodeStatement[code, Rope.Cat["word _ ", Convert.RopeFromCard[index], ";"]]; KipperACardinal[gContext, code, "word", localVal]; AppendRopeCodeStatement[code, Rope.Cat[fnNameText, "[kipperer, ", varName, "];"]]; AppendClosingRopeCodeStatement[code, "END;"]; index _ index + 1; END; SeeOneType: PROC[xType: TypeNode, mContext: KipperContext, fnName: NameNode] = BEGIN -- we must avoid any types that are equivalent to ANY or REF ANY -- ANY itself will always be generated, because its presence on the work list is how we come to be in this procedure in the first place finalXType: TypeNode _ GetFinalNamedType[xType]; IF mContext = self THEN finalXType _ GetUltimateTargetType[finalXType]; IF GetTypeNodeCase[finalXType] # builtIn OR GetBuiltInTypeCase[finalXType] # Any THEN BEGIN varName: Rope.ROPE _ Rope.Cat["x", Convert.RopeFromCard[index]]; typeNameText: Rope.ROPE _ GetNameNodeInfo[GetTypeNodeName[xType]].text; varTypeText: Rope.ROPE _ SELECT mContext FROM self => typeNameText, refTarget => Rope.Cat["REF ", typeNameText], listTarget => Rope.Cat["LIST OF ", typeNameText], ENDCASE => ERROR; InstallOneEntry[varName, varTypeText, GetNameNodeInfo[fnName].text]; END; END; InstallOneEntry["rope", "Rope.ROPE", "KipperRope"]; InstallOneEntry["text", "REF TEXT", "KipperRefText"]; GenKipperedTypes[gContext, kipper, SeeOneType]; END; AppendClosingRopeCodeStatement[code, "ENDCASE => ERROR;"]; RecordCedarProcUse[code, "KipperRope", "KipperSupport"]; RecordCedarProcUse[code, "KipperRefText", "KipperSupport"]; END; <> <> UnKipperAnAny: PROC[gContext: GeneratorContext, code: Code, type: TypeNode, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN IF fieldCase # ref THEN ERROR; UnKipperACardinal[gContext, code, "word", localVal]; AppendRopeCodeStatement[code, "IF word = 1 THEN RETURN[NIL]"]; AppendOpenRopeCodeStatement[code, " ELSE SELECT word FROM"]; BEGIN index: CARDINAL _ 2; InstallOneEntry: PROC[fnNameText: Rope.ROPE] = BEGIN AppendRopeCodeStatement[code, Rope.Cat[ Rope.Cat[Convert.RopeFromCard[index], " => "], Rope.Cat[exp, " _ ", fnNameText, "[unKipperer];"]]]; index _ index + 1; END; SeeOneType: PROC[xType: TypeNode, mContext: KipperContext, fnName: NameNode] = BEGIN -- we must avoid any types that are equivalent to ANY or REF ANY -- ANY itself will always be generated, because its presence on the work list is how we come to be in this procedure in the first place finalXType: TypeNode _ GetFinalNamedType[xType]; IF mContext = self THEN finalXType _ GetUltimateTargetType[finalXType]; IF GetTypeNodeCase[finalXType] # builtIn OR GetBuiltInTypeCase[finalXType] # Any THEN InstallOneEntry[GetNameNodeInfo[fnName].text]; END; InstallOneEntry["UnKipperRope"]; InstallOneEntry["UnKipperRefText"]; GenKipperedTypes[gContext, unKipper, SeeOneType]; END; AppendClosingRopeCodeStatement[code, "ENDCASE => ERROR;"]; RecordCedarProcUse[code, "UnKipperRope", "KipperSupport"]; RecordCedarProcUse[code, "UnKipperRefText", "KipperSupport"]; END; <> KipperAChar: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; AppendRopeCodeStatement[code, Rope.Cat["word _ ORD[", valExp, "];"]]; KipperOneWord[gContext, code, "word", localVal] END; UnKipperAChar: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; UnKipperOneWord[gContext, code, "word", localVal]; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ VAL[word];"]]; END; <> KipperAnInteger: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {KipperOneWord[gContext, code, exp, fieldCase]}; UnKipperAnInteger: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {UnKipperOneWord[gContext, code, exp, fieldCase]}; <> KipperANat: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; AppendRopeCodeStatement[code, Rope.Cat["word _ ", valExp, ";"]]; KipperOneWord[gContext, code, "word", localVal] END; UnKipperANat: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN valExp: Rope.ROPE _ FormValExp[exp, fieldCase]; UnKipperOneWord[gContext, code, "word", localVal]; AppendRopeCodeStatement[code, Rope.Cat[valExp, " _ word;"]]; END; <> KipperAReal: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {KipperDoubleWord[gContext, code, exp, fieldCase]}; UnKipperAReal: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {UnKipperDoubleWord[gContext, code, exp, fieldCase]}; <> KipperAWord: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {KipperOneWord[gContext, code, exp, fieldCase]}; UnKipperAWord: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {UnKipperOneWord[gContext, code, exp, fieldCase]}; <> KipperACard: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {KipperDoubleWord[gContext, code, exp, fieldCase]}; UnKipperACard: PROC[gContext: GeneratorContext, code: Code, exp: Rope.ROPE, fieldCase: FieldExpCase] = {UnKipperDoubleWord[gContext, code, exp, fieldCase]}; <> <> KipperOneWord: PROC[gContext: GeneratorContext, code: Code, wordExp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN SELECT fieldCase FROM localVal, shortField => AppendRopeCodeStatement[code, Rope.Cat["UnsafePutBlock[kipperer.stream, [LOOPHOLE[LONG[@", wordExp, "], LONG POINTER TO RawBytes], 0, 2]];"]]; longField => AppendRopeCodeStatement[code, Rope.Cat["UnsafePutBlock[kipperer.stream, [LOOPHOLE[@", wordExp, ", LONG POINTER TO RawBytes], 0, 2]];"]]; ref => AppendRopeCodeStatement[code, Rope.Cat["UnsafePutBlock[kipperer.stream, [LOOPHOLE[", wordExp, ", LONG POINTER TO RawBytes], 0, 2]];"]]; ENDCASE => ERROR; END; UnKipperOneWord: PROC[gContext: GeneratorContext, code: Code, wordExp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN SELECT fieldCase FROM localVal, shortField => AppendRopeCodeStatement[code, Rope.Cat["IF UnsafeGetBlock[unKipperer.stream, [LOOPHOLE[LONG[@", wordExp, "], LONG POINTER TO RawBytes], 0, 2]] # 2 THEN ERROR;"]]; longField => AppendRopeCodeStatement[code, Rope.Cat["IF UnsafeGetBlock[unKipperer.stream, [LOOPHOLE[@", wordExp, ", LONG POINTER TO RawBytes], 0, 2]] # 2 THEN ERROR;"]]; ref => AppendRopeCodeStatement[code, Rope.Cat["IF UnsafeGetBlock[unKipperer.stream, [LOOPHOLE[", wordExp, ", LONG POINTER TO RawBytes], 0, 2]] # 2 THEN ERROR;"]]; ENDCASE => ERROR; END; <> KipperDoubleWord: PROC[gContext: GeneratorContext, code: Code, doubleWordExp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN SELECT fieldCase FROM localVal, shortField => AppendRopeCodeStatement[code, Rope.Cat["UnsafePutBlock[kipperer.stream, [LOOPHOLE[LONG[@", doubleWordExp, "], LONG POINTER TO RawBytes], 0, 4]];"]]; longField => AppendRopeCodeStatement[code, Rope.Cat["UnsafePutBlock[kipperer.stream, [LOOPHOLE[@", doubleWordExp, ", LONG POINTER TO RawBytes], 0, 4]];"]]; ref => AppendRopeCodeStatement[code, Rope.Cat["UnsafePutBlock[kipperer.stream, [LOOPHOLE[", doubleWordExp, ", LONG POINTER TO RawBytes], 0, 4]];"]]; ENDCASE => ERROR; END; UnKipperDoubleWord: PROC[gContext: GeneratorContext, code: Code, doubleWordExp: Rope.ROPE, fieldCase: FieldExpCase] = BEGIN SELECT fieldCase FROM localVal, shortField => AppendRopeCodeStatement[code, Rope.Cat["IF UnsafeGetBlock[unKipperer.stream, [LOOPHOLE[LONG[@", doubleWordExp, "], LONG POINTER TO RawBytes], 0, 4]] # 4 THEN ERROR;"]]; longField => AppendRopeCodeStatement[code, Rope.Cat["IF UnsafeGetBlock[unKipperer.stream, [LOOPHOLE[@", doubleWordExp, ", LONG POINTER TO RawBytes], 0, 4]] # 4 THEN ERROR;"]]; ref => AppendRopeCodeStatement[code, Rope.Cat["IF UnsafeGetBlock[unKipperer.stream, [LOOPHOLE[", doubleWordExp, ", LONG POINTER TO RawBytes], 0, 4]] # 4 THEN ERROR;"]]; ENDCASE => ERROR; END; <> <<(note the old Mesa convention for an array of unknown size)>> <> KipperArrayOfWord: PROC[code: Code, arrayExp, countExp: Rope.ROPE] = BEGIN ERROR END; UnKipperArrayOfWord: PROC[code: Code, arrayExp, countExp: Rope.ROPE] = BEGIN ERROR END; <> Code: TYPE = REF CodeBody; CodeBody: TYPE = RECORD[ text: Rope.ROPE, currentIndent: CARDINAL, context: TypeContextNode, variety: CodeVariety, codeName: NameNode, usage: Usage]; CodeVariety: TYPE = {def, impl}; BuildEmptyCode: PROC[context: TypeContextNode, name: NameNode, variety: CodeVariety] RETURNS[Code] = {RETURN[NEW[CodeBody_[NIL, 0, context, variety, name, BuildEmptyUsage[]]]]}; GetContextOfCode: PROC[code: Code] RETURNS[TypeContextNode] = {RETURN[code.context]}; <> <> <<>> <> <> <<>> <> << >> AppendOpenRopeCodeStatement: PROC[code: Code, statement: Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; IO.PutF[s, "\N"]; FOR I: CARDINAL IN [0..code.currentIndent) DO IO.PutF[s, " "] ENDLOOP; IO.PutF[s, "%g", IO.rope[statement]]; code.currentIndent _ code.currentIndent+3; code.text _ Rope.Cat[code.text, IO.RopeFromROS[s]]; END; AppendRopeCodeStatement: PROC[code: Code, statement: Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; IO.PutF[s, "\N"]; FOR I: CARDINAL IN [0..code.currentIndent) DO IO.PutF[s, " "] ENDLOOP; IO.PutF[s, "%g", IO.rope[statement]]; code.text _ Rope.Cat[code.text, IO.RopeFromROS[s]]; END; ExtendOpenRopeCodeStatement: PROC[code: Code, statement: Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; IO.PutF[s, "%g", IO.rope[statement]]; code.text _ Rope.Cat[code.text, IO.RopeFromROS[s]]; code.currentIndent _ code.currentIndent+3; END; ExtendRopeCodeStatement: PROC[code: Code, statement: Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; IO.PutF[s, "%g", IO.rope[statement]]; code.text _ Rope.Cat[code.text, IO.RopeFromROS[s]]; END; AppendClosingRopeCodeStatement: PROC[code: Code, statement: Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; IO.PutF[s, "\N"]; FOR I: CARDINAL IN [0..code.currentIndent) DO IO.PutF[s, " "] ENDLOOP; IO.PutF[s, "%g", IO.rope[statement]]; code.text _ Rope.Cat[code.text, IO.RopeFromROS[s]]; code.currentIndent _ code.currentIndent-3; END; AppendClosingOpenRopeCodeStatement: PROC[code: Code, statement: Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; IO.PutF[s, "\N"]; FOR I: CARDINAL IN [0..code.currentIndent-2) DO IO.PutF[s, " "] ENDLOOP; IO.PutF[s, "%g", IO.rope[statement]]; code.text _ Rope.Cat[code.text, IO.RopeFromROS[s]]; END; ExtendClosingRopeCodeStatement: PROC[code: Code, statement: Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; IO.PutF[s, "%g", IO.rope[statement]]; code.text _ Rope.Cat[code.text, IO.RopeFromROS[s]]; code.currentIndent _ code.currentIndent - 3; END; RecordFunctionCall: PROC[code: Code, gContext: GeneratorContext, fnName: NameNode] = BEGIN defFile: NameNode; implFile: NameNode; [defFile, implFile] _ GetFunctionInfo[gContext, fnName]; IF EqualNames[implFile, code.codeName] THEN RETURN; RecordNameUse[code.usage, fnName, defFile, import] END; RecordFunctionExport: PROC[code: Code, gContext: GeneratorContext, fnName: NameNode] = {RecordNameUse[code.usage, fnName, GetFunctionInfo[gContext, fnName].defFile, export]}; RecordNamedTypeUse: PROC[code: Code, type: TypeNode] = BEGIN defFileName: NameNode _ GetTypeNodeTypeDefFile[type]; IF EqualNames[code.codeName, defFileName] THEN RETURN; IF defFileName = NIL THEN RETURN; RecordNameUse[code.usage, GetTypeNodeName[type], defFileName, ref]; END; RecordCedarTypeUse: PROC[code: Code, type: Rope.ROPE, from: Rope.ROPE] = BEGIN typeName: NameNode _ BuildRopeName[type]; defFileName: NameNode _ BuildRopeName[from]; RecordNameUse[code.usage, typeName, defFileName, ref]; END; RecordCedarProcUse: PROC[code: Code, proc: Rope.ROPE, from: Rope.ROPE] = BEGIN procName: NameNode _ BuildRopeName[proc]; defFileName: NameNode _ BuildRopeName[from]; RecordNameUse[code.usage, procName, defFileName, import]; END; ShowCode: PUBLIC PROC[code: Code, on: IO.STREAM] = BEGIN IO.PutF[on, "%g", IO.rope[BuildDirectoryRope[code.usage]]]; IO.PutF[on, "%g: %g%g%g =\N", IO.rope[GetNameNodeInfo[code.codeName].text], IO.rope[IF code.variety = def THEN "CEDAR DEFINITIONS" ELSE "CEDAR PROGRAM"], IO.rope[BuildImportsRope[code.usage]], IO.rope[BuildExportsRope[code.usage]]]; IO.PutF[on, "BEGIN\N"]; IO.PutF[on, "%g", IO.rope[BuildOpenRope[code.usage]]]; IO.PutF[on, "%g", IO.rope[code.text]]; IO.PutF[on, "\N\NEND.."]; END; -- usage info Use: TYPE = {ref, import, export}; Usage: TYPE = REF UsageBody; UsageBody: TYPE = RECORD[ ht: HashTable]; UseInfo: TYPE = REF UseInfoBody; UseInfoBody: TYPE = RECORD[ bits: ARRAY Use OF BOOLEAN, names: HashTable]; NameInfo: TYPE = REF CARDINAL; -- just for non nil fill BuildEmptyUsage: PROC[] RETURNS[Usage] = {RETURN[NEW[UsageBody_[CreateHashTable[10]]]]}; RecordNameUse: PROC[usage: Usage, name: NameNode, fromFile: NameNode, use: Use] = BEGIN info: UseInfo _ NARROW[FindEntry[usage.ht, fromFile]]; IF info = NIL THEN BEGIN info _ NEW[UseInfoBody_[[FALSE, FALSE, FALSE], CreateHashTable[10]]]; MakeEntry[usage.ht, fromFile, info]; END; info.bits[use] _ TRUE; SELECT use FROM export => NULL; ref, import => BEGIN nameInfo: NameInfo _ NARROW[FindEntry[info.names, name]]; IF nameInfo = NIL THEN MakeEntry[info.names, name, NEW[CARDINAL_0]]; END; ENDCASE => ERROR; END; BuildDirectoryRope: PROC[usage: Usage] RETURNS[Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; empty: BOOLEAN _ TRUE; SeeOneFileEntry: PROC[useRef: REF ANY, fileName: NameNode] = BEGIN useInfo: UseInfo _ NARROW[useRef]; noNames: BOOLEAN _ TRUE; SeeOneNameEntry: PROC[nameRef: REF ANY, name: NameNode] = BEGIN IF noNames THEN noNames _ FALSE ELSE IO.PutF[s, ", "]; IO.PutF[s, "%g", IO.rope[GetNameNodeInfo[name].text]]; END; IF empty THEN {empty _ FALSE; IO.PutF[s, "DIRECTORY\N"]} ELSE IO.PutF[s, ",\N"]; IO.PutF[s, " %g USING[", IO.rope[GetNameNodeInfo[fileName].text]]; EnumerateHashTable[useInfo.names, SeeOneNameEntry]; IO.PutF[s, "]"]; END; EnumerateHashTable[usage.ht, SeeOneFileEntry]; IF NOT empty THEN IO.PutF[s, ";\N\N"]; RETURN[IO.RopeFromROS[s]]; END; BuildImportsRope: PROC[usage: Usage] RETURNS[Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; empty: BOOLEAN _ TRUE; SeeOneFileEntry: PROC[useRef: REF ANY, fileName: NameNode] = BEGIN useInfo: UseInfo _ NARROW[useRef]; IF useInfo.bits[import] THEN BEGIN IF empty THEN {empty _ FALSE; IO.PutF[s, " IMPORTS "]} ELSE IO.PutF[s, ", "]; IO.PutF[s, "%g", IO.rope[GetNameNodeInfo[fileName].text]]; END; END; EnumerateHashTable[usage.ht, SeeOneFileEntry]; IF NOT empty THEN IO.PutF[s, " "]; RETURN[IO.RopeFromROS[s]]; END; BuildExportsRope: PROC[usage: Usage] RETURNS[Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; empty: BOOLEAN _ TRUE; SeeOneFileEntry: PROC[useRef: REF ANY, fileName: NameNode] = BEGIN useInfo: UseInfo _ NARROW[useRef]; IF useInfo.bits[export] THEN BEGIN IF empty THEN {empty _ FALSE; IO.PutF[s, " EXPORTS "]} ELSE IO.PutF[s, ", "]; IO.PutF[s, "%g", IO.rope[GetNameNodeInfo[fileName].text]]; END; END; EnumerateHashTable[usage.ht, SeeOneFileEntry]; IF NOT empty THEN IO.PutF[s, " "]; RETURN[IO.RopeFromROS[s]]; END; BuildOpenRope: PROC[usage: Usage] RETURNS[Rope.ROPE] = BEGIN s: IO.STREAM _ IO.ROS[]; empty: BOOLEAN _ TRUE; SeeOneFileEntry: PROC[useRef: REF ANY, fileName: NameNode] = BEGIN useInfo: UseInfo _ NARROW[useRef]; IF useInfo.bits[ref] OR useInfo.bits[import] THEN BEGIN IF empty THEN {empty _ FALSE; IO.PutF[s, "OPEN "]} ELSE IO.PutF[s, ", "]; IO.PutF[s, "%g", IO.rope[GetNameNodeInfo[fileName].text]]; END; END; EnumerateHashTable[usage.ht, SeeOneFileEntry]; IF NOT empty THEN IO.PutF[s, ";\N\N"]; RETURN[IO.RopeFromROS[s]]; END; END..