fcl-passrc: resolver: read widechar literals

git-svn-id: trunk@36810 -
This commit is contained in:
Mattias Gaertner 2017-07-28 17:50:24 +00:00
parent e76b1b2959
commit e266fd75e0
2 changed files with 138 additions and 29 deletions

View File

@ -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;

View File

@ -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);');