globle int CheckArgumentAgainstRestriction( struct expr *theExpression, int theRestriction) { CONSTRAINT_RECORD *cr1, *cr2, *cr3; /*=============================================*/ /* Generate a constraint record for the actual */ /* argument passed to the function. */ /*=============================================*/ cr1 = ExpressionToConstraintRecord(theExpression); /*================================================*/ /* Generate a constraint record based on the type */ /* of argument expected by the function. */ /*================================================*/ cr2 = ArgumentTypeToConstraintRecord(theRestriction); /*===============================================*/ /* Intersect the two constraint records and then */ /* discard them. */ /*===============================================*/ cr3 = IntersectConstraints(cr1,cr2); RemoveConstraint(cr1); RemoveConstraint(cr2); /*====================================================*/ /* If the intersection of the two constraint records */ /* is empty, then the argument passed to the function */ /* doesn't satisfy the restrictions for the argument. */ /*====================================================*/ if (UnmatchableConstraint(cr3)) { RemoveConstraint(cr3); return(TRUE); } /*===================================================*/ /* The argument satisfies the function restrictions. */ /*===================================================*/ RemoveConstraint(cr3); return(FALSE); }
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 struct lhsParseNode *AddToVariableConstraints( struct lhsParseNode *oldList, struct lhsParseNode *newItems) { CONSTRAINT_RECORD *newConstraints; struct lhsParseNode *temp, *trace; /*=================================================*/ /* Loop through each of the new constraints adding */ /* it to the list if it's not already present or */ /* modifying the constraint if it is. */ /*=================================================*/ while (newItems != NULL) { /*==========================================*/ /* Get the next item since the next pointer */ /* value (right) needs to be set to NULL. */ /*==========================================*/ temp = newItems->right; newItems->right = NULL; /*===================================*/ /* Search the list for the variable. */ /*===================================*/ for (trace = oldList; trace != NULL; trace = trace->right) { /*=========================================*/ /* If the variable is already in the list, */ /* modify the constraint already there to */ /* include the new constraint. */ /*=========================================*/ if (trace->value == newItems->value) { newConstraints = IntersectConstraints(trace->constraints, newItems->constraints); RemoveConstraint(trace->constraints); trace->constraints = newConstraints; ReturnLHSParseNodes(newItems); break; } } /*=================================*/ /* Add the variable constraints to */ /* the list if it wasn't found. */ /*=================================*/ if (trace == NULL) { newItems->right = oldList; oldList = newItems; } /*===========================*/ /* Move on to the next item. */ /*===========================*/ newItems = temp; } return(oldList); }
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); }
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); }
static int PropagateVariableToNodes( void *theEnv, struct lhsParseNode *theNode, int theType, struct symbolHashNode *variableName, struct lhsParseNode *theReference, int startDepth, int assignReference, int ignoreVariableTypes) { struct constraintRecord *tempConstraints; /*===========================================*/ /* Traverse the nodes using the bottom link. */ /*===========================================*/ while (theNode != NULL) { /*==================================================*/ /* If the field/slot contains a predicate or return */ /* value constraint, then propagate the variable to */ /* the expression associated with that constraint. */ /*==================================================*/ if (theNode->expression != NULL) { PropagateVariableToNodes(theEnv,theNode->expression,theType,variableName, theReference,startDepth,assignReference,TRUE); } if (theNode->secondaryExpression != NULL) { PropagateVariableToNodes(theEnv,theNode->secondaryExpression,theType,variableName, theReference,startDepth,assignReference,TRUE); } /*======================================================*/ /* If the field/slot is a single or multifield variable */ /* with the same name as the propagated variable, */ /* then propagate the variable location to this node. */ /*======================================================*/ else if (((theNode->type == SF_VARIABLE) || (theNode->type == MF_VARIABLE)) && (theNode->value == (void *) variableName)) { /*======================================================*/ /* Check for mixing of single and multifield variables. */ /*======================================================*/ if (ignoreVariableTypes == FALSE) { if (((theType == SF_VARIABLE) && (theNode->type == MF_VARIABLE)) || ((theType == MF_VARIABLE) && (theNode->type == SF_VARIABLE))) { return(TRUE); } } /*======================================================*/ /* Intersect the propagated variable's constraints with */ /* the current constraints for this field/slot. */ /*======================================================*/ if ((theReference->constraints != NULL) && (! theNode->negated)) { tempConstraints = theNode->constraints; theNode->constraints = IntersectConstraints(theEnv,theReference->constraints, tempConstraints); if (theNode->derivedConstraints) { RemoveConstraint(theEnv,tempConstraints); } theNode->derivedConstraints = TRUE; } /*=====================================================*/ /* Don't propagate the variable if it originates from */ /* a different type of pattern object and the variable */ /* reference has already been resolved. */ /*=====================================================*/ if (assignReference) { if (theNode->referringNode == NULL) { theNode->referringNode = theReference; } else if (theReference->pattern == theNode->pattern) { theNode->referringNode = theReference; } else if (theReference->patternType == theNode->patternType) { theNode->referringNode = theReference; } } } /*========================================================*/ /* If the field/slot is the node representing the entire */ /* pattern, then propagate the variable location to the */ /* fact address associated with the pattern (if it is the */ /* same variable name). */ /*========================================================*/ else if ((theNode->type == PATTERN_CE) && (theNode->value == (void *) variableName) && (assignReference == TRUE)) { if (theType == MF_VARIABLE) return(TRUE); theNode->referringNode = theReference; } /*=====================================================*/ /* Propagate the variable to other fields contained */ /* within the same & field constraint or same pattern. */ /*=====================================================*/ if (theNode->right != NULL) { if (PropagateVariableToNodes(theEnv,theNode->right,theType,variableName, theReference,startDepth,assignReference,ignoreVariableTypes)) { return(TRUE); } } /*============================================================*/ /* Propagate the variable to other patterns within the same */ /* semantic scope (if dealing with the node for an entire */ /* pattern) or to the next | field constraint within a field. */ /*============================================================*/ if ((theNode->type == PATTERN_CE) || (theNode->type == TEST_CE)) { if (theNode->endNandDepth < startDepth) theNode = NULL; else theNode = theNode->bottom; } else { theNode = theNode->bottom; } } /*========================================================*/ /* Return FALSE to indicate that no errors were detected. */ /*========================================================*/ return(FALSE); }