fcl-passrc: specialize generic method

git-svn-id: trunk@43090 -
This commit is contained in:
Mattias Gaertner 2019-09-29 13:30:50 +00:00
parent 49026e1261
commit 683d4d4301
5 changed files with 137 additions and 40 deletions

View File

@ -1761,6 +1761,11 @@ type
function EvalBaseTypeCast(Params: TParamsExpr; bt: TResolverBaseType): TResEvalvalue; function EvalBaseTypeCast(Params: TParamsExpr; bt: TResolverBaseType): TResEvalvalue;
protected protected
// generic/specialize // generic/specialize
type
TScopeStashState = record
ScopeCount: integer;
StashCount: integer;
end;
procedure AddGenericTemplateIdentifiers(GenericTemplateTypes: TFPList; procedure AddGenericTemplateIdentifiers(GenericTemplateTypes: TFPList;
Scope: TPasIdentifierScope); Scope: TPasIdentifierScope);
procedure AddSpecializedTemplateIdentifiers(GenericTemplateTypes: TFPList; procedure AddSpecializedTemplateIdentifiers(GenericTemplateTypes: TFPList;
@ -1789,7 +1794,8 @@ type
GenTempl: TPasGenericTemplateType; ErrorPos: TPasElement); GenTempl: TPasGenericTemplateType; ErrorPos: TPasElement);
function CreateSpecializedItem(El: TPasElement; GenericEl: TPasElement; function CreateSpecializedItem(El: TPasElement; GenericEl: TPasElement;
const ParamsResolved: TPasTypeArray): TPRSpecializedItem; virtual; const ParamsResolved: TPasTypeArray): TPRSpecializedItem; virtual;
function InitSpecializeScopes(El: TPasElement): integer; virtual; procedure InitSpecializeScopes(El: TPasElement; out State: TScopeStashState); virtual;
procedure RestoreSpecializeScopes(const State: TScopeStashState); virtual;
procedure SpecializeGenericIntf(SpecializedItem: TPRSpecializedItem); virtual; procedure SpecializeGenericIntf(SpecializedItem: TPRSpecializedItem); virtual;
procedure SpecializeGenericImpl(SpecializedItem: TPRSpecializedItem); virtual; procedure SpecializeGenericImpl(SpecializedItem: TPRSpecializedItem); virtual;
procedure SpecializeMembers(GenMembersType, SpecMembersType: TPasMembersType); virtual; procedure SpecializeMembers(GenMembersType, SpecMembersType: TPasMembersType); virtual;
@ -6027,7 +6033,7 @@ type
end; end;
var var
ClassScope: TPasClassScope; ClassScope: TPasClassScope;
i, j, k, OldStashCount: Integer; i, j, k: Integer;
IntfType: TPasClassType; IntfType: TPasClassType;
Resolutions: array of TMethResolution; Resolutions: array of TMethResolution;
Map: TPasClassIntfMap; Map: TPasClassIntfMap;
@ -6043,6 +6049,7 @@ var
SectionScope: TPasSectionScope; SectionScope: TPasSectionScope;
SpecializedItems: TObjectList; SpecializedItems: TObjectList;
SpecializedItem: TPRSpecializedTypeItem; SpecializedItem: TPRSpecializedTypeItem;
OldScopeState: TScopeStashState;
begin begin
Resolutions:=nil; Resolutions:=nil;
ClassScope:=nil; ClassScope:=nil;
@ -6218,7 +6225,7 @@ begin
SpecializedItem:=TPRSpecializedTypeItem(SpecializedItems[i]); SpecializedItem:=TPRSpecializedTypeItem(SpecializedItems[i]);
SpecializedItem.GenericEl:=El; SpecializedItem.GenericEl:=El;
if SpecializedItem.Step<>prssNone then continue; if SpecializedItem.Step<>prssNone then continue;
OldStashCount:=InitSpecializeScopes(El); InitSpecializeScopes(El,OldScopeState);
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
WriteScopesShort('TPasResolver.FinishClassType Finishing specialize interface: '+GetObjName(SpecializedItem.SpecializedType)); WriteScopesShort('TPasResolver.FinishClassType Finishing specialize interface: '+GetObjName(SpecializedItem.SpecializedType));
{$ENDIF} {$ENDIF}
@ -6228,7 +6235,7 @@ begin
WriteScopesShort('TPasResolver.FinishClassType Finished specialize interface: '+GetObjName(SpecializedItem.SpecializedType)); WriteScopesShort('TPasResolver.FinishClassType Finished specialize interface: '+GetObjName(SpecializedItem.SpecializedType));
{$ENDIF} {$ENDIF}
RestoreStashedScopes(OldStashCount); RestoreSpecializeScopes(OldScopeState);
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
WriteScopesShort('TPasResolver.FinishClassType RestoreStashedScopes '+GetObjName(SpecializedItem.SpecializedType)); WriteScopesShort('TPasResolver.FinishClassType RestoreStashedScopes '+GetObjName(SpecializedItem.SpecializedType));
{$ENDIF} {$ENDIF}
@ -7026,13 +7033,16 @@ begin
ProcScope.ClassRecScope:=ClassOrRecScope; ProcScope.ClassRecScope:=ClassOrRecScope;
TemplTypes:=GetProcTemplateTypes(Proc); TemplTypes:=GetProcTemplateTypes(Proc);
if TemplTypes<>nil then
RaiseNotYetImplemented(20190911105953,Proc);
FindData:=Default(TFindProcData); FindData:=Default(TFindProcData);
IsClassConDestructor:=(Proc.ClassType=TPasClassConstructor) IsClassConDestructor:=(Proc.ClassType=TPasClassConstructor)
or (Proc.ClassType=TPasClassDestructor); or (Proc.ClassType=TPasClassDestructor);
if not IsClassConDestructor then if IsClassConDestructor then
begin
if TemplTypes<>nil then
RaiseNotYetImplemented(20190911105953,Proc);
end
else
begin begin
FindData.Proc:=Proc; FindData.Proc:=Proc;
FindData.Args:=Proc.ProcType.Args; FindData.Args:=Proc.ProcType.Args;
@ -7107,7 +7117,7 @@ var
SelfArg: TPasArgument; SelfArg: TPasArgument;
p: Integer; p: Integer;
SelfType, LoSelfType: TPasType; SelfType, LoSelfType: TPasType;
ImplTemplTypes: TFPList; LastNamePart: TProcedureNamePart;
begin begin
if ImplProc.IsExternal then if ImplProc.IsExternal then
RaiseMsg(20170216151715,nInvalidXModifierY,sInvalidXModifierY,[GetElementTypeName(ImplProc),'external'],ImplProc); RaiseMsg(20170216151715,nInvalidXModifierY,sInvalidXModifierY,[GetElementTypeName(ImplProc),'external'],ImplProc);
@ -7126,10 +7136,8 @@ begin
if ImplProc.NameParts<>nil then if ImplProc.NameParts<>nil then
begin begin
ProcName:=TProcedureNamePart(ImplProc.NameParts[ImplProc.NameParts.Count-1]).Name; LastNamePart:=TProcedureNamePart(ImplProc.NameParts[ImplProc.NameParts.Count-1]);
ImplTemplTypes:=GetProcTemplateTypes(ImplProc); ProcName:=LastNamePart.Name;
if ImplTemplTypes<>nil then
RaiseNotYetImplemented(20190911105319,ImplProc);
end end
else else
begin begin
@ -7139,7 +7147,6 @@ begin
if p<1 then break; if p<1 then break;
Delete(ProcName,1,p); Delete(ProcName,1,p);
until false; until false;
ImplTemplTypes:=nil;
end; end;
if ImplProcScope.DeclarationProc=nil then if ImplProcScope.DeclarationProc=nil then
@ -12222,11 +12229,6 @@ begin
NamePart:=TProcedureNamePart(TypeParams[Level-1]); NamePart:=TProcedureNamePart(TypeParams[Level-1]);
if NamePart.Name<>ProcName then if NamePart.Name<>ProcName then
RaiseNotYetImplemented(20190818122551,El,IntToStr(Level)+': '+NamePart.Name+'<>'+ProcName); RaiseNotYetImplemented(20190818122551,El,IntToStr(Level)+': '+NamePart.Name+'<>'+ProcName);
if NamePart.Templates<>nil then
begin
// ToDo: generic method
RaiseNotYetImplemented(20190818122619,El);
end;
end; end;
end end
@ -15959,7 +15961,8 @@ begin
SpecializeGenericImpl(Result); SpecializeGenericImpl(Result);
end; end;
function TPasResolver.InitSpecializeScopes(El: TPasElement): integer; procedure TPasResolver.InitSpecializeScopes(El: TPasElement; out
State: TScopeStashState);
function PushParentScopes(CurEl: TPasElement): integer; function PushParentScopes(CurEl: TPasElement): integer;
var var
@ -16012,6 +16015,7 @@ function TPasResolver.InitSpecializeScopes(El: TPasElement): integer;
StashScopes(Keep); StashScopes(Keep);
if Keep<>FScopeCount then if Keep<>FScopeCount then
RaiseNotYetImplemented(20190813005130,El); RaiseNotYetImplemented(20190813005130,El);
State.ScopeCount:=ScopeCount;
end; end;
if (CurEl.ClassType=TImplementationSection) then if (CurEl.ClassType=TImplementationSection) then
begin begin
@ -16035,7 +16039,8 @@ begin
{$IFDEF VerboseInitSpecializeScopes} {$IFDEF VerboseInitSpecializeScopes}
writeln('TPasResolver.InitSpecializeScopes START ',GetObjName(El)); writeln('TPasResolver.InitSpecializeScopes START ',GetObjName(El));
{$ENDIF} {$ENDIF}
Result:=FStashScopeCount; State.ScopeCount:=ScopeCount;
State.StashCount:=FStashScopeCount;
Keep:=PushParentScopes(El.Parent)+1; Keep:=PushParentScopes(El.Parent)+1;
if Keep<FScopeCount then if Keep<FScopeCount then
begin begin
@ -16052,17 +16057,24 @@ begin
{$ENDIF} {$ENDIF}
end; end;
procedure TPasResolver.RestoreSpecializeScopes(const State: TScopeStashState);
begin
while ScopeCount>State.ScopeCount do
PopScope;
RestoreStashedScopes(State.StashCount);
end;
procedure TPasResolver.SpecializeGenericIntf(SpecializedItem: TPRSpecializedItem procedure TPasResolver.SpecializeGenericIntf(SpecializedItem: TPRSpecializedItem
); );
var var
SpecEl, GenericEl: TPasElement; SpecEl, GenericEl: TPasElement;
OldStashCount: Integer;
C: TClass; C: TClass;
NewRecordType, GenRecordType: TPasRecordType; NewRecordType, GenRecordType: TPasRecordType;
NewClassType, GenClassType: TPasClassType; NewClassType, GenClassType: TPasClassType;
NewArrayType, GenArrayType: TPasArrayType; NewArrayType, GenArrayType: TPasArrayType;
GenProcType, NewProcType: TPasProcedureType; GenProcType, NewProcType: TPasProcedureType;
GenProc, NewProc: TPasProcedure; GenProc, NewProc: TPasProcedure;
OldScopeState: TScopeStashState;
begin begin
if SpecializedItem.Step<>prssNone then if SpecializedItem.Step<>prssNone then
exit; exit;
@ -16071,7 +16083,8 @@ begin
GenericEl:=SpecializedItem.GenericEl; GenericEl:=SpecializedItem.GenericEl;
// change scope // change scope
OldStashCount:=InitSpecializeScopes(GenericEl); WriteScopesShort('AAA1 TPasResolver.SpecializeGenericIntf *******************');
InitSpecializeScopes(GenericEl,OldScopeState);
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
WriteScopesShort('TPasResolver.SpecializeGenericIntf Init SpecEl='+SpecEl.FullName+' GenericEl='+GenericEl.FullName); WriteScopesShort('TPasResolver.SpecializeGenericIntf Init SpecEl='+SpecEl.FullName+' GenericEl='+GenericEl.FullName);
{$ENDIF} {$ENDIF}
@ -16117,7 +16130,7 @@ begin
WriteScopesShort('TPasResolver.SpecializeGenericIntf Finish: '+SpecEl.FullName); WriteScopesShort('TPasResolver.SpecializeGenericIntf Finish: '+SpecEl.FullName);
{$ENDIF} {$ENDIF}
RestoreStashedScopes(OldStashCount); RestoreSpecializeScopes(OldScopeState);
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
WriteScopesShort('TPasResolver.SpecializeGenericIntf RestoreStashedScopes: '+SpecEl.FullName); WriteScopesShort('TPasResolver.SpecializeGenericIntf RestoreStashedScopes: '+SpecEl.FullName);
{$ENDIF} {$ENDIF}
@ -16132,7 +16145,7 @@ var
SpecializedProcItem: TPRSpecializedProcItem; SpecializedProcItem: TPRSpecializedProcItem;
GenImplProc, GenIntfProc, SpecDeclProc: TPasProcedure; GenImplProc, GenIntfProc, SpecDeclProc: TPasProcedure;
GenDeclProcScope: TPasProcedureScope; GenDeclProcScope: TPasProcedureScope;
OldStashCount: Integer; OldScopeState: TScopeStashState;
begin begin
// check specialized type step // check specialized type step
if SpecializedItem.Step>prssInterfaceFinished then if SpecializedItem.Step>prssInterfaceFinished then
@ -16179,9 +16192,9 @@ begin
RaiseNotYetImplemented(20190920192731,GenImplProc); // GenScope.GenericStep is wrong RaiseNotYetImplemented(20190920192731,GenImplProc); // GenScope.GenericStep is wrong
SpecDeclProc:=SpecializedProcItem.SpecializedProc; SpecDeclProc:=SpecializedProcItem.SpecializedProc;
OldStashCount:=InitSpecializeScopes(GenImplProc); InitSpecializeScopes(GenImplProc,OldScopeState);
SpecializeGenImplProc(GenIntfProc,SpecDeclProc,SpecializedProcItem); SpecializeGenImplProc(GenIntfProc,SpecDeclProc,SpecializedProcItem);
RestoreStashedScopes(OldStashCount); RestoreSpecializeScopes(OldScopeState);
end; end;
end; end;
@ -16211,10 +16224,11 @@ procedure TPasResolver.SpecializeMembersImpl(GenericType,
SpecType: TPasMembersType; SpecializedItem: TPRSpecializedTypeItem); SpecType: TPasMembersType; SpecializedItem: TPRSpecializedTypeItem);
var var
GenClassOrRec, SpecClassOrRec: TPasMembersType; GenClassOrRec, SpecClassOrRec: TPasMembersType;
OldStashCount, i: Integer; i: Integer;
GenMember, SpecMember, ImplParent: TPasElement; GenMember, SpecMember, ImplParent: TPasElement;
GenIntfProc, GenImplProc, SpecIntfProc: TPasProcedure; GenIntfProc, GenImplProc, SpecIntfProc: TPasProcedure;
GenIntfProcScope: TPasProcedureScope; GenIntfProcScope: TPasProcedureScope;
OldScopeState: TScopeStashState;
begin begin
GenClassOrRec:=TPasMembersType(GenericType); GenClassOrRec:=TPasMembersType(GenericType);
SpecClassOrRec:=TPasMembersType(SpecType); SpecClassOrRec:=TPasMembersType(SpecType);
@ -16225,7 +16239,7 @@ begin
// specialize member bodies // specialize member bodies
ImplParent:=nil; ImplParent:=nil;
OldStashCount:=FStashScopeCount; OldScopeState:=default(TScopeStashState);
for i:=0 to GenClassOrRec.Members.Count-1 do for i:=0 to GenClassOrRec.Members.Count-1 do
begin begin
GenMember:=TPasElement(GenClassOrRec.Members[i]); GenMember:=TPasElement(GenClassOrRec.Members[i]);
@ -16247,7 +16261,7 @@ begin
begin begin
// switch scope (e.g. unit implementation section) // switch scope (e.g. unit implementation section)
ImplParent:=GenImplProc.Parent; ImplParent:=GenImplProc.Parent;
OldStashCount:=InitSpecializeScopes(GenImplProc); InitSpecializeScopes(GenImplProc,OldScopeState);
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
writeln('TPasResolver.SpecializeGenImplProc Specialize implprocs: SpecType=',GetObjName(SpecType),' ImplParent=',GetObjName(ImplParent),' ScopeCount=',ScopeCount,' FStashScopeCount=',FStashScopeCount,' TopScope=',GetObjName(TopScope)); writeln('TPasResolver.SpecializeGenImplProc Specialize implprocs: SpecType=',GetObjName(SpecType),' ImplParent=',GetObjName(ImplParent),' ScopeCount=',ScopeCount,' FStashScopeCount=',FStashScopeCount,' TopScope=',GetObjName(TopScope));
{$ENDIF} {$ENDIF}
@ -16267,7 +16281,7 @@ begin
if ImplParent<>nil then if ImplParent<>nil then
begin begin
// restore scope // restore scope
RestoreStashedScopes(OldStashCount); RestoreSpecializeScopes(OldScopeState);
end; end;
end; end;
@ -16808,8 +16822,7 @@ begin
RaiseNotYetImplemented(20190920203700,SpecEl); RaiseNotYetImplemented(20190920203700,SpecEl);
if GenProcScope.OverriddenProc<>nil then if GenProcScope.OverriddenProc<>nil then
RaiseNotYetImplemented(20190920203536,SpecEl); RaiseNotYetImplemented(20190920203536,SpecEl);
if GenProcScope.ClassRecScope<>nil then SpecProcScope.ClassRecScope:=GenProcScope.ClassRecScope;
RaiseNotYetImplemented(20190920203609,SpecEl);
if GenProcScope.SelfArg<>nil then if GenProcScope.SelfArg<>nil then
RaiseNotYetImplemented(20190920203626,SpecEl); RaiseNotYetImplemented(20190920203626,SpecEl);
// SpecProcScope.Flags // SpecProcScope.Flags
@ -16897,7 +16910,7 @@ begin
FinishProcedure(SpecEl); FinishProcedure(SpecEl);
end end
else if SpecializedItem=nil then else if SpecializedItem=nil then
// forward or unit-intf declaration // declaration proc, parent is specialized
FinishProcedure(SpecEl) FinishProcedure(SpecEl)
else else
begin begin

