mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-18 13:09:18 +02:00
fcl-passrc: const eval: pred(), succ(), ord()
git-svn-id: trunk@36601 -
This commit is contained in:
parent
84b08b61a8
commit
8935b3c05c
@ -17,42 +17,45 @@ Abstract:
|
|||||||
Evaluation of Pascal constants.
|
Evaluation of Pascal constants.
|
||||||
|
|
||||||
Works:
|
Works:
|
||||||
- Emitting range check warnings
|
- Emitting range check warnings
|
||||||
- Error on overflow
|
- Error on overflow
|
||||||
- bool: not, =, <>, and, or, xor, low(), high()
|
- bool: not, =, <>, and, or, xor, low(), high(), pred(), succ(), ord()
|
||||||
- int/uint
|
- int/uint
|
||||||
- unary +, -
|
- unary +, -
|
||||||
- binary: +, -, *, div, mod, ^^, =, <>, <, >, <=, >=, and, or, xor, not
|
- binary: +, -, *, div, mod, ^^, =, <>, <, >, <=, >=, and, or, xor, not
|
||||||
- string: +
|
- low(), high(), pred(), succ(), ord()
|
||||||
- float:
|
- typecast int
|
||||||
- enum/set
|
- string:
|
||||||
|
- +
|
||||||
|
- pred(), succ()
|
||||||
|
- float:
|
||||||
|
- enum/set
|
||||||
|
|
||||||
ToDo:
|
ToDo:
|
||||||
- enable eval via option, default off
|
- enable eval via option, default off
|
||||||
- bool:
|
- bool:
|
||||||
- low(), high(), pred(), succ(), ord()
|
- boolean(1)
|
||||||
- int
|
- int
|
||||||
- typecast
|
- typecast intsingle(-1), uintsingle(-1), longint(-1)
|
||||||
- low(), high(), pred(), succ()
|
- string:
|
||||||
- string:
|
- =, <>, <, >, <=, >=
|
||||||
- =, <>, <, >, <=, >=
|
- string encoding
|
||||||
- string encoding
|
- s[]
|
||||||
- s[]
|
- length(string)
|
||||||
- length(string)
|
- chr(), ord(), low(), high()
|
||||||
- chr(), ord(), low(), high(), pred(), succ()
|
- #65
|
||||||
- #65
|
- #$DC00
|
||||||
- #$DC00
|
- float
|
||||||
- float
|
- typecast float
|
||||||
- typecast float
|
- /
|
||||||
- /
|
- +, -, *, div, mod, ^^, =, <>, <, >, <=, >=, and, or, xor, not
|
||||||
- +, -, *, div, mod, ^^, =, <>, <, >, <=, >=, and, or, xor, not
|
- enum
|
||||||
- enum
|
- low(), high(), pred(), succ(), ord(), typecast
|
||||||
- low(), high(), pred(), succ(), ord(), typecast
|
- sets
|
||||||
- sets
|
- [a,b,c..d]
|
||||||
- [a,b,c..d]
|
- +, -, *, =, <>, <=, >=, in, ><
|
||||||
- +, -, *, =, <>, <=, >=, in, ><
|
- arrays
|
||||||
- arrays
|
- length(), low(), high()
|
||||||
- length(), low(), high()
|
|
||||||
}
|
}
|
||||||
unit PasResolveEval;
|
unit PasResolveEval;
|
||||||
|
|
||||||
@ -235,6 +238,16 @@ const
|
|||||||
// possibly resulting in a range check error -> using a qword const instead
|
// possibly resulting in a range check error -> using a qword const instead
|
||||||
HighIntAsUInt = MaxPrecUInt(High(MaxPrecInt));
|
HighIntAsUInt = MaxPrecUInt(High(MaxPrecInt));
|
||||||
|
|
||||||
|
const
|
||||||
|
MinSafeIntCurrency = -922337203685477;
|
||||||
|
MaxSafeIntCurrency = 922337203685477;
|
||||||
|
MinSafeIntSingle = -16777216;
|
||||||
|
MaxSafeIntSingle = 16777216;
|
||||||
|
MaskUIntSingle = $3fffff;
|
||||||
|
MinSafeIntDouble = -$10000000000000;
|
||||||
|
MaxSafeIntDouble = $fffffffffffff;
|
||||||
|
MaskUIntDouble = $fffffffffffff;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ TResEvalValue }
|
{ TResEvalValue }
|
||||||
|
|
||||||
@ -276,15 +289,38 @@ type
|
|||||||
function AsString: string; override;
|
function AsString: string; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TResEvalTypedInt = (
|
||||||
|
reitNone,
|
||||||
|
reitByte,
|
||||||
|
reitShortInt,
|
||||||
|
reitWord,
|
||||||
|
reitSmallInt,
|
||||||
|
reitUIntSingle,
|
||||||
|
reitIntSingle,
|
||||||
|
reitLongWord,
|
||||||
|
reitLongInt,
|
||||||
|
reitUIntDouble,
|
||||||
|
reitIntDouble);
|
||||||
|
TResEvalTypedInts = set of TResEvalTypedInt;
|
||||||
|
|
||||||
|
const
|
||||||
|
reitDefaults = [reitNone,reitByte,reitShortInt,reitWord,reitSmallInt,reitLongWord,reitLongInt];
|
||||||
|
reitAllSigned = [reitNone,reitShortInt,reitSmallInt,reitIntSingle,reitLongInt,reitIntDouble];
|
||||||
|
reitAllUnsigned = [reitByte,reitWord,reitUIntSingle,reitLongWord,reitUIntDouble];
|
||||||
|
|
||||||
|
type
|
||||||
{ TResEvalInt }
|
{ TResEvalInt }
|
||||||
|
|
||||||
TResEvalInt = class(TResEvalValue)
|
TResEvalInt = class(TResEvalValue)
|
||||||
public
|
public
|
||||||
Int: MaxPrecInt;
|
Int: MaxPrecInt;
|
||||||
|
Typed: TResEvalTypedInt;
|
||||||
constructor Create; override;
|
constructor Create; override;
|
||||||
constructor CreateValue(const aValue: MaxPrecInt);
|
constructor CreateValue(const aValue: MaxPrecInt);
|
||||||
|
constructor CreateValue(const aValue: MaxPrecInt; aTyped: TResEvalTypedInt);
|
||||||
function Clone: TResEvalValue; override;
|
function Clone: TResEvalValue; override;
|
||||||
function AsString: string; override;
|
function AsString: string; override;
|
||||||
|
function AsDebugString: string; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TResEvalUInt }
|
{ TResEvalUInt }
|
||||||
@ -421,6 +457,7 @@ type
|
|||||||
|
|
||||||
TResExprEvaluator = class
|
TResExprEvaluator = class
|
||||||
private
|
private
|
||||||
|
FAllowedInts: TResEvalTypedInts;
|
||||||
FOnEvalIdentifier: TPasResEvalIdentHandler;
|
FOnEvalIdentifier: TPasResEvalIdentHandler;
|
||||||
FOnEvalParams: TPasResEvalParamsHandler;
|
FOnEvalParams: TPasResEvalParamsHandler;
|
||||||
FOnLog: TPasResEvalLogHandler;
|
FOnLog: TPasResEvalLogHandler;
|
||||||
@ -453,8 +490,21 @@ type
|
|||||||
function EvalSetParams(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
|
function EvalSetParams(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
|
||||||
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 SuccBool(Value: TResEvalBool; ErrorEl: TPasElement);
|
||||||
|
procedure PredInt(Value: TResEvalInt; ErrorEl: TPasElement);
|
||||||
|
procedure SuccInt(Value: TResEvalInt; ErrorEl: TPasElement);
|
||||||
|
procedure PredUInt(Value: TResEvalUInt; ErrorEl: TPasElement);
|
||||||
|
procedure SuccUInt(Value: TResEvalUInt; ErrorEl: TPasElement);
|
||||||
|
procedure PredString(Value: TResEvalString; ErrorEl: TPasElement);
|
||||||
|
procedure SuccString(Value: TResEvalString; ErrorEl: TPasElement);
|
||||||
|
procedure PredUnicodeString(Value: TResEvalUTF16; ErrorEl: TPasElement);
|
||||||
|
procedure SuccUnicodeString(Value: TResEvalUTF16; ErrorEl: TPasElement);
|
||||||
|
procedure PredEnum(Value: TResEvalEnum; ErrorEl: TPasElement);
|
||||||
|
procedure SuccEnum(Value: TResEvalEnum; ErrorEl: TPasElement);
|
||||||
function CreateResEvalInt(UInt: MaxPrecUInt): TResEvalValue; virtual;
|
function CreateResEvalInt(UInt: MaxPrecUInt): TResEvalValue; virtual;
|
||||||
public
|
public
|
||||||
|
constructor Create;
|
||||||
function Eval(Expr: TPasExpr; Flags: TResEvalFlags): TResEvalValue;
|
function Eval(Expr: TPasExpr; Flags: TResEvalFlags): TResEvalValue;
|
||||||
function IsInRange(Expr, RangeExpr: TPasExpr; EmitHints: boolean): boolean;
|
function IsInRange(Expr, RangeExpr: TPasExpr; EmitHints: boolean): boolean;
|
||||||
function IsConst(Expr: TPasExpr): boolean;
|
function IsConst(Expr: TPasExpr): boolean;
|
||||||
@ -463,9 +513,13 @@ type
|
|||||||
PosEl: TPasElement); virtual;
|
PosEl: TPasElement); virtual;
|
||||||
procedure EmitRangeCheckConst(id: int64; const aValue: String;
|
procedure EmitRangeCheckConst(id: int64; const aValue: String;
|
||||||
MinVal, MaxVal: MaxPrecInt; PosEl: TPasElement);
|
MinVal, MaxVal: MaxPrecInt; PosEl: TPasElement);
|
||||||
|
function OrdValue(Value: TResEvalValue; ErrorEl: TPasElement): TResEvalInt; virtual;
|
||||||
|
procedure PredValue(Value: TResEvalValue; ErrorEl: TPasElement); virtual;
|
||||||
|
procedure SuccValue(Value: TResEvalValue; ErrorEl: TPasElement); virtual;
|
||||||
property OnLog: TPasResEvalLogHandler read FOnLog write FOnLog;
|
property OnLog: TPasResEvalLogHandler read FOnLog write FOnLog;
|
||||||
property OnEvalIdentifier: TPasResEvalIdentHandler read FOnEvalIdentifier write FOnEvalIdentifier;
|
property OnEvalIdentifier: TPasResEvalIdentHandler read FOnEvalIdentifier write FOnEvalIdentifier;
|
||||||
property OnEvalParams: TPasResEvalParamsHandler read FOnEvalParams write FOnEvalParams;
|
property OnEvalParams: TPasResEvalParamsHandler read FOnEvalParams write FOnEvalParams;
|
||||||
|
property AllowedInts: TResEvalTypedInts read FAllowedInts write FAllowedInts;
|
||||||
end;
|
end;
|
||||||
TResExprEvaluatorClass = class of TResExprEvaluator;
|
TResExprEvaluatorClass = class of TResExprEvaluator;
|
||||||
|
|
||||||
@ -869,7 +923,13 @@ begin
|
|||||||
if TResEvalInt(Result).Int=0 then exit;
|
if TResEvalInt(Result).Int=0 then exit;
|
||||||
if Result.Element<>nil then
|
if Result.Element<>nil then
|
||||||
Result:=Result.Clone;
|
Result:=Result.Clone;
|
||||||
TResEvalInt(Result).Int:=-TResEvalInt(Result).Int;
|
if TResEvalInt(Result).Int=0 then exit;
|
||||||
|
if not (TResEvalInt(Result).Typed in reitAllSigned) then
|
||||||
|
begin
|
||||||
|
// switch to untyped
|
||||||
|
TResEvalInt(Result).Typed:=reitNone;
|
||||||
|
end;
|
||||||
|
TResEvalInt(Result).Int:=-TResEvalInt(Result).Int
|
||||||
end;
|
end;
|
||||||
revkUInt:
|
revkUInt:
|
||||||
begin
|
begin
|
||||||
@ -897,7 +957,19 @@ begin
|
|||||||
begin
|
begin
|
||||||
if Result.Element<>nil then
|
if Result.Element<>nil then
|
||||||
Result:=Result.Clone;
|
Result:=Result.Clone;
|
||||||
TResEvalInt(Result).Int:=not TResEvalInt(Result).Int;
|
case TResEvalInt(Result).Typed of
|
||||||
|
reitByte: TResEvalInt(Result).Int:=not byte(TResEvalInt(Result).Int);
|
||||||
|
reitShortInt: TResEvalInt(Result).Int:=not shortint(TResEvalInt(Result).Int);
|
||||||
|
reitWord: TResEvalInt(Result).Int:=not word(TResEvalInt(Result).Int);
|
||||||
|
reitSmallInt: TResEvalInt(Result).Int:=not smallint(TResEvalInt(Result).Int);
|
||||||
|
reitUIntSingle: TResEvalInt(Result).Int:=(not TResEvalInt(Result).Int) and $3fffff;
|
||||||
|
reitIntSingle: TResEvalInt(Result).Int:=(not TResEvalInt(Result).Int) and $7fffff;
|
||||||
|
reitLongWord: TResEvalInt(Result).Int:=not longword(TResEvalInt(Result).Int);
|
||||||
|
reitLongInt: TResEvalInt(Result).Int:=not longint(TResEvalInt(Result).Int);
|
||||||
|
reitUIntDouble: TResEvalInt(Result).Int:=(not TResEvalInt(Result).Int) and $fffffffffffff;
|
||||||
|
reitIntDouble: TResEvalInt(Result).Int:=(not TResEvalInt(Result).Int) and $1fffffffffffff;
|
||||||
|
else TResEvalInt(Result).Int:=not TResEvalInt(Result).Int;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
revkUInt:
|
revkUInt:
|
||||||
begin
|
begin
|
||||||
@ -1945,7 +2017,7 @@ begin
|
|||||||
writeln('TResExprEvaluator.EvalArrayParams ');
|
writeln('TResExprEvaluator.EvalArrayParams ');
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
if refConst in Flags then
|
if refConst in Flags then
|
||||||
RaiseConstantExprExp(20170522173150,Expr);
|
RaiseConstantExprExp(20170522173151,Expr);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TResExprEvaluator.EvalFuncParams(Expr: TParamsExpr;
|
function TResExprEvaluator.EvalFuncParams(Expr: TParamsExpr;
|
||||||
@ -1973,7 +2045,7 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
if refConst in Flags then
|
if refConst in Flags then
|
||||||
RaiseConstantExprExp(20170522173150,Expr);
|
RaiseConstantExprExp(20170522173152,Expr);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TResExprEvaluator.ExprStringToOrd(Value: TResEvalValue;
|
function TResExprEvaluator.ExprStringToOrd(Value: TResEvalValue;
|
||||||
@ -2187,6 +2259,12 @@ begin
|
|||||||
Result:=TResEvalUInt.CreateValue(UInt);
|
Result:=TResEvalUInt.CreateValue(UInt);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
constructor TResExprEvaluator.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FAllowedInts:=ReitDefaults;
|
||||||
|
end;
|
||||||
|
|
||||||
function TResExprEvaluator.Eval(Expr: TPasExpr; Flags: TResEvalFlags
|
function TResExprEvaluator.Eval(Expr: TPasExpr; Flags: TResEvalFlags
|
||||||
): TResEvalValue;
|
): TResEvalValue;
|
||||||
var
|
var
|
||||||
@ -2203,7 +2281,7 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
{$IFDEF VerbosePasResEval}
|
{$IFDEF VerbosePasResEval}
|
||||||
writeln('TPasResolver.Eval Expr=',GetObjName(Expr),' Flags=',dbgs(Flags));
|
writeln('TResExprEvaluator.Eval Expr=',GetObjName(Expr),' Flags=',dbgs(Flags));
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
if refAutoConst in Flags then
|
if refAutoConst in Flags then
|
||||||
begin
|
begin
|
||||||
@ -2469,6 +2547,243 @@ begin
|
|||||||
EmitRangeCheckConst(id,aValue,IntToStr(MinVal),IntToStr(MaxVal),PosEl);
|
EmitRangeCheckConst(id,aValue,IntToStr(MinVal),IntToStr(MaxVal),PosEl);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TResExprEvaluator.OrdValue(Value: TResEvalValue; ErrorEl: TPasElement
|
||||||
|
): TResEvalInt;
|
||||||
|
begin
|
||||||
|
case Value.Kind of
|
||||||
|
revkBool:
|
||||||
|
if TResEvalBool(Value).B then
|
||||||
|
Result:=TResEvalInt.CreateValue(1)
|
||||||
|
else
|
||||||
|
Result:=TResEvalInt.CreateValue(0);
|
||||||
|
revkString:
|
||||||
|
if length(TResEvalString(Value).S)<>1 then
|
||||||
|
RaiseRangeCheck(20170624160128,ErrorEl)
|
||||||
|
else
|
||||||
|
Result:=TResEvalInt.CreateValue(ord(TResEvalString(Value).S[1]));
|
||||||
|
revkUnicodeString:
|
||||||
|
if length(TResEvalUTF16(Value).S)<>1 then
|
||||||
|
RaiseRangeCheck(20170624160129,ErrorEl)
|
||||||
|
else
|
||||||
|
Result:=TResEvalInt.CreateValue(ord(TResEvalUTF16(Value).S[1]));
|
||||||
|
revkEnum:
|
||||||
|
Result:=TResEvalInt.CreateValue(TResEvalEnum(Value).Index);
|
||||||
|
else
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TResExprEvaluator.OrdValue ',Value.AsDebugString);
|
||||||
|
{$ENDIF}
|
||||||
|
RaiseNotYetImplemented(20170624155932,ErrorEl);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.PredValue(Value: TResEvalValue; ErrorEl: TPasElement
|
||||||
|
);
|
||||||
|
begin
|
||||||
|
case Value.Kind of
|
||||||
|
revkBool:
|
||||||
|
PredBool(TResEvalBool(Value),ErrorEl);
|
||||||
|
revkInt:
|
||||||
|
PredInt(TResEvalInt(Value),ErrorEl);
|
||||||
|
revkUInt:
|
||||||
|
PredUInt(TResEvalUInt(Value),ErrorEl);
|
||||||
|
revkString:
|
||||||
|
PredString(TResEvalString(Value),ErrorEl);
|
||||||
|
revkUnicodeString:
|
||||||
|
PredUnicodeString(TResEvalUTF16(Value),ErrorEl);
|
||||||
|
revkEnum:
|
||||||
|
PredEnum(TResEvalEnum(Value),ErrorEl);
|
||||||
|
else
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TResExprEvaluator.PredValue ',Value.AsDebugString);
|
||||||
|
{$ENDIF}
|
||||||
|
ReleaseEvalValue(Value);
|
||||||
|
RaiseNotYetImplemented(20170624135738,ErrorEl);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.SuccValue(Value: TResEvalValue; ErrorEl: TPasElement
|
||||||
|
);
|
||||||
|
begin
|
||||||
|
case Value.Kind of
|
||||||
|
revkBool:
|
||||||
|
SuccBool(TResEvalBool(Value),ErrorEl);
|
||||||
|
revkInt:
|
||||||
|
SuccInt(TResEvalInt(Value),ErrorEl);
|
||||||
|
revkUInt:
|
||||||
|
SuccUInt(TResEvalUInt(Value),ErrorEl);
|
||||||
|
revkString:
|
||||||
|
SuccString(TResEvalString(Value),ErrorEl);
|
||||||
|
revkUnicodeString:
|
||||||
|
SuccUnicodeString(TResEvalUTF16(Value),ErrorEl);
|
||||||
|
revkEnum:
|
||||||
|
SuccEnum(TResEvalEnum(Value),ErrorEl);
|
||||||
|
else
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TResExprEvaluator.SuccValue ',Value.AsDebugString);
|
||||||
|
{$ENDIF}
|
||||||
|
ReleaseEvalValue(Value);
|
||||||
|
RaiseNotYetImplemented(20170624151252,ErrorEl);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.PredBool(Value: TResEvalBool; ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if Value.B=false then
|
||||||
|
EmitRangeCheckConst(20170624140251,Value.AsString,
|
||||||
|
'true','true',ErrorEl);
|
||||||
|
Value.B:=not Value.B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.SuccBool(Value: TResEvalBool; ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if Value.B=true then
|
||||||
|
EmitRangeCheckConst(20170624142316,Value.AsString,
|
||||||
|
'false','false',ErrorEl);
|
||||||
|
Value.B:=not Value.B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.PredInt(Value: TResEvalInt; ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if Value.Int=low(MaxPrecInt) then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624142511,IntToStr(Value.Int),
|
||||||
|
IntToStr(succ(low(MaxPrecInt))),IntToStr(high(MaxPrecInt)),ErrorEl);
|
||||||
|
Value.Int:=high(Value.Int);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
dec(Value.Int);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.SuccInt(Value: TResEvalInt; ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if Value.Int=high(MaxPrecInt) then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624142920,IntToStr(Value.Int),
|
||||||
|
IntToStr(low(MaxPrecInt)),IntToStr(pred(high(MaxPrecInt))),ErrorEl);
|
||||||
|
Value.Int:=low(Value.Int);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inc(Value.Int);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.PredUInt(Value: TResEvalUInt; ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if Value.UInt=low(MaxPrecUInt) then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624143122,IntToStr(Value.UInt),
|
||||||
|
IntToStr(succ(low(MaxPrecUInt))),IntToStr(high(MaxPrecUInt)),ErrorEl);
|
||||||
|
Value.UInt:=high(Value.UInt);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
dec(Value.UInt);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.SuccUInt(Value: TResEvalUInt; ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if Value.UInt=high(MaxPrecUInt) then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624142921,IntToStr(Value.UInt),
|
||||||
|
IntToStr(low(MaxPrecUInt)),IntToStr(pred(high(MaxPrecUInt))),ErrorEl);
|
||||||
|
Value.UInt:=low(Value.UInt);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inc(Value.UInt);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.PredString(Value: TResEvalString;
|
||||||
|
ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if length(Value.S)<>1 then
|
||||||
|
RaiseRangeCheck(20170624150138,ErrorEl);
|
||||||
|
if Value.S[1]=#0 then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624150220,Value.AsString,'#1','#255',ErrorEl);
|
||||||
|
Value.S:=#255;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Value.S:=pred(Value.S[1]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.SuccString(Value: TResEvalString;
|
||||||
|
ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if length(Value.S)<>1 then
|
||||||
|
RaiseRangeCheck(20170624150432,ErrorEl);
|
||||||
|
if Value.S[1]=#255 then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624150441,Value.AsString,'#0','#254',ErrorEl);
|
||||||
|
Value.S:=#0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Value.S:=succ(Value.S[1]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.PredUnicodeString(Value: TResEvalUTF16;
|
||||||
|
ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if length(Value.S)<>1 then
|
||||||
|
RaiseRangeCheck(20170624150703,ErrorEl);
|
||||||
|
if Value.S[1]=#0 then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624150710,Value.AsString,'#1','#65535',ErrorEl);
|
||||||
|
Value.S:=WideChar(#65535);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Value.S:=pred(Value.S[1]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.SuccUnicodeString(Value: TResEvalUTF16;
|
||||||
|
ErrorEl: TPasElement);
|
||||||
|
begin
|
||||||
|
if length(Value.S)<>1 then
|
||||||
|
RaiseRangeCheck(20170624150849,ErrorEl);
|
||||||
|
if Value.S[1]=#65535 then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624150910,Value.AsString,'#0','#65534',ErrorEl);
|
||||||
|
Value.S:=#0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Value.S:=succ(Value.S[1]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.PredEnum(Value: TResEvalEnum; ErrorEl: TPasElement);
|
||||||
|
var
|
||||||
|
EnumValue: TPasEnumValue;
|
||||||
|
EnumType: TPasEnumType;
|
||||||
|
begin
|
||||||
|
EnumValue:=Value.IdentEl as TPasEnumValue;
|
||||||
|
EnumType:=EnumValue.Parent as TPasEnumType;
|
||||||
|
if Value.Index<=0 then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624144332,Value.AsString,
|
||||||
|
TPasEnumValue(EnumType.Values[Min(1,EnumType.Values.Count-1)]).Name,
|
||||||
|
TPasEnumValue(EnumType.Values[EnumType.Values.Count-1]).Name,ErrorEl);
|
||||||
|
Value.Index:=EnumType.Values.Count-1;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
dec(Value.Index);
|
||||||
|
Value.IdentEl:=TPasEnumValue(EnumType.Values[Value.Index]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TResExprEvaluator.SuccEnum(Value: TResEvalEnum; ErrorEl: TPasElement);
|
||||||
|
var
|
||||||
|
EnumValue: TPasEnumValue;
|
||||||
|
EnumType: TPasEnumType;
|
||||||
|
begin
|
||||||
|
EnumValue:=Value.IdentEl as TPasEnumValue;
|
||||||
|
EnumType:=EnumValue.Parent as TPasEnumType;
|
||||||
|
if Value.Index>=EnumType.Values.Count-1 then
|
||||||
|
begin
|
||||||
|
EmitRangeCheckConst(20170624145013,Value.AsString,
|
||||||
|
TPasEnumValue(EnumType.Values[0]).Name,
|
||||||
|
TPasEnumValue(EnumType.Values[Max(0,EnumType.Values.Count-2)]).Name,ErrorEl);
|
||||||
|
Value.Index:=0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inc(Value.Index);
|
||||||
|
Value.IdentEl:=TPasEnumValue(EnumType.Values[Value.Index]);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TResolveData }
|
{ TResolveData }
|
||||||
|
|
||||||
procedure TResolveData.SetElement(AValue: TPasElement);
|
procedure TResolveData.SetElement(AValue: TPasElement);
|
||||||
@ -2571,10 +2886,19 @@ begin
|
|||||||
Int:=aValue;
|
Int:=aValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
constructor TResEvalInt.CreateValue(const aValue: MaxPrecInt; aTyped: TResEvalTypedInt
|
||||||
|
);
|
||||||
|
begin
|
||||||
|
Create;
|
||||||
|
Int:=aValue;
|
||||||
|
Typed:=aTyped;
|
||||||
|
end;
|
||||||
|
|
||||||
function TResEvalInt.Clone: TResEvalValue;
|
function TResEvalInt.Clone: TResEvalValue;
|
||||||
begin
|
begin
|
||||||
Result:=inherited Clone;
|
Result:=inherited Clone;
|
||||||
TResEvalInt(Result).Int:=Int;
|
TResEvalInt(Result).Int:=Int;
|
||||||
|
TResEvalInt(Result).Typed:=Typed;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TResEvalInt.AsString: string;
|
function TResEvalInt.AsString: string;
|
||||||
@ -2582,6 +2906,29 @@ begin
|
|||||||
Result:=IntToStr(Int);
|
Result:=IntToStr(Int);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TResEvalInt.AsDebugString: string;
|
||||||
|
begin
|
||||||
|
if Typed=reitNone then
|
||||||
|
Result:=inherited AsDebugString
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
str(Kind,Result);
|
||||||
|
case Typed of
|
||||||
|
reitByte: Result:=Result+':byte';
|
||||||
|
reitShortInt: Result:=Result+':shortint';
|
||||||
|
reitWord: Result:=Result+':word';
|
||||||
|
reitSmallInt: Result:=Result+':smallint';
|
||||||
|
reitUIntSingle: Result:=Result+':uintsingle';
|
||||||
|
reitIntSingle: Result:=Result+':intsingle';
|
||||||
|
reitLongWord: Result:=Result+':longword';
|
||||||
|
reitLongInt: Result:=Result+':longint';
|
||||||
|
reitUIntDouble: Result:=Result+':uintdouble';
|
||||||
|
reitIntDouble: Result:=Result+':intdouble';
|
||||||
|
end;
|
||||||
|
Result:=Result+'='+AsString;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TResEvalFloat }
|
{ TResEvalFloat }
|
||||||
|
|
||||||
constructor TResEvalFloat.Create;
|
constructor TResEvalFloat.Create;
|
||||||
|
@ -207,6 +207,9 @@ unit PasResolver;
|
|||||||
{$mode objfpc}{$H+}
|
{$mode objfpc}{$H+}
|
||||||
{$inline on}
|
{$inline on}
|
||||||
|
|
||||||
|
{$IFOPT Q+}{$DEFINE OverflowCheckOn}{$ENDIF}
|
||||||
|
{$IFOPT R+}{$DEFINE RangeCheckOn}{$ENDIF}
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
@ -361,14 +364,6 @@ const
|
|||||||
'range..'
|
'range..'
|
||||||
);
|
);
|
||||||
|
|
||||||
const
|
|
||||||
MinSafeIntCurrency = -922337203685477;
|
|
||||||
MaxSafeIntCurrency = 922337203685477;
|
|
||||||
MinSafeIntSingle = -16777216;
|
|
||||||
MaxSafeIntSingle = 16777216;
|
|
||||||
MinSafeIntDouble = -$10000000000000;
|
|
||||||
MaxSafeIntDouble = $fffffffffffff;
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TResolverBuiltInProc = (
|
TResolverBuiltInProc = (
|
||||||
bfCustom,
|
bfCustom,
|
||||||
@ -1093,6 +1088,7 @@ type
|
|||||||
Expr: TPrimitiveExpr; Flags: TResEvalFlags): TResEvalValue; virtual;
|
Expr: TPrimitiveExpr; Flags: TResEvalFlags): TResEvalValue; virtual;
|
||||||
function OnExprEvalParams(Sender: TResExprEvaluator;
|
function OnExprEvalParams(Sender: TResExprEvaluator;
|
||||||
Params: TParamsExpr; Flags: TResEvalFlags): TResEvalValue; virtual;
|
Params: TParamsExpr; Flags: TResEvalFlags): TResEvalValue; virtual;
|
||||||
|
function EvalBaseTypeCast(Params: TParamsExpr; bt: TResolverBaseType): TResEvalvalue;
|
||||||
function Eval(Expr: TPasExpr; Flags: TResEvalFlags; Store: boolean = true): TResEvalValue;
|
function Eval(Expr: TPasExpr; Flags: TResEvalFlags; Store: boolean = true): TResEvalValue;
|
||||||
protected
|
protected
|
||||||
// custom types (added by descendant resolvers)
|
// custom types (added by descendant resolvers)
|
||||||
@ -1140,6 +1136,8 @@ type
|
|||||||
Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
|
Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
|
||||||
procedure BI_Ord_OnGetCallResult(Proc: TResElDataBuiltInProc;
|
procedure BI_Ord_OnGetCallResult(Proc: TResElDataBuiltInProc;
|
||||||
{%H-}Params: TParamsExpr; out ResolvedEl: TPasResolverResult); virtual;
|
{%H-}Params: TParamsExpr; out ResolvedEl: TPasResolverResult); virtual;
|
||||||
|
procedure BI_Ord_OnEval(Proc: TResElDataBuiltInProc;
|
||||||
|
Params: TParamsExpr; out Evaluated: TResEvalValue); virtual;
|
||||||
function BI_LowHigh_OnGetCallCompatibility(Proc: TResElDataBuiltInProc;
|
function BI_LowHigh_OnGetCallCompatibility(Proc: TResElDataBuiltInProc;
|
||||||
Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
|
Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
|
||||||
procedure BI_LowHigh_OnGetCallResult(Proc: TResElDataBuiltInProc;
|
procedure BI_LowHigh_OnGetCallResult(Proc: TResElDataBuiltInProc;
|
||||||
@ -7333,22 +7331,56 @@ var
|
|||||||
Decl: TPasElement;
|
Decl: TPasElement;
|
||||||
C: TClass;
|
C: TClass;
|
||||||
BaseTypeData: TResElDataBaseType;
|
BaseTypeData: TResElDataBaseType;
|
||||||
|
ResolvedType: TPasResolverResult;
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
if not (Expr.CustomData is TResolvedReference) then
|
if not (Expr.CustomData is TResolvedReference) then
|
||||||
RaiseNotYetImplemented(20170518203134,Expr);
|
RaiseNotYetImplemented(20170518203134,Expr);
|
||||||
Ref:=TResolvedReference(Expr.CustomData);
|
Ref:=TResolvedReference(Expr.CustomData);
|
||||||
Decl:=Ref.Declaration;
|
Decl:=Ref.Declaration;
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TPasResolver.OnExprEvalIdentifier Value=',Expr.Value,' Decl=',GetObjName(Decl));
|
||||||
|
{$ENDIF}
|
||||||
C:=Decl.ClassType;
|
C:=Decl.ClassType;
|
||||||
if C=TPasConst then
|
if C=TPasConst then
|
||||||
begin
|
begin
|
||||||
if (TPasConst(Decl).Expr<>nil)
|
if (TPasConst(Decl).Expr<>nil)
|
||||||
and (TPasConst(Decl).IsConst or (TPasConst(Decl).VarType=nil)) then
|
and (TPasConst(Decl).IsConst or (TPasConst(Decl).VarType=nil)) then
|
||||||
begin
|
begin
|
||||||
Result:=fExprEvaluator.Eval(TPasConst(Decl).Expr,Flags);
|
if TPasConst(Decl).VarType<>nil then
|
||||||
|
begin
|
||||||
|
// typed const
|
||||||
|
ComputeElement(TPasConst(Decl).VarType,ResolvedType,[rcType]);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
ResolvedType.BaseType:=btNone;
|
||||||
|
Result:=fExprEvaluator.Eval(TPasConst(Decl).Expr,Flags+[refConst]);
|
||||||
if Result<>nil then
|
if Result<>nil then
|
||||||
begin
|
begin
|
||||||
|
if (Result.Element<>nil) and (Result.Element<>TPasConst(Decl).Expr) then
|
||||||
|
Result:=Result.Clone;
|
||||||
Result.IdentEl:=Decl;
|
Result.IdentEl:=Decl;
|
||||||
|
if TPasConst(Decl).VarType<>nil then
|
||||||
|
begin
|
||||||
|
// typed const
|
||||||
|
if Result.Kind=revkInt then
|
||||||
|
case ResolvedType.BaseType of
|
||||||
|
btByte: TResEvalInt(Result).Typed:=reitByte;
|
||||||
|
btShortInt: TResEvalInt(Result).Typed:=reitShortInt;
|
||||||
|
btWord: TResEvalInt(Result).Typed:=reitWord;
|
||||||
|
btSmallInt: TResEvalInt(Result).Typed:=reitSmallInt;
|
||||||
|
btUIntSingle: TResEvalInt(Result).Typed:=reitUIntSingle;
|
||||||
|
btIntSingle: TResEvalInt(Result).Typed:=reitIntSingle;
|
||||||
|
btLongWord: TResEvalInt(Result).Typed:=reitLongWord;
|
||||||
|
btLongint: TResEvalInt(Result).Typed:=reitLongInt;
|
||||||
|
btUIntDouble: TResEvalInt(Result).Typed:=reitUIntDouble;
|
||||||
|
btIntDouble: TResEvalInt(Result).Typed:=reitIntDouble;
|
||||||
|
btInt64: TResEvalInt(Result).Typed:=reitNone; // default
|
||||||
|
else
|
||||||
|
ReleaseEvalValue(Result);
|
||||||
|
RaiseNotYetImplemented(20170624181050,TPasConst(Decl).VarType);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -7423,6 +7455,7 @@ var
|
|||||||
Decl: TPasElement;
|
Decl: TPasElement;
|
||||||
C: TClass;
|
C: TClass;
|
||||||
BuiltInProc: TResElDataBuiltInProc;
|
BuiltInProc: TResElDataBuiltInProc;
|
||||||
|
bt: TResolverBaseType;
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
if Params.Value.CustomData is TResolvedReference then
|
if Params.Value.CustomData is TResolvedReference then
|
||||||
@ -7438,19 +7471,137 @@ begin
|
|||||||
if Decl.CustomData is TResElDataBuiltInProc then
|
if Decl.CustomData is TResElDataBuiltInProc then
|
||||||
begin
|
begin
|
||||||
BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
|
BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
|
||||||
{$IFDEF VerbosePas2JS}
|
{$IFDEF VerbosePasResEval}
|
||||||
writeln('TPasResolver.OnExprEvalParams BuiltInProc ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
|
writeln('TPasResolver.OnExprEvalParams BuiltInProc ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
case BuiltInProc.BuiltIn of
|
case BuiltInProc.BuiltIn of
|
||||||
bfLength: BI_Length_OnEval(BuiltInProc,Params,Result);
|
bfLength: BI_Length_OnEval(BuiltInProc,Params,Result);
|
||||||
|
bfOrd: BI_Ord_OnEval(BuiltInProc,Params,Result);
|
||||||
bfLow,bfHigh: BI_LowHigh_OnEval(BuiltInProc,Params,Result);
|
bfLow,bfHigh: BI_LowHigh_OnEval(BuiltInProc,Params,Result);
|
||||||
|
bfPred,bfSucc: BI_PredSucc_OnEval(BuiltInProc,Params,Result);
|
||||||
|
else
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TPasResolver.OnExprEvalParams BuiltInProc ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
|
||||||
|
{$ENDIF}
|
||||||
|
RaiseNotYetImplemented(20170624192324,Params);
|
||||||
end;
|
end;
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
if Result<>nil then
|
||||||
|
writeln('TPasResolver.OnExprEvalParams BuiltInProc ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn],' Result=',Result.AsString)
|
||||||
|
else
|
||||||
|
writeln('TPasResolver.OnExprEvalParams BuiltInProc ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn],' Result=nil');
|
||||||
|
{$ENDIF}
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else if Decl.CustomData is TResElDataBaseType then
|
||||||
|
begin
|
||||||
|
// typecast to basetype
|
||||||
|
bt:=TResElDataBaseType(Decl.CustomData).BaseType;
|
||||||
|
Result:=EvalBaseTypeCast(Params,bt);
|
||||||
end;
|
end;
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TPasResolver.OnExprEvalParams BuiltInProc ',Decl.Name,' ',GetObjName(Decl.CustomData));
|
||||||
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
if Flags=[] then ;
|
if Flags=[] then ;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPasResolver.EvalBaseTypeCast(Params: TParamsExpr;
|
||||||
|
bt: TResolverBaseType): TResEvalvalue;
|
||||||
|
var
|
||||||
|
Value: TResEvalValue;
|
||||||
|
Int: MaxPrecInt;
|
||||||
|
MinIntVal, MaxIntVal: int64;
|
||||||
|
begin
|
||||||
|
Result:=nil;
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TPasResolver.EvalBaseTypeCast bt=',bt);
|
||||||
|
{$ENDIF}
|
||||||
|
Value:=Eval(Params.Params[0],[refAutoConst]);
|
||||||
|
if Value=nil then exit;
|
||||||
|
try
|
||||||
|
case Value.Kind of
|
||||||
|
revkInt:
|
||||||
|
begin
|
||||||
|
Int:=TResEvalInt(Value).Int;
|
||||||
|
if bt=btQWord then
|
||||||
|
begin
|
||||||
|
// int to qword
|
||||||
|
if (Int<0) then
|
||||||
|
fExprEvaluator.EmitRangeCheckConst(20170624195049,
|
||||||
|
Value.AsString,'0',IntToStr(High(qword)),Params);
|
||||||
|
{$R-}
|
||||||
|
Result:=TResEvalUInt.CreateValue(MaxPrecUInt(Int));
|
||||||
|
{$IFDEF RangeCheckOn}{$R+}{$ENDIF}
|
||||||
|
end
|
||||||
|
else if bt in (btAllInteger-[btQWord]) then
|
||||||
|
begin
|
||||||
|
// int to int
|
||||||
|
GetIntegerRange(bt,MinIntVal,MaxIntVal);
|
||||||
|
if (Int<MinIntVal) or (Int>MaxIntVal) then
|
||||||
|
begin
|
||||||
|
fExprEvaluator.EmitRangeCheckConst(20170624194534,
|
||||||
|
Value.AsString,MinIntVal,MaxIntVal,Params);
|
||||||
|
{$R-}
|
||||||
|
case bt of
|
||||||
|
btByte: Result:=TResEvalInt.CreateValue(byte(Int),reitByte);
|
||||||
|
btShortInt: Result:=TResEvalInt.CreateValue(shortint(Int),reitShortInt);// ToDo: negative
|
||||||
|
btWord: Result:=TResEvalInt.CreateValue(word(Int),reitWord);
|
||||||
|
btSmallInt: Result:=TResEvalInt.CreateValue(smallint(Int),reitSmallInt);// ToDo: negative
|
||||||
|
btUIntSingle: Result:=TResEvalInt.CreateValue(Int and MaskUIntSingle,reitUIntSingle);// ToDo: negative
|
||||||
|
btIntSingle: Result:=TResEvalInt.CreateValue(Int and MaskUIntSingle,reitIntSingle);// ToDo: negative
|
||||||
|
btLongWord: Result:=TResEvalInt.CreateValue(longword(Int),reitLongWord);
|
||||||
|
btLongint: Result:=TResEvalInt.CreateValue(longint(Int),reitLongInt);// ToDo: negative
|
||||||
|
btUIntDouble: Result:=TResEvalInt.CreateValue(Int and MaskUIntDouble,reitUIntDouble);// ToDo: negative
|
||||||
|
btIntDouble: Result:=TResEvalInt.CreateValue(Int and MaskUIntDouble,reitIntDouble);// ToDo: negative
|
||||||
|
btInt64: Result:=TResEvalInt.CreateValue(Int);
|
||||||
|
else
|
||||||
|
RaiseNotYetImplemented(20170624200109,Params);
|
||||||
|
end;
|
||||||
|
{$IFDEF RangeCheckOn}{$R+}{$ENDIF}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{$R-}
|
||||||
|
case bt of
|
||||||
|
btByte: Result:=TResEvalInt.CreateValue(Int,reitByte);
|
||||||
|
btShortInt: Result:=TResEvalInt.CreateValue(Int,reitShortInt);
|
||||||
|
btWord: Result:=TResEvalInt.CreateValue(Int,reitWord);
|
||||||
|
btSmallInt: Result:=TResEvalInt.CreateValue(Int,reitSmallInt);
|
||||||
|
btUIntSingle: Result:=TResEvalInt.CreateValue(Int,reitUIntSingle);
|
||||||
|
btIntSingle: Result:=TResEvalInt.CreateValue(Int,reitIntSingle);
|
||||||
|
btLongWord: Result:=TResEvalInt.CreateValue(Int,reitLongWord);
|
||||||
|
btLongint: Result:=TResEvalInt.CreateValue(Int,reitLongInt);
|
||||||
|
btUIntDouble: Result:=TResEvalInt.CreateValue(Int,reitUIntDouble);
|
||||||
|
btIntDouble: Result:=TResEvalInt.CreateValue(Int,reitIntDouble);
|
||||||
|
btInt64: Result:=TResEvalInt.CreateValue(Int);
|
||||||
|
else
|
||||||
|
RaiseNotYetImplemented(20170624200109,Params);
|
||||||
|
end;
|
||||||
|
{$IFDEF RangeCheckOn}{$R+}{$ENDIF}
|
||||||
|
end;
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TPasResolver.OnExprEvalParams typecast int to ',bt);
|
||||||
|
{$ENDIF}
|
||||||
|
RaiseNotYetImplemented(20170624194308,Params);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TPasResolver.OnExprEvalParams typecast to ',bt);
|
||||||
|
{$ENDIF}
|
||||||
|
RaiseNotYetImplemented(20170624193436,Params);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
ReleaseEvalValue(Value);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPasResolver.Eval(Expr: TPasExpr; Flags: TResEvalFlags;
|
function TPasResolver.Eval(Expr: TPasExpr; Flags: TResEvalFlags;
|
||||||
Store: boolean): TResEvalValue;
|
Store: boolean): TResEvalValue;
|
||||||
// Important: Caller must free result if (Result<>nil) and (Result.Element=nil)
|
// Important: Caller must free result if (Result<>nil) and (Result.Element=nil)
|
||||||
@ -7461,6 +7612,9 @@ begin
|
|||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
Result:=fExprEvaluator.Eval(Expr,Flags);
|
Result:=fExprEvaluator.Eval(Expr,Flags);
|
||||||
if Result=nil then exit;
|
if Result=nil then exit;
|
||||||
|
{$IFDEF VerbosePasResEval}
|
||||||
|
writeln('TPasResolver.Eval Result=',Result.AsString);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
if Store
|
if Store
|
||||||
and (Expr.CustomData=nil)
|
and (Expr.CustomData=nil)
|
||||||
@ -7913,13 +8067,13 @@ begin
|
|||||||
exit(cIncompatible);
|
exit(cIncompatible);
|
||||||
Params:=TParamsExpr(Expr);
|
Params:=TParamsExpr(Expr);
|
||||||
|
|
||||||
// first param: enum or char
|
// first param: bool, enum or char
|
||||||
Param:=Params.Params[0];
|
Param:=Params.Params[0];
|
||||||
ComputeElement(Param,ParamResolved,[]);
|
ComputeElement(Param,ParamResolved,[]);
|
||||||
Result:=cIncompatible;
|
Result:=cIncompatible;
|
||||||
if rrfReadable in ParamResolved.Flags then
|
if rrfReadable in ParamResolved.Flags then
|
||||||
begin
|
begin
|
||||||
if ParamResolved.BaseType=btChar then
|
if ParamResolved.BaseType in (btAllBooleans+btAllChars) then
|
||||||
Result:=cExact
|
Result:=cExact
|
||||||
else if (ParamResolved.BaseType=btContext) and (ParamResolved.TypeEl is TPasEnumType) then
|
else if (ParamResolved.BaseType=btContext) and (ParamResolved.TypeEl is TPasEnumType) then
|
||||||
Result:=cExact;
|
Result:=cExact;
|
||||||
@ -7933,7 +8087,25 @@ end;
|
|||||||
procedure TPasResolver.BI_Ord_OnGetCallResult(Proc: TResElDataBuiltInProc;
|
procedure TPasResolver.BI_Ord_OnGetCallResult(Proc: TResElDataBuiltInProc;
|
||||||
Params: TParamsExpr; out ResolvedEl: TPasResolverResult);
|
Params: TParamsExpr; out ResolvedEl: TPasResolverResult);
|
||||||
begin
|
begin
|
||||||
SetResolverIdentifier(ResolvedEl,btSmallInt,Proc.Proc,FBaseTypes[btSmallInt],[rrfReadable]);
|
SetResolverIdentifier(ResolvedEl,btLongint,Proc.Proc,FBaseTypes[btLongint],[rrfReadable]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPasResolver.BI_Ord_OnEval(Proc: TResElDataBuiltInProc;
|
||||||
|
Params: TParamsExpr; out Evaluated: TResEvalValue);
|
||||||
|
var
|
||||||
|
Param: TPasExpr;
|
||||||
|
Value: TResEvalValue;
|
||||||
|
begin
|
||||||
|
Evaluated:=nil;
|
||||||
|
Param:=Params.Params[0];
|
||||||
|
Value:=Eval(Param,[]);
|
||||||
|
if Value=nil then exit;
|
||||||
|
try
|
||||||
|
Evaluated:=fExprEvaluator.OrdValue(Value,Params);
|
||||||
|
finally
|
||||||
|
if Evaluated=nil then
|
||||||
|
ReleaseEvalValue(Value);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasResolver.BI_LowHigh_OnGetCallCompatibility(
|
function TPasResolver.BI_LowHigh_OnGetCallCompatibility(
|
||||||
@ -8261,8 +8433,22 @@ end;
|
|||||||
|
|
||||||
procedure TPasResolver.BI_PredSucc_OnEval(Proc: TResElDataBuiltInProc;
|
procedure TPasResolver.BI_PredSucc_OnEval(Proc: TResElDataBuiltInProc;
|
||||||
Params: TParamsExpr; out Evaluated: TResEvalValue);
|
Params: TParamsExpr; out Evaluated: TResEvalValue);
|
||||||
|
var
|
||||||
|
Param: TPasExpr;
|
||||||
begin
|
begin
|
||||||
|
//writeln('TPasResolver.BI_PredSucc_OnEval START');
|
||||||
|
Evaluated:=nil;
|
||||||
|
Param:=Params.Params[0];
|
||||||
|
Evaluated:=Eval(Param,[]);
|
||||||
|
//writeln('TPasResolver.BI_PredSucc_OnEval Param=',Evaluated<>nil);
|
||||||
|
if Evaluated=nil then exit;
|
||||||
|
//writeln('TPasResolver.BI_PredSucc_OnEval Param=',Evaluated.AsString);
|
||||||
|
if Evaluated.Element<>nil then
|
||||||
|
Evaluated:=Evaluated.Clone;
|
||||||
|
if Proc.BuiltIn=bfPred then
|
||||||
|
fExprEvaluator.PredValue(Evaluated,Params)
|
||||||
|
else
|
||||||
|
fExprEvaluator.SuccValue(Evaluated,Params);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasResolver.BI_Str_CheckParam(IsFunc: boolean; Param: TPasExpr;
|
function TPasResolver.BI_Str_CheckParam(IsFunc: boolean; Param: TPasExpr;
|
||||||
@ -9447,7 +9633,8 @@ begin
|
|||||||
@BI_Chr_OnGetCallCompatibility,@BI_Chr_OnGetCallResult,nil,nil,bfChr);
|
@BI_Chr_OnGetCallCompatibility,@BI_Chr_OnGetCallResult,nil,nil,bfChr);
|
||||||
if bfOrd in TheBaseProcs then
|
if bfOrd in TheBaseProcs then
|
||||||
AddBuiltInProc('Ord','function Ord(const Enum or Char): integer',
|
AddBuiltInProc('Ord','function Ord(const Enum or Char): integer',
|
||||||
@BI_Ord_OnGetCallCompatibility,@BI_Ord_OnGetCallResult,nil,nil,bfOrd);
|
@BI_Ord_OnGetCallCompatibility,@BI_Ord_OnGetCallResult,
|
||||||
|
@BI_Ord_OnEval,nil,bfOrd);
|
||||||
if bfLow in TheBaseProcs then
|
if bfLow in TheBaseProcs then
|
||||||
AddBuiltInProc('Low','function Low(const array or ordinal): ordinal or integer',
|
AddBuiltInProc('Low','function Low(const array or ordinal): ordinal or integer',
|
||||||
@BI_LowHigh_OnGetCallCompatibility,@BI_LowHigh_OnGetCallResult,
|
@BI_LowHigh_OnGetCallCompatibility,@BI_LowHigh_OnGetCallResult,
|
||||||
@ -9459,11 +9646,11 @@ begin
|
|||||||
if bfPred in TheBaseProcs then
|
if bfPred in TheBaseProcs then
|
||||||
AddBuiltInProc('Pred','function Pred(const ordinal): ordinal',
|
AddBuiltInProc('Pred','function Pred(const ordinal): ordinal',
|
||||||
@BI_PredSucc_OnGetCallCompatibility,@BI_PredSucc_OnGetCallResult,
|
@BI_PredSucc_OnGetCallCompatibility,@BI_PredSucc_OnGetCallResult,
|
||||||
nil,nil,bfPred);
|
@BI_PredSucc_OnEval,nil,bfPred);
|
||||||
if bfSucc in TheBaseProcs then
|
if bfSucc in TheBaseProcs then
|
||||||
AddBuiltInProc('Succ','function Succ(const ordinal): ordinal',
|
AddBuiltInProc('Succ','function Succ(const ordinal): ordinal',
|
||||||
@BI_PredSucc_OnGetCallCompatibility,@BI_PredSucc_OnGetCallResult,
|
@BI_PredSucc_OnGetCallCompatibility,@BI_PredSucc_OnGetCallResult,
|
||||||
nil,nil,bfSucc);
|
@BI_PredSucc_OnEval,nil,bfSucc);
|
||||||
if bfStrProc in TheBaseProcs then
|
if bfStrProc in TheBaseProcs then
|
||||||
AddBuiltInProc('Str','procedure Str(const var; var String)',
|
AddBuiltInProc('Str','procedure Str(const var; var String)',
|
||||||
@BI_StrProc_OnGetCallCompatibility,nil,nil,
|
@BI_StrProc_OnGetCallCompatibility,nil,nil,
|
||||||
|
@ -50,10 +50,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, AVL_Tree, PasTree, PScanner,
|
Classes, SysUtils, AVL_Tree, PasTree, PScanner,
|
||||||
{$IFDEF VerbosePasAnalyzer}
|
PasResolver, PasResolveEval;
|
||||||
PasResolveEval,
|
|
||||||
{$ENDIF}
|
|
||||||
PasResolver;
|
|
||||||
|
|
||||||
const
|
const
|
||||||
nPAUnitNotUsed = 5023;
|
nPAUnitNotUsed = 5023;
|
||||||
|
@ -215,7 +215,6 @@ procedure TPasWriter.WriteClass(AClass: TPasClassType);
|
|||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
Member: TPasElement;
|
Member: TPasElement;
|
||||||
InterfacesListPrefix: string;
|
|
||||||
LastVisibility, CurVisibility: TPasMemberVisibility;
|
LastVisibility, CurVisibility: TPasMemberVisibility;
|
||||||
begin
|
begin
|
||||||
PrepareDeclSection('type');
|
PrepareDeclSection('type');
|
||||||
@ -228,19 +227,7 @@ begin
|
|||||||
okInterface: wrt('interface');
|
okInterface: wrt('interface');
|
||||||
end;
|
end;
|
||||||
if Assigned(AClass.AncestorType) then
|
if Assigned(AClass.AncestorType) then
|
||||||
wrt('(' + AClass.AncestorType.Name);
|
wrtln('(' + AClass.AncestorType.Name + ')')
|
||||||
if AClass.Interfaces.Count > 0 then
|
|
||||||
begin
|
|
||||||
if Assigned(AClass.AncestorType) then
|
|
||||||
InterfacesListPrefix:=', '
|
|
||||||
else
|
|
||||||
InterfacesListPrefix:='(';
|
|
||||||
wrt(InterfacesListPrefix + TPasType(AClass.Interfaces[0]).Name);
|
|
||||||
for i := 1 to AClass.Interfaces.Count - 1 do
|
|
||||||
wrt(', ' + TPasType(AClass.Interfaces[i]).Name);
|
|
||||||
end;
|
|
||||||
if Assigned(AClass.AncestorType) or (AClass.Interfaces.Count > 0) then
|
|
||||||
wrtln(')')
|
|
||||||
else
|
else
|
||||||
wrtln;
|
wrtln;
|
||||||
IncIndent;
|
IncIndent;
|
||||||
|
@ -191,7 +191,7 @@ type
|
|||||||
Procedure TestByteRangeFail;
|
Procedure TestByteRangeFail;
|
||||||
Procedure TestCustomIntRangeFail;
|
Procedure TestCustomIntRangeFail;
|
||||||
Procedure TestConstIntOperators;
|
Procedure TestConstIntOperators;
|
||||||
// ToDo: TestConstBitwiseOps 3 and not 2, 3 and not longword(2)
|
Procedure TestConstBitwiseOps;
|
||||||
Procedure TestConstBoolOperators;
|
Procedure TestConstBoolOperators;
|
||||||
|
|
||||||
// strings
|
// strings
|
||||||
@ -2243,6 +2243,25 @@ begin
|
|||||||
' q:longword=not (5 or not 2);',
|
' q:longword=not (5 or not 2);',
|
||||||
' r=low(word)+high(int64);',
|
' r=low(word)+high(int64);',
|
||||||
' s=low(longint)+high(integer);',
|
' s=low(longint)+high(integer);',
|
||||||
|
' t=succ(2)+pred(2);',
|
||||||
|
'begin']);
|
||||||
|
ParseProgram;
|
||||||
|
CheckResolverUnexpectedHints;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestResolver.TestConstBitwiseOps;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'const',
|
||||||
|
' a=3;',
|
||||||
|
' b=not a;',
|
||||||
|
' c=not word(a);',
|
||||||
|
' d=1 shl 2;',
|
||||||
|
' e=13 shr 1;',
|
||||||
|
' f=13 and 5;',
|
||||||
|
' g=10 or 5;',
|
||||||
|
' h=5 xor 7;',
|
||||||
'begin']);
|
'begin']);
|
||||||
ParseProgram;
|
ParseProgram;
|
||||||
CheckResolverUnexpectedHints;
|
CheckResolverUnexpectedHints;
|
||||||
@ -2261,6 +2280,7 @@ begin
|
|||||||
' f=a<>b;',
|
' f=a<>b;',
|
||||||
' g=low(boolean) or high(boolean);',
|
' g=low(boolean) or high(boolean);',
|
||||||
' h=succ(false) or pred(true);',
|
' h=succ(false) or pred(true);',
|
||||||
|
' i=ord(false)+ord(true);',
|
||||||
'begin']);
|
'begin']);
|
||||||
ParseProgram;
|
ParseProgram;
|
||||||
CheckResolverUnexpectedHints;
|
CheckResolverUnexpectedHints;
|
||||||
|
Loading…
Reference in New Issue
Block a user