mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-12-28 10:04:43 +01:00
Implement advanced class helper syntax which allows "inheritance" of class helpers. This is not the same as normal class inheritance as its only used to extend the scope to other class helpers (that pseudo heritage line) when searching for a symbol. The real parent is always the extended class.
- compiler/symdef.pas: add "helperparent" which contains the class helper the current class helper "inherits" from (its real parent is the extended class); it's saved to ppu as well - compiler/ppu.pas: increase ppu version - compiler/pdecobj.pas: * parse the "parent" of a class helper before parsing the extended class (the real parent) * also disallow to inherit from class helpers for normal class (and to extend class helpers for class helpers) * disallow the declarations of fields * disallow the use of destructors * don't parse abstract/sealed for class helpers - compiler/ptyp.pas: _FOR is now parsed inside pdecobj.pas - compiler/msg*: * extended some messages for class helpers * added some class helper related messages (perhaps the one or other will vanish again...) git-svn-id: branches/svenbarth/classhelpers@16792 -
This commit is contained in:
parent
a9b64c80ad
commit
d4be11cb42
@ -368,7 +368,7 @@ scanner_w_illegal_warn_identifier=02087_W_Illegal identifier "$1" for $WARN dire
|
||||
#
|
||||
# Parser
|
||||
#
|
||||
# 03304 is the last used one
|
||||
# 03308 is the last used one
|
||||
#
|
||||
% \section{Parser messages}
|
||||
% This section lists all parser messages. The parser takes care of the
|
||||
@ -917,9 +917,9 @@ parser_e_no_access_specifier_in_interfaces=03172_E_Access specifiers can't be us
|
||||
% The access specifiers \var{public}, \var{private}, \var{protected} and
|
||||
% \var{published} can't be used in interfaces, Objective-C protocols and categories because all methods
|
||||
% of an interface/protocol/category must be public.
|
||||
parser_e_no_vars_in_interfaces=03173_E_An interface or Objective-C protocol or category cannot contain fields
|
||||
% Declarations of fields are not allowed in interfaces and Objective-C protocols and categories.
|
||||
% An interface/protocol/category can contain only methods and properties with method read/write specifiers.
|
||||
parser_e_no_vars_in_interfaces=03173_E_An interface or class helper or Objective-C protocol or category cannot contain fields
|
||||
% Declarations of fields are not allowed in interfaces, class helpers and Objective-C protocols and categories.
|
||||
% An interface/class helper/protocol/category can contain only methods and properties with method read/write specifiers.
|
||||
parser_e_no_local_proc_external=03174_E_Can't declare local procedure as EXTERNAL
|
||||
% Declaring local procedures as external is not possible. Local procedures
|
||||
% get hidden parameters that will make the chance of errors very high.
|
||||
@ -1352,8 +1352,8 @@ parser_e_forward_protocol_declaration_must_be_resolved=03298_E_Forward declarati
|
||||
% where \var{MyProtocol} is declared but not defined.
|
||||
parser_e_no_record_published=03299_E_Record types cannot have published sections
|
||||
% Published sections can be used only inside classes.
|
||||
parser_e_no_destructor_in_records=03300_E_Destructors aren't allowed in records
|
||||
% Destructor declarations aren't allowed in records.
|
||||
parser_e_no_destructor_in_records=03300_E_Destructors aren't allowed in records or class helpers
|
||||
% Destructor declarations aren't allowed in records or class helpers.
|
||||
parser_e_class_methods_only_static_in_records=03301_E_Class methods must be static in records
|
||||
% Class methods declarations aren't allowed in records without static modifier.
|
||||
% Records have no inheritance and therefore non static class methods have no sence for them.
|
||||
@ -1365,7 +1365,18 @@ parser_e_at_least_one_argument_must_be_of_type=03303_E_At least one argument mus
|
||||
% For example class operators must contain at least one argument of the structure where they are defined.
|
||||
parser_e_cant_use_type_parameters_here=03304_E_Type parameters may require initialization/finalization - can't be used in variant records
|
||||
% Type parameters may be specialized with types which (e.g. \var{ansistring}) need initialization/finalization
|
||||
% code which is implicitly generated by the compiler.
|
||||
% code which is implicitly generated by the compiler.
|
||||
parser_e_classhelper_id_expected=03305_E_Class helper identifier expected
|
||||
% A class helper can only inherit from another class helper.
|
||||
parser_e_classhelper_must_extend_subclass=03306_E_Derived class helper must extend a subclass of the class extended by the parent class helper
|
||||
% When a class helper inherits from another class helper the extended class must
|
||||
% extend either the same class as the parent class helper or a subclass of it
|
||||
parser_e_classhelper_not_allowed_here=03307_E_A class helper is not allowed here
|
||||
% A class helper can only be referenced when inheriting from it. All other uses
|
||||
% (like variable type, field type, parameter type, with clause) are disallowed.
|
||||
parser_e_not_allowed_in_classhelper=03308_E_"$1" is not allowed in class helpers
|
||||
% Some directives and specifiers like "virtual", "dynamic", "published" aren't
|
||||
% allowed inside class helpers in mode ObjFPC (they are ignored in mode Delphi).
|
||||
#
|
||||
# Type Checking
|
||||
#
|
||||
|
||||
@ -393,6 +393,10 @@ const
|
||||
parser_e_no_constructor_in_records=03302;
|
||||
parser_e_at_least_one_argument_must_be_of_type=03303;
|
||||
parser_e_cant_use_type_parameters_here=03304;
|
||||
parser_e_classhelper_id_expected=03305;
|
||||
parser_e_classhelper_must_extend_subclass=03306;
|
||||
parser_e_classhelper_not_allowed_here=03307;
|
||||
parser_e_not_allowed_in_classhelper=03308;
|
||||
type_e_mismatch=04000;
|
||||
type_e_incompatible_types=04001;
|
||||
type_e_not_equal_types=04002;
|
||||
@ -882,9 +886,9 @@ const
|
||||
option_info=11024;
|
||||
option_help_pages=11025;
|
||||
|
||||
MsgTxtSize = 58664;
|
||||
MsgTxtSize = 58927;
|
||||
|
||||
MsgIdxMax : array[1..20] of longint=(
|
||||
24,88,305,99,84,54,111,22,202,63,
|
||||
24,88,309,99,84,54,111,22,202,63,
|
||||
49,20,1,1,1,1,1,1,1,1
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -436,12 +436,30 @@ implementation
|
||||
intfchildof:=nil;
|
||||
hasparentdefined:=false;
|
||||
|
||||
{ the "parent" of a class helper is not really treated as its parent;
|
||||
it's only used to extend the searched scope }
|
||||
if is_objectpascal_classhelper(current_structdef) then
|
||||
begin
|
||||
if try_to_consume(_LKLAMMER) then
|
||||
begin
|
||||
{ TODO : check what these flags mean }
|
||||
single_type(hdef,[stoAllowTypeDef, stoParseClassParent]);
|
||||
if not is_objectpascal_classhelper(hdef) then
|
||||
begin
|
||||
Message(parser_e_classhelper_id_expected);
|
||||
hdef:=nil;
|
||||
end;
|
||||
current_objectdef.helperparent:=tobjectdef(hdef);
|
||||
consume(_RKLAMMER);
|
||||
end;
|
||||
consume(_FOR);
|
||||
end;
|
||||
|
||||
{ reads the parent class }
|
||||
if (token=_LKLAMMER) or
|
||||
is_objccategory(current_structdef) or
|
||||
is_objectpascal_classhelper(current_structdef) then
|
||||
is_classhelper(current_structdef) then
|
||||
begin
|
||||
if not is_objectpascal_classhelper(current_objectdef) then
|
||||
if not is_objectpascal_classhelper(current_structdef) then
|
||||
consume(_LKLAMMER);
|
||||
{ use single_type instead of id_type for specialize support }
|
||||
single_type(hdef,[stoAllowTypeDef, stoParseClassParent]);
|
||||
@ -464,23 +482,29 @@ implementation
|
||||
isn't allowed }
|
||||
case current_objectdef.objecttype of
|
||||
odt_class:
|
||||
if not(is_class(childof)) then
|
||||
begin
|
||||
if is_interface(childof) then
|
||||
begin
|
||||
{ we insert the interface after the child
|
||||
is set, see below
|
||||
}
|
||||
intfchildof:=childof;
|
||||
childof:=class_tobject;
|
||||
end
|
||||
else
|
||||
Message(parser_e_mix_of_classes_and_objects);
|
||||
end
|
||||
if is_objectpascal_classhelper(childof) then
|
||||
{ a class helper is not allowed as parent or extended
|
||||
class
|
||||
}
|
||||
Message(parser_e_classhelper_not_allowed_here)
|
||||
else
|
||||
if (oo_is_sealed in childof.objectoptions) and
|
||||
not is_objectpascal_classhelper(current_objectdef) then
|
||||
Message1(parser_e_sealed_descendant,childof.typename);
|
||||
if not(is_class(childof)) then
|
||||
begin
|
||||
if is_interface(childof) then
|
||||
begin
|
||||
{ we insert the interface after the child
|
||||
is set, see below
|
||||
}
|
||||
intfchildof:=childof;
|
||||
childof:=class_tobject;
|
||||
end
|
||||
else
|
||||
Message(parser_e_mix_of_classes_and_objects);
|
||||
end
|
||||
else
|
||||
if (oo_is_sealed in childof.objectoptions) and
|
||||
not is_objectpascal_classhelper(current_structdef) then
|
||||
Message1(parser_e_sealed_descendant,childof.typename);
|
||||
odt_interfacecorba,
|
||||
odt_interfacecom:
|
||||
begin
|
||||
@ -564,7 +588,8 @@ implementation
|
||||
{ remove forward flag, is resolved }
|
||||
exclude(current_structdef.objectoptions,oo_is_forward);
|
||||
|
||||
if hasparentdefined then
|
||||
if hasparentdefined and
|
||||
not is_objectpascal_classhelper(current_structdef) then
|
||||
begin
|
||||
if current_objectdef.objecttype in [odt_class,odt_objcclass,odt_objcprotocol] then
|
||||
begin
|
||||
@ -575,8 +600,7 @@ implementation
|
||||
handleImplementedProtocol(intfchildof);
|
||||
readImplementedInterfacesAndProtocols(current_objectdef.objecttype=odt_class);
|
||||
end;
|
||||
if not is_objectpascal_classhelper(current_objectdef) then
|
||||
consume(_RKLAMMER);
|
||||
consume(_RKLAMMER);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -780,7 +804,8 @@ implementation
|
||||
if object_member_blocktype=bt_general then
|
||||
begin
|
||||
if is_interface(current_structdef) or
|
||||
is_objc_protocol_or_category(current_structdef) then
|
||||
is_objc_protocol_or_category(current_structdef) or
|
||||
is_objectpascal_classhelper(current_structdef) then
|
||||
Message(parser_e_no_vars_in_interfaces);
|
||||
|
||||
if (current_structdef.symtable.currentvisibility=vis_published) and
|
||||
@ -938,6 +963,10 @@ implementation
|
||||
if is_interface(current_structdef) then
|
||||
Message(parser_e_no_con_des_in_interfaces);
|
||||
|
||||
{ (class) destructors are not allowed in class helpers }
|
||||
if is_objectpascal_classhelper(current_structdef) then
|
||||
Message(parser_e_no_destructor_in_records);
|
||||
|
||||
if not is_classdef and (current_structdef.symtable.currentvisibility<>vis_public) then
|
||||
Message(parser_w_destructor_should_be_public);
|
||||
|
||||
@ -1089,7 +1118,7 @@ implementation
|
||||
include(current_structdef.objectoptions,oo_is_classhelper);
|
||||
end;
|
||||
|
||||
{ change classhepers into Delphi type class helpers }
|
||||
{ change classhelpers into Object Pascal style class helpers }
|
||||
if (objecttype=odt_classhelper) then
|
||||
begin
|
||||
current_objectdef.objecttype:=odt_class;
|
||||
@ -1097,7 +1126,8 @@ implementation
|
||||
end;
|
||||
|
||||
{ parse list of options (abstract / sealed) }
|
||||
if not(objecttype in [odt_objcclass,odt_objcprotocol,odt_objccategory]) then
|
||||
if not(objecttype in [odt_objcclass,odt_objcprotocol,odt_objccategory]) and
|
||||
not is_objectpascal_classhelper(current_objectdef) then
|
||||
parse_object_options;
|
||||
|
||||
symtablestack.push(current_structdef.symtable);
|
||||
|
||||
@ -43,7 +43,7 @@ type
|
||||
{$endif Test_Double_checksum}
|
||||
|
||||
const
|
||||
CurrentPPUVersion = 126;
|
||||
CurrentPPUVersion = 127;
|
||||
|
||||
{ buffer sizes }
|
||||
maxentrysize = 1024;
|
||||
|
||||
@ -1546,7 +1546,6 @@ implementation
|
||||
if (idtoken=_HELPER) then
|
||||
begin
|
||||
consume(_HELPER);
|
||||
consume(_FOR);
|
||||
def:=object_dec(odt_classhelper,name,genericdef,genericlist,nil);
|
||||
end
|
||||
else
|
||||
|
||||
@ -255,6 +255,12 @@ interface
|
||||
childof : tobjectdef;
|
||||
childofderef : tderef;
|
||||
|
||||
{ for Object Pascal class helpers: the parent class helper is only
|
||||
used to extend the scope of a used class helper by another class
|
||||
helper for the same extended class or a superclass (which is defined
|
||||
by childof }
|
||||
helperparent : tobjectdef;
|
||||
helperparentderef: tderef;
|
||||
{ for C++ classes: name of the library this class is imported from }
|
||||
import_lib,
|
||||
{ for Objective-C: protocols and classes can have the same name there }
|
||||
@ -4095,6 +4101,9 @@ implementation
|
||||
iidstr:=stringdup(ppufile.getstring);
|
||||
end;
|
||||
|
||||
if oo_is_classhelper in objectoptions then
|
||||
ppufile.getderef(helperparentderef);
|
||||
|
||||
vmtentries:=TFPList.Create;
|
||||
vmtentries.count:=ppufile.getlongint;
|
||||
for i:=0 to vmtentries.count-1 do
|
||||
@ -4253,6 +4262,8 @@ implementation
|
||||
ppufile.putguid(iidguid^);
|
||||
ppufile.putstring(iidstr^);
|
||||
end;
|
||||
if oo_is_classhelper in objectoptions then
|
||||
ppufile.putderef(helperparentderef);
|
||||
|
||||
ppufile.putlongint(vmtentries.count);
|
||||
for i:=0 to vmtentries.count-1 do
|
||||
@ -4311,6 +4322,9 @@ implementation
|
||||
else
|
||||
tstoredsymtable(symtable).buildderef;
|
||||
|
||||
if oo_is_classhelper in objectoptions then
|
||||
helperparentderef.build(helperparent);
|
||||
|
||||
for i:=0 to vmtentries.count-1 do
|
||||
begin
|
||||
vmtentry:=pvmtentry(vmtentries[i]);
|
||||
@ -4339,6 +4353,8 @@ implementation
|
||||
end
|
||||
else
|
||||
tstoredsymtable(symtable).deref;
|
||||
if oo_is_classhelper in objectoptions then
|
||||
helperparent:=tobjectdef(helperparentderef.resolve);
|
||||
for i:=0 to vmtentries.count-1 do
|
||||
begin
|
||||
vmtentry:=pvmtentry(vmtentries[i]);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user