View File

@ -4683,14 +4683,17 @@ procedure TPasProcedure.ForEachCall(const aMethodCall: TOnForEachPasElement;
const Arg: Pointer); const Arg: Pointer);
var var
i, j: Integer; i, j: Integer;
Templates: TFPList;
begin begin
inherited ForEachCall(aMethodCall, Arg); inherited ForEachCall(aMethodCall, Arg);
if NameParts<>nil then if NameParts<>nil then
for i:=0 to NameParts.Count-1 do for i:=0 to NameParts.Count-1 do
with TProcedureNamePart(NameParts[i]) do begin
if Templates<>nil then Templates:=TProcedureNamePart(NameParts[i]).Templates;
for j:=0 to Templates.Count-1 do if Templates<>nil then
ForEachChildCall(aMethodCall,Arg,TPasElement(Templates[i]),false); for j:=0 to Templates.Count-1 do
ForEachChildCall(aMethodCall,Arg,TPasElement(Templates[j]),false);
end;
ForEachChildCall(aMethodCall,Arg,ProcType,false); ForEachChildCall(aMethodCall,Arg,ProcType,false);
ForEachChildCall(aMethodCall,Arg,PublicName,false); ForEachChildCall(aMethodCall,Arg,PublicName,false);
ForEachChildCall(aMethodCall,Arg,LibraryExpr,false); ForEachChildCall(aMethodCall,Arg,LibraryExpr,false);

