const type: intRange is new struct
var integer: minValue is integer.first;
var integer: maxValue is integer.last;
var boolean: mayOverflow is FALSE;
var boolean: mayRaiseException is TRUE;
end struct;
const func boolean: (ref intRange: range1) = (ref intRange: range2) is
return range1.minValue = range2.minValue and range1.maxValue = range2.maxValue;
const func boolean: (ref intRange: range1) <> (ref intRange: range2) is
return range1.minValue <> range2.minValue or range1.maxValue <> range2.maxValue;
const type: intRangeOfVariableHash is hash[reference] intRange;
var intRangeOfVariableHash: intRangeOfVariable is intRangeOfVariableHash.value;
const func intRange: getIntRange (in integer: number) is func
result
var intRange: numberRange is intRange.value;
begin
numberRange.minValue := number;
numberRange.maxValue := number;
numberRange.mayOverflow := FALSE;
numberRange.mayRaiseException := FALSE;
end func;
const func intRange: getIntRange (in reference: intExpression) is forward;
const func intRange: getIntAbsRange (in intRange: argument1Range) is func
result
var intRange: absRange is intRange.value;
begin
if argument1Range.minValue > argument1Range.maxValue then
absRange.minValue := 0;
absRange.maxValue := -1;
else
if argument1Range.minValue = integer.first then
if argument1Range.maxValue = integer.first then
absRange.minValue := 0;
absRange.maxValue := -1;
absRange.mayOverflow := TRUE;
else
if argument1Range.maxValue >= 0 then
absRange.minValue := 0;
else
absRange.minValue := -argument1Range.maxValue;
end if;
absRange.mayOverflow := TRUE;
end if;
else
if argument1Range.minValue <= 0 and argument1Range.maxValue >= 0 then
absRange.minValue := 0;
else
absRange.minValue := min(abs(argument1Range.minValue),
abs(argument1Range.maxValue));
end if;
absRange.maxValue := max(abs(argument1Range.minValue),
abs(argument1Range.maxValue));
end if;
absRange.mayRaiseException := argument1Range.mayRaiseException or
absRange.mayOverflow;
end if;
end func;
const func intRange: getIntAddRange (in intRange: summand1Range, in intRange: summand2Range) is func
result
var intRange: sumRange is intRange.value;
local
var boolean: valueOutOfRange is FALSE;
begin
if summand1Range.minValue > summand1Range.maxValue or
summand2Range.minValue > summand2Range.maxValue then
sumRange.minValue := 0;
sumRange.maxValue := -1;
else
if summand1Range.minValue < 0 then
if summand2Range.minValue >= 0 or
summand1Range.minValue >= integer.first - summand2Range.minValue then
sumRange.minValue := summand1Range.minValue + summand2Range.minValue;
else
sumRange.mayOverflow := TRUE;
end if;
else
if summand2Range.minValue <= 0 or
summand1Range.minValue <= integer.last - summand2Range.minValue then
sumRange.minValue := summand1Range.minValue + summand2Range.minValue;
else
valueOutOfRange := TRUE;
end if
end if;
if summand1Range.maxValue > 0 then
if summand2Range.maxValue <= 0 or
summand1Range.maxValue <= integer.last - summand2Range.maxValue then
sumRange.maxValue := summand1Range.maxValue + summand2Range.maxValue;
else
sumRange.mayOverflow := TRUE;
end if;
else
if summand2Range.maxValue >= 0 or
summand1Range.maxValue >= integer.first - summand2Range.maxValue then
sumRange.maxValue := summand1Range.maxValue + summand2Range.maxValue;
else
valueOutOfRange := TRUE;
end if
end if;
if sumRange.minValue > sumRange.maxValue or valueOutOfRange then
sumRange.minValue := 0;
sumRange.maxValue := -1;
sumRange.mayOverflow := TRUE;
end if;
sumRange.mayRaiseException := summand1Range.mayRaiseException or
summand2Range.mayRaiseException or
sumRange.mayOverflow;
end if;
end func;
const func intRange: getIntSbtrRange (in intRange: minuendRange, in intRange: subtrahendRange) is func
result
var intRange: differenceRange is intRange.value;
local
var boolean: valueOutOfRange is FALSE;
begin
if minuendRange.minValue > minuendRange.maxValue or
subtrahendRange.minValue > subtrahendRange.maxValue then
differenceRange.minValue := 0;
differenceRange.maxValue := -1;
else
if minuendRange.minValue < 0 then
if subtrahendRange.maxValue <= 0 or
minuendRange.minValue >= integer.first + subtrahendRange.maxValue then
differenceRange.minValue := minuendRange.minValue - subtrahendRange.maxValue;
else
differenceRange.mayOverflow := TRUE;
end if;
else
if subtrahendRange.maxValue >= 0 or
minuendRange.minValue <= integer.last + subtrahendRange.maxValue then
differenceRange.minValue := minuendRange.minValue - subtrahendRange.maxValue;
else
valueOutOfRange := TRUE;
end if
end if;
if minuendRange.maxValue >= 0 then
if subtrahendRange.minValue >= 0 or
minuendRange.maxValue <= integer.last + subtrahendRange.minValue then
differenceRange.maxValue := minuendRange.maxValue - subtrahendRange.minValue;
else
differenceRange.mayOverflow := TRUE;
end if;
else
if subtrahendRange.minValue <= 0 or
minuendRange.maxValue >= integer.first + subtrahendRange.minValue then
differenceRange.maxValue := minuendRange.maxValue - subtrahendRange.minValue;
else
valueOutOfRange := TRUE;
end if
end if;
if differenceRange.minValue > differenceRange.maxValue or valueOutOfRange then
differenceRange.minValue := 0;
differenceRange.maxValue := -1;
differenceRange.mayOverflow := TRUE;
end if;
differenceRange.mayRaiseException := minuendRange.mayRaiseException or
subtrahendRange.mayRaiseException or
differenceRange.mayOverflow;
end if;
end func;
const func intRange: getIntLshiftRange (in intRange: numberRange, in intRange: lshiftRange) is func
result
var intRange: valueRange is intRange.value;
local
var boolean: valueOutOfRange is FALSE;
var integer: lshiftMin is 0;
var integer: lshiftMax is 0;
var integer: lshiftFound is 0;
var integer: lshift is 0;
begin
if numberRange.minValue > numberRange.maxValue or
lshiftRange.minValue > lshiftRange.maxValue then
valueRange.minValue := 0;
valueRange.maxValue := -1;
elsif lshiftRange.maxValue < 0 or
lshiftRange.minValue > bitLength(integer.last) then
valueRange.minValue := 0;
valueRange.maxValue := -1;
valueRange.mayOverflow := TRUE;
else
if numberRange.minValue < 0 then
if lshiftRange.maxValue <= bitLength(integer.last) and
numberRange.minValue >= integer.first >> lshiftRange.maxValue then
valueRange.minValue := numberRange.minValue << lshiftRange.maxValue;
else
lshiftMin := max(0, lshiftRange.minValue);
lshiftMax := min(bitLength(integer.last), lshiftRange.maxValue);
lshiftFound := integer.last;
for lshift range lshiftMin to lshiftMax until lshiftFound <> integer.last do
if integer.first >> lshift >= numberRange.minValue then
lshiftFound := lshift;
end if;
end for;
if lshiftFound <> integer.last then
valueRange.minValue := integer.first >> lshiftFound << lshiftFound;
end if;
valueRange.mayOverflow := TRUE;
end if;
elsif numberRange.minValue > 0 then
if lshiftRange.minValue >= 0 then
if numberRange.minValue <= integer.last >> lshiftRange.minValue then
valueRange.minValue := numberRange.minValue << lshiftRange.minValue;
else
valueOutOfRange := TRUE;
valueRange.mayOverflow := TRUE;
end if;
else
valueRange.minValue := numberRange.minValue;
valueRange.mayOverflow := TRUE;
end if;
else
valueRange.minValue := 0;
end if;
if numberRange.maxValue < 0 then
if lshiftRange.minValue >= 0 then
if numberRange.maxValue >= integer.first >> lshiftRange.minValue then
valueRange.maxValue := numberRange.maxValue << lshiftRange.minValue;
else
valueOutOfRange := TRUE;
valueRange.mayOverflow := TRUE;
end if;
else
valueRange.maxValue := numberRange.maxValue;
valueRange.mayOverflow := TRUE;
end if;
elsif numberRange.maxValue > 0 then
if lshiftRange.maxValue <= bitLength(integer.last) and
numberRange.maxValue <= integer.last >> lshiftRange.maxValue then
valueRange.maxValue := numberRange.maxValue << lshiftRange.maxValue;
else
lshiftMin := max(0, lshiftRange.minValue);
lshiftMax := min(bitLength(integer.last), lshiftRange.maxValue);
lshiftFound := integer.last;
for lshift range lshiftMin to lshiftMax until lshiftFound <> integer.last do
if integer.last >> lshift <= numberRange.maxValue then
lshiftFound := lshift;
end if;
end for;
if lshiftFound <> integer.last then
valueRange.maxValue := integer.last >> lshiftFound << lshiftFound;
end if;
valueRange.mayOverflow := TRUE;
end if;
else
valueRange.maxValue := 0;
end if;
if valueRange.minValue > valueRange.maxValue or valueOutOfRange then
valueRange.minValue := 0;
valueRange.maxValue := -1;
end if;
valueRange.mayOverflow := valueRange.mayOverflow or
lshiftRange.minValue < 0 or
lshiftRange.maxValue > bitLength(integer.last);
valueRange.mayRaiseException := numberRange.mayRaiseException or
lshiftRange.mayRaiseException or
valueRange.mayOverflow;
end if;
end func;
const func intRange: getIntRshiftRange (in intRange: numberRange, in intRange: rshiftRange) is func
result
var intRange: valueRange is intRange.value;
local
var boolean: valueOutOfRange is FALSE;
begin
if numberRange.minValue > numberRange.maxValue or
rshiftRange.minValue > rshiftRange.maxValue then
valueRange.minValue := 0;
valueRange.maxValue := -1;
elsif rshiftRange.maxValue < 0 or
rshiftRange.minValue > bitLength(integer.last) then
valueRange.minValue := 0;
valueRange.maxValue := -1;
valueRange.mayOverflow := TRUE;
else
if numberRange.minValue < 0 then
if rshiftRange.minValue >= 0 then
valueRange.minValue := numberRange.minValue >> rshiftRange.minValue;
else
valueRange.minValue := numberRange.minValue;
end if;
elsif numberRange.minValue > 0 then
if rshiftRange.maxValue <= bitLength(integer.last) then
valueRange.minValue := numberRange.minValue >> rshiftRange.maxValue;
else
valueRange.minValue := 0;
end if;
else
valueRange.minValue := 0;
end if;
if numberRange.maxValue < 0 then
if rshiftRange.maxValue <= bitLength(integer.last) then
valueRange.maxValue := numberRange.maxValue >> rshiftRange.maxValue;
else
valueRange.maxValue := -1;
end if;
elsif numberRange.maxValue > 0 then
if rshiftRange.minValue >= 0 then
valueRange.maxValue := numberRange.maxValue >> rshiftRange.minValue;
else
valueRange.maxValue := numberRange.maxValue;
end if;
else
valueRange.maxValue := 0;
end if;
if valueRange.minValue > valueRange.maxValue then
valueRange.minValue := 0;
valueRange.maxValue := -1;
end if;
valueRange.mayOverflow := rshiftRange.minValue < 0 or
rshiftRange.maxValue > bitLength(integer.last);
valueRange.mayRaiseException := numberRange.mayRaiseException or
rshiftRange.mayRaiseException or
valueRange.mayOverflow;
end if;
end func;
const func intRange: getIntModRange (in reference: dividend, in reference: divisor) is func
result
var intRange: valueRange is intRange.value;
local
var intRange: divisorRange is intRange.value;
var reference: evaluatedParam is NIL;
var integer: dividendValue is 0;
var intRange: valueRange2 is intRange.value;
begin
divisorRange := getIntRange(divisor);
if divisorRange.minValue > 0 then
valueRange.minValue := 0;
valueRange.maxValue := pred(divisorRange.maxValue);
elsif divisorRange.maxValue < 0 then
valueRange.minValue := succ(divisorRange.minValue);
valueRange.maxValue := 0;
end if;
if getConstant(dividend, INTOBJECT, evaluatedParam) then
dividendValue := getValue(evaluatedParam, integer);
if dividendValue = integer.first then
valueRange2.minValue := succ(integer.first) div 2;
valueRange2.maxValue := -2 - integer.first;
elsif dividendValue = integer.last then
valueRange2.minValue := 2 - integer.last;
valueRange2.maxValue := pred(integer.last) div 2;
elsif dividendValue > 0 then
if integer.first + dividendValue <= 2 - dividendValue then
valueRange2.minValue := integer.first + dividendValue;
else
valueRange2.minValue := 2 - dividendValue;
end if;
valueRange2.maxValue := dividendValue;
elsif dividendValue = 0 then
valueRange2.minValue := 0;
valueRange2.maxValue := 0;
else
valueRange2.minValue := dividendValue;
if integer.last + dividendValue >= -(dividendValue + 2) then
valueRange2.maxValue := integer.last + dividendValue;
else
valueRange2.maxValue := -(dividendValue + 2);
end if;
end if;
valueRange.minValue := max(valueRange.minValue, valueRange2.minValue);
valueRange.maxValue := min(valueRange.maxValue, valueRange2.maxValue);
end if;
if valueRange.minValue > valueRange.maxValue then
valueRange.minValue := 0;
valueRange.maxValue := -1;
end if;
end func;
const func intRange: getIntNegateRange (in intRange: argument1Range) is func
result
var intRange: negatedRange is intRange.value;
begin
if argument1Range.maxValue < argument1Range.minValue then
negatedRange.minValue := 0;
negatedRange.maxValue := -1;
elsif argument1Range.maxValue < -integer.last then
negatedRange.minValue := 0;
negatedRange.maxValue := -1;
negatedRange.mayOverflow := TRUE;
else
negatedRange.minValue := -argument1Range.maxValue;
if argument1Range.minValue < -integer.last then
negatedRange.maxValue := integer.last;
negatedRange.mayOverflow := TRUE;
else
negatedRange.maxValue := -argument1Range.minValue;
end if;
negatedRange.mayRaiseException := argument1Range.mayRaiseException or
negatedRange.mayOverflow;
end if;
end func;
const func intRange: getIntMultRange (in integer: factor1, in intRange: factor2Range) is func
result
var intRange: productRange is intRange.value;
local
var boolean: valueOutOfRange is FALSE;
begin
if factor1 >= 2 then
if factor2Range.minValue <= integer.last div factor1 then
if factor2Range.minValue >= integer.first div factor1 then
productRange.minValue := factor2Range.minValue * factor1;
else
productRange.minValue := integer.first div factor1 * factor1;
productRange.mayOverflow := TRUE;
end if;
else
valueOutOfRange := TRUE;
end if;
if factor2Range.maxValue >= integer.first div factor1 then
if factor2Range.maxValue <= integer.last div factor1 then
productRange.maxValue := factor2Range.maxValue * factor1;
else
productRange.maxValue := integer.last div factor1 * factor1;
productRange.mayOverflow := TRUE;
end if;
else
valueOutOfRange := TRUE;
end if;
elsif factor1 = 1 then
productRange := factor2Range;
productRange.mayOverflow := FALSE;
elsif factor1 = 0 then
productRange.minValue := 0;
productRange.maxValue := 0;
elsif factor1 = -1 then
productRange := getIntNegateRange(factor2Range);
else
if factor2Range.minValue <= integer.first div factor1 then
if factor2Range.minValue >= integer.last div factor1 then
productRange.maxValue := factor2Range.minValue * factor1;
else
productRange.maxValue := integer.last div factor1 * factor1;
productRange.mayOverflow := TRUE;
end if;
else
valueOutOfRange := TRUE;
end if;
if factor2Range.maxValue >= integer.last div factor1 then
if factor2Range.maxValue <= integer.first div factor1 then
productRange.minValue := factor2Range.maxValue * factor1;
else
productRange.minValue := integer.first div factor1 * factor1;
productRange.mayOverflow := TRUE;
end if;
else
valueOutOfRange := TRUE;
end if;
end if;
if valueOutOfRange then
productRange.minValue := 0;
productRange.maxValue := -1;
productRange.mayOverflow := TRUE;
end if;
productRange.mayRaiseException := factor2Range.mayRaiseException or
productRange.mayOverflow;
end func;
const func intRange: getIntMultRange (in intRange: factor1Range, in intRange: factor2Range) is func
result
var intRange: productRange is intRange.value;
local
var boolean: valueOutOfRange is FALSE;
var integer: minProduct is integer.last;
var integer: maxProduct is integer.first;
var boolean: maxFound is FALSE;
begin
if factor1Range.minValue > factor1Range.maxValue or
factor2Range.minValue > factor2Range.maxValue then
productRange.minValue := 0;
productRange.maxValue := -1;
elsif factor1Range.minValue = factor1Range.maxValue then
productRange := getIntMultRange(factor1Range.minValue, factor2Range)
elsif factor2Range.minValue = factor2Range.maxValue then
productRange := getIntMultRange(factor2Range.minValue, factor1Range)
else
if factor1Range.maxValue > 0 then
if factor2Range.minValue < 0 then
if factor2Range.minValue >= integer.first div factor1Range.maxValue then
minProduct := factor1Range.maxValue * factor2Range.minValue;
else
minProduct := integer.first;
productRange.mayOverflow := TRUE;
end if;
elsif factor2Range.minValue = 0 then
minProduct := 0;
end if;
if factor2Range.maxValue > 0 then
if factor1Range.maxValue <= integer.last div factor2Range.maxValue then
maxProduct := factor1Range.maxValue * factor2Range.maxValue;
else
maxProduct := integer.last;
productRange.mayOverflow := TRUE;
end if;
elsif factor2Range.maxValue = 0 then
maxProduct := 0;
end if;
elsif factor1Range.maxValue = 0 then
if factor2Range.minValue <= 0 then
minProduct := 0;
end if;
if factor2Range.maxValue >= 0 then
maxProduct := 0;
end if;
else
if factor2Range.maxValue < 0 then
if (factor1Range.maxValue <> integer.first or factor2Range.maxValue <> -1) and
(factor1Range.maxValue <> -1 or factor2Range.maxValue <> integer.first) and
factor1Range.maxValue >= integer.last div factor2Range.maxValue then
minProduct := factor1Range.maxValue * factor2Range.maxValue;
else
valueOutOfRange := TRUE;
productRange.mayOverflow := TRUE;
end if;
elsif factor2Range.maxValue = 0 then
minProduct := 0;
end if;
if factor2Range.minValue > 0 then
if factor1Range.maxValue >= integer.first div factor2Range.minValue then
maxProduct := factor1Range.maxValue * factor2Range.minValue;
else
valueOutOfRange := TRUE;
productRange.mayOverflow := TRUE;
end if;
elsif factor2Range.minValue = 0 then
maxProduct := 0;
end if;
end if;
if factor1Range.minValue > 0 then
if factor2Range.minValue > 0 then
if factor1Range.minValue <= integer.last div factor2Range.minValue then
minProduct := min(minProduct,
factor1Range.minValue * factor2Range.minValue);
else
valueOutOfRange := TRUE;
productRange.mayOverflow := TRUE;
end if;
elsif factor2Range.minValue = 0 then
minProduct := min(minProduct, 0);
end if;
if factor2Range.maxValue < 0 then
if factor2Range.maxValue >= integer.first div factor1Range.minValue then
maxProduct := max(maxProduct,
factor1Range.minValue * factor2Range.maxValue);
else
valueOutOfRange := TRUE;
productRange.mayOverflow := TRUE;
end if;
elsif factor2Range.maxValue = 0 then
maxProduct := max(maxProduct, 0);
end if;
elsif factor1Range.minValue = 0 then
if factor2Range.minValue >= 0 then
minProduct := min(minProduct, 0);
end if;
if factor2Range.minValue <= 0 then
maxProduct := max(maxProduct, 0);
end if;
else
if factor2Range.maxValue > 0 then
if factor1Range.minValue >= integer.first div factor2Range.maxValue then
minProduct := min(minProduct,
factor1Range.minValue * factor2Range.maxValue);
else
minProduct := integer.first;
productRange.mayOverflow := TRUE;
end if;
elsif factor2Range.maxValue = 0 then
minProduct := min(minProduct, 0);
end if;
if factor2Range.minValue < 0 then
if (factor1Range.minValue <> integer.first or factor2Range.minValue <> -1) and
(factor1Range.minValue <> -1 or factor2Range.minValue <> integer.first) and
factor1Range.minValue >= integer.last div factor2Range.minValue then
maxProduct := max(maxProduct,
factor1Range.minValue * factor2Range.minValue);
else
maxProduct := integer.last;
productRange.mayOverflow := TRUE;
end if;
elsif factor2Range.minValue = 0 then
maxProduct := max(maxProduct, 0);
end if;
end if;
productRange.minValue := minProduct;
productRange.maxValue := maxProduct;
if productRange.minValue > productRange.maxValue or valueOutOfRange then
productRange.minValue := 0;
productRange.maxValue := -1;
end if;
productRange.mayRaiseException := factor1Range.mayRaiseException or
factor2Range.mayRaiseException or
productRange.mayOverflow;
end if;
end func;
const func intRange: getArrValueRange (in reference: arr) is func
result
var intRange: valueRange is intRange.value;
local
var integer: arraySize is 0;
var ref_list: arrayList is ref_list.EMPTY;
var reference: element is NIL;
var integer: elementValue is 0;
begin
arraySize := arrayLength(arr);
if arraySize < 10000 then
valueRange.minValue := integer.last;
valueRange.maxValue := integer.first;
arrayList := arrayToList(arr);
for element range arrayList do
elementValue := getValue(element, integer);
if elementValue < valueRange.minValue then
valueRange.minValue := elementValue;
end if;
if elementValue > valueRange.maxValue then
valueRange.maxValue := elementValue;
end if;
end for;
end if;
end func;
const func intRange: getArrLenRange (in reference: arr) is func
result
var intRange: valueRange is intRange.value;
local
var reference: evaluatedParam is NIL;
begin
if getConstant(arr, ARRAYOBJECT, evaluatedParam) then
valueRange.minValue := arrayLength(evaluatedParam);
valueRange.maxValue := valueRange.minValue
elsif isActionExpression(arr, "ARR_SUBARR") and
getConstant(getActionParameter(arr, 5), INTOBJECT, evaluatedParam) or
isActionExpression(arr, "ARR_HEAD") and
getConstant(getActionParameter(arr, 4), INTOBJECT, evaluatedParam) then
valueRange.minValue := 0;
valueRange.maxValue := getValue(evaluatedParam, integer);
elsif ccConf.POINTER_SIZE > ccConf.GENERIC_SIZE then
valueRange.minValue := 0;
valueRange.maxValue := integer.last;
else
valueRange.minValue := 0;
valueRange.maxValue :=
ord(2_ ** ccConf.POINTER_SIZE div bigInteger(ccConf.GENERIC_SIZE div 8));
end if;
end func;
const func intRange: getStrLenRange (in reference: stri) is func
result
var intRange: valueRange is intRange.value;
local
var reference: evaluatedParam is NIL;
var intRange: argumentRange is intRange.value;
var integer: base is 0;
var integer: length is 0;
begin
if getConstant(stri, STRIOBJECT, evaluatedParam) then
length := length(getValue(evaluatedParam, string));
valueRange.minValue := length;
valueRange.maxValue := length;
valueRange.mayRaiseException := FALSE;
elsif isActionExpression(stri, "STR_SUBSTR_FIXLEN") and
getConstant(getActionParameter(stri, 5), INTOBJECT, evaluatedParam) then
length := getValue(evaluatedParam, integer);
valueRange.minValue := length;
valueRange.maxValue := length;
elsif isActionExpression(stri, "STR_SUBSTR") and
getConstant(getActionParameter(stri, 5), INTOBJECT, evaluatedParam) or
isActionExpression(stri, "STR_HEAD") and
getConstant(getActionParameter(stri, 4), INTOBJECT, evaluatedParam) then
valueRange.minValue := 0;
valueRange.maxValue := getValue(evaluatedParam, integer);
elsif isActionExpression(stri, "CHR_STR") then
valueRange.minValue := 1;
valueRange.maxValue := 1;
valueRange.mayRaiseException := FALSE;
elsif isActionExpression(stri, "INT_STR") then
argumentRange := getIntRange(getActionParameter(stri, 1));
valueRange.minValue := 1;
valueRange.maxValue := max(length(str(argumentRange.minValue)),
length(str(argumentRange.maxValue)));
elsif (isActionExpression(stri, "INT_RADIX") or
isActionExpression(stri, "INT_radix")) and
getConstant(getActionParameter(stri, 3), INTOBJECT, evaluatedParam) then
argumentRange := getIntRange(getActionParameter(stri, 1));
base := getValue(evaluatedParam, integer);
valueRange.minValue := 1;
valueRange.maxValue := max(length(argumentRange.minValue radix base),
length(argumentRange.maxValue radix base));
elsif isActionExpression(stri, "INT_N_BYTES_BE_SIGNED") or
isActionExpression(stri, "INT_N_BYTES_BE_UNSIGNED") or
isActionExpression(stri, "INT_N_BYTES_LE_SIGNED") or
isActionExpression(stri, "INT_N_BYTES_LE_UNSIGNED") then
argumentRange := getIntRange(getActionParameter(stri, 4));
valueRange.minValue := max(1, argumentRange.minValue);
valueRange.maxValue := max(1, argumentRange.maxValue);
elsif isActionExpression(stri, "INT_BYTES_BE_SIGNED") or
isActionExpression(stri, "INT_BYTES_LE_SIGNED") then
argumentRange := getIntRange(getActionParameter(stri, 1));
valueRange.minValue := 1;
valueRange.maxValue := max(length(bytes(argumentRange.minValue, SIGNED, LE)),
length(bytes(argumentRange.maxValue, SIGNED, LE)));
elsif isActionExpression(stri, "INT_BYTES_BE_UNSIGNED") or
isActionExpression(stri, "INT_BYTES_LE_UNSIGNED") then
valueRange.minValue := 1;
valueRange.maxValue := max(length(bytes(max(0, argumentRange.minValue), UNSIGNED, LE)),
length(bytes(max(0, argumentRange.maxValue), UNSIGNED, LE)));
elsif isActionExpression(stri, "BIN_N_BYTES_BE") or
isActionExpression(stri, "BIN_N_BYTES_LE") then
argumentRange := getIntRange(getActionParameter(stri, 3));
valueRange.minValue := max(1, argumentRange.minValue);
valueRange.maxValue := max(1, argumentRange.maxValue);
elsif ccConf.POINTER_SIZE > ccConf.INTTYPE_SIZE then
valueRange.minValue := 0;
valueRange.maxValue := integer.last;
else
valueRange.minValue := 0;
valueRange.maxValue := pred(2 ** (ccConf.POINTER_SIZE - 2));
end if;
end func;
const func intRange: getIntBytes2IntRange (in reference: stri) is func
result
var intRange: valueRange is intRange.value;
local
var intRange: strLenRange is intRange.value;
begin
strLenRange := getStrLenRange(stri);
if strLenRange.maxValue >= 1 and strLenRange.maxValue < 8 then
if ccConf.TWOS_COMPLEMENT_INTTYPE then
valueRange.minValue := -2 ** pred(strLenRange.maxValue * 8);
else
valueRange.minValue := -pred(2 ** pred(strLenRange.maxValue * 8));
end if;
valueRange.maxValue := pred(2 ** pred(strLenRange.maxValue * 8));
end if;
end func;
const func intRange: getIntBytes2UIntRange (in reference: stri) is func
result
var intRange: valueRange is intRange.value;
local
var intRange: strLenRange is intRange.value;
begin
valueRange.minValue := 0;
strLenRange := getStrLenRange(stri);
if strLenRange.maxValue >= 1 and strLenRange.maxValue < 8 then
valueRange.maxValue := pred(2 ** (strLenRange.maxValue * 8));
end if;
end func;
const func intRange: getIntParse1Range (in reference: stri) is func
result
var intRange: valueRange is intRange.value;
local
var intRange: strLenRange is intRange.value;
begin
strLenRange := getStrLenRange(stri);
if strLenRange.maxValue >= 1 then
if strLenRange.maxValue < length(str(integer.first)) then
valueRange.minValue := -pred(10 ** pred(strLenRange.maxValue));
end if;
if strLenRange.maxValue < length(str(integer.last)) then
valueRange.maxValue := pred(10 ** strLenRange.maxValue);
end if;
end if;
end func;
const func intRange: getSetRandRange (in reference: aSet) is func
result
var intRange: valueRange is intRange.value;
local
var reference: evaluatedParam is NIL;
var bitset: setValue is {};
begin
if getConstant(aSet, SETOBJECT, evaluatedParam) then
setValue := getValue(evaluatedParam, bitset);
if setValue = {} then
valueRange.minValue := 0;
valueRange.maxValue := -1;
else
valueRange.minValue := min(setValue);
valueRange.maxValue := max(setValue);
end if;
end if;
end func;
const func intRange: getBlnTernaryRange (in reference: condition,
in reference: thenParam, in reference: elseParam,
inout reference: limitedVariable) is forward;
const func intRange: lessEqualLimit (in integer: limit, in reference: conditionParam,
in reference: thenOrElseParam, inout reference: limitedVariable) is func
result
var intRange: valueRange is intRange.value;
local
var intRange: subExprValueRange is intRange.value;
var ref_list: params is ref_list.EMPTY;
var reference: subExprLimitedVariable is NIL;
begin
if conditionParam = thenOrElseParam then
subExprValueRange := getIntRange(thenOrElseParam);
valueRange.minValue := min(subExprValueRange.minValue, limit);
valueRange.maxValue := min(subExprValueRange.maxValue, limit);
limitedVariable := conditionParam;
elsif category(thenOrElseParam) = MATCHOBJECT then
params := getValue(thenOrElseParam, ref_list);
if category(params[1]) = ACTOBJECT and
str(getValue(params[1], ACTION)) = "BLN_TERNARY" then
subExprValueRange :=
getBlnTernaryRange(params[2], params[4], params[6], subExprLimitedVariable);
if subExprLimitedVariable = conditionParam then
valueRange.minValue := min(subExprValueRange.minValue, limit);
valueRange.maxValue := min(subExprValueRange.maxValue, limit);
limitedVariable := conditionParam;
end if;
end if;
end if;
end func;
const func intRange: greaterEqualLimit (in integer: limit, in reference: conditionParam,
in reference: thenOrElseParam, inout reference: limitedVariable) is func
result
var intRange: valueRange is intRange.value;
local
var intRange: subExprValueRange is intRange.value;
var ref_list: params is ref_list.EMPTY;
var reference: subExprLimitedVariable is NIL;
begin
if conditionParam = thenOrElseParam then
subExprValueRange := getIntRange(thenOrElseParam);
valueRange.minValue := max(subExprValueRange.minValue, limit);
valueRange.maxValue := max(subExprValueRange.maxValue, limit);
limitedVariable := conditionParam;
elsif category(thenOrElseParam) = MATCHOBJECT then
params := getValue(thenOrElseParam, ref_list);
if category(params[1]) = ACTOBJECT and
str(getValue(params[1], ACTION)) = "BLN_TERNARY" then
subExprValueRange :=
getBlnTernaryRange(params[2], params[4], params[6], subExprLimitedVariable);
if subExprLimitedVariable = conditionParam then
valueRange.minValue := max(subExprValueRange.minValue, limit);
valueRange.maxValue := max(subExprValueRange.maxValue, limit);
limitedVariable := conditionParam;
end if;
end if;
end if;
end func;
const func intRange: getBlnTernaryRange (in reference: condition,
in reference: thenParam, in reference: elseParam,
inout reference: limitedVariable) is func
result
var intRange: valueRange is intRange.value;
local
var reference: evaluatedParam is NIL;
var integer: limit is 0;
var reference: evaluatedThenParam is NIL;
var reference: evaluatedElseParam is NIL;
var integer: number is 0;
begin
if isActionExpression(condition, "INT_GT") or
isActionExpression(condition, "INT_GE") then
if getConstant(getActionParameter(condition, 3), INTOBJECT, evaluatedParam) then
limit := getValue(evaluatedParam, integer);
if getConstant(thenParam, INTOBJECT, evaluatedThenParam) then
number := getValue(evaluatedThenParam, integer);
if limit = number then
valueRange := lessEqualLimit(limit, getActionParameter(condition, 1),
elseParam, limitedVariable);
end if;
elsif getConstant(elseParam, INTOBJECT, evaluatedElseParam) then
number := getValue(evaluatedElseParam, integer);
if limit = number then
valueRange := greaterEqualLimit(limit, getActionParameter(condition, 1),
thenParam, limitedVariable);
end if;
end if;
elsif getConstant(getActionParameter(condition, 1), INTOBJECT, evaluatedParam) then
limit := getValue(evaluatedParam, integer);
if getConstant(thenParam, INTOBJECT, evaluatedThenParam) then
number := getValue(evaluatedThenParam, integer);
if limit = number then
valueRange := greaterEqualLimit(limit, getActionParameter(condition, 3),
elseParam, limitedVariable);
end if;
elsif getConstant(elseParam, INTOBJECT, evaluatedElseParam) then
number := getValue(evaluatedElseParam, integer);
if limit = number then
valueRange := lessEqualLimit(limit, getActionParameter(condition, 3),
thenParam, limitedVariable);
end if;
end if;
end if;
elsif isActionExpression(condition, "INT_LT") or
isActionExpression(condition, "INT_LE") then
if getConstant(getActionParameter(condition, 3), INTOBJECT, evaluatedParam) then
limit := getValue(evaluatedParam, integer);
if getConstant(thenParam, INTOBJECT, evaluatedThenParam) then
number := getValue(evaluatedThenParam, integer);
if limit = number then
valueRange := greaterEqualLimit(limit, getActionParameter(condition, 1),
elseParam, limitedVariable);
end if;
elsif getConstant(elseParam, INTOBJECT, evaluatedElseParam) then
number := getValue(evaluatedElseParam, integer);
if limit = number then
valueRange := lessEqualLimit(limit, getActionParameter(condition, 1),
thenParam, limitedVariable);
end if;
end if;
elsif getConstant(getActionParameter(condition, 1), INTOBJECT, evaluatedParam) then
limit := getValue(evaluatedParam, integer);
if getConstant(thenParam, INTOBJECT, evaluatedThenParam) then
number := getValue(evaluatedThenParam, integer);
if limit = number then
valueRange := lessEqualLimit(limit, getActionParameter(condition, 3),
elseParam, limitedVariable);
end if;
elsif getConstant(elseParam, INTOBJECT, evaluatedElseParam) then
number := getValue(evaluatedElseParam, integer);
if limit = number then
valueRange := greaterEqualLimit(limit, getActionParameter(condition, 3),
thenParam, limitedVariable);
end if;
end if;
end if;
end if;
end func;
const func intRange: getBlnTernaryRange (in reference: condition,
in reference: thenParam, in reference: elseParam) is func
result
var intRange: valueRange is intRange.value;
local
var reference: evaluatedParam is NIL;
var reference: limitedVariable is NIL;
var intRange: thenValueRange is intRange.value;
var intRange: elseValueRange is intRange.value;
var boolean: done is FALSE;
begin
if getConstant(condition, ENUMLITERALOBJECT, evaluatedParam) then
if getValue(evaluatedParam, boolean) then
valueRange := getIntRange(thenParam);
else
valueRange := getIntRange(elseParam);
end if;
done := TRUE;
else
valueRange := getBlnTernaryRange(condition, thenParam, elseParam, limitedVariable);
done := limitedVariable <> NIL;
end if;
if not done then
thenValueRange := getIntRange(thenParam);
elseValueRange := getIntRange(elseParam);
valueRange.minValue := min(thenValueRange.minValue,
elseValueRange.minValue);
valueRange.maxValue := max(thenValueRange.maxValue,
elseValueRange.maxValue);
end if;
end func;
const func intRange: getBigOrdOfBigModRange (in bigInteger: divisor) is func
result
var intRange: valueRange is intRange.value;
begin
if divisor > 0_ and divisor <= 2_ ** 63 then
valueRange.minValue := 0;
valueRange.maxValue := ord(pred(divisor));
elsif divisor < 0_ and divisor >= pred(-2_ ** 63) then
valueRange.minValue := ord(succ(divisor));
valueRange.maxValue := 0;
end if;
end func;
const func intRange: getIntRange (in reference: intExpression) is func
result
var intRange: valueRange is intRange.value;
local
var reference: function is NIL;
var ref_list: params is ref_list.EMPTY;
var string: actionName is "";
var reference: evaluatedParam is NIL;
var integer: number is 0;
var intRange: argument1Range is intRange.value;
var intRange: argument2Range is intRange.value;
begin
if reduceOverflowChecks then
if getConstant(intExpression, INTOBJECT, evaluatedParam) then
number := getValue(evaluatedParam, integer);
valueRange.minValue := number;
valueRange.maxValue := number;
valueRange.mayRaiseException := FALSE;
elsif intExpression in intRangeOfVariable then
valueRange := intRangeOfVariable[intExpression];
valueRange.mayRaiseException := FALSE;
elsif category(intExpression) = CALLOBJECT then
params := getValue(intExpression, ref_list);
function := params[1];
params := params[2 ..];
if category(function) = ACTOBJECT then
actionName := str(getValue(function, ACTION));
case actionName of
when {"BIG_BIT_LENGTH", "BST_LNG", "CMD_FILESIZE", "CON_HEIGHT",
"CON_WIDTH", "DRW_HEIGHT", "DRW_WIDTH", "DRW_SCREEN_HEIGHT",
"DRW_SCREEN_WIDTH", "FIL_LNG", "HSH_LNG", "RFL_LNG",
"SET_CARD", "SQL_STMT_COLUMN_COUNT"}:
valueRange.minValue := 0;
valueRange.maxValue := integer.last;
when {"BIG_CMP", "BIN_CMP", "BST_CMP", "CHR_CMP", "DRW_CMP",
"FLT_CMP", "INT_CMP", "ITF_CMP", "PCS_CMP", "REF_CMP",
"SET_CMP", "SQL_CMP_DB", "SQL_CMP_STMT", "STR_CMP",
"TYP_CMP"}:
valueRange.minValue := -1;
valueRange.maxValue := 1;
when {"ARR_IDX"}:
if getConstant(params[1], ARRAYOBJECT, evaluatedParam) then
valueRange := getArrValueRange(evaluatedParam);
end if;
when {"ARR_LNG"}:
valueRange := getArrLenRange(params[1]);
when {"BIG_LOWEST_SET_BIT"}:
valueRange.minValue := -1;
valueRange.maxValue := integer.last;
when {"BIG_ORD"}:
if isActionExpression(params[1], "BIG_MOD") and
getConstant(getActionParameter(params[1], 3),
BIGINTOBJECT, evaluatedParam) then
valueRange := getBigOrdOfBigModRange(
getValue(evaluatedParam, bigInteger));
end if;
when {"BIN_AND"}:
if getConstant(params[1], INTOBJECT, evaluatedParam) or
getConstant(params[3], INTOBJECT, evaluatedParam) then
number := getValue(evaluatedParam, integer);
if number >= 0 then
valueRange.minValue := 0;
valueRange.maxValue := number;
else
valueRange.minValue := integer.first;
valueRange.maxValue := number - integer.first;
end if;
end if;
when {"BIN_CARD"}:
valueRange.minValue := 0;
valueRange.maxValue := ccConf.INTTYPE_SIZE;
when {"BLN_ORD"}:
valueRange.minValue := 0;
valueRange.maxValue := 1;
when {"BLN_TERNARY"}:
valueRange := getBlnTernaryRange(params[1], params[3], params[5]);
when {"CHR_ORD"}:
if ccConf.TWOS_COMPLEMENT_INTTYPE then
valueRange.minValue := -2147483648;
else
valueRange.minValue := -2147483647;
end if;
valueRange.maxValue := 2147483647;
when {"ENU_ORD2"}:
valueRange.minValue := 0;
valueRange.maxValue :=
pred(length(getValue(evaluate(prog, params[2]), ref_list)));
when {"FIL_TELL"}:
valueRange.minValue := 1;
valueRange.maxValue := integer.last;
when {"INT_ABS"}:
valueRange := getIntAbsRange(getIntRange(params[1]));
when {"INT_ADD"}:
valueRange := getIntAddRange(getIntRange(params[1]),
getIntRange(params[3]));
when {"INT_BIT_LENGTH"}:
argument1Range := getIntRange(params[1]);
if argument1Range.minValue <= 0 and argument1Range.maxValue >= 0 then
valueRange.minValue := 0;
else
valueRange.minValue := min(bitLength(argument1Range.minValue),
bitLength(argument1Range.maxValue));
end if;
valueRange.maxValue := max(bitLength(argument1Range.minValue),
bitLength(argument1Range.maxValue));
when {"INT_BYTES_BE_2_INT",
"INT_BYTES_LE_2_INT"}:
valueRange := getIntBytes2IntRange(params[1]);
when {"INT_BYTES_BE_2_UINT",
"INT_BYTES_LE_2_UINT"}:
valueRange := getIntBytes2UIntRange(params[1]);
when {"INT_DIV"}:
if getConstant(params[3], INTOBJECT, evaluatedParam) then
number := getValue(evaluatedParam, integer);
argument1Range := getIntRange(params[1]);
if number > 0 then
valueRange.minValue := argument1Range.minValue div number;
valueRange.maxValue := argument1Range.maxValue div number;
elsif number = -1 then
valueRange := getIntNegateRange(argument1Range);
elsif number < -1 then
valueRange.minValue := argument1Range.maxValue div number;
valueRange.maxValue := argument1Range.minValue div number;
end if;
elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
number := getValue(evaluatedParam, integer);
if number >= 0 then
valueRange.minValue := -number;
valueRange.maxValue := number;
elsif number <> integer.first then
valueRange.minValue := number;
valueRange.maxValue := -number;
end if;
end if;
when {"INT_FACT"}:
valueRange.minValue := 1;
valueRange.maxValue := 2432902008176640000;
when {"INT_ICONV1"}:
valueRange := getIntRange(params[1]);
when {"INT_ICONV3"}:
valueRange := getIntRange(params[3]);
when {"INT_LOG10"}:
argument1Range := getIntRange(params[1]);
if argument1Range.maxValue >= 0 then
if argument1Range.minValue >= 0 then
valueRange.minValue := log10(argument1Range.minValue);
else
valueRange.minValue := -1;
end if;
valueRange.maxValue := log10(argument1Range.maxValue);
else
valueRange.minValue := 0;
valueRange.maxValue := -1;
end if;
when {"INT_LOG2"}:
argument1Range := getIntRange(params[1]);
if argument1Range.maxValue >= 0 then
if argument1Range.minValue >= 0 then
valueRange.minValue := log2(argument1Range.minValue);
else
valueRange.minValue := -1;
end if;
valueRange.maxValue := log2(argument1Range.maxValue);
else
valueRange.minValue := 0;
valueRange.maxValue := -1;
end if;
when {"INT_LOWEST_SET_BIT"}:
valueRange.minValue := -1;
valueRange.maxValue := pred(ccConf.INTTYPE_SIZE);
when {"INT_LSHIFT"}:
valueRange := getIntLshiftRange(getIntRange(params[1]),
getIntRange(params[3]));
when {"INT_MDIV"}:
if getConstant(params[3], INTOBJECT, evaluatedParam) then
number := getValue(evaluatedParam, integer);
argument1Range := getIntRange(params[1]);
if number > 0 then
valueRange.minValue := argument1Range.minValue mdiv number;
valueRange.maxValue := argument1Range.maxValue mdiv number;
elsif number = -1 then
valueRange := getIntNegateRange(argument1Range);
elsif number < -1 then
valueRange.minValue := argument1Range.maxValue mdiv number;
valueRange.maxValue := argument1Range.minValue mdiv number;
end if;
elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
number := getValue(evaluatedParam, integer);
if number >= 0 then
valueRange.minValue := -number;
valueRange.maxValue := number;
elsif number <> integer.first then
valueRange.minValue := number;
valueRange.maxValue := -number;
end if;
end if;
when {"INT_MOD"}:
valueRange := getIntModRange(params[1], params[3]);
when {"INT_MULT"}:
valueRange := getIntMultRange(getIntRange(params[1]),
getIntRange(params[3]));
when {"INT_NEGATE"}:
valueRange := getIntNegateRange(getIntRange(params[2]));
when {"INT_PARSE1"}:
valueRange := getIntParse1Range(params[1]);
when {"INT_PLUS"}:
valueRange := getIntRange(params[2]);
when {"INT_PRED"}:
argument1Range := getIntRange(params[1]);
if argument1Range.minValue <> integer.first then
valueRange.minValue := pred(argument1Range.minValue);
else
valueRange.minValue := integer.first;
end if;
if argument1Range.maxValue <> integer.first then
valueRange.maxValue := pred(argument1Range.maxValue);
else
valueRange.maxValue := integer.first;
end if;
if not argument1Range.mayRaiseException and
argument1Range.minValue <> integer.first then
valueRange.mayRaiseException := FALSE;
end if;
when {"INT_RAND"}:
argument1Range := getIntRange(params[1]);
argument2Range := getIntRange(params[2]);
valueRange.minValue := argument1Range.minValue;
valueRange.maxValue := argument2Range.maxValue;
if not (argument1Range.mayRaiseException or
argument2Range.mayRaiseException) and
argument1Range.maxValue <= argument2Range.minValue then
valueRange.mayRaiseException := FALSE;
end if;
when {"INT_REM"}:
if getConstant(params[3], INTOBJECT, evaluatedParam) then
number := getValue(evaluatedParam, integer);
if number > 0 then
valueRange.minValue := -pred(number);
valueRange.maxValue := pred(number);
elsif number < 0 then
valueRange.minValue := succ(number);
valueRange.maxValue := -succ(number);
end if;
elsif getConstant(params[1], INTOBJECT, evaluatedParam) then
number := getValue(evaluatedParam, integer);
if number >= 0 then
valueRange.minValue := 0;
valueRange.maxValue := number;
elsif number = 0 then
valueRange.minValue := 0;
valueRange.maxValue := 0;
else
valueRange.minValue := number;
valueRange.maxValue := 0;
end if;
end if;
when {"INT_RSHIFT"}:
valueRange := getIntRshiftRange(getIntRange(params[1]),
getIntRange(params[3]));
when {"INT_SBTR"}:
valueRange := getIntSbtrRange(getIntRange(params[1]),
getIntRange(params[3]));
when {"INT_SQRT"}:
argument1Range := getIntRange(params[1]);
if argument1Range.maxValue >= 0 then
if argument1Range.minValue >= 0 then
valueRange.minValue := sqrt(argument1Range.minValue);
else
valueRange.minValue := 0;
end if;
valueRange.maxValue := sqrt(argument1Range.maxValue);
else
valueRange.minValue := 0;
valueRange.maxValue := -1;
end if;
when {"INT_SUCC"}:
argument1Range := getIntRange(params[1]);
if argument1Range.minValue <> integer.last then
valueRange.minValue := succ(argument1Range.minValue);
else
valueRange.minValue := integer.last;
end if;
if argument1Range.maxValue <> integer.last then
valueRange.maxValue := succ(argument1Range.maxValue);
else
valueRange.maxValue := integer.last;
end if;
if not argument1Range.mayRaiseException and
argument1Range.maxValue <> integer.last then
valueRange.mayRaiseException := FALSE;
end if;
when {"SET_RAND"}:
valueRange := getSetRandRange(params[1]);
when {"STR_CHIPOS", "STR_CHPOS", "STR_IPOS", "STR_POS",
"STR_RCHIPOS", "STR_RCHPOS", "STR_RIPOS", "STR_RPOS"}:
valueRange.minValue := 0;
valueRange.maxValue := getStrLenRange(params[1]).maxValue;
when {"STR_LNG"}:
valueRange := getStrLenRange(params[1]);
end case;
elsif category(function) = BLOCKOBJECT then
if resultVar(function) = NIL and
resultInitValue(function) = NIL and
localConsts(function) = ref_list.EMPTY and
localVars(function) = ref_list.EMPTY then
valueRange := getIntRange(body(function));
end if;
end if;
elsif category(intExpression) = VALUEPARAMOBJECT then
if intExpression in inlineParam and
inlineParam[intExpression][1].actualParam <> NIL then
if category(inlineParam[intExpression][1].actualParam) <> CALLOBJECT or
category(getValue(inlineParam[intExpression][1].actualParam, ref_list)[1]) <> BLOCKOBJECT then
valueRange := getIntRange(inlineParam[intExpression][1].actualParam);
end if;
end if;
end if;
end if;
end func;