-- file ReplPack.mesa
-- last modified by Satterthwaite, 22-Jan-82 10:05:18

DIRECTORY
  ReplOps: TYPE USING [BodyHandle, IdHandle, MatchAttr],
  Strings: TYPE USING [SubStringDescriptor, EqualSubStrings],
  SymbolTable: TYPE USING [Base],
  Symbols: TYPE USING [
    Linkage,
    HTIndex, SEIndex, ISEIndex, CSEIndex, RecordSEIndex, CTXIndex, CBTIndex,
    HTNull, SENull, ISENull, typeTYPE],
  Types: TYPE USING [Handle, Assignable, Equivalent];

ReplPack: PROGRAM IMPORTS Strings, Types EXPORTS ReplOps = {
  OPEN Symbols;

  IdHandle: TYPE = ReplOps.IdHandle;
  
  MatchedNames: PROC [id1, id2: IdHandle] RETURNS [BOOLEAN] = {
    OPEN b1: id1.stb, b2: id2.stb;
    ss1, ss2: Strings.SubStringDescriptor;
    IF id1.sei = ISENull OR id2.sei = ISENull THEN RETURN [FALSE];
    b1.SubStringForHash[@ss1, b1.seb[id1.sei].hash];
    b2.SubStringForHash[@ss2, b2.seb[id2.sei].hash];
    RETURN [Strings.EqualSubStrings[@ss1, @ss2]]};

-- matching fields

  MatchMode: PROC [id: IdHandle] RETURNS [Linkage] = {
    -- LinkMode for a virtual defs module
    OPEN b: id.stb;
    RETURN [IF b.seb[id.sei].idType = typeTYPE AND b.seb[id.sei].public
      THEN type
      ELSE
	IF b.seb[id.sei].constant THEN
	  SELECT b.XferMode[b.seb[id.sei].idType] FROM
	    proc, program, signal, error => val,
	    ENDCASE => manifest
	  ELSE ref]};

  MatchedAttrs: PROC [idL, idR: IdHandle] RETURNS [BOOLEAN] = {
    OPEN bL: idL.stb, bR: idR.stb;
    typeL: CSEIndex = bL.UnderType[bL.seb[idL.sei].idType];
    mode: Linkage = MatchMode[idL];
    matched: BOOLEAN;
    IF idR.sei # ISENull THEN {
      typeR: CSEIndex = bR.UnderType[bR.seb[idR.sei].idType];
      matched ← SELECT mode FROM
        val =>
	  Types.Assignable[[idL.stb, typeL], [idR.stb, typeR]]
	    AND
	  (bL.seb[idL.sei].idValue = bR.seb[idR.sei].idValue),
	ref =>
	  Types.Equivalent[[idL.stb, typeL], [idR.stb, typeR]]
	    AND
	  (bL.seb[idL.sei].idValue = bR.seb[idR.sei].idValue)	-- offsets
	    AND
	  (bL.seb[idL.sei].idInfo = bR.seb[idR.sei].idInfo),	-- sizes
	type =>
	  (bR.seb[idR.sei].idType = typeTYPE) AND (bR.seb[idR.sei].public)
	    AND
	  Types.Equivalent[
	    [idL.stb, bL.UnderType[idL.sei]], [idR.stb, bR.UnderType[idR.sei]]],
	ENDCASE => TRUE}
    ELSE matched ← mode # manifest;
    IF ~matched THEN SIGNAL Unmatched[id, idL];
    RETURN [matched]};
    

  CTXHandle: TYPE = RECORD [
    stb: SymbolTable.Base,
    ctx: CTXIndex];

  MatchedContexts: PROC [ctxL, ctxR: CTXHandle] RETURNS [BOOLEAN] = {
    OPEN bL: ctxL.stb, bR: ctxR.stb;
    n: CARDINAL ← 0;
    FOR sei: ISEIndex ← bL.FirstCtxSe[ctxL.ctx], bL.NextSe[sei]
     UNTIL sei = ISENull OR n > 4 DO
      IF bL.seb[sei].hash # HTNull THEN {
        ss: Strings.SubStringDescriptor;
	bL.SubStringForHash[@ss, bL.seb[sei].hash];
	IF ~MatchedAttrs[
	    [ctxL.stb, sei],
	    [ctxR.stb, bR.SearchContext[bR.FindString[@ss], ctxR.ctx]]] THEN
	  n ← n+1};
      ENDLOOP;
    RETURN [n = 0]};
    

  RecordHandle: TYPE = RECORD [
    stb: SymbolTable.Base,
    sei: RecordSEIndex];

  MatchedRecords: PROC [recL, recR: RecordHandle] RETURNS [BOOLEAN] = {
    OPEN bL: recL.stb, bR: recR.stb;
    RETURN [IF recL.sei = SENull OR recR.sei = SENull
      THEN recL.sei = recR.sei
      ELSE MatchedContexts[ 
             [recL.stb, bL.seb[recL.sei].fieldCtx],
	     [recR.stb, bR.seb[recR.sei].fieldCtx]]]};
	     
  MatchedArgLists: PROC [argL, argR: Types.Handle] RETURNS [BOOLEAN] = {
    OPEN bL: argL.stb, bR: argR.stb;
    inL, inR, outL, outR: RecordSEIndex;
    [inL, outL] ← bL.TransferTypes[argL.sei];
    [inR, outR] ← bR.TransferTypes[argR.sei];
    RETURN [
      MatchedRecords[[argL.stb, inL], [argR.stb, inR]]
        AND
      MatchedRecords[[argL.stb, outL], [argR.stb, outR]]]};
      
                    
-- main entry

  BodyHandle: TYPE = ReplOps.BodyHandle;

  Unmatched: PUBLIC SIGNAL [ReplOps.MatchAttr, IdHandle] = CODE;

  MatchedBodies: PUBLIC PROC [bodyL, bodyR: BodyHandle] RETURNS [BOOLEAN] = {
    OPEN bL: bodyL.stb, bR: bodyR.stb;
    matched: BOOLEAN ← TRUE;
    IF ~bL.bb[bodyL.bti].hints.noStrings THEN {
      SIGNAL Unmatched[strings, [bodyL.stb, bL.bb[bodyL.bti].id]];
      matched ← FALSE};
    IF ~bR.bb[bodyR.bti].hints.noStrings THEN {
      IF ~matched THEN SIGNAL Unmatched[strings, [bodyR.stb, bR.bb[bodyR.bti].id]];
      matched ← FALSE};
    IF ~(
       MatchedNames[
         [bodyL.stb, bL.bb[bodyL.bti].id], [bodyR.stb, bR.bb[bodyR.bti].id]]
          AND
       (bL.bb[bodyL.bti].entryIndex = bR.bb[bodyR.bti].entryIndex)
          AND
       Types.Assignable[
         [bodyL.stb, bL.bb[bodyL.bti].ioType],
	 [bodyR.stb, bR.bb[bodyR.bti].ioType]]
          AND
       MatchedArgLists[
         [bodyL.stb, bL.bb[bodyL.bti].ioType],
	 [bodyR.stb, bR.bb[bodyR.bti].ioType]])
     THEN {
      SIGNAL Unmatched[id, [bodyL.stb, bL.bb[bodyL.bti].id]];
      matched ← FALSE};
    IF ~MatchedContexts[
        [bodyL.stb, bL.bb[bodyL.bti].localCtx],
	[bodyR.stb, bR.bb[bodyR.bti].localCtx]] THEN matched ← FALSE;
    RETURN [matched]};
	
  }.