globle struct lhsParseNode *GetExpressionVarConstraints( struct lhsParseNode *theExpression) { struct lhsParseNode *list1 = NULL, *list2; for (; theExpression != NULL; theExpression = theExpression->bottom) { if (theExpression->right != NULL) { list2 = GetExpressionVarConstraints(theExpression->right); list1 = AddToVariableConstraints(list2,list1); } if (theExpression->type == SF_VARIABLE) { list2 = GetLHSParseNode(); if (theExpression->referringNode != NULL) { list2->type = theExpression->referringNode->type; } else { list2->type = SF_VARIABLE; } list2->value = theExpression->value; list2->derivedConstraints = TRUE; list2->constraints = CopyConstraintRecord(theExpression->constraints); list1 = AddToVariableConstraints(list2,list1); } } return(list1); }
globle struct constraintRecord *CopyConstraintRecord( void *theEnv, EXEC_STATUS, CONSTRAINT_RECORD *sourceConstraint) { CONSTRAINT_RECORD *theConstraint; if (sourceConstraint == NULL) return(NULL); theConstraint = get_struct(theEnv,execStatus,constraintRecord); theConstraint->anyAllowed = sourceConstraint->anyAllowed; theConstraint->symbolsAllowed = sourceConstraint->symbolsAllowed; theConstraint->stringsAllowed = sourceConstraint->stringsAllowed; theConstraint->floatsAllowed = sourceConstraint->floatsAllowed; theConstraint->integersAllowed = sourceConstraint->integersAllowed; theConstraint->instanceNamesAllowed = sourceConstraint->instanceNamesAllowed; theConstraint->instanceAddressesAllowed = sourceConstraint->instanceAddressesAllowed; theConstraint->externalAddressesAllowed = sourceConstraint->externalAddressesAllowed; theConstraint->voidAllowed = sourceConstraint->voidAllowed; theConstraint->multifieldsAllowed = sourceConstraint->multifieldsAllowed; theConstraint->singlefieldsAllowed = sourceConstraint->singlefieldsAllowed; theConstraint->factAddressesAllowed = sourceConstraint->factAddressesAllowed; theConstraint->anyRestriction = sourceConstraint->anyRestriction; theConstraint->symbolRestriction = sourceConstraint->symbolRestriction; theConstraint->stringRestriction = sourceConstraint->stringRestriction; theConstraint->floatRestriction = sourceConstraint->floatRestriction; theConstraint->integerRestriction = sourceConstraint->integerRestriction; theConstraint->classRestriction = sourceConstraint->classRestriction; theConstraint->instanceNameRestriction = sourceConstraint->instanceNameRestriction; theConstraint->classList = CopyExpression(theEnv,execStatus,sourceConstraint->classList); theConstraint->restrictionList = CopyExpression(theEnv,execStatus,sourceConstraint->restrictionList); theConstraint->minValue = CopyExpression(theEnv,execStatus,sourceConstraint->minValue); theConstraint->maxValue = CopyExpression(theEnv,execStatus,sourceConstraint->maxValue); theConstraint->minFields = CopyExpression(theEnv,execStatus,sourceConstraint->minFields); theConstraint->maxFields = CopyExpression(theEnv,execStatus,sourceConstraint->maxFields); theConstraint->bucket = -1; theConstraint->count = 0; theConstraint->multifield = CopyConstraintRecord(theEnv,execStatus,sourceConstraint->multifield); theConstraint->next = NULL; return(theConstraint); }
struct lhsParseNode *RestrictionParse( char *readSource, struct token *theToken, int multifieldSlot, struct symbolHashNode *theSlot, int slotNumber, CONSTRAINT_RECORD *theConstraints, int position) { struct lhsParseNode *topNode = NULL, *lastNode = NULL, *nextNode; int numberOfSingleFields = 0; int numberOfMultifields = 0; int startPosition = position; int error = FALSE; CONSTRAINT_RECORD *tempConstraints; /*==================================================*/ /* Keep parsing fields until a right parenthesis is */ /* encountered. This will either indicate the end */ /* of an instance or deftemplate slot or the end of */ /* an ordered fact. */ /*==================================================*/ while (theToken->type != RPAREN) { /*========================================*/ /* Look for either a single or multifield */ /* wildcard or a conjuctive restriction. */ /*========================================*/ if ((theToken->type == SF_WILDCARD) || (theToken->type == MF_WILDCARD)) { nextNode = GetLHSParseNode(); nextNode->type = theToken->type; nextNode->negated = FALSE; GetToken(readSource,theToken); } else { nextNode = ConjuctiveRestrictionParse(readSource,theToken,&error); if (nextNode == NULL) { ReturnLHSParseNodes(topNode); return(NULL); } } /*========================================================*/ /* Fix up the pretty print representation of a multifield */ /* slot so that the fields don't run together. */ /*========================================================*/ if ((theToken->type != RPAREN) && (multifieldSlot == TRUE)) { PPBackup(); SavePPBuffer(" "); SavePPBuffer(theToken->printForm); } /*========================================*/ /* Keep track of the number of single and */ /* multifield restrictions encountered. */ /*========================================*/ if ((nextNode->type == SF_WILDCARD) || (nextNode->type == SF_VARIABLE)) { numberOfSingleFields++; } else { numberOfMultifields++; } /*===================================*/ /* Assign the slot name and indices. */ /*===================================*/ nextNode->slot = theSlot; nextNode->slotNumber = slotNumber; nextNode->index = position++; /*==============================================*/ /* If we're not dealing with a multifield slot, */ /* attach the constraints directly to the node */ /* and return. */ /*==============================================*/ if (! multifieldSlot) { if (theConstraints == NULL) { if (nextNode->type == SF_VARIABLE) { nextNode->constraints = GetConstraintRecord(); } else nextNode->constraints = NULL; } else nextNode->constraints = theConstraints; return(nextNode); } /*====================================================*/ /* Attach the restriction to the list of restrictions */ /* already parsed for this slot or ordered fact. */ /*====================================================*/ if (lastNode == NULL) topNode = nextNode; else lastNode->right = nextNode; lastNode = nextNode; } /*=====================================================*/ /* Once we're through parsing, check to make sure that */ /* a single field slot was given a restriction. If the */ /* following test fails, then we know we're dealing */ /* with a multifield slot. */ /*=====================================================*/ if ((topNode == NULL) && (! multifieldSlot)) { SyntaxErrorMessage("defrule"); return(NULL); } /*===============================================*/ /* Loop through each of the restrictions in the */ /* list of restrictions for the multifield slot. */ /*===============================================*/ for (nextNode = topNode; nextNode != NULL; nextNode = nextNode->right) { /*===================================================*/ /* Assign a constraint record to each constraint. If */ /* the slot has an explicit constraint, then copy */ /* this and store it with the constraint. Otherwise, */ /* create a constraint record for a single field */ /* constraint and skip the constraint modifications */ /* for a multifield constraint. */ /*===================================================*/ if (theConstraints == NULL) { if (nextNode->type == SF_VARIABLE) { nextNode->constraints = GetConstraintRecord(); } else { continue; } } else { nextNode->constraints = CopyConstraintRecord(theConstraints); } /*==========================================*/ /* Remove the min and max field constraints */ /* for the entire slot from the constraint */ /* record for this single constraint. */ /*==========================================*/ ReturnExpression(nextNode->constraints->minFields); ReturnExpression(nextNode->constraints->maxFields); nextNode->constraints->minFields = GenConstant(SYMBOL,NegativeInfinity); nextNode->constraints->maxFields = GenConstant(SYMBOL,PositiveInfinity); nextNode->derivedConstraints = TRUE; /*====================================================*/ /* If we're not dealing with a multifield constraint, */ /* then no further modifications are needed to the */ /* min and max constraints for this constraint. */ /*====================================================*/ if ((nextNode->type != MF_WILDCARD) && (nextNode->type != MF_VARIABLE)) { continue; } /*==========================================================*/ /* Create a separate constraint record to keep track of the */ /* cardinality information for this multifield constraint. */ /*==========================================================*/ tempConstraints = GetConstraintRecord(); SetConstraintType(MULTIFIELD,tempConstraints); tempConstraints->singlefieldsAllowed = FALSE; tempConstraints->multifield = nextNode->constraints; nextNode->constraints = tempConstraints; /*=====================================================*/ /* Adjust the min and max field values for this single */ /* multifield constraint based on the min and max */ /* fields for the entire slot and the number of single */ /* field values contained in the slot. */ /*=====================================================*/ if (theConstraints->maxFields->value != PositiveInfinity) { ReturnExpression(tempConstraints->maxFields); tempConstraints->maxFields = GenConstant(INTEGER,AddLong(ValueToLong(theConstraints->maxFields->value) - numberOfSingleFields)); } if ((numberOfMultifields == 1) && (theConstraints->minFields->value != NegativeInfinity)) { ReturnExpression(tempConstraints->minFields); tempConstraints->minFields = GenConstant(INTEGER,AddLong(ValueToLong(theConstraints->minFields->value) - numberOfSingleFields)); } } /*================================================*/ /* If a multifield slot is being parsed, place a */ /* node on top of the list of constraints parsed. */ /*================================================*/ if (multifieldSlot) { nextNode = GetLHSParseNode(); nextNode->type = MF_WILDCARD; nextNode->multifieldSlot = TRUE; nextNode->bottom = topNode; nextNode->slot = theSlot; nextNode->slotNumber = slotNumber; nextNode->index = startPosition; nextNode->constraints = theConstraints; topNode = nextNode; TallyFieldTypes(topNode->bottom); } /*=================================*/ /* Return the list of constraints. */ /*=================================*/ return(topNode); }
static BOOLEAN CheckArgumentForConstraintError( struct expr *expressionList, struct expr *lastOne, int i, struct FunctionDefinition *theFunction, struct lhsParseNode *theLHS) { int theRestriction; CONSTRAINT_RECORD *constraint1, *constraint2, *constraint3, *constraint4; struct lhsParseNode *theVariable; struct expr *tmpPtr; int rv = FALSE; /*=============================================================*/ /* Skip anything that isn't a variable or isn't an argument to */ /* a user defined function (i.e. deffunctions and generic have */ /* no constraint information so they aren't checked). */ /*=============================================================*/ if ((expressionList->type != SF_VARIABLE) || (theFunction == NULL)) { return (rv); } /*===========================================*/ /* Get the restrictions for the argument and */ /* convert them to a constraint record. */ /*===========================================*/ theRestriction = GetNthRestriction(theFunction,i); constraint1 = ArgumentTypeToConstraintRecord(theRestriction); /*================================================*/ /* Look for the constraint record associated with */ /* binding the variable in the LHS of the rule. */ /*================================================*/ theVariable = FindVariable((SYMBOL_HN *) expressionList->value,theLHS); if (theVariable != NULL) { if (theVariable->type == MF_VARIABLE) { constraint2 = GetConstraintRecord(); SetConstraintType(MULTIFIELD,constraint2); } else if (theVariable->constraints == NULL) { constraint2 = GetConstraintRecord(); } else { constraint2 = CopyConstraintRecord(theVariable->constraints); } } else { constraint2 = NULL; } /*================================================*/ /* Look for the constraint record associated with */ /* binding the variable on the RHS of the rule. */ /*================================================*/ constraint3 = FindBindConstraints((SYMBOL_HN *) expressionList->value); /*====================================================*/ /* Union the LHS and RHS variable binding constraints */ /* (the variable must satisfy one or the other). */ /*====================================================*/ constraint3 = UnionConstraints(constraint3,constraint2); /*====================================================*/ /* Intersect the LHS/RHS variable binding constraints */ /* with the function argument restriction constraints */ /* (the variable must satisfy both). */ /*====================================================*/ constraint4 = IntersectConstraints(constraint3,constraint1); /*====================================*/ /* Check for unmatchable constraints. */ /*====================================*/ if (UnmatchableConstraint(constraint4) && GetStaticConstraintChecking()) { PrintErrorID("RULECSTR",3,TRUE); PrintRouter(WERROR,"Previous variable bindings of ?"); PrintRouter(WERROR,ValueToString((SYMBOL_HN *) expressionList->value)); PrintRouter(WERROR," caused the type restrictions"); PrintRouter(WERROR,"\nfor argument #"); PrintLongInteger(WERROR,(long int) i); PrintRouter(WERROR," of the expression "); tmpPtr = lastOne->nextArg; lastOne->nextArg = NULL; PrintExpression(WERROR,lastOne); lastOne->nextArg = tmpPtr; PrintRouter(WERROR,"\nfound in the rule's RHS to be violated.\n"); rv = TRUE; } /*===========================================*/ /* Free the temporarily created constraints. */ /*===========================================*/ RemoveConstraint(constraint1); RemoveConstraint(constraint2); RemoveConstraint(constraint3); RemoveConstraint(constraint4); /*========================================*/ /* Return TRUE if unmatchable constraints */ /* were detected, otherwise FALSE. */ /*========================================*/ return(rv); }
static BOOLEAN MultifieldCardinalityViolation( struct lhsParseNode *theNode) { struct lhsParseNode *tmpNode; struct expr *tmpMax; long minFields = 0; long maxFields = 0; int posInfinity = FALSE; CONSTRAINT_RECORD *newConstraint, *tempConstraint; /*================================*/ /* A single field slot can't have */ /* a cardinality violation. */ /*================================*/ if (theNode->multifieldSlot == FALSE) return(FALSE); /*=============================================*/ /* Determine the minimum and maximum number of */ /* fields the slot could contain based on the */ /* slot constraints found in the pattern. */ /*=============================================*/ for (tmpNode = theNode->bottom; tmpNode != NULL; tmpNode = tmpNode->right) { /*====================================================*/ /* A single field variable increases both the minimum */ /* and maximum number of fields by one. */ /*====================================================*/ if ((tmpNode->type == SF_VARIABLE) || (tmpNode->type == SF_WILDCARD)) { minFields++; maxFields++; } /*=================================================*/ /* Otherwise a multifield wildcard or variable has */ /* been encountered. If it is constrained then use */ /* minimum and maximum number of fields constraint */ /* associated with this LHS node. */ /*=================================================*/ else if (tmpNode->constraints != NULL) { /*=======================================*/ /* The lowest minimum of all the min/max */ /* pairs will be the first in the list. */ /*=======================================*/ if (tmpNode->constraints->minFields->value != NegativeInfinity) { minFields += ValueToLong(tmpNode->constraints->minFields->value); } /*=========================================*/ /* The greatest maximum of all the min/max */ /* pairs will be the last in the list. */ /*=========================================*/ tmpMax = tmpNode->constraints->maxFields; while (tmpMax->nextArg != NULL) tmpMax = tmpMax->nextArg; if (tmpMax->value == PositiveInfinity) { posInfinity = TRUE; } else { maxFields += ValueToLong(tmpMax->value); } } /*================================================*/ /* Otherwise an unconstrained multifield wildcard */ /* or variable increases the maximum number of */ /* fields to positive infinity. */ /*================================================*/ else { posInfinity = TRUE; } } /*==================================================================*/ /* Create a constraint record for the cardinality of the sum of the */ /* cardinalities of the restrictions inside the multifield slot. */ /*==================================================================*/ if (theNode->constraints == NULL) tempConstraint = GetConstraintRecord(); else tempConstraint = CopyConstraintRecord(theNode->constraints); ReturnExpression(tempConstraint->minFields); ReturnExpression(tempConstraint->maxFields); tempConstraint->minFields = GenConstant(INTEGER,AddLong((long) minFields)); if (posInfinity) tempConstraint->maxFields = GenConstant(SYMBOL,PositiveInfinity); else tempConstraint->maxFields = GenConstant(INTEGER,AddLong((long) maxFields)); /*================================================================*/ /* Determine the final cardinality for the multifield slot by */ /* intersecting the cardinality sum of the restrictions within */ /* the multifield slot with the original cardinality of the slot. */ /*================================================================*/ newConstraint = IntersectConstraints(theNode->constraints,tempConstraint); if (theNode->derivedConstraints) RemoveConstraint(theNode->constraints); RemoveConstraint(tempConstraint); theNode->constraints = newConstraint; theNode->derivedConstraints = TRUE; /*===================================================================*/ /* Determine if the final cardinality for the slot can be satisfied. */ /*===================================================================*/ if (GetStaticConstraintChecking() == FALSE) return(FALSE); if (UnmatchableConstraint(newConstraint)) return(TRUE); return(FALSE); }
globle struct constraintRecord *IntersectConstraints( void *theEnv, CONSTRAINT_RECORD *c1, CONSTRAINT_RECORD *c2) { struct constraintRecord *rv; int c1Changed = FALSE, c2Changed = FALSE; /*=================================================*/ /* If both constraint records are NULL,then create */ /* a constraint record that allows any value. */ /*=================================================*/ if ((c1 == NULL) && (c2 == NULL)) { rv = GetConstraintRecord(theEnv); rv->multifieldsAllowed = TRUE; return(rv); } /*=================================================*/ /* If one of the constraint records is NULL, then */ /* the intersection is the other constraint record */ /* (a NULL value means no constraints). */ /*=================================================*/ if (c1 == NULL) return(CopyConstraintRecord(theEnv,c2)); if (c2 == NULL) return(CopyConstraintRecord(theEnv,c1)); /*=================================*/ /* Create a new constraint record. */ /*=================================*/ rv = GetConstraintRecord(theEnv); /*==============================*/ /* Intersect the allowed types. */ /*==============================*/ if ((c1->multifieldsAllowed != c2->multifieldsAllowed) && (c1->singlefieldsAllowed != c2->singlefieldsAllowed)) { rv->anyAllowed = FALSE; return(rv); } if (c1->multifieldsAllowed && c2->multifieldsAllowed) { rv->multifieldsAllowed = TRUE; } else { rv->multifieldsAllowed = FALSE; } if (c1->singlefieldsAllowed && c2->singlefieldsAllowed) { rv->singlefieldsAllowed = TRUE; } else { rv->singlefieldsAllowed = FALSE; } if (c1->anyAllowed && c2->anyAllowed) rv->anyAllowed = TRUE; else { if (c1->anyAllowed) { c1Changed = TRUE; SetAnyAllowedFlags(c1,FALSE); } else if (c2->anyAllowed) { c2Changed = TRUE; SetAnyAllowedFlags(c2,FALSE); } rv->anyAllowed = FALSE; rv->symbolsAllowed = (c1->symbolsAllowed && c2->symbolsAllowed); rv->stringsAllowed = (c1->stringsAllowed && c2->stringsAllowed); rv->floatsAllowed = (c1->floatsAllowed && c2->floatsAllowed); rv->integersAllowed = (c1->integersAllowed && c2->integersAllowed); rv->instanceNamesAllowed = (c1->instanceNamesAllowed && c2->instanceNamesAllowed); rv->instanceAddressesAllowed = (c1->instanceAddressesAllowed && c2->instanceAddressesAllowed); rv->externalAddressesAllowed = (c1->externalAddressesAllowed && c2->externalAddressesAllowed); rv->voidAllowed = (c1->voidAllowed && c2->voidAllowed); rv->multifieldsAllowed = (c1->multifieldsAllowed && c2->multifieldsAllowed); rv->factAddressesAllowed = (c1->factAddressesAllowed && c2->factAddressesAllowed); #if FUZZY_DEFTEMPLATES rv->fuzzyValuesAllowed = (c1->fuzzyValuesAllowed && c2->fuzzyValuesAllowed); #endif if (c1Changed) SetAnyAllowedFlags(c1,TRUE); if (c2Changed) SetAnyAllowedFlags(c2,TRUE); } /*=====================================*/ /* Intersect the allowed-values flags. */ /*=====================================*/ if (c1->anyRestriction || c2->anyRestriction) rv->anyRestriction = TRUE; else { rv->anyRestriction = FALSE; rv->symbolRestriction = (c1->symbolRestriction || c2->symbolRestriction); rv->stringRestriction = (c1->stringRestriction || c2->stringRestriction); rv->floatRestriction = (c1->floatRestriction || c2->floatRestriction); rv->integerRestriction = (c1->integerRestriction || c2->integerRestriction); rv->classRestriction = (c1->classRestriction || c2->classRestriction); rv->instanceNameRestriction = (c1->instanceNameRestriction || c2->instanceNameRestriction); #if FUZZY_DEFTEMPLATES rv->fuzzyValueRestriction = (c1->fuzzyValueRestriction || c2->fuzzyValueRestriction); #endif } /*==================================================*/ /* Intersect the allowed values list, allowed class */ /* list, min and max values, and the range values. */ /*==================================================*/ IntersectAllowedValueExpressions(theEnv,c1,c2,rv); IntersectAllowedClassExpressions(theEnv,c1,c2,rv); IntersectNumericExpressions(theEnv,c1,c2,rv,TRUE); IntersectNumericExpressions(theEnv,c1,c2,rv,FALSE); /*==========================================*/ /* Update the allowed-values flags based on */ /* the previous intersection for allowed, */ /* min and max, and range values. */ /*==========================================*/ UpdateRestrictionFlags(rv); /*============================================*/ /* If multifields are allowed, then intersect */ /* the constraint record for them. */ /*============================================*/ if (rv->multifieldsAllowed) { rv->multifield = IntersectConstraints(theEnv,c1->multifield,c2->multifield); if (UnmatchableConstraint(rv->multifield)) { rv->multifieldsAllowed = FALSE; } } /*========================*/ /* Return the intersected */ /* constraint record. */ /*========================*/ return(rv); }
globle struct constraintRecord *UnionConstraints( void *theEnv, CONSTRAINT_RECORD *c1, CONSTRAINT_RECORD *c2) { struct constraintRecord *rv; int c1Changed = FALSE, c2Changed = FALSE; /*=================================================*/ /* If both constraint records are NULL,then create */ /* a constraint record that allows any value. */ /*=================================================*/ if ((c1 == NULL) && (c2 == NULL)) return(GetConstraintRecord(theEnv)); /*=====================================================*/ /* If one of the constraint records is NULL, then the */ /* union is the other constraint record. Note that */ /* this is different from the way that intersections */ /* were handled (a NULL constraint record implied that */ /* any value was legal which in turn would imply that */ /* the union would allow any value as well). */ /*=====================================================*/ if (c1 == NULL) return(CopyConstraintRecord(theEnv,c2)); if (c2 == NULL) return(CopyConstraintRecord(theEnv,c1)); /*=================================*/ /* Create a new constraint record. */ /*=================================*/ rv = GetConstraintRecord(theEnv); /*==========================*/ /* Union the allowed types. */ /*==========================*/ if (c1->multifieldsAllowed || c2->multifieldsAllowed) { rv->multifieldsAllowed = TRUE; } if (c1->singlefieldsAllowed || c2->singlefieldsAllowed) { rv->singlefieldsAllowed = TRUE; } if (c1->anyAllowed || c2->anyAllowed) rv->anyAllowed = TRUE; else { rv->anyAllowed = FALSE; rv->symbolsAllowed = (c1->symbolsAllowed || c2->symbolsAllowed); rv->stringsAllowed = (c1->stringsAllowed || c2->stringsAllowed); rv->floatsAllowed = (c1->floatsAllowed || c2->floatsAllowed); rv->integersAllowed = (c1->integersAllowed || c2->integersAllowed); rv->instanceNamesAllowed = (c1->instanceNamesAllowed || c2->instanceNamesAllowed); rv->instanceAddressesAllowed = (c1->instanceAddressesAllowed || c2->instanceAddressesAllowed); rv->externalAddressesAllowed = (c1->externalAddressesAllowed || c2->externalAddressesAllowed); rv->voidAllowed = (c1->voidAllowed || c2->voidAllowed); rv->factAddressesAllowed = (c1->factAddressesAllowed || c2->factAddressesAllowed); #if FUZZY_DEFTEMPLATES rv->fuzzyValuesAllowed = (c1->fuzzyValuesAllowed || c2->factAddressesAllowed); #endif } /*=================================*/ /* Union the allowed-values flags. */ /*=================================*/ if (c1->anyRestriction && c2->anyRestriction) rv->anyRestriction = TRUE; else { if (c1->anyRestriction) { c1Changed = TRUE; SetAnyRestrictionFlags(c1,FALSE); } else if (c2->anyRestriction) { c2Changed = TRUE; SetAnyRestrictionFlags(c2,FALSE); } rv->anyRestriction = FALSE; rv->symbolRestriction = (c1->symbolRestriction && c2->symbolRestriction); rv->stringRestriction = (c1->stringRestriction && c2->stringRestriction); rv->floatRestriction = (c1->floatRestriction && c2->floatRestriction); rv->integerRestriction = (c1->integerRestriction && c2->integerRestriction); rv->classRestriction = (c1->classRestriction && c2->classRestriction); rv->instanceNameRestriction = (c1->instanceNameRestriction && c2->instanceNameRestriction); #if FUZZY_DEFTEMPLATES rv->fuzzyValueRestriction = (c1->fuzzyValueRestriction && c2->fuzzyValueRestriction); #endif if (c1Changed) SetAnyRestrictionFlags(c1,FALSE); else if (c2Changed) SetAnyRestrictionFlags(c2,FALSE); } /*========================================*/ /* Union the allowed values list, the min */ /* and max values, and the range values. */ /*========================================*/ UnionAllowedValueExpressions(theEnv,c1,c2,rv); UnionAllowedClassExpressions(theEnv,c1,c2,rv); UnionNumericExpressions(theEnv,c1,c2,rv,TRUE); UnionNumericExpressions(theEnv,c1,c2,rv,FALSE); /*========================================*/ /* If multifields are allowed, then union */ /* the constraint record for them. */ /*========================================*/ if (rv->multifieldsAllowed) { rv->multifield = UnionConstraints(theEnv,c1->multifield,c2->multifield); } /*====================*/ /* Return the unioned */ /* constraint record. */ /*====================*/ return(rv); }