mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-14 10:29:24 +02:00
fcl-passrc: resolver: eval set of integer range
git-svn-id: trunk@36819 -
This commit is contained in:
parent
936fac3a33
commit
37c9dc2c3f
@ -47,9 +47,15 @@ Works:
|
|||||||
- error on duplicate in const set
|
- error on duplicate in const set
|
||||||
|
|
||||||
ToDo:
|
ToDo:
|
||||||
- set of 1..7
|
|
||||||
- arrays
|
- arrays
|
||||||
- length(), low(), high(), []
|
- length(), [], [a..b], [a,b], +
|
||||||
|
- array of int
|
||||||
|
- of char
|
||||||
|
- of enum
|
||||||
|
- of bool
|
||||||
|
- of record
|
||||||
|
- of string
|
||||||
|
- enum ranges: type f=(a,b,c,d); g=b..c;
|
||||||
}
|
}
|
||||||
unit PasResolveEval;
|
unit PasResolveEval;
|
||||||
|
|
||||||
@ -303,6 +309,33 @@ const
|
|||||||
reitAllSigned = [reitNone,reitShortInt,reitSmallInt,reitIntSingle,reitLongInt,reitIntDouble];
|
reitAllSigned = [reitNone,reitShortInt,reitSmallInt,reitIntSingle,reitLongInt,reitIntDouble];
|
||||||
reitAllUnsigned = [reitByte,reitWord,reitUIntSingle,reitLongWord,reitUIntDouble];
|
reitAllUnsigned = [reitByte,reitWord,reitUIntSingle,reitLongWord,reitUIntDouble];
|
||||||
|
|
||||||
|
reitLow: array[TResEvalTypedInt] of MaxPrecInt = (
|
||||||
|
low(MaxPrecInt), // reitNone,
|
||||||
|
low(Byte), // reitByte,
|
||||||
|
low(ShortInt), // reitShortInt,
|
||||||
|
low(Word), // reitWord,
|
||||||
|
low(SmallInt), // reitSmallInt,
|
||||||
|
0, // reitUIntSingle,
|
||||||
|
MinSafeIntSingle, // reitIntSingle,
|
||||||
|
low(LongWord), // reitLongWord,
|
||||||
|
low(LongInt), // reitLongInt,
|
||||||
|
0, // reitUIntDouble,
|
||||||
|
MinSafeIntDouble // reitIntDouble)
|
||||||
|
);
|
||||||
|
reitHigh: array[TResEvalTypedInt] of MaxPrecInt = (
|
||||||
|
high(MaxPrecInt), // reitNone,
|
||||||
|
high(Byte), // reitByte,
|
||||||
|
high(ShortInt), // reitShortInt,
|
||||||
|
high(Word), // reitWord,
|
||||||
|
high(SmallInt), // reitSmallInt,
|
||||||
|
MaxSafeIntSingle, // reitUIntSingle,
|
||||||
|
MaxSafeIntSingle, // reitIntSingle,
|
||||||
|
high(LongWord), // reitLongWord,
|
||||||
|
high(LongInt), // reitLongInt,
|
||||||
|
MaxSafeIntDouble, // reitUIntDouble,
|
||||||
|
MaxSafeIntDouble // reitIntDouble)
|
||||||
|
);
|
||||||
|
|
||||||
type
|
type
|
||||||
{ TResEvalInt }
|
{ TResEvalInt }
|
||||||
|
|
||||||
@ -338,6 +371,7 @@ type
|
|||||||
constructor CreateValue(const aValue: MaxPrecFloat);
|
constructor CreateValue(const aValue: MaxPrecFloat);
|
||||||
function Clone: TResEvalValue; override;
|
function Clone: TResEvalValue; override;
|
||||||
function AsString: string; override;
|
function AsString: string; override;
|
||||||
|
function IsInt(out Int: MaxPrecInt): boolean;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TResEvalString - Kind=revkString }
|
{ TResEvalString - Kind=revkString }
|
||||||
@ -492,6 +526,8 @@ type
|
|||||||
function EvalParamsExpr(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
|
function EvalParamsExpr(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
|
||||||
function EvalArrayParamsExpr(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
|
function EvalArrayParamsExpr(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
|
||||||
function EvalSetParamsExpr(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalSet;
|
function EvalSetParamsExpr(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalSet;
|
||||||
|
function EvalSetExpr(Expr: TPasExpr; ExprArray: TPasExprArray; Flags: TResEvalFlags): TResEvalSet;
|
||||||
|
function EvalArrayValuesExpr(Expr: TArrayValues; Flags: TResEvalFlags): TResEvalSet;
|
||||||
function ExprStringToOrd(Value: TResEvalValue; PosEl: TPasElement): longword; virtual;
|
function ExprStringToOrd(Value: TResEvalValue; PosEl: TPasElement): longword; virtual;
|
||||||
function EvalPrimitiveExprString(Expr: TPrimitiveExpr): TResEvalValue; virtual;
|
function EvalPrimitiveExprString(Expr: TPrimitiveExpr): TResEvalValue; virtual;
|
||||||
procedure PredBool(Value: TResEvalBool; ErrorEl: TPasElement);
|
procedure PredBool(Value: TResEvalBool; ErrorEl: TPasElement);
|
||||||
@ -904,32 +940,65 @@ end;
|
|||||||
|
|
||||||
function TResExprEvaluator.EvalUnaryExpr(Expr: TUnaryExpr; Flags: TResEvalFlags
|
function TResExprEvaluator.EvalUnaryExpr(Expr: TUnaryExpr; Flags: TResEvalFlags
|
||||||
): TResEvalValue;
|
): TResEvalValue;
|
||||||
|
var
|
||||||
|
Int: MaxPrecInt;
|
||||||
|
UInt: MaxPrecUInt;
|
||||||
begin
|
begin
|
||||||
Result:=Eval(Expr.Operand,Flags);
|
Result:=Eval(Expr.Operand,Flags);
|
||||||
if Result=nil then exit;
|
if Result=nil then exit;
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TResExprEvaluator.EvalUnaryExpr ',OpcodeStrings[Expr.OpCode],' Value=',Result.AsDebugString);
|
||||||
|
{$ENDIF}
|
||||||
case Expr.OpCode of
|
case Expr.OpCode of
|
||||||
eopAdd: ;
|
eopAdd: ;
|
||||||
eopSubtract:
|
eopSubtract:
|
||||||
case Result.Kind of
|
case Result.Kind of
|
||||||
revkInt:
|
revkInt:
|
||||||
begin
|
begin
|
||||||
if TResEvalInt(Result).Int=0 then exit;
|
Int:=TResEvalInt(Result).Int;
|
||||||
|
if Int=0 then exit;
|
||||||
if Result.Element<>nil then
|
if Result.Element<>nil then
|
||||||
Result:=Result.Clone;
|
Result:=Result.Clone;
|
||||||
if TResEvalInt(Result).Int=0 then exit;
|
if (TResEvalInt(Result).Typed in reitAllSigned) then
|
||||||
if not (TResEvalInt(Result).Typed in reitAllSigned) then
|
|
||||||
begin
|
begin
|
||||||
// switch to untyped
|
if Int=reitLow[TResEvalInt(Result).Typed] then
|
||||||
|
begin
|
||||||
|
// need higher precision
|
||||||
|
if TResEvalInt(Result).Typed<>reitNone then
|
||||||
|
// unsigned -> switch to untyped
|
||||||
|
TResEvalInt(Result).Typed:=reitNone
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// switch to float
|
||||||
|
ReleaseEvalValue(Result);
|
||||||
|
Result:=TResEvalFloat.CreateValue(-MaxPrecFloat(low(MaxPrecInt)));
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// unsigned -> switch to untyped
|
||||||
TResEvalInt(Result).Typed:=reitNone;
|
TResEvalInt(Result).Typed:=reitNone;
|
||||||
end;
|
end ;
|
||||||
TResEvalInt(Result).Int:=-TResEvalInt(Result).Int
|
// negate
|
||||||
|
TResEvalInt(Result).Int:=-Int;
|
||||||
end;
|
end;
|
||||||
revkUInt:
|
revkUInt:
|
||||||
begin
|
begin
|
||||||
if TResEvalUInt(Result).UInt=0 then exit;
|
UInt:=TResEvalUInt(Result).UInt;
|
||||||
if Result.Element<>nil then
|
if UInt=0 then exit;
|
||||||
Result:=Result.Clone;
|
if UInt<=High(MaxPrecInt) then
|
||||||
TResEvalUInt(Result).UInt:=-TResEvalUInt(Result).UInt;
|
begin
|
||||||
|
ReleaseEvalValue(Result);
|
||||||
|
Result:=TResEvalInt.CreateValue(-MaxPrecInt(UInt));
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// switch to float
|
||||||
|
ReleaseEvalValue(Result);
|
||||||
|
Result:=TResEvalFloat.CreateValue(-MaxPrecFloat(UInt));
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
revkFloat:
|
revkFloat:
|
||||||
begin
|
begin
|
||||||
@ -2810,6 +2879,15 @@ end;
|
|||||||
|
|
||||||
function TResExprEvaluator.EvalSetParamsExpr(Expr: TParamsExpr;
|
function TResExprEvaluator.EvalSetParamsExpr(Expr: TParamsExpr;
|
||||||
Flags: TResEvalFlags): TResEvalSet;
|
Flags: TResEvalFlags): TResEvalSet;
|
||||||
|
begin
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TResExprEvaluator.EvalSetParamsExpr length(Expr.Params)=',length(Expr.Params));
|
||||||
|
{$ENDIF}
|
||||||
|
Result:=EvalSetExpr(Expr,Expr.Params,Flags);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TResExprEvaluator.EvalSetExpr(Expr: TPasExpr;
|
||||||
|
ExprArray: TPasExprArray; Flags: TResEvalFlags): TResEvalSet;
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
RangeStart, RangeEnd: MaxPrecInt;
|
RangeStart, RangeEnd: MaxPrecInt;
|
||||||
@ -2818,18 +2896,18 @@ var
|
|||||||
El: TPasExpr;
|
El: TPasExpr;
|
||||||
begin
|
begin
|
||||||
{$IFDEF VerbosePasResEval}
|
{$IFDEF VerbosePasResEval}
|
||||||
writeln('TResExprEvaluator.EvalSetParamsExpr length(Expr.Params)=',length(Expr.Params));
|
writeln('TResExprEvaluator.EvalSetExpr Expr=',GetObjName(Expr),' length(ExprArray)=',length(ExprArray));
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
Result:=TResEvalSet.Create;
|
Result:=TResEvalSet.Create;
|
||||||
Value:=nil;
|
Value:=nil;
|
||||||
OnlyConstElements:=true;
|
OnlyConstElements:=true;
|
||||||
ok:=false;
|
ok:=false;
|
||||||
try
|
try
|
||||||
for i:=0 to length(Expr.Params)-1 do
|
for i:=0 to length(ExprArray)-1 do
|
||||||
begin
|
begin
|
||||||
El:=Expr.Params[i];
|
El:=ExprArray[i];
|
||||||
{$IFDEF VerbosePasResEval}
|
{$IFDEF VerbosePasResEval}
|
||||||
writeln('TResExprEvaluator.EvalSetParamsExpr ',i,' of ',length(Expr.Params),' El=',GetObjName(El));
|
writeln('TResExprEvaluator.EvalSetExpr ',i,' of ',length(ExprArray),' El=',GetObjName(El));
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
Value:=Eval(El,Flags);
|
Value:=Eval(El,Flags);
|
||||||
if Value=nil then
|
if Value=nil then
|
||||||
@ -2839,7 +2917,7 @@ begin
|
|||||||
continue;
|
continue;
|
||||||
end;
|
end;
|
||||||
{$IFDEF VerbosePasResEval}
|
{$IFDEF VerbosePasResEval}
|
||||||
//writeln('TResExprEvaluator.EvalSetParamsExpr ',i,' of ',length(Expr.Params),' Value=',Value.AsDebugString);
|
//writeln('TResExprEvaluator.EvalSetExpr ',i,' of ',length(ExprArray),' Value=',Value.AsDebugString);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
case Value.Kind of
|
case Value.Kind of
|
||||||
revkBool:
|
revkBool:
|
||||||
@ -2904,7 +2982,7 @@ begin
|
|||||||
end
|
end
|
||||||
else if Result.ElKind<>revskEnum then
|
else if Result.ElKind<>revskEnum then
|
||||||
RaiseNotYetImplemented(20170713143559,El)
|
RaiseNotYetImplemented(20170713143559,El)
|
||||||
else if Result.ElType<>Value.IdentEl.Parent then
|
else if Result.ElType<>TResEvalEnum(Value).ElType then
|
||||||
RaiseNotYetImplemented(20170713201021,El);
|
RaiseNotYetImplemented(20170713201021,El);
|
||||||
RangeStart:=TResEvalEnum(Value).Index;
|
RangeStart:=TResEvalEnum(Value).Index;
|
||||||
RangeEnd:=RangeStart;
|
RangeEnd:=RangeStart;
|
||||||
@ -2937,7 +3015,7 @@ begin
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
{$IF defined(VerbosePasResEval) or defined(VerbosePasResolver)}
|
{$IF defined(VerbosePasResEval) or defined(VerbosePasResolver)}
|
||||||
writeln('TResExprEvaluator.EvalSetParamsExpr Result.ElKind=',Result.ElKind,' Value.Kind=',Value.Kind);
|
writeln('TResExprEvaluator.EvalSetExpr Result.ElKind=',Result.ElKind,' Value.Kind=',Value.Kind);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
RaiseNotYetImplemented(20170713143422,El);
|
RaiseNotYetImplemented(20170713143422,El);
|
||||||
end;
|
end;
|
||||||
@ -2945,7 +3023,7 @@ begin
|
|||||||
if Result.Intersects(RangeStart,RangeEnd)>=0 then
|
if Result.Intersects(RangeStart,RangeEnd)>=0 then
|
||||||
begin
|
begin
|
||||||
{$IF defined(VerbosePasResEval) or defined(VerbosePasResolver)}
|
{$IF defined(VerbosePasResEval) or defined(VerbosePasResolver)}
|
||||||
writeln('TResExprEvaluator.EvalSetParamsExpr Value=',Value.AsDebugString,' Range=',RangeStart,'..',RangeEnd,' Result=',Result.AsDebugString);
|
writeln('TResExprEvaluator.EvalSetExpr Value=',Value.AsDebugString,' Range=',RangeStart,'..',RangeEnd,' Result=',Result.AsDebugString);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
RaiseMsg(20170714141326,nRangeCheckInSetConstructor,
|
RaiseMsg(20170714141326,nRangeCheckInSetConstructor,
|
||||||
sRangeCheckInSetConstructor,[],El);
|
sRangeCheckInSetConstructor,[],El);
|
||||||
@ -2960,6 +3038,15 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TResExprEvaluator.EvalArrayValuesExpr(Expr: TArrayValues;
|
||||||
|
Flags: TResEvalFlags): TResEvalSet;
|
||||||
|
begin
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TResExprEvaluator.EvalArrayValuesExpr length(Expr.Values)=',length(Expr.Values));
|
||||||
|
{$ENDIF}
|
||||||
|
Result:=EvalSetExpr(Expr,Expr.Values,Flags);
|
||||||
|
end;
|
||||||
|
|
||||||
function TResExprEvaluator.EvalBinaryPowerExpr(Expr: TBinaryExpr; LeftValue,
|
function TResExprEvaluator.EvalBinaryPowerExpr(Expr: TBinaryExpr; LeftValue,
|
||||||
RightValue: TResEvalValue): TResEvalValue;
|
RightValue: TResEvalValue): TResEvalValue;
|
||||||
var
|
var
|
||||||
@ -3276,7 +3363,7 @@ begin
|
|||||||
pekIdent:
|
pekIdent:
|
||||||
begin
|
begin
|
||||||
Result:=OnEvalIdentifier(Self,TPrimitiveExpr(Expr),Flags);
|
Result:=OnEvalIdentifier(Self,TPrimitiveExpr(Expr),Flags);
|
||||||
writeln('TResExprEvaluator.Eval primitiv result=',Result<>nil,' ',dbgs(Result));
|
//writeln('TResExprEvaluator.Eval primitiv result=',Result<>nil,' ',dbgs(Result));
|
||||||
end;
|
end;
|
||||||
pekNumber:
|
pekNumber:
|
||||||
begin
|
begin
|
||||||
@ -3284,6 +3371,11 @@ begin
|
|||||||
val(TPrimitiveExpr(Expr).Value,Int,Code);
|
val(TPrimitiveExpr(Expr).Value,Int,Code);
|
||||||
if Code=0 then
|
if Code=0 then
|
||||||
begin
|
begin
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TResExprEvaluator.Eval Int=',Int,' Value="',TPrimitiveExpr(Expr).Value,'"');
|
||||||
|
{$ENDIF}
|
||||||
|
if (Int<0) and (Pos('-',TPrimitiveExpr(Expr).Value)<1) then
|
||||||
|
RaiseInternalError(20170802141254,'bug in FPC str()');
|
||||||
Result:=TResEvalInt.CreateValue(Int);
|
Result:=TResEvalInt.CreateValue(Int);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -3292,6 +3384,9 @@ begin
|
|||||||
if Code=0 then
|
if Code=0 then
|
||||||
begin
|
begin
|
||||||
Result:=TResEvalUInt.CreateValue(UInt);
|
Result:=TResEvalUInt.CreateValue(UInt);
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TResExprEvaluator.Eval UInt=',UInt,' Value="',TPrimitiveExpr(Expr).Value,'"');
|
||||||
|
{$ENDIF}
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
// try float
|
// try float
|
||||||
@ -3299,6 +3394,9 @@ begin
|
|||||||
if Code=0 then
|
if Code=0 then
|
||||||
begin
|
begin
|
||||||
Result:=TResEvalFloat.CreateValue(Flo);
|
Result:=TResEvalFloat.CreateValue(Flo);
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TResExprEvaluator.Eval Float=',Flo,' Value="',TPrimitiveExpr(Expr).Value,'"');
|
||||||
|
{$ENDIF}
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
RaiseRangeCheck(20170518202252,Expr);
|
RaiseRangeCheck(20170518202252,Expr);
|
||||||
@ -3323,6 +3421,8 @@ begin
|
|||||||
Result:=EvalBinaryExpr(TBinaryExpr(Expr),Flags)
|
Result:=EvalBinaryExpr(TBinaryExpr(Expr),Flags)
|
||||||
else if C=TParamsExpr then
|
else if C=TParamsExpr then
|
||||||
Result:=EvalParamsExpr(TParamsExpr(Expr),Flags)
|
Result:=EvalParamsExpr(TParamsExpr(Expr),Flags)
|
||||||
|
else if C=TArrayValues then
|
||||||
|
Result:=EvalArrayValuesExpr(TArrayValues(Expr),Flags)
|
||||||
else if refConst in Flags then
|
else if refConst in Flags then
|
||||||
RaiseConstantExprExp(20170518213800,Expr);
|
RaiseConstantExprExp(20170518213800,Expr);
|
||||||
writeln('TResExprEvaluator.Eval END ',Expr.ClassName,' result=',Result<>nil,' ',dbgs(Result));
|
writeln('TResExprEvaluator.Eval END ',Expr.ClassName,' result=',Result<>nil,' ',dbgs(Result));
|
||||||
@ -4225,6 +4325,16 @@ begin
|
|||||||
str(FloatValue,Result);
|
str(FloatValue,Result);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TResEvalFloat.IsInt(out Int: MaxPrecInt): boolean;
|
||||||
|
begin
|
||||||
|
Int:=0;
|
||||||
|
if Frac(FloatValue)<>0 then exit(false);
|
||||||
|
if FloatValue<MaxPrecFloat(low(MaxPrecInt)) then exit(false);
|
||||||
|
if FloatValue>MaxPrecFloat(high(MaxPrecInt)) then exit(false);
|
||||||
|
Int:=Trunc(FloatValue);
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TResEvalString }
|
{ TResEvalString }
|
||||||
|
|
||||||
constructor TResEvalString.Create;
|
constructor TResEvalString.Create;
|
||||||
|
@ -137,9 +137,7 @@ Works:
|
|||||||
- dotted unitnames
|
- dotted unitnames
|
||||||
- eval:
|
- eval:
|
||||||
- nil, true, false
|
- nil, true, false
|
||||||
|
- range checking:
|
||||||
ToDo:
|
|
||||||
- range checking:
|
|
||||||
- integer ranges
|
- integer ranges
|
||||||
- boolean ranges
|
- boolean ranges
|
||||||
- enum ranges
|
- enum ranges
|
||||||
@ -148,12 +146,16 @@ ToDo:
|
|||||||
- =, <>, <, <=, >, >=
|
- =, <>, <, <=, >, >=
|
||||||
- ord(), low(), high(), pred(), succ(), length()
|
- ord(), low(), high(), pred(), succ(), length()
|
||||||
- string[index]
|
- string[index]
|
||||||
- arr[index]
|
|
||||||
- call(param)
|
- call(param)
|
||||||
- indexedprop[param]
|
|
||||||
- a:=value
|
- a:=value
|
||||||
- set+set, set*set, set-set
|
|
||||||
|
ToDo:
|
||||||
|
- range checking:
|
||||||
|
- arr[index]
|
||||||
|
- indexedprop[param]
|
||||||
- case-of unique
|
- case-of unique
|
||||||
|
- defaultvalue
|
||||||
|
- stored
|
||||||
- @@
|
- @@
|
||||||
- fail to write a loop var inside the loop
|
- fail to write a loop var inside the loop
|
||||||
- warn: create class with abstract methods
|
- warn: create class with abstract methods
|
||||||
@ -1367,7 +1369,7 @@ type
|
|||||||
function IsArrayType(const ResolvedEl: TPasResolverResult): boolean;
|
function IsArrayType(const ResolvedEl: TPasResolverResult): boolean;
|
||||||
function IsTypeCast(Params: TParamsExpr): boolean;
|
function IsTypeCast(Params: TParamsExpr): boolean;
|
||||||
function ProcNeedsParams(El: TPasProcedureType): boolean;
|
function ProcNeedsParams(El: TPasProcedureType): boolean;
|
||||||
function GetRangeLength(RangeResolved: TPasResolverResult): integer;
|
function GetRangeLength(const RangeResolved: TPasResolverResult): MaxPrecInt;
|
||||||
function HasTypeInfo(El: TPasType): boolean; virtual;
|
function HasTypeInfo(El: TPasType): boolean; virtual;
|
||||||
function GetActualBaseType(bt: TResolverBaseType): TResolverBaseType; virtual;
|
function GetActualBaseType(bt: TResolverBaseType): TResolverBaseType; virtual;
|
||||||
function GetCombinedBoolean(Bool1, Bool2: TResolverBaseType; ErrorEl: TPasElement): TResolverBaseType; virtual;
|
function GetCombinedBoolean(Bool1, Bool2: TResolverBaseType; ErrorEl: TPasElement): TResolverBaseType; virtual;
|
||||||
@ -1652,6 +1654,8 @@ procedure SetResolverIdentifier(out ResolvedType: TPasResolverResult;
|
|||||||
BaseType: TResolverBaseType; IdentEl: TPasElement; TypeEl: TPasType;
|
BaseType: TResolverBaseType; IdentEl: TPasElement; TypeEl: TPasType;
|
||||||
Flags: TPasResolverResultFlags);
|
Flags: TPasResolverResultFlags);
|
||||||
begin
|
begin
|
||||||
|
if IdentEl is TPasExpr then
|
||||||
|
raise Exception.Create('20170729101017');
|
||||||
ResolvedType.BaseType:=BaseType;
|
ResolvedType.BaseType:=BaseType;
|
||||||
ResolvedType.SubType:=btNone;
|
ResolvedType.SubType:=btNone;
|
||||||
ResolvedType.IdentEl:=IdentEl;
|
ResolvedType.IdentEl:=IdentEl;
|
||||||
@ -6437,6 +6441,7 @@ begin
|
|||||||
ResolvedEl:=LeftResolved;
|
ResolvedEl:=LeftResolved;
|
||||||
ResolvedEl.SubType:=ResolvedEl.BaseType;
|
ResolvedEl.SubType:=ResolvedEl.BaseType;
|
||||||
ResolvedEl.BaseType:=btRange;
|
ResolvedEl.BaseType:=btRange;
|
||||||
|
ResolvedEl.ExprEl:=Bin;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -10977,7 +10982,22 @@ begin
|
|||||||
or (MaxVal<MaxPrecInt(TResEvalUInt(RValue).UInt)) then
|
or (MaxVal<MaxPrecInt(TResEvalUInt(RValue).UInt)) then
|
||||||
fExprEvaluator.EmitRangeCheckConst(20170530093616,
|
fExprEvaluator.EmitRangeCheckConst(20170530093616,
|
||||||
IntToStr(TResEvalUInt(RValue).UInt),IntToStr(MinVal),IntToStr(MaxVal),RHS);
|
IntToStr(TResEvalUInt(RValue).UInt),IntToStr(MinVal),IntToStr(MaxVal),RHS);
|
||||||
|
revkFloat:
|
||||||
|
if TResEvalFloat(RValue).IsInt(Int) then
|
||||||
|
begin
|
||||||
|
if (MinVal>Int) or (MaxVal<Int) then
|
||||||
|
fExprEvaluator.EmitRangeCheckConst(20170802133307,
|
||||||
|
IntToStr(Int),MinVal,MaxVal,RHS,mtError);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
writeln('AAA1 TPasResolver.CheckAssignExprRange ',Frac(TResEvalFloat(RValue).FloatValue),' ',TResEvalFloat(RValue).FloatValue<MaxPrecFloat(low(MaxPrecInt)),' ',TResEvalFloat(RValue).FloatValue>MaxPrecFloat(high(MaxPrecInt)),' ',TResEvalFloat(RValue).FloatValue,' ',high(MaxPrecInt));
|
||||||
|
RaiseRangeCheck(20170802133750,RHS);
|
||||||
|
end;
|
||||||
else
|
else
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TPasResolver.CheckAssignExprRange ',RValue.AsDebugString);
|
||||||
|
{$ENDIF}
|
||||||
RaiseNotYetImplemented(20170530092731,RHS);
|
RaiseNotYetImplemented(20170530092731,RHS);
|
||||||
end
|
end
|
||||||
else if LeftResolved.BaseType=btQWord then
|
else if LeftResolved.BaseType=btQWord then
|
||||||
@ -11283,23 +11303,28 @@ begin
|
|||||||
Result:=CheckAssignCompatibilityArrayType(LHS,RHS,ErrorEl,RaiseOnIncompatible);
|
Result:=CheckAssignCompatibilityArrayType(LHS,RHS,ErrorEl,RaiseOnIncompatible);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$IFDEF VerbosePasResolver}
|
|
||||||
writeln('TPasResolver.CheckAssignResCompatibility incompatible LHS='+GetResolverResultDbg(LHS)+' RHS='+GetResolverResultDbg(RHS));
|
|
||||||
{$ENDIF}
|
|
||||||
if (Result>=0) and (Result<cIncompatible) then
|
if (Result>=0) and (Result<cIncompatible) then
|
||||||
begin
|
begin
|
||||||
// type fits -> check readable
|
// type fits -> check readable
|
||||||
if not (rrfReadable in RHS.Flags) then
|
if not (rrfReadable in RHS.Flags) then
|
||||||
begin
|
begin
|
||||||
if RaiseOnIncompatible then
|
if RaiseOnIncompatible then
|
||||||
|
begin
|
||||||
|
{$IFDEF VerbosePasResolver}
|
||||||
|
writeln('TPasResolver.CheckAssignResCompatibility RHS not readable. LHS='+GetResolverResultDbg(LHS)+' RHS='+GetResolverResultDbg(RHS));
|
||||||
|
{$ENDIF}
|
||||||
RaiseMsg(20170318235637,nVariableIdentifierExpected,
|
RaiseMsg(20170318235637,nVariableIdentifierExpected,
|
||||||
sVariableIdentifierExpected,[],ErrorEl);
|
sVariableIdentifierExpected,[],ErrorEl);
|
||||||
|
end;
|
||||||
exit(cIncompatible);
|
exit(cIncompatible);
|
||||||
end;
|
end;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// incompatible
|
// incompatible
|
||||||
|
{$IFDEF VerbosePasResolver}
|
||||||
|
writeln('TPasResolver.CheckAssignResCompatibility incompatible LHS='+GetResolverResultDbg(LHS)+' RHS='+GetResolverResultDbg(RHS));
|
||||||
|
{$ENDIF}
|
||||||
if not RaiseOnIncompatible then
|
if not RaiseOnIncompatible then
|
||||||
exit(cIncompatible);
|
exit(cIncompatible);
|
||||||
|
|
||||||
@ -12046,7 +12071,7 @@ function TPasResolver.CheckAssignCompatibilityArrayType(const LHS,
|
|||||||
if IsLastRange then
|
if IsLastRange then
|
||||||
begin
|
begin
|
||||||
ComputeElement(ArrType.ElType,ElTypeResolved,[rcType]);
|
ComputeElement(ArrType.ElType,ElTypeResolved,[rcType]);
|
||||||
ElTypeResolved.IdentEl:=Range;
|
ElTypeResolved.ExprEl:=Range;
|
||||||
Include(ElTypeResolved.Flags,rrfWritable);
|
Include(ElTypeResolved.Flags,rrfWritable);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -12997,6 +13022,8 @@ begin
|
|||||||
begin
|
begin
|
||||||
ComputeElement(TPasRangeType(El).RangeExpr,ResolvedEl,[rcConstant],StartEl);
|
ComputeElement(TPasRangeType(El).RangeExpr,ResolvedEl,[rcConstant],StartEl);
|
||||||
ResolvedEl.IdentEl:=El;
|
ResolvedEl.IdentEl:=El;
|
||||||
|
if ResolvedEl.ExprEl=nil then
|
||||||
|
ResolvedEl.ExprEl:=TPasRangeType(El).RangeExpr;
|
||||||
ResolvedEl.Flags:=[];
|
ResolvedEl.Flags:=[];
|
||||||
end
|
end
|
||||||
else if ElClass=TPasSetType then
|
else if ElClass=TPasSetType then
|
||||||
@ -13380,17 +13407,57 @@ begin
|
|||||||
Result:=(El.Args.Count>0) and (TPasArgument(El.Args[0]).ValueExpr=nil);
|
Result:=(El.Args.Count>0) and (TPasArgument(El.Args[0]).ValueExpr=nil);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasResolver.GetRangeLength(RangeResolved: TPasResolverResult
|
function TPasResolver.GetRangeLength(const RangeResolved: TPasResolverResult
|
||||||
): integer;
|
): MaxPrecInt;
|
||||||
|
var
|
||||||
|
TypeEl: TPasType;
|
||||||
|
{$IFDEF EnablePasResRangeCheck}
|
||||||
|
Value: TResEvalValue;
|
||||||
|
{$ENDIF}
|
||||||
begin
|
begin
|
||||||
Result:=0;
|
Result:=0;
|
||||||
if RangeResolved.BaseType=btContext then
|
if RangeResolved.BaseType=btContext then
|
||||||
begin
|
begin
|
||||||
if RangeResolved.IdentEl is TPasEnumType then
|
if RangeResolved.IdentEl is TPasType then
|
||||||
Result:=TPasEnumType(RangeResolved.IdentEl).Values.Count;
|
begin
|
||||||
|
TypeEl:=ResolveAliasType(TPasType(RangeResolved.IdentEl));
|
||||||
|
if TypeEl<>nil then
|
||||||
|
begin
|
||||||
|
if TypeEl.ClassType=TPasEnumType then
|
||||||
|
Result:=TPasEnumType(TypeEl).Values.Count;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else if RangeResolved.ExprEl<>nil then
|
||||||
|
begin
|
||||||
|
{$IFDEF EnablePasResRangeCheck}
|
||||||
|
Value:=Eval(RangeResolved.ExprEl,[]);
|
||||||
|
if Value=nil then
|
||||||
|
RaiseMsg(20170729094135,nIncompatibleTypesGotExpected,
|
||||||
|
sIncompatibleTypesGotExpected,
|
||||||
|
[GetResolverResultDescription(RangeResolved),'range'],RangeResolved.ExprEl);
|
||||||
|
try
|
||||||
|
case Value.Kind of
|
||||||
|
revkRangeInt:
|
||||||
|
Result:=TResEvalRangeInt(Value).RangeEnd-TResEvalRangeInt(Value).RangeStart+1;
|
||||||
|
else
|
||||||
|
RaiseMsg(20170729093823,nIncompatibleTypesGotExpected,
|
||||||
|
sIncompatibleTypesGotExpected,
|
||||||
|
[GetResolverResultDescription(RangeResolved),'range'],RangeResolved.ExprEl);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
ReleaseEvalValue(Value);
|
||||||
|
end;
|
||||||
|
{$ELSE}
|
||||||
|
Result:=2;
|
||||||
|
{$ENDIF}
|
||||||
end
|
end
|
||||||
else if RangeResolved.BaseType in btAllBooleans then
|
else if RangeResolved.BaseType in btAllBooleans then
|
||||||
Result:=2;
|
Result:=2;
|
||||||
|
{$IFDEF VerbosePasResolver}
|
||||||
|
//if Result=0 then
|
||||||
|
writeln('TPasResolver.GetRangeLength ',GetResolverResultDbg(RangeResolved),' Result=',Result);
|
||||||
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasResolver.HasTypeInfo(El: TPasType): boolean;
|
function TPasResolver.HasTypeInfo(El: TPasType): boolean;
|
||||||
|
@ -237,6 +237,7 @@ type
|
|||||||
Procedure TestEnumSet_AnonymousEnumtype;
|
Procedure TestEnumSet_AnonymousEnumtype;
|
||||||
Procedure TestEnumSet_AnonymousEnumtypeName;
|
Procedure TestEnumSet_AnonymousEnumtypeName;
|
||||||
Procedure TestEnumSet_Const;
|
Procedure TestEnumSet_Const;
|
||||||
|
Procedure TestSet_IntRange_Const;
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
Procedure TestPrgAssignment;
|
Procedure TestPrgAssignment;
|
||||||
@ -552,6 +553,7 @@ type
|
|||||||
Procedure TestArray_TypeCastWrongElTypeFail;
|
Procedure TestArray_TypeCastWrongElTypeFail;
|
||||||
Procedure TestArray_ConstDynArrayWrite;
|
Procedure TestArray_ConstDynArrayWrite;
|
||||||
Procedure TestArray_ConstOpenArrayWriteFail;
|
Procedure TestArray_ConstOpenArrayWriteFail;
|
||||||
|
Procedure TestArray_Static_Const;
|
||||||
|
|
||||||
// static arrays
|
// static arrays
|
||||||
Procedure TestArrayIntRange_OutOfRange;
|
Procedure TestArrayIntRange_OutOfRange;
|
||||||
@ -3022,6 +3024,21 @@ begin
|
|||||||
CheckResolverUnexpectedHints;
|
CheckResolverUnexpectedHints;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestResolver.TestSet_IntRange_Const;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'type',
|
||||||
|
' TIntRg = 2..6;',
|
||||||
|
' TSevenSet = set of TIntRg;',
|
||||||
|
'const',
|
||||||
|
' a: TSevenSet = [2..3,5]+[4];',
|
||||||
|
' b = low(TIntRg)+high(TIntRg);',
|
||||||
|
'begin']);
|
||||||
|
ParseProgram;
|
||||||
|
CheckResolverUnexpectedHints;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestResolver.TestPrgAssignment;
|
procedure TTestResolver.TestPrgAssignment;
|
||||||
var
|
var
|
||||||
El: TPasElement;
|
El: TPasElement;
|
||||||
@ -8916,6 +8933,22 @@ begin
|
|||||||
CheckResolverException('Variable identifier expected',nVariableIdentifierExpected);
|
CheckResolverException('Variable identifier expected',nVariableIdentifierExpected);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestResolver.TestArray_Static_Const;
|
||||||
|
begin
|
||||||
|
{$IFDEF EnablePasResRangeCheck}
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'type',
|
||||||
|
' TIntArr = array[1..3] of longint;',
|
||||||
|
'const',
|
||||||
|
' a = low(TIntArr)+high(TIntArr);',
|
||||||
|
' b: array[1..3] of longint = (10,11,12);',
|
||||||
|
'begin']);
|
||||||
|
ParseProgram;
|
||||||
|
CheckResolverUnexpectedHints;
|
||||||
|
{$ENDIF}
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestResolver.TestArrayIntRange_OutOfRange;
|
procedure TTestResolver.TestArrayIntRange_OutOfRange;
|
||||||
begin
|
begin
|
||||||
StartProgram(false);
|
StartProgram(false);
|
||||||
|
Loading…
Reference in New Issue
Block a user