mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-14 11:09:41 +02:00
fcl-passrc: resolver: read widechar literals
git-svn-id: trunk@36810 -
This commit is contained in:
parent
e76b1b2959
commit
e266fd75e0
@ -1074,7 +1074,7 @@ type
|
|||||||
procedure CombineArrayLitElTypes(Left, Right: TPasExpr;
|
procedure CombineArrayLitElTypes(Left, Right: TPasExpr;
|
||||||
var LHS: TPasResolverResult; const RHS: TPasResolverResult);
|
var LHS: TPasResolverResult; const RHS: TPasResolverResult);
|
||||||
procedure ConvertRangeToFirstValue(var ResolvedEl: TPasResolverResult);
|
procedure ConvertRangeToFirstValue(var ResolvedEl: TPasResolverResult);
|
||||||
function IsCharLiteral(const Value: string): boolean; virtual;
|
function IsCharLiteral(const Value: string; ErrorPos: TPasElement): TResolverBaseType; virtual;
|
||||||
function CheckBuiltInMinParamCount(Proc: TResElDataBuiltInProc; Expr: TPasExpr;
|
function CheckBuiltInMinParamCount(Proc: TResElDataBuiltInProc; Expr: TPasExpr;
|
||||||
MinCount: integer; RaiseOnError: boolean): boolean;
|
MinCount: integer; RaiseOnError: boolean): boolean;
|
||||||
function CheckBuiltInMaxParamCount(Proc: TResElDataBuiltInProc; Params: TParamsExpr;
|
function CheckBuiltInMaxParamCount(Proc: TResElDataBuiltInProc; Params: TParamsExpr;
|
||||||
@ -3327,7 +3327,7 @@ begin
|
|||||||
if EnumType.CustomData is TResElDataBaseType then
|
if EnumType.CustomData is TResElDataBaseType then
|
||||||
begin
|
begin
|
||||||
BaseTypeData:=TResElDataBaseType(EnumType.CustomData);
|
BaseTypeData:=TResElDataBaseType(EnumType.CustomData);
|
||||||
if BaseTypeData.BaseType in [btChar,btBoolean] then
|
if BaseTypeData.BaseType in (btAllChars+[btBoolean]) then
|
||||||
exit;
|
exit;
|
||||||
RaiseXExpectedButYFound(20170216151553,'char or boolean',EnumType.ElementTypeName,EnumType);
|
RaiseXExpectedButYFound(20170216151553,'char or boolean',EnumType.ElementTypeName,EnumType);
|
||||||
end;
|
end;
|
||||||
@ -6268,11 +6268,11 @@ begin
|
|||||||
if (RightResolved.BaseType in btAllStringAndChars) then
|
if (RightResolved.BaseType in btAllStringAndChars) then
|
||||||
case Bin.OpCode of
|
case Bin.OpCode of
|
||||||
eopNone:
|
eopNone:
|
||||||
if (Bin.Kind=pekRange) and (LeftResolved.BaseType in [btChar]) then
|
if (Bin.Kind=pekRange) and (LeftResolved.BaseType in btAllChars) then
|
||||||
begin
|
begin
|
||||||
if RightResolved.BaseType<>btChar then
|
if not (RightResolved.BaseType in btAllChars) then
|
||||||
RaiseXExpectedButYFound(20170216152603,'char',BaseTypeNames[RightResolved.BaseType],Bin.right);
|
RaiseXExpectedButYFound(20170216152603,'char',BaseTypeNames[RightResolved.BaseType],Bin.right);
|
||||||
SetResolverValueExpr(ResolvedEl,btRange,FBaseTypes[btChar],Bin,[rrfReadable]);
|
SetResolverValueExpr(ResolvedEl,btRange,FBaseTypes[LeftResolved.BaseType],Bin,[rrfReadable]);
|
||||||
ResolvedEl.SubType:=LeftResolved.BaseType;
|
ResolvedEl.SubType:=LeftResolved.BaseType;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -6364,8 +6364,9 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else if (RightResolved.BaseType=btSet) and (RightResolved.SubType=btChar)
|
else if (RightResolved.BaseType=btSet)
|
||||||
and (LeftResolved.BaseType=btChar) then
|
and (RightResolved.SubType in btAllChars)
|
||||||
|
and (LeftResolved.BaseType in btAllChars) then
|
||||||
begin
|
begin
|
||||||
case Bin.OpCode of
|
case Bin.OpCode of
|
||||||
eopIn:
|
eopIn:
|
||||||
@ -6443,13 +6444,13 @@ begin
|
|||||||
if (rrfReadable in LeftResolved.Flags)
|
if (rrfReadable in LeftResolved.Flags)
|
||||||
and (rrfReadable in RightResolved.Flags) then
|
and (rrfReadable in RightResolved.Flags) then
|
||||||
begin
|
begin
|
||||||
if LeftResolved.BaseType in (btAllInteger+[btChar]) then
|
if LeftResolved.BaseType in (btAllInteger+btAllChars) then
|
||||||
begin
|
begin
|
||||||
if (RightResolved.BaseType<>btSet) then
|
if (RightResolved.BaseType<>btSet) then
|
||||||
RaiseXExpectedButYFound(20170216152607,'set of '+BaseTypeNames[LeftResolved.BaseType],LeftResolved.TypeEl.ElementTypeName,Bin.right);
|
RaiseXExpectedButYFound(20170216152607,'set of '+BaseTypeNames[LeftResolved.BaseType],LeftResolved.TypeEl.ElementTypeName,Bin.right);
|
||||||
if LeftResolved.BaseType=btChar then
|
if LeftResolved.BaseType in btAllChars then
|
||||||
begin
|
begin
|
||||||
if RightResolved.SubType<>btChar then
|
if not (RightResolved.SubType in btAllChars) then
|
||||||
RaiseXExpectedButYFound(20170216152609,'set of '+BaseTypeNames[LeftResolved.BaseType],'set of '+BaseTypeNames[RightResolved.SubType],Bin.right);
|
RaiseXExpectedButYFound(20170216152609,'set of '+BaseTypeNames[LeftResolved.BaseType],'set of '+BaseTypeNames[RightResolved.SubType],Bin.right);
|
||||||
end
|
end
|
||||||
else if not (RightResolved.SubType in btAllInteger) then
|
else if not (RightResolved.SubType in btAllInteger) then
|
||||||
@ -7269,22 +7270,79 @@ begin
|
|||||||
ResolvedEl.SubType:=btNone;
|
ResolvedEl.SubType:=btNone;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasResolver.IsCharLiteral(const Value: string): boolean;
|
function TPasResolver.IsCharLiteral(const Value: string; ErrorPos: TPasElement
|
||||||
|
): TResolverBaseType;
|
||||||
|
// returns true if Value is a Pascal char literal
|
||||||
|
// btChar: #65, #$50, ^G, 'a'
|
||||||
|
// btWideChar: #10000, 'ä'
|
||||||
var
|
var
|
||||||
p: PChar;
|
p: PChar;
|
||||||
|
i: SizeInt;
|
||||||
|
base: Integer;
|
||||||
begin
|
begin
|
||||||
Result:=false;
|
Result:=btNone;
|
||||||
|
//writeln('TPasResolver.IsCharLiteral ',BaseTypeChar,' "',Value,'" l=',length(Value));
|
||||||
p:=PChar(Value);
|
p:=PChar(Value);
|
||||||
if (p^='''') then
|
case p^ of
|
||||||
|
'''':
|
||||||
begin
|
begin
|
||||||
inc(p);
|
inc(p);
|
||||||
if p^ in [#32..#196] then
|
case p^ of
|
||||||
begin
|
'''':
|
||||||
inc(p);
|
if (p[1]='''') and (p[2]='''') and (p[3]=#0) then
|
||||||
if p^='''' then
|
Result:=btChar;
|
||||||
exit(true);
|
#32..#38,#40..#191:
|
||||||
end;
|
if (p[1]='''') and (p[2]=#0) then
|
||||||
|
Result:=btChar;
|
||||||
|
#192..#255:
|
||||||
|
if BaseTypeChar=btWideChar then
|
||||||
|
begin
|
||||||
|
// default char is widechar: UTF-8 'ä' is a widechar
|
||||||
|
i:=Utf8CodePointLen(p,4,false);
|
||||||
|
//writeln('TPasResolver.IsCharLiteral "',Value,'" ',length(Value),' i=',i);
|
||||||
|
if i<2 then
|
||||||
|
exit;
|
||||||
|
inc(p,i);
|
||||||
|
if (p^='''') and (p[1]=#0) then
|
||||||
|
// single UTF-8 codepoint
|
||||||
|
Result:=btWideChar;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
|
'#':
|
||||||
|
begin
|
||||||
|
inc(p);
|
||||||
|
case p^ of
|
||||||
|
'$': begin base:=16; inc(p); end;
|
||||||
|
'&': begin base:=8; inc(p); end;
|
||||||
|
'%': begin base:=2; inc(p); end;
|
||||||
|
'0'..'9': base:=10;
|
||||||
|
else RaiseNotYetImplemented(20170728142709,ErrorPos);
|
||||||
|
end;
|
||||||
|
i:=0;
|
||||||
|
repeat
|
||||||
|
case p^ of
|
||||||
|
'0'..'9': i:=i*base+ord(p^)-ord('0');
|
||||||
|
'A'..'Z': i:=i*base+ord(p^)-ord('A')+10;
|
||||||
|
'a'..'z': i:=i*base+ord(p^)-ord('a')+10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
inc(p);
|
||||||
|
until false;
|
||||||
|
if p^=#0 then
|
||||||
|
if i<256 then
|
||||||
|
Result:=btChar
|
||||||
|
else
|
||||||
|
Result:=btWideChar;
|
||||||
|
end;
|
||||||
|
'^':
|
||||||
|
begin
|
||||||
|
inc(p);
|
||||||
|
if (p^ in ['a'..'z','A'..'Z']) and (p[1]=#0) then
|
||||||
|
exit(btChar);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasResolver.CheckBuiltInMinParamCount(Proc: TResElDataBuiltInProc;
|
function TPasResolver.CheckBuiltInMinParamCount(Proc: TResElDataBuiltInProc;
|
||||||
@ -7431,7 +7489,7 @@ begin
|
|||||||
Result:=TResEvalRangeInt.Create;
|
Result:=TResEvalRangeInt.Create;
|
||||||
TResEvalRangeInt(Result).ElKind:=revskChar;
|
TResEvalRangeInt(Result).ElKind:=revskChar;
|
||||||
TResEvalRangeInt(Result).RangeStart:=0;
|
TResEvalRangeInt(Result).RangeStart:=0;
|
||||||
if BaseTypeChar=btChar then
|
if BaseTypeChar in [btChar,btAnsiChar] then
|
||||||
TResEvalRangeInt(Result).RangeEnd:=$ff
|
TResEvalRangeInt(Result).RangeEnd:=$ff
|
||||||
else
|
else
|
||||||
TResEvalRangeInt(Result).RangeEnd:=$ffff;
|
TResEvalRangeInt(Result).RangeEnd:=$ffff;
|
||||||
@ -8163,7 +8221,8 @@ end;
|
|||||||
procedure TPasResolver.BI_Chr_OnGetCallResult(Proc: TResElDataBuiltInProc;
|
procedure TPasResolver.BI_Chr_OnGetCallResult(Proc: TResElDataBuiltInProc;
|
||||||
Params: TParamsExpr; out ResolvedEl: TPasResolverResult);
|
Params: TParamsExpr; out ResolvedEl: TPasResolverResult);
|
||||||
begin
|
begin
|
||||||
SetResolverIdentifier(ResolvedEl,btChar,Proc.Proc,FBaseTypes[btChar],[rrfReadable]);
|
SetResolverIdentifier(ResolvedEl,BaseTypeChar,Proc.Proc,
|
||||||
|
FBaseTypes[BaseTypeChar],[rrfReadable]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TPasResolver.BI_Chr_OnEval(Proc: TResElDataBuiltInProc;
|
procedure TPasResolver.BI_Chr_OnEval(Proc: TResElDataBuiltInProc;
|
||||||
@ -11022,8 +11081,8 @@ begin
|
|||||||
else if (LBT in btAllBooleans)
|
else if (LBT in btAllBooleans)
|
||||||
and (RBT in btAllBooleans) then
|
and (RBT in btAllBooleans) then
|
||||||
Result:=cCompatible
|
Result:=cCompatible
|
||||||
else if (LBT in btAllStringAndChars)
|
else if (LBT in btAllChars)
|
||||||
and (RBT in btAllStringAndChars) then
|
and (RBT in btAllChars) then
|
||||||
case LBT of
|
case LBT of
|
||||||
btAnsiChar:
|
btAnsiChar:
|
||||||
Result:=cLossyConversion;
|
Result:=cLossyConversion;
|
||||||
@ -11032,6 +11091,12 @@ begin
|
|||||||
Result:=cCompatible
|
Result:=cCompatible
|
||||||
else
|
else
|
||||||
Result:=cLossyConversion;
|
Result:=cLossyConversion;
|
||||||
|
else
|
||||||
|
RaiseNotYetImplemented(20170728132440,ErrorEl,BaseTypeNames[LBT]);
|
||||||
|
end
|
||||||
|
else if (LBT in btAllStrings)
|
||||||
|
and (RBT in btAllStringAndChars) then
|
||||||
|
case LBT of
|
||||||
btAnsiString:
|
btAnsiString:
|
||||||
if RBT in [btAnsiChar,btShortString,btRawByteString] then
|
if RBT in [btAnsiChar,btShortString,btRawByteString] then
|
||||||
Result:=cCompatible
|
Result:=cCompatible
|
||||||
@ -11158,7 +11223,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
if RHS.TypeEl=nil then
|
if RHS.TypeEl=nil then
|
||||||
Result:=cExact // empty set
|
Result:=cExact // empty set
|
||||||
else if (LHS.SubType=RHS.SubType) and (LHS.SubType in (btAllBooleans+btAllInteger+[btChar])) then
|
else if (LHS.SubType=RHS.SubType) and (LHS.SubType in (btAllBooleans+btAllInteger+btAllChars)) then
|
||||||
Result:=cExact
|
Result:=cExact
|
||||||
else if ((LHS.SubType in btAllBooleans) and (RHS.SubType in btAllBooleans))
|
else if ((LHS.SubType in btAllBooleans) and (RHS.SubType in btAllBooleans))
|
||||||
or ((LHS.SubType in btAllInteger) and (RHS.SubType in btAllInteger)) then
|
or ((LHS.SubType in btAllInteger) and (RHS.SubType in btAllInteger)) then
|
||||||
@ -11414,7 +11479,7 @@ begin
|
|||||||
exit(cExact); // empty set
|
exit(cExact); // empty set
|
||||||
if LHS.TypeEl=RHS.TypeEl then
|
if LHS.TypeEl=RHS.TypeEl then
|
||||||
exit(cExact);
|
exit(cExact);
|
||||||
if (LHS.SubType=RHS.SubType) and (LHS.SubType in (btAllBooleans+btAllInteger+[btChar])) then
|
if (LHS.SubType=RHS.SubType) and (LHS.SubType in (btAllBooleans+btAllInteger+btAllChars)) then
|
||||||
exit(cExact);
|
exit(cExact);
|
||||||
if ((LHS.SubType in btAllBooleans) and (RHS.SubType in btAllBooleans))
|
if ((LHS.SubType in btAllBooleans) and (RHS.SubType in btAllBooleans))
|
||||||
or ((LHS.SubType in btAllInteger) and (RHS.SubType in btAllInteger)) then
|
or ((LHS.SubType in btAllInteger) and (RHS.SubType in btAllInteger)) then
|
||||||
@ -12696,6 +12761,7 @@ procedure TPasResolver.ComputeElement(El: TPasElement; out
|
|||||||
var
|
var
|
||||||
DeclEl: TPasElement;
|
DeclEl: TPasElement;
|
||||||
ElClass: TClass;
|
ElClass: TClass;
|
||||||
|
bt: TResolverBaseType;
|
||||||
begin
|
begin
|
||||||
if StartEl=nil then StartEl:=El;
|
if StartEl=nil then StartEl:=El;
|
||||||
ResolvedEl:=Default(TPasResolverResult);
|
ResolvedEl:=Default(TPasResolverResult);
|
||||||
@ -12725,8 +12791,13 @@ begin
|
|||||||
{$IFDEF VerbosePasResolver}
|
{$IFDEF VerbosePasResolver}
|
||||||
writeln('TPasResolver.ComputeElement pekString Value="',TPrimitiveExpr(El).Value,'"');
|
writeln('TPasResolver.ComputeElement pekString Value="',TPrimitiveExpr(El).Value,'"');
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
if IsCharLiteral(TPrimitiveExpr(El).Value) then
|
bt:=IsCharLiteral(TPrimitiveExpr(El).Value,El);
|
||||||
SetResolverValueExpr(ResolvedEl,btChar,FBaseTypes[btChar],TPrimitiveExpr(El),[rrfReadable])
|
if bt in btAllChars then
|
||||||
|
begin
|
||||||
|
if bt=BaseTypeChar then
|
||||||
|
bt:=btChar;
|
||||||
|
SetResolverValueExpr(ResolvedEl,bt,FBaseTypes[bt],TPrimitiveExpr(El),[rrfReadable]);
|
||||||
|
end
|
||||||
else
|
else
|
||||||
SetResolverValueExpr(ResolvedEl,btString,FBaseTypes[btString],TPrimitiveExpr(El),[rrfReadable]);
|
SetResolverValueExpr(ResolvedEl,btString,FBaseTypes[btString],TPrimitiveExpr(El),[rrfReadable]);
|
||||||
end;
|
end;
|
||||||
|
@ -216,6 +216,7 @@ type
|
|||||||
Procedure TestConstStringOperators;
|
Procedure TestConstStringOperators;
|
||||||
Procedure TestConstUnicodeStringOperators;
|
Procedure TestConstUnicodeStringOperators;
|
||||||
Procedure TestCharSet_Const;
|
Procedure TestCharSet_Const;
|
||||||
|
Procedure TestCharAssignStringFail;
|
||||||
|
|
||||||
// enums
|
// enums
|
||||||
Procedure TestEnums;
|
Procedure TestEnums;
|
||||||
@ -248,6 +249,7 @@ type
|
|||||||
Procedure TestIntegerOperators;
|
Procedure TestIntegerOperators;
|
||||||
Procedure TestBooleanOperators;
|
Procedure TestBooleanOperators;
|
||||||
Procedure TestStringOperators;
|
Procedure TestStringOperators;
|
||||||
|
Procedure TestWideCharOperators;
|
||||||
Procedure TestFloatOperators;
|
Procedure TestFloatOperators;
|
||||||
Procedure TestCAssignments;
|
Procedure TestCAssignments;
|
||||||
Procedure TestTypeCastBaseTypes;
|
Procedure TestTypeCastBaseTypes;
|
||||||
@ -2600,6 +2602,19 @@ begin
|
|||||||
CheckResolverUnexpectedHints;
|
CheckResolverUnexpectedHints;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestResolver.TestCharAssignStringFail;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'var',
|
||||||
|
' c: char;',
|
||||||
|
' s: string;',
|
||||||
|
'begin',
|
||||||
|
' c:=s;']);
|
||||||
|
CheckResolverException('Incompatible types: got "String" expected "Char"',
|
||||||
|
nIncompatibleTypesGotExpected);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestResolver.TestEnums;
|
procedure TTestResolver.TestEnums;
|
||||||
begin
|
begin
|
||||||
StartProgram(false);
|
StartProgram(false);
|
||||||
@ -3271,6 +3286,7 @@ begin
|
|||||||
Add('var');
|
Add('var');
|
||||||
Add(' i,j:string;');
|
Add(' i,j:string;');
|
||||||
Add(' k:char;');
|
Add(' k:char;');
|
||||||
|
Add(' w:widechar;');
|
||||||
Add('begin');
|
Add('begin');
|
||||||
Add(' i:='''';');
|
Add(' i:='''';');
|
||||||
Add(' i:=''''+'''';');
|
Add(' i:=''''+'''';');
|
||||||
@ -3278,8 +3294,30 @@ begin
|
|||||||
Add(' i:=''''+k;');
|
Add(' i:=''''+k;');
|
||||||
Add(' i:=''a''+j;');
|
Add(' i:=''a''+j;');
|
||||||
Add(' i:=''abc''+j;');
|
Add(' i:=''abc''+j;');
|
||||||
Add(' k:=j;');
|
Add(' k:=#65;');
|
||||||
|
Add(' k:=#$42;');
|
||||||
Add(' k:=''a'';');
|
Add(' k:=''a'';');
|
||||||
|
Add(' k:='''''''';');
|
||||||
|
Add(' k:=j[1];');
|
||||||
|
Add(' w:=k;');
|
||||||
|
Add(' w:=#66;');
|
||||||
|
Add(' w:=#6666;');
|
||||||
|
ParseProgram;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestResolver.TestWideCharOperators;
|
||||||
|
begin
|
||||||
|
ResolverEngine.BaseTypeChar:=btWideChar;
|
||||||
|
ResolverEngine.BaseTypeString:=btUnicodeString;
|
||||||
|
StartProgram(false);
|
||||||
|
Add('var');
|
||||||
|
Add(' k:char;');
|
||||||
|
Add(' w:widechar;');
|
||||||
|
Add('begin');
|
||||||
|
Add(' w:=k;');
|
||||||
|
Add(' w:=#66;');
|
||||||
|
Add(' w:=#6666;');
|
||||||
|
Add(' w:=''ä'';');
|
||||||
ParseProgram;
|
ParseProgram;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -3367,7 +3405,7 @@ begin
|
|||||||
Add(' d: double;');
|
Add(' d: double;');
|
||||||
Add(' b: boolean;');
|
Add(' b: boolean;');
|
||||||
Add(' c: char;');
|
Add(' c: char;');
|
||||||
Add(' s: char;');
|
Add(' s: string;');
|
||||||
Add('begin');
|
Add('begin');
|
||||||
Add(' d:=double({#a_read}i);');
|
Add(' d:=double({#a_read}i);');
|
||||||
Add(' i:=shortint({#b_read}i);');
|
Add(' i:=shortint({#b_read}i);');
|
||||||
|
Loading…
Reference in New Issue
Block a user