View File

@ -143,7 +143,10 @@ type
// generic methods // generic methods
procedure TestGenMethod_VirtualFail; procedure TestGenMethod_VirtualFail;
procedure TestGenMethod_ClassInterfaceMethodFail; procedure TestGenMethod_ClassInterfaceMethodFail;
// ToDo: parametrized method mismatch interface method procedure TestGenMethod_ClassConstructorFail;
procedure TestGenMethod_TemplNameDifferFail;
procedure TestGenMethod_ImplConstraintFail;
procedure TestGenMethod_TypeParamCntOverload;
// ToDo: generic class method overload <T> <S,T> // ToDo: generic class method overload <T> <S,T>
// ToDo: generic class method overload <T>(bool) <T>(word) // ToDo: generic class method overload <T>(bool) <T>(word)
// ToDo: procedure TestGenMethod_ClassConstructorFail; // ToDo: procedure TestGenMethod_ClassConstructorFail;
@ -2042,6 +2045,80 @@ begin
CheckParserException('generic is not allowed in interface',nParserXNotAllowedInY); CheckParserException('generic is not allowed in interface',nParserXNotAllowedInY);
end; end;
procedure TTestResolveGenerics.TestGenMethod_ClassConstructorFail;
begin
StartProgram(false);
Add([
'type',
' TObject = class',
' generic class constructor Run<T>(a: T);',
' end;',
'generic class constructor TObject.Run<T>(a: T);',
'begin end;',
'begin',
'']);
CheckParserException('Expected "Procedure" or "Function" at token "constructor" in file afile.pp at line 4 column 19',
nParserExpectToken2Error);
end;
procedure TTestResolveGenerics.TestGenMethod_TemplNameDifferFail;
begin
StartProgram(false);
Add([
'type',
' TObject = class',
' generic procedure Run<T>(a: T);',
' end;',
'generic procedure TObject.Run<S>(a: S);',
'begin',
'end;',
'begin',
'']);
CheckResolverException('Declaration of "TObject.Run<S>" differs from previous declaration at afile.pp(4,28)',
nDeclOfXDiffersFromPrevAtY);
end;
procedure TTestResolveGenerics.TestGenMethod_ImplConstraintFail;
begin
StartProgram(false);
Add([
'type',
' TObject = class',
' generic procedure Run<T>(a: T);',
' end;',
'generic procedure TObject.Run<T: class>(a: T);',
'begin',
'end;',
'begin',
'']);
CheckResolverException(sImplMustNotRepeatConstraints,nImplMustNotRepeatConstraints);
end;
procedure TTestResolveGenerics.TestGenMethod_TypeParamCntOverload;
begin
StartProgram(false);
Add([
'type',
' TObject = class',
' generic procedure {#A}Run<T>(a: T);',
' generic procedure {#B}Run<M,N>(a: M);',
' end;',
'generic procedure TObject.Run<T>(a: T);',
'begin',
'end;',
'generic procedure TObject.Run<M,N>(a: M);',
'begin',
' specialize {@A}Run<M>(a);',
' specialize {@B}Run<double,char>(1.3);',
'end;',
'var obj: TObject;',
'begin',
' obj.specialize {@A}Run<word>(3);',
' obj.specialize {@B}Run<word,char>(4);',
'']);
ParseProgram;
end;
initialization initialization
RegisterTests([TTestResolveGenerics]); RegisterTests([TTestResolveGenerics]);

