static struct lhsParseNode *UnionVariableConstraints( struct lhsParseNode *list1, struct lhsParseNode *list2) { struct lhsParseNode *list3 = NULL, *trace, *temp; /*===================================*/ /* Loop through all of the variables */ /* in the first list. */ /*===================================*/ while (list1 != NULL) { /*=============================================*/ /* Search for the variable in the second list. */ /*=============================================*/ for (trace = list2; trace != NULL; trace = trace->right) { /*============================================*/ /* If the variable is found in both lists, */ /* union the constraints and add the variable */ /* to the new list being constructed. */ /*============================================*/ if (list1->value == trace->value) { temp = GetLHSParseNode(); temp->derivedConstraints = TRUE; temp->value = list1->value; temp->constraints = UnionConstraints(list1->constraints,trace->constraints); temp->right = list3; list3 = temp; break; } } /*==============================*/ /* Move on to the next variable */ /* in the first list. */ /*==============================*/ temp = list1->right; list1->right = NULL; ReturnLHSParseNodes(list1); list1 = temp; } /*====================================*/ /* Free the items in the second list. */ /*====================================*/ ReturnLHSParseNodes(list2); /*======================*/ /* Return the new list. */ /*======================*/ return(list3); }
static int AddBindName( void *theEnv, SYMBOL_HN *variableName, CONSTRAINT_RECORD *theConstraint) { CONSTRAINT_RECORD *tmpConstraint; struct BindInfo *currentBind, *lastBind; int theIndex = 1; /*=========================================================*/ /* Look for the variable name in the list of bind variable */ /* names already parsed. If it is found, then return the */ /* index to the variable and union the new constraint */ /* information with the old constraint information. */ /*=========================================================*/ lastBind = NULL; currentBind = ProcedureParserData(theEnv)->ListOfParsedBindNames; while (currentBind != NULL) { if (currentBind->name == variableName) { if (theConstraint != NULL) { tmpConstraint = currentBind->constraints; currentBind->constraints = UnionConstraints(theEnv,theConstraint,currentBind->constraints); RemoveConstraint(theEnv,tmpConstraint); RemoveConstraint(theEnv,theConstraint); } return(theIndex); } lastBind = currentBind; currentBind = currentBind->next; theIndex++; } /*===============================================================*/ /* If the variable name wasn't found, then add it to the list of */ /* variable names and store the constraint information with it. */ /*===============================================================*/ currentBind = get_struct(theEnv,BindInfo); currentBind->name = variableName; currentBind->constraints = theConstraint; currentBind->next = NULL; if (lastBind == NULL) ProcedureParserData(theEnv)->ListOfParsedBindNames = currentBind; else lastBind->next = currentBind; return(theIndex); }
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); }
globle BOOLEAN ProcessConnectedConstraints( struct lhsParseNode *theNode, struct lhsParseNode *multifieldHeader, struct lhsParseNode *patternHead) { struct constraintRecord *orConstraints = NULL, *andConstraints; struct constraintRecord *tmpConstraints, *rvConstraints; struct lhsParseNode *orNode, *andNode; struct expr *tmpExpr; /*============================================*/ /* Loop through all of the or (|) constraints */ /* found in the connected constraint. */ /*============================================*/ for (orNode = theNode->bottom; orNode != NULL; orNode = orNode->bottom) { /*=================================================*/ /* Intersect all of the &'ed constraints together. */ /*=================================================*/ andConstraints = NULL; for (andNode = orNode; andNode != NULL; andNode = andNode->right) { if (! andNode->negated) { if (andNode->type == RETURN_VALUE_CONSTRAINT) { if (andNode->expression->type == FCALL) { rvConstraints = FunctionCallToConstraintRecord(andNode->expression->value); tmpConstraints = andConstraints; andConstraints = IntersectConstraints(andConstraints,rvConstraints); RemoveConstraint(tmpConstraints); RemoveConstraint(rvConstraints); } } else if (ConstantType(andNode->type)) { tmpExpr = GenConstant(andNode->type,andNode->value); rvConstraints = ExpressionToConstraintRecord(tmpExpr); tmpConstraints = andConstraints; andConstraints = IntersectConstraints(andConstraints,rvConstraints); RemoveConstraint(tmpConstraints); RemoveConstraint(rvConstraints); ReturnExpression(tmpExpr); } else if (andNode->constraints != NULL) { tmpConstraints = andConstraints; andConstraints = IntersectConstraints(andConstraints,andNode->constraints); RemoveConstraint(tmpConstraints); } } } /*===========================================================*/ /* Intersect the &'ed constraints with the slot constraints. */ /*===========================================================*/ tmpConstraints = andConstraints; andConstraints = IntersectConstraints(andConstraints,theNode->constraints); RemoveConstraint(tmpConstraints); /*===============================================================*/ /* Remove any negated constants from the list of allowed values. */ /*===============================================================*/ for (andNode = orNode; andNode != NULL; andNode = andNode->right) { if ((andNode->negated) && ConstantType(andNode->type)) { RemoveConstantFromConstraint(andNode->type,andNode->value,andConstraints); } } /*=======================================================*/ /* Union the &'ed constraints with the |'ed constraints. */ /*=======================================================*/ tmpConstraints = orConstraints; orConstraints = UnionConstraints(orConstraints,andConstraints); RemoveConstraint(tmpConstraints); RemoveConstraint(andConstraints); } /*===============================================*/ /* Replace the constraints for the slot with the */ /* constraints derived from the connected */ /* constraints (which should be a subset. */ /*===============================================*/ if (orConstraints != NULL) { if (theNode->derivedConstraints) RemoveConstraint(theNode->constraints); theNode->constraints = orConstraints; theNode->derivedConstraints = TRUE; } /*==================================*/ /* Check for constraint violations. */ /*==================================*/ if (CheckForUnmatchableConstraints(theNode,(int) patternHead->whichCE)) { return(TRUE); } /*=========================================*/ /* If the constraints are for a multifield */ /* slot, check for cardinality violations. */ /*=========================================*/ if ((multifieldHeader != NULL) && (theNode->right == NULL)) { if (MultifieldCardinalityViolation(multifieldHeader)) { ConstraintViolationErrorMessage("The group of restrictions", NULL,FALSE, (int) patternHead->whichCE, multifieldHeader->slot, multifieldHeader->index, CARDINALITY_VIOLATION, multifieldHeader->constraints,TRUE); return(TRUE); } } /*=======================================*/ /* Return FALSE indicating no constraint */ /* violations were detected. */ /*=======================================*/ return(FALSE); }
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); }