DIRECTORY Alloc USING [Notifier, Top], ConvertUnsafe USING [SubString], MimData USING [bitsToAlignment, bodyIndex, idLOCK, idUNWIND, ownSymbols, seAnon, table, textIndex, typeCONDITION, typeListANY, typeLOCK, worstAlignment], MimosaCopier USING [CompleteContext], MimosaLog USING [Error, ErrorNode, ErrorSei, ErrorTree, ErrorTreeOp], MimP3 USING [And, Apply, AssignDefaults, Attr, BindTree, BoundNP, BumpArgRefs, CheckLength, CheckLocals, CheckScope, ClearRefStack, EnterComposite, EnterType, Exp, FieldVoid, FirstId, fullAttr, InitialExp, KeyedList, lockNode, MakeLongType, MakeRefType, MatchFields, MergeNP, NPUse, pathNP, phraseNP, PopCtx, PushCtx, RAttrPop, Rhs, RPop, RPush, RType, Safety, SafetyAttr, SealRefStack, SearchCtxList, SequenceNP, SetNP, SetSafety, SetType, Stmt, TextForm, TypeAppl, UnsealRefStack, UpdateTreeAttr, UType, VoidComponent, VoidExp], MimP3S USING [BodyData, continued, currentBody, markCatch, safety], Pass3Attributes USING [AssignableType, Bundling, CanonicalType, DefaultInit, LongPath, LongType, NewableType, OperandInternal, OperandLhs, OperandType, TargetType, TypeForTree, Unbundle, Voidable], SourceMap USING [Loc], Symbols USING [Base, BitOrder, BodyRecord, bodyType, BTFirst, BTIndex, CBTIndex, CBTNull, CSEIndex, CSENull, CTXIndex, CTXNull, ctxType, HTIndex, HTNull, ISEIndex, ISENull, lG, lZ, mdType, nullType, RecordSEIndex, RecordSENull, RefSEIndex, RootBti, SERecord, seType, Type, typeANY], SymbolOps USING [ArgCtx, ArgRecord, CopyXferType, CtxLevel, DecodeBti, EnterString, EqTypes, FindString, FirstCtxSe, FromType, MakeNonCtxSe, NextSe, NormalType, own, ReferentType, SetCtxLevel, TransferTypes, TypeForm, TypeRoot, UnderType, XferMode], Target: TYPE MachineParms USING [bitOrder, bitsPerAU, bitsPerLongWord, bitsPerProcess, bitsPerProgram, bitsPerRef, bitsPerWord], Tree USING [Base, Index, Link, Map, NodeName, Null, nullIndex, Scan, treeType], TreeOps USING [FreeNode, FreeTree, FromLoc, GetNode, GetTag, IdentityMap, MakeList, MakeNode, NthSon, PopTree, PushTree, PushSe, PushNode, PutAttr, OpName, ReverseUpdateList, ScanList, SetAttr, SetInfo, ToLoc, UpdateList], Types USING [Assignable, Equivalent]; Pass3M: PROGRAM IMPORTS Alloc, MimData, MimosaCopier, MimosaLog, MimP3, MimP3S, Pass3Attributes, SymbolOps, TreeOps, Types EXPORTS MimP3 = { OPEN MimP3, Pass3Attributes, Symbols, TreeOps; targetBitOrder: Symbols.BitOrder = SELECT Target.bitOrder FROM msBit => msBit, lsBit => lsBit, ENDCASE => ERROR; checkLong: BOOL = Target.bitsPerLongWord # Target.bitsPerWord; InsertCatchLabel: PUBLIC SIGNAL [catchSeen, exit: BOOL] = CODE; tb: Tree.Base; -- tree base address (local copy) seb: Symbols.Base; -- se table base address (local copy) ctxb: Symbols.Base; -- context table base (local copy) mdb: Symbols.Base; -- module table base (local copy) bb: Symbols.Base; -- body table base (local copy) MiscNotify: PUBLIC Alloc.Notifier = { tb ¬ base[Tree.treeType]; seb ¬ base[seType]; ctxb ¬ base[ctxType]; mdb ¬ base[mdType]; bb ¬ base[bodyType]; }; current: POINTER TO MimP3S.BodyData = @MimP3S.currentBody; MiscStmt: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { name: Tree.NodeName = tb[node].name; val ¬ [subtree[index: node]]; -- the default SELECT name FROM signal, error, start, join, wait => { new: Tree.Link; IF name = wait THEN { son1: Tree.Link ¬ SampleAndFree[node, 1]; subNode: Tree.Index; saveNP: NPUse; IF NOT current.lockHeld THEN MimosaLog.Error[misplacedMonitorRef]; subNode ¬ Apply[GetNode[ForceApplication[son1]], typeANY, TRUE]; SELECT tb[subNode].name FROM wait, apply => NULL; ENDCASE => MimosaLog.ErrorTreeOp[missingOp, tb[subNode].son[1], wait]; IF OperandLhs[tb[subNode].son[1]] = none THEN MimosaLog.ErrorTree[nonLHS, tb[subNode].son[1]]; [] ¬ FreeTree[tb[subNode].son[2]]; saveNP ¬ phraseNP; tb[subNode].son[2] ¬ tb[subNode].son[1]; tb[subNode].son[1] ¬ CopyLock[]; phraseNP ¬ MergeNP[saveNP][phraseNP]; new ¬ [subtree[subNode]]; } ELSE new ¬ MiscXfer[node, typeANY]; PushTree[new]; SELECT RType[] FROM CSENull, typeANY => NULL; ENDCASE => MimosaLog.Error[nonVoidStmt]; SetInfo[FromLoc[MimData.textIndex]]; val ¬ PopTree[]; RPop[]; pathNP ¬ SequenceNP[pathNP][phraseNP]; IF name = error THEN current.reachable ¬ FALSE; }; xerror => { subNode: Tree.Index; IF current.catchDepth # 0 THEN MimosaLog.Error[misplacedReturn]; tb[node].name ¬ error; val ¬ MiscStmt[node]; subNode ¬ GetNode[val]; IF tb[subNode].attr1 THEN MimosaLog.ErrorTree[typeClash, val]; SELECT tb[subNode].name FROM error, errorx => tb[subNode].name ¬ xerror; ENDCASE; tb[subNode].attr1 ¬ current.entry; tb[subNode].attr3 ¬ FALSE; IF current.entry THEN tb[subNode].attr2 ¬ CheckLocals[tb[subNode].son[2]]; IF tb[subNode].nSons > 2 THEN MimosaLog.Error[misplacedCatch]; current.reachable ¬ FALSE; }; resume => { rSei: RecordSEIndex = current.resumeRecord; son: Tree.Link ¬ tb[node].son[1]; IF NOT current.resumeFlag THEN MimosaLog.Error[misplacedResume]; IF rSei # RecordSENull AND son = Tree.Null THEN { n: CARDINAL ¬ 0; BumpArgRefs[rSei, FALSE]; FOR sei: ISEIndex ¬ SymbolOps.FirstCtxSe[SymbolOps.own, seb[rSei].fieldCtx], SymbolOps.NextSe[SymbolOps.own, sei] UNTIL sei = ISENull DO n ¬ n+1; IF n=1 AND seb[sei].hash = HTNull THEN MimosaLog.Error[illDefinedReturn]; PushSe[sei]; ENDLOOP; tb[node].son[1] ¬ son ¬ MakeList[n]; } ELSE { tb[node].son[1] ¬ son ¬ IF tb[node].attr1 AND rSei # RecordSENull THEN Rhs[son, rSei] ELSE MatchFields[rSei, son]; RPop[]; pathNP ¬ SequenceNP[pathNP][phraseNP]; }; current.reachable ¬ FALSE; }; reject => { IF current.catchDepth = 0 THEN MimosaLog.Error[misplacedResume]; current.reachable ¬ FALSE; }; continue, retry => { SIGNAL InsertCatchLabel[catchSeen: FALSE, exit: name=continue]; current.reachable ¬ FALSE; }; notify, broadcast => { type: Type; son1: Tree.Link ¬ tb[node].son[1]; IF ~current.lockHeld THEN MimosaLog.Error[misplacedMonitorRef]; son1 ¬ tb[node].son[1] ¬ Exp[son1, typeANY]; IF OperandLhs[son1] = none THEN MimosaLog.ErrorTree[nonLHS, son1]; type ¬ RType[]; RPop[]; pathNP ¬ SequenceNP[pathNP][phraseNP]; IF ~SymbolOps.EqTypes[SymbolOps.own, type, MimData.typeCONDITION] THEN MimosaLog.ErrorTreeOp[missingOp, son1, name] }; free => { type: Type; subType, nType: CSEIndex; long, counted: BOOL; son1: Tree.Link ¬ tb[node].son[1]; son2: Tree.Link ¬ tb[node].son[2]; [v: son1, long: long, counted: counted] ¬ EvalZone[son1]; tb[node].son[1] ¬ son1; RPop[]; IF counted AND OpName[son2] = addr THEN PutAttr[son2, 1, TRUE]; son2 ¬ tb[node].son[2] ¬ Exp[son2, typeANY]; type ¬ RType[]; RPop[]; subType ¬ SymbolOps.NormalType[SymbolOps.own, type]; WITH s: seb[subType] SELECT FROM ref => { IF s.readOnly THEN MimosaLog.ErrorTree[typeClash, son2]; IF checkLong AND long # LongType[s.refType] THEN GO TO fail; nType ¬ SymbolOps.NormalType[SymbolOps.own, s.refType]; WITH t: seb[nType] SELECT FROM ref => IF t.counted # counted THEN GO TO fail; ENDCASE => GO TO fail; IF MimP3S.safety = checked AND ~counted THEN MimosaLog.ErrorNode[unsafeOperation, node]; EXITS fail => MimosaLog.ErrorTree[typeClash, son2]; }; ENDCASE => MimosaLog.ErrorTree[typeClash, son2]; IF tb[node].nSons > 3 THEN { saveNP: NPUse = phraseNP; [] ¬ CatchPhrase[tb[node].son[4]]; phraseNP ¬ MergeNP[saveNP][phraseNP]; }; tb[node].attr2 ¬ long; tb[node].attr3 ¬ counted; SELECT TRUE FROM NOT counted => tb[node].attr1 ¬ FALSE; (OpName[son2] # addr) => { MimosaLog.ErrorTree[nonVar, son2]; tb[node].attr1 ¬ FALSE; }; ENDCASE => tb[node].attr1 ¬ OperandLhs[NthSon[son2, 1]] = counted; }; enable => { saveEnabled: BOOL = current.unwindEnabled; IF CatchPhrase[tb[node].son[1]].unwindCaught THEN current.unwindEnabled ¬ TRUE; IF phraseNP # none THEN pathNP ¬ unsafe; tb[node].son[2] ¬ UpdateList[tb[node].son[2], Stmt]; tb[node].attr3 ¬ FALSE; current.unwindEnabled ¬ saveEnabled; }; ENDCASE => MimosaLog.Error[unimplemented]; }; New: PUBLIC PROC [node: Tree.Index, target: Type] = { pType: RefSEIndex; subType: Type; attr: Attr; saveNP: NPUse; long, counted: BOOL; zoneTree: Tree.Link ¬ tb[node].son[1]; typeTree: Tree.Link ¬ tb[node].son[2]; initTree: Tree.Link ¬ tb[node].son[3]; [v: zoneTree, long: long, counted: counted] ¬ EvalZone[zoneTree]; tb[node].son[1] ¬ zoneTree; attr ¬ RAttrPop[]; saveNP ¬ phraseNP; current.noXfers ¬ attr.noXfer ¬ attr.const ¬ FALSE; tb[node].son[2] ¬ typeTree ¬ TypeAppl[typeTree]; attr ¬ And[attr, RAttrPop[]]; saveNP ¬ MergeNP[saveNP][phraseNP]; subType ¬ TypeForTree[typeTree]; IF NOT NewableType[subType] THEN MimosaLog.ErrorTree[typeLength, typeTree]; IF counted THEN EnterType[SymbolOps.TypeRoot[SymbolOps.own, subType], FALSE]; IF initTree = Tree.Null THEN initTree ¬ DefaultInit[subType] ELSE { StringInit: PROC [t: Tree.Link] RETURNS [BOOL] = INLINE { RETURN [SELECT OpName[t] FROM stringinit => TRUE, lengthen => (OpName[NthSon[t, 1]] = stringinit), ENDCASE => FALSE] }; extFlag: BOOL; [initTree, extFlag] ¬ InitialExp[initTree, subType]; SELECT TRUE FROM extFlag => MimosaLog.ErrorTree[misusedInline, initTree]; StringInit[initTree] => MimosaLog.ErrorTree[defaultForm, initTree]; ENDCASE => initTree ¬ CheckInit[initTree, subType, counted]; }; tb[node].son[3] ¬ initTree; attr ¬ And[attr, RAttrPop[]]; phraseNP ¬ SequenceNP[saveNP][phraseNP]; pType ¬ MakeRefType[ cType: subType, bits: Target.bitsPerRef, readOnly: tb[node].attr1, counted: counted, hint: SymbolOps.NormalType[SymbolOps.own, target]]; IF initTree = Tree.Null THEN { IF NOT Voidable[subType] THEN MimosaLog.ErrorNode[missingInit, node]; } ELSE { IF counted THEN EnterComposite[SymbolOps.UnderType[SymbolOps.own, subType], initTree, TRUE]; }; IF tb[node].nSons > 3 THEN { saveNP: NPUse = phraseNP; [] ¬ CatchPhrase[tb[node].son[4]]; phraseNP ¬ MergeNP[saveNP][phraseNP]; }; tb[node].attr2 ¬ long; tb[node].attr3 ¬ counted; RPush[IF checkLong AND long THEN MakeLongType[pType, target] ELSE pType, attr]; }; EvalZone: PROC [t: Tree.Link] RETURNS [v: Tree.Link, long, counted: BOOL] = { long ¬ counted ¬ TRUE; IF t = Tree.Null THEN {v ¬ Tree.Null; RPush[typeANY, fullAttr]} ELSE { nDerefs: CARDINAL ¬ 0; type: Type; v ¬ Exp[t, typeANY]; type ¬ RType[]; DO nType: CSEIndex ¬ SymbolOps.NormalType[SymbolOps.own, type]; WITH s: seb[nType] SELECT FROM zone => { long ¬ ~s.mds; counted ¬ s.counted; GO TO success; }; ref => { IF (nDerefs ¬ nDerefs + 1) > 16 THEN GO TO failure; PushTree[v]; PushNode[uparrow, 1]; SetAttr[2, LongType[type]]; type ¬ s.refType; SetType[type]; v ¬ PopTree[]; }; record => IF Bundling[nType] # 0 THEN type ¬ Unbundle[LOOPHOLE[nType, RecordSEIndex]] ELSE GO TO failure; ENDCASE => GO TO failure; ENDLOOP; EXITS success => {}; failure => MimosaLog.ErrorTree[typeClash, v]; }; }; Cons: PUBLIC PROC [node: Tree.Index, target: Type] RETURNS [Tree.Link] = { type: Type = SymbolOps.ReferentType[SymbolOps.own, ListType[target, [subtree[node]]]]; PushTree[tb[node].son[1]]; tb[node].son[1] ¬ Tree.Null; PushNode[implicitTC, 0]; SetType[SymbolOps.UnderType[SymbolOps.own, type]]; CheckLength[tb[node].son[2], 2]; PushTree[tb[node].son[2]]; tb[node].son[2] ¬ Tree.Null; PushTree[Tree.Null]; PushNode[apply, -2]; SetAttr[1, FALSE]; IF tb[node].nSons > 2 THEN { PushTree[tb[node].son[3]]; tb[node].son[3] ¬ Tree.Null; PushNode[new, 4]; } ELSE PushNode[new, 3]; FreeNode[node]; RETURN [Exp[PopTree[], target]]; }; ListCons: PUBLIC PROC [node: Tree.Index, target: Type] = { lType: CSEIndex = ListType[target, [subtree[node]]]; nType: Type = SymbolOps.ReferentType[SymbolOps.own, lType]; componentType: Type = ItemType[nType]; cType: Type = TargetType[componentType]; attr: Attr; exitNP: NPUse; long, counted: BOOL; started: BOOL ¬ FALSE; MapValue: Tree.Map = { type: Type; subAttr: Attr; IF ~started AND KeyedList[t] THEN MimosaLog.Error[keys]; v ¬ SELECT TRUE FROM (t = Tree.Null) => DefaultInit[componentType], (OpName[t] = void) => FieldVoid[t], ENDCASE => Rhs[t, cType]; type ¬ RType[]; subAttr ¬ RAttrPop[]; SELECT TRUE FROM v = Tree.Null => VoidComponent[componentType]; counted => EnterComposite[SymbolOps.UnderType[SymbolOps.own, componentType], v, TRUE]; ENDCASE; v ¬ CheckInit[v, type, TRUE]; exitNP ¬ MergeNP[exitNP][phraseNP]; attr ¬ And[attr, subAttr]; started ¬ TRUE; }; [v: tb[node].son[1], long: long, counted: counted] ¬ EvalZone[tb[node].son[1]]; attr ¬ RAttrPop[]; exitNP ¬ phraseNP; current.noXfers ¬ attr.noXfer ¬ attr.const ¬ FALSE; IF counted THEN EnterType[SymbolOps.TypeRoot[SymbolOps.own, nType], FALSE]; tb[node].son[2] ¬ ReverseUpdateList[tb[node].son[2], MapValue]; tb[node].attr2 ¬ long; tb[node].attr3 ¬ counted; RPush[lType, attr]; phraseNP ¬ exitNP; }; ListType: PROC [target: Type, t: Tree.Link] RETURNS [lType: CSEIndex] = { subType: CSEIndex = SymbolOps.NormalType[SymbolOps.own, target]; WITH r: seb[subType] SELECT FROM ref => { rType: CSEIndex = SymbolOps.UnderType[SymbolOps.own, r.refType]; IF ~r.list AND (seb[rType].typeTag = any OR rType = typeANY) THEN lType ¬ MimData.typeListANY ELSE { IF ~r.list THEN {MimosaLog.ErrorTree[typeClash, t]; lType ¬ typeANY} ELSE lType ¬ SymbolOps.UnderType[SymbolOps.own, target]; }; }; ENDCASE => IF subType = typeANY THEN lType ¬ MimData.typeListANY ELSE {MimosaLog.ErrorTree[typeClash, t]; lType ¬ typeANY}; }; ItemType: PUBLIC PROC [nType: Type] RETURNS [Type] = { sei: CSEIndex = SymbolOps.UnderType[SymbolOps.own, nType]; WITH r: seb[sei] SELECT FROM record => RETURN [seb[SymbolOps.FirstCtxSe[SymbolOps.own, r.fieldCtx]].idType]; ENDCASE => RETURN [typeANY]; }; MiscXfer: PUBLIC PROC [node: Tree.Index, target: Type] RETURNS [val: Tree.Link] = { val ¬ [subtree[node]]; SELECT tb[node].name FROM signal, error, signalx, errorx => val ¬ Signal[node]; create => val ¬ Create[node, target]; start, startx => { subNode: Tree.Index ¬ Apply[ GetNode[ForceApplication[tb[node].son[1]]], typeANY, TRUE]; SELECT tb[subNode].name FROM start, startx, apply => NULL; ENDCASE => MimosaLog.ErrorTreeOp[missingOp, tb[subNode].son[1], start]; tb[node].son[1] ¬ Tree.Null; FreeNode[node]; val ¬ [subtree[subNode]]; }; fork => val ¬ Fork[node, target]; join, joinx => { son1: Tree.Link ¬ SampleAndFree[node, 1]; subNode: Tree.Index ¬ Apply[GetNode[ForceApplication[son1]], typeANY, TRUE]; SELECT tb[subNode].name FROM join, joinx, apply => {}; ENDCASE => MimosaLog.ErrorTreeOp[missingOp, tb[subNode].son[1], join]; val ¬ [subtree[subNode]]; }; ENDCASE => MimosaLog.Error[unimplemented]; }; MakeFrameRecord: PUBLIC PROC [t: Tree.Link] RETURNS [rSei: CSEIndex ¬ typeANY] = { bti: CBTIndex = XferBody[t]; IF bti # CBTNull THEN { argType: Type = SymbolOps.TransferTypes[SymbolOps.own, bb[bti].ioType].typeIn; rSei ¬ bb[bti].type; IF rSei = RecordSENull OR argType # nullType THEN { rSei ¬ LOOPHOLE[SymbolOps.MakeNonCtxSe[SERecord.cons.record.linked.SIZE]]; seb[rSei] ¬ SERecord[mark3: TRUE, mark4: FALSE, body: cons[ align: MimData.worstAlignment, typeInfo: record[ painted: TRUE, machineDep: FALSE, argument: FALSE, packed: FALSE, spare: FALSE, list: FALSE, bitOrder: targetBitOrder, grain: Target.bitsPerAU, hints: [ unifield: FALSE, variant: FALSE, assignable: FALSE, comparable: FALSE, privateFields: TRUE, refField: TRUE, default: FALSE, voidable: FALSE], fieldCtx: bb[bti].localCtx, length: IF bb[bti].type # RecordSENull THEN seb[bb[bti].type].length ELSE 0, monitored: bb[bti].monitored, linkPart: linked[argType]]]]; }; WITH r: seb[rSei] SELECT FROM record => { ctx: CTXIndex ¬ r.fieldCtx; WITH ct: ctxb[ctx] SELECT FROM included => MimosaCopier.CompleteContext[LOOPHOLE[ctx], rc]; ENDCASE; }; ENDCASE => ERROR; } ELSE MimosaLog.Error[nonTypeCons]; }; XferBody: PROC [t: Tree.Link] RETURNS [bti: CBTIndex ¬ CBTNull] = { WITH t SELECT GetTag[t] FROM symbol => { sei: ISEIndex = index; type: Type = seb[sei].idType; SELECT SymbolOps.TypeForm[SymbolOps.own, type] FROM $transfer => IF seb[sei].immutable THEN SELECT SymbolOps.XferMode[SymbolOps.own, type] FROM $program => SELECT TRUE FROM ~ seb[sei].mark4 => bti ¬ RootBti; seb[sei].constant => bti ¬ SymbolOps.DecodeBti[seb[sei].idInfo]; ENDCASE; $proc => IF sei = bb[MimData.bodyIndex].id THEN bti ¬ MimData.bodyIndex; ENDCASE; ENDCASE; }; ENDCASE; }; XferForFrame: PUBLIC PROC [ctx: CTXIndex] RETURNS [CSEIndex] = { bti: BTIndex ¬ BTFirst; btLimit: BTIndex = (MimData.table).Top[bodyType]; UNTIL bti = btLimit DO WITH entry: bb[bti] SELECT FROM Callable => { IF entry.localCtx = ctx THEN RETURN [entry.ioType]; bti ¬ bti + BodyRecord.Callable.SIZE; }; ENDCASE => bti ¬ bti + BodyRecord.Other.SIZE; ENDLOOP; RETURN [CSENull]; }; Create: PROC [node: Tree.Index, target: Type] RETURNS [val: Tree.Link] = { subNode: Tree.Index ¬ GetNode[ val ¬ ForceApplication[SampleAndFree[node, 1]] ]; type, mType, rType: CSEIndex; attr: Attr; CreateError: PROC = { MimosaLog.ErrorTreeOp[missingOp, tb[subNode].son[1], create]; type ¬ typeANY; }; tb[subNode].name ¬ create; tb[subNode].attr1 ¬ TRUE; tb[subNode].son[1] ¬ Exp[tb[subNode].son[1], typeANY]; mType ¬ UType[]; attr ¬ RAttrPop[]; phraseNP ¬ SetNP[phraseNP]; WITH m: seb[mType] SELECT FROM transfer => IF m.mode = program THEN SELECT XferBody[tb[subNode].son[1]] FROM CBTNull => type ¬ mType; RootBti => { type ¬ (IF SymbolOps.TypeForm[SymbolOps.own, target] = $ref THEN MakeRefType[ cType: MakeFrameRecord[tb[subNode].son[1]], hint: target, bits: Target.bitsPerProgram] ELSE mType); tb[subNode].attr1 ¬ FALSE}; ENDCASE => CreateError[] ELSE CreateError[]; ref => { type ¬ mType; rType ¬ SymbolOps.UnderType[SymbolOps.own, m.refType]; WITH r: seb[rType] SELECT FROM record => SELECT TRUE FROM (SymbolOps.CtxLevel[SymbolOps.own, r.fieldCtx] # lG) => CreateError[]; (SymbolOps.TypeForm[SymbolOps.own, target] = $transfer) => { type ¬ XferForFrame[r.fieldCtx]; IF type = CSENull THEN { MimosaLog.Error[unimplemented]; type ¬ typeANY; }; }; ENDCASE; ENDCASE => IF m.refType # typeANY THEN CreateError[]; }; ENDCASE => IF mType = typeANY THEN type ¬ typeANY ELSE CreateError[]; IF tb[subNode].son[2] # Tree.Null THEN { MimosaLog.ErrorTree[noApplication, tb[subNode].son[1]]; tb[subNode].son[2] ¬ UpdateList[tb[subNode].son[2], VoidExp]; }; IF tb[subNode].nSons > 2 THEN [] ¬ CatchPhrase[tb[subNode].son[3]]; current.noXfers ¬ attr.noXfer ¬ attr.const ¬ FALSE; RPush[type, attr]; }; Fork: PROC [node: Tree.Index, target: Type] RETURNS [Tree.Link] = { subNode: Tree.Index; type: CSEIndex; attr: Attr; t: Tree.Link ¬ ForceApplication[SampleAndFree[node, 1]]; subNode ¬ Apply[GetNode[t], typeANY, TRUE]; attr ¬ RAttrPop[]; SELECT tb[subNode].name FROM call, callx => { s: Tree.Link ¬ tb[subNode].son[1]; subType: CSEIndex; IF OpName[s] = thread THEN { s ¬ NthSon[s, 1]; MimosaLog.ErrorTree[misusedInline, s]; }; IF current.lockHeld AND OperandInternal[s] THEN MimosaLog.ErrorTree[internalCall, s]; subType ¬ SymbolOps.UnderType[SymbolOps.own, OperandType[s]]; WITH procType: seb[subType] SELECT FROM transfer => { type ¬ SymbolOps.MakeNonCtxSe[SERecord.cons.transfer.SIZE]; seb[type] ¬ SERecord[mark3: TRUE, mark4: TRUE, body: cons[ align: MimData.bitsToAlignment[Target.bitsPerProcess], typeInfo: transfer[ mode: process, safe: procType.safe, typeIn: RecordSENull, typeOut: procType.typeOut, length: Target.bitsPerProcess]]]; IF MimP3S.safety = checked THEN { CheckArg: Tree.Map = { argType: Type = OperandType[t]; subType: CSEIndex = SymbolOps.NormalType[SymbolOps.own, argType]; WITH s: seb[subType] SELECT FROM ref => {IF s.var THEN MimosaLog.ErrorTreeOp[unsafeOp, t, fork]; v ¬ t}; transfer => v ¬ CheckScope[t, argType]; ENDCASE => v ¬ t; }; tb[subNode].son[1] ¬ CheckScope[s, subType]; tb[subNode].son[2] ¬ UpdateList[tb[subNode].son[2], CheckArg]; }; }; ENDCASE => ERROR; tb[subNode].name ¬ fork; }; apply => type ¬ typeANY; ENDCASE => { MimosaLog.ErrorTreeOp[missingOp, tb[subNode].son[1], fork]; type ¬ typeANY; }; tb[subNode].info ¬ SymbolOps.FromType[type]; RPush[type, attr]; RETURN [[subtree[subNode]]]; }; LockVar: PUBLIC PROC [t: Tree.Link] RETURNS [Tree.Link] = { nDerefs: NAT ¬ 0; val: Tree.Link ¬ Exp[t, typeANY]; long: BOOL ¬ LongPath[val]; type: Type ¬ RType[]; Dereference: PROC [type: Type] = { PushTree[val]; PushNode[uparrow, 1]; SetType[type]; SetAttr[2, long]; val ¬ PopTree[]; }; RPop[]; DO nType: CSEIndex; IF SymbolOps.EqTypes[SymbolOps.own, type, MimData.typeLOCK] THEN { IF nDerefs # 0 THEN Dereference[type]; EXIT; }; type ¬ SymbolOps.TypeRoot[SymbolOps.own, type]; nType ¬ SymbolOps.NormalType[SymbolOps.own, type]; WITH seb[nType] SELECT FROM record => { IF monitored THEN { b: BOOL; sei: ISEIndex; desc: ConvertUnsafe.SubString ¬ ["LOCK"L, 0, ("LOCK"L).length]; [b, sei] ¬ SearchCtxList[SymbolOps.EnterString[desc], fieldCtx]; IF ~b THEN {MimosaLog.Error[noAccess]; sei ¬ MimData.seAnon}; PushTree[val]; PushSe[sei]; PushNode[IF nDerefs = 0 THEN dollar ELSE dot, 2]; SetType[MimData.idLOCK]; SetAttr[2, long]; val ¬ PopTree[]; EXIT; }; GO TO failure; }; ref => { IF (nDerefs ¬ nDerefs + 1) > 16 THEN GO TO failure; long ¬ LongType[type]; IF nDerefs > 1 THEN Dereference[type]; type ¬ refType; }; ENDCASE => GO TO failure; REPEAT failure => MimosaLog.ErrorTreeOp[missingOp, val, lock]; ENDLOOP; IF OperandLhs[val] = none THEN MimosaLog.ErrorTree[nonLHS, val]; RETURN [val]; }; FindLockParams: PUBLIC PROC RETURNS [formal, actual: ISEIndex ¬ ISENull] = { node: Tree.Index = GetNode[tb[MimP3.lockNode].son[1]]; IF node # Tree.nullIndex THEN { formal ¬ FirstId[node]; IF current.inputRecord # RecordSENull THEN { found: BOOL; [found, actual] ¬ SearchCtxList[ seb[formal].hash, seb[current.inputRecord].fieldCtx]; IF ~found THEN actual ¬ ISENull; }; }; }; CopyLock: PUBLIC PROC RETURNS [val: Tree.Link ¬ Tree.Null] = { formal: ISEIndex ¬ ISENull; actual: ISEIndex ¬ ISENull; BindFormal: PROC [sei: ISEIndex] RETURNS [Tree.Link] = { RETURN [[symbol[index: IF sei = formal THEN actual ELSE sei]]]; }; SELECT TRUE FROM MimP3.lockNode = Tree.nullIndex => RETURN [Tree.Null]; tb[current.bodyNode].son[4] # Tree.Null => val ¬ tb[current.bodyNode].son[4]; ENDCASE => { [formal: formal, actual: actual] ¬ FindLockParams[]; IF formal # ISENull THEN { IF actual = ISENull THEN { MimosaLog.ErrorSei[missingLock, formal]; actual ¬ MimData.seAnon; }; IF ~Types.Assignable[ [MimData.ownSymbols, SymbolOps.UnderType[SymbolOps.own, seb[formal].idType]], [MimData.ownSymbols, SymbolOps.UnderType[SymbolOps.own, seb[actual].idType]]] THEN MimosaLog.ErrorSei[typeClash, actual]; }; val ¬ tb[MimP3.lockNode].son[2]; }; val ¬ BindTree[val, BindFormal]; [] ¬ UpdateTreeAttr[val]; }; Signal: PUBLIC PROC [node: Tree.Index] RETURNS [Tree.Link] = { nodeTag: Tree.NodeName = tb[node].name; son1: Tree.Link ¬ SampleAndFree[node, 1]; subNode: Tree.Index ¬ Apply[GetNode[ForceApplication[son1]], typeANY, TRUE]; SELECT tb[subNode].name FROM signal, signalx => tb[subNode].name ¬ nodeTag; error, errorx => { SELECT nodeTag FROM signal, signalx => MimosaLog.ErrorTreeOp[missingOp, tb[subNode].son[1], nodeTag]; ENDCASE; tb[subNode].name ¬ nodeTag; }; apply => {}; ENDCASE => MimosaLog.ErrorTree[typeClash, tb[subNode].son[1]]; RETURN [[subtree[subNode]]]; }; ForceApplication: PROC [t: Tree.Link] RETURNS [Tree.Link] = { IF OpName[t] = apply THEN RETURN [t]; PushTree[t]; PushTree[Tree.Null]; RETURN [MakeNode[apply, 2]]; }; CatchPhrase: PUBLIC PROC [t: Tree.Link] RETURNS [unwindCaught: BOOL ¬ FALSE] = { saveReachable: BOOL = current.reachable; savePathNP: NPUse = pathNP; saveSafety: Safety = MimP3S.safety; enclosingSafe: BOOL = (saveSafety = checked); entryNP, exitNP: NPUse ¬ none; CatchItem: Tree.Scan = { node: Tree.Index = GetNode[t]; type: CSEIndex ¬ typeANY; mixed, safe, error: BOOL ¬ FALSE; saveIndex: SourceMap.Loc = MimData.textIndex; CatchLabel: Tree.Map = { subType: CSEIndex; oops: BOOL ¬ FALSE; v ¬ Exp[t, typeANY]; subType ¬ SymbolOps.UnderType[SymbolOps.own, CanonicalType[RType[]]]; RPop[]; entryNP ¬ SequenceNP[entryNP][phraseNP]; WITH t: seb[subType] SELECT FROM transfer => SELECT t.mode FROM signal, error => { SELECT TRUE FROM type = typeANY => type ¬ subType; NOT Types.Equivalent[ [MimData.ownSymbols, type], [MimData.ownSymbols, subType]] => mixed ¬ TRUE; ENDCASE; IF t.safe THEN safe ¬ TRUE; IF t.mode = error THEN error ¬ TRUE; }; ENDCASE => oops ¬ TRUE; ENDCASE => oops ¬ TRUE; SELECT TreeOps.OpName[v] FROM errorx, signalx => oops ¬ TRUE; ENDCASE; IF oops THEN MimosaLog.ErrorTree[typeClash, v]; }; MimData.textIndex ¬ ToLoc[tb[node].info]; tb[node].son[1] ¬ UpdateList[tb[node].son[1], CatchLabel]; IF mixed THEN type ¬ typeANY; IF type # typeANY AND type # nullType THEN { type ¬ SymbolOps.CopyXferType[type, TreeOps.IdentityMap]; }; tb[node].son[2] ¬ CatchBody[ tb[node].son[2], type, safe OR (error AND enclosingSafe)]; IF tb[node].son[1] = Tree.Link[symbol[index: MimData.idUNWIND]] THEN { unwindCaught ¬ TRUE; IF current.entry AND ~current.unwindEnabled AND current.catchDepth = 0 THEN { PushTree[tb[node].son[2]]; PushTree[CopyLock[]]; PushNode[unlock, 1]; SetInfo[FromLoc[MimData.textIndex]]; tb[node].son[2] ¬ MakeList[2]}}; tb[node].info ¬ SymbolOps.FromType[IF type # typeANY THEN type ELSE nullType]; MimData.textIndex ¬ saveIndex; }; CatchBody: PROC [body: Tree.Link, type: CSEIndex, safe: BOOL] RETURNS [Tree.Link] = { saveRecord: RecordSEIndex = current.resumeRecord; saveFlag: BOOL = current.resumeFlag; inType: CSEIndex ¬ CSENull; outType: CSEIndex ¬ CSENull; current.resumeFlag ¬ FALSE; current.resumeRecord ¬ RecordSENull; current.catchDepth ¬ current.catchDepth + 1; WITH t: seb[type] SELECT FROM transfer => { inType ¬ t.typeIn; outType ¬ t.typeOut; current.resumeFlag ¬ t.mode = signal; PushArgCtx[inType]; BumpArgRefs[SymbolOps.ArgRecord[SymbolOps.own, inType], TRUE]; current.resumeRecord ¬ SymbolOps.ArgRecord[SymbolOps.own, outType]; PushArgCtx[current.resumeRecord]; ClearRefStack[]; }; ENDCASE; current.reachable ¬ TRUE; pathNP ¬ entryNP; SELECT OpName[body] FROM block, checked => SetSafety[SafetyAttr[GetNode[body]]]; ENDCASE; IF safe AND MimP3S.safety = none THEN MimosaLog.Error[unsafeBlock]; body ¬ UpdateList[body, Stmt ! InsertCatchLabel => {IF catchSeen THEN RESUME}]; IF current.resumeRecord # RecordSENull THEN { ctx: CTXIndex = SymbolOps.ArgCtx[SymbolOps.own, outType]; assigns: Tree.Link = MimP3.AssignDefaults[ctx, FALSE]; bodyName: Tree.NodeName = OpName[body]; SELECT bodyName FROM block, checked => { whichSon: NAT = IF bodyName = checked THEN 1 ELSE 2; bodyNode: Tree.Index ¬ GetNode[body]; PushTree[assigns]; PushTree[tb[bodyNode].son[whichSon]]; PushNode[list, 2]; tb[bodyNode].son[whichSon] ¬ PopTree[]; }; ENDCASE => { PushTree[assigns]; PushTree[body]; PushNode[list, 2]; body ¬ PopTree[]; }; }; exitNP ¬ BoundNP[exitNP][pathNP]; WITH t: seb[type] SELECT FROM transfer => {PopArgCtx[outType]; PopArgCtx[inType]}; ENDCASE; current.catchDepth ¬ current.catchDepth - 1; current.resumeRecord ¬ saveRecord; current.resumeFlag ¬ saveFlag; SetSafety[saveSafety]; RETURN [body]; }; setLabel, continued: BOOL ¬ FALSE; node: Tree.Index = GetNode[t]; SealRefStack[]; { ENABLE InsertCatchLabel => { IF ~catchSeen THEN { setLabel ¬ TRUE; IF exit THEN continued ¬ TRUE; SIGNAL InsertCatchLabel[catchSeen: TRUE, exit: exit]; RESUME}}; ScanList[tb[node].son[1], CatchItem]; IF tb[node].nSons > 1 THEN tb[node].son[2] ¬ CatchBody[tb[node].son[2], typeANY, enclosingSafe]; }; IF setLabel THEN {MimP3S.markCatch ¬ TRUE; MimP3S.continued ¬ continued}; UnsealRefStack[]; current.reachable ¬ saveReachable; phraseNP ¬ exitNP; pathNP ¬ savePathNP; }; PushArgCtx: PROC [sei: CSEIndex] = INLINE { ctx: CTXIndex = SymbolOps.ArgCtx[SymbolOps.own, sei]; IF ctx # CTXNull THEN { SymbolOps.SetCtxLevel[ctx, current.level + current.catchDepth]; PushCtx[ctx]; }; }; PopArgCtx: PROC [sei: CSEIndex] = INLINE { ctx: CTXIndex = SymbolOps.ArgCtx[SymbolOps.own, sei]; IF ctx # CTXNull THEN { PopCtx[]; SymbolOps.SetCtxLevel[ctx, lZ]; }; }; CheckInit: PROC [t: Tree.Link, type: Type, safe: BOOL] RETURNS [Tree.Link] = { ut: CSEIndex = SymbolOps.UnderType[SymbolOps.own, type]; IF NOT AssignableType[ut, FALSE] THEN SELECT TreeOps.OpName[t] FROM construct, rowcons => {}; ENDCASE => MimosaLog.ErrorTreeOp[missingOp, t, assign]; SELECT SymbolOps.TypeForm[SymbolOps.own, ut] FROM $transfer => IF MimP3S.safety = checked THEN RETURN [CheckScope[t, ut]]; ENDCASE; RETURN [t]; }; SampleAndFree: PROC [node: Tree.Index, index: NAT] RETURNS [v: Tree.Link] = INLINE { v ¬ tb[node].son[index]; tb[node].son[index] ¬ Tree.Null; FreeNode[node]; }; CheckHash: PROC [hti: HTIndex, s: LONG STRING] RETURNS [BOOL] = INLINE { desc: ConvertUnsafe.SubString = [base: s, offset: 0, length: s.length]; RETURN [SymbolOps.FindString[SymbolOps.own, desc] = hti]; }; TextRep: PUBLIC PROC [rType: Type] RETURNS [form: TextForm ¬ text] = { type: CSEIndex = SymbolOps.UnderType[SymbolOps.own, rType]; WITH t: seb[type] SELECT FROM record => WITH c: ctxb[t.fieldCtx] SELECT FROM included => { IF CheckHash[mdb[c.module].moduleId, "Rope"L] THEN WITH se: seb[rType] SELECT FROM id => { SELECT TRUE FROM CheckHash[se.hash, "RopeRep"L] => RETURN [$rope]; CheckHash[se.hash, "TextRep"L] => RETURN [$ropeText]; ENDCASE; }; ENDCASE; }; ENDCASE; ENDCASE; }; }. x Pass3M.mesa Copyright Ó 1985, 1986, 1987, 1991 by Xerox Corporation. All rights reserved. Satterthwaite, June 18, 1986 12:30:20 pm PDT Russ Atkinson (RRA) July 18, 1988 3:32:49 pm PDT called by allocator whenever table area is repacked Statements Dynamic storage allocation No explicit initialization No explicit or default initialization Explicit initialization List allocation Control transfers Allocate the frame record Monitors Signals Catch phrases This also checks for errors & signals raised in the selectors RRA: we need to copy the context, perhaps this will work? We must declare the default resume values. This was left out of previous versions of the compiler, leading to both incorrect code and a safety violation. FURTHER NOTE! This code inserts a tree already processed by Pass3. Therefore we have to slip it in AFTER we have done the UpdateList operation just above. Otherwise we can see construct, union, and rowcons nodes in MimP3.Exp processing, which is not kosher (results in "unimplemented construct" errors). Recent utilities Rope identification (temporary) The type originally comes from the Rope interface ÊÒ•NewlineDelimiter –(cedarcode) style™headšœ ™ Icodešœ ÏeœC™NLšÏy,™,L™0L˜šÏk ˜ LšœŸœ˜LšœŸœ ˜ LšœŸœŒ˜™Lšœ Ÿœ˜%Lšœ Ÿœ6˜ELšœŸœ‡˜’LšœŸœ7˜CLšœŸœ°˜ÅLšœ Ÿœ˜LšœŸœ˜šLšœ Ÿœê˜ùLšœŸœŸœa˜€LšœŸœE˜OLšœŸœÑ˜ÞLšœŸœ˜%——šÏnœŸ˜LšŸœc˜jLšŸœ ˜LšŸœ*˜.L˜šœ#ŸœŸ˜>Lšœ ŸœŸœ˜1L˜—Lšœ Ÿœ/˜>L˜Lš  œŸœŸœŸœŸœ˜?L˜LšœÏc!˜0Lšœ¡%˜8Lšœ¡"˜6Lšœ¡!˜4Lšœ¡˜1L˜š  œŸœ˜%L™3L˜L˜L˜L˜L˜L˜L˜—Lšœ ŸœŸœ'˜:—™ š œŸœŸœŸœ˜EL˜$Lšœ¡˜,šŸœŸ˜šœ%˜%Lšœ˜šŸœ ˜šŸœ˜Lšœ)˜)L˜L˜LšŸœŸœŸœ&˜BLšœ:Ÿœ˜@šŸœŸ˜LšœŸœ˜LšŸœ?˜F—šŸœ'Ÿ˜-Lšœ0˜0—L˜"L˜L˜(L˜ L˜%Lšœ˜L˜—LšŸœ˜#—Lšœ˜šŸœ Ÿ˜LšœŸœ˜LšŸœ!˜(—L˜$L˜L˜L˜&LšŸœŸœŸœ˜/L˜—˜ L˜LšŸœŸœ"˜@L˜L˜.LšŸœŸœ%˜>šŸœŸ˜L˜+LšŸœ˜—L˜"LšœŸœ˜LšŸœŸœ5˜JLšŸœŸœ!˜>LšœŸœ˜L˜L˜—˜ L˜+Lšœ!˜!LšŸœŸœŸœ"˜@šŸœŸœ˜*šŸœ˜LšœŸœ˜LšœŸœ˜šŸœoŸœŸ˜ˆL˜ LšŸœŸœŸœ#˜IL˜ LšŸœ˜—Lšœ$˜$L˜—šŸœ˜šœŸœŸœ˜ALšŸœ˜LšŸœ˜—L˜L˜&L˜——LšœŸœ˜L˜—L˜˜ LšŸœŸœ"˜@LšœŸœ˜L˜L˜—˜LšŸœŸœ˜?LšœŸœ˜L˜L˜—˜L˜ L˜"LšŸœŸœ&˜?L˜,LšŸœŸœ#˜BL˜L˜L˜&šŸœ@Ÿ˜FL˜,—L˜L˜—˜ L˜ L˜LšœŸœ˜Lšœ"˜"Lšœ"˜"Lšœ9˜9Lšœ˜Lšœ˜LšŸœ ŸœŸœŸœ˜?Lšœ,˜,Lšœ˜Lšœ˜L˜4šŸœŸœŸ˜ ˜LšŸœ Ÿœ&˜8Lš Ÿœ ŸœŸœŸœŸœ˜L˜—L˜—LšŸœŸœ˜—L˜L˜—L˜šŸœ˜ Lšœ;˜;Lšœ˜Lšœ˜——L˜,L˜LšŸœ˜L˜——™š œŸœŸœŸœ˜;Lšœ Ÿœ˜L˜!LšœŸœ˜L˜š  œŸœ˜"L˜L˜L˜L˜L˜L˜—L˜šŸ˜L˜šŸœ:Ÿœ˜BLšŸœ Ÿœ˜&LšŸœ˜L˜—L˜/L˜2šŸœ ŸœŸ˜˜ šŸœ Ÿœ˜LšœŸœ˜L˜L˜?L˜@LšŸœŸœ3˜=L˜L˜ Lšœ Ÿœ ŸœŸœ ˜1L˜L˜L˜LšŸœ˜L˜—LšŸœŸœ ˜L˜—˜LšŸœŸœŸœŸœ ˜3L˜LšŸœ Ÿœ˜&L˜L˜—LšŸœŸœŸœ ˜—šŸ˜L˜7—LšŸœ˜—LšŸœŸœ"˜@LšŸœ˜ L˜L˜—š œŸœŸœŸœ)˜LLšœ6˜6šŸœŸœ˜L˜šŸœ$Ÿœ˜,LšœŸœ˜ ˜ L˜L˜#—LšŸœŸœ˜ L˜—L˜—L˜L˜—š œŸœŸœŸœ!˜>L˜L˜š  œŸœŸœ˜8LšŸœŸœŸœŸœ˜?L˜—šŸœŸœŸ˜Lšœ#Ÿœ ˜6˜*L˜"—šŸœ˜ L˜4šŸœŸœ˜šŸœŸœ˜L˜(L˜L˜—šŸœ˜L˜MLšœNŸ˜RL˜&—L˜—Lšœ ˜ L˜——Lšœ ˜ Lšœ˜L˜——™š œŸœŸœŸœ˜>L˜'Lšœ)˜)LšœFŸœ˜LšŸœŸ˜L˜.˜šŸœ Ÿœ˜˜L˜>—LšŸœ˜—L˜L˜—L˜ LšŸœ7˜>—LšŸœ˜L˜L˜—š œŸœŸœ˜=LšŸœŸœŸœ˜%L˜ L˜LšŸœ˜L˜——™ š   œŸœŸœŸœŸœŸœ˜PLšœŸœ˜(L˜L˜#LšœŸœ˜-L˜š  œ˜L˜L˜LšœŸœŸœ˜!L˜-š  œ˜L˜LšœŸœŸœ˜L˜L˜EL˜L˜(šŸœŸœŸ˜ ˜ šŸœŸ˜šœ˜šŸœŸœŸ˜Lšœ!˜!šŸœP˜SLšœŸœ˜ —LšŸœ˜—LšŸœŸœŸœ˜LšŸœŸœ Ÿœ˜$L˜—LšŸœ Ÿœ˜——LšŸœ Ÿœ˜—šŸœŸ˜šœŸœ˜L™=—LšŸœ˜—LšŸœŸœ#˜/L˜—L˜)L˜:LšŸœŸœ˜šŸœŸœŸœ˜,LšŸœ6™9Lšœ9˜9L˜—˜LšœŸœŸœ˜:—šŸœ>Ÿœ˜FLšœŸœ˜šŸœŸœŸœŸœ˜ML˜1L˜:L˜ ——Lšœ#ŸœŸœŸœ ˜NL˜L˜—š  œŸœ(ŸœŸœ˜UL˜1Lšœ Ÿœ˜$Lšœ˜Lšœ˜LšœŸœ˜Lšœ$˜$L˜,šŸœŸœŸ˜˜ L˜L˜L˜%L˜Lšœ8Ÿœ˜>L˜CL˜!L˜L˜—LšŸœ˜—LšœŸœ˜Lšœ˜šŸœŸ˜Lšœ7˜7LšŸœ˜—LšŸœŸœŸœ˜CLšœ4Ÿœ ŸœŸœ˜OšŸœ%Ÿœ˜-L™šInotešœ²™²L˜9Lšœ/Ÿœ˜6Lšœ'˜'šŸœ Ÿ˜˜Lš œ ŸœŸœŸœŸœ˜4Lšœ%˜%Lšœ˜Lšœ%˜%Lšœ˜Lšœ'˜'L˜—šŸœ˜ Lšœ˜Lšœ˜Lšœ˜Lšœ˜Lšœ˜——L˜—L˜!šŸœŸœŸ˜L˜4LšŸœ˜—L˜,L˜"L˜L˜LšŸœ˜L˜—LšœŸœŸœ˜"L˜L˜˜šŸœ˜šŸœ Ÿœ˜Lšœ Ÿœ˜LšŸœŸœ Ÿœ˜LšŸœŸœŸœ˜?——L˜%šŸœŸ˜L˜E—L˜—LšŸœ ŸœŸœ ˜IL˜L˜"L˜L˜L˜L˜—š  œŸœŸœ˜+L˜5šŸœŸœ˜L˜?L˜ L˜—˜L˜——š  œŸœŸœ˜*L˜5šŸœŸœ˜Lšœ ˜ Lšœ˜Lšœ˜—L˜——™š  œŸœ"ŸœŸœ˜NLšœ8˜8šŸœŸœŸœŸ˜%šŸœŸ˜L˜LšŸœ0˜7——šŸœ'Ÿ˜1šœ ˜ LšŸœŸœŸœ˜;—LšŸœ˜—LšŸœ˜ L˜L˜—š   œŸœŸœŸœŸœ˜TLšœ˜Lšœ ˜ Lšœ˜L˜——™š  œŸœŸœŸœŸœŸœŸœ˜HL˜GLšŸœ3˜9L˜L˜—š œŸœŸœŸœ˜FL˜;šŸœŸœŸ˜˜ šŸœŸœŸ˜$šœ ˜ šŸœ,Ÿ˜2L™1šŸœŸœŸ˜˜šŸœŸœŸ˜Lšœ"Ÿœ ˜1Lšœ"Ÿœ ˜5LšŸœ˜—L˜—LšŸœ˜——L˜—LšŸœ˜——LšŸœ˜—L˜L˜——L˜L˜—…—p²‘ü