DIRECTORY IO USING [PutF, PutFR, rope, RopeFromROS, ROS, STREAM], Rope USING [Equal, ROPE], SaffronATDef USING [EvaluateAndTypeCheckExpression, ExpNode, InitializationNode, TypeExpNode], SaffronBaseDef USING [AccessValNode, CompilerStateNode, DemandTypeDeclarationField, FieldNode, LookupNameInContextRib, LookupNameInFieldList], SaffronContext USING [], SaffronContextPrivateTypes, SaffronErrorHandling USING [FatalError, InternalError, Message, Warning], SaffronGenericDef USING [IdNode], SaffronProgramGraphPrivateTypes USING [ParameterizedFieldDescriptorNodeBody]; SaffronDeclarationAnalysisImpl: CEDAR PROGRAM IMPORTS IO, Rope, SaffronATDef, SaffronBaseDef, SaffronErrorHandling EXPORTS SaffronBaseDef, SaffronContext ~ BEGIN OPEN AT: SaffronATDef, BD: SaffronBaseDef, EH: SaffronErrorHandling, GEN: SaffronGenericDef, PG: SaffronProgramGraphPrivateTypes, PT: SaffronContextPrivateTypes; LocalContextNode: TYPE ~ REF LocalContextNodeBody; LocalContextNodeBody: PUBLIC TYPE ~ PT.LocalContextNodeBody; ContextRibNode: TYPE ~ REF ContextRibNodeBody; ContextRibNodeBody: PUBLIC TYPE ~ PT.ContextRibNodeBody; FrozenFieldListNode: TYPE = REF FrozenFieldListNodeBody; FrozenFieldListNodeBody: PUBLIC TYPE = PT.FrozenFieldListNodeBody; FieldListNode: TYPE = REF FieldListNodeBody; FieldListNodeBody: PUBLIC TYPE = PT.FieldListNodeBody; TypeGraphNodeNode: TYPE ~ REF TypeGraphNodeNodeBody; TypeGraphNodeNodeBody: PUBLIC TYPE ~ PT.TypeGraphNodeNodeBody; ValueNode: TYPE = REF ValueNodeBody; ValueNodeBody: PUBLIC TYPE = PT.ValueNodeBody; FieldNode: TYPE = REF FieldNodeBody; FieldNodeBody: PUBLIC TYPE = PT.FieldNodeBody; ParameterizedFieldDescriptorNode: TYPE = REF ParameterizedFieldDescriptorNodeBody; ParameterizedFieldDescriptorNodeBody: PUBLIC TYPE = PG.ParameterizedFieldDescriptorNodeBody; AnalyzeDependencies: PUBLIC PROC [dg: DependencyGraphNode, fl: FieldListNode, lc: LocalContextNode, cs: BD.CompilerStateNode] RETURNS [FieldListNode, LocalContextNode]~ BEGIN NodeProc: PROC [dgn: DependencyGraphNodeNode] = BEGIN WITH dgn SELECT FROM d: REF value DependencyGraphNodeNodeBody => IF NOT DependsOnRuntimeState[dgn] THEN { field: REF constant FieldNodeBody _ NARROW[d.of]; targetType: TypeGraphNodeNode _ field.type; expNode: AT.ExpNode _ NARROW[field.value, REF unparsed ValueNodeBody].parseTree; field.value _ AT.EvaluateAndTypeCheckExpression[expNode, lc, fl, cs, targetType]; }; d: REF runtime DependencyGraphNodeNodeBody => {}; d: REF size DependencyGraphNodeNodeBody => SIGNAL EH.Warning[0, "size dgn proc not yet implemented"]; d: REF first DependencyGraphNodeNodeBody => IF DependsOnRuntimeState[dgn] THEN ERROR EH.FatalError[0, "FIRST[] is not constant"] ELSE { field: REF typeDecl FieldNodeBody _ NARROW[d.of]; namedType: PT.NamedTGN _ NARROW[field.type.body]; elementTGN: PT.ElementTGN _ NARROW[namedType.type.body]; WITH elementTGN SELECT FROM e: REF subrange PT.ElementTGNBody => { expNode: AT.ExpNode _ NARROW[e.body.firstElement, REF unparsed ValueNodeBody].parseTree; e.body.firstElement _ AT.EvaluateAndTypeCheckExpression[expNode, lc, fl, cs, e.body.baseType]; }; e: REF enumerated base PT.ElementTGNBody => { SIGNAL EH.Warning[0, "first dgn proc not yet implemented for base enumerated tgn"] }; ENDCASE => ERROR EH.InternalError["should not be dependency-analyzing this kind of element type"]; }; d: REF last DependencyGraphNodeNodeBody => IF DependsOnRuntimeState[dgn] THEN ERROR EH.FatalError[0, "LAST[] is not constant"] ELSE { field: REF typeDecl FieldNodeBody _ NARROW[d.of]; namedType: PT.NamedTGN _ NARROW[field.type.body]; elementTGN: PT.ElementTGN _ NARROW[namedType.type.body]; WITH elementTGN SELECT FROM e: REF subrange PT.ElementTGNBody => { expNode: AT.ExpNode _ NARROW[e.body.lastElement, REF unparsed ValueNodeBody].parseTree; e.body.lastElement _ AT.EvaluateAndTypeCheckExpression[expNode, lc, fl, cs, e.body.baseType]; }; e: REF enumerated base PT.ElementTGNBody => { SIGNAL EH.Warning[0, "last dgn proc not yet implemented for base enumerated tgn"] }; ENDCASE => ERROR EH.InternalError["should not be dependency-analyzing this kind of element type"]; }; ENDCASE; END; lc.dependencyGraph _ dg; WalkDependencyGraph[lc.dependencyGraph, NodeProc]; RETURN[fl, lc]; END; LookupIdentifierTGNs: PUBLIC PROC [fl: FieldListNode, lc: LocalContextNode] RETURNS [FieldListNode] = BEGIN LookupTypeIdentifiersInFieldList[fl, fl, lc]; RETURN [fl]; END; LookupTypeIdentifiers: PROC [tgn: TypeGraphNodeNode, fl: FieldListNode, lc: LocalContextNode] RETURNS [TypeGraphNodeNode] = BEGIN IF ISTYPE[tgn.body, PT.IdentifierTGN] THEN BEGIN access: BD.AccessValNode; lookedUpTGN: TypeGraphNodeNode; id: GEN.IdNode _ NARROW[tgn.body, PT.IdentifierTGN].id; field: FieldNode _ BD.LookupNameInFieldList[fl, id]; IF field = NIL THEN field _ BD.LookupNameInContextRib[id, lc.parentRib]; [access, lookedUpTGN] _ BD.DemandTypeDeclarationField[field]; RETURN [lookedUpTGN]; END ELSE BEGIN WITH tgn.body SELECT FROM t: PT.ArrayTGN => { t.indexType _ LookupTypeIdentifiers[t.indexType, fl, lc]; t.itemType _ LookupTypeIdentifiers[t.itemType, fl, lc]; }; t: PT.AtomTGN => {}; t: PT.BlockTGN => ERROR EH.InternalError["Name in local context bound to block TGN"]; t: PT.ConditionTGN => {}; t: PT.DescriptorTGN => t.itemType _ LookupTypeIdentifiers[t.itemType, fl, lc]; t: REF base PT.ElementTGNBody => {}; t: REF subrange PT.ElementTGNBody => t.body.baseType _ LookupTypeIdentifiers[t.body.baseType, fl, lc]; t: PT.InterfaceTGN => ERROR EH.InternalError["Name in local context bound to interface TGN"]; t: PT.ListTGN => t.elementType _ LookupTypeIdentifiers[t.elementType, fl, lc]; t: PT.LongTGN => t.underlyingType _ LookupTypeIdentifiers[t.underlyingType, fl, lc]; t: PT.MonitorlockTGN => {}; t: PT.NamedTGN => t.type _ LookupTypeIdentifiers[t.type, fl, lc]; t: PT.OpaqueTGN => {}; t: PT.PointerTGN => t.target _ LookupTypeIdentifiers[t.target, fl, lc]; t: PT.RealTGN => {}; t: PT.RecordTGN => LookupTypeIdentifiersInFrozenFieldList[t.fields, fl, lc]; t: PT.RefTGN => t.target _ LookupTypeIdentifiers[t.target, fl, lc]; t: PT.ReferentTGN => t.contents _ LookupTypeIdentifiers[t.contents, fl, lc]; t: PT.RelativeTGN => { t.base _ LookupTypeIdentifiers[t.base, fl, lc]; t.pointer _ LookupTypeIdentifiers[t.pointer, fl, lc]; }; t: PT.SequenceTGN => { t.tagType _ LookupTypeIdentifiers[t.tagType, fl, lc]; t.type _ LookupTypeIdentifiers[t.type, fl, lc]; }; t: PT.SpecianatedTGN => { t.underlyingType _ LookupTypeIdentifiers[t.underlyingType, fl, lc]; }; t: PT.StringTGN => {}; t: PT.TopTGN => {}; t: PT.BottomTGN => {}; t: PT.TransferTGN => { LookupTypeIdentifiersInFrozenFieldList[t.arguments, fl, lc]; LookupTypeIdentifiersInFrozenFieldList[t.results, fl, lc]; }; t: PT.UnspecifiedTGN => {}; t: PT.VarTGN => t.target _ LookupTypeIdentifiers[t.target, fl, lc]; t: PT.VariantPartTGN => { t.tagType _ LookupTypeIdentifiers[t.tagType, fl, lc]; LookupTypeIdentifiersInFrozenUnionList[t.types, fl, lc]; }; t: PT.ZoneTGN => {}; ENDCASE => ERROR; RETURN [tgn]; END; END; LookupTypeIdentifiersInFrozenFieldList: PROC [ffl: FrozenFieldListNode, fl: FieldListNode, lc: LocalContextNode] = BEGIN LookupTypeIdentifiersInFieldList[ffl.cells, fl, lc]; END; LookupTypeIdentifiersInFieldList: PROC [arg: FieldListNode, fl: FieldListNode, lc: LocalContextNode] = BEGIN FOR cell: PT.FieldListCell _ arg.first, cell.next WHILE (cell # NIL) DO WITH cell.node SELECT FROM f: REF typeDecl FieldNodeBody => f.type _ LookupTypeIdentifiers[f.type, fl, lc]; f: REF constant FieldNodeBody => f.type _ LookupTypeIdentifiers[f.type, fl, lc]; f: REF variable FieldNodeBody => f.type _ LookupTypeIdentifiers[f.type, fl, lc]; f: REF recordField FieldNodeBody => f.type _ LookupTypeIdentifiers[f.type, fl, lc]; ENDCASE => ERROR; ENDLOOP; END; LookupTypeIdentifiersInFrozenUnionList: PROC [ful: PT.FrozenUnionList, fl: FieldListNode, lc: LocalContextNode] = BEGIN FOR i: INT IN [0..ful.nTypes) DO LookupTypeIdentifiersInFrozenFieldList[ful[i].fields, fl, lc]; ENDLOOP; END; DiscernSpecianatedTGNs: PUBLIC PROC [fl: FieldListNode, lc: LocalContextNode] RETURNS [FieldListNode] = BEGIN DiscernSpecTGNsInFieldList[fl, fl, lc]; RETURN [fl]; END; DiscernSpecTGNs: PROC [tgn: TypeGraphNodeNode, fl: FieldListNode, lc: LocalContextNode] RETURNS [TypeGraphNodeNode _ NIL] = BEGIN IF ISTYPE[tgn.body, PT.SpecianatedTGN] THEN BEGIN stgn: PT.SpecianatedTGN _ NARROW[tgn.body]; underlyingType: TypeGraphNodeNode _ stgn.underlyingType; restrictionList: LIST OF GEN.IdNode _ NIL; WHILE TRUE DO WITH underlyingType.body SELECT FROM ut: PT.NamedTGN => {underlyingType _ ut.type; restrictionList _ ut.restriction}; ENDCASE => ERROR EH.FatalError[0, "Bad type underlying specianated tgn"]; ENDLOOP; END ELSE BEGIN WITH tgn.body SELECT FROM t: PT.ArrayTGN => { t.indexType _ DiscernSpecTGNs[t.indexType, fl, lc]; t.itemType _ DiscernSpecTGNs[t.itemType, fl, lc]; }; t: PT.AtomTGN => {}; t: PT.BlockTGN => ERROR EH.InternalError["Name in local context bound to block TGN"]; t: PT.ConditionTGN => {}; t: PT.DescriptorTGN => t.itemType _ DiscernSpecTGNs[t.itemType, fl, lc]; t: REF base PT.ElementTGNBody => {}; t: REF subrange PT.ElementTGNBody => t.body.baseType _ DiscernSpecTGNs[t.body.baseType, fl, lc]; t: PT.InterfaceTGN => ERROR EH.InternalError["Name in local context bound to interface TGN"]; t: PT.ListTGN => t.elementType _ DiscernSpecTGNs[t.elementType, fl, lc]; t: PT.LongTGN => t.underlyingType _ DiscernSpecTGNs[t.underlyingType, fl, lc]; t: PT.MonitorlockTGN => {}; t: PT.NamedTGN => t.type _ DiscernSpecTGNs[t.type, fl, lc]; t: PT.OpaqueTGN => {}; t: PT.PointerTGN => t.target _ DiscernSpecTGNs[t.target, fl, lc]; t: PT.RealTGN => {}; t: PT.RecordTGN => DiscernSpecTGNsInFrozenFieldList[t.fields, fl, lc]; t: PT.RefTGN => t.target _ DiscernSpecTGNs[t.target, fl, lc]; t: PT.ReferentTGN => t.contents _ DiscernSpecTGNs[t.contents, fl, lc]; t: PT.RelativeTGN => { t.base _ DiscernSpecTGNs[t.base, fl, lc]; t.pointer _ DiscernSpecTGNs[t.pointer, fl, lc]; }; t: PT.SequenceTGN => { t.tagType _ DiscernSpecTGNs[t.tagType, fl, lc]; t.type _ DiscernSpecTGNs[t.type, fl, lc]; }; t: PT.StringTGN => {}; t: PT.TopTGN => {}; t: PT.BottomTGN => {}; t: PT.TransferTGN => { DiscernSpecTGNsInFrozenFieldList[t.arguments, fl, lc]; DiscernSpecTGNsInFrozenFieldList[t.results, fl, lc]; }; t: PT.UnspecifiedTGN => {}; t: PT.VarTGN => t.target _ DiscernSpecTGNs[t.target, fl, lc]; t: PT.VariantPartTGN => { t.tagType _ DiscernSpecTGNs[t.tagType, fl, lc]; DiscernSpecTGNsInFrozenUnionList[t.types, fl, lc]; }; t: PT.ZoneTGN => {}; ENDCASE => ERROR; RETURN [tgn]; END; END; DiscernSpecTGNsInFrozenFieldList: PROC [ffl: FrozenFieldListNode, fl: FieldListNode, lc: LocalContextNode] = BEGIN DiscernSpecTGNsInFieldList[ffl.cells, fl, lc]; END; DiscernSpecTGNsInFieldList: PROC [arg: FieldListNode, fl: FieldListNode, lc: LocalContextNode] = BEGIN FOR cell: PT.FieldListCell _ arg.first, cell.next WHILE (cell # NIL) DO WITH cell.node SELECT FROM f: REF typeDecl FieldNodeBody => f.type _ DiscernSpecTGNs[f.type, fl, lc]; f: REF constant FieldNodeBody => f.type _ DiscernSpecTGNs[f.type, fl, lc]; f: REF variable FieldNodeBody => f.type _ DiscernSpecTGNs[f.type, fl, lc]; f: REF recordField FieldNodeBody => f.type _ DiscernSpecTGNs[f.type, fl, lc]; ENDCASE => ERROR; ENDLOOP; END; DiscernSpecTGNsInFrozenUnionList: PROC [ful: PT.FrozenUnionList, fl: FieldListNode, lc: LocalContextNode] = BEGIN FOR i: INT IN [0..ful.nTypes) DO DiscernSpecTGNsInFrozenFieldList[ful[i].fields, fl, lc]; ENDLOOP; END; DependencyGraphNode: TYPE = REF DependencyGraphNodeBody; DependencyGraphNodeBody: PUBLIC TYPE = PT.DependencyGraphNodeBody; DependencyGraphNodeNode: TYPE = REF DependencyGraphNodeNodeBody; DependencyGraphNodeNodeBody: PUBLIC TYPE = PT.DependencyGraphNodeNodeBody; DependencyGraphNodeCell: TYPE = REF DependencyGraphNodeCellBody; DependencyGraphNodeCellBody: PUBLIC TYPE = PT.DependencyGraphNodeCellBody; DependencyKind: PUBLIC TYPE = PT.DependencyKind; CreateDependencyGraph: PROC [fl: FieldListNode, lc: LocalContextNode] RETURNS [DependencyGraphNode] = BEGIN dg: DependencyGraphNode _ NEW[DependencyGraphNodeBody _ [lc, NIL]]; AddDGN: PROC [dgn: DependencyGraphNodeNode] = BEGIN dg.roots _ CONS[dgn, dg.roots]; END; FOR cell: PT.FieldListCell _ fl.first, cell.next WHILE (cell # NIL) DO WITH cell.node SELECT FROM c: REF typeDecl FieldNodeBody => { namedTGN: PT.NamedTGN _ NARROW[c.type.body]; AddDGN[NEW[DependencyGraphNodeNodeBody _ [TRASH, NIL, NIL, size[cell.node]]]]; IF ISTYPE[namedTGN.type.body, PT.ElementTGN] THEN { AddDGN[NEW[DependencyGraphNodeNodeBody _ [TRASH, NIL, NIL, first[cell.node]]]]; AddDGN[NEW[DependencyGraphNodeNodeBody _ [TRASH, NIL, NIL, last[cell.node]]]]; }; }; c: REF constant FieldNodeBody => { AddDGN[NEW[DependencyGraphNodeNodeBody _ [TRASH, NIL, NIL, value[cell.node]]]]; }; c: REF variable FieldNodeBody => { AddDGN[NEW[DependencyGraphNodeNodeBody _ [TRASH, NIL, NIL, value[cell.node]]]]; }; ENDCASE => ERROR EH.InternalError["Bad kind of field for dependency analysis"]; ENDLOOP; AddDGN[NEW[DependencyGraphNodeNodeBody _ [TRASH, NIL, NIL, runtime[]]]]; RETURN[dg]; END; FakeDamageDependencyGraph: PUBLIC PROC [dg: DependencyGraphNode] RETURNS [DependencyGraphNode] = { RETURN [dg] }; FindDGN: PROC [dg: DependencyGraphNode, id: GEN.IdNode, kind: DependencyKind] RETURNS [found: BOOLEAN, dgn: DependencyGraphNodeNode] = BEGIN FOR roots: LIST OF DependencyGraphNodeNode _ dg.roots, roots.rest WHILE (roots # NIL) DO dgn: DependencyGraphNodeNode _ roots.first; IF (dgn.dependencyKind = kind) AND (WITH dgn SELECT FROM d: REF value DependencyGraphNodeNodeBody => Rope.Equal[id.text, d.of.name.text], d: REF first DependencyGraphNodeNodeBody => Rope.Equal[id.text, d.of.name.text], d: REF last DependencyGraphNodeNodeBody => Rope.Equal[id.text, d.of.name.text], d: REF size DependencyGraphNodeNodeBody => Rope.Equal[id.text, d.of.name.text], d: REF runtime DependencyGraphNodeNodeBody => TRUE, ENDCASE => ERROR ) THEN RETURN[TRUE, dgn]; ENDLOOP; RETURN[FALSE, NIL]; END; AddDependency: PROC [dgn1, dgn2: DependencyGraphNodeNode] = BEGIN cell: DependencyGraphNodeCell _ NEW[DependencyGraphNodeCellBody _ [dgn2, NIL]]; IF dgn1.first = NIL THEN dgn1.first _ cell ELSE dgn1.last.next _ cell; dgn1.last _ cell; END; AddFirstDependency: PUBLIC PROC [dg: DependencyGraphNode, dgn1: DependencyGraphNodeNode, id: GEN.IdNode] RETURNS [DependencyGraphNode] = BEGIN found: BOOLEAN; dgn2: DependencyGraphNodeNode; [found, dgn2] _ FindDGN[dg, id, first]; IF found THEN AddDependency[dgn1, dgn2] ELSE [] _ BD.DemandTypeDeclarationField[BD.LookupNameInContextRib[id, dg.lc.parentRib]]; RETURN [dg]; END; AddLastDependency: PUBLIC PROC [dg: DependencyGraphNode, dgn1: DependencyGraphNodeNode, id: GEN.IdNode] RETURNS [DependencyGraphNode] = BEGIN found: BOOLEAN; dgn2: DependencyGraphNodeNode; [found, dgn2] _ FindDGN[dg, id, last]; IF found THEN AddDependency[dgn1, dgn2] ELSE [] _ BD.DemandTypeDeclarationField[BD.LookupNameInContextRib[id, dg.lc.parentRib]]; RETURN [dg]; END; AddSizeDependency: PUBLIC PROC [dg: DependencyGraphNode, dgn1: DependencyGraphNodeNode, id: GEN.IdNode] RETURNS [DependencyGraphNode] = BEGIN found: BOOLEAN; dgn2: DependencyGraphNodeNode; [found, dgn2] _ FindDGN[dg, id, size]; IF found THEN AddDependency[dgn1, dgn2] ELSE [] _ BD.DemandTypeDeclarationField[BD.LookupNameInContextRib[id, dg.lc.parentRib]]; RETURN [dg]; END; AddValueDependency: PUBLIC PROC [dg: DependencyGraphNode, dgn1: DependencyGraphNodeNode, id: GEN.IdNode] RETURNS [DependencyGraphNode] = BEGIN found: BOOLEAN; dgn2: DependencyGraphNodeNode; [found, dgn2] _ FindDGN[dg, id, value]; IF found THEN AddDependency[dgn1, dgn2] ELSE { dg _ AddRuntimeDependency[dg, dgn1]; -- FIX ME! }; RETURN [dg]; END; AddRuntimeDependency: PUBLIC PROC [dg: DependencyGraphNode, dgn1: DependencyGraphNodeNode] RETURNS [DependencyGraphNode] = BEGIN found: BOOLEAN; dgn2: DependencyGraphNodeNode; [found, dgn2] _ FindDGN[dg, NIL, runtime]; IF NOT found THEN ERROR; AddDependency[dgn1, dgn2]; RETURN [dg]; END; ShowDependencyGraph: PUBLIC PROC [on: IO.STREAM, nest: INT, dg: DependencyGraphNode] = BEGIN FOR roots: LIST OF DependencyGraphNodeNode _ dg.roots, roots.rest WHILE (roots # NIL) DO dgn: DependencyGraphNodeNode _ roots.first; IF dgn.dependencyKind # runtime THEN { IO.PutF[on, "%g depends on ", IO.rope[RopeFromDGN[dgn]]]; IF dgn.first = NIL THEN IO.PutF[on, "nothing"] ELSE FOR cell: DependencyGraphNodeCell _ dgn.first, cell.next WHILE (cell # NIL) DO IO.PutF[on, "%g", IO.rope[RopeFromDGN[cell.dependsOn]]]; IF cell.next # NIL THEN IO.PutF[on, ", "]; ENDLOOP; IO.PutF[on, "\n"]; }; ENDLOOP; END; RopeFromDGN: PROC [dgn: DependencyGraphNodeNode] RETURNS [Rope.ROPE] = BEGIN RETURN [WITH dgn SELECT FROM d: REF value DependencyGraphNodeNodeBody => IO.PutFR["value of %g", IO.rope[d.of.name.text]], d: REF first DependencyGraphNodeNodeBody => IO.PutFR["FIRST[%g]", IO.rope[d.of.name.text]], d: REF last DependencyGraphNodeNodeBody => IO.PutFR["LAST[%g]", IO.rope[d.of.name.text]], d: REF size DependencyGraphNodeNodeBody => IO.PutFR["SIZE[%g]", IO.rope[d.of.name.text]], d: REF runtime DependencyGraphNodeNodeBody => "runtime state" ENDCASE => ERROR ]; END; BuildDependencyGraph: PUBLIC PROC [fl: FieldListNode, lc: LocalContextNode] RETURNS [DependencyGraphNode] = BEGIN dg: DependencyGraphNode _ CreateDependencyGraph[fl, lc]; FOR cell: PT.FieldListCell _ fl.first, cell.next WHILE (cell # NIL) DO WITH cell.node SELECT FROM c: REF typeDecl FieldNodeBody => { dgn1: DependencyGraphNodeNode _ FindDGN[dg, cell.node.name, size].dgn; typeExp: AT.TypeExpNode _ c.parseTree; namedTGN: PT.NamedTGN _ NARROW[c.type.body]; IF typeExp = NIL -- is it an opaque type? THEN NULL -- eventually, we have to hook into the opaque type's OptSize.... ELSE dg _ typeExp.procs.AddSizeDependencies[typeExp, dg, dgn1]; IF ISTYPE[namedTGN.type.body, PT.ElementTGN] THEN { elementTGN: PT.ElementTGN _ NARROW[namedTGN.type.body]; dgnf: DependencyGraphNodeNode _ FindDGN[dg, cell.node.name, first].dgn; dgnl: DependencyGraphNodeNode _ FindDGN[dg, cell.node.name, last].dgn; dg _ typeExp.procs.AddFirstDependencies[typeExp, dg, dgnf]; dg _ typeExp.procs.AddLastDependencies[typeExp, dg, dgnl]; }; }; c: REF constant FieldNodeBody => { dgn1: DependencyGraphNodeNode _ FindDGN[dg, cell.node.name, value].dgn; initialization: AT.InitializationNode _ c.initialization.node; dg _ initialization.procs.AddValueDependencies[initialization, dg, dgn1]; }; c: REF variable FieldNodeBody => { dgn1: DependencyGraphNodeNode _ FindDGN[dg, cell.node.name, value].dgn; dg _ AddRuntimeDependency[dg, dgn1]; }; ENDCASE => ERROR EH.InternalError["Bad kind of field for dependency analysis"]; ENDLOOP; RETURN [dg]; END; WalkDependencyGraph: PROC [dg: DependencyGraphNode, nodeProc: PROC [DependencyGraphNodeNode]] = BEGIN FOR rootList: LIST OF DependencyGraphNodeNode _ dg.roots, rootList.rest WHILE (rootList # NIL) DO rootList.first.visited _ FALSE; ENDLOOP; FOR rootList: LIST OF DependencyGraphNodeNode _ dg.roots, rootList.rest WHILE (rootList # NIL) DO VisitNode[rootList.first, NIL, nodeProc]; ENDLOOP; END; VisitNode: PROC [node: DependencyGraphNodeNode, path: LIST OF DependencyGraphNodeNode, nodeProc: PROC [DependencyGraphNodeNode]] = BEGIN IF node.visited THEN RETURN; IF NodeIsInPath[node, path] THEN { ros: IO.STREAM _ IO.ROS[]; ros.PutF["Cycle in dependency graph: %g", IO.rope[RopeFromDGN[node]]]; FOR p: LIST OF DependencyGraphNodeNode _ path, p.rest WHILE (p # NIL) DO ros.PutF[" _ %g", IO.rope[RopeFromDGN[p.first]]]; IF p.first = node THEN EXIT; ENDLOOP; ERROR EH.FatalError[0, ros.RopeFromROS[]]; }; FOR cell: DependencyGraphNodeCell _ node.first, cell.next WHILE (cell # NIL) DO VisitNode[cell.dependsOn, CONS[node, path], nodeProc]; ENDLOOP; nodeProc[node]; node.visited _ TRUE; END; NodeIsInPath: PROC [dgn: DependencyGraphNodeNode, path: LIST OF DependencyGraphNodeNode] RETURNS [BOOLEAN] = BEGIN FOR p: LIST OF DependencyGraphNodeNode _ path, p.rest WHILE (p # NIL) DO IF p.first = dgn THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; NullNodeProc: PROC [dgn: DependencyGraphNodeNode] = BEGIN SIGNAL EH.Message[IO.PutFR["Doing DGN %g", IO.rope[RopeFromDGN[dgn]]]]; END; DependsOnRuntimeState: PROC [dgn: DependencyGraphNodeNode] RETURNS [BOOLEAN] = BEGIN IF dgn.dependencyKind = runtime THEN RETURN [TRUE]; FOR cell: DependencyGraphNodeCell _ dgn.first, cell.next WHILE (cell # NIL) DO IF DependsOnRuntimeState[cell.dependsOn] THEN RETURN [TRUE]; ENDLOOP; RETURN [FALSE]; END; END. 1–SaffronDeclarationAnalysisImpl.mesa Last edited by: James Rauen August 25, 1988 4:36:21 pm PDT Primitives for constructing and analyzing dependency graphs. Perform the analysis described above on contextNode. If contextNode is okay, fill in all of its SIZE, FIRST, and LAST fields. (If we get really clever, and lucky, maybe we can also discriminate the Specianated types.) CompileDecList: PUBLIC PROC [decls: AT.DecListNode, lc: LocalContextNode, cs: BD.CompilerStateNode] RETURNS [LocalContextNode] = BEGIN This is the starting point for compiling a list of declarations. CompileDecList does the following: (1) Build a field list with one entry for each name declared in decls. Represent identifiers appearing where type expressions are expected as IdentifierTGN's. Represent identifiers appearing where value expressions are expected as ???. (2) Chill the field list, create a BlockTGN, and stuff the BlockTGN into lc's contents. (3) Look up the names stubbed out in part (1), bashing their occurrences. (4) Build a dependency graph for the names declared in decls. (5) Walk through the dependency graph, filling in size/value/first/last attributes. (Note that the bodies of procedure definitions, etc., are handled at this point). (6) Return the local context, ready to be frozen into a rib. fl: BD.FieldListNode; ffl: BD.FrozenFieldListNode; block: TypeGraphNodeNode; Build a field list with one entry for each name declared in decls. Represent identifiers appearing where type expressions are expected as IdentifierTGN's. Represent identifiers appearing where value expressions are expected as ???. Chill the field list, create a BlockTGN, and stuff the BlockTGN into lc's contents. [fl, lc] _ decls.procs.AddDeclarationsToFieldList[decls, BD.CreateEmptyFieldList[], lc, cs]; [lc, ffl] _ BD.FreezeFieldList[lc, fl]; [lc, block] _ BD.CreateBlockTGN[lc, ffl]; lc.contents _ NEW[PT.LocalContextContentsBody _ [frozen[block]]]; Now go back and look up all the IdentiferTGNs. Replace the body field of each identifer TypeGraphNode with named TypeGraphNode corresponding to the identifier. (Note: At this point, all value expressions are still trash or unparsed or defaultMe.) LookupTypeIdentifersInLocalContext[lc, ffl]; Build a dependency graph for the names declared in decls. lc.dependencyGraph _ BuildDependencyGraph[ffl, lc]; Do a topological sort of the dependency graph, performing the following on each node: If the node is a value node which does not ultimately depend on the runtime state, then it must represent a static (compile-time constant) value. Use the expression compiler to change the value's parse tree into a static representation. If the node is a value node which ultimately depends on the runtime state, then it represents a variable or runtime constant. Do nothing with it at this time. If the node is a FIRST, LAST, or SIZE node which does not ultimately depend on the runtime state, then use the expression compiler to compute a static value and stuff this value into the appropriate slot of the appropriate type graph node. If the node is a FIRST, LAST, or SIZE node which ultimately depends on the runtime state, then raise an error. This will determine all the compile-time (static) quantities in the dependency graph. BEGIN NodeProc: PROC [dgn: DependencyGraphNodeNode] = BEGIN WITH dgn SELECT FROM d: REF value DependencyGraphNodeNodeBody => IF NOT DependsOnRuntimeState[dgn] THEN { field: REF constant FieldNodeBody _ NARROW[d.of]; targetType: TypeGraphNodeNode _ field.type; expNode: AT.ExpNode _ NARROW[field.value, REF unparsed ValueNodeBody].parseTree; [field.value, lc] _ AT.CompileAndTypeCheckExpression[expNode, lc, cs, targetType]; }; d: REF runtime DependencyGraphNodeNodeBody => {}; d: REF size DependencyGraphNodeNodeBody => SIGNAL EH.Warning[0, "size dgn proc not yet implemented"]; d: REF first DependencyGraphNodeNodeBody => IF DependsOnRuntimeState[dgn] THEN ERROR EH.FatalError[0, "FIRST[] is not constant"] ELSE { field: REF typeDecl FieldNodeBody _ NARROW[d.of]; namedType: PT.NamedTGN _ NARROW[field.type.body]; elementTGN: PT.ElementTGN _ NARROW[namedType.type.body]; WITH elementTGN SELECT FROM e: REF subrange PT.ElementTGNBody => { expNode: AT.ExpNode _ NARROW[e.body.firstElement, REF unparsed ValueNodeBody].parseTree; [e.body.firstElement, lc] _ AT.CompileAndTypeCheckExpression[expNode, lc, cs, e.body.baseType]; }; e: REF enumerated base PT.ElementTGNBody => { SIGNAL EH.Warning[0, "first dgn proc not yet implemented for base enumerated tgn"] }; ENDCASE => ERROR EH.InternalError["should not be dependency-analyzing this kind of element type"]; }; d: REF last DependencyGraphNodeNodeBody => IF DependsOnRuntimeState[dgn] THEN ERROR EH.FatalError[0, "LAST[] is not constant"] ELSE { field: REF typeDecl FieldNodeBody _ NARROW[d.of]; namedType: PT.NamedTGN _ NARROW[field.type.body]; elementTGN: PT.ElementTGN _ NARROW[namedType.type.body]; WITH elementTGN SELECT FROM e: REF subrange PT.ElementTGNBody => { expNode: AT.ExpNode _ NARROW[e.body.lastElement, REF unparsed ValueNodeBody].parseTree; [e.body.lastElement, lc] _ AT.CompileAndTypeCheckExpression[expNode, lc, cs, e.body.baseType]; }; e: REF enumerated base PT.ElementTGNBody => { SIGNAL EH.Warning[0, "last dgn proc not yet implemented for base enumerated tgn"] }; ENDCASE => ERROR EH.InternalError["should not be dependency-analyzing this kind of element type"]; }; ENDCASE; END; lc.dependencyGraph _ BuildDependencyGraph[ffl, lc]; WalkDependencyGraph[lc.dependencyGraph, NodeProc]; END; Now, proceed sequentially through the field list (the declarations), performing the following on each field: If the field is a TYPE declaration, ignore it. (What about type codes, etc.?) If the field is a constant declaration and the ValueNode in its value slot is a static ValueNode, then we know that the field represents a compile-time constant and that it was processed in the previous step. So, ignore it. (Fill in its code? -- no, the static value constructors should do this!). If the field is a constant declaration and the ValueNode in its value slot is an unparsed value, then we know that it is a runtime constant. Compile the ValueNode, producing a runtime ValueNode, and stuff this new node into the field's value slot. (Can constants be initialized to trash? They probably can!) If the field is a variable declaration, then look at its initialValue slot: If there is a defaultMe ValueNode there, then no initialization was provided for the variable. Check to see if the variable's type has a default initialization. If so, produce a ValueNode containing this (how???). If not, produce a trash ValueNode. Either way, stuff the new ValueNode into the field's initialValue slot. If there is an unparsed ValueNode there, then compile the expression (producing a static or runtime ValueNode) and stuff this new ValueNode into the field's initialValue slot. If there is a trash ValueNode there, then the variable was explicitly initialized to TRASH. Do nothing else. Foo. BEGIN FOR cell: PT.FieldListCell _ ffl.cells.first, cell.next WHILE (cell # NIL) DO WITH cell.node SELECT FROM field: REF typeDecl FieldNodeBody => {}; field: REF constant FieldNodeBody => { WITH field.value SELECT FROM value: REF static ValueNodeBody => {}; value: REF unparsed ValueNodeBody => { [field.value, lc] _ AT.CompileAndTypeCheckExpression[value.parseTree, lc, cs, field.type]; }; value: REF trash ValueNodeBody => {}; ENDCASE => ERROR EH.InternalError["a"]; }; field: REF variable FieldNodeBody => { WITH field.initialValue SELECT FROM initialValue: REF defaultMe ValueNodeBody => { field.initialValue _ BD.MakeTrash[field.type] this also must check field.type for a default initialization!! }; initialValue: REF unparsed ValueNodeBody => { [field.initialValue, lc] _ AT.CompileAndTypeCheckExpression[initialValue.parseTree, lc, cs, field.type]; }; initialValue: REF trash ValueNodeBody => {}; ENDCASE => ERROR EH.InternalError["b"]; }; ENDCASE => ERROR EH.InternalError["c"]; ENDLOOP; END; Return the local context. RETURN[lc]; END; Looking Up IdentiferTGN's t: PT.LinkTGN => { t.tgn _ LookupTypeIdentifiers[t.tgn, fl, lc]; t.if _ LookupTypeIdentifiers[t.if, fl, lc]; }; Discerning SpecianatedTGN's ut: PT.InterfaceTGN => IF (stgn.idParam = NIL) OR (stgn.expParam # NIL) THEN ERROR EH.FatalError[0, "Bad form of interface field selector"] ELSE { WHILE restrictionList # NIL DO IF Rope.Equal[restrictionList.first.text, stgn.idParam.text] THEN { field: FieldNode _ SaffronContext.LookupNameInFieldList[ut.entries.cells, stgn.idParam]; WITH field SELECT FROM f: REF typeDecl FieldNodeBody => RETURN[f.type]; ENDCASE => ERROR EH.FatalError[stgn.idParam.position, "Mumblefrotz in interface is not a type."]; } ELSE restrictionList _ restrictionList.rest; ENDLOOP; ERROR EH.FatalError[stgn.idParam.position, IO.PutFR["%g is not valid as an interface field selector.", IO.rope[stgn.idParam.text]]]; }; a better error message, please? t: PT.LinkTGN => { t.tgn _ DiscernSpecTGNs[t.tgn, fl, lc]; t.if _ DiscernSpecTGNs[t.if, fl, lc]; }; Dependency Graph Primitives Create a dependency graph with one node for each interesting quantity in ffl, plus an extra node indicating a runtime or side-effecting value. do lookups Add the dependency "dgn1 depends on dgn2" SIGNAL EH.Message[IO.PutFR["Adding dependency: %g depends on %g", IO.rope[RopeFromDGN[dgn1]], IO.rope[RopeFromDGN[dgn2]]]]; if "first[id]" is not in dg, then just demand that id names a type. If id does name a type, then this type must be in a higher context, and its size must therefore already be known. If id doesn't name a type, then the call to LookupTypeNameInLocalContext will cause an error. If it turns out that id is in dg, but first[id] isn't, then something else had better catch the error. (the expression compiler?) but it shouldn't affect the validity of the dependency graph. VERIFY THIS!!! OR FIX IT!!! if "last[id]" is not in dg, then just demand that id names a type. If id does name a type, then this type must be in a higher context, and its size must therefore already be known. If id doesn't name a type, then the call to LookupTypeNameInLocalContext will cause an error. If it turns out that id is in dg, but first[id] isn't, then something else had better catch the error. (the expression compiler?) but it shouldn't affect the validity of the dependency graph. VERIFY THIS!!! OR FIX IT!!! if "size[id]" is not in dg, then just demand that id names a type. If id does name a type, then this type must be in a higher context, and its size must therefore already be known. If id doesn't name a type, then the call to LookupTypeNameInLocalContext will cause an error. pfd: ParameterizedFieldDescriptorNode; tgn: TypeGraphNodeNode; [pfd, tgn] _ BD.GetPathToName[dg.lc, id]; IF NOT BD.Static[BD.CompileLValueIntoRValue[pfd, dg.lc]] THEN dg _ AddRuntimeDependency[dg, dgn1]; Dependency Graph Construction this does not catch named-named types, etc. maybe a predicate in TypeConformanceImpl? valueExp: AT.ExpNode _ NARROW[c.value, REF unparsed ValueNodeBody].parseTree; dg _ valueExp.procs.AddValueDependencies[valueExp, dg, dgn1]; Topological Sort Perform a topological sort on dg. Apply nodeProc to each node of dg, applying nodeProc to a node n only after having applied it to all the nodes that n depends upon. Signal an error and return immediately if a cycle is detected. Return TRUE if dgn is an element of path, FALSE if it isn't. Return TRUE if there is a path from dgn to a runtime DGN, FALSE otherwise. AddDeclarationsToLocalContext: PUBLIC PROC [fl: BD.FieldListNode, lc: LocalContextNode, cs: BD.CompilerStateNode] RETURNS [LocalContextNode] = BEGIN fl should have been accumulated by calls to AddDeclarationToFieldList. At this point, we have a field list which contains type graph trees (no names looked up yet). This procedure looks up all the names referenced in fl, links them up, performs dependency analysis, and stuffs the resulting field list into the local context. This should eventually be merged with FreezeLocalContext. ffl: FrozenFieldListNode _ FreezeFieldList[lc, fl].ffl; block: TypeGraphNodeNode _ CreateBlockTGN[lc, ffl].tgn; lc.contents _ NEW[PT.LocalContextContentsBody _ [frozen[block]]]; RETURN [lc]; END; moved to SaffronContextCreateCTImpl MakeFieldListFromDecList: PUBLIC PROC [decls: AT.DecListNode, lc: LocalContextNode, cs: BD.CompilerStateNode] RETURNS [BD.FieldListNode, LocalContextNode] = BEGIN fl: BD.FieldListNode; lc1: LocalContextNode; [fl, lc1] _ decls.procs.AddDeclarationsToFieldList[ decls, BD.CreateEmptyFieldList[], lc, cs]; link em up dependency analysis RETURN [fl, lc]; END; ΚZ˜šœ#™#Icodešœ:™:—lead1™J˜Jšœ œœ˜$Jšœœœœ˜.J˜Jšœ œœ˜$Jšœœœœ˜.J˜Jšœ"œœ&˜RJšœ&œœœ&˜\J˜J˜š žœœœHœœ$˜©Kšœaœœœf™άKš˜šžœœ"˜5šœœ˜šœœ%˜+šœœœ˜(Kšœœœ˜1Kšœ+˜+Kšœ œ œœ#˜PKšœœA˜QK˜——Kšœœ+˜1šœœ%˜+Kšœœ1˜:—šœœ&˜,šœ˜Kšœœœ)˜6šœ˜Kšœœœ˜1Kšœ œ œ˜1Kšœ œœ˜8šœ œ˜šœœ œ˜&Kšœ œ œœ#˜XKšœœF˜^K˜—šœœœ˜-KšœœI˜RK˜—KšœœœO˜b—K˜———šœœ%˜+šœ˜Kšœœœ(˜5šœ˜Kšœœœ˜1Kšœ œ œ˜1Kšœ œœ˜8šœ œ˜šœœ œ˜&Kšœ œ œœ#˜WKšœœF˜]K˜—šœœœ˜-KšœœH˜QK˜—KšœœœO˜b—K˜———Kšœ˜—Kšœ˜—Kšœ˜Kšœ2˜2Kšœ ˜Kšœ˜K˜—š žœœœ œ(œœ™†™dK™νK™WK™IK™=K™¦K™=—Kšœœ™Kšœœ™Kšœ™K™Ibody™ΎK™Kšœ9œ!™\Kšœ œ™'Kšœœ™)Kšœœœ-™AK™M™ψK™Kšœ,™,K™™9K™—Kšœ3™3K™™UM™νM™ŸMšœœœœΚ™οMšœœœœI™n—M™UK™š™šžœœ"™5šœœ™šœœ%™+šœœœ™(Kšœœœ™1Kšœ+™+Kšœ œ œœ#™PKšœœ<™RK™——Kšœœ+™1šœœ%™+Kšœœ1™:—šœœ&™,šœ™Kšœœœ)™6šœ™Kšœœœ™1Kšœ œ œ™1Kšœ œœ™8šœ œ™šœœ œ™&Kšœ œ œœ#™XKšœœA™_K™—šœœœ™-KšœœI™RK™—KšœœœO™b—K™———šœœ%™+šœ™Kšœœœ(™5šœ™Kšœœœ™1Kšœ œ œ™1Kšœ œœ™8šœ œ™šœœ œ™&Kšœ œ œœ#™WKšœœA™^K™—šœœœ™-KšœœH™QK™—KšœœœO™b—K™———Kšœ™Kšœ™—Kšœ3™3Kšœ2™2—šœ™K™——™lMšœœ8™NMšœ¬™¬Mšœψ™ψM™<™MM™ΕM™°MšœUœ™m——Mšœ™K™š™š œœ,œ œ™Mšœ œ™Kšœœ™(šœœ™&šœ œ™Kšœœ™&šœœ™&KšœœD™ZK™—Kšœœ™%Kšœœœ™'—K™—šœœ™&šœœ™#šœœ™.Kšœœ™-K™>K™—šœœ™-KšœœK™hK™—Kšœœ™,Kšœœœ™'—K™—Kšœœœ™'—Kšœ™——Kš™K™M™K™Kšœ™ K™Kšœ™—K˜—headšΟz™š žœœœ+œ˜kKšœ-˜-Kšœ˜ Kšœ˜K˜—šžœœCœ˜šœœ œ˜%šœ˜ Kšœœ˜Kšœ˜Kšœœ œ œ˜7Kšœœ˜4Kšœ œœ œ*˜HKšœœ#˜=Kšœ˜Kš˜—šœ˜ šœ œ˜šœœ˜K˜:K˜7Kšœ˜—Kšœœ˜Kšœœ œœ;˜UKšœœ˜KšœœI˜NKšœœœ˜$šœœ œ˜%KšœA˜A—Kšœœœœ?˜]šœœ ™Kšœ.™.Kšœ+™+Kšœ™—KšœœI˜NKšœœO˜TKšœœ˜Kšœœ<˜AKšœœ˜KšœœB˜GKšœœ˜KšœœG˜LKšœœ>˜CKšœœG˜Lšœœ˜Kšœ0˜0Kšœ5˜5Kšœ˜—šœœ˜Kšœ6˜6Kšœ/˜/Kšœ˜—šœœ˜KšœC˜CK˜—Kšœœ˜Kšœœ˜Kšœœ˜šœœ˜K˜˜Cšœœ˜Kšœ5˜5K˜8K˜—Kšœœ˜Kšœœ˜—Kšœ˜ Kšœ˜——šœ˜K˜——šž&œœG˜xKšœ4˜4Kšœ˜K˜—šž œœA˜lš œœ&œ œ˜Gšœ œ˜KšœœK˜QKšœœK˜QKšœœK˜QKšœœM˜SKšœœ˜—Kšœ˜—Kšœ˜K˜—šž&œœœ=˜wšœœœ˜ Kšœ>˜>Kšœ˜—Kšœ˜K˜K˜K˜——šŸ™š žœœœ+œ˜mKšœ'˜'Kšœ˜ Kšœ˜K˜—š žœœCœœ˜šœœ œ˜&šœ˜ Kšœœœ ˜+Kšœ8˜8Kš œœœœ œ˜*šœœœ˜šœœ˜$KšœœJ˜Pšœœ™šœœœœ™1Kšœœœ6™Cšœ™šœœ™šœ:™<šœ™KšœX™Xšœœ™Kšœœœ ™0K™a—K™—Kšœ(™,—Kšœ™—Kšœœ#œ:œ™„Kšœ™———Kšœœœ6˜IK™—Kšœ˜—Kš˜—šœ˜ šœ œ˜šœœ˜Kšœ4˜4Kšœ1˜1Kšœ˜—Kšœœ˜Kšœœ œœ;˜UKšœœ˜KšœœC˜HKšœœœ˜$šœœ œ˜%Kšœ;˜;—Kšœœœœ?˜]šœœ ™Kšœ(™(Kšœ%™%Kšœ™—KšœœC˜HKšœœI˜NKšœœ˜Kšœœ6˜;Kšœœ˜Kšœœ<˜AKšœœ˜KšœœA˜FKšœœ8˜=KšœœA˜Fšœœ˜Kšœ*˜*Kšœ/˜/Kšœ˜—šœœ˜Kšœ0˜0Kšœ)˜)Kšœ˜—Kšœœ˜Kšœœ˜Kšœœ˜šœœ˜Kšœ6˜6Kšœ4˜4K˜—Kšœœ˜Kšœœ8˜=šœœ˜Kšœ/˜/Kšœ2˜2K˜—Kšœœ˜Kšœœ˜—Kšœ˜ Kšœ˜——šœ˜K˜——šž œœG˜rKšœ.˜.Kšœ˜K˜—šžœœA˜fš œœ&œ œ˜Gšœ œ˜KšœœE˜KKšœœE˜KKšœœE˜KKšœœG˜MKšœœ˜—Kšœ˜—Kšœ˜K˜—šž œœœ=˜qšœœœ˜ Kšœ8˜8Kšœ˜—Kšœ˜K˜K˜K˜——šŸ™Jšœœœ˜8Jšœœœœ˜BJ˜Jšœœœ˜@Jšœœœœ˜JJ˜Jšœœœ˜@Jšœœœœ˜JJ˜Jšœœœœ˜0J˜K˜šžœœ+œ˜kK™ŽKšœœ œ˜Cšžœœ"˜3Kšœ œ˜Kšœ˜—š œœ%œ œ˜Fšœ œ˜šœœ˜"K™ Kšœ œ œ˜,šœœ˜)Jšœ œœ˜%—šœœœ œ˜3šœœ˜)Jšœ œœ˜&—šœœ˜)Jšœ œœ˜%—J˜—J˜—šœœ˜"šœœ˜)Jšœ œœ˜&—J˜—šœœ˜"šœœ˜)Jšœ œœ˜&—J˜—šœ˜ Jšœœ<˜D——Jšœ˜—Jšœœ  œœ˜HJšœ˜ Jšœ˜J˜—š žœœœœœ˜qJ˜—š žœœœœ œ#˜š œœœ0œ œ˜XKšœ+˜+š œœœœœ˜9KšœœJ˜PKšœœJ˜PKšœœI˜OKšœœI˜OKšœœ(œ˜3Kšœ˜K˜Kšœœœ˜—Kšœ˜—Kšœœœ˜Kšœ˜K˜—šž œœ)˜AK™)Kšœ œ&œ˜OKš œœ œ.œœ™{šœ˜Kšœ˜Kšœ˜—K˜Kšœ˜K˜—š žœœœ>œ œ˜ŽKšœœ˜Kšœ˜Kšœ'˜'šœ˜ Kšœ˜Kšœœœ.˜XKšœυ™υ—Kšœ˜ Kšœ˜K˜—š žœœœ>œ œ˜Kšœœ˜Kšœ˜Kšœ&˜&šœ˜ Kšœ˜Kšœœœ.˜XKšœτ™τ—Kšœ˜ Kšœ˜K˜—š žœœœ>œ œ˜Kšœœ˜Kšœ˜Kšœ&˜&šœ˜ Kšœ˜Kšœœœ.˜XKšœ”™”—Kšœ˜ Kšœ˜K˜—š žœœœ>œ œ˜ŽKšœœ˜Kšœ˜Kšœ'˜'šœ˜ Kšœ˜šœ˜Kšœ&™&K™Kšœ œ™)šœœœœ%™8Kšœ%™)—Kšœ%Οc ˜/K˜——Kšœ˜ Kšœ˜K˜—š žœœœ:œ˜€Kšœœ˜Kšœ˜Kšœœ ˜*Kšœœœœ˜Kšœ˜Kšœ˜ Kšœ˜K˜K˜—š žœ œœœœ˜\š œœœ0œ œ˜XKšœ+˜+šœœ˜&Kšœœ˜9šœ œ˜Kšœœ˜š œœ6œ œ˜SKšœœ$˜8Kšœ œœœ˜*Kšœ˜——Jšœ˜—J˜Jšœ˜—šœ˜K˜—K˜—š ž œœ œœ˜Lšœœœ˜šœœ&˜,Kšœœ˜1—šœœ&˜,Kšœœ˜/—šœœ%˜+Kšœœ˜.—šœœ%˜+Kšœœ˜.—šœœ(˜.Kšœ˜—Kšœ˜K˜—Kšœ˜——šŸ™šžœ œ+œ˜qKšœ8˜8š œœ%œ œ˜Fšœ œ˜šœœ˜"JšœF˜FJšœ œ˜&Jšœ œ œ˜,šœ œ ˜)Jšœœ A˜KJšœ;˜?—šœœœ œ˜3J™VJšœ œœ˜7JšœG˜GJšœF˜FJ˜;J˜:J˜J˜—J˜—šœœ˜"JšœG˜GJšœœ,˜>JšœI˜IJšœ œ œ œ#™MJšœ=™=J˜—šœœ˜"JšœG˜GJ˜$J˜—šœ˜ Jšœœ<˜D——Jšœ˜—Jšœ˜ Jšœ˜—K™—šŸ™K˜šžœœ%œ˜eKšœζ™ζšœ œœ3˜Hšœ œ˜Kšœœ˜Kšœ˜——šœ œœ3˜Hšœ œ˜Kšœœ ˜)Kšœ˜——Kšœ˜K™—š ž œœ'œœ$œ˜ˆKšœœœ˜šœœ˜"Kš œœœœœ˜Kšœ*œ˜Fš œœœ(œœ˜HKšœœ˜1Kšœœœ˜Kšœ˜—Kšœœ"˜*K˜—šœ7œ œ˜OKšœœ˜6Kšœ˜—K˜Kšœœ˜Kšœ˜K˜—š ž œœ&œœœœ˜rKšœœœ ™<š œœœ(œœ˜HKšœœœœ˜#Jšœ˜—Kšœœ˜Kšœ˜K˜—šž œœ"˜9Kšœœ œœ˜GKšœ˜K˜—š žœœ œœ˜TKšœœ/œ ™KKšœœœœ˜3šœ6œ œ˜NKšœ'œœœ˜