MODULE M3ASTScope; IMPORT ASTWalk, AST, M3AST_AS, M3AST_SM; IMPORT SeqM3AST_AS_DEF_ID, SeqM3AST_AS_Binding; IMPORT M3AST_AS_F, M3AST_SM_F; REVEAL Closure = Closure_public BRANDED OBJECT for_scope: M3AST_SM.SCOPE := NIL; for_end: AST.NODE := NIL; END; PROCEDURE Set(cl: Closure; n: AST.NODE; vm: ASTWalk.VisitMode)= BEGIN TYPECASE n OF | M3AST_AS.UNIT(unit) => IF vm = ASTWalk.VisitMode.Entry THEN cl.scope := unit.as_id.vSCOPE ELSE cl.scope := NIL END; | M3AST_AS.Proc_decl(p) => (* Only when we enter the Block, if any, do the formals come into scope, so we let the Block node do the work on entry. On exit, we reset the scope to the enclosing scope. *) IF vm = ASTWalk.VisitMode.Exit AND p.as_body # NIL THEN cl.scope := cl.scope.sm_enc_scope; END; | M3AST_AS.Block(block) => IF vm = ASTWalk.VisitMode.Entry THEN cl.scope := block.vSCOPE ELSE cl.scope := cl.scope.sm_enc_scope; END; | M3AST_AS.Handler(h) => IF vm = ASTWalk.VisitMode.Exit AND h.as_id # NIL THEN cl.scope := cl.scope.sm_enc_scope; END; | M3AST_AS.Handler_id(id) => IF vm = ASTWalk.VisitMode.Entry THEN cl.scope := id.vSCOPE; END; | M3AST_AS.Tcase(h) => IF vm = ASTWalk.VisitMode.Exit AND h.as_id # NIL THEN cl.scope := cl.scope.sm_enc_scope; END; | M3AST_AS.Tcase_id(id) => IF vm = ASTWalk.VisitMode.Entry THEN cl.scope := id.vSCOPE; END; | M3AST_AS.Binding(b) => (* As we exit a Binding, the With_id comes into scope (for the next Binding, for example). They all go out of scope as we exit the With_st. *) IF vm = ASTWalk.VisitMode.Exit THEN cl.scope := b.as_id.vSCOPE; END; | M3AST_AS.With_st(w) => (* scope reverts to encloser of that asssociated with first binding *) IF vm = ASTWalk.VisitMode.Exit THEN VAR iter := SeqM3AST_AS_Binding.NewIter(w.as_binding_s); b: M3AST_AS.Binding; BEGIN IF SeqM3AST_AS_Binding.Next(iter, b) THEN cl.scope := b.as_id.vSCOPE.sm_enc_scope; END; END; END; | M3AST_AS.For_st(for_st) => (* Somewhat tricky; the For_id does not come into scope until the statement sequence, and we have an optional BY node. *) IF vm = ASTWalk.VisitMode.Entry THEN IF for_st.as_by # NIL THEN cl.for_end := for_st.as_by ELSE cl.for_end := for_st.as_from; END; cl.for_scope := for_st.as_id.vSCOPE; ELSE cl.scope := for_st.as_id.vSCOPE.sm_enc_scope; END; ELSE IF vm = ASTWalk.VisitMode.Exit THEN IF n = cl.for_end THEN cl.scope := cl.for_scope; cl.for_end := NIL; END; END; END END Set; PROCEDURE Lookup(s: M3AST_SM.SCOPE; used_id: M3AST_AS.USED_ID): M3AST_AS.DEF_ID= VAR ps: M3AST_SM.SCOPE; BEGIN IF used_id.lx_symrep = NIL THEN RETURN NIL END; WHILE s # NIL DO VAR iter := SeqM3AST_AS_DEF_ID.NewIter(s.sm_def_id_s); def_id: M3AST_AS.DEF_ID; BEGIN WHILE SeqM3AST_AS_DEF_ID.Next(iter, def_id) DO IF used_id.lx_symrep = def_id.lx_symrep THEN RETURN def_id; END; END; ps := s; s := s.sm_enc_scope; IF (s = NIL OR (s.sm_level # ps.sm_level)) THEN RETURN NIL END; END; END; END Lookup; BEGIN END M3ASTScope.