-- MobConnectionMXCode.mesa
DIRECTORY Atom, MobConnection, Rope, Scheme;
MobConnectionMXCode: CEDAR PROGRAM
IMPORTS Atom, MobConnection, Scheme
= BEGIN OPEN Scheme;
  SymbolFromRope: PROC [rope: Rope.ROPE] RETURNS [Symbol] ~ {RETURN[Atom.MakeAtom[rope]]};
  RopeFromSymbol: PROC [Symbol] RETURNS [Rope.ROPE] ~ Atom.GetPName;
  TheSymbol: PROC [a: Any] RETURNS [Scheme.Symbol] = {
    WITH a SELECT FROM
      a: Scheme.Symbol => RETURN [a];
      ENDCASE => Complain[a, "not a Scheme.Symbol"];
    };
  SymbolForFilterItem: REF ARRAY MobConnection.FilterItem OF Symbol = InitSymbolForFilterItem[];
  InitSymbolForFilterItem: PROC RETURNS [a: REF ARRAY MobConnection.FilterItem OF Symbol] = {
    a ← NEW[ARRAY MobConnection.FilterItem OF Symbol];
    a[versions] ← $versions;
    a[directory] ← $directory;
    a[using] ← $using;
    a[imports] ← $imports;
    a[importedItems] ← Atom.MakeAtom["imported-items"];
    a[exports] ← $exports;
    a[typeExports] ← Atom.MakeAtom["type-exports"];
    a[exportedItems] ← Atom.MakeAtom["exported-items"];
    a[modules] ← $modules;
    a[configurations] ← $configurations;
    };
  TheFilterItem: PROC [a: Any] RETURNS [MobConnection.FilterItem] = {
    FOR k: MobConnection.FilterItem IN MobConnection.FilterItem DO
      IF a=SymbolForFilterItem[k] THEN RETURN [k];
      ENDLOOP;
    ERROR Complain[a, "is not a MobConnection.FilterItem"];
    };
  MobConnectionPrim: PROC [SELF: Primitive, ARG1,ARG2,ARG3: Any, REST: ProperList] RETURNS [result: Any ← unspecified] = {
INNER: PROC = {
    POP: PROC RETURNS [a: Any ← undefined] = {
      IF REST#NIL THEN {a ← REST.car; REST ← NARROW[REST.cdr]}};
    DATA: Pair ~ NARROW[SELF.data];
    env: Environment ~ NARROW[DATA.cdr];
    SELECT NAT[NARROW[DATA.car, REF INT]↑] FROM
      0 => {
        filename: Any ← ARG1;
        filter: Any ← ARG2;
        stack: LIST OF Appender ← NIL;
        Begin: PROC [id: Symbol] = {
        head: Pair = Cons[id, NIL];
        stack ← CONS[[head, head], stack];
        };
        End: PROC = {
        a: Any ← stack.first.head;
        stack ← stack.rest;
        IF stack = NIL THEN result ← a ELSE Put[a];
        };
        Put: PROC [a: Any] = {
        stack.first.last ← stack.first.last.cdr ← Cons[a, NIL]
        };
        PutATOM: PROC [a: Symbol] = {Put[a]};
        PutROPE: PROC [a: Rope.ROPE] = {Put[StringFromRope[a]]};
        PutINT: PROC [a: INT] = {Put[MakeFixnum[a]]};
        PutBOOL: PROC [a: BOOL] = {Put[IF a THEN true ELSE false]};
        PutModuleID: PROC [a: MobConnection.ModuleID] = {
        Begin[$id]; PutATOM[a.identifier]; PutATOM[a.version]; End[]
        };
        f: MobConnection.Filter ← ALL[FALSE];
        IF filter = undefined
        THEN f ← ALL[TRUE]
        ELSE {
        FOR tail: Any ← filter, Cdr[tail] UNTIL tail = NIL DO
        f[TheFilterItem[Car[tail]]] ← TRUE;
        ENDLOOP;
        };
        MobConnection.DecodeMob[fileName: RopeFromString[TheString[filename]], begin: Begin, end: End, putATOM: PutATOM, putROPE: PutROPE, putINT: PutINT, putBOOL: PutBOOL, putModuleID: PutModuleID, filter: f];
        IF stack # NIL THEN ERROR;
        };
      ENDCASE => ERROR
    }; INNER[!
        MobConnection.Error => Complain[culprit, msg];
    ];
    };
    
  MobConnectionInit: PROC [env: Environment] = {
    DefinePrimitive[name: "decode-mob", nArgs: 2, proc: MobConnectionPrim, doc: "(filename [ filter ]) Extract useful information from a mob file", env: env, optional: 1, dotted: FALSE, data: Cons[MakeFixnum[0], env]];
    };
    
  Appender: TYPE  = RECORD [head, last: Pair];
  RegisterInit[MobConnectionInit];
END.