home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / emerald / emrldsys.lha / Kernel / Em / kConform.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-17  |  18.3 KB  |  653 lines

  1. #include "Kernel/h/system.h"
  2. #include "Kernel/h/assert.h"
  3. #include "Kernel/h/map.h"
  4. #include "Kernel/h/mmMsgTypes.h"
  5. #include "Kernel/h/emTypes.h"
  6. #include "Kernel/h/kmdTypes.h"
  7. #include "Kernel/h/builtins.h"
  8. #include "Kernel/h/emkDefs.h"
  9. #include "Kernel/h/utils.h"
  10.  
  11. extern SSPtr                preemptRunning();
  12. extern void                 fail(), schedule();
  13. extern Boolean              LoadRequest();
  14. extern ODP                  OTLookup();
  15. extern AbConPtr             OIDOIDOIDToAbCon();
  16.  
  17. extern char *PPSSPlace(), *PPPOID(), *PPGOID(), *PPOID(), *PPCOID(),
  18.         *PPCodePtr(), *PPFindLineNo();
  19.  
  20. /*
  21.  * The function conforms takes two abstract type OIDS 
  22.  * and determines whether they conform or not.  The abstract types are 
  23.  * represented
  24.  * by strings (to save space).  The format of the strings are:
  25.  *
  26.  *    AT ::=        CannotBCT IsVector Immutable { operation }
  27.  *    CannotBCT ::=    ( 'Y' | 'N' )
  28.  *    IsVector ::=    ( 'Y' | 'N' )
  29.  *    Immutable ::=    ( 'Y' | 'N' )
  30.  *    operation ::=    ( 'O' | 'F' ) 'O' 8hexdigits param -> param
  31.  *    param ::=    '[' [ type { ',' type } ] ']'
  32.  *    type ::=    'S' | 'O' 8hexdigits
  33.  */
  34.  
  35. /*
  36.  * The algorithm is as follows:
  37.  *  if we know that at1 conforms to at2, then return TRUE
  38.  *  else 
  39.  *    1.  assume that at1 *> at2.
  40.  *    2.  for each operation (o2) in at2 
  41.  *        a.  if no identically named operation exitsts in at1 then retract
  42.  *        the assumption and return false.
  43.  *        b.  if numparams or numresults do not match then retract the
  44.  *        assumption and return FALSE.
  45.  *        c.  for each param(p1, p2), 
  46.  *        * note that parameters must conform in the backwards
  47.  *           direction.
  48.  *        i.  if p1 *> p2 then continue.
  49.  *        ii. else retract the assumption and return FALSE.
  50.  *        c.  for each result(r1, r2), 
  51.  *        i.  if r2 *> r1 then continue
  52.  *        ii. else retract the assumption and return FALSE.
  53.  *        d.  return true (having proved our current assumption that 
  54.  *        t1 *> t2)
  55.  *
  56.  * The algorithm for conformity between anything and a type variable is 
  57.  * exactly the same, except that at the
  58.  * assumption stage we identify at1 and at2, that is we say that they conform
  59.  * in both directions.  When we retract the assumption we must remember to
  60.  * invalidate in both directions.
  61.  */
  62.  
  63. typedef struct {
  64.   Boolean        hasValue : 16;
  65.   Boolean        value    : 16;
  66.   OID            missingAT;
  67. } ConformsResult;
  68.  
  69. void ConformInit()
  70. {
  71.   KMDSetTrace(Conform);
  72. }
  73.  
  74. typedef enum { IDENTICAL, CONFORMS, NOTCONFORMS } Relationship;
  75. #define opnameSame(p, q) (!strncmp((p)+2, (q)+2, 8))
  76. #define paramsOf(p) ((p)+10)
  77. #define opsOf(p) ((p) + 1+1+1)
  78.  
  79. char *resultsOf(p)
  80. register char *p;
  81. {
  82.   p += 12;
  83.   while (*p && *p != '>') p++;
  84.   assert(*p == '>');
  85.   return(p+1);
  86. }
  87.  
  88. char *skipOp(p)
  89. register char *p;
  90. {
  91.   p += 9;
  92.   while (*p && *p != ']') p++;
  93.   assert(*p == ']');
  94.   p++;
  95.   assert(*p == '-');
  96.   p++;
  97.   assert(*p == '>');
  98.   p++;
  99.   while (*p && *p != ']') p++;
  100.   assert(*p == ']');
  101.   return(p+1);
  102. }
  103.  
  104. static Boolean relationshipResults [] = { TRUE, TRUE, FALSE };
  105.  
  106. static Map conformsMap = NULL;
  107. static OID cacheKey = NULL;
  108. static Map cacheMap;
  109.  
  110. static int guessLevel = 0;
  111. typedef struct GuessRecord {
  112.   int guessLevel;
  113.   OID oid1, oid2;
  114.   Relationship relationship;
  115.   struct GuessRecord *prev;
  116. } GuessRecord, *GuessRecordPtr;
  117. static GuessRecordPtr guessRecords = NULL;
  118.  
  119. static Relationship getRelationship(oid1, oid2)
  120. OID oid1, oid2;
  121. {
  122.   if (conformsMap == NULL) {
  123.     conformsMap = Map_Create();
  124.   }
  125.   if (oid1 != cacheKey) {
  126.     cacheKey = oid1;
  127.     cacheMap = (Map) Map_Lookup(conformsMap, (int)oid1);
  128.     if (cacheMap == (Map)NIL) {
  129.       cacheMap = Map_Create();
  130.       Map_Insert(conformsMap, (int)oid1, (int)cacheMap);
  131.     }
  132.   }
  133.   return((Relationship)Map_Lookup(cacheMap, (int)oid2));
  134. }
  135.  
  136. static void setRelationship(oid1, oid2, relationship, guess)
  137. OID oid1, oid2;
  138. Relationship relationship;
  139. Boolean guess;
  140. {
  141.   register GuessRecordPtr g;
  142.  
  143.   if (conformsMap == NULL) {
  144.     conformsMap = Map_Create();
  145.   }
  146.   if (oid1 != cacheKey) {
  147.     cacheKey = oid1;
  148.     cacheMap = (Map) Map_Lookup(conformsMap, (int)oid1);
  149.     if (cacheMap == (Map)NIL) {
  150.       cacheMap = Map_Create();
  151.       Map_Insert(conformsMap, (int)oid1, (int)cacheMap);
  152.     }
  153.   }
  154.   Map_Insert(cacheMap, (int)oid2, (int)relationship);
  155.   if (guess) {
  156.     g = (GuessRecordPtr) malloc(sizeof(GuessRecord));
  157.     g->guessLevel = guessLevel;
  158.     g->oid1 = oid1;
  159.     g->oid2 = oid2;
  160.     g->relationship = relationship;
  161.     g->prev = guessRecords;
  162.     guessRecords = g;
  163.   }
  164. }
  165.     
  166. static void startGuessing(oid1, oid2, relationship)
  167. OID oid1, oid2;
  168. Relationship relationship;
  169. {
  170.   guessLevel++;
  171.   setRelationship(oid1, oid2, relationship, TRUE);
  172.   if (relationship == IDENTICAL) setRelationship(oid2, oid1, IDENTICAL, TRUE);
  173. }
  174.  
  175. static void endGuessing(worked, conforms)
  176. Boolean worked, conforms;
  177. {
  178.   register GuessRecordPtr g;
  179.   for (g=guessRecords; g != NULL && g->guessLevel==guessLevel; g=g->prev) {
  180.     if (!worked) {
  181.       setRelationship(g->oid1, g->oid2, (Relationship)NIL, FALSE);
  182.     } else if (!conforms) {
  183.       setRelationship(g->oid1, g->oid2, (Relationship)NOTCONFORMS, FALSE);
  184.     }
  185.     guessRecords = g->prev;
  186.     free((char *)g);
  187.   }
  188.   guessLevel--;
  189. }
  190.  
  191. static ConformsResult allConform(), hardConforms(), i_conforms();
  192.  
  193. char *fetchInfo(atOID)
  194. OID atOID;
  195. {
  196.   /* otlookup, if not there return NULL */
  197.   /* else return the pointer the chars of the string */
  198.   CodeODP codp;
  199.   CodePtr cp;
  200.   StringPtr stringPtr;
  201.  
  202.   codp = (CodeODP) OTLookup(atOID);
  203.   if (IsNULL(codp) || IsNULL(codp->dataPtr)) return(NULL);
  204.   cp = codp->dataPtr;
  205.   stringPtr = (StringPtr) addOffset(cp, cp->abstractTypeInfoOffset);
  206.   return((char *) &stringPtr->data[0]);
  207. }
  208.  
  209. /* Call back for at loaded for conforms */
  210. HResult ConformsCallBack(fReq, fOID)
  211. ConformReqPtr   fReq;
  212. OID             fOID;
  213. {
  214.   ConformsResult result;
  215.   KMDTrace("Conform", 1,
  216.     "AT %s loaded, re-starting conforms of %s to %s\n",
  217.     PPCOID(fOID), PPCOID(fReq->oid1), PPCOID(fReq->oid2));
  218.   do {
  219.     result = i_conforms(fReq->oid1, fReq->oid2, 1);
  220.     if (! result.hasValue) {
  221.       if (! LoadRequest(result.missingAT, (GenericReqPtr) fReq)) break;
  222.     }
  223.   } while (! result.hasValue);
  224.   /* result is as good as it gets */
  225.   if (result.hasValue) {
  226.     fReq->waiting->resultBrand = DataBrand;
  227.     fReq->waiting->regs.arg1 = (int)result.value;
  228.     schedule(fReq->waiting);
  229.     FreeRequest((GenericReqPtr) fReq);
  230.   }
  231. }
  232.  
  233. /* Kernel call */
  234. void Conform(at1, at2)
  235. OID at1, at2;
  236. {
  237.   ConformsResult result;
  238.   ConformReqPtr req = NULL;
  239.   do {
  240.     result = i_conforms(at1, at2, 1);
  241.     if (! result.hasValue) {
  242.       /* create request */
  243.       if (req == NULL) {
  244.     req = mNewRequest(Conform);
  245.     req->oid1 = at1;
  246.     req->oid2 = at2;
  247.     req->hdr.callBack = (GenericHandlerPtr) ConformsCallBack;
  248.       }
  249.       KMDTrace("Conform", 1, "Waiting for AT %s to be loaded\n",
  250.     PPCOID(result.missingAT));
  251.       if (! LoadRequest(result.missingAT, (GenericReqPtr) req)) break;
  252.     }
  253.   } while (! result.hasValue);
  254.   /* result is as good as it gets */
  255.   if (result.hasValue) {
  256.     currentSSP->resultBrand = DataBrand;
  257.     currentSSP->regs.arg1 = (int)result.value;
  258.     if (req != NULL) FreeRequest((GenericReqPtr) req);
  259.   } else {
  260.     req->waiting = preemptRunning();
  261.     req->waiting->status.rs = SSConformWait;
  262.     KMDTrace("LineNumber", 4, "%s waiting on conformity check in %s\n",
  263.     PPPOID(req->waiting->processOID), PPSSPlace(req->waiting));
  264.   }
  265. }
  266.  
  267. /* Call back for at loaded for Views */
  268. HResult ViewCallBack(fReq, fOID)
  269. ViewReqPtr          fReq;
  270. OID                 fOID;
  271. {
  272.   ConformsResult result;
  273.   CodeODP codp;
  274.   CodePtr cp;
  275.  
  276.   if (IsNIL(fReq->restrictOID)) {
  277.     /* we have just loaded the code so we can get the ATOID */
  278.     codp = (CodeODP) OTLookup(fReq->ctOID);
  279.     assert(NonNULL(codp));
  280.     assert(NonNULL(codp->dataPtr));
  281.     cp                  = codp->dataPtr;
  282.     fReq->restrictOID   = cp->ownAbstractType;
  283.     KMDTrace("Conform", 1, "CT %s is loaded, starting view of %s to %s\n",
  284.       PPCOID(fOID), PPCOID(fReq->restrictOID), PPCOID(fReq->newATOID));
  285.   } else {
  286.     KMDTrace("Conform", 1, "AT %s is loaded, re-starting view of %s to %s\n",
  287.       PPCOID(fOID), PPCOID(fReq->restrictOID), PPCOID(fReq->newATOID));
  288.   }
  289.   do {
  290.     result = i_conforms(fReq->restrictOID, fReq->newATOID, 1);
  291.     if (! result.hasValue) {
  292.       KMDTrace("Conform", 1, "Waiting for AT %s to be loaded\n",
  293.     PPCOID(result.missingAT));
  294.       if (! LoadRequest(result.missingAT, (GenericReqPtr) fReq)) break;
  295.     }
  296.   } while (! result.hasValue);
  297.   /* result is as good as it gets */
  298.   if (result.hasValue) {
  299.     if (result.value) {
  300.       codp = (CodeODP) OTLookup(fReq->ctOID);
  301.       if (
  302.           (NonNULL(codp)) && NonNULL(codp->dataPtr) &&
  303.           (codp->dataPtr->ownAbstractType == fReq->restrictOID)
  304.       ) {
  305.       fReq->restrictOID = (OID) NIL;
  306.       }
  307.       
  308.       fReq->waiting->resultBrand = VariableBrand;
  309.       fReq->waiting->regs.arg1 = (int) fReq->dataPtr;
  310.       fReq->waiting->regs.arg2 = (int) OIDOIDOIDToAbCon(fReq->newATOID,
  311.         fReq->restrictOID, fReq->ctOID);
  312.       
  313.       schedule(fReq->waiting);
  314.     } else {
  315.       fail(fReq->waiting);
  316.     }
  317.     FreeRequest((GenericReqPtr) fReq);
  318.   }
  319. }
  320.  
  321. /* Kernel call */
  322. void ViewPtr(dataPtr, abConPtr, atPtr)
  323. DataAddr dataPtr;
  324. struct AbCon *abConPtr;
  325. CodePtr atPtr;
  326. /* View the object pointed to by dataPtr and abConPtr as one of atPtr */
  327. {
  328.   OID                       ownATOID = 0, ownCTOID = 0, at;
  329.   ConformsResult            result;
  330.   register ViewReqPtr       req = NULL;
  331.   
  332.   at = atPtr->ownOID;
  333.   KMDTrace("Conform", 3, "ViewPtr (0x%04x) as one of %s\n", dataPtr,
  334.       PPCodePtr(atPtr));
  335.   
  336.   if (abConPtr == (AbConPtr) EMNIL || dataPtr == (DataAddr) EMNIL) {
  337.     currentSSP->resultBrand = VariableBrand;
  338.     currentSSP->regs.arg1 = (int) EMNIL;
  339.     currentSSP->regs.arg2 = (int) EMNIL;
  340.     return;
  341.   }
  342.   ownCTOID = abConPtr->CodeOID;
  343.   if (IsNIL(abConPtr->restrictOID) && IsNULL(abConPtr->cPtr)) {
  344.     req = mNewRequest(View);
  345.     req->restrictOID = (OID) NIL;
  346.     req->newATOID   = at;
  347.     req->ctOID      = ownCTOID;
  348.     req->dataPtr    = dataPtr;
  349.     req->hdr.callBack = (GenericHandlerPtr) ViewCallBack;
  350.     KMDTrace("Conform", 1, "Waiting for CT %s to be loaded\n",
  351.       PPCOID(ownCTOID));
  352.     if (! LoadRequest(ownCTOID, (GenericReqPtr) req)) {
  353.       req->waiting = preemptRunning();
  354.       req->waiting->status.rs = SSConformWait;
  355.       KMDTrace("LineNumber", 4, "%s waiting on conformity check in %s\n",
  356.     PPPOID(req->waiting->processOID), PPSSPlace(req->waiting));
  357.       return;
  358.     } else {
  359.       assert(NonNULL(abConPtr->cPtr));
  360.     }
  361.   }
  362.   ownATOID = abConPtr->restrictOID;
  363.   if (IsNIL(ownATOID)) {
  364.       ownATOID  = abConPtr->cPtr->ownAbstractType;
  365.   }
  366.   
  367.   do {
  368.     result = i_conforms(ownATOID, at, 1);
  369.     if (! result.hasValue) {
  370.       /* create request */
  371.       if (req == NULL) {
  372.     req = mNewRequest(View);
  373.     req->restrictOID        = ownATOID;
  374.     req->newATOID           = at;
  375.     req->ctOID              = ownCTOID;
  376.     req->dataPtr            = dataPtr;
  377.     req->hdr.callBack = (GenericHandlerPtr) ViewCallBack;
  378.       }
  379.       KMDTrace("Conform", 1, "Waiting for AT %s to be loaded\n",
  380.     PPCOID(result.missingAT));
  381.       if (! LoadRequest(result.missingAT, (GenericReqPtr) req)) break;
  382.     }
  383.   } while (! result.hasValue);
  384.   /* result is as good as it gets */
  385.   if (result.hasValue) {
  386.     if (result.value) {
  387.       CodeODP codp;
  388.       
  389.       codp = (CodeODP) OTLookup(ownCTOID);
  390.       if (
  391.           (NonNULL(codp)) && NonNULL(codp->dataPtr) &&
  392.           (codp->dataPtr->ownAbstractType == ownATOID)
  393.       ) {
  394.       ownATOID = (OID) NIL;
  395.       }
  396.       
  397.       currentSSP->resultBrand = VariableBrand;
  398.       currentSSP->regs.arg1 = (int) dataPtr;
  399.       currentSSP->regs.arg2 = (int) OIDOIDOIDToAbCon(at, ownATOID, ownCTOID);
  400.     } else {
  401.       fail(preemptRunning());
  402.     }
  403.     if (req != NULL) FreeRequest((GenericReqPtr) req);
  404.   } else {
  405.     req->waiting = preemptRunning();
  406.     req->waiting->status.rs = SSConformWait;
  407.     KMDTrace("LineNumber", 4, "%s waiting on conformity check in %s\n",
  408.     PPPOID(req->waiting->processOID), PPSSPlace(req->waiting));
  409.   }
  410. }
  411.  
  412. static char *SPACES = "                                                    ";
  413.  
  414. #define ANSWER(b, id) { \
  415.   result.hasValue = (id == 0); \
  416.   result.value = b; \
  417.   result.missingAT = id; \
  418.   return(result); \
  419. }
  420.  
  421. static ConformsResult i_conforms(oid1, oid2, level)
  422. OID oid1, oid2;
  423. int level;
  424. {
  425.   Relationship relationship;
  426.   ConformsResult result;
  427.   char *at1, *at2;
  428.   Boolean theResult;
  429.  
  430.   KMDTrace("Conform", level, "%.*sConforming 0x%08x to 0x%08x\n", 
  431.     level, SPACES, oid1, oid2);
  432.  
  433.   if ((at1 = fetchInfo(oid1)) == NULL) ANSWER(FALSE, oid1);
  434.   if ((at2 = fetchInfo(oid2)) == NULL) ANSWER(FALSE, oid2);
  435.  
  436.   if (oid1 == oid2) {
  437.     KMDTrace("Conform", level, "%.*sSame oid => true\n", level, SPACES);
  438.     ANSWER(TRUE, 0);
  439.   }
  440.   if (oid1 == OIDOfBuiltin(B_INSTAT, NILINDEX)) {
  441.     KMDTrace("Conform", level, "%.*sNil conforms to anything => true\n",
  442.       level, SPACES);
  443.     ANSWER(TRUE, 0);
  444.   } else if (oid2 == OIDOfBuiltin(B_INSTAT, NILINDEX)) {
  445.      KMDTrace("Conform", level, "%.*sOnly nil conforms to None => false\n",
  446.        level, SPACES);
  447.      ANSWER(FALSE, 0);
  448.   }
  449.   relationship = getRelationship(oid1, oid2);
  450.   if ((int) relationship != NIL) {
  451.     theResult = relationshipResults[(int)relationship];
  452.     KMDTrace("Conform", level, "%.*sAlready know => %s\n", level, SPACES,
  453.       theResult ? "true" : "false");
  454.     ANSWER(theResult, 0);
  455.   }
  456.  
  457.   /* if at2 will not admit conformers, then give up */
  458.   if (*at2 == 'Y') {
  459.     if (*(at2+1) == 'Y' && *(at1+1) == 'Y') {
  460.       KMDTrace("Conform", level,
  461.     "%.*s0x%08x cannotBeConformedTo but 0x%08x is a vector: keep going\n",
  462.     level, SPACES, oid2, oid1);
  463.     } else {
  464.       KMDTrace("Conform", level, "%.*s0x%08x cannotBeConformedTo => false\n",
  465.     level, SPACES, oid2);
  466.       ANSWER(FALSE, 0);
  467.     }
  468.   }
  469.  
  470.   startGuessing(oid1, oid2, CONFORMS);
  471.   result = hardConforms(oid1, oid2, at1, at2, level+1);
  472.   if (result.hasValue && result.value) {
  473.     endGuessing(TRUE, TRUE);
  474.     KMDTrace("Conform", level, "%.*s=> true\n", level, SPACES);
  475.     ANSWER(TRUE, 0);
  476.   } else {
  477.     endGuessing(result.hasValue, result.value);
  478.     if (result.hasValue) 
  479.       KMDTrace("Conform", level, "%.*s=> false\n", level, SPACES);
  480.     ANSWER(FALSE, result.missingAT);
  481.   }
  482. }
  483.  
  484. static int pLength(s)
  485. register char *s;
  486. {
  487.   register int r = 0;
  488.   assert(*s == '[');
  489.   while (*s && *s != ']') {
  490.     if (*s == 'S' || *s == 'O') r++;
  491.     s++;
  492.   }
  493.   return(r);
  494. }
  495.  
  496. static ConformsResult hardConforms(oid1, oid2, at1, at2, level)
  497. OID oid1, oid2;
  498. char *at1, *at2;
  499. int level;
  500. {
  501.   char *ops1, *ops2, *args1, *args2, *res1, *res2;
  502.   ConformsResult result;
  503.  
  504.   /* check immutability */
  505.   if (*(at2+2) == 'Y' && *(at1+2) == 'N') {
  506.     KMDTrace("Conform", level,
  507.       "%.*s0x%08x is immutable, 0x%08x isnt => false\n", level,
  508.       SPACES, oid2, oid1);
  509.     ANSWER(FALSE, 0);
  510.   }
  511.  
  512.   ops1 = opsOf(at1);
  513.   ops2 = opsOf(at2);
  514.   while (*ops2 && *ops2 != '\n') {
  515.     KMDTrace("Conform", level, "%.*sChecking operation %.8s\n", level, SPACES,
  516.       ops2+2);
  517.     while (*ops1 && *ops1 != '\n' && !opnameSame(ops1, ops2)) {
  518.       ops1 = skipOp(ops1);
  519.     }
  520.     if (*ops1 == '\0' || *ops1 == '\n') {
  521.       KMDTrace("Conform", level, "%.*s%s not defined => false\n", level,
  522.     SPACES, ops2 + 2);
  523.       ANSWER(FALSE, 0);
  524.     }
  525.     args1 = paramsOf(ops1);
  526.     res1 = resultsOf(ops1);
  527.     args2 = paramsOf(ops2);
  528.     res2 = resultsOf(ops2);
  529.     if (pLength(args1) != pLength(args2)) {
  530.       KMDTrace("Conform", level,
  531.     "%.*soperation %.8s argument number mismatch %d != %d => false\n",
  532.     level, SPACES, ops1+2, pLength(args1), pLength(args2));
  533.       ANSWER(FALSE, 0);
  534.     }
  535.     if (pLength(res1) != pLength(res2)) {
  536.       KMDTrace("Conform", level,
  537.     "%.*soperation %.8s result number mismatch %d != %d => false\n",
  538.     level, SPACES, ops1+2, pLength(res1), pLength(res2));
  539.       ANSWER(FALSE, 0);
  540.     }
  541.     if (*ops2 == 'F' && *ops1 == 'O') {
  542.       KMDTrace("Conform", level,
  543.     "%.*soperation %.8s function mismatch => false\n", level, SPACES,
  544.     ops1+2);
  545.       ANSWER(FALSE, 0);
  546.     }
  547.     result = allConform(oid2, oid1, args2, args1, level+1);
  548.     if (! result.hasValue) ANSWER(FALSE, result.missingAT);
  549.     if (! result.value) {
  550.       KMDTrace("Conform", level,
  551.     "%.*soperation %.8s arguments mismatch => false\n", level, SPACES,
  552.     ops1+2);
  553.       ANSWER(FALSE, 0);
  554.     }
  555.     result = allConform(oid1, oid2, res1, res2, level+1);
  556.     if (! result.hasValue) ANSWER(FALSE, result.missingAT);
  557.     if (! result.value) {
  558.       KMDTrace("Conform", level,
  559.     "%.*soperation %.8s results mismatch  => false\n", level, SPACES,
  560.     ops1+2);
  561.       ANSWER(FALSE, 0);
  562.     }
  563.     KMDTrace("Conform", level, "%.*soperation %.8s matches\n", level, SPACES,
  564.       ops1+2);
  565.     ops1 = skipOp(ops1);
  566.     ops2 = skipOp(ops2);
  567.   }
  568.   ANSWER(TRUE, 0);
  569. }
  570.  
  571. char *fetchOID(fOID, fOIDP, p)
  572. OID fOID, *fOIDP;
  573. register char *p;
  574. {
  575.   register OID oid;
  576.   register int c;
  577.   if (*p == 'S') {
  578.     *fOIDP = fOID;
  579.     p++;
  580.   } else {
  581.     assert(*p == 'O');
  582.     p ++;
  583.     oid = 0;
  584.     while (*p != ',' && *p != ']') {
  585.       c = *p++;
  586.       oid <<= 4;
  587.       oid += '0' <= c && c <= '9' ? c - '0' : c - 'a' + 10;
  588.     }
  589.     *fOIDP = oid;
  590.   }
  591.   return(*p == ',' ? p + 1 : p);
  592. }
  593.  
  594. static ConformsResult allConform(oid1, oid2, ps1, ps2, level)
  595. OID oid1, oid2;
  596. register char *ps1, *ps2;
  597. int level;
  598. {
  599.   ConformsResult result;
  600.   OID poid1, poid2;
  601.   assert(*ps1 == '[');
  602.   ps1 ++;
  603.   assert(*ps2 == '[');
  604.   ps2 ++;
  605.   while (*ps1 != ']') {
  606.     ps1 = fetchOID(oid1, &poid1, ps1);
  607.     ps2 = fetchOID(oid2, &poid2, ps2);
  608.     result = i_conforms(poid1, poid2, level+1);
  609.     if (! result.hasValue) ANSWER(FALSE, result.missingAT);
  610.     if (! result.value) ANSWER(FALSE, 0);
  611.   }
  612.   ANSWER(TRUE, 0);
  613. }
  614.  
  615. /*  kernel call*/
  616. void RestrictPtr(dataPtr, abConPtr, restrictPtr)
  617. DataAddr dataPtr;
  618. struct AbCon *abConPtr;
  619. CodePtr restrictPtr;
  620. /* Restrict the object pointed to by dataPtr and abConPtr to restrictPtr */
  621. {
  622.   AVariable                 aVar;
  623.   AbConPtr                  newAbConPtr;
  624.   
  625.   aVar.myAddr               = dataPtr;
  626.   aVar.myAbConPtr           = abConPtr;
  627.   
  628.   KMDTrace("View", 3, "RestrictPtr (0x%04x) Var: %s to %s\n", dataPtr,
  629.       PPVar(&aVar), PPCodePtr(restrictPtr));
  630.   
  631.   if (IsNIL(abConPtr) || IsNIL(dataPtr)) {
  632.     KMDTrace("View", 3, "variable is NIL\n");
  633.     currentSSP->resultBrand = VariableBrand;
  634.     currentSSP->regs.arg1 =
  635.     currentSSP->regs.arg2 = (int) EMNIL;
  636.     return;
  637.   }
  638.   newAbConPtr   = OIDOIDOIDToAbCon(restrictPtr->ownOID, restrictPtr->ownOID,
  639.       abConPtr->CodeOID);
  640.   if (NonNULL(newAbConPtr)) {
  641.       currentSSP->resultBrand   = VariableBrand;
  642.       currentSSP->regs.arg1     = (int) dataPtr;
  643.       currentSSP->regs.arg2     = (int) newAbConPtr;
  644.       KMDTrace("View", 3, "Result: AbCon (0x%04x) Var: %s\n",
  645.  
  646.       PPVar((AVariablePtr) ¤tSSP->regs.arg1));
  647.       return;
  648.   }
  649.   assert(FALSE);
  650.   abort();
  651. }
  652.  
  653.