diff options
| author | kr.angelov <kr.angelov@gmail.com> | 2012-07-31 15:16:04 +0000 |
|---|---|---|
| committer | kr.angelov <kr.angelov@gmail.com> | 2012-07-31 15:16:04 +0000 |
| commit | 83b321d862472f31c0c9f7feca8360ad5bfe8a75 (patch) | |
| tree | 0f0ef20ad78e25b320013c7bb160211a8612d4e9 /src/runtime/c/teyjus/simulator/hopu.c | |
| parent | 314662dd09d5d1480007faa79258b0e93cc2aa59 (diff) | |
An initial import of the teyjus source code in the C runtime for GF. The two runtime are still not connected but the source code compiles.
Diffstat (limited to 'src/runtime/c/teyjus/simulator/hopu.c')
| -rw-r--r-- | src/runtime/c/teyjus/simulator/hopu.c | 1693 |
1 files changed, 1693 insertions, 0 deletions
diff --git a/src/runtime/c/teyjus/simulator/hopu.c b/src/runtime/c/teyjus/simulator/hopu.c new file mode 100644 index 000000000..505eed6df --- /dev/null +++ b/src/runtime/c/teyjus/simulator/hopu.c @@ -0,0 +1,1693 @@ +////////////////////////////////////////////////////////////////////////////// +//Copyright 2008 +// Andrew Gacek, Steven Holte, Gopalan Nadathur, Xiaochu Qi, Zach Snow +////////////////////////////////////////////////////////////////////////////// +// This file is part of Teyjus. // +// // +// Teyjus is free software: you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation, either version 3 of the License, or // +// (at your option) any later version. // +// // +// Teyjus is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with Teyjus. If not, see <http://www.gnu.org/licenses/>. // +////////////////////////////////////////////////////////////////////////////// +/****************************************************************************/ +/* */ +/* File hopu.c. This file contains the main routines implementing the */ +/* interpretive part of higher-order pattern unification. */ +/* */ +/****************************************************************************/ +#ifndef HOPU_C +#define HOPU_C + +#include "hopu.h" +#include "mctypes.h" +#include "dataformats.h" +#include "hnorm.h" +#include "abstmachine.h" +#include "types.h" +#include "trail.h" +#include "../system/error.h" +#include "../system/memory.h" + +#include <stdio.h> + +/* Unify types associated with constants. */ +static void HOPU_typesUnify(DF_TypePtr tyEnv1, DF_TypePtr tyEnv2, int n) +{ + AM_pdlError(2*n); + AM_initTypesPDL(); + TY_pushPairsToPDL((MemPtr)tyEnv1, (MemPtr)tyEnv2, n); + TY_typesUnify(); +} + +/* Return the dereference of the abstraction body of the given term. */ +DF_TermPtr HOPU_lamBody(DF_TermPtr tmPtr) +{ + tmPtr = DF_termDeref(tmPtr); + while (DF_isLam(tmPtr)) tmPtr = DF_termDeref(DF_lamBody(tmPtr)); + return tmPtr; +} + +/***************************************************************************/ +/* Globalize functions needed for HOPU_patternUnidyPair */ +/***************************************************************************/ + +/* Globalize a rigid term. */ +/* If the term pointer is not one referring to a heap address, the atomic */ +/* content is then copied onto the current top of heap; the term pointer */ +/* is updated to the new heap term. */ +static DF_TermPtr HOPU_globalizeRigid(DF_TermPtr rPtr) +{ + if (AM_nHeapAddr((MemPtr)rPtr)) {//rPtr must refer to const (no type), int, + //float, str, (stream), nil, cons + MemPtr nhreg = AM_hreg + DF_TM_ATOMIC_SIZE; + AM_heapError(nhreg); + DF_copyAtomic(rPtr, AM_hreg); + rPtr = (DF_TermPtr)AM_hreg; + AM_hreg = nhreg; + } + return rPtr; +} + +/* Globalize a rigid term and make a variable binding. */ +/* If the term pointer to the rigid term is not one referring to a heap */ +/* address, its atomic content is then copied into the variable to be bound*/ +/* Otherwise, the variable is made a reference to the rigid term. */ +void HOPU_globalizeCopyRigid(DF_TermPtr rPtr, DF_TermPtr vPtr) +{ + if (AM_nHeapAddr((MemPtr)rPtr)) //rPtr must refer to rigid atomic term + DF_copyAtomic(rPtr, (MemPtr)vPtr); + else DF_mkRef((MemPtr)vPtr, rPtr); //rPtr could also be app +} + +/* Globalize a flex term. */ +/* If the term pointer is one referring to a stack address, (in which case */ +/* the flex term must be a free variable itself), the atomic content is */ +/* copied onto the current top of heap; the free variable on stack is then */ +/* bound to the new heap term, and the binding is trailed if necessary; the */ +/* term pointer is updated to the new heap term. */ +DF_TermPtr HOPU_globalizeFlex(DF_TermPtr fPtr) +{ + if (AM_stackAddr((MemPtr)fPtr)) {//fPtr must be a reference to var + MemPtr nhreg = AM_hreg + DF_TM_ATOMIC_SIZE; + AM_heapError(nhreg); + DF_copyAtomic(fPtr, AM_hreg); + TR_trailETerm(fPtr); + DF_mkRef((MemPtr)fPtr, (DF_TermPtr)AM_hreg); + fPtr = (DF_TermPtr)AM_hreg; + AM_hreg = nhreg; + } + return fPtr; +} + +/***************************************************************************/ +/* Explicit eta expansion (on a rigid term) */ +/***************************************************************************/ + +/* Eta expands a rigid term whose term pointer and decomposition are given */ +/* by arguments. The new lambda body is returned. (It is unnecessary to */ +/* create a new lambda term for the abstractions in the front of the eta */ +/* expanded form. Note that the term head and argument vector are updated */ +/* as side-effect. */ +/* Note globalization on the term head is always performed and no */ +/* specialized version of this function is provided based on the assumption*/ +/* that explicit eta-expansion is rarely needed. */ +static DF_TermPtr HOPU_etaExpand(DF_TermPtr *h, DF_TermPtr *args, int nargs, + int nabs) +{ + DF_TermPtr hPtr = *h, oldArgs = *args, rtPtr; + MemPtr suspLoc; //where susps are to be created + int newArity = nargs + nabs; + if (DF_isBV(hPtr)){ //lift index by nabs if the head is a bound variable + int ind = DF_bvIndex(hPtr) + nabs; + AM_embedError(ind); + AM_heapError(AM_hreg + DF_TM_ATOMIC_SIZE); + *h = hPtr =(DF_TermPtr)AM_hreg; //update head pointer + DF_mkBV(AM_hreg,ind); + AM_hreg += DF_TM_ATOMIC_SIZE; + } else + //always perform globalization; eta expansion is rarely needed + *h = hPtr = HOPU_globalizeRigid(hPtr); + + AM_arityError(newArity); + AM_heapError(AM_hreg + nargs * DF_TM_SUSP_SIZE + newArity*DF_TM_ATOMIC_SIZE + + DF_TM_APP_SIZE); + suspLoc = AM_hreg; + AM_hreg += nargs * DF_TM_SUSP_SIZE; //allocate space for nargs suspensions + rtPtr = (DF_TermPtr)AM_hreg; //new application + DF_mkApp(AM_hreg, newArity, hPtr, (DF_TermPtr)(AM_hreg + DF_TM_APP_SIZE)); + AM_hreg += DF_TM_APP_SIZE; + *args = (DF_TermPtr)AM_hreg; //update arg vector pointer + for (; nargs > 0; nargs--){//create suspensions over original arguments + DF_mkSusp(suspLoc, 0, nabs, DF_termDeref(oldArgs), DF_EMPTY_ENV); + DF_mkRef(AM_hreg, (DF_TermPtr)suspLoc); + suspLoc += DF_TM_SUSP_SIZE; AM_hreg += DF_TM_ATOMIC_SIZE; + oldArgs = (DF_TermPtr)(((MemPtr)oldArgs) + DF_TM_ATOMIC_SIZE); + } + for (; nabs > 0; nabs--){//create de Bruijn indices from #nabs to #1 + DF_mkBV(AM_hreg, nabs); + AM_hreg += DF_TM_ATOMIC_SIZE; + } + return rtPtr; +} + +/***************************************************************************/ +/* PATTERN RECOGNITION */ +/* */ +/* Auxiliary functions for recognizing LLambda pattens for flexible terms. */ +/***************************************************************************/ +/* Whether a bound variable occurs in the given arguments. */ +/* It is assumned that the given arguments can only contain bound variables*/ +/* and constants. */ +static Boolean HOPU_uniqueBV(int bvInd, DF_TermPtr args, int n) +{ + DF_TermPtr tPtr; + for ( ; n > 0 ; n-- ){ + tPtr = DF_termDeref(args); + if (DF_isBV(tPtr) && (bvInd == DF_bvIndex(tPtr))) return FALSE; + //otherwise different bv or constant, check the next + args = (DF_TermPtr)(((MemPtr)args) + DF_TM_ATOMIC_SIZE); + } + return TRUE; +} + +/* Whether a constant occurs in the given arguments. */ +/* It is assumned that the given arguments can only contain bound variables*/ +/* and constants. */ +/* CHANGES have to be made here if the semantics of local constants are */ +/* changed with respect to polymorphism. */ +static Boolean HOPU_uniqueConst(DF_TermPtr cPtr, DF_TermPtr args, int n) +{ + DF_TermPtr tPtr; + for ( ; n > 0 ; n--){ + tPtr = DF_termDeref(args); + if (DF_isConst(tPtr) && DF_sameConsts(tPtr, cPtr)) { + if (DF_isTConst(tPtr)) { + EM_TRY { + HOPU_typesUnify(DF_constType(tPtr), DF_constType(cPtr), + AM_cstTyEnvSize(DF_constTabIndex(cPtr))); + } EM_CATCH { + if (EM_CurrentExnType == EM_FAIL) { + AM_resetTypesPDL();//remove tys from pdl for ty unif + return FALSE; + } else EM_RETHROW(); + } + } else return FALSE; + } //otherwise different constant or bv, check the next + args = (DF_TermPtr)(((MemPtr)args) + DF_TM_ATOMIC_SIZE); + } //for loop + return TRUE; +} + +/* Checking whether the argments of the head normal form given by registers*/ +/* AM_argVec, AM_numArgs and AM_numAbs are those of an eta-expanded form. */ +/* Specifically, the arguments are attempted to match de Bruijn indices */ +/* #n ... #1, where n is the current value of AM_numAbs. */ +/* It is assumed that the argument vector is not empty. */ +static Boolean HOPU_isEtaExpArgs() +{ + if (AM_numArgs != AM_numAbs) return FALSE; + else { + int i = AM_numAbs; + Boolean match = TRUE; + DF_TermPtr oneArg = AM_argVec; + DF_TermPtr head = AM_head; + while (match && (i > 0)){ + HN_hnorm(oneArg); + if (AM_numArgs == 0) + match = ((AM_numArgs == 0) && DF_isBV(AM_head) && + (DF_bvIndex(AM_head) == i)); + else + match = (DF_isBV(AM_head) && (DF_bvIndex(AM_head)-AM_numAbs==i) + && HOPU_isEtaExpArgs()); + oneArg = (DF_TermPtr)(((MemPtr)oneArg + DF_TM_ATOMIC_SIZE)); + i--; + } + AM_head = head; + return match; + } +} + +/* Checking whether the arguments of a flexible term satisfy with the */ +/* LLambda pattern with respect to the universe count of its flex head. */ +/* CHANGES have to be made here if the semantics of local constants are */ +/* changed with respect to polymorphism. */ +static Boolean HOPU_isLLambda(int uc, int nargs, DF_TermPtr args) +{ + if (nargs == 0) return TRUE; + else { + int i; + DF_TermPtr myArgs = args; + for (i = 0; i < nargs; i++){ + HN_hnorm(args); + if (AM_numArgs == 0) { + if (AM_numAbs != 0) return FALSE; //abstraction + if (DF_isBV(AM_head)) { //bound variable + if (!HOPU_uniqueBV(DF_bvIndex(AM_head), myArgs, i)) + return FALSE; + } else if (DF_isConst(AM_head)) { //constant + if (!(uc < DF_constUnivCount(AM_head) && + HOPU_uniqueConst(AM_head, myArgs, i))) return FALSE; + } else return FALSE; //other sort of terms + } else { //AM_numArgs != 0 + if (DF_isBV(AM_head)) { //bound variable head + int dbInd = DF_bvIndex(AM_head) - AM_numAbs; //eta-norm + if (dbInd > 0 && HOPU_uniqueBV(dbInd, myArgs, i) && + HOPU_isEtaExpArgs()) { + TR_trailHTerm(args); + DF_mkBV((MemPtr)args, dbInd); + } else return FALSE; + } else { //!(DF_isBV(AM_head)) + if (DF_isConst(AM_head)) { //constant head + if (uc < DF_constUnivCount(AM_head) && + HOPU_uniqueConst(AM_head, myArgs, i) && + HOPU_isEtaExpArgs()) { + TR_trailHTerm(args); + if (DF_isTConst(AM_head)) + DF_mkRef((MemPtr)args, AM_head); + else DF_copyAtomic(AM_head, (MemPtr)args); + } else return FALSE; + } else return FALSE; //other sort of terms + } //!(DF_isBV(AM_head)) + } //AM_numArgs != 0 + args = (DF_TermPtr)(((MemPtr)args) + DF_TM_ATOMIC_SIZE); + } //for loop + return TRUE; + } //nargs != 0 +} + +/***************************************************************************/ +/* BINDING */ +/* */ +/* Attempt to find bindings for free variables (counter part of mksubst in */ +/* the sml pattern unfication code). */ +/***************************************************************************/ +/* A flag denoting whether new structure is created during the process of */ +/* finding substitutions. */ +Boolean HOPU_copyFlagGlb = FALSE; + +/* Return a non-zero index of a bound variable appears in a list of */ +/* arguments. Note the index is the position from the right and the */ +/* embedding level is taken into account. */ +static int HOPU_bvIndex(int dbInd, DF_TermPtr args, int nargs, int lev) +{ + int ind; + dbInd -= lev; + for (ind = nargs; ind > 0; ind--){ + DF_TermPtr tPtr = DF_termDeref(args); + if (DF_isBV(tPtr) && (dbInd == DF_bvIndex(tPtr))) return (ind+lev); + //otherwise try the next + args = (DF_TermPtr)(((MemPtr)args) + DF_TM_ATOMIC_SIZE); + } + return 0; //not found +} + +/* Return a non-zero index if a constant appears in a list of arguments. */ +/* Note the index is the position from the right and the embedding level */ +/* is taken into account. */ +/* CHANGES have to be made here if the semantics of local constants are */ +/* changed with respect to polymorphism. */ +static int HOPU_constIndex(DF_TermPtr cPtr, DF_TermPtr args, int nargs, int lev) +{ + int ind; + for (ind = nargs; ind > 0; ind--){ + DF_TermPtr tPtr = DF_termDeref(args); + if (DF_isConst(tPtr) && DF_sameConsts(tPtr, cPtr)) { + if (DF_isTConst(tPtr)) { + Boolean found = FALSE; + EM_TRY { + HOPU_typesUnify(DF_constType(tPtr), DF_constType(cPtr), + AM_cstTyEnvSize(DF_constTabIndex(cPtr))); + found = TRUE; + } EM_CATCH {//remove types added for ty unif from the PDL + if (EM_CurrentExnType == EM_FAIL) AM_resetTypesPDL(); + else EM_RETHROW(); + } + if (found) return (ind+lev); + } else return (ind+lev); //cPtr does not have type associated + } //otherwise try the next + args = (DF_TermPtr)(((MemPtr)args) + DF_TM_ATOMIC_SIZE); + } + return 0; //not found +} + +/***************************************************************************/ +/* BINDING FOR FLEX-FLEX */ +/* */ +/* Auxiliary functions for solving flex-flex pairs. */ +/* Non-LLambda pairs are delayed onto the disagreement list. */ +/***************************************************************************/ + +/* Collect raising components for internal variable in the LLambda case */ +/* when it is known it has a higher universe index than the outside llambda*/ +/* variable. */ +/* It is assumned that the incoming argument vector has a size larger than */ +/* zero. */ +/* As a result of this process, segments of the argument vectors for both */ +/* variables are decided. That for the internal variable is created on the */ +/* current top of heap, while that for the outside variable, each */ +/* argument of which must be a de Bruijn index, is recorded into an integer*/ +/* array which is set by side-effect. */ +/* The number returned by this procedure is the length of both of the */ +/* argument vector segements. Raising occured when this number is non-zero.*/ +/* CHANGES have to be made here if the semantics of local constants are */ +/* changed with respect to polymorphism. */ +static int HOPU_raise(int varuc, DF_TermPtr args, int nargs, int emblev, + int *args11) +{ + int numRaised = 0; //number of args that have been raised + AM_heapError(AM_hreg + nargs * DF_TM_ATOMIC_SIZE);//max possible size + for (; nargs > 0; nargs--){ + DF_TermPtr tmPtr = DF_termDeref(args); + if (DF_isConst(tmPtr) && (DF_constUnivCount(tmPtr) <= varuc)){ + args11[numRaised] = nargs + emblev; //args11 + if (DF_isTConst(tmPtr)) DF_mkRef(AM_hreg, tmPtr); //args21 + else DF_copyAtomic(tmPtr, AM_hreg); + AM_hreg += DF_TM_ATOMIC_SIZE; + numRaised++; + } + args = (DF_TermPtr)(((MemPtr)args) + DF_TM_ATOMIC_SIZE); + } + return numRaised; +} + + +/* Generate the indices for items not to be pruned when the internal */ +/* variable is known to have a universe index greater than that of the */ +/* external one. */ +/* It is assumned that arg vector of the internal flex term has a size */ +/* larger than zero. */ +/* As a result of this process, segments of the argument vectors for both */ +/* variables are decided. That for the internal variable is created on the */ +/* current top of heap, while that for the outside variable, each */ +/* argument of which must be a de Bruijn index, is recorded into an integer*/ +/* array which is set by side-effect. */ +/* The number returned by this procedure is the length of both of the */ +/* argument vector segements. Pruning occured when this number is smaller */ +/* than the size of the arg vector of the internal term. */ +static int HOPU_prune(DF_TermPtr args1, int nargs1, DF_TermPtr args2, + int nargs2, int emblev, int *args12) +{ + + int numNotPruned = 0; + AM_heapError(AM_hreg + nargs2 * DF_TM_ATOMIC_SIZE);//max possible size + for (; nargs2 > 0; nargs2--){ + DF_TermPtr tmPtr = DF_termDeref(args2); + if (DF_isConst(tmPtr)) { + int ind = HOPU_constIndex(tmPtr, args1, nargs1, emblev); + if (ind > 0) { + args12[numNotPruned] = ind; //args12 + DF_mkBV(AM_hreg, nargs2); //args22 + AM_hreg += DF_TM_ATOMIC_SIZE; + numNotPruned ++; + HOPU_copyFlagGlb = TRUE; + } //ind == 0 the argument is pruned + } else {//bv + int ind = DF_bvIndex(tmPtr); + if (ind > emblev) { + int newind = HOPU_bvIndex(ind, args1, nargs1, emblev); + if (newind > 0) { + args12[numNotPruned] = newind; //args12 + DF_mkBV(AM_hreg, nargs2); //args22 + AM_hreg += DF_TM_ATOMIC_SIZE; + numNotPruned ++; + if (ind != newind) HOPU_copyFlagGlb = TRUE; + } //newind == 0 the argument is pruned + } else {//ind <= lev + args12[numNotPruned] = ind; //args12 + DF_mkBV(AM_hreg, nargs2); //args22 + AM_hreg += DF_TM_ATOMIC_SIZE; + numNotPruned ++; + } + } //bv + args2 = (DF_TermPtr)(((MemPtr)args2) + DF_TM_ATOMIC_SIZE); + } //for loop + return numNotPruned; +} + +/* When the index of the internal variable is less than or equal to that */ +/* of the external one in the LLambda case, we have to raise the outside */ +/* variable over those constants in the internal list that have smaller */ +/* index and we have to prune other constants and bound variables in this */ +/* list that are not shared. */ +/* It is assumned that the arg vector of the internal flex term has a size */ +/* larger than zero. */ +/* As a result of this process, the argument vectors for both variables */ +/* are decided. That for the outside variable is created on the current */ +/* top of heap, while that for the internal variable, each argument of */ +/* which must be a de Bruijn index, is recorded into an integer array which*/ +/* is set by side-effect. */ +/* The number returned by this procedure is the length of both of the */ +/* argument vectors. Pruning occured when this number is smaller than the */ +/* size of the arg vector of the internal term. */ +/* CHANGES have to be made here if the semantics of local constants are */ +/* changed with respect to polymorphism. */ +static int HOPU_pruneAndRaise(DF_TermPtr args1, int nargs1, DF_TermPtr args2, + int nargs2, int emblev, int *args) +{ + int numNotPruned = 0; + AM_heapError(AM_hreg + nargs2 * DF_TM_ATOMIC_SIZE); //max possible size + for (; nargs2 > 0; nargs2 --){ + DF_TermPtr tmPtr = DF_termDeref(args2); + if (DF_isBV(tmPtr)){ + int ind = DF_bvIndex(tmPtr); + if (ind > emblev) { + int newind = HOPU_bvIndex(ind, args1, nargs1, emblev); + if (newind > 0) { + DF_mkBV(AM_hreg, newind); //args for outside var + AM_hreg += DF_TM_ATOMIC_SIZE; + args[numNotPruned] = nargs2; //args for internal var + numNotPruned ++; + if (ind != newind) HOPU_copyFlagGlb = TRUE; + } // newind == 0, the argument is prubed + } else { //ind <= emblev + DF_mkBV(AM_hreg, ind); //args for outside var + AM_hreg += DF_TM_ATOMIC_SIZE; + args[numNotPruned] = nargs2; //args for internal var + numNotPruned ++; + } + } else { //tmPtr is const + if (DF_constUnivCount(tmPtr) > AM_adjreg){ + int ind = HOPU_constIndex(tmPtr, args1, nargs1, emblev); + if (ind > 0) { + DF_mkBV(AM_hreg, ind); //args for outside var + AM_hreg += DF_TM_ATOMIC_SIZE; + args[numNotPruned] = nargs2; //args for internal var + numNotPruned ++; + HOPU_copyFlagGlb = TRUE; + } //else ind = 0, the argument is pruned + } else { //const uc <= AM_adjreg + if (DF_isTConst(tmPtr)) DF_mkRef(AM_hreg, tmPtr);//args out var + else DF_copyAtomic(tmPtr, AM_hreg); + AM_hreg += DF_TM_ATOMIC_SIZE; + args[numNotPruned] = nargs2; //args for internal var + numNotPruned ++; + } + } + args2 = (DF_TermPtr)(((MemPtr)args2) + DF_TM_ATOMIC_SIZE); + } //for loop + return numNotPruned; +} + +/* Generating the arguments of a pruning substitution for the case when */ +/* when trying to unify two flexible terms of the form */ +/* (F a1 ... an) = lam(k, (F b1 ... bm)) */ +/* The resulted argument vector is created on the current top of heap, and */ +/* the integer returned by this procedure is the length of the argument */ +/* vector resulted from pruning. Pruning takes place if this value is */ +/* smaller that nargs2. */ +/* It is assumed that the sum of n and k is the same as m. */ +/* CHANGES have to be made here if the semantics of local constants are */ +/* changed with respect to polymorphism. */ +static int HOPU_pruneSameVar(DF_TermPtr args1, int nargs1, DF_TermPtr args2, + int nargs2, int lev) +{ + if (nargs2 == 0) return 0; + else { + int numNotPruned = 0; + DF_TermPtr tPtr2; + AM_heapError(AM_hreg + nargs2 * DF_TM_ATOMIC_SIZE); //max possible size + nargs1 = nargs2 - nargs1; //reused nargs1 + for (; nargs2 > nargs1; nargs2 --){ + DF_TermPtr tPtr1 = DF_termDeref(args1); + tPtr2 = DF_termDeref(args2); + if (DF_isBV(tPtr1)){ + int ind = DF_bvIndex(tPtr1) + lev; + if (DF_isBV(tPtr2) && (ind == DF_bvIndex(tPtr2))){ + DF_mkBV(AM_hreg, nargs2); AM_hreg += DF_TM_ATOMIC_SIZE; + numNotPruned++; + if (nargs2 != ind) HOPU_copyFlagGlb = TRUE; + } //else this argument is pruned + } else {// tPtr1 is a constant + if (DF_isConst(tPtr2) && DF_sameConsts(tPtr1, tPtr2)){ + if (DF_isTConst(tPtr2)) { + EM_TRY { + HOPU_typesUnify(DF_constType(tPtr1),DF_constType(tPtr2), + AM_cstTyEnvSize(DF_constTabIndex(tPtr1))); + DF_mkBV(AM_hreg, nargs2); AM_hreg += DF_TM_ATOMIC_SIZE; + numNotPruned++; + HOPU_copyFlagGlb = TRUE; + } EM_CATCH {//remove tys for type unif from the PDL + if (EM_CurrentExnType == EM_FAIL) + AM_resetTypesPDL(); + else EM_RETHROW(); + } //EM_catch + } else {//no type association + DF_mkBV(AM_hreg, nargs2); AM_hreg+=DF_TM_ATOMIC_SIZE; + numNotPruned++; + HOPU_copyFlagGlb = TRUE; + } + }//else pruned + } //tPtr1 is a constant + args1 = (DF_TermPtr)(((MemPtr)args1) + DF_TM_ATOMIC_SIZE); + args2 = (DF_TermPtr)(((MemPtr)args2) + DF_TM_ATOMIC_SIZE); + } //for (; nargs2 > nargs1; nargs2--) + for (; nargs2 > 0; nargs2--){ + tPtr2 = DF_termDeref(args2); + if (DF_isBV(tPtr2) && (DF_bvIndex(tPtr2) == nargs2)){ + DF_mkBV(AM_hreg, nargs2); AM_hreg += DF_TM_ATOMIC_SIZE; + numNotPruned++; + } //else pruned + args2 = (DF_TermPtr)(((MemPtr)args2) + DF_TM_ATOMIC_SIZE); + } //for (; nargs2 > 0; nargs2--) + return numNotPruned; + } //nargs2 != 0 +} + +/* Push a new free variable with given universe count onto the current heap */ +/* top. */ +static void HOPU_pushVarToHeap(int uc) +{ + MemPtr newhtop = AM_hreg + DF_TM_ATOMIC_SIZE; + AM_heapError(newhtop); + DF_mkVar(AM_hreg, uc); + AM_hreg = newhtop; +} + +/* Perform substitution to realize pruning and raising for an internal */ +/* variable in the LLambda situation when the variable has an index greater*/ +/* than that of the outside one */ +/* This procedure is also used to perform substitution for flex-flex pairs */ +/* with same variable heads in the LLambda situation. */ +static void HOPU_mkPandRSubst(DF_TermPtr hPtr, DF_TermPtr args, int nargs, + DF_TermPtr vPtr, int nabs) +{ + TR_trailTerm(vPtr); AM_bndFlag = ON; + if (nargs == 0) { + if (nabs == 0) DF_mkRef((MemPtr)vPtr, hPtr); + else DF_mkLam((MemPtr)vPtr, nabs, hPtr); + } else { //nargs > 0 + DF_TermPtr tPtr = (DF_TermPtr)AM_hreg; + AM_heapError(AM_hreg + DF_TM_APP_SIZE); + AM_arityError(nargs); + DF_mkApp(AM_hreg, nargs, hPtr, args); //application body + AM_hreg += DF_TM_APP_SIZE; + AM_embedError(nabs); + if (nabs == 0) DF_mkRef((MemPtr)vPtr, tPtr); + else DF_mkLam((MemPtr)vPtr, nabs, tPtr); + } +} + +/* Perform substitution to realize pruning and raising for an internal */ +/* variable in the LLambda situation when the variable has an index smaller*/ +/* than or equal to that of the outside one */ +/* The arguments of the substitution which should be de Bruijn indices */ +/* are given by an integer array. */ +static void HOPU_mkPrunedSubst(DF_TermPtr hPtr, int *args, int nargs, + DF_TermPtr vPtr, int nabs) +{ + AM_bndFlag = ON; + TR_trailTerm(vPtr); + if (nargs == 0) { + if (nabs == 0) DF_mkRef((MemPtr)vPtr, hPtr); + else DF_mkLam((MemPtr)vPtr, nabs, hPtr); + } else { //nargs > 0; + DF_TermPtr argvec = (DF_TermPtr)AM_hreg, appPtr; + int i; + AM_heapError(AM_hreg + DF_TM_APP_SIZE + nargs * DF_TM_ATOMIC_SIZE); + for (i = 0; i < nargs; i++){//commit bvs in args onto heap + DF_mkBV(AM_hreg, args[i]); + AM_hreg += DF_TM_ATOMIC_SIZE; + } + appPtr = (DF_TermPtr)AM_hreg; + DF_mkApp(AM_hreg, nargs, hPtr, argvec); + AM_hreg += DF_TM_APP_SIZE; + if (nabs == 0) DF_mkRef((MemPtr)vPtr, appPtr); + else DF_mkLam((MemPtr)vPtr, nabs, appPtr); + } +} + +/* Generating the partial structure of a substitution to realize pruning */ +/* and raising for an outside variable in the LLambda situation when the */ +/* variable has an index smaller than that of the internal one. */ +/* The arguments of the susbsitution consists of two segments of de Burijn */ +/* indices, which are given by two integer arrays respectively. */ +static DF_TermPtr HOPU_mkPandRTerm(DF_TermPtr hPtr, int args1[], int nargs1, + int args2[], int nargs2) +{ + if ((nargs1 == 0) && (nargs2 == 0)) return hPtr; + else { + DF_TermPtr args = (DF_TermPtr)AM_hreg, rtPtr; + int nargs = nargs1 + nargs2; //new arity (non-zero) + int i; + AM_arityError(nargs); + AM_heapError(AM_hreg + DF_TM_APP_SIZE + nargs * DF_TM_ATOMIC_SIZE); + for (i = 0; i < nargs1 ; i++){ //commit bvs in a11 onto heap + DF_mkBV(AM_hreg, args1[i]); + AM_hreg += DF_TM_ATOMIC_SIZE; + } + for (i = 0; i < nargs2 ; i++){ //commit bvs in a12 onto heap + DF_mkBV(AM_hreg, args2[i]); + AM_hreg += DF_TM_ATOMIC_SIZE; + } + rtPtr = (DF_TermPtr)AM_hreg; + DF_mkApp(AM_hreg, nargs, hPtr, args); + AM_hreg += DF_TM_APP_SIZE; + return rtPtr; + } +} + +/* Generating the partial structure of a substitution to realize pruning */ +/* and raising for an internal variable in the LLambda situation when the */ +/* variable has an index greater than or equal to that of the outside one. */ +static DF_TermPtr HOPU_mkPrunedTerm(DF_TermPtr hPtr, DF_TermPtr args, int nargs) +{ + if (nargs == 0) return hPtr; + else { + DF_TermPtr rtPtr = (DF_TermPtr)AM_hreg; + AM_heapError(AM_hreg + DF_TM_APP_SIZE); + DF_mkApp(AM_hreg, nargs, hPtr, args); + AM_hreg += DF_TM_APP_SIZE; + return rtPtr; + } +} + +/* Find the (partial) structure of the substitution for a flex head of a */ +/* LLambda term corresponding to an internal flex term which is known to be */ +/* LLambda. The internal free variable is bound to a proper substitution as */ +/* side-effect. +/* The arguments of this procedure are: */ +/* args1 : reference to the argument vector of the outside flex term */ +/* nargs1: number of arguments of the outside flex term */ +/* uc : universe count of the internal free variable */ +/* tPtr2 : refers to the dereference of ABSTRACTION BODY of the internal */ +/* flex term */ +/* fhPtr : refers to the head of the internal flex term */ +/* args2 : refers to the argument vector of the internal flex term */ +/* nargs2: number of arguments of the internal flex term */ +/* lev : the abstraction context of the internal flex term */ +/* Note that the outside free variable and its universe count are assumed to */ +/* be given by the global variables (registers) AM_vbbreg and AM_adjreg. */ +static DF_TermPtr HOPU_flexNestedLLambda(DF_TermPtr args1, int nargs1, int uc, + DF_TermPtr tPtr2, DF_TermPtr fhPtr, DF_TermPtr args2, + int nargs2, int lev) +{ + DF_TermPtr bnd; //(partial) binding for the outside free var + MemPtr oldhtop = AM_hreg; + DF_TermPtr heapArgs = (DF_TermPtr)AM_hreg; + if (AM_adjreg < uc){ + int *args11 = NULL, *args12 = NULL; //hold args of bnd of the outside v + int nargs11 = 0, nargs12 = 0; + if (nargs1 != 0) { + args11 = (int*)EM_malloc(nargs1 * sizeof(int)); + nargs11 = HOPU_raise(uc, args1, nargs1, lev, args11); + } + if (nargs2 != 0) { + args12 = (int*)EM_malloc(nargs2 * sizeof(int)); + nargs12 = HOPU_prune(args1, nargs1, args2, nargs2, lev, args12); + } + if ((nargs11 == 0) && (nargs12 == nargs2)) {//neither raised nor pruned + AM_hreg = oldhtop; //the internal free var remains unbound + TR_trailTerm(fhPtr); AM_bndFlag = ON; + DF_modVarUC(fhPtr, AM_adjreg); + if (HOPU_copyFlagGlb) + bnd = HOPU_mkPandRTerm(fhPtr, args11, nargs11, args12, nargs12); + else bnd = tPtr2; + } else { //raised or pruned + DF_TermPtr newVar = (DF_TermPtr)AM_hreg; + HOPU_pushVarToHeap(AM_adjreg); + HOPU_mkPandRSubst(newVar, heapArgs, nargs11+nargs12, fhPtr, nargs2); + bnd = HOPU_mkPandRTerm(newVar, args11, nargs11, args12, nargs12); + HOPU_copyFlagGlb = TRUE; + } + if (nargs1 != 0) free(args11); if (nargs2 != 0) free(args12); + } else { //AM_adjreg >= uc + int *newargs2 = NULL; + int nnewargs2 = 0; + if (nargs2 != 0) { + newargs2 = (int*)EM_malloc(nargs2 * sizeof(int)); + nnewargs2 = HOPU_pruneAndRaise(args1,nargs1,args2,nargs2,lev, + newargs2); + } + if (nnewargs2 == nargs2){//not pruned + if (HOPU_copyFlagGlb) + bnd = HOPU_mkPrunedTerm(fhPtr, heapArgs, nnewargs2); + else { AM_hreg = oldhtop; bnd = tPtr2; } + } else { //pruned + DF_TermPtr newVar = (DF_TermPtr)AM_hreg; + HOPU_pushVarToHeap(uc); + HOPU_mkPrunedSubst(newVar, newargs2, nnewargs2, fhPtr, nargs2); + bnd = HOPU_mkPrunedTerm(newVar, heapArgs, nnewargs2); + HOPU_copyFlagGlb = TRUE; + } + if (nargs2 != 0) free(newargs2); + } //AM_adjreg >= uc + return bnd; +} + +/* Checking the arguments of a flex (non-LLambda) term to see whetehr a */ +/* free variable same as that currently in the AM_vbbreg register, a free */ +/* variable with higher univ count than that currently in the AM_adjreg */ +/* register, a constant with higher univ count than that currently in */ +/* AM_adjreg, or a de Bruijn index bound by abstractions over the variable */ +/* for which a substitution is being constructed occurs. */ +/* If one of the situations occurs, exception is raised. */ +static void HOPU_flexCheck(DF_TermPtr args, int nargs, int emblev) +{ + for (; nargs > 0; nargs --){ + int nemblev; + HN_hnorm(args); + nemblev = emblev + AM_numAbs; + if (AM_rigFlag){ + if (DF_isBV(AM_head)) { + if (DF_bvIndex(AM_head) > nemblev) EM_THROW(EM_FAIL); + } else { + if (DF_isConst(AM_head)&&(DF_constUnivCount(AM_head)>AM_adjreg)) + EM_THROW(EM_FAIL); + } //otherwise succeeds + } else { //AM_rigFlag == FALSE + if ((AM_vbbreg == AM_head) || (DF_fvUnivCount(AM_head)>AM_adjreg)) + EM_THROW(EM_FAIL); + } + HOPU_flexCheck(AM_argVec, AM_numArgs, nemblev); + args = (DF_TermPtr)(((MemPtr)args) + DF_TM_ATOMIC_SIZE); + } +} + +/* This version of flexCheckC is needed in the compiled form of pattern */ +/* unification. The essential difference from the other version is that the */ +/* variable being bound is already partially bound to a structure. */ +/* The difference from the other procedure is the head normalization */ +/* procedure invoked is one performs the occurs checking on partially bound */ +/* variables */ +static void HOPU_flexCheckC(DF_TermPtr args, int nargs, int emblev) +{ + for (; nargs > 0; nargs--){ + int nemblev; + HN_hnormOcc(args); + nemblev = emblev + AM_numAbs; + if (AM_rigFlag) { + if (DF_isBV(AM_head)) { + if (DF_bvIndex(AM_head) > nemblev) EM_THROW(EM_FAIL); + } else { + if (DF_isConst(AM_head)&&(DF_constUnivCount(AM_head)>AM_adjreg)) + EM_THROW(EM_FAIL); + } //otherwise succeeds + } else //AM_rigFlag == FALSE + if (DF_fvUnivCount(AM_head) > AM_adjreg) EM_THROW(EM_FAIL); + + HOPU_flexCheckC(AM_argVec, AM_numArgs, nemblev); + args = (DF_TermPtr)(((MemPtr)args)+DF_TM_ATOMIC_SIZE); + } +} + +/* Generating a term on the top of heap which is to be added into a */ +/* disagreement pair. */ +/* The term has the following structure: */ +/* (h [|a1, 0, lev, nil|] ... [|an, 0, lev, nil|] #lev ... #1) */ +/* It is assumed that nargs and lev are not equal to zero. */ +static void HOPU_mkTermNLL(DF_TermPtr h, DF_TermPtr args, int nargs, int lev) +{ + int newArity = nargs + lev; + MemPtr newArgs = AM_hreg + DF_TM_APP_SIZE; //spare app (head) size on heap + AM_arityError(newArity); + AM_heapError(AM_hreg + nargs*DF_TM_SUSP_SIZE + newArity*DF_TM_ATOMIC_SIZE + + DF_TM_APP_SIZE); + DF_mkApp(AM_hreg, newArity, h, (DF_TermPtr)newArgs); + AM_hreg += (DF_TM_APP_SIZE + newArity * DF_TM_ATOMIC_SIZE);//alloc arg vec + for (; nargs > 0; nargs--){ //[|ai, 0, lev, nil|], for i <= nargs + DF_mkRef(newArgs, (DF_TermPtr)AM_hreg); + DF_mkSusp(AM_hreg, 0, lev, DF_termDeref(args), DF_EMPTY_ENV); + newArgs += DF_TM_ATOMIC_SIZE; AM_hreg += DF_TM_SUSP_SIZE; + args = (DF_TermPtr)(((MemPtr)args) + DF_TM_ATOMIC_SIZE); + } + for (; lev > 0; lev--){ //#i, for i <= lev + DF_mkBV(newArgs, lev); + newArgs += DF_TM_ATOMIC_SIZE; + } +} + +/* Generating a partial subsitution for the free head of a LLambda term */ +/* corresponding to an internal flex term which is known to be non-LLambda.*/ +/* The partial substitution is of form: */ +/* (h #n ... #1) */ +/* It is assumed that n is not equal to zero. */ +static void HOPU_mkSubstNLL(DF_TermPtr h, int n) +{ + AM_arityError(n); + AM_heapError(AM_hreg + DF_TM_APP_SIZE + n * DF_TM_ATOMIC_SIZE); + DF_mkApp(AM_hreg, n, h, (DF_TermPtr)(AM_hreg + DF_TM_APP_SIZE)); + AM_hreg += DF_TM_APP_SIZE; + for (; n > 0; n--){ + DF_mkBV(AM_hreg, n); + AM_hreg += DF_TM_ATOMIC_SIZE; + } +} + +/* Try to solve G = ...(F a1 ... an)..., where F and G are different free */ +/* variables, and (F a1 ... an) is non-LLambda. */ +/* Either G is bound to (F a1 ... an) or an exception is raised. In the */ +/* latter case, the caller of this function is responsible to add a */ +/* disagreement pair to the live list. */ +static void HOPU_bndVarNestedFlex(DF_TermPtr fhPtr, DF_TermPtr args, int nargs, + int lev) +{ + HOPU_flexCheck(args, nargs, lev); + if (DF_fvUnivCount(fhPtr) > AM_adjreg) { + TR_trailTerm(fhPtr); + AM_bndFlag = ON; + DF_modVarUC(fhPtr, AM_adjreg); + } +} + +/* Try to find the (partial) structure of the substitution for a flex head */ +/* of a LLambda term corresponding to an internal flex term which is not */ +/* known to be LLambda. */ +/* If the internal flex term is LLambda, HOPU_flexNestedLLambda is invoked */ +/* to generate the (parital) substitution for the outside variable, and */ +/* perform proper substitutions on the internal free variable if necessary. */ +/* Otherwise, a disagreement pair is added into the live list. */ +static DF_TermPtr HOPU_flexNestedSubst(DF_TermPtr args1, int nargs1, + DF_TermPtr fhPtr, DF_TermPtr args2, + int nargs2, DF_TermPtr tmPtr, int emblev) +{ + DF_TermPtr bnd; + int varuc = DF_fvUnivCount(fhPtr); + if (HOPU_isLLambda(varuc, nargs2, args2)){ + if (fhPtr == AM_vbbreg) EM_THROW(EM_FAIL); //occurs check + bnd = HOPU_flexNestedLLambda(args1, nargs1, varuc, tmPtr, fhPtr, args2, + nargs2, emblev); + } else {// the internal flex term is not LLambda: delay (opt possible) + DF_TermPtr newVar; + DF_TermPtr newTerm; + Boolean found = FALSE; + if ((fhPtr != AM_vbbreg) && (nargs1 == 0)) { + EM_TRY{ + HOPU_bndVarNestedFlex(fhPtr, args2, nargs2, emblev); + bnd = tmPtr; + found = TRUE; + } EM_CATCH {if (EM_CurrentExnType != EM_FAIL) EM_RETHROW();} + } + if (!found) { + newVar = (DF_TermPtr)AM_hreg; + HOPU_pushVarToHeap(AM_adjreg); + HOPU_copyFlagGlb = TRUE; + if ((nargs1 == 0) && (emblev == 0)) { + bnd = newVar; + AM_addDisPair(bnd, tmPtr); + } else { + newTerm = (DF_TermPtr)AM_hreg; + HOPU_mkTermNLL(newVar, args1, nargs1, emblev); + AM_addDisPair(newTerm, tmPtr); + bnd = (DF_TermPtr)AM_hreg; + HOPU_mkSubstNLL(newVar, emblev + nargs1); + } + } + } + return bnd; +} + +/* This version of flexNestedSubst is needed in the compiled form of pattern */ +/* unification. The essential difference from the other version is that the */ +/* variable being bound is already partially bound to a structure. */ +/* The difference from the other procedure is first the head normalization */ +/* process invokded is one performs occurs checking on partially bound */ +/* variables, and second, the "top-level" flexible term is a free variable: */ +/* so there is no need to distinguish whether the other flex term is Llambda */ +/* or not: the substitution can be found by an invocation of flexCheckC */ +DF_TermPtr HOPU_flexNestedSubstC(DF_TermPtr fhPtr, DF_TermPtr args, int nargs, + DF_TermPtr tmPtr, int emblev) +{ + DF_TermPtr bnd, newVar, newTerm; + int varuc; + Boolean found = FALSE; + + EM_TRY { + HOPU_flexCheckC(args, nargs, emblev); + if (DF_fvUnivCount(fhPtr) > AM_adjreg){ + TR_trailTerm(fhPtr); + AM_bndFlag = ON; + DF_modVarUC(fhPtr, AM_adjreg); + } + bnd = tmPtr; + found = TRUE; + } EM_CATCH { if (EM_CurrentExnType != EM_FAIL) EM_RETHROW(); } + + if (!found) { + varuc = DF_fvUnivCount(fhPtr); + if (HOPU_isLLambda(varuc, nargs, args)){ + bnd = HOPU_flexNestedLLambda(NULL, 0, varuc, tmPtr, fhPtr, args, nargs, + emblev); + } else {//otherwise delay this pair onto the live list + HOPU_copyFlagGlb = TRUE; + newVar = (DF_TermPtr)AM_hreg; + HOPU_pushVarToHeap(AM_adjreg); + if (emblev == 0) { + bnd = newVar; + AM_addDisPair(bnd, tmPtr); + } else { + newTerm = (DF_TermPtr)AM_hreg; + HOPU_mkTermNLL(newVar, NULL, 0, emblev); + AM_addDisPair(newTerm, tmPtr); + bnd = (DF_TermPtr)AM_hreg; + HOPU_mkSubstNLL(newVar, emblev); + } + } + } + return bnd; +} + +/* Try to solve G = (F a1 ... an), where F and G are different free */ +/* variables, and (F a1 ... an) is non-LLambda. */ +/* Either G is bound to (F a1 ... an) or an exception is raised. In the */ +/* latter case, the caller of this function is responsible to add a */ +/* disagreement pair to the live list. */ +static void HOPU_bndVarFlex(DF_TermPtr vPtr, DF_TermPtr fPtr, DF_TermPtr fhPtr, + DF_TermPtr args, int nargs) +{ + AM_vbbreg = vPtr; AM_adjreg = DF_fvUnivCount(vPtr); + HOPU_flexCheck(args, nargs, 0); + if (DF_fvUnivCount(fhPtr) > AM_adjreg) { + TR_trailTerm(fPtr); + AM_bndFlag = ON; + DF_modVarUC(fhPtr, AM_adjreg); + } + TR_trailTerm(vPtr); + AM_bndFlag = ON; + DF_mkRef((MemPtr)vPtr, fPtr); +} + +/* Try to solve (F a1 ... an) = lam(k, (G b1 ... bm)), where F and G are */ +/* both free variables. */ +/* The arguments are: */ +/* tPtr1 : reference to the ABSTRACTION BODY of the first flex term */ +/* h1 : reference to the flex head of the first term */ +/* nargs1: number of arguments of the first flex term */ +/* args1 : reference to the argument vector of the first flex term */ +/* tPtr2 : reference to the ABSTRACTION BODY of the second flex term */ +/* h2 : reference to the flex head of the second flex term */ +/* nargs2: number of arguments of the second flex term */ +/* args2 : reference to the argument vector of the second flex term */ +/* lev : abstraction context of the second term with respect to the */ +/* first one. */ +/* */ +/* Non-Llambda pairs could be encountered during this process, and in */ +/* this situation, the pair is delayed onto the disagreement list. */ +static void HOPU_flexMkSubst(DF_TermPtr tPtr1, DF_TermPtr h1, int nargs1, + DF_TermPtr args1, DF_TermPtr tPtr2, DF_TermPtr h2, + int nargs2, DF_TermPtr args2, int lev) +{ + int uc = DF_fvUnivCount(h1); + if (HOPU_isLLambda(uc, nargs1, args1)){ //the first term is LLambda + DF_TermPtr bndBody; + if (h1 == h2) { //same variable (comparing addresses) + if (HOPU_isLLambda(uc, nargs2, args2)) {//same var common uc + MemPtr oldhtop = AM_hreg; + DF_TermPtr newArgs = (DF_TermPtr)AM_hreg; + HOPU_copyFlagGlb = FALSE; + nargs1 = HOPU_pruneSameVar(args1, nargs1, args2, nargs2, lev); + if ((nargs1 != nargs2) || HOPU_copyFlagGlb){ + DF_TermPtr newVar = (DF_TermPtr)AM_hreg; + HOPU_pushVarToHeap(uc); + HOPU_mkPandRSubst(newVar, newArgs, nargs1, h1, nargs2); + } else AM_hreg = oldhtop; //unbound + } else { //(F a1 ... an)[ll] = (lam(k, (F b1 ... bm)))[non-ll] + if (lev == 0) AM_addDisPair(tPtr1, tPtr2); + else { + MemPtr nhtop = AM_hreg + DF_TM_LAM_SIZE; + DF_TermPtr tmPtr = (DF_TermPtr)AM_hreg; + AM_heapError(AM_hreg); + DF_mkLam(AM_hreg, lev, tPtr2); + AM_hreg = nhtop; + AM_addDisPair(tPtr1, tmPtr); + } //(lev != 0) + } //tPtr2 not LLambda + } else { //different variable + int nabs; + AM_vbbreg = h1; AM_adjreg = uc; //set regs for occ + HOPU_copyFlagGlb = FALSE; + bndBody = HOPU_flexNestedSubst(args1, nargs1, h2, args2, nargs2, + tPtr2, lev); + nabs = lev + nargs1; + TR_trailTerm(h1); AM_bndFlag = ON; + if (nabs == 0) DF_mkRef((MemPtr)h1, bndBody); + else { + AM_embedError(nabs); + DF_mkLam((MemPtr)h1, nabs, bndBody); + } + } //different variable + } else { //the first term is non-LLambda + Boolean found = FALSE; + if ((nargs2 == 0) && (lev == 0) && (h1 != h2)) { // (F t1 ... tm) = G + EM_TRY{ + HOPU_bndVarFlex(h2, tPtr1, h1, args1, nargs1); + found = TRUE; + } EM_CATCH { + if (EM_CurrentExnType != EM_FAIL) EM_RETHROW(); + } + } + if (!found) { + if (lev == 0) AM_addDisPair(tPtr1, tPtr2); + else { + MemPtr nhtop = AM_hreg + DF_TM_LAM_SIZE; + DF_TermPtr tmPtr = (DF_TermPtr)AM_hreg; + AM_heapError(AM_hreg); + DF_mkLam(AM_hreg, lev, tPtr2); + AM_hreg = nhtop; + AM_addDisPair(tPtr1, tmPtr); + } //(lev != 0) + } + } //the first term is non-LLambda +} + +/* The counterpart of HOPU_flexMkSubst invoked from HOPU_patternUnifyPair. */ +/* Care is taken to avoid making a reference to a stack address in binding */ +/* and creating disagreement pairs. */ +/* It is assumed that the first term (F a1 ... an) given by its */ +/* is not embedded in any abstractions. */ +static void HOPU_flexMkSubstGlb(DF_TermPtr tPtr1, DF_TermPtr h1, int nargs1, + DF_TermPtr args1, + DF_TermPtr tPtr2, DF_TermPtr h2, int nargs2, + DF_TermPtr args2, + DF_TermPtr topPtr2, int lev) +{ + int uc = DF_fvUnivCount(h1); + if (HOPU_isLLambda(uc, nargs1, args1)) { //the first term is LLambda + DF_TermPtr bndBody; + if (h1 == h2) { //same variable (comparing addresses) + if (HOPU_isLLambda(uc, nargs2, args2)){//same var; common uc + MemPtr oldhtop = AM_hreg; + DF_TermPtr newArgs = (DF_TermPtr)AM_hreg; + HOPU_copyFlagGlb = FALSE; + nargs1 = HOPU_pruneSameVar(args1, nargs1, args2, nargs2, lev); + if ((nargs1 != nargs2) || HOPU_copyFlagGlb) { + DF_TermPtr newVar = (DF_TermPtr)AM_hreg; + HOPU_pushVarToHeap(uc); + HOPU_mkPandRSubst(newVar, newArgs, nargs1, h1, nargs2); + } else AM_hreg = oldhtop; //variable remain unbound + } else { //(F a1 ... an)[ll] = (lam(k, (F b1 ... bm)))[non-ll] + //non-LLambda term must locate on the heap + if (nargs1 == 0) tPtr1 = HOPU_globalizeFlex(tPtr1); + if (lev == 0) AM_addDisPair(tPtr1, tPtr2); + else AM_addDisPair(tPtr1, DF_termDeref(topPtr2)); + } //tPtr2 not LLambda + } else { //different variable + int nabs; + AM_vbbreg = h1; AM_adjreg = uc; //set regs for occ + HOPU_copyFlagGlb = FALSE; + bndBody = HOPU_flexNestedSubst(args1, nargs1, h2, args2, nargs2, + tPtr2, lev); + nabs = nargs1 + lev; + TR_trailTerm(h1); AM_bndFlag = ON; + if (HOPU_copyFlagGlb == FALSE) + bndBody = HOPU_globalizeFlex(bndBody); + if (nabs == 0) DF_mkRef((MemPtr)h1, bndBody); + else { + AM_embedError(nabs); + DF_mkLam((MemPtr)h1, nabs, bndBody); + } + } + } else {//the first term is non-LLambda (must locate on heap) + Boolean found = FALSE; + if ((nargs2 == 0) && (lev == 0) && (h1 != h2)) {//(F t1...tm)[nll] = G + EM_TRY { + HOPU_bndVarFlex(h2, tPtr1, h1, args1, nargs1); + found = TRUE; + } EM_CATCH { + if (EM_CurrentExnType == EM_FAIL) + tPtr2 = HOPU_globalizeFlex(tPtr2); + else EM_RETHROW(); + } + } + if (!found) { + if (lev == 0) AM_addDisPair(tPtr1, tPtr2); + else AM_addDisPair(tPtr1, DF_termDeref(topPtr2)); + } + } //the first term is non-LLambda +} + + +/***************************************************************************/ +/* BINDING FOR FLEX-RIGID */ +/* */ +/* Auxiliary functions for solving flex-rigid pairs. */ +/* Non-LLambda pairs are delayed onto the disagreement list. */ +/***************************************************************************/ +/* Try to find the (partial) binding of the head of a flex term correponding */ +/* to a rigid atom during the process of unifying the flex term with a */ +/* rigid one. The global variable HOPU_copyFlagGlb is used to indicate */ +/* whether a new term is created during this process. */ +/* Note it is assumed that rPtr refers to the dereference of a rigid atom */ +/* or cons. */ +static DF_TermPtr HOPU_getHead(DF_TermPtr rPtr, DF_TermPtr args, int nargs, + int emblev) +{ + DF_TermPtr rtPtr; + switch(DF_termTag(rPtr)){ + case DF_TM_TAG_CONST:{ + if (DF_constUnivCount(rPtr) > AM_adjreg){ + MemPtr newhtop; + int ind = HOPU_constIndex(rPtr, args, nargs, emblev); + if (ind == 0) EM_THROW(EM_FAIL); //occurs-check + AM_embedError(ind); + newhtop = AM_hreg + DF_TM_ATOMIC_SIZE; + AM_heapError(newhtop); + HOPU_copyFlagGlb = TRUE; //new structure is created + rtPtr = (DF_TermPtr)AM_hreg; //create a db on the heap top + DF_mkBV(AM_hreg, ind); + AM_hreg = newhtop; + } else rtPtr = rPtr; //DF_constUnivCount(rPtr <= AM_adjreg) + break; + } + case DF_TM_TAG_BVAR: { + int dbInd = DF_bvIndex(rPtr); + if (dbInd > emblev){ + int ind = HOPU_bvIndex(dbInd, args, nargs, emblev); + if (ind == 0) EM_THROW(EM_FAIL); //occurs-check + AM_embedError(ind); + if (ind == dbInd) rtPtr = rPtr; //use the old db term + else { //create a db on the heap top + MemPtr newhtop = AM_hreg + DF_TM_ATOMIC_SIZE; + AM_heapError(newhtop); + HOPU_copyFlagGlb = TRUE; //new structure is created + rtPtr = (DF_TermPtr)AM_hreg; + DF_mkBV(AM_hreg, ind); + AM_hreg = newhtop; + } + } else rtPtr = rPtr; //dbInd <= emlev + break; + } + default: { rtPtr = rPtr; break;} //other rigid head: cons,nil,int,fl,str + } //switch + return rtPtr; +} + +/* Create a new cons or app term on the current heap top. */ +static void HOPU_mkConsOrApp(DF_TermPtr tmPtr, DF_TermPtr funcPtr, + DF_TermPtr argvec, int nargs) +{ + MemPtr newhtop; + if (DF_isCons(tmPtr)) { + newhtop = AM_hreg + DF_TM_CONS_SIZE; + AM_heapError(newhtop); + DF_mkCons(AM_hreg, argvec); + } else {// application + newhtop = AM_hreg + DF_TM_APP_SIZE; + AM_heapError(newhtop); + DF_mkApp(AM_hreg, nargs, funcPtr, argvec); + } + AM_hreg = newhtop; +} + +/* Try to find the (partial) binding of the head of a flex term when */ +/* unifying it with a rigid term possible under abstractions. */ +/* The arguments are: */ +/* fargs: reference to the arguments of the flex term */ +/* fnargs: number of arguments of the flex term */ +/* rhPtr: reference to the rigid head */ +/* rPtr: reference to the ABSTRACTION BODY of the rigid term */ +/* rargs: reference to the arguments of the rigid term */ +/* rnargs: number of arguments of the rigid term */ +/* emblev: abstraction context of the rigid term */ +/* The global variable HOPU_copyFlagGlb is used to indicate whether new */ +/* term is created in this process. */ +/* Note that if the rigid term is app or cons, it is first assumed that */ +/* a new argument vector is to be created. However, after all the args in */ +/* the binding are calculated, a checking is made on whether this is */ +/* really necessary. If it is not, the old arg vector is used, and the new */ +/* one is abandoned. (Heap space for it is deallocated.) */ +/* It is assumed that the flexible head and its universe count are */ +/* in registers AM_vbbreg and AM_adjreg. */ +static DF_TermPtr HOPU_rigNestedSubst(DF_TermPtr fargs, int fnargs, + DF_TermPtr rhPtr, DF_TermPtr rPtr, + DF_TermPtr rargs, int rnargs, int emblev) +{ + rhPtr = HOPU_getHead(rhPtr, fargs, fnargs, emblev); //head of the binding + if (rnargs == 0) return rhPtr; //the rigid term is atomic + else { //the rigid term is cons or app + Boolean myCopyFlagHead = HOPU_copyFlagGlb, myCopyFlagArgs = FALSE; + int i; + MemPtr oldHreg = AM_hreg; //the old heap top + MemPtr argLoc = AM_hreg; //arg vector location + DF_TermPtr newArgs = (DF_TermPtr)AM_hreg; //new argument vector + DF_TermPtr oldArgs = rargs; //old argument vector + AM_heapError(AM_hreg + rnargs * DF_TM_ATOMIC_SIZE); + AM_hreg += rnargs * DF_TM_ATOMIC_SIZE; //allocate space for argvec + HOPU_copyFlagGlb = FALSE; + for (i = 0; i < rnargs; i++){ + DF_TermPtr bnd; + int nabs; + MemPtr tmpHreg = AM_hreg; + HN_hnorm(rargs); nabs = AM_numAbs; //dereference of hnf + if (AM_hreg != tmpHreg) {myCopyFlagArgs = TRUE; } + + if (AM_rigFlag){ + bnd = HOPU_rigNestedSubst(fargs, fnargs, AM_head, + HOPU_lamBody(rargs), AM_argVec, AM_numArgs, nabs+emblev); + } else { //AM_rigFlag = FALSE + bnd = HOPU_flexNestedSubst(fargs, fnargs, AM_head, AM_argVec, + AM_numArgs, HOPU_lamBody(rargs), nabs+emblev); + } + if (nabs == 0) DF_mkRef(argLoc, bnd); //compact atomic?? + else DF_mkLam(argLoc, nabs, bnd); + argLoc += DF_TM_ATOMIC_SIZE; //note: abs has atomic size + if (HOPU_copyFlagGlb) {myCopyFlagArgs=TRUE; HOPU_copyFlagGlb=FALSE;} + rargs = (DF_TermPtr)(((MemPtr)rargs)+DF_TM_ATOMIC_SIZE); //next arg + } //for loop + if (myCopyFlagArgs) { + DF_TermPtr tmPtr = (DF_TermPtr)AM_hreg; //new cons or app + HOPU_mkConsOrApp(rPtr, rhPtr, newArgs, rnargs); + HOPU_copyFlagGlb = TRUE; + return tmPtr; + } else { //myCopyFlagBody == FALSE + AM_hreg = oldHreg; //deallocate space for the argument vector + //note no new terms are created form any argument + if (myCopyFlagHead){ + DF_TermPtr tmPtr = (DF_TermPtr)AM_hreg; //new cons or app + HOPU_mkConsOrApp(rPtr, rhPtr, oldArgs, rnargs); + HOPU_copyFlagGlb = TRUE; + return tmPtr; + } else return rPtr; //myCopyFlagHead==FALSE, myCopyFlagArgs==FALSE + } + }//rnargs > 0 +} + +/* This version of rigNestedSubstC is needed in the compiled form of pattern */ +/* unification. The essential difference from the other version is that the */ +/* variable being bound is already partially bound to a structure. */ +/* The difference from the other procedure is first the head normalization */ +/* procedure invoked is one performs the occurs checking on partially bound */ +/* variables, and second, the incoming flexible term is in fact a free */ +/* variable. */ +DF_TermPtr HOPU_rigNestedSubstC(DF_TermPtr rhPtr, DF_TermPtr rPtr, + DF_TermPtr rargs, int rnargs, int emblev) +{ + rhPtr = HOPU_getHead(rhPtr, NULL, 0, emblev); + if (rnargs == 0) return rhPtr; + else { + Boolean myCopyFlagHead = HOPU_copyFlagGlb, myCopyFlagArgs = FALSE; + int i; + MemPtr oldHreg = AM_hreg; //the old heap top + MemPtr argLoc = AM_hreg; //arg vector location + DF_TermPtr newArgs = (DF_TermPtr)AM_hreg; //new arg vector + DF_TermPtr oldArgs = rargs; //old arg vector + AM_heapError(AM_hreg + rnargs * DF_TM_ATOMIC_SIZE); + AM_hreg += rnargs * DF_TM_ATOMIC_SIZE; //alloc space for new args + HOPU_copyFlagGlb = FALSE; + for (i = 0; i < rnargs; i++) { + DF_TermPtr bnd; + int nabs; + MemPtr tmpHreg = AM_hreg; + HN_hnormOcc(rargs); nabs = AM_numAbs; + if (tmpHreg != AM_hreg) {myCopyFlagArgs = TRUE; } + if (AM_rigFlag) + bnd = HOPU_rigNestedSubstC(AM_head, HOPU_lamBody(rargs), + AM_argVec, AM_numArgs, nabs+emblev); + else //AM_rigFlag == FALSE + bnd = HOPU_flexNestedSubstC(AM_head, AM_argVec, AM_numArgs, + HOPU_lamBody(rargs), nabs+emblev); + + if (nabs == 0) DF_mkRef(argLoc, bnd); + else DF_mkLam(argLoc, nabs, bnd); + + argLoc += DF_TM_ATOMIC_SIZE; + if (HOPU_copyFlagGlb) {myCopyFlagArgs=TRUE; HOPU_copyFlagGlb=FALSE;} + rargs = (DF_TermPtr)(((MemPtr)rargs)+DF_TM_ATOMIC_SIZE); + } //for loop + if (myCopyFlagArgs) { + DF_TermPtr tmPtr = (DF_TermPtr)AM_hreg; //new cons or app + HOPU_mkConsOrApp(rPtr, rhPtr, newArgs, rnargs); + HOPU_copyFlagGlb = TRUE; + return tmPtr; + } else { //myCopyFlagArgs == FALSE + AM_hreg = oldHreg;//deallocate space for arg vector + if (myCopyFlagHead) { + DF_TermPtr tmPtr = (DF_TermPtr)AM_hreg; + HOPU_mkConsOrApp(rPtr, rhPtr, oldArgs, rnargs); + HOPU_copyFlagGlb = TRUE; + return tmPtr; + } else return rPtr; ////myCopyFlagHead==FALSE, myCopyFlagArgs==FALSE + } + }//rnargs > 0 +} + +/* Try to solve (F a1 ... an) = lam(k, (r b1 ... bm)), where r is rigid. */ +/* The arguments are: */ +/* fPtr : reference to the ABSTRACTION BODY of the flex term */ +/* fhPtr : reference to the flex head */ +/* fnargs: number of arguments of the flex term */ +/* fargs : reference to the argument vector of the flex term */ +/* rPtr : reference to the ABSTRACTION BODY of the rigid term */ +/* rhPtr : reference to the rigid head (Note it could be cons) */ +/* rnargs: number of arguments of the rigid term */ +/* rargs : reference to the argument vector of the rigid term */ +/* */ +/* Non-Llambda pairs could be encountered during this process, and in */ +/* this situation, the pair is delayed onto the disagreement list. */ +static void HOPU_rigMkSubst(DF_TermPtr fPtr, DF_TermPtr fhPtr, int fnargs, + DF_TermPtr fargs, DF_TermPtr rPtr, DF_TermPtr rhPtr, + int rnargs, DF_TermPtr rargs, int emblev) +{ + int uc = DF_fvUnivCount(fhPtr); + if (HOPU_isLLambda(uc, fnargs, fargs)){//Llambda pattern + DF_TermPtr bndBody; //abs body of bnd of the fv + int nabs; + + AM_vbbreg = fhPtr; AM_adjreg = uc; //set regs for occurs check + HOPU_copyFlagGlb = FALSE; + bndBody = HOPU_rigNestedSubst(fargs, fnargs, rhPtr, rPtr, + rargs, rnargs, emblev); + nabs = emblev + fnargs; //# abs in the front of the binding + TR_trailTerm(fhPtr); AM_bndFlag = ON; + if (nabs == 0) DF_mkRef((MemPtr)fhPtr, bndBody); + else { + AM_embedError(nabs); + DF_mkLam((MemPtr)fhPtr, nabs, bndBody); + } + } else { //non-Llambda pattern + if (emblev == 0) AM_addDisPair(fPtr, rPtr); + else { + MemPtr nhtop = AM_hreg + DF_TM_LAM_SIZE; + DF_TermPtr tmPtr = (DF_TermPtr)AM_hreg; + AM_heapError(AM_hreg); + DF_mkLam(AM_hreg, emblev, rPtr); + AM_hreg = nhtop; + AM_addDisPair(fPtr, tmPtr); + } // (emblev != 0) + } //non-LLambda pattern +} + +/* The counter part of HOPU_rigMkSubst invoked by HOPU_patternUnifyPair. */ +/* Care is taken to avoid making a reference to a register/stack address in */ +/* binding and creating disagreement pair. */ +/* It is assumed that the pair of terms are not embedded in any abstractions*/ +/* ie. (F a1 ... an) = (r b1 ... bm) */ +/* Note both fPtr and rPtr are not dereferenced. */ +static void HOPU_rigMkSubstGlb(DF_TermPtr fPtr, DF_TermPtr fhPtr, int fnargs, + DF_TermPtr fargs, + DF_TermPtr rPtr, DF_TermPtr rhPtr, int rnargs, + DF_TermPtr rargs) +{ + int uc = DF_fvUnivCount(fhPtr); + if (HOPU_isLLambda(uc, fnargs, fargs)) { //LLambda pattern + DF_TermPtr bndBody; + AM_vbbreg = fhPtr; AM_adjreg = uc; + HOPU_copyFlagGlb = FALSE; + bndBody = HOPU_rigNestedSubst(fargs, fnargs, rhPtr, DF_termDeref(rPtr), + rargs, rnargs, 0); + TR_trailTerm(fhPtr); AM_bndFlag = ON; + if (HOPU_copyFlagGlb) {//bndBody must locate on the heap + if (fnargs == 0) DF_mkRef((MemPtr)fhPtr, bndBody); + else { + AM_embedError(fnargs); + DF_mkLam((MemPtr)fhPtr, fnargs, bndBody); + } + } else { //HOPU_copyFlagGlb == FALSE + /* //note: rPtr is the undereferenced rigid term; in this case, + // it is assumed rPtr cannot be a reference to the stack. + // This assumption should be ensured by the fact that atomic + // rigid terms on stack are alway copied into registers in + // binding. + if (fnargs == 0) DF_copyAtomic(rPtr, (MemPtr)fhPtr); */ + if (fnargs == 0) HOPU_globalizeCopyRigid(bndBody, fhPtr); + else { + bndBody = HOPU_globalizeRigid(bndBody); + AM_embedError(fnargs); + DF_mkLam((MemPtr)fhPtr, fnargs, bndBody); + } + } //HOPU_copyFlagGlb == FALSE + } else //non_LLambda flex (must locate on the heap) + AM_addDisPair(DF_termDeref(fPtr), + HOPU_globalizeRigid(DF_termDeref(rPtr))); +} + +/***************************************************************************/ +/* TERM SIMPLIFICATION (RIGID-RIGID) */ +/* */ +/* Auxiliary functions for solving rigid-rigid pairs. */ +/***************************************************************************/ + +/* Matching heads of two rigid terms. Eta-expansion is considered when */ +/* necessary. It is assumed that the heads have been dereferenced. */ +static void HOPU_matchHeads(DF_TermPtr hPtr1, DF_TermPtr hPtr2, int nabs) +{ + switch(DF_termTag(hPtr1)){ + case DF_TM_TAG_CONST:{ + if (!(DF_isConst(hPtr2) && (DF_sameConsts(hPtr1, hPtr2)))) + EM_THROW(EM_FAIL); + if (DF_isTConst(hPtr1)){ //(first-order) unify type environments + HOPU_typesUnify(DF_constType(hPtr1), DF_constType(hPtr2), + AM_cstTyEnvSize(DF_constTabIndex(hPtr1))); + } + break; + } + case DF_TM_TAG_BVAR: { + if (!DF_isBV(hPtr2)) EM_THROW(EM_FAIL); + else { + int ind = DF_bvIndex(hPtr2) + nabs; //lifting for eta-expansion + AM_embedError(ind); + if (DF_bvIndex(hPtr1) != ind) EM_THROW(EM_FAIL); + } + break; + } + case DF_TM_TAG_NIL: { if (!DF_isNil(hPtr2)) EM_THROW(EM_FAIL); break;} + case DF_TM_TAG_INT: { + if (!(DF_isInt(hPtr2) && (DF_intValue(hPtr2) == DF_intValue(hPtr1)))) + EM_THROW(EM_FAIL); + break; + } + case DF_TM_TAG_FLOAT:{ + if (!(DF_isFloat(hPtr2)&&(DF_floatValue(hPtr2)==DF_floatValue(hPtr1)))) + EM_THROW(EM_FAIL); + break; + } + case DF_TM_TAG_STR: { + if (!(DF_isStr(hPtr2) && (DF_sameStrs(hPtr1, hPtr2)))) + EM_THROW(EM_FAIL); + break; + } + case DF_TM_TAG_CONS: { + if (!(DF_isCons(hPtr2))) EM_THROW(EM_FAIL); + break; + } + } //switch +} + +/* Set up PDL by sub problems resulted from rigid-rigid pairs upon */ +/* successful matching of their heads. Eta-expansion is performed on-a-fly */ +/* when necessary. */ +void HOPU_setPDL(MemPtr args1, MemPtr args2, int nargs, int nabs) +{ + if (nabs == 0){ //no need for eta-expansion + AM_pdlError(nargs * 2); + for (; nargs > 0; nargs --){ + AM_pushPDL(args1); args1 += DF_TM_ATOMIC_SIZE; + AM_pushPDL(args2); args2 += DF_TM_ATOMIC_SIZE; + } + } else { //nabs > 0 (eta-expansion) + AM_pdlError((nargs + nabs) * 2); + AM_heapError(AM_hreg + nargs*DF_TM_SUSP_SIZE + nabs*DF_TM_ATOMIC_SIZE); + for (; nargs > 0; nargs --){ //[|ai, 0, nabs, nil|] + AM_pushPDL(args1); AM_pushPDL(AM_hreg); + DF_mkSusp(AM_hreg, 0, nabs, DF_termDeref((DF_TermPtr)args2), + DF_EMPTY_ENV); + AM_hreg += DF_TM_SUSP_SIZE; + args1 += DF_TM_ATOMIC_SIZE; args2 += DF_TM_ATOMIC_SIZE; + } + for (; nabs > 0; nabs --){ // bv(i) + AM_pushPDL(args1); AM_pushPDL(AM_hreg); + DF_mkBV(AM_hreg, nabs); + args1 += DF_TM_ATOMIC_SIZE; AM_hreg += DF_TM_ATOMIC_SIZE; + } + } +} + +/***************************************************************************/ +/* HIGHER_ORDER PATTERN UNIFICATION */ +/* */ +/* The main routines of this file. */ +/***************************************************************************/ +/* Perform higher-order pattern unification over the pairs delayed on the */ +/* PDL stack. The PDL stack is empty upon successful termination of this */ +/* procedure. */ +void HOPU_patternUnifyPDL() +{ + DF_TermPtr tPtr1, tPtr2, //pointers to terms to be unified + hPtr, //pointer to head of hnf + args; //arg vec of hnf + Flag rig, cons; //rigid flag and cons flags + int nabs, nargs; //binder length and # of arguments of hnf + while (AM_nemptyPDL()){ + //retrieve the pair of terms on the current top of PDL + tPtr1 = (DF_TermPtr)AM_popPDL(); tPtr2 = (DF_TermPtr)AM_popPDL(); + HN_hnorm(tPtr1); //hnorm tPtr1 + hPtr = AM_head; args = AM_argVec; nabs = AM_numAbs; nargs = AM_numArgs; + rig = AM_rigFlag; //bookkeeping relevant info of hnf of tPtr1 + HN_hnorm(tPtr2); //hnorm tPtr2 + if (rig){ + if (AM_rigFlag){// rigid - rigid + if (nabs > AM_numAbs) { + nabs = nabs - AM_numAbs; //reuse nabs + HOPU_matchHeads(hPtr, AM_head, nabs); + HOPU_setPDL((MemPtr)args,(MemPtr)AM_argVec,AM_numArgs,nabs); + } else { //nabs <= AM_numAbs + nabs = AM_numAbs - nabs; //reuse nabs + HOPU_matchHeads(AM_head, hPtr, nabs); + HOPU_setPDL((MemPtr)AM_argVec, (MemPtr)args, nargs, nabs); + } + } else { // rigid - flex + DF_TermPtr rigBody = HOPU_lamBody(tPtr1); + DF_TermPtr flexBody = HOPU_lamBody(tPtr2); + if (nabs < AM_numAbs) { //eta expand rigid term first + nabs = AM_numAbs - nabs; //reuse nabs + rigBody = HOPU_etaExpand(&hPtr, &args, nargs, nabs); + HOPU_rigMkSubst(flexBody, AM_head, AM_numArgs, AM_argVec, + rigBody, hPtr, (nargs+nabs), args, 0); + } else HOPU_rigMkSubst(flexBody,AM_head, AM_numArgs, AM_argVec, + rigBody,hPtr,nargs,args,nabs-AM_numAbs); + } // rigid-flex + } else { //(rig == FALSE) + DF_TermPtr absBody1 = HOPU_lamBody(tPtr1); + DF_TermPtr absBody2 = HOPU_lamBody(tPtr2); + if (AM_rigFlag){// flex - rigid + if (AM_numAbs < nabs) { //eta expand rigid term first + nabs = nabs - AM_numAbs; //reuse nabs + absBody2 = HOPU_etaExpand(&AM_head, &AM_argVec, AM_numArgs, + nabs); + HOPU_rigMkSubst(absBody1, hPtr, nargs, args, absBody2, + AM_head, AM_numArgs+nabs, AM_argVec, 0); + }else HOPU_rigMkSubst(absBody1,hPtr,nargs,args,absBody2,AM_head, + AM_numArgs,AM_argVec,AM_numAbs-nabs); + } else { // flex - flex + if (AM_numAbs > nabs) + HOPU_flexMkSubst(absBody1, hPtr, nargs, args, absBody2, + AM_head, AM_numArgs, AM_argVec, + AM_numAbs-nabs); + else HOPU_flexMkSubst(absBody2, AM_head, AM_numArgs, AM_argVec, + absBody1,hPtr,nargs,args,nabs-AM_numAbs); + } // flex - flex + } //(rig == FALSE) + } // while (AM_nemptyPDL()) +} + +/* Interpretively pattern unify first the pairs delayed on the PDL, then */ +/* those delayed on the live list, if binding occured during the first step */ +/* or previous compiled unification process. */ +/* Upon successful termination, PDL should be empty and pairs left on the */ +/* live list should be those other than LLambda. */ +void HOPU_patternUnify() +{ + HOPU_patternUnifyPDL(); //first solve those left from compiled unification + while (AM_bndFlag && AM_nempLiveList()){ + DF_DisPairPtr dset = AM_llreg; + do { //move everything in live list to PDL + AM_pdlError(2); + AM_pushPDL((MemPtr)DF_disPairSecondTerm(dset)); + AM_pushPDL((MemPtr)DF_disPairFirstTerm(dset)); + dset = DF_disPairNext(dset); + } while (DF_isNEmpDisSet(dset)); + AM_bndFlag = OFF; + AM_llreg = DF_EMPTY_DIS_SET; + HOPU_patternUnifyPDL(); //unsolvable pairs are added to live list + } +} + +/* Interpretively pattern unify a pair of terms given as parameters. This is*/ +/* the counter part of HOPU_patterUnifyPDL that is invoked from the compiled*/ +/* part of unification. In this situation, the procedure has to be applied */ +/* to two terms as opposed to pairs delayed on the PDL stack. */ +/* */ +/* The input term pointers may dereference to register and stack addresses */ +/* Care must be taken to avoid making a reference to a register (stack) */ +/* address in binding a variable, and in making a disagreement pair. */ + +void HOPU_patternUnifyPair(DF_TermPtr tPtr1, DF_TermPtr tPtr2) +{ + DF_TermPtr h1Ptr, h2Ptr, args1, args2; + Flag rig1, rig2, cons1, cons2; + int nabs1, nabs2, nargs1, nargs2; + MemPtr oldPdlBot = AM_pdlBot; + + AM_pdlBot = AM_pdlTop; + HN_hnorm(tPtr1); h1Ptr = AM_head; args1 = AM_argVec; + nabs1 = AM_numAbs; nargs1 = AM_numArgs; rig1 = AM_rigFlag; + HN_hnorm(tPtr2); h2Ptr = AM_head; args2 = AM_argVec; + nabs2 = AM_numAbs; nargs2 = AM_numArgs; rig2 = AM_rigFlag; + + + if (rig1) { + if (rig2) { //rigid-rigid + if (nabs1 > nabs2) { + nabs1 = nabs1 - nabs2; + HOPU_matchHeads(h1Ptr, h2Ptr, nabs1); + HOPU_setPDL((MemPtr)args1, (MemPtr)args2, nargs2, nabs1); + } else {//nabs1 <= nabs2 + nabs1 = nabs2 - nabs1; + HOPU_matchHeads(h2Ptr, h1Ptr, nabs1); + HOPU_setPDL((MemPtr)args2, (MemPtr)args1, nargs1, nabs1); + } + } else { //rigid-flex + if ((nabs1 == 0) && (nabs2 == 0)) + HOPU_rigMkSubstGlb(tPtr2, h2Ptr, nargs2, args2, + tPtr1, h1Ptr, nargs1, args1); + else { + DF_TermPtr rigBody = HOPU_lamBody(tPtr1); + DF_TermPtr flexBody = HOPU_lamBody(tPtr2); + if (nabs1 < nabs2) { + nabs1 = nabs2 - nabs1; + rigBody = HOPU_etaExpand(&h1Ptr, &args1, nargs1, nabs1); + //now rigBody must locate on heap + HOPU_rigMkSubst(flexBody, h2Ptr, nargs2, args2, rigBody, + h1Ptr, nargs1+nabs1, args1, 0); + } else // (nabs1 >= nabs2) + HOPU_rigMkSubst(flexBody, h2Ptr, nargs2, args2, rigBody, + h1Ptr, nargs1, args1, nabs1-nabs2); + } // !(nabs1 == nabs2 == 0) + } //rigid-flex + } else { // rig1 = FALSE + if (rig2) { //flex-rigid + if ((nabs2 == 0) && (nabs1 == 0)) + HOPU_rigMkSubstGlb(tPtr1, h1Ptr, nargs1, args1, + tPtr2, h2Ptr, nargs2, args2); + else { //!(nabs1 == nabs2 == 0) + DF_TermPtr rigBody = HOPU_lamBody(tPtr2); + DF_TermPtr flexBody = HOPU_lamBody(tPtr1); + if (nabs2 < nabs1) { + nabs1 = nabs2 - nabs1; + rigBody = HOPU_etaExpand(&h2Ptr, &args2, nargs2, nabs1); + //now rigBody must locate on heap + HOPU_rigMkSubst(flexBody, h1Ptr, nargs1, args1, rigBody, + h2Ptr, nargs2+nabs1, args2, 0); + } else //(nabs2 >= nabs1) + HOPU_rigMkSubst(flexBody, h1Ptr, nargs1, args1, rigBody, + h2Ptr, nargs2, args2, nabs2-nabs1); + } //!(nabs1 == nabs2 == 0) + } else { //flex-flex + if (nabs1 == 0) //nabs2 >= nabs1 + HOPU_flexMkSubstGlb(DF_termDeref(tPtr1), h1Ptr, nargs1, args1, + HOPU_lamBody(tPtr2), h2Ptr, nargs2, args2, + tPtr2, nabs2); + else { //(nabs1 > 0) + if (nabs2 == 0) //nabs2 < nabs1 + HOPU_flexMkSubstGlb(DF_termDeref(tPtr2),h2Ptr,nargs2,args2, + HOPU_lamBody(tPtr1),h1Ptr,nargs1,args1, + tPtr1,nabs1); + + else { //nabs1 != 0 && nabs2 != 0 + DF_TermPtr flexBody1 = HOPU_lamBody(tPtr1); + DF_TermPtr flexBody2 = HOPU_lamBody(tPtr2); + if (nabs2 > nabs1) + HOPU_flexMkSubst(flexBody1, h1Ptr, nargs1, args1, + flexBody2, h2Ptr, nargs2, args2, + nabs2-nabs1); + else //nabs2 <= nabs1 + HOPU_flexMkSubst(flexBody2, h2Ptr, nargs2, args2, + flexBody1, h1Ptr, nargs1, args1, + nabs1-nabs2); + } //nabs1 != 0 && nabs2 != 0 + } //(nabs1 > 0) + } //flex-flex + } //rig1 = FALSE + //solve the pairs (which must locate on heap) remaining on the PDL + HOPU_patternUnifyPDL(); + AM_pdlBot = oldPdlBot; +} + +#endif //HOPU_C |