View File

@ -24,7 +24,7 @@ type
Procedure TestGen_ClassAncestor; Procedure TestGen_ClassAncestor;
Procedure TestGen_TypeInfo; Procedure TestGen_TypeInfo;
// ToDo: TBird, TBird<T>, TBird<S,T> // ToDo: TBird, TBird<T>, TBird<S,T>
// ToDo: local const T // ToDo: rename local const T
// generic external class // generic external class
procedure TestGen_ExtClass_Array; procedure TestGen_ExtClass_Array;

View File

@ -2762,7 +2762,8 @@ End.
<li>You can typecast function addresses and function references to JS <li>You can typecast function addresses and function references to JS
function, e.g. <i>TJSFunction(@SomeProc)</i>, <i>TJSFunction(OnClick)</i>. function, e.g. <i>TJSFunction(@SomeProc)</i>, <i>TJSFunction(OnClick)</i>.
Keep in mind that typecasting a method address creates a function wrapper Keep in mind that typecasting a method address creates a function wrapper
to bind the Self argument.</li> to bind the Self argument, except when typecasting to <i>TJSFunction</i>
(pas2js 1.5+).</li>
</ul> </ul>
</div> </div>
@ -3009,6 +3010,7 @@ End.
<li>{$mode delphi} or {$mode objfpc}: Same as -Mdelphi or -Mobjfpc, but only for this unit. You can use units of both modes in a program. If present must be at the top of the unit, or after the module name.</li> <li>{$mode delphi} or {$mode objfpc}: Same as -Mdelphi or -Mobjfpc, but only for this unit. You can use units of both modes in a program. If present must be at the top of the unit, or after the module name.</li>
<li>{$modeswitch externalclass}: allow declaring external classes</li> <li>{$modeswitch externalclass}: allow declaring external classes</li>
<li>{$modeswitch arrayoperators}: allow + operator to concatenate arrays, default in mode delphi</li> <li>{$modeswitch arrayoperators}: allow + operator to concatenate arrays, default in mode delphi</li>
<li>{$modeswitch OmitRTTI}: treat published sections as public</li>
<li>{$macro on|off} enables macro replacements. Only macros with a value are replaced. Macros are never replaced inside directives.</li> <li>{$macro on|off} enables macro replacements. Only macros with a value are replaced. Macros are never replaced inside directives.</li>
<li>{$I filename} or {$include filename} - insert include file</li> <li>{$I filename} or {$include filename} - insert include file</li>
<li>{$I %param%}: <li>{$I %param%}:
@ -3072,6 +3074,8 @@ End.
<li>Check type casts, e.g. <i>TBird(AnObject)</i> becomes <i>AnObject as TBird</i></li> <li>Check type casts, e.g. <i>TBird(AnObject)</i> becomes <i>AnObject as TBird</i></li>
</ul> </ul>
</li> </li>
<li>{$DispatchField Msg}: enable checking <i>message number</i> methods for record field name "Msg"</li>
<li>{$DispatchStrField MsgStr}: enable checking <i>message string</i> methods for record field name "Msg"</li>
</ul> </ul>
Defines: Defines:
<ul> <ul>