m3tk/src/pl/M3LProgContext.m3


 Copyright (C) 1990, Digital Equipment Corporation           
 All rights reserved.                                        
 See the file COPYRIGHT for a full description.              

MODULE M3LProgContext;

IMPORT RefList, Text;
IMPORT M3Context, M3CUnit, M3AST_AS, M3CId;

IMPORT M3AST_AS_F, M3AST_SM_F, M3AST_PL_F;

IMPORT M3LMain, M3LDepends;
IMPORT SeqM3AST_AS_Module, SeqM3AST_AS_Used_interface_id,
    SeqM3AST_AS_Interface;

PROCEDURE BuildInContext(
    c: M3Context.T;
    m: M3AST_AS.Module): M3Context.T
    RAISES {}=
  VAR
    iter: SeqM3AST_AS_Module.Iter;
    depends: M3AST_AS.Module;
  BEGIN
    RecordImportsAndExports(c, m);
    (* record imports/exports for dependent modules *)
    iter := SeqM3AST_AS_Module.NewIter(m.pl_dependson_s);
    WHILE SeqM3AST_AS_Module.Next(iter, depends) DO
      RecordImportsAndExports(c, depends);
    END; (* while *)
    RETURN c;
  END BuildInContext;

PROCEDURE Build(m: M3AST_AS.Module): M3Context.T RAISES {}=
  BEGIN
    WITH c = M3Context.New() DO RETURN BuildInContext(c, m) END;
  END Build;

PROCEDURE BuildC(c: M3Context.T; name: TEXT := NIL): M3Context.T RAISES {}=
  VAR
    cu_s: RefList.T := M3LMain.Module(c);
  BEGIN
    IF cu_s = NIL THEN
      RETURN NIL;  (* no main program modules at all *)
    ELSE
      VAR cu: M3AST_AS.Compilation_Unit := cu_s.head;
      BEGIN
        IF name # NIL THEN
          WHILE cu_s # NIL DO
            cu := cu_s.head;
            IF Text.Equal(name, M3CId.ToText(cu.as_root.as_id.lx_symrep)) THEN
              EXIT;
            END;
            cu_s := cu_s.tail;
          END;
          IF cu_s = NIL THEN RETURN NIL END;
        END;
        M3LDepends.Set(c, M3LDepends.Default());
        RETURN Build(cu.as_root);
      END;
    END; (* if *)
  END BuildC;

TYPE
  Closure = M3Context.Closure OBJECT
    list: SeqM3AST_AS_Interface.T;
    exporters := SeqM3AST_AS_Module.Null;
  OVERRIDES
    callback := FindExporters
  END;

PROCEDURE BuildPartial(
    c: M3Context.T;
    list: SeqM3AST_AS_Interface.T)
    : M3Context.T RAISES {}=
  VAR
    iter: SeqM3AST_AS_Module.Iter;
    module: M3AST_AS.Module;
    nc := M3Context.New();
    cl := NEW(Closure, list := list);
  BEGIN
    <*FATAL ANY*> BEGIN
      M3Context.ApplyToSet(c, cl,
          M3CUnit.TypeSet{M3CUnit.Type.Module, M3CUnit.Type.Module_gen_ins});
    END;
    iter := SeqM3AST_AS_Module.NewIter(cl.exporters);
    M3LDepends.Set(c, M3LDepends.Default());
    WHILE SeqM3AST_AS_Module.Next(iter, module) DO
      EVAL BuildInContext(nc, module);
    END; (* while *)
    RETURN nc;
  END BuildPartial;

PROCEDURE FindExporters(
    cl: Closure;
    ut: M3CUnit.Type;
    <*UNUSED*> name: TEXT;
    cu: M3AST_AS.Compilation_Unit)
    RAISES {}=
  VAR
    iter := SeqM3AST_AS_Interface.NewIter(cl.list);
    iter2: SeqM3AST_AS_Used_interface_id.Iter;
    intf: M3AST_AS.Interface;
    used_intf_id: M3AST_AS.Used_interface_id;
    module: M3AST_AS.Module;
  BEGIN
    cu := M3CUnit.ToGenIns(cu, ut);
    module := cu.as_root;
    iter2 := SeqM3AST_AS_Used_interface_id.NewIter(module.sm_export_s);
    WHILE SeqM3AST_AS_Used_interface_id.Next(iter2, used_intf_id) DO
      WHILE SeqM3AST_AS_Interface.Next(iter, intf) DO
        IF used_intf_id.sm_def= intf.as_id THEN
          SeqM3AST_AS_Module.AddFront(cl.exporters, module);
        END;
      END; (* while *)
    END; (* while *)
  END FindExporters;

PROCEDURE RecordImportsAndExports(
    c: M3Context.T; depends: M3AST_AS.Module)
    RAISES {}=
  VAR
    iter2: SeqM3AST_AS_Used_interface_id.Iter;
    used_intf_id: M3AST_AS.Used_interface_id;
  BEGIN
    CheckEnter(c, depends, M3CUnit.Type.Module);
    (* record which interfaces this module uses/exports *)
    iter2 := SeqM3AST_AS_Used_interface_id.NewIter(depends.sm_import_s);
    WHILE SeqM3AST_AS_Used_interface_id.Next(iter2, used_intf_id) DO
      CheckEnterId(c, used_intf_id.sm_def);
    END; (* while *)
    iter2 := SeqM3AST_AS_Used_interface_id.NewIter(depends.sm_export_s);
    WHILE SeqM3AST_AS_Used_interface_id.Next(iter2, used_intf_id) DO
      CheckEnterId(c, used_intf_id.sm_def);
    END; (* while *)
    END RecordImportsAndExports;

PROCEDURE CheckEnter(c: M3Context.T; u: M3AST_AS.UNIT;
    ut: M3CUnit.Type) RAISES {}=
  BEGIN
    TRY
      M3Context.Add(c, M3CId.ToText(u.as_id.lx_symrep), ut, u.sm_comp_unit);
    EXCEPT
    | M3Context.Duplicate => (* thats ok *)
    END; (* try *)
  END CheckEnter;

PROCEDURE CheckEnterId(c: M3Context.T; d: M3AST_AS.UNIT_ID) RAISES {}=
  VAR ut: M3CUnit.Type;
  BEGIN
    IF d # NIL THEN
      IF ISTYPE(d, M3AST_AS.Interface_id) THEN ut := M3CUnit.Type.Interface
      ELSE ut := M3CUnit.Type.Module;
      END;
      CheckEnter(c, d.sm_spec, ut);
    END; (* if *)
  END CheckEnterId;

BEGIN

END M3LProgContext.