DIRECTORY CCTypes USING[ApplyOperand, BinaryTargetTypes, BreakPrintType, CCError, CCErrorCase, CCTypeProcs, CheckConformance, CheckFamilyInclusion, CoerceToType, ConformanceCheck, ContainsVariance, CreateCedarType, GetGroundTypeClass, GetIndirectType, GetNilRefType, GetNodeType, GetNVariants, GetProcDataFromGroundType, GetProcDataFromType, GetRefAnyType, GetRTargetType, GetTargetTypeOfIndirect, Index, IsAnIndirect, IsASingleton, Load, LR, Operand, Operator, SelectIdField, UnaryOp], CedarCode USING[CodeToExtractField, CodeToLoadContentsOfAMNode, CodeToDoUnaryOp, CodeToLoadThroughIndirect, CodeToStoreUnpopped, ConcatCode, CreateCedarNode, ExtractFieldFromNode, ForceNodeIn, GetDataFromNode, GetTypeOfNode, LoadThroughIndirectNode, OperationsBody, SelectFieldFromNode, ShowNode, StoreThroughIndirectNode], CedarOtherPureTypes USING[CreateParseTreeNode], CirioSyntacticOperations USING[ParseTree], CirioTypes USING[BasicTypeInfo, Code, CompilerContext, Mem, Node, Type, TypedCode, TypeClass], IO, PointerTypes USING [CreatePointerType], RefTypes USING[RefNodeInfo], Rope; RefTypesImpl: CEDAR PROGRAM IMPORTS CCTypes, CedarCode, CedarOtherPureTypes, IO, PointerTypes, Rope EXPORTS RefTypes = BEGIN CC: TYPE = CirioTypes.CompilerContext; BasicTypeInfo: TYPE = CirioTypes.BasicTypeInfo; Type: TYPE = CirioTypes.Type; TypedCode: TYPE = CirioTypes.TypedCode; Code: TYPE = CirioTypes.Code; Mem: TYPE = CirioTypes.Mem; Node: TYPE = CirioTypes.Node; CCE: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE _ NIL] _ CCTypes.CCError; RefTargetTypeInfo: TYPE = REF RefTargetTypeInfoBody; RefTargetTypeInfoBody: TYPE = RECORD[ containsVarianceIsKnown: RTTCVKnown, containsVariance: BOOLEAN, self: Type, indirect: Type, bodyType: Type, -- NIL for a REF ANY target type, T for a REF T target. codeForBodyType: INT]; RTTCVKnown: TYPE = {no, deciding, yes}; CreateRefTargetType: PROC[bodyType: Type, codeForBodyType: INT, cc: CC] RETURNS[Type] = BEGIN rttInfo: RefTargetTypeInfo _ NEW[RefTargetTypeInfoBody_[ no, FALSE, -- any value will do, it will be ignored NIL, NIL, bodyType, codeForBodyType]]; type: Type _ rttInfo.self _ CCTypes.CreateCedarType[$refTargetType, RefTargetTypeCCTypeProcs, IndirectRefTargetTypeCCTypeProcs, cc, rttInfo]; RETURN[type]; END; SetRefTargetTypeContainsVariance: PROC[rttInfo: RefTargetTypeInfo, cc: CC] = BEGIN SELECT rttInfo.containsVarianceIsKnown FROM no => BEGIN rttInfo.containsVarianceIsKnown _ deciding; rttInfo.containsVariance _ (rttInfo.bodyType = NIL) OR CCTypes.ContainsVariance[rttInfo.bodyType, cc]; rttInfo.containsVarianceIsKnown _ yes; END; deciding => CCE[cirioError]; yes => RETURN; ENDCASE => CCE[cirioError]; END; RefTargetTypeCCTypeProcs: REF CCTypes.CCTypeProcs _ NEW[CCTypes.CCTypeProcs _[ checkConformance: RTTCCTypesCheckConformance, checkFamilyInclusion: RTTCCTypesCheckFamilyInclusion, isASingleton: RTTCCTypesIsASingleton, getNVariants: RTTCCTypesGetNVariants]]; RTTCCTypesCheckConformance: PROC[valType, varType: Type, cc: CC, procData: REF ANY] RETURNS[CCTypes.ConformanceCheck] = BEGIN valInfo: RefTargetTypeInfo _ NARROW[procData]; IF valInfo.containsVarianceIsKnown # yes THEN SetRefTargetTypeContainsVariance[valInfo, cc]; WITH CCTypes.GetProcDataFromGroundType[varType, cc] SELECT FROM varInfo: RefTargetTypeInfo => BEGIN IF varInfo.containsVarianceIsKnown # yes THEN SetRefTargetTypeContainsVariance[varInfo, cc]; IF varInfo.bodyType = NIL THEN RETURN[yes]; RETURN[CCTypes.CheckConformance[valInfo.bodyType, varInfo.bodyType, cc]]; END; ENDCASE => RETURN[no]; END; RTTCCTypesCheckFamilyInclusion: PROC[valType, varType: Type, cc: CC, procData: REF ANY] RETURNS[BOOLEAN] = BEGIN valInfo: RefTargetTypeInfo _ NARROW[procData]; IF valInfo.containsVarianceIsKnown # yes THEN SetRefTargetTypeContainsVariance[valInfo, cc]; WITH CCTypes.GetProcDataFromGroundType[varType, cc] SELECT FROM varInfo: RefTargetTypeInfo => BEGIN IF varInfo.containsVarianceIsKnown # yes THEN SetRefTargetTypeContainsVariance[varInfo, cc]; IF varInfo.bodyType = NIL THEN RETURN[TRUE]; IF valInfo.codeForBodyType # varInfo.codeForBodyType THEN RETURN[FALSE]; IF NOT CCTypes.CheckFamilyInclusion[valInfo.bodyType, varInfo.bodyType, cc] THEN CCE[cirioError, "ref target types found with equal typecodes and unequal body types"]; -- if the body type codes agree then the families should bloody well be equal. RETURN[TRUE]; END; ENDCASE => RETURN[FALSE]; END; RTTCCTypesIsASingleton: PROC[type: Type, cc: CC, procData: REF ANY] RETURNS[BOOLEAN] = BEGIN valInfo: RefTargetTypeInfo _ NARROW[procData]; IF valInfo.bodyType = NIL THEN RETURN[FALSE]; -- RTT(ANY) RETURN[CCTypes.IsASingleton[valInfo.bodyType, cc]]; END; RTTCCTypesGetNVariants: PROC[type: Type, cc: CC, procData: REF ANY] RETURNS[INT] = BEGIN info: RefTargetTypeInfo _ NARROW[procData]; IF info.containsVarianceIsKnown # yes THEN SetRefTargetTypeContainsVariance[info, cc]; RETURN[CCTypes.GetNVariants[info.bodyType, cc]]; END; IndirectRefTargetTypeCCTypeProcs: REF CCTypes.CCTypeProcs _ NEW[CCTypes.CCTypeProcs _[ store: IRTTCCTypesStore, load: IRTTCCTypesLoad]]; IRTTCCTypesStore: PROC[value: TypedCode, indirect: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN info: RefTargetTypeInfo _ NARROW[procData]; IF info.containsVariance THEN CCE[operation, "attempt to store into a variant record field"]; -- client error, attempt to store into a (possibly nested) variant record field or target of a REF ANY. (We shall eventually have to allow this for initialization.) BEGIN code: Code _ CedarCode.ConcatCode[ indirect.code, CedarCode.ConcatCode[ value.code, CedarCode.CodeToStoreUnpopped[indirect.type, value.type]]]; RETURN[[code, value.type]]; END; END; IRTTCCTypesLoad: PROC[indirect: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN code: Code _ CedarCode.ConcatCode[ indirect.code, CedarCode.CodeToLoadThroughIndirect[indirect.type]]; type: Type _ CCTypes.GetRTargetType[indirect.type, cc]; RETURN[[code, type]]; END; RefInfo: TYPE = REF RefInfoBody; RefInfoBody: TYPE = RECORD[ made: BOOL _ FALSE, target: Type, -- target = NIL is used for NIL REF. bti: BasicTypeInfo]; CreateRefAnyType: PUBLIC PROC[cc: CC, bti: BasicTypeInfo] RETURNS[Type] = { nominal: Type _ CCTypes.GetRefAnyType[cc]; IF nominal # NIL THEN RETURN[nominal]; {refInfo: RefInfo _ NEW[RefInfoBody_[TRUE, CreateRefTargetType[NIL, 0, cc], bti]]; -- the zero code here is meaningless type: Type _ CCTypes.CreateCedarType[$refAny, RefTypeCCTypeProcs, IndirectRefTypeCCTypeProcs, cc, refInfo]; RETURN[type]}}; CreateRefType: PUBLIC PROC[cc: CC, bti: BasicTypeInfo] RETURNS[Type] = { refInfo: RefInfo _ NEW[RefInfoBody_[FALSE, NIL, bti]]; type: Type _ CCTypes.CreateCedarType[$ref, RefTypeCCTypeProcs, IndirectRefTypeCCTypeProcs, cc, refInfo]; RETURN[type]}; SetReferent: PUBLIC PROC [refType, clientTargetType: Type, codeForClientTargetType: INT, cc: CC] ~ { refInfo: RefInfo ~ NARROW[CCTypes.GetProcDataFromType[refType]]; IF refInfo.made THEN CCE[cirioError, "Re-SetReferent"]; refInfo.target _ CreateRefTargetType[clientTargetType, codeForClientTargetType, cc]; refInfo.made _ TRUE; RETURN}; CreateNilRefType: PUBLIC PROC[cc: CC] RETURNS[Type] = BEGIN nominal: Type _ CCTypes.GetNilRefType[cc]; IF nominal # NIL THEN RETURN[nominal]; BEGIN refInfo: RefInfo _ NEW[RefInfoBody_[TRUE, NIL]]; type: Type _ CCTypes.CreateCedarType[$nilRef, NilRefTypeCCTypeProcs, IndirectNilRefTypeCCTypeProcs, cc, refInfo]; RETURN[type]; END; END; RefTypeCCTypeProcs: REF CCTypes.CCTypeProcs _ NEW[CCTypes.CCTypeProcs _[ checkConformance: RefCCTypesCheckConformance, binaryOperandTypes: RefCCTypesBinaryOperandTypes, getRTargetType: RefCCTypesGetRTargetType, operand: RefCCTypesOperand, indexOperand: RefCCTypesIndexOperand, coerceToType: RefCCTypesCoerceToType, unaryOp: RefCCTypesUnaryOp, selectIdField: RefCCTypesSelectIdField, index: RefCCTypesIndex, printType: RefCCTypesPrintType]]; RefCCTypesCheckConformance: PROC[valType, varType: Type, cc: CC, procData: REF ANY] RETURNS[CCTypes.ConformanceCheck] = BEGIN valInfo: RefInfo _ NARROW[procData]; WITH CCTypes.GetProcDataFromGroundType[varType, cc] SELECT FROM varInfo: RefInfo => BEGIN IF varInfo.target = NIL THEN RETURN[no]; -- var is NIL REF, we are not. RETURN[CCTypes.CheckConformance[CCTypes.GetIndirectType[valInfo.target], CCTypes.GetIndirectType[varInfo.target], cc]]; END; ENDCASE => RETURN[no]; END; RefCCTypesBinaryOperandTypes: PROC[op: CCTypes.Operator, left, right: Type, cc: CC, procData: REF ANY] RETURNS[CCTypes.BinaryTargetTypes] = BEGIN leftInfo: RefInfo _ NARROW[procData]; leftTargetTypeInfo: RefTargetTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[leftInfo.target, cc]]; SELECT op FROM $assign => RETURN[[CCTypes.GetIndirectType[leftTargetTypeInfo.bodyType], leftTargetTypeInfo.bodyType]]; $eq, $ne, $lt, $gt, $le, $ge => RETURN [[left, left]]; ENDCASE => CCE[cirioError]; END; RefCCTypesGetRTargetType: PROC[type: Type, cc: CC, procData: REF ANY] RETURNS[Type] = BEGIN refTypeInfo: RefInfo _ NARROW[procData]; refTargetTypeInfo: RefTargetTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[refTypeInfo.target, cc]]; RETURN[refTargetTypeInfo.bodyType]; END; RefCCTypesOperand: PROC[op: CCTypes.Operator, lr: CCTypes.LR, tc: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN refTypeInfo: RefInfo _ NARROW[procData]; refTargetTypeInfo: RefTargetTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[refTypeInfo.target, cc]]; IF refTargetTypeInfo.bodyType = NIL THEN -- we are dealing with a REF ANY RETURN[CCTypes.CoerceToType[CCTypes.GetNodeType[cc], tc, cc]] ELSE -- we are not dealing with a REF ANY SELECT op FROM $selectId, $uparrow, $index, $leftSideuparrow => RETURN[tc]; $dot, $extractId, $apply => -- try dereferencing first BEGIN tc1: TypedCode _ CCTypes.UnaryOp[$uparrow, tc, cc]; RETURN[CCTypes.Operand[op, lr, tc1, cc]]; END; $eq, $ne, $lt, $gt, $le, $ge => RETURN [tc]; ENDCASE => CCE[operation]; -- client error, invalid operation END; RefCCTypesIndexOperand: PROC[operatorType: Type, operand: CirioSyntacticOperations.ParseTree, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN refTypeInfo: RefInfo _ NARROW[procData]; refTargetTypeInfo: RefTargetTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[refTypeInfo.target, cc]]; IF refTargetTypeInfo.bodyType = NIL THEN -- we are dealing with a REF ANY BEGIN node: Node _ CedarOtherPureTypes.CreateParseTreeNode[operand, cc]; code: CirioTypes.Code _ CedarCode.CodeToLoadContentsOfAMNode[node]; type: Type _ CCTypes.GetNodeType[cc]; RETURN[[code, type]]; END ELSE -- we are not dealing with a REF ANY RETURN[CCTypes.ApplyOperand[refTargetTypeInfo.bodyType, operand, cc]]; END; RefCCTypesCoerceToType: PROC[targetType: Type, tc: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN refTypeInfo: RefInfo _ NARROW[procData]; refTargetTypeInfo: RefTargetTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[refTypeInfo.target, cc]]; bodyType: Type _ refTargetTypeInfo.bodyType; IF bodyType = NIL THEN CCE[typeConformity] ELSE BEGIN code1: Code _ CedarCode.ConcatCode[ tc.code, CedarCode.CodeToExtractField["&indirectToBody", tc.type]]; type1: Type _ CCTypes.GetIndirectType[bodyType]; RETURN[CCTypes.CoerceToType[targetType, [code1, type1], cc]]; END; END; RefCCTypesUnaryOp: PROC[op: CCTypes.Operator, arg: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN refTypeInfo: RefInfo _ NARROW[procData]; refTargetTypeInfo: RefTargetTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[refTypeInfo.target, cc]]; bodyType: Type _ refTargetTypeInfo.bodyType; code1: Code _ CedarCode.CodeToExtractField["&indirectToBody", arg.type]; SELECT op FROM $leftSideuparrow => BEGIN code: Code _ CedarCode.ConcatCode[ arg.code, code1]; type: Type _ CCTypes.GetIndirectType[bodyType]; RETURN[[code, type]]; END; $uparrow => BEGIN code2: Code _ CedarCode.CodeToLoadThroughIndirect[CCTypes.GetIndirectType[bodyType]]; code: Code _ CedarCode.ConcatCode[ arg.code, CedarCode.ConcatCode[ code1, code2]]; RETURN[[code, bodyType]]; END; ENDCASE => CCE[typeConformity]; -- client type error END; RefCCTypesSelectIdField: PROC[id: Rope.ROPE, fieldIndirectContext: Type, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN refTypeInfo: RefInfo _ NARROW[procData]; refTargetTypeInfo: RefTargetTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[refTypeInfo.target, cc]]; bodyType: Type _ refTargetTypeInfo.bodyType; code1: Code _ CedarCode.CodeToExtractField["&indirectToBody", fieldIndirectContext]; type1: Type _ CCTypes.GetIndirectType[bodyType]; tc2: TypedCode _ CCTypes.SelectIdField[id, type1, cc]; code: Code _ CedarCode.ConcatCode[code1, tc2.code]; RETURN[[code, tc2.type]]; END; RefCCTypesIndex: PROC[operator: TypedCode, operand: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN refTypeInfo: RefInfo _ NARROW[procData]; refTargetTypeInfo: RefTargetTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[refTypeInfo.target, cc]]; bodyType: Type _ refTargetTypeInfo.bodyType; code1: Code _ CedarCode.ConcatCode[ operator.code, CedarCode.CodeToExtractField["&indirectToBody", operator.type]]; type1: Type _ CCTypes.GetIndirectType[bodyType]; tc1: TypedCode _ [code1, type1]; RETURN[CCTypes.Index[tc1, operand, cc]]; END; RefCCTypesPrintType: PROC [to: IO.STREAM, type: Type, printDepth: INT, printWidth: INT, cc: CC, procData: REF ANY] = { refTypeInfo: RefInfo _ NARROW[procData]; refTargetTypeInfo: RefTargetTypeInfo _ NARROW[CCTypes.GetProcDataFromGroundType[refTypeInfo.target, cc]]; bodyType: Type _ refTargetTypeInfo.bodyType; refTypeClass: CirioTypes.TypeClass _ CCTypes.GetGroundTypeClass[type, cc]; IF refTypeClass = $refAny THEN to.PutRope["REF ANY"] ELSE { to.PutRope["REF"]; CCTypes.BreakPrintType[to, bodyType, printDepth-1, printWidth, cc, " "]; }; }; NilRefTypeCCTypeProcs: REF CCTypes.CCTypeProcs _ NEW[CCTypes.CCTypeProcs _[ checkConformance: NilRefCCTypesCheckConformance]]; NilRefCCTypesCheckConformance: PROC[valType, varType: Type, cc: CC, procData: REF ANY] RETURNS[CCTypes.ConformanceCheck] = BEGIN valInfo: RefInfo _ NARROW[procData]; WITH CCTypes.GetProcDataFromGroundType[varType, cc] SELECT FROM varInfo: RefInfo => RETURN[yes]; -- NIL REF conforms to all REF types. ENDCASE => RETURN[no]; END; IndirectRefTypeCCTypeProcs: REF CCTypes.CCTypeProcs _ NEW[CCTypes.CCTypeProcs _[ createIndirectNode: RefCreateIndirect, getBitSize: RefBitSize, operand: IRefCCTypesOperand, unaryOp: IRefCCTypesUnaryOp, store: IRefCCTypesStore, load: IRefCCTypesLoad, printType: RefCCTypesPrintType]]; IndirectNilRefTypeCCTypeProcs: REF CCTypes.CCTypeProcs _ NEW[CCTypes.CCTypeProcs _[ store: INilRefCCTypesStore, load: INilRefCCTypesLoad]]; RefCreateIndirect: PROC [cc: CC, procData: REF ANY, indirectType, targetType: Type, mem: Mem] RETURNS [Node] ~ { refInfo: RefInfo _ NARROW[procData]; IF refInfo.bti=NIL THEN CCE[cirioError, "CreateIndirect[bti-less Type]"]; RETURN refInfo.bti.createIndirectNode[refInfo.bti, cc, indirectType, targetType, mem]}; RefBitSize: PROC[indirectType, targetType: Type, cc: CC, procData: REF ANY] RETURNS[CARD] ~ { refInfo: RefInfo _ NARROW[procData]; IF refInfo.bti=NIL THEN CCE[cirioError, "GetBitSize[bti-less Type]"]; RETURN refInfo.bti.getBitSize[refInfo.bti, cc, indirectType, targetType]}; IRefCCTypesOperand: PROC[op: CCTypes.Operator, lr: CCTypes.LR, tc: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN SELECT op FROM $selectId, $index, $leftSideuparrow => -- try dereferencing first BEGIN tc1: TypedCode _ CCTypes.Load[tc, cc]; RETURN[CCTypes.Operand[op, lr, tc1, cc]]; END; $address => RETURN[tc]; ENDCASE => CCE[operation]; -- client error, invalid operation END; IRefCCTypesUnaryOp: PROC[op: CCTypes.Operator, arg: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN SELECT op FROM $address => BEGIN code: CirioTypes.Code _ CedarCode.ConcatCode[ arg.code, CedarCode.CodeToDoUnaryOp[op, arg.type]]; ptrType: Type _ PointerTypes.CreatePointerType[CCTypes.GetTargetTypeOfIndirect[arg.type], cc, NIL--same reasons as always (see default)--]; RETURN [[code, ptrType]]; END; ENDCASE => CCE[cirioError]; END; IRefCCTypesStore: PROC[value: TypedCode, indirect: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN code: Code _ CedarCode.ConcatCode[ indirect.code, CedarCode.ConcatCode[ value.code, CedarCode.CodeToStoreUnpopped[indirect.type, value.type]]]; RETURN[[code, value.type]]; END; IRefCCTypesLoad: PROC[indirect: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN code: Code _ CedarCode.ConcatCode[ indirect.code, CedarCode.CodeToLoadThroughIndirect[indirect.type]]; type: Type _ CCTypes.GetRTargetType[indirect.type, cc]; RETURN[[code, type]]; END; INilRefCCTypesStore: PROC[value: TypedCode, indirect: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN code: Code _ CedarCode.ConcatCode[ indirect.code, CedarCode.ConcatCode[ value.code, CedarCode.CodeToStoreUnpopped[indirect.type, value.type]]]; RETURN[[code, value.type]]; END; INilRefCCTypesLoad: PROC[indirect: TypedCode, cc: CC, procData: REF ANY] RETURNS[TypedCode] = BEGIN code: Code _ CedarCode.ConcatCode[ indirect.code, CedarCode.CodeToLoadThroughIndirect[indirect.type]]; type: Type _ CCTypes.GetRTargetType[indirect.type, cc]; RETURN[[code, type]]; END; RefNodeData: TYPE = RECORD[ indirectToRefTarget: Node, info: RefTypes.RefNodeInfo]; CreateRefNode: PUBLIC PROC[type: Type, info: RefTypes.RefNodeInfo, cc: CC] RETURNS[Node] = { IF NOT CCTypes.IsAnIndirect[CedarCode.GetTypeOfNode[info.indirectToClientTarget], cc] THEN CCE[cirioError, "RefTypesImpl.CreateRefNode given a non-indirect target node"]; {indirectToRefTarget: Node _ CreateIndirectRefTargetNode[info.clientTargetType, info.codeForClientTargetType, info.indirectToClientTarget, cc]; actualRefType: Type _ CreateRefType[cc, NIL--MJS, May 22, 1991: Hypothesis: this is OK 'case it'll never be needed--]; data: REF RefNodeData _ NEW[RefNodeData_[indirectToRefTarget, info]]; SetReferent[actualRefType, info.clientTargetType, info.codeForClientTargetType, cc]; RETURN[CedarCode.CreateCedarNode[RefNodeOps, actualRefType, data]]; }}; CreateNilRefNode: PUBLIC PROC[cc: CC] RETURNS[Node] = {RETURN[CedarCode.CreateCedarNode[NilRefNodeOps, CreateNilRefType[cc], NIL]]}; RefNodeOps: REF CedarCode.OperationsBody _ NEW[CedarCode.OperationsBody_[ getCurrentType: RefNodeGetCurrentType, extractField: RefNodeExtractField, show: RefNodeShow, getNodeRepresentation: RefNodeGetRepresentation]]; RefNodeGetCurrentType: PROC[node: Node, cc: CC] RETURNS[Type] = {RETURN[CedarCode.GetTypeOfNode[node]]}; RefNodeExtractField: PROC[id: Rope.ROPE, type: Type, node: Node, cc: CC] RETURNS[Node] = BEGIN data: REF RefNodeData _ NARROW[CedarCode.GetDataFromNode[node]]; SELECT TRUE FROM Rope.Equal[id, "&indirectToBody"] => BEGIN RETURN[CedarCode.SelectFieldFromNode["&body", CedarCode.GetTypeOfNode[data.indirectToRefTarget], data.indirectToRefTarget, cc]]; END; ENDCASE => CCE[cirioError]; -- shouldn't happen END; RefNodeShow: PROC[to: IO.STREAM, node: Node, depth: INT, width: INT, cc: CC] = { data: REF RefNodeData _ NARROW[CedarCode.GetDataFromNode[node]]; refType: Type _ CedarCode.GetTypeOfNode[node]; refTypeInfo: RefInfo _ NARROW[CCTypes.GetProcDataFromGroundType[refType, cc]]; target: Node _ CedarCode.LoadThroughIndirectNode[CCTypes.GetIndirectType[refTypeInfo.target], data.indirectToRefTarget, cc]; to.PutChar['^]; CedarCode.ShowNode[to, target, depth, width, cc]; RETURN}; RefNodeGetRepresentation: PROC[node: Node, cc: CC] RETURNS[REF ANY] = BEGIN data: REF RefNodeData _ NARROW[CedarCode.GetDataFromNode[node]]; RETURN[data.info]; END; NilRefNodeOps: REF CedarCode.OperationsBody _ NEW[CedarCode.OperationsBody_[ getCurrentType: NilRefNodeGetCurrentType, extractField: NilRefNodeExtractField, show: NilRefNodeShow, getNodeRepresentation: NilRefNodeGetRepresentation]]; NilRefNodeGetCurrentType: PROC[node: Node, cc: CC] RETURNS[Type] = {CCE[cirioError]}; NilRefNodeExtractField: PROC[id: Rope.ROPE, type: Type, node: Node, cc: CC] RETURNS[Node] = {CCE[operation, "NIL fault"]}; NilRefNodeShow: PROC[to: IO.STREAM, node: Node, depth: INT, width: INT, cc: CC] = {to.PutRope["NIL"]}; NilRefNodeGetRepresentation: PROC[node: Node, cc: CC] RETURNS[REF ANY] = {RETURN[NIL]}; IRefTargetData: TYPE = RECORD[ bodyType: Type, indirectToBody: Node]; CreateIndirectRefTargetNode: PROC[bodyType: Type, codeForBodyType: INT, indirectToBody: Node, cc: CC] RETURNS[Node] = BEGIN irtData: REF IRefTargetData _ NEW[IRefTargetData_[bodyType, indirectToBody]]; refTargetType: Type _ CreateRefTargetType[bodyType, codeForBodyType, cc]; node: Node _ CedarCode.CreateCedarNode[IndirectRTOps, CCTypes.GetIndirectType[refTargetType], irtData]; RETURN[node]; END; IndirectRTOps: REF CedarCode.OperationsBody _ NEW[CedarCode.OperationsBody_[ getCurrentType: IndirectRTGetCurrentType, store: IndirectRTStore, load: IndirectRTLoad, selectField: IndirectRTSelectField, show: IndirectRTShow]]; IndirectRTGetCurrentType: PROC[node: Node, cc: CC] RETURNS[Type] = BEGIN irtData: REF IRefTargetData _ NARROW[CedarCode.GetDataFromNode[node]]; RETURN[CCTypes.GetIndirectType[irtData.bodyType]]; END; IndirectRTStore: PROC[valType: Type, valNode: Node, indirectType: Type, indirectNode: Node, cc: CC] = BEGIN indirectData: REF IRefTargetData _ NARROW[CedarCode.GetDataFromNode[indirectNode]]; indirectBody: Node _ CedarCode.SelectFieldFromNode["&body", indirectType, indirectNode, cc]; indirectBodyType: Type _ CedarCode.GetTypeOfNode[indirectBody]; valBody: Node _ CedarCode.ExtractFieldFromNode["&body", valType, valNode, cc]; valBodyType: Type _ CedarCode.GetTypeOfNode[valBody]; CedarCode.StoreThroughIndirectNode[valBodyType, valBody, indirectBodyType, indirectBody, cc]; END; IndirectRTLoad: PROC[indirectType: Type, indirectNode: Node, cc: CC] RETURNS[Node] = BEGIN -- note: indirectType is compile time, and does not know the actual type. valType: Type _ CCTypes.GetRTargetType[CedarCode.GetTypeOfNode[indirectNode], cc]; data: REF IRefTargetData _ NARROW[CedarCode.GetDataFromNode[indirectNode]]; RETURN[CreateRTNode[valType, DelayedLoadExtractBody, data, cc, FALSE]]; END; IndirectRTSelectField: PROC[id: Rope.ROPE, indirectType: Type, indirectNode: Node, cc: CC] RETURNS[Node] = BEGIN data: REF IRefTargetData _ NARROW[CedarCode.GetDataFromNode[indirectNode]]; SELECT TRUE FROM Rope.Equal[id, "&body"] => RETURN[data.indirectToBody]; ENDCASE => CCE[cirioError]; -- shouldn't happen END; IndirectRTShow: PROC[to: IO.STREAM, node: Node, depth: INT, width: INT, cc: CC] = { to.PutChar['^]; IF depth = 0 THEN {to.PutRope["..."]; RETURN}; { irtType: Type _ CedarCode.GetTypeOfNode[node]; rt: Node _ CedarCode.LoadThroughIndirectNode[irtType, node, cc]; CedarCode.ShowNode[to, rt, depth, width, cc]; RETURN}}; DelayedLoadExtractBody: PROC[procData: REF ANY, cc: CC] RETURNS[Node] = BEGIN data: REF IRefTargetData _ NARROW[procData]; indirectBody: Node _ data.indirectToBody; indirectBodyType: Type _ CedarCode.GetTypeOfNode[indirectBody]; RETURN[CedarCode.LoadThroughIndirectNode[indirectBodyType, indirectBody, cc]]; END; RTData: TYPE = RECORD[ type: Type, alreadyIn: BOOLEAN, extractBody: PROC[procData: REF ANY, cc: CC] RETURNS[Node], procData: REF ANY]; CreateRTNode: PROC[type: Type, extractBody: PROC[procData: REF ANY, cc: CC] RETURNS[Node], procData: REF ANY, cc: CC, alreadyIn: BOOLEAN] RETURNS[Node] = BEGIN rtData: REF RTData _ NEW[RTData_[type, alreadyIn, extractBody, procData]]; node: Node _ CedarCode.CreateCedarNode[RTOps, type, rtData]; RETURN[node]; END; RTOps: REF CedarCode.OperationsBody _ NEW[CedarCode.OperationsBody_[ forceIn: RTForceIn, extractField: RTExtractField, show: RTShow]]; RTForceIn: PROC[type: Type, node: Node, cc: CC] RETURNS[Node] = BEGIN rtData: REF RTData _ NARROW[CedarCode.GetDataFromNode[node]]; IF rtData.alreadyIn THEN RETURN[node] ELSE BEGIN nominalBody: Node _ rtData.extractBody[rtData.procData, cc]; bodyType: Type _ CedarCode.GetTypeOfNode[nominalBody]; body: Node _ CedarCode.ForceNodeIn[bodyType, nominalBody, cc]; RETURN[ConstructRTNode[type, body, cc]]; END; END; RTExtractField: PROC[id: Rope.ROPE, type: Type, node: Node, cc: CC] RETURNS[Node] = BEGIN rtData: REF RTData _ NARROW[CedarCode.GetDataFromNode[node]]; SELECT TRUE FROM Rope.Equal[id, "&body"] => RETURN[rtData.extractBody[rtData.procData, cc]]; ENDCASE => CCE[cirioError]; -- shouldn't happen END; RTShow: PROC[to: IO.STREAM, node: Node, depth: INT, width: INT, cc: CC] = { rtData: REF RTData _ NARROW[CedarCode.GetDataFromNode[node]]; body: Node _ rtData.extractBody[rtData.procData, cc]; CedarCode.ShowNode[to, body, depth, width, cc]}; CRTNodeData: TYPE = RECORD[ body: Node]; ConstructRTNode: PROC[type: Type, body: Node, cc: CC] RETURNS[Node] = BEGIN data: REF CRTNodeData _ NEW[CRTNodeData_[body]]; RETURN[CreateRTNode[type, CRTNodeExtractBody, data, cc, TRUE]]; END; CRTNodeExtractBody: PROC[procData: REF ANY, cc: CC] RETURNS[Node] = BEGIN data: REF CRTNodeData _ NARROW[procData]; RETURN[NARROW[data.body]]; END; END.. 'è RefTypesImpl.mesa Copyright Ó 1990 by Xerox Corporation. All rights reserved. Sturgis, September 5, 1989 9:42:59 am PDT Last changed by Theimer on June 1, 1989 3:19:17 pm PDT Hopcroft July 26, 1989 10:41:56 am PDT Last tweaked by Mike Spreitzer on January 9, 1992 11:09 am PST Sturgis: November 28, 1988 11:10:39 am PST REF types present several problems because such constructors as REF VariantRecord do not produce the types that one would initially expect. We offer a brief discourse on how the following types work: VariantRecord ANY Sequence REF VariantRecord REF ANY REF Sequence REF REF VariantRecord REF REF ANY REF REF Sequence In this list of constructors, we use VariantRecord as shorthand for any record type expression containing a variant record construction, and we use Sequence as shorthand for any record type expression containing a SEQUENCE. Let VR stand for any of the type expressions: ANY, Sequence, and VariantRecord. VR denotes the obvious union type. (Let this type be T, a collection of types t B T.) REF VR denotes a union type, {Indirect TO RECORD[typeIndex: TypeIndex, body: t] | t B T}, with the constraint that if @[i, b] B REF VR, then i is an index for the type of b. Note that REF VR does not denote an Indirect To Union type, but rather a union of Indirect types. (I use Indirect as an unloaded word for pointer.) REF REF VR denotes an indirect type, specifically, an indirect to a union type: Indirect To {Indirect TO RECORD[typeIndex: TypeIndex, body: t] | t B T}. We can load through a REF VR. The result is that some record belonging to VR is (virtually) placed on the stack. This is implemented by the load through indirect code in the VariantRecordsImpl module. We cannot store through a REF VR. (Because REF VR is a union type, and the store would have to be type safe for all possible elements of REF VR. The actual Cedar compiler treats this a unsafe.) (It is possible to initialize the target of a REF VR, this is in effect a store through the Indirect TO VR, i.e., an indirect to a union type.) If we perform a field selection on a REF VR, there are three possibilities: 1) all components of the union have target types which accept the field selection using the same implementation, 2) some, but not all, of the targets of components of the union accept the field selection (or perhaps all accept the field selection, but with differing implementations), and 3) none of the targets of components of the union accept the field selection In case 1 we emit the field selection operation. In cases 2 and 3 a Cedar compiler would report a type error. We report a type error in case 3, while in case 2 we bundle the value into a Node, and let the run time figure out what to do. Further, in case 1, sometimes the resulting type is a union and sometimes not. If the selected field includes the variable part of the record constructor VR, then the resulting type is an appropriate union of indirect types. If the selected field does not include the variable part of the record constructor, then we get an indirect type. Finally, a REF REF VR is an indirect to a union type, not a union of indirects. We define the following four type families: RefTargets This is a collection of types. A union type (the target of a REF ANY), together with various levels of discrimination. This first level of discrimination will be a type. Subsequent levels depend on the first level type. If the first level type is a variant record, then subsequent levels are those appropriate to the variant record. IndirectRefTargets These are indirects to the various RefTargets types. Refs This is a collection of types. Each is an indirect, or union of indirects, to fully discriminated types among RefTargets. i.e., each is an indirect, or union of indirects, from among the IndirectRefTargets. Further, while REF ANY and REF VR are union types, REF REF ANY and REF REF VR are indirects to union types, rather than unions of indirects. If T is a union type, then REF T is a union of indirects if GetNVariants[T] # 0, otherwise it is an indirect to a union. [This will be modified when we add Sequence types, which have not been added as of December 15, 1988 9:30:16 am PST.] There are three classes of Ref types: REF ANY, REF T, and NIL REF. See comments in RefTypes.mesa. The REF ANY class is implemented as a REF T class, where T is the REF ANY Target type. IndirectRefs These are vanilla indirects to Ref types. The target type is sometimes a union, depending on the Ref. We begin with RefTargets We could proceed as we do in the VariantRecords module: define a Struct record that describes the whole family of types, then define an Info record that describes a specific type in the family. However, there is only one family, hence there is no need for a Struct. Further, we need not keep around the list of modifiers (such as we do in VariantRecords.VRInfo) because they will be embedded in the specific target type. We choose not to keep an array of the possible variants, but build them on demand. WARNING: At some point we have to add the code to (1) treat REF ANY TARGET as a value to be bundled up into a node whenever any operation approaches, and (2) be prepared to try field references through an intermediate node. These should follow from the default coercion mechanisms invoked by Operand etc. We avoid setting containsVariance at creation. Otherwise the following nasty loop occurs: someone asks if rcd type R contains variance. That question results in asking that question for each field, and in particular, creating each field type. Suppose one of these field types is REF R. Then we end up creating REF R, hence creating a RefTargetType for R. If we ask about the variance for R during that operation, we have a cycle. But we must ask about the variance for R in order to set the containsVariance field. This will blow up for a REF ANY, what should we do? What should be the correct anwer? Better yet, how can we prevent anyone from calling this? We continue with Indirect Ref Targets Warning: At some point I have to come to grips with both the coerce mechansim (that inserts needed default dereferences and unbracketing), and the node mechanism (that packages everything up into nodes for run time examination (when we are presented with a ref any target type). That is, if an operation can be applied to the target type, then we must generate code to get us to a value of that targt type. Further, when it might be applied to a target type, then we bundle up into nodes. The code for load and store seems to be common to a lot of types. How can we make use of this fact? so it is ok to do it It is legal to load through an indirect to a union type. What we must prevent is loading through a union of indirects, i.e., a REF type. Now we can address REF types themselves. When made is FALSE, we don't yet know what this is a REF to. The target is the RefTargetType to which the Ref implicitly points Note: ClientTarget is frequently called Body in the code in this module someone is trying to store through the REF arrange to give him an indirect to the body Someone is trying to do an assignment through a REF and needs a (tentative) target type for the compilation of the right hand side. Lets give him the client target type. True Cedar would reject this situation We package everything up into nodes and try again at run time True Cedar would reject this situation generate code to package the operand into a node. This will cause the caller to package the operator into a node and try again at run time. treat the operand the same as would be done for an ApplyOperand of the ref target type By the time we get here, we know that we do not conform So we try handing out an indirect to the body of the target This is exactly what RefCCTypesBinaryOperandTypes is expecting us to do when we are the left hand side of an assignment. we are a ref any. We can not be coerced to any reasonable type Moreover, the nominal mechanism would produce a NIL for a type at a later stage and this would be very bad. (I could fix that by not using a NIL at refTargetTypeInfo.bodyType to represent REF ANY.) So we just generate a type error. hopefully, the id will be recognized by the body The code for load and store seems to be common to a lot of types. How can we make use of this fact? note: this is identical to the code for DefaultIndirect. How might we safely take advantage of this? Nodes begin here There are four types which are candidates for node constructions. Not all are necessary here. Currently (December 15, 1988) PrincOpsFrameContextImpl provides a general mechanism for indirects to fields from which atomic loads and stores will be made. This mechanism suffices for Indirects to Refs. (Eventually, that mechanism will be moved to a more general location that is not target world specific. However, it should still be a general machanism that will cover indirects to Refs.) That leaves nodes of three varieties: Refs, indirects to RefTargets, and RefTargets. Ref nodes Note: ClientTarget is frequently refered to as Body in the code in this module. We can compute the actualRefType safely since the target of a REF can not change its type. Or, another way to say this, is that if type is for a REF ANY, then type is a union type, and the rule is that when loading a union type, we construct a node whose type is the type of the actually loaded value. since ref targets never change type, when this node was created it acquired a type that will always be good. Not sure what I should implement. A NARROW should always succeed. Not sure if there are other clients. hmm, if the rope was "&indirectToBody" maybe I should have returned a nilIndirectToClientBody, which would have rejected whatever the subsequent operation was. The interface says this returns NIL. Indirects to RefTargets GetCurrentType returns an indirect to the type of the client data in the target, as opposed to the type of the RefTarget, i.e., a pair . I am not sure what is intended here. At this writing, I am now sure when these store will be generated RefTarget nodes Constructed RTNodes ÊY•NewlineDelimiter ™codešœ™K™—K˜Kšœ*™*K˜šÏk ˜ Kšœœ œ-˜ÜKšœ œ´˜ÃKšœœ˜/Kšœœ ˜*Kšœ œN˜^Kšœ˜Kšœ œ˜'Kšœ œ˜Kšœ˜—K˜šÏn œœ˜Kšœ*œ˜GKšœ ˜—Kšœ˜Kšœœ˜&Kšœœ˜/Kšœœ˜Kšœ œ˜'Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ&œœ˜NK˜šœÉ™ÉKšœ ™ Kšœ™Kšœ™Kšœ™Kšœ™Kšœ ™ Kšœ™Kšœ ™ Kšœ™—K™Kšœ°™°K™KšœV™VKšœÃ™ÃšœO™OKšœH™H—K™KšœÊ™ÊK™KšœÔ™ÔK™Kšœÿ™ÿK™KšœO™OK™K™šœ+™+K™šœ ™ KšœÐ™Ð—K™šœ™Kšœ4™4—K™šœ™KšœÏ™Ïšœº™ºK™——šœ ™ Kšœf™f——K™šœ™™Kšœ¦™¦K™KšœR™RK™Kšœ±™±K™Kšœˆ™ˆ—K™Kšœœœ˜4šœœœ˜%K˜$Kšœœ˜K˜ K˜KšœÏc7˜GKšœœ˜—K˜Kšœ œ˜'K˜š žœœ"œœœ˜WKš˜šœœ˜8K˜KšœŸ(˜/Kšœ˜Kšœ˜K˜ K˜—K˜Kšœ˜ Kšœ˜—K˜šž œœ!œ˜LKš˜šœ!˜+˜Kš˜K˜+Kšœ/œœ0˜fK˜&Kšœ˜—Kšœ œ ˜Kšœœ˜Kšœœ ˜—Kšœ˜—K˜šžœœœ˜NK˜-K˜5K˜%K˜'—K˜š žœœœ œœœ˜wKš˜Kšœœ ˜.Kšœ'œ/˜\šœ0œ˜?˜Kš˜Kšœ'œ/˜\Kšœœœœ˜+KšœC˜IKšœ˜—Kšœœ˜—Kšœ˜—K˜šžœœœ œœœœ˜jKš˜Kšœœ ˜.Kšœ'œ/˜\šœ0œ˜?˜Kš˜Kšœ'œ/˜\Kš œœœœœ˜,K˜Kšœ3œœœ˜HKš œœFœœTŸN˜öKšœœ˜ K˜Kšœ˜—Kšœœœ˜—Kšœ˜—K˜šžœœœ œœœœ˜VKš˜Kšœœ ˜.Kš œœœœœŸ ˜9Kšœ-˜3Kšœ˜—˜Kšœ™—šžœœœ œœœœ˜RKš˜Kšœœ ˜+Kšœ$œ,˜VKšœ*˜0Kšœ˜K˜—K˜K˜—K™šœ%™%K™Kšœê™êK™šž œœœ˜VK˜K˜—˜Kšœd™d—K˜š žœœ,œ œœœ ˜mKš˜Kšœœ ˜+K˜Kšœœœ=Ÿ¤˜‚K˜šœ™Kš˜˜"K˜˜K˜ K˜;——Kšœ˜Kšœ˜—Kšœ˜—˜Kšœ‰™‰—š žœœœ œœœ ˜ZKš˜˜"K˜K˜4—K˜7Kšœ˜Kšœ˜—K˜—K˜šœ(™(K™—Kšœ œœ ˜ šœ œœ˜šœœœ˜K™<—KšœŸ$˜2Kšœ˜KšœB™BšœG™GK™——K˜š žœœœœœ ˜KK˜*Kšœ œœœ ˜&KšœœœœŸ$˜xK˜kKšœ ˜—K˜š ž œœœœœ ˜HKšœœœœ˜6K˜hKšœ˜—K˜š ž œœœ<œœ˜dKšœœ'˜@Kšœœœ˜7KšœT˜TKšœœ˜Kšœ˜—K˜š žœœœœœ˜5Kš˜K˜*šœ œœœ ˜&Kš˜Kšœœœœ˜0K˜qKšœ˜ Kšœ˜—Kšœ˜—K˜šžœœœ˜HK˜-K˜1K˜)K˜K˜%K˜%K˜K˜'K˜K˜!—K˜š žœœœ œœœ˜wKš˜Kšœœ ˜$šœ0œ˜?˜Kš˜Kš œœœœŸ˜GKšœq˜wKšœ˜—Kšœœ˜—Kšœ˜—K˜š žœœ.œ œœœ˜‹Kš˜Kšœœ ˜%Kšœ(œ9˜gšœ˜˜ Kšœ*™*Kšœ+™+KšœV˜\—Kšœ œ˜6Kšœœ ˜—Kšœ˜—K˜™Kšœ©™©—š žœœœ œœœ˜UKš˜Kšœœ ˜(Kšœ'œ<˜iKšœ˜#Kšœ˜—K˜šžœœ#œœ œœœ ˜|Kš˜Kšœœ ˜(Kšœ'œ<˜išœœœŸ ˜IKšœ&™&Kšœ=™=Kšœ7˜=—šœŸ$˜)šœ˜Kšœ1œ˜<šœŸ˜6Kš˜K˜3Kšœ#˜)Kšœ˜—Kšœ œ˜,Kšœœ Ÿ"˜=——Kšœ˜—K˜š žœœFœ œœœ ˜Kš˜Kšœœ ˜(Kšœ'œ<˜išœœœŸ ˜IKšœ&™&KšœŒ™ŒKš˜K˜BK˜CK˜%Kšœ˜Kš˜šœŸ$˜)KšœV™VKšœ@˜F——Kšœ˜—˜Kšœ7™7šœ;™;Kšœx™x——š žœœ&œ œœœ ˜mKš˜Kšœœ ˜(Kšœ'œ<˜iK˜,šœ œœ˜Kšœ?™?KšœÆ™ÆKšœ!™!Kšœ˜š˜Kš˜˜#K˜K˜:—K˜0Kšœ7˜=Kšœ˜——Kšœ˜—K˜š žœœ+œ œœœ ˜mKš˜Kšœœ ˜(Kšœ'œ<˜iK˜,K˜Hšœ˜˜Kš˜˜"K˜ K˜—K˜/Kšœ˜Kšœ˜—˜ Kš˜K˜U˜"K˜ ˜K˜K˜——Kšœ˜Kšœ˜—KšœœŸ˜4—Kšœ˜—K˜˜Kšœ0™0—šžœœ œ"œ œœœ ˜xKš˜Kšœœ ˜(Kšœ'œ<˜iK˜,K˜TK˜0K˜6K˜3Kšœ˜Kšœ˜—K˜š žœœ.œ œœœ ˜nKš˜Kšœœ ˜(Kšœ'œ<˜iK˜,˜#K˜K˜@—K˜0K˜ Kšœ"˜(Kšœ˜—K˜šžœœœœœœœ œœ˜vKšœœ ˜(Kšœ'œ<˜iK˜,K˜Jšœ˜Kšœ˜šœ˜K˜KšœH˜HKšœ˜——K˜—K˜šžœœœ˜KK˜2—K˜š žœœœ œœœ˜zKš˜Kšœœ ˜$šœ0œ˜?˜KšœŸ%˜2—Kšœœ˜—Kšœ˜—K˜K˜K˜šžœœœ˜PK˜&K˜K˜K˜K˜K˜K˜!—K˜šžœœœ˜SK˜K˜—˜Kšœd™d—K˜š žœœœ œœ,œ ˜pKšœœ ˜$Kšœ œœœ.˜IKšœQ˜W—K˜šž œœ%œ œœœœ˜]Kšœœ ˜$Kšœ œœœ*˜EKšœD˜J—K˜šžœœ#œœ œœœ ˜}Kš˜šœ˜šœ'Ÿ˜AKš˜K˜&Kšœ#˜)Kšœ˜—Kšœ œ˜Kšœœ Ÿ"˜=—Kšœ˜—K˜˜K™e—š žœœ+œ œœœ ˜nKš˜šœ˜šœ ˜ Kš˜˜-K˜ Kšœ)˜)—Kšœ^Ÿ(œ˜‹Kšœ˜Kšœ˜—Kšœœ ˜—Kšœ˜K˜—š žœœ,œ œœœ ˜mKš˜˜"K˜˜K˜ K˜;——Kšœ˜Kšœ˜—K˜š žœœœ œœœ ˜ZKš˜˜"K˜K˜4—K˜7Kšœ˜Kšœ˜—K˜š žœœ,œ œœœ ˜pKš˜˜"K˜˜K˜ K˜;——Kšœ˜Kšœ˜—K˜š žœœœ œœœ ˜]Kš˜˜"K˜K˜4—K˜7Kšœ˜Kšœ˜—K˜šœ™K™—˜Kšœê™êKšœT™TK˜K˜Kšœ ™ ™šœ œœ˜K˜K˜˜KšœO™O—Kšœ¯™¯—š ž œœœ-œœ ˜\KšœœPœœL˜ªK˜Kšœ(ŸIœ˜vKšœœœ*˜EKšœT˜TKšœ=˜CKšœ˜—K˜š žœœœœœ˜5Kšœœ@œ˜NK˜K˜K˜—K˜šž œœœ˜IK˜&K˜"K˜K˜2—K˜˜Kšœl™l—šžœœœœ˜?Kšœœ!˜(—K™K˜š žœœ œœœ˜XKš˜Kšœœœ"˜@šœœ˜˜$Kš˜K˜Kšœz˜€Kšœ˜—KšœœŸ˜/—Kšœ˜—K˜šž œœœœœ œœ˜PKšœœœ"˜@K˜.Kšœœ1˜NK˜|K˜Kšœ1˜1Kšœ˜—K˜š žœœœœœœ˜EKš˜Kšœœœ"˜@Kšœ ˜Kšœ˜—K˜šž œœœ˜LK˜)K˜%K˜K˜5—K˜šžœœœœ˜Bšœœ˜Kšœh™h——K˜š žœœ œœœ˜[šœœ˜KšœŸ™Ÿ——K˜šžœœœœœ œœ˜OKšœ˜—K˜š žœœœœœœ˜Hšœœœ˜Kšœ$™$———K˜šœ™K˜K˜šœœœ˜K˜K˜—K˜š žœœ"œœœ˜uKš˜Kšœ œœ,˜MK˜IK˜gKšœ˜ Kšœ˜—K˜šž œœœ˜LK˜)K˜K˜K˜#K˜—˜KšœÀ™À—šžœœœœ˜BKš˜Kšœ œœ"˜FKšœ,˜2Kšœ˜—˜KšœA™A—šžœœKœ˜eKš˜Kšœœœ*˜SK˜\K˜?K˜NK˜5K˜]Kšœ˜—K˜šžœœ-œœ˜TKšœŸI˜PK˜RKšœœœ*˜KKšœ9œ˜GKšœ˜—K˜š žœœ œ.œœ˜jKš˜Kšœœœ*˜Kšœœ˜Kšœœ˜7KšœœŸ˜/—Kšœ˜K˜—šžœœœœœ œœ˜SK˜Kšœ œœ˜.Kšœ˜K˜.K˜@Kšœ-˜-Kšœ˜ —K˜š žœœ œœœœ˜GKš˜Kšœœœ ˜,K˜)K˜?KšœH˜NKšœ˜——K˜šœ™K˜šœœœ˜K˜ Kšœ œ˜Kš œ œ œœœœ˜;Kšœ œœ˜—K˜šž œœœ œœœœœœœ œœ˜™Kš˜Kšœœ œ2˜JK˜Kšœ"˜(Kšœ˜——K˜Kšœ˜—K˜š žœœ œœœ˜SKš˜Kšœœ œ"˜=šœœ˜Kšœœ*˜KKšœœŸ˜/—Kšœ˜—K˜šžœœœœœ œœ˜KKšœœ œ"˜=K˜5Kšœ0˜0—K˜K˜K˜—šœ™K˜šœ œœ˜K˜ —K˜šžœœœœ˜EKš˜Kšœœœ˜0Kšœ2œ˜?Kšœ˜—K˜š žœœ œœœœ˜CKš˜Kšœœœ ˜)Kšœœ ˜Kšœ˜—K˜K˜——Kšœ˜—…—a¬¤í