fcl-passrc: resolver: const float typecast, operators, string[]

git-svn-id: trunk@36725 -
This commit is contained in:
Mattias Gaertner 2017-07-11 16:46:56 +00:00
parent be39ca0c85
commit 82569975c6
4 changed files with 777 additions and 188 deletions

View File

@ -19,43 +19,38 @@ Abstract:
Works:
- Emitting range check warnings
- Error on overflow
- bool: not, =, <>, and, or, xor, low(), high(), pred(), succ(), ord()
- bool:
- not, =, <>, and, or, xor, low(), high(), pred(), succ(), ord()
- boolean(0), boolean(1)
- int/uint
- unary +, -
- binary: +, -, *, div, mod, ^^, =, <>, <, >, <=, >=, and, or, xor, not
- binary: +, -, *, div, mod, ^^, =, <>, <, >, <=, >=, and, or, xor, not, shl, shr
- low(), high(), pred(), succ(), ord()
- typecast int
- string:
- +
- pred(), succ()
- typecast longint(-1), word(-2), intsingle(-1), uintsingle(1)
- float:
- typecast float
- +, -, /, *, =, <>, <, >, <=, >=
- string:
- #65, '', 'a', 'ab'
- +, =, <>, <, >, <=, >=
- pred(), succ()
- s[]
- length(string)
- enum/set
ToDo:
- enable eval via option, default off
- bool:
- boolean(1)
- int
- typecast intsingle(-1), uintsingle(-1), longint(-1)
- string:
- =, <>, <, >, <=, >=
- string encoding
- s[]
- length(string)
- chr(), ord(), low(), high()
- #65
- #$DC00
- float
- typecast float
- /
- +, -, *, div, mod, ^^, =, <>, <, >, <=, >=, and, or, xor, not
- unicodestring
- enum
- low(), high(), pred(), succ(), ord(), typecast
- sets
- [a,b,c..d]
- +, -, *, =, <>, <=, >=, in, ><
- arrays
- length(), low(), high()
- length(), low(), high(), []
}
unit PasResolveEval;
@ -478,6 +473,7 @@ type
function EvalBinaryAddExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
function EvalBinarySubExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
function EvalBinaryMulExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
function EvalBinaryDivideExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
function EvalBinaryDivExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
function EvalBinaryModExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
function EvalBinaryPowerExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
@ -485,9 +481,7 @@ type
function EvalBinaryBoolOpExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
function EvalBinaryNEqualExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
function EvalBinaryLessGreaterExpr(Expr: TBinaryExpr; LeftValue, RightValue: TResEvalValue): TResEvalValue;
function EvalArrayParams(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
function EvalFuncParams(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
function EvalSetParams(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
function EvalParamsExpr(Expr: TParamsExpr; Flags: TResEvalFlags): TResEvalValue;
function ExprStringToOrd(Value: TResEvalValue; PosEl: TPasElement): longword; virtual;
function EvalPrimitiveExprString(Expr: TPrimitiveExpr): TResEvalValue; virtual;
procedure PredBool(Value: TResEvalBool; ErrorEl: TPasElement);
@ -510,9 +504,9 @@ type
function IsConst(Expr: TPasExpr): boolean;
function IsSimpleExpr(Expr: TPasExpr): boolean; // true = no need to store result
procedure EmitRangeCheckConst(id: int64; const aValue, MinVal, MaxVal: String;
PosEl: TPasElement); virtual;
PosEl: TPasElement; MsgType: TMessageType = mtWarning); virtual;
procedure EmitRangeCheckConst(id: int64; const aValue: String;
MinVal, MaxVal: MaxPrecInt; PosEl: TPasElement);
MinVal, MaxVal: MaxPrecInt; PosEl: TPasElement; MsgType: TMessageType = mtWarning);
function OrdValue(Value: TResEvalValue; ErrorEl: TPasElement): TResEvalInt; virtual;
procedure PredValue(Value: TResEvalValue; ErrorEl: TPasElement); virtual;
procedure SuccValue(Value: TResEvalValue; ErrorEl: TPasElement); virtual;
@ -938,6 +932,13 @@ begin
Result:=Result.Clone;
TResEvalUInt(Result).UInt:=-TResEvalUInt(Result).UInt;
end;
revkFloat:
begin
if TResEvalFloat(Result).FloatValue=0 then exit;
if Result.Element<>nil then
Result:=Result.Clone;
TResEvalFloat(Result).FloatValue:=-TResEvalFloat(Result).FloatValue;
end
else
begin
if Result.Element=nil then
@ -1021,6 +1022,8 @@ begin
Result:=EvalBinarySubExpr(Expr,LeftValue,RightValue);
eopMultiply:
Result:=EvalBinaryMulExpr(Expr,LeftValue,RightValue);
eopDivide:
Result:=EvalBinaryDivideExpr(Expr,LeftValue,RightValue);
eopDiv:
Result:=EvalBinaryDivExpr(Expr,LeftValue,RightValue);
eopMod:
@ -1196,6 +1199,7 @@ function TResExprEvaluator.EvalBinaryAddExpr(Expr: TBinaryExpr; LeftValue,
var
Int: MaxPrecInt;
UInt: MaxPrecUInt;
Flo: MaxPrecFloat;
LeftCP, RightCP: TSystemCodePage;
begin
Result:=nil;
@ -1204,42 +1208,68 @@ begin
{$R+}
case LeftValue.Kind of
revkInt:
begin
Int:=TResEvalInt(LeftValue).Int;
case RightValue.Kind of
revkInt:
// int+int
if (TResEvalInt(LeftValue).Int>0) and (TResEvalInt(RightValue).Int>0) then
revkInt: // int + int
if (Int>0) and (TResEvalInt(RightValue).Int>0) then
begin
UInt:=MaxPrecUInt(TResEvalInt(LeftValue).Int)+MaxPrecUInt(TResEvalInt(RightValue).Int);
UInt:=MaxPrecUInt(Int)+MaxPrecUInt(TResEvalInt(RightValue).Int);
Result:=CreateResEvalInt(UInt);
end
else
begin
Int:=TResEvalInt(LeftValue).Int + TResEvalInt(RightValue).Int;
Int:=Int + TResEvalInt(RightValue).Int;
Result:=TResEvalInt.CreateValue(Int);
end;
revkUInt:
IntAddUInt(TResEvalInt(LeftValue).Int,TResEvalUInt(RightValue).UInt);
revkUInt: // int + uint
IntAddUInt(Int,TResEvalUInt(RightValue).UInt);
revkFloat: // int + float
Result:=TResEvalFloat.CreateValue(Int + TResEvalFloat(RightValue).FloatValue);
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryAddExpr int+? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170525115537,Expr);
end;
end;
revkUInt:
begin
UInt:=TResEvalUInt(LeftValue).UInt;
case RightValue.Kind of
revkInt:
IntAddUInt(TResEvalUInt(LeftValue).UInt,TResEvalInt(RightValue).Int);
revkUInt:
revkInt: // uint + int
IntAddUInt(UInt,TResEvalInt(RightValue).Int);
revkUInt: // uint + uint
begin
UInt:=TResEvalUInt(LeftValue).UInt+TResEvalUInt(RightValue).UInt;
UInt:=UInt+TResEvalUInt(RightValue).UInt;
Result:=TResEvalUInt.CreateValue(UInt);
end
end;
revkFloat: // uint + float
Result:=TResEvalFloat.CreateValue(UInt + TResEvalFloat(RightValue).FloatValue);
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryAddExpr uint+? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170601141031,Expr);
end;
end;
revkFloat:
begin
Flo:=TResEvalFloat(LeftValue).FloatValue;
case RightValue.Kind of
revkInt: // float + int
Result:=TResEvalFloat.CreateValue(Flo + TResEvalInt(RightValue).Int);
revkUInt: // float + uint
Result:=TResEvalFloat.CreateValue(Flo + TResEvalUInt(RightValue).UInt);
revkFloat: // float + float
Result:=TResEvalFloat.CreateValue(Flo + TResEvalFloat(RightValue).FloatValue);
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryAddExpr float+? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170711145637,Expr);
end;
end;
revkString:
case RightValue.Kind of
revkString:
@ -1307,36 +1337,148 @@ function TResExprEvaluator.EvalBinarySubExpr(Expr: TBinaryExpr; LeftValue,
var
Int: MaxPrecInt;
UInt: MaxPrecUInt;
Flo: MaxPrecFloat;
begin
Result:=nil;
case LeftValue.Kind of
revkInt:
begin
Int:=TResEvalInt(LeftValue).Int;
case RightValue.Kind of
revkInt:
// int-int
// int - int
try
{$Q+}
Int:=TResEvalInt(LeftValue).Int - TResEvalInt(RightValue).Int;
Int:=Int - TResEvalInt(RightValue).Int;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalInt.CreateValue(Int);
except
on E: EOverflow do
if (TResEvalInt(LeftValue).Int>0) and (TResEvalInt(RightValue).Int<0) then
if (Int>0) and (TResEvalInt(RightValue).Int<0) then
begin
UInt:=MaxPrecUInt(TResEvalInt(LeftValue).Int)+MaxPrecUInt(-TResEvalInt(RightValue).Int);
UInt:=MaxPrecUInt(Int)+MaxPrecUInt(-TResEvalInt(RightValue).Int);
Result:=CreateResEvalInt(UInt);
end
else
RaiseOverflowArithmetic(20170525230247,Expr);
end;
// ToDo: int-uint
revkUInt:
// int - uint
try
{$Q+}
Int:=Int - TResEvalUInt(RightValue).UInt;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalInt.CreateValue(Int);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711151201,Expr);
end;
revkFloat:
// int - float
try
{$Q+}
Flo:=MaxPrecFloat(Int) - TResEvalFloat(RightValue).FloatValue;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711151313,Expr);
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinarySubExpr sub int-? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170525230028,Expr);
end;
// ToDo: uint-int, uint-uint
end;
revkUInt:
begin
UInt:=TResEvalUInt(LeftValue).UInt;
case RightValue.Kind of
revkInt:
// uint - int
try
{$Q+}
UInt:=UInt - TResEvalInt(RightValue).Int;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalUInt.CreateValue(UInt);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711151405,Expr);
end;
revkUInt:
// uint - uint
try
{$Q+}
UInt:=UInt - TResEvalUInt(RightValue).UInt;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalUInt.CreateValue(UInt);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711151419,Expr);
end;
revkFloat:
// uint - float
try
{$Q+}
Flo:=MaxPrecFloat(UInt) - TResEvalFloat(RightValue).FloatValue;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711151428,Expr);
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinarySubExpr sub uint-? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170711151435,Expr);
end;
end;
revkFloat:
begin
Flo:=TResEvalFloat(LeftValue).FloatValue;
case RightValue.Kind of
revkInt:
// float - int
try
{$Q+}
Flo:=Flo - TResEvalInt(RightValue).Int;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711151519,Expr);
end;
revkUInt:
// float - uint
try
{$Q+}
Flo:=Flo - TResEvalUInt(RightValue).UInt;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711151538,Expr);
end;
revkFloat:
// float - float
try
{$Q+}
Flo:=Flo - TResEvalFloat(RightValue).FloatValue;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711151552,Expr);
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinarySubExpr sub float-? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170711151600,Expr);
end;
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinarySubExpr sub ?- Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
@ -1350,25 +1492,28 @@ function TResExprEvaluator.EvalBinaryMulExpr(Expr: TBinaryExpr; LeftValue,
var
Int: MaxPrecInt;
UInt: MaxPrecUInt;
Flo: MaxPrecFloat;
begin
Result:=nil;
case LeftValue.Kind of
revkInt:
begin
Int:=TResEvalInt(LeftValue).Int;
case RightValue.Kind of
revkInt:
// int*int
// int * int
try
{$Q+}
Int:=TResEvalInt(LeftValue).Int * TResEvalInt(RightValue).Int;
Int:=Int * TResEvalInt(RightValue).Int;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalInt.CreateValue(Int);
except
on E: EOverflow do
if (TResEvalInt(LeftValue).Int>0) and (TResEvalInt(RightValue).Int>0) then
if (Int>0) and (TResEvalInt(RightValue).Int>0) then
try
// try uint*uint
{$Q+}
UInt:=MaxPrecUInt(TResEvalInt(LeftValue).Int) * MaxPrecUInt(TResEvalInt(RightValue).Int);
UInt:=MaxPrecUInt(Int) * MaxPrecUInt(TResEvalInt(RightValue).Int);
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=CreateResEvalInt(UInt);
except
@ -1378,14 +1523,128 @@ begin
else
RaiseOverflowArithmetic(20170525230247,Expr);
end;
// ToDo: int*uint
revkUInt:
// int * uint
try
{$Q+}
Int:=Int * TResEvalUInt(RightValue).UInt;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalInt.CreateValue(Int);
except
RaiseOverflowArithmetic(20170711164445,Expr);
end;
revkFloat:
// int * float
try
{$Q+}
Flo:=Int * TResEvalFloat(RightValue).FloatValue;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
RaiseOverflowArithmetic(20170711164541,Expr);
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryMulExpr mul int*? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170525230028,Expr);
end;
// ToDo: uint*int, uint*uint
end;
revkUInt:
begin
UInt:=TResEvalUInt(LeftValue).UInt;
case RightValue.Kind of
revkInt:
// uint * int
if TResEvalInt(RightValue).Int>=0 then
try
{$Q+}
UInt:=UInt * TResEvalInt(RightValue).Int;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalUInt.CreateValue(UInt);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711164714,Expr);
end
else
try
{$Q+}
Int:=UInt * TResEvalInt(RightValue).Int;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalInt.CreateValue(Int);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711164736,Expr);
end;
revkUInt:
// uint * uint
try
{$Q+}
UInt:=UInt * TResEvalUInt(RightValue).UInt;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalUInt.CreateValue(UInt);
except
RaiseOverflowArithmetic(20170711164751,Expr);
end;
revkFloat:
// uint * float
try
{$Q+}
Flo:=UInt * TResEvalFloat(RightValue).FloatValue;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
RaiseOverflowArithmetic(20170711164800,Expr);
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryMulExpr mul uint*? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170711164810,Expr);
end;
end;
revkFloat:
begin
Flo:=TResEvalFloat(LeftValue).FloatValue;
case RightValue.Kind of
revkInt:
// float * int
try
{$Q+}
Flo:=Flo * TResEvalInt(RightValue).Int;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
on E: EOverflow do
RaiseOverflowArithmetic(20170711164920,Expr);
end;
revkUInt:
// float * uint
try
{$Q+}
Flo:=Flo * TResEvalUInt(RightValue).UInt;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
RaiseOverflowArithmetic(20170711164940,Expr);
end;
revkFloat:
// float * float
try
{$Q+}
Flo:=Flo * TResEvalFloat(RightValue).FloatValue;
{$IFNDEF OverflowCheckOn}{$Q-}{$ENDIF}
Result:=TResEvalFloat.CreateValue(Flo);
except
RaiseOverflowArithmetic(20170711164955,Expr);
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryMulExpr mul float*? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170711165004,Expr);
end;
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryMulExpr mul ?- Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
@ -1394,6 +1653,122 @@ begin
end;
end;
function TResExprEvaluator.EvalBinaryDivideExpr(Expr: TBinaryExpr; LeftValue,
RightValue: TResEvalValue): TResEvalValue;
var
Int: MaxPrecInt;
UInt: MaxPrecUInt;
Flo: MaxPrecFloat;
begin
Result:=nil;
case LeftValue.Kind of
revkInt:
begin
Int:=TResEvalInt(LeftValue).Int;
case RightValue.Kind of
revkInt:
// int / int
if TResEvalInt(RightValue).Int=0 then
RaiseDivByZero(20170711143925,Expr)
else
Result:=TResEvalFloat.CreateValue(Int / TResEvalInt(RightValue).Int);
revkUInt:
// int / uint
if TResEvalUInt(RightValue).UInt=0 then
RaiseDivByZero(20170711144013,Expr)
else
Result:=TResEvalFloat.CreateValue(Int / TResEvalUInt(RightValue).UInt);
revkFloat:
begin
// int / float
try
Flo:=Int / TResEvalFloat(RightValue).FloatValue;
except
RaiseMsg(20170711144525,nDivByZero,sDivByZero,[],Expr);
end;
Result:=TResEvalFloat.CreateValue(Flo);
end
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryDivideExpr int / ? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170711144057,Expr);
end;
end;
revkUInt:
begin
UInt:=TResEvalUInt(LeftValue).UInt;
case RightValue.Kind of
revkInt:
// uint / int
if TResEvalInt(RightValue).Int=0 then
RaiseDivByZero(20170711144103,Expr)
else
Result:=TResEvalFloat.CreateValue(UInt / TResEvalInt(RightValue).Int);
revkUInt:
// uint / uint
if TResEvalUInt(RightValue).UInt=0 then
RaiseDivByZero(20170711144203,Expr)
else
Result:=TResEvalFloat.CreateValue(UInt / TResEvalUInt(RightValue).UInt);
revkFloat:
begin
// uint / float
try
Flo:=UInt / TResEvalFloat(RightValue).FloatValue;
except
RaiseMsg(20170711144912,nDivByZero,sDivByZero,[],Expr);
end;
Result:=TResEvalFloat.CreateValue(Flo);
end
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryDivideExpr uint / ? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170711144239,Expr);
end;
end;
revkFloat:
begin
Flo:=TResEvalFloat(LeftValue).FloatValue;
case RightValue.Kind of
revkInt:
// float / int
if TResEvalInt(RightValue).Int=0 then
RaiseDivByZero(20170711144954,Expr)
else
Result:=TResEvalFloat.CreateValue(Flo / TResEvalInt(RightValue).Int);
revkUInt:
// float / uint
if TResEvalUInt(RightValue).UInt=0 then
RaiseDivByZero(20170711145023,Expr)
else
Result:=TResEvalFloat.CreateValue(Flo / TResEvalUInt(RightValue).UInt);
revkFloat:
begin
// float / float
try
Flo:=Flo / TResEvalFloat(RightValue).FloatValue;
except
RaiseMsg(20170711145040,nDivByZero,sDivByZero,[],Expr);
end;
Result:=TResEvalFloat.CreateValue(Flo);
end
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryDivideExpr float / ? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170711145050,Expr);
end;
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryDivExpr div ?- Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170530102352,Expr);
end;
end;
function TResExprEvaluator.EvalBinaryDivExpr(Expr: TBinaryExpr; LeftValue,
RightValue: TResEvalValue): TResEvalValue;
var
@ -1766,6 +2141,17 @@ begin
Result.Free;
RaiseNotYetImplemented(20170601122806,Expr);
end;
revkString:
case RightValue.Kind of
revkString:
TResEvalBool(Result).B:=TResEvalString(LeftValue).S=TResEvalString(RightValue).S;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryNEqualExpr string ',Expr.OpCode,' ? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
Result.Free;
RaiseNotYetImplemented(20170711175409,Expr);
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryNEqualExpr ',Expr.OpCode,' ?- Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
@ -1919,6 +2305,26 @@ begin
Result.Free;
RaiseNotYetImplemented(20170601133421,Expr);
end;
revkString:
case RightValue.Kind of
revkString:
case Expr.OpCode of
eopLessThan:
TResEvalBool(Result).B:=TResEvalString(LeftValue).S < TResEvalString(RightValue).S;
eopGreaterThan:
TResEvalBool(Result).B:=TResEvalString(LeftValue).S > TResEvalString(RightValue).S;
eopLessthanEqual:
TResEvalBool(Result).B:=TResEvalString(LeftValue).S <= TResEvalString(RightValue).S;
eopGreaterThanEqual:
TResEvalBool(Result).B:=TResEvalString(LeftValue).S >= TResEvalString(RightValue).S;
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryLowerGreaterExpr string ',Expr.OpCode,' ? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
{$ENDIF}
Result.Free;
RaiseNotYetImplemented(20170711175629,Expr);
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalBinaryLowerGreaterExpr ? ',Expr.OpCode,' ? Left=',LeftValue.AsDebugString,' Right=',RightValue.AsDebugString);
@ -1934,6 +2340,76 @@ begin
end;
end;
function TResExprEvaluator.EvalParamsExpr(Expr: TParamsExpr;
Flags: TResEvalFlags): TResEvalValue;
var
ArrayValue, IndexValue: TResEvalValue;
Int: MaxPrecInt;
Param0: TPasExpr;
MaxIndex: Integer;
begin
Result:=OnEvalParams(Self,Expr,Flags);
if Result<>nil then exit;
ArrayValue:=Eval(Expr.Value,Flags);
if ArrayValue=nil then
begin
if (refConst in Flags) then
RaiseConstantExprExp(20170711181321,Expr.Value);
exit;
end;
IndexValue:=nil;
try
case ArrayValue.Kind of
revkString,revkUnicodeString:
begin
Param0:=Expr.Params[0];
IndexValue:=Eval(Param0,Flags);
if IndexValue=nil then
begin
if (refConst in Flags) then
RaiseConstantExprExp(20170711181603,Param0);
exit;
end;
case IndexValue.Kind of
revkInt: Int:=TResEvalInt(IndexValue).Int;
revkUInt:
if TResEvalUInt(IndexValue).UInt>High(MaxPrecInt) then
RaiseRangeCheck(20170711182006,Param0)
else
Int:=TResEvalUInt(IndexValue).UInt;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalParamsExpr string[',IndexValue.AsDebugString,']');
{$ENDIF}
RaiseNotYetImplemented(20170711182100,Expr);
end;
if ArrayValue.Kind=revkString then
MaxIndex:=length(TResEvalString(ArrayValue).S)
else
MaxIndex:=length(TResEvalUTF16(ArrayValue).S);
if (Int<1) or (Int>MaxIndex) then
EmitRangeCheckConst(20170711183058,IntToStr(Int),'1',IntToStr(MaxIndex),Param0,mtError);
if ArrayValue.Kind=revkString then
Result:=TResEvalString.CreateValue(TResEvalString(ArrayValue).S[Int])
else
Result:=TResEvalUTF16.CreateValue(TResEvalUTF16(ArrayValue).S[Int]);
exit;
end;
else
{$IFDEF VerbosePasResolver}
writeln('TResExprEvaluator.EvalParamsExpr Array=',ArrayValue.AsDebugString);
{$ENDIF}
RaiseNotYetImplemented(20170711181507,Expr);
end;
if (refConst in Flags) then
RaiseConstantExprExp(20170522173150,Expr);
finally
ReleaseEvalValue(ArrayValue);
ReleaseEvalValue(IndexValue);
end;
end;
function TResExprEvaluator.EvalBinaryPowerExpr(Expr: TBinaryExpr; LeftValue,
RightValue: TResEvalValue): TResEvalValue;
var
@ -2009,45 +2485,6 @@ begin
end;
end;
function TResExprEvaluator.EvalArrayParams(Expr: TParamsExpr;
Flags: TResEvalFlags): TResEvalValue;
begin
Result:=nil;
{$IFDEF VerbosePasResEval}
writeln('TResExprEvaluator.EvalArrayParams ');
{$ENDIF}
if refConst in Flags then
RaiseConstantExprExp(20170522173151,Expr);
end;
function TResExprEvaluator.EvalFuncParams(Expr: TParamsExpr;
Flags: TResEvalFlags): TResEvalValue;
begin
Result:=nil;
{$IFDEF VerbosePasResEval}
writeln('TResExprEvaluator.EvalFuncParams ');
{$ENDIF}
Result:=OnEvalParams(Self,Expr,Flags);
if (refConst in Flags) and (Result=nil) then
RaiseConstantExprExp(20170522173150,Expr);
end;
function TResExprEvaluator.EvalSetParams(Expr: TParamsExpr; Flags: TResEvalFlags
): TResEvalValue;
begin
Result:=nil;
{$IFDEF VerbosePasResEval}
writeln('TResExprEvaluator.EvalSetParams ');
{$ENDIF}
if length(Expr.Params)=0 then
begin
Result:=TResEvalValue.CreateKind(revkSetEmpty);
exit;
end;
if refConst in Flags then
RaiseConstantExprExp(20170522173152,Expr);
end;
function TResExprEvaluator.ExprStringToOrd(Value: TResEvalValue;
PosEl: TPasElement): longword;
var
@ -2339,13 +2776,7 @@ begin
else if C=TBinaryExpr then
Result:=EvalBinaryExpr(TBinaryExpr(Expr),Flags)
else if C=TParamsExpr then
case TParamsExpr(Expr).Kind of
pekArrayParams: Result:=EvalArrayParams(TParamsExpr(Expr),Flags);
pekFuncParams: Result:=EvalFuncParams(TParamsExpr(Expr),Flags);
pekSet: Result:=EvalSetParams(TParamsExpr(Expr),Flags);
else
RaiseInternalError(20170522173013);
end
Result:=EvalParamsExpr(TParamsExpr(Expr),Flags)
else if refConst in Flags then
RaiseConstantExprExp(20170518213800,Expr);
end;
@ -2535,16 +2966,17 @@ begin
end;
procedure TResExprEvaluator.EmitRangeCheckConst(id: int64; const aValue,
MinVal, MaxVal: String; PosEl: TPasElement);
MinVal, MaxVal: String; PosEl: TPasElement; MsgType: TMessageType);
begin
LogMsg(id,mtWarning,nRangeCheckEvaluatingConstantsVMinMax,
LogMsg(id,MsgType,nRangeCheckEvaluatingConstantsVMinMax,
sRangeCheckEvaluatingConstantsVMinMax,[aValue,MinVal,MaxVal],PosEl);
end;
procedure TResExprEvaluator.EmitRangeCheckConst(id: int64;
const aValue: String; MinVal, MaxVal: MaxPrecInt; PosEl: TPasElement);
const aValue: String; MinVal, MaxVal: MaxPrecInt; PosEl: TPasElement;
MsgType: TMessageType);
begin
EmitRangeCheckConst(id,aValue,IntToStr(MinVal),IntToStr(MaxVal),PosEl);
EmitRangeCheckConst(id,aValue,IntToStr(MinVal),IntToStr(MaxVal),PosEl,MsgType);
end;
function TResExprEvaluator.OrdValue(Value: TResEvalValue; ErrorEl: TPasElement

View File

@ -5769,7 +5769,7 @@ begin
end
else if (C=TSelfExpr) or ((C=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent)) then
// ok
else if (Access=rraRead)
else if (Access in [rraRead,rraParamToUnknownProc])
and ((C=TPrimitiveExpr)
or (C=TNilExpr)
or (C=TBoolConstExpr)) then
@ -7513,6 +7513,7 @@ var
Value: TResEvalValue;
Int: MaxPrecInt;
MinIntVal, MaxIntVal: int64;
Flo: MaxPrecFloat;
begin
Result:=nil;
{$IFDEF VerbosePasResEval}
@ -7528,9 +7529,6 @@ begin
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}
@ -7541,21 +7539,21 @@ begin
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
btShortInt: Result:=TResEvalInt.CreateValue(shortint(Int),reitShortInt);
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
btSmallInt: Result:=TResEvalInt.CreateValue(smallint(Int),reitSmallInt);
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
btLongint: Result:=TResEvalInt.CreateValue(longint(Int),reitLongInt);
btInt64: Result:=TResEvalInt.CreateValue(Int);
btUIntSingle,
btIntSingle,
btUIntDouble,
btIntDouble:
fExprEvaluator.EmitRangeCheckConst(20170624194534,
Value.AsString,MinIntVal,MaxIntVal,Params,mtError);
else
RaiseNotYetImplemented(20170624200109,Params);
end;
@ -7583,6 +7581,26 @@ begin
end;
exit;
end
else if bt=btboolean then
case Int of
0: Result:=TResEvalBool.CreateValue(false);
1: Result:=TResEvalBool.CreateValue(true);
else
fExprEvaluator.EmitRangeCheckConst(20170710203254,
Value.AsString,0,1,Params,mtError);
end
else if bt=btSingle then
try
Result:=TResEvalFloat.CreateValue(Single(Int))
except
RaiseMsg(20170711002015,nRangeCheckError,sRangeCheckError,[],Params);
end
else if bt=btDouble then
try
Result:=TResEvalFloat.CreateValue(Double(Int))
except
RaiseMsg(20170711002016,nRangeCheckError,sRangeCheckError,[],Params);
end
else
begin
{$IFDEF VerbosePasResEval}
@ -7591,6 +7609,66 @@ begin
RaiseNotYetImplemented(20170624194308,Params);
end;
end;
revkFloat:
begin
Flo:=TResEvalFloat(Value).FloatValue;
if bt in (btAllInteger-[btQWord]) then
begin
// float to int
GetIntegerRange(bt,MinIntVal,MaxIntVal);
if (Flo<MinIntVal) or (Flo>MaxIntVal) then
fExprEvaluator.EmitRangeCheckConst(20170711001228,
Value.AsString,MinIntVal,MaxIntVal,Params,mtError);
{$R-}
try
Int:=Round(Flo);
except
RaiseMsg(20170711002218,nRangeCheckError,sRangeCheckError,[],Params);
end;
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(20170711001513,Params);
end;
{$IFDEF RangeCheckOn}{$R+}{$ENDIF}
exit;
end
else if bt=btSingle then
begin
// float to single
try
Result:=TResEvalFloat.CreateValue(single(Flo));
except
RaiseMsg(20170711002315,nRangeCheckError,sRangeCheckError,[],Params);
end;
end
else if bt=btDouble then
begin
// float to double
try
Result:=TResEvalFloat.CreateValue(double(Flo));
except
RaiseMsg(20170711002327,nRangeCheckError,sRangeCheckError,[],Params);
end;
end
else
begin
{$IFDEF VerbosePasResEval}
writeln('TPasResolver.OnExprEvalParams typecast float to ',bt);
{$ENDIF}
RaiseNotYetImplemented(20170711002542,Params);
end;
end
else
{$IFDEF VerbosePasResEval}
writeln('TPasResolver.OnExprEvalParams typecast to ',bt);
@ -7613,7 +7691,7 @@ begin
Result:=fExprEvaluator.Eval(Expr,Flags);
if Result=nil then exit;
{$IFDEF VerbosePasResEval}
writeln('TPasResolver.Eval Result=',Result.AsString);
writeln('TPasResolver.Eval Result=',Result.AsDebugString);
{$ENDIF}
if Store
@ -10716,6 +10794,9 @@ begin
// simple type check is enough
else if RValue.Kind=revkBool then
// simple type check is enough
else if LeftResolved.BaseType in [btSingle,btDouble] then
// simple type check is enough
// ToDo: check if precision loss
else
begin
{$IFDEF VerbosePasResolver}

View File

@ -170,7 +170,7 @@ type
Procedure TestAliasTypeNotFoundPosition;
Procedure TestTypeAliasType; // ToDo
// var, const
// vars, const
Procedure TestVarLongint;
Procedure TestVarInteger;
Procedure TestConstInteger;
@ -184,15 +184,21 @@ type
Procedure TestArgWrongExprFail;
Procedure TestVarExternal;
Procedure TestVarNoSemicolonBeginFail;
Procedure TestConstIntOperators;
Procedure TestConstBitwiseOps;
Procedure TestIntegerTypeCast;
Procedure TestConstBoolOperators;
Procedure TestBoolTypeCast;
Procedure TestConstFloatOperators;
Procedure TestFloatTypeCast;
// integer range
Procedure TestIntegerRange;
Procedure TestIntegerRangeHighLowerLowFail;
Procedure TestIntegerRangeLowHigh;
Procedure TestAssignIntRangeFail;
Procedure TestByteRangeFail;
Procedure TestCustomIntRangeFail;
Procedure TestConstIntOperators;
Procedure TestConstBitwiseOps;
Procedure TestConstBoolOperators;
// strings
Procedure TestChar_Ord;
@ -2131,6 +2137,137 @@ begin
nParserExpectTokenError);
end;
procedure TTestResolver.TestConstIntOperators;
begin
StartProgram(false);
Add([
'type',
' integer = longint;',
'const',
' a:byte=1+2;',
' b:shortint=1-2;',
' c:word=2*3;',
' d:smallint=5 div 2;',
' e:longword=5 mod 2;',
' f:longint=5 shl 2;',
' g:qword=5 shr 2;',
' h:boolean=5=2;',
' i:boolean=5<>2;',
' j:boolean=5<2;',
' k:boolean=5>2;',
' l:boolean=5<=2;',
' m:boolean=5>=2;',
' n:longword=5 and 2;',
' o:longword=5 or 2;',
' p:longword=5 xor 2;',
' q:longword=not (5 or not 2);',
' r=low(word)+high(int64);',
' 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']);
ParseProgram;
CheckResolverUnexpectedHints;
end;
procedure TTestResolver.TestIntegerTypeCast;
begin
StartProgram(false);
Add([
'const',
' a=longint(-11);',
' b=not shortint(-12);',
' c=word(-2);',
' d=word(longword(-3));',
'begin']);
ParseProgram;
CheckResolverUnexpectedHints;
end;
procedure TTestResolver.TestConstBoolOperators;
begin
StartProgram(false);
Add([
'const',
' a=true and false;',
' b=true or false;',
' c=true xor false;',
' d=not b;',
' e=a=b;',
' f=a<>b;',
' g=low(boolean) or high(boolean);',
' h=succ(false) or pred(true);',
' i=ord(false)+ord(true);',
'begin']);
ParseProgram;
CheckResolverUnexpectedHints;
end;
procedure TTestResolver.TestBoolTypeCast;
begin
StartProgram(false);
Add('var');
Add(' a: boolean = boolean(0);');
Add(' b: boolean = boolean(1);');
Add('begin');
ParseProgram;
CheckResolverUnexpectedHints;
end;
procedure TTestResolver.TestConstFloatOperators;
begin
StartProgram(false);
Add([
'const',
' a=4/2 + 6.1/3 + 8.1/4.1 + 10/5.1;',
' b=(1.1+1) + (2.1+3.1) + (4+5.1);',
' c=(1.1-1) + (2.1-3.1) + (4-5.1);',
' d=4*2 + 6.1*3 + 8.1*4.1 + 10*5.1;',
' e=a=b;',
' f=a<>b;',
' g=a>b;',
' h=a>=b;',
' i=a<b;',
' j=a<=b;',
' k=(1.1<1) or (2.1<3.1) or (4<5.1);',
' l=(1.1=1) or (2.1=3.1) or (4=5.1);',
'begin']);
ParseProgram;
CheckResolverUnexpectedHints;
end;
procedure TTestResolver.TestFloatTypeCast;
begin
StartProgram(false);
Add([
'const',
' a=-123456890123456789012345;',
' b: double=-123456890123456789012345;',
' c=single(double(-123456890123456789012345));',
' d=single(-1);',
' e=single(word(-1));',
'begin']);
ParseProgram;
CheckResolverUnexpectedHints;
end;
procedure TTestResolver.TestIntegerRange;
begin
StartProgram(false);
@ -2217,75 +2354,6 @@ begin
{$ENDIF}
end;
procedure TTestResolver.TestConstIntOperators;
begin
StartProgram(false);
Add([
'type',
' integer = longint;',
'const',
' a:byte=1+2;',
' b:shortint=1-2;',
' c:word=2*3;',
' d:smallint=5 div 2;',
' e:longword=5 mod 2;',
' f:longint=5 shl 2;',
' g:qword=5 shr 2;',
' h:boolean=5=2;',
' i:boolean=5<>2;',
' j:boolean=5<2;',
' k:boolean=5>2;',
' l:boolean=5<=2;',
' m:boolean=5>=2;',
' n:longword=5 and 2;',
' o:longword=5 or 2;',
' p:longword=5 xor 2;',
' q:longword=not (5 or not 2);',
' r=low(word)+high(int64);',
' 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']);
ParseProgram;
CheckResolverUnexpectedHints;
end;
procedure TTestResolver.TestConstBoolOperators;
begin
StartProgram(false);
Add([
'const',
' a=true and false;',
' b=true or false;',
' c=true xor false;',
' d=not b;',
' e=a=b;',
' f=a<>b;',
' g=low(boolean) or high(boolean);',
' h=succ(false) or pred(true);',
' i=ord(false)+ord(true);',
'begin']);
ParseProgram;
CheckResolverUnexpectedHints;
end;
procedure TTestResolver.TestChar_Ord;
begin
StartProgram(false);
@ -2396,7 +2464,16 @@ begin
StartProgram(false);
Add([
'const',
' a=''o''+''x'';',
' a=''o''+''x''+''''+''ab'';',
' b=#65#66;',
' c=a=b;',
' d=a<>b;',
' e=a<b;',
' f=a<=b;',
' g=a>b;',
' h=a>=b;',
' i=a[1];',
' j=length(a);',
'begin']);
ParseProgram;
CheckResolverUnexpectedHints;

View File

@ -267,7 +267,6 @@ ToDos:
- pointer of record
- nested types in class
- asm: pas() - useful for overloads and protect an identifier from optimization
- source maps
- ifthen
- stdcall of methods: pass original 'this' as first parameter