m3ovr/src/Main.m3


---------------------------------------------------------------------------
MODULE Main;

IMPORT Text, TextSeq, ParseParams, Pathname, OSError, Stdio, Process;
IMPORT SMsg AS Msg, FSUtils, M3makefile, TextUtils, PathRepr, Creation;
IMPORT (* FSFixed AS *) FS;
---------------------------------------------------------------------------
CONST maxLevel = 5;
---------------------------------------------------------------------------
PROCEDURE EvalParams() =
  VAR pp := NEW(ParseParams.T).init(Stdio.stderr);
  BEGIN
    pdir := Pathname.Current;
    root := Pathname.Current;
    Msg.tFlag := TRUE;
    TRY
      Msg.vFlag := pp.keywordPresent("-v"); (* be verbose *)
      Msg.dFlag := pp.keywordPresent("-d"); (* debug messages *)

      IF pp.keywordPresent("-r") OR pp.keywordPresent("-root") THEN
        root := pp.getNext();
        pdir := root;
      END;
      (* creation date option *)
      IF pp.keywordPresent("-created") THEN
        Msg.T(Creation.Date & " on " & Creation.System);
        Process.Exit(0);
      END;
      npkgs := NUMBER(pp.arg^) - pp.next;
      pkglocs := NEW(TextSeq.T).init(npkgs);
      FOR i := 1 TO npkgs DO
	VAR t := pp.getNext(); BEGIN
	  IF Text.GetChar(t, 0) = '-' THEN
	    Msg.Fatal("unrecognized option: " & t, 2);
	  ELSE
	    pkglocs.addhi(t);
	  END;
	END;
      END;
      pp.finish();
    EXCEPT
      ParseParams.Error =>
      Msg.Fatal("unknown command line arguments; usage: " &
        "m3ovr [-v] [-d] [-r dir] pkg-location-1 .. pkg-location-n");
    END;
  END EvalParams;
---------------------------------------------------------------------------
PROCEDURE FindMakefileAndPkgName() =
  VAR
    rmkfname := Pathname.Join("src", "m3makefile", NIL);
    mkfname := Pathname.Join(root, rmkfname, NIL);
  BEGIN
    TRY
      pdir := FS.GetAbsolutePathname(pdir);
      root := FS.GetAbsolutePathname(root);
    EXCEPT
      OSError.E => Msg.Fatal("cannot get working directory");
    END;
    WHILE (level < maxLevel) AND NOT FSUtils.IsFile(mkfname) DO
      INC(level);
      root := Pathname.Prefix(root);
      pdir := Pathname.Prefix(pdir);
      mkfname := Pathname.Join(root, rmkfname, NIL);
    END;
    IF level = maxLevel THEN
      Msg.Fatal("cannot find m3makefile")
    END;
    pname := Pathname.Last(pdir);
    TRY
      fn := FS.GetAbsolutePathname(mkfname);
    EXCEPT
      OSError.E => Msg.Fatal("cannot get absolute pathname");
    END;
  END FindMakefileAndPkgName;
---------------------------------------------------------------------------
PROCEDURE ParseMakefile() =
  BEGIN
    TRY
      mkf := M3makefile.New(fn);
    EXCEPT
      OSError.E => Msg.Fatal("error reading m3makefile");
    | M3makefile.ParseError(e) => Msg.Fatal("error parsing m3makefile: " & e);
    END;
  END ParseMakefile;
---------------------------------------------------------------------------
PROCEDURE C(m : TEXT) =
  BEGIN
    Msg.V("% " & m);
  END C;
---------------------------------------------------------------------------
PROCEDURE M(m : TEXT) =
  BEGIN
    Msg.T( m);
  END M;
---------------------------------------------------------------------------
VAR
  mkf      : M3makefile.T;
  fn       : TEXT;
  root     : TEXT;
  level    := 0;
  pdir     : Pathname.T;
  pname    := "undefined";
  imps     : TextSeq.T;
  decls    : M3makefile.M3DeclarationList;
  pkgs     : TextSeq.T;
  pkglocs  : TextSeq.T;
  npkgs    : CARDINAL;
BEGIN (* Main *)
  EvalParams();

  FindMakefileAndPkgName();

  ParseMakefile();

  IF mkf.unknownElements() THEN
    Msg.Warning("m3makefile " & fn &
      "\n     contains elements unknown to m3dep");
    C("m3makefile contains elements unknown to m3dep");
  END;

  IF Msg.vFlag THEN
    IF mkf.targetType() = M3makefile.TargetType.Library THEN
      IF mkf.targetName() = NIL THEN
        C("undefined main target");
      ELSE
        C("main target is library " & mkf.targetName());
      END;
    ELSIF mkf.targetType() = M3makefile.TargetType.Program THEN
      IF mkf.targetName() = NIL THEN
        C("undefined main target");
      ELSE
        C("main target is program " & mkf.targetName());
      END;
    ELSE
      C("unknown main target");
    END;

    decls := mkf.elements();
    WHILE decls # NIL DO
      IF decls.name = NIL THEN
        C("procedure/option " & decls.type);
      ELSE
        C(decls.type & " declaration " & decls.name & " (args = " &
          TextUtils.TextSeqToText(decls.args) & ")");
      END;
      decls := decls.next;
    END;
  END;

  imps := mkf.imports();
  pkgs := NEW(TextSeq.T).init(npkgs);
  FOR i := 0 TO npkgs - 1 DO
    WITH pkgloc = pkglocs.get(i) DO
      WITH pkg = Pathname.Last(pkgloc) DO
        pkgs.addhi(pkg);
        WITH loc = PathRepr.Posix(Pathname.Prefix(pkgloc)) DO
          IF TextUtils.MemberOfTextSeq(imps, pkg) THEN
            M("override(\"" & pkg & "\", \"" & loc & "\")");
          ELSE
            C("package " & pkg & " not used");
          END;
        END;
      END;
    END;
  END;
  IF mkf.targetType() = M3makefile.TargetType.Program THEN
    M("if not defined(\"PM3\")");
    M("  % The procedure \"build_standalone\" exists only in SRC Modula-3.");
    M("  if not defined(\"build_standalone\")");
    M("    PM3 = \"T\"");
    M("  end");
    M("end");
    M("if defined(\"PM3\")");
    M("  proc build_standalone() is");
    M("    option(\"standalone\", \"T\")");
    M("  end");
    M("end");
    M("if not defined(\"DYNAMIC\")");
    M("  build_standalone()");
    M("end");
    Msg.Warning("program " & mkf.targetName() & " will be linked statically");
  END;
  FOR i := 0 TO imps.size() - 1 DO
    WITH imp = imps.get(i) DO
      IF NOT TextUtils.MemberOfTextSeq(pkgs, imp) THEN
        C("location of imported package " & imp & " not overriden");
        Msg.Warning("location of imported package " & imp & " not overriden");
      END;
    END;
  END;
END Main.

interface TextUtils is in:


interface Creation is in: