<<>> <> <> <> <> <> <> DIRECTORY Arrays USING[ArrayIndirectNodeInfo, ArrayTypeProcs], CCTypes USING[AsIndexSet, BinaryTargetTypes, BreakPrintType, CCError, CCErrorCase, CCTypeProcs, CheckConformance, CheckFamilyInclusion, CoerceToType, ConformanceCheck, ContainsVariance, CreateCedarType, GetIndirectType, GetNElements, GetProcDataFromGroundType, GetRTargetType, LR, GetGroundTypeClass, sia], CirioSyntacticOperations USING[CompileForRHS, ParseTree], CirioTypes USING[CompilerContext, Mem, Node, Type, TypedCode], CedarCode USING[AMNodeConstructArrayNode, Code, CodeToDoApply, CodeToDoIndex, CodeToExtractField, ConcatCode, CreateCedarNode, ForceNodeIn, GetDataFromNode, GetTypeOfNode, LoadThroughIndirectNode, NodeAsIndex, OperationsBody, Operator, ShowNode, ShowNodeBracketed, StoreThroughIndirectNode], IO, Records USING[CreateRecordType, RecordTypeProcs], Rope, StructuredStreams; ArraysImpl: CEDAR PROGRAM IMPORTS CCTypes, CedarCode, CirioSyntacticOperations, IO, Records, Rope, StructuredStreams EXPORTS Arrays = BEGIN OPEN CSO: CirioSyntacticOperations, SS: StructuredStreams; CC: TYPE = CirioTypes.CompilerContext; Code: TYPE = CedarCode.Code; Type: TYPE = CirioTypes.Type; TypedCode: TYPE = CirioTypes.TypedCode; Mem: TYPE = CirioTypes.Mem; Node: TYPE = CirioTypes.Node; CCE: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE _ NIL] _ CCTypes.CCError; Operator: TYPE = CedarCode.Operator; <> ArrayTypeInfo: TYPE = REF ArrayTypeInfoBody; ArrayTypeInfoBody: TYPE = RECORD[ containsVariance: VarianceInfo, procs: REF Arrays.ArrayTypeProcs, suppliedndexSet: Type, actualIndexSet: Type, indexRecord: Type, self: Type, indirectType: Type, data: REF ANY]; VarianceInfo: TYPE = {dontKnow, deciding, yes, no}; CreateArrayType: PUBLIC PROC[indexSet: Type, procs: REF Arrays.ArrayTypeProcs, cc: CC, data: REF ANY] RETURNS[Type] = BEGIN ati: ArrayTypeInfo _ NEW[ArrayTypeInfoBody _ [dontKnow, procs, indexSet, CCTypes.AsIndexSet[indexSet, cc], NIL, NIL, NIL, data]]; type: Type _ ati.self _ CCTypes.CreateCedarType[$array, ArrayTypeCCTypeProcs, IndirectArrayCCTypeProcs, cc, ati]; ati.indexRecord _ Records.CreateRecordType[IndexRecordTypeProcs, cc, ati]; RETURN[type]; END; ArrayTypeCCTypeProcs: REF CCTypes.CCTypeProcs _ NEW[CCTypes.CCTypeProcs _[ checkConformance: ArrayCCTypesCheckConformance, checkFamilyInclusion: ArrayCCTypesCheckFamilyInclusion, isASingleton: ArrayCCTypesIsASingleton, binaryOperandTypes: ArrayCCTypesBinaryOperandTypes, containsVariance: ArrayCCTypesContainsVariance, operand: ArrayCCTypesOperand, applyOperand: ArrayCCTypesApplyOperand, apply: ArrayCCTypesApply, printType: ArrayCCTypesPrintType]]; ArrayCCTypesCheckConformance: PROC[valType, varType: Type, cc: CC, procData: REF ANY] RETURNS[CCTypes.ConformanceCheck] = BEGIN valInfo: ArrayTypeInfo _ NARROW[procData]; WITH CCTypes.GetProcDataFromGroundType[varType, cc] SELECT FROM varInfo: ArrayTypeInfo => BEGIN indexCheck1: CCTypes.ConformanceCheck _ CCTypes.CheckConformance[varInfo.actualIndexSet, valInfo.actualIndexSet, cc]; indexCheck2: CCTypes.ConformanceCheck _ CCTypes.CheckConformance[valInfo.actualIndexSet, varInfo.actualIndexSet, cc]; entryCheck: CCTypes.ConformanceCheck _ CCTypes.CheckConformance[valInfo.procs.getEntryType[cc, valInfo.data], varInfo.procs.getEntryType[cc, varInfo.data], cc]; IF indexCheck1 = no OR indexCheck2 = no OR entryCheck = no THEN RETURN[no]; IF indexCheck1 = dontKnow OR indexCheck2 = dontKnow OR entryCheck = dontKnow THEN RETURN[dontKnow]; RETURN[yes]; END; ENDCASE => RETURN[no]; END; ArrayCCTypesCheckFamilyInclusion: PROC[valType, varType: Type, cc: CC, procData: REF ANY] RETURNS[BOOLEAN] = BEGIN valInfo: ArrayTypeInfo _ NARROW[procData]; WITH CCTypes.GetProcDataFromGroundType[varType, cc] SELECT FROM varInfo: ArrayTypeInfo => BEGIN IF NOT CCTypes.CheckFamilyInclusion[valInfo.actualIndexSet, varInfo.actualIndexSet, cc] THEN RETURN[FALSE]; -- NOTE we know that the actualIndexSet will be a singleton Cedar Type family, hence we need not check in the opposite direction. IF NOT CCTypes.CheckFamilyInclusion[valInfo.procs.getEntryType[cc, valInfo.data], varInfo.procs.getEntryType[cc, varInfo.data], cc] THEN RETURN[FALSE]; RETURN[TRUE]; END; ENDCASE => RETURN[FALSE]; END; ArrayCCTypesIsASingleton: PROC[type: Type, cc: CC, procData: REF ANY] RETURNS[BOOLEAN] = {RETURN [ArrayCCTypesContainsVariance[type, cc, procData]=oldCrocky]}; oldCrocky: BOOL _ FALSE; ArrayCCTypesContainsVariance: PROC[type: Type, cc: CC, procData: REF ANY] RETURNS[BOOLEAN] = BEGIN info: ArrayTypeInfo _ NARROW[procData]; BEGIN ENABLE UNWIND => BEGIN IF info.containsVariance = deciding THEN info.containsVariance _ dontKnow; END; IF info.containsVariance = deciding THEN CCE[cirioError]; -- shouldnt happen IF info.containsVariance = dontKnow THEN BEGIN info.containsVariance _ deciding; IF CCTypes.ContainsVariance[info.procs.getEntryType[cc, info.data], cc] THEN info.containsVariance _ yes ELSE info.containsVariance _ no; END; RETURN[info.containsVariance = yes]; END; END; <> ArrayCCTypesBinaryOperandTypes: PROC[op: Operator, left, right: Type, cc: CC, procData: REF ANY] RETURNS[CCTypes.BinaryTargetTypes] = BEGIN info: ArrayTypeInfo _ NARROW[procData]; RETURN[[left, info.actualIndexSet]]; END; ArrayCCTypesOperand: PROC[op: Operator, lr: CCTypes.LR, tc: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN info: ArrayTypeInfo _ NARROW[procData]; SELECT op FROM $apply => SELECT lr FROM left => RETURN[tc]; ENDCASE => CCE[operation]; ENDCASE => CCE[operation]; END; ArrayCCTypesApplyOperand: PROC[operatorType: Type, operand: CirioSyntacticOperations.ParseTree, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN info: ArrayTypeInfo _ NARROW[procData]; tc1: TypedCode _ CSO.CompileForRHS[operand, info.indexRecord, cc]; tc2: TypedCode _ CCTypes.CoerceToType[info.indexRecord, tc1, cc]; code: Code _ CedarCode.ConcatCode[ tc2.code, CedarCode.CodeToExtractField["", tc2.type]]; RETURN[[code, info.actualIndexSet]]; END; ArrayCCTypesApply: PROC[operator: TypedCode, operand: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN info: ArrayTypeInfo _ NARROW[procData]; code: Code _ CedarCode.ConcatCode[ operator.code, CedarCode.ConcatCode[ operand.code, CedarCode.CodeToDoApply[operator.type, operand.type]]]; type: Type _ info.procs.getEntryType[cc, info.data]; RETURN[[code, type]]; END; ArrayCCTypesPrintType: PROC [to: IO.STREAM, type: Type, printDepth: INT, printWidth: INT, cc: CC, procData: REF ANY] = { info: ArrayTypeInfo _ NARROW[procData]; to.PutRope["ARRAY"]; CCTypes.BreakPrintType[to, info.actualIndexSet, 1, printWidth, cc, " "]; to.PutRope[" OF"]; CCTypes.BreakPrintType[to, info.procs.getEntryType[cc, info.data], printDepth-1, printWidth, cc, " "]; RETURN}; <<>> <> <<>> IndexRecordTypeProcs: REF Records.RecordTypeProcs _ NEW[Records.RecordTypeProcs _ [ getPaint: IndexRecordGetPaint, comparePaint: IndexRecordComparePaint, nFields: IndexRecordnFields, fieldIndexToName: IndexRecordFieldIndexToName, nameToFieldIndex: IndexRecordNameToFieldIndex, fieldIndexToType: IndexRecordFieldIndexToType]]; IndexRecordGetPaint: PROC[data: REF ANY] RETURNS[REF ANY] = {RETURN[NIL]}; IndexRecordComparePaint: PROC[data: REF ANY, otherPaint: REF ANY] RETURNS[BOOLEAN] = {RETURN[otherPaint = NIL]}; IndexRecordnFields: PROC[data: REF ANY] RETURNS[INT] = {RETURN[1]}; IndexRecordFieldIndexToName: PROC[index: INT, data: REF ANY] RETURNS[Rope.ROPE] = {RETURN[IF index = 0 THEN "" ELSE CCE[operation]]}; IndexRecordNameToFieldIndex: PROC[name: Rope.ROPE, data: REF ANY] RETURNS[INT] = {RETURN[IF Rope.Equal[name, ""] THEN 0 ELSE CCE[operation]]}; IndexRecordFieldIndexToType: PROC[index: INT, cc: CC, data: REF ANY] RETURNS[CirioTypes.Type] = BEGIN info: ArrayTypeInfo _ NARROW[data]; RETURN[info.actualIndexSet]; END; <> IndirectArrayCCTypeProcs: REF CCTypes.CCTypeProcs _ NEW[CCTypes.CCTypeProcs _[ createIndirectNode: CreateIndirectArray, getBitSize: ArrayBitSize, operand: IndirectArrayCCTypesOperand, indexOperand: ArrayCCTypesApplyOperand, -- code was identical, so used the same procedure index: IndirectArrayCCTypesIndex, printType: ArrayCCTypesPrintType]]; CreateIndirectArray: PROC [cc: CC, procData: REF ANY, indirectType, targetType: Type, mem: Mem] RETURNS [Node] ~ { info: ArrayTypeInfo _ NARROW[procData]; RETURN info.procs.createIndirectNode[cc, info.data, indirectType, targetType, mem]}; ArrayBitSize: PROC[indirectType, targetType: Type, cc: CC, procData: REF ANY] RETURNS[CARD] ~ { info: ArrayTypeInfo _ NARROW[procData]; RETURN info.procs.getBitSize[indirectType, cc, info.data]}; IndirectArrayCCTypesOperand: PROC[op: Operator, lr: CCTypes.LR, tc: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN SELECT op FROM $index => SELECT lr FROM left => RETURN[tc]; ENDCASE => CCE[operation]; $address => RETURN [tc]; ENDCASE => CCE[operation, "illegal operation"]; -- client error, illegal operation END; IndirectArrayCCTypesIndex: PROC[operator: TypedCode, operand: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN info: ArrayTypeInfo _ NARROW[procData]; code: Code _ CedarCode.ConcatCode[ operator.code, CedarCode.ConcatCode[ operand.code, CedarCode.CodeToDoIndex[operator.type, operand.type]]]; type: Type _ info.procs.getEntryType[cc, info.data]; RETURN[[code, CCTypes.GetIndirectType[type]]]; END; <> CreateArrayIndirectNode: PUBLIC PROC[type: Type, info: Arrays.ArrayIndirectNodeInfo] RETURNS[Node] = BEGIN RETURN[CedarCode.CreateCedarNode[ArrayIndirectOps, type, info]]; END; ArrayIndirectOps: REF CedarCode.OperationsBody _ NEW[CedarCode.OperationsBody _[ unaryOp: ArrayIndirectUnaryOp, store: ArrayIndirectStore, load: ArrayIndirectLoad, index: ArrayIndirectIndex, show: ArrayIndirectShow ]]; <<>> ArrayIndirectUnaryOp: PROC [op: CedarCode.Operator, type: CirioTypes.Type, node: CirioTypes.Node, cc: CC] RETURNS [CirioTypes.Node] = BEGIN indirectNodeData: Arrays.ArrayIndirectNodeInfo _ NARROW[CedarCode.GetDataFromNode[node]]; RETURN[indirectNodeData.getPointer[indirectNodeData.data, cc]]; END; ArrayIndirectStore: PROC[valType: Type, valNode: Node, indirectType: Type, indirectNode: Node, cc: CC] = BEGIN valTypeInfo: ArrayTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[valType, cc]]; valNodeData: REF ArrayData _ NARROW[CedarCode.GetDataFromNode[valNode]]; indirectNodeData: Arrays.ArrayIndirectNodeInfo _ NARROW[CedarCode.GetDataFromNode[indirectNode]]; nEntries: CARD _ CCTypes.GetNElements[valTypeInfo.actualIndexSet, cc]; FOR I: CARD IN [0..nEntries) DO indirectField: Node _ indirectNodeData.selectEntry[I, cc, indirectNodeData.data]; indirectFieldType: Type _ CedarCode.GetTypeOfNode[indirectField]; valField: Node _ valNodeData.procs.extractEntry[I, cc, valNodeData.data]; valFieldType: Type _ CedarCode.GetTypeOfNode[valField]; CedarCode.StoreThroughIndirectNode[valFieldType, valField, indirectFieldType, indirectField, cc]; ENDLOOP; END; ArrayIndirectLoad: PROC[indirectType: Type, indirectNode: Node, cc: CC] RETURNS[Node] = BEGIN targetType: Type _ CCTypes.GetRTargetType[indirectType, cc]; data: Arrays.ArrayIndirectNodeInfo _ NARROW[CedarCode.GetDataFromNode[indirectNode]]; RETURN[CreateArrayNode[targetType, DeferedLoadArrayProcs, data, cc, FALSE]] END; ArrayIndirectIndex: PROC[indirectOperatorType: Type, operandType: Type, indirectOperator: Node, operand: Node, cc: CC] RETURNS[Node] = BEGIN aiData: Arrays.ArrayIndirectNodeInfo _ NARROW[CedarCode.GetDataFromNode[indirectOperator]]; index: CARD _ CedarCode.NodeAsIndex[operandType, operand, cc]; RETURN[aiData.selectEntry[index, cc, aiData.data]]; END; ArrayIndirectShow: PROC[to: IO.STREAM, node: Node, depth: INT, width: INT, cc: CC] = { aiData: Arrays.ArrayIndirectNodeInfo _ NARROW[CedarCode.GetDataFromNode[node]]; iaType: Type _ CedarCode.GetTypeOfNode[node]; array: Node _ CedarCode.LoadThroughIndirectNode[iaType, node, cc]; to.PutChar['^]; CedarCode.ShowNode[to, array, depth, width, cc]; RETURN}; DeferedLoadArrayProcs: REF ArrayNodeProcs _ NEW[ArrayNodeProcs _[ extractEntry: DeferedLoadArrayExtractEntry]]; DeferedLoadArrayExtractEntry: PROC[index: CARD, cc: CC, data: REF ANY] RETURNS[Node] = BEGIN info: Arrays.ArrayIndirectNodeInfo _ NARROW[data]; indirectEntry: Node _ info.selectEntry[index, cc, info.data]; indirectEntryType: Type _ CedarCode.GetTypeOfNode[indirectEntry]; RETURN[CedarCode.LoadThroughIndirectNode[indirectEntryType, indirectEntry, cc]]; END; <> ArrayData: TYPE = RECORD[ type: Type, alreadyLoaded: BOOLEAN, procs: REF ArrayNodeProcs, data: REF ANY]; ArrayNodeProcs: TYPE = RECORD[ extractEntry: PROC[index: CARD, cc: CC, data: REF ANY] RETURNS[Node]]; ArrayOps: REF CedarCode.OperationsBody _ NEW[CedarCode.OperationsBody_[ forceIn: ArrayForceIn, apply: ArrayApply, show: ArrayShow]]; CreateArrayNode: PROC[arrayType: CirioTypes.Type, procs: REF ArrayNodeProcs, data: REF ANY, cc: CC, alreadyLoaded: BOOLEAN] RETURNS[CirioTypes.Node] = BEGIN node: Node _ CedarCode.CreateCedarNode[ArrayOps, arrayType, NEW[ArrayData _ [arrayType, alreadyLoaded, procs, data]]]; RETURN[node]; END; ArrayForceIn: PROC[type: Type, node: Node, cc: CC] RETURNS[Node] = BEGIN data: REF ArrayData _ NARROW[CedarCode.GetDataFromNode[node]]; IF data.alreadyLoaded THEN RETURN[node] ELSE BEGIN typeInfo: ArrayTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[type, cc]]; nEntries: CARD _ CCTypes.GetNElements[typeInfo.actualIndexSet, cc]; entries: LIST OF CirioTypes.Node _ NIL; FOR I: CARD DECREASING IN [0..nEntries) DO nominalEntry: CirioTypes.Node _ data.procs.extractEntry[I, cc, data.data]; entryType: CirioTypes.Type _ CedarCode.GetTypeOfNode[nominalEntry]; entry: CirioTypes.Node _ CedarCode.ForceNodeIn[entryType, nominalEntry, cc]; entries _ CONS[entry, entries]; ENDLOOP; RETURN[ConstructArrayNode[type, entries, cc]]; END; END; ArrayApply: PROC[operatorType: Type, operandType: Type, operator: Node, operand: Node, cc: CC] RETURNS[Node] = BEGIN data: REF ArrayData _ NARROW[CedarCode.GetDataFromNode[operator]]; typeInfo: ArrayTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[operatorType, cc]]; index: CARD _ CedarCode.NodeAsIndex[operandType, operand, cc]; RETURN[data.procs.extractEntry[index, cc, data.data]]; END; ArrayShow: PROC[to: IO.STREAM, node: Node, depth: INT, width: INT, cc: CC] = { data: REF ArrayData _ NARROW[CedarCode.GetDataFromNode[node]]; typeInfo: ArrayTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[data.type, cc]]; nEntries: CARD _ CCTypes.GetNElements[typeInfo.actualIndexSet, cc]; cWidth: INT _ width; iwidth: INT _ IF nEntries>1 THEN (width*2)/3 ELSE width; to.PutF["(%g)[", [cardinal[nEntries]] ]; IF depth < 1 THEN to.PutRope["..."] ELSE FOR I: CARD IN [0..nEntries) DO entry: Node _ data.procs.extractEntry[I, cc, data.data]; IF I>0 THEN {to.PutChar[',]; SS.Bp[to, lookLeft, CCTypes.sia, " "]} ELSE SS.Bp[to, lookLeft, CCTypes.sia]; IF cWidth < 0 THEN {to.PutRope["..."]; EXIT} ELSE CedarCode.ShowNodeBracketed[to, entry, depth-1, iwidth, cc]; cWidth _ cWidth-1; ENDLOOP; to.PutChar[']]; RETURN}; <> ConstructArrayNode: PUBLIC PROC[arrayType: CirioTypes.Type, entries: LIST OF CirioTypes.Node, cc: CC] RETURNS[CirioTypes.Node] = BEGIN <> <> <> <> <> IF entries = NIL OR CCTypes.GetGroundTypeClass[CedarCode.GetTypeOfNode[entries.first], cc] # $amnode THEN BEGIN typeInfo: ArrayTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[arrayType, cc]]; nEntries: CARD _ CCTypes.GetNElements[typeInfo.actualIndexSet, cc]; ca: ConstructedArray _ NEW[ConstructedArrayBody[nEntries]]; entryIndex: CARD _ 0; FOR ln: LIST OF CirioTypes.Node _ entries, ln.rest WHILE ln # NIL DO ca[entryIndex] _ ln.first; entryIndex _ entryIndex + 1; ENDLOOP; IF entryIndex # nEntries THEN CCE[operation, "not enough entries supplied"]; RETURN[CreateArrayNode[arrayType, ConstructedArrayProcs, ca, cc, TRUE]]; END ELSE BEGIN -- first entry is an amnode. We assume that they all are. We uncrate them and recompile. BUT, somehow this code should be in the Node implmentation. (See similar remarks in RecordsImpl.) RETURN[CedarCode.AMNodeConstructArrayNode[arrayType, entries, cc]]; END; END; ConstructedArray: TYPE = REF ConstructedArrayBody; ConstructedArrayBody: TYPE = RECORD[ SEQUENCE nEntries: CARDINAL OF Node]; ConstructedArrayProcs: REF ArrayNodeProcs _ NEW[ArrayNodeProcs_[ extractEntry: CAExtractEntry]]; CAExtractEntry: PROC[index: CARD, cc: CC, data: REF ANY] RETURNS[CirioTypes.Node] = BEGIN ca: ConstructedArray _ NARROW[data]; RETURN[ca[index]]; END; END.