mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-15 23:29:13 +02:00
+ Objective-C category support (old and new ABI, both external and
implemented in Pascal). See http://wiki.freepascal.org/FPC_PasCocoa#Category_declaration for syntax details git-svn-id: trunk@14196 -
This commit is contained in:
parent
9e87f42b16
commit
f8754d8fab
11
.gitattributes
vendored
11
.gitattributes
vendored
@ -8963,6 +8963,13 @@ tests/test/tobjc20.pp svneol=native#text/plain
|
|||||||
tests/test/tobjc21.pp svneol=native#text/plain
|
tests/test/tobjc21.pp svneol=native#text/plain
|
||||||
tests/test/tobjc22.pp svneol=native#text/plain
|
tests/test/tobjc22.pp svneol=native#text/plain
|
||||||
tests/test/tobjc23.pp svneol=native#text/plain
|
tests/test/tobjc23.pp svneol=native#text/plain
|
||||||
|
tests/test/tobjc24.pp svneol=native#text/plain
|
||||||
|
tests/test/tobjc25.pp svneol=native#text/plain
|
||||||
|
tests/test/tobjc26.pp svneol=native#text/plain
|
||||||
|
tests/test/tobjc26a.pp svneol=native#text/plain
|
||||||
|
tests/test/tobjc27a.pp svneol=native#text/plain
|
||||||
|
tests/test/tobjc27b.pp svneol=native#text/plain
|
||||||
|
tests/test/tobjc28.pp svneol=native#text/plain
|
||||||
tests/test/tobjc3.pp svneol=native#text/plain
|
tests/test/tobjc3.pp svneol=native#text/plain
|
||||||
tests/test/tobjc4.pp svneol=native#text/plain
|
tests/test/tobjc4.pp svneol=native#text/plain
|
||||||
tests/test/tobjc4a.pp svneol=native#text/plain
|
tests/test/tobjc4a.pp svneol=native#text/plain
|
||||||
@ -9300,6 +9307,10 @@ tests/test/units/sysutils/tfloattostr.pp svneol=native#text/plain
|
|||||||
tests/test/units/sysutils/tlocale.pp svneol=native#text/plain
|
tests/test/units/sysutils/tlocale.pp svneol=native#text/plain
|
||||||
tests/test/units/sysutils/tsscanf.pp svneol=native#text/plain
|
tests/test/units/sysutils/tsscanf.pp svneol=native#text/plain
|
||||||
tests/test/units/sysutils/tstrtobool.pp svneol=native#text/plain
|
tests/test/units/sysutils/tstrtobool.pp svneol=native#text/plain
|
||||||
|
tests/test/uobjc24.pp svneol=native#text/plain
|
||||||
|
tests/test/uobjc26.pp svneol=native#text/plain
|
||||||
|
tests/test/uobjc27a.pp svneol=native#text/plain
|
||||||
|
tests/test/uobjc27b.pp svneol=native#text/plain
|
||||||
tests/test/uobjc7.pp svneol=native#text/plain
|
tests/test/uobjc7.pp svneol=native#text/plain
|
||||||
tests/test/uobjcl1.pp svneol=native#text/plain
|
tests/test/uobjcl1.pp svneol=native#text/plain
|
||||||
tests/test/uprec6.pp svneol=native#text/plain
|
tests/test/uprec6.pp svneol=native#text/plain
|
||||||
|
@ -366,7 +366,7 @@ scan_w_multiple_main_name_overrides=02086_W_Overriding name of "main" procedure
|
|||||||
#
|
#
|
||||||
# Parser
|
# Parser
|
||||||
#
|
#
|
||||||
# 03275 is the last used one
|
# 03280 is the last used one
|
||||||
#
|
#
|
||||||
% \section{Parser messages}
|
% \section{Parser messages}
|
||||||
% This section lists all parser messages. The parser takes care of the
|
% This section lists all parser messages. The parser takes care of the
|
||||||
@ -913,11 +913,11 @@ parser_e_no_con_des_in_interfaces=03171_E_Con- and destructors aren't allowed in
|
|||||||
% be used to create a new interface.
|
% be used to create a new interface.
|
||||||
parser_e_no_access_specifier_in_interfaces=03172_E_Access specifiers can't be used in INTERFACEs and OBJCPROTOCOLs
|
parser_e_no_access_specifier_in_interfaces=03172_E_Access specifiers can't be used in INTERFACEs and OBJCPROTOCOLs
|
||||||
% The access specifiers \var{public}, \var{private}, \var{protected} and
|
% The access specifiers \var{public}, \var{private}, \var{protected} and
|
||||||
% \var{published} can't be used in interfaces and Objective-C protocols because all methods
|
% \var{published} can't be used in interfaces, Objective-C protocols and categories because all methods
|
||||||
% of an interface/protocol must be public.
|
% of an interface/protocol/category must be public.
|
||||||
parser_e_no_vars_in_interfaces=03173_E_An interface or Objective-C protocol cannot contain fields
|
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. An interface/protocol
|
% Declarations of fields are not allowed in interfaces and Objective-C protocols and categories.
|
||||||
% can contain only methods and properties with method read/write specifiers.
|
% An interface/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
|
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
|
% Declaring local procedures as external is not possible. Local procedures
|
||||||
% get hidden parameters that will make the chance of errors very high.
|
% get hidden parameters that will make the chance of errors very high.
|
||||||
@ -992,7 +992,7 @@ parser_e_illegal_calling_convention=03195_W_Calling convention directive ignored
|
|||||||
% Some calling conventions are supported only by certain CPUs. I.e. most non-i386 ports support
|
% Some calling conventions are supported only by certain CPUs. I.e. most non-i386 ports support
|
||||||
% only the standard ABI calling convention of the CPU.
|
% only the standard ABI calling convention of the CPU.
|
||||||
parser_e_no_object_reintroduce=03196_E_REINTRODUCE can't be used in objects
|
parser_e_no_object_reintroduce=03196_E_REINTRODUCE can't be used in objects
|
||||||
% \var{reintroduce} is not supported for objects.
|
% \var{reintroduce} is not supported for objects, Objective-C classes and Objective-C protocols.
|
||||||
parser_e_paraloc_only_one_para=03197_E_Each argument must have its own location
|
parser_e_paraloc_only_one_para=03197_E_Each argument must have its own location
|
||||||
% If locations for arguments are specified explicitly as it is required by
|
% If locations for arguments are specified explicitly as it is required by
|
||||||
% some syscall conventions, each argument must have its own location. Things
|
% some syscall conventions, each argument must have its own location. Things
|
||||||
@ -1245,13 +1245,13 @@ parser_e_no_objc_published=03271_E_Objective-C classes cannot have published sec
|
|||||||
parser_f_need_objc=03272_F_This module requires an Objective-C mode switch to be compiled
|
parser_f_need_objc=03272_F_This module requires an Objective-C mode switch to be compiled
|
||||||
% This error indicates the use of Objective-C language features without an Objective-C mode switch
|
% This error indicates the use of Objective-C language features without an Objective-C mode switch
|
||||||
% active. Enable one via the -M command line switch, or the {\$modeswitch x} directive.
|
% active. Enable one via the -M command line switch, or the {\$modeswitch x} directive.
|
||||||
parser_e_must_use_override_objc=03273_E_Inherited methods can only be overridden in Objective-C, add ``override''.
|
parser_e_must_use_override_objc=03273_E_Inherited methods can only be overridden in Objective-C, add "override".
|
||||||
parser_h_should_use_override_objc=03274_H_Inherited methods can only be overridden in Objective-C, add ``override''.
|
parser_h_should_use_override_objc=03274_H_Inherited methods can only be overridden in Objective-C, add "override".
|
||||||
% It is not possible to ``reintroduce'' methods in Objective-C like in Object Pascal. Methods with the same
|
% It is not possible to \var{reintroduce} methods in Objective-C like in Object Pascal. Methods with the same
|
||||||
% name always map to the same virtual method entry. In order to make this clear in the source code,
|
% name always map to the same virtual method entry. In order to make this clear in the source code,
|
||||||
% the compiler always requires the ``override'' directive to be specified when implementing overriding
|
% the compiler always requires the \var{override} directive to be specified when implementing overriding
|
||||||
% Objective-C methods in Pascal. If the implementation is external, this rule is relaxed because Objective-C
|
% Objective-C methods in Pascal. If the implementation is external, this rule is relaxed because Objective-C
|
||||||
% does not have any ``override''-style keyword (since it's the default and only behaviour in that language),
|
% does not have any \var{override}-style keyword (since it's the default and only behaviour in that language),
|
||||||
% which makes it hard for automated header conversion tools to include it everywhere.
|
% which makes it hard for automated header conversion tools to include it everywhere.
|
||||||
parser_e_objc_message_name_changed=03275_E_Message name "$1" in inherited class is different from message name "$2" in current class.
|
parser_e_objc_message_name_changed=03275_E_Message name "$1" in inherited class is different from message name "$2" in current class.
|
||||||
% An overriding Objective-C method cannot have a different message name than an inherited method. The reason
|
% An overriding Objective-C method cannot have a different message name than an inherited method. The reason
|
||||||
@ -1260,11 +1260,24 @@ parser_e_objc_message_name_changed=03275_E_Message name "$1" in inherited class
|
|||||||
parser_e_no_objc_unique=03276_E_It is not yet possible to make unique copies of Objective-C types
|
parser_e_no_objc_unique=03276_E_It is not yet possible to make unique copies of Objective-C types
|
||||||
% Duplicating an Objective-C type using \var{type x = type y;} is not yet supported. You may be able to
|
% Duplicating an Objective-C type using \var{type x = type y;} is not yet supported. You may be able to
|
||||||
% obtain the desired effect using \var{type x = objcclass(y) end;} instead.
|
% obtain the desired effect using \var{type x = objcclass(y) end;} instead.
|
||||||
|
parser_e_no_category_as_types=03277_E_Objective-C categories cannot be used as types
|
||||||
|
% It is not possible to declare a variable as an instance of an Objective-C category. A
|
||||||
|
% category adds methods to the scope of an existing class, but does not define a type by itself.
|
||||||
|
parser_e_no_category_override=03278_E_Categories do not override, but replace methods. Use "reintroduce" instead.
|
||||||
|
parser_e_must_use_reintroduce_objc=03279_E_Replaced methods can only be reintroduced in Objective-C, add "reintroduce".
|
||||||
|
parser_h_should_use_reintroduce_objc=03280_H_Replaced methods can only be reintroduced in Objective-C, add "reintroduce".
|
||||||
|
% A category replaces an existing method in an Objective-C class, rather than that it overrides it.
|
||||||
|
% Calling an inherited method from an category method will call that method in
|
||||||
|
% the extended class' parent, not in the extended class itself. The
|
||||||
|
% replaced method in the original class is basically lost, and can no longer be
|
||||||
|
% called or referred to. This behaviour corresponds somewhat more closely to
|
||||||
|
% \var{reintroduce} than to \var{override} (although in case of \var{reintroduce}
|
||||||
|
% in Object Pascal, hidden methods are still reachable via inherited).
|
||||||
% \end{description}
|
% \end{description}
|
||||||
#
|
#
|
||||||
# Type Checking
|
# Type Checking
|
||||||
#
|
#
|
||||||
# 04093 is the last used one
|
# 04094 is the last used one
|
||||||
#
|
#
|
||||||
% \section{Type checking errors}
|
% \section{Type checking errors}
|
||||||
% This section lists all errors that can occur when type checking is
|
% This section lists all errors that can occur when type checking is
|
||||||
@ -1578,7 +1591,9 @@ type_e_objc_type_unsupported=04092_E_The type "$1" is not supported for interact
|
|||||||
% interfaces) cannot be used as fields of Objective-C classes, cannot be
|
% interfaces) cannot be used as fields of Objective-C classes, cannot be
|
||||||
% directly passed to Objective-C methods, and cannot be encoded using \var{objc_encode}.
|
% directly passed to Objective-C methods, and cannot be encoded using \var{objc_encode}.
|
||||||
type_e_class_or_objcclass_type_expected=04093_E_Class or objcclass type expected, but got "$1"
|
type_e_class_or_objcclass_type_expected=04093_E_Class or objcclass type expected, but got "$1"
|
||||||
% It is only possible to create class reference types of \var{class} and
|
% It is only possible to create class reference types of \var{class} and \var{objcclass}
|
||||||
|
type_e_objcclass_type_expected=04094_E_Objcclass type expected
|
||||||
|
% The compiler expected an Objc
|
||||||
% \var{objcclass} types
|
% \var{objcclass} types
|
||||||
%
|
%
|
||||||
% \end{description}
|
% \end{description}
|
||||||
|
@ -364,6 +364,10 @@ const
|
|||||||
parser_h_should_use_override_objc=03274;
|
parser_h_should_use_override_objc=03274;
|
||||||
parser_e_objc_message_name_changed=03275;
|
parser_e_objc_message_name_changed=03275;
|
||||||
parser_e_no_objc_unique=03276;
|
parser_e_no_objc_unique=03276;
|
||||||
|
parser_e_no_category_as_types=03277;
|
||||||
|
parser_e_no_category_override=03278;
|
||||||
|
parser_e_must_use_reintroduce_objc=03279;
|
||||||
|
parser_h_should_use_reintroduce_objc=03280;
|
||||||
type_e_mismatch=04000;
|
type_e_mismatch=04000;
|
||||||
type_e_incompatible_types=04001;
|
type_e_incompatible_types=04001;
|
||||||
type_e_not_equal_types=04002;
|
type_e_not_equal_types=04002;
|
||||||
@ -448,6 +452,7 @@ const
|
|||||||
type_e_protocol_type_expected=04091;
|
type_e_protocol_type_expected=04091;
|
||||||
type_e_objc_type_unsupported=04092;
|
type_e_objc_type_unsupported=04092;
|
||||||
type_e_class_or_objcclass_type_expected=04093;
|
type_e_class_or_objcclass_type_expected=04093;
|
||||||
|
type_e_objcclass_type_expected=04094;
|
||||||
sym_e_id_not_found=05000;
|
sym_e_id_not_found=05000;
|
||||||
sym_f_internal_error_in_symtablestack=05001;
|
sym_f_internal_error_in_symtablestack=05001;
|
||||||
sym_e_duplicate_id=05002;
|
sym_e_duplicate_id=05002;
|
||||||
@ -827,9 +832,9 @@ const
|
|||||||
option_info=11024;
|
option_info=11024;
|
||||||
option_help_pages=11025;
|
option_help_pages=11025;
|
||||||
|
|
||||||
MsgTxtSize = 54197;
|
MsgTxtSize = 54546;
|
||||||
|
|
||||||
MsgIdxMax : array[1..20] of longint=(
|
MsgIdxMax : array[1..20] of longint=(
|
||||||
24,87,277,94,71,51,108,22,202,62,
|
24,87,281,95,71,51,108,22,202,62,
|
||||||
48,20,1,1,1,1,1,1,1,1
|
48,20,1,1,1,1,1,1,1,1
|
||||||
);
|
);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -281,8 +281,12 @@ implementation
|
|||||||
if (po_virtualmethod in vmtpd.procoptions) and
|
if (po_virtualmethod in vmtpd.procoptions) and
|
||||||
(
|
(
|
||||||
not(po_virtualmethod in pd.procoptions) or
|
not(po_virtualmethod in pd.procoptions) or
|
||||||
{ new one has not override }
|
(
|
||||||
(is_class_or_interface_or_objc(_class) and not(po_overridingmethod in pd.procoptions))
|
{ new one does not have reintroduce in case of an objccategory }
|
||||||
|
(is_objccategory(_class) and not(po_reintroduce in pd.procoptions)) or
|
||||||
|
{ new one does not have override in case of objpas/objc class/intf/proto }
|
||||||
|
(is_class_or_interface_or_objc(_class) and not is_objccategory(_class) and not(po_overridingmethod in pd.procoptions))
|
||||||
|
)
|
||||||
) then
|
) then
|
||||||
begin
|
begin
|
||||||
if (
|
if (
|
||||||
@ -305,12 +309,18 @@ implementation
|
|||||||
because requiring override everywhere may make
|
because requiring override everywhere may make
|
||||||
automated header translation tools too complex. }
|
automated header translation tools too complex. }
|
||||||
if not(oo_is_external in _class.objectoptions) then
|
if not(oo_is_external in _class.objectoptions) then
|
||||||
MessagePos1(pd.fileinfo,parser_e_must_use_override_objc,pd.fullprocname(false))
|
if not is_objccategory(_class) then
|
||||||
|
MessagePos1(pd.fileinfo,parser_e_must_use_override_objc,pd.fullprocname(false))
|
||||||
|
else
|
||||||
|
MessagePos1(pd.fileinfo,parser_e_must_use_reintroduce_objc,pd.fullprocname(false))
|
||||||
{ there may be a lot of these in auto-translated
|
{ there may be a lot of these in auto-translated
|
||||||
heaeders, so only calculate the fullprocname if
|
heaeders, so only calculate the fullprocname if
|
||||||
the hint will be shown }
|
the hint will be shown }
|
||||||
else if CheckVerbosity(V_Hint) then
|
else if CheckVerbosity(V_Hint) then
|
||||||
MessagePos1(pd.fileinfo,parser_h_should_use_override_objc,pd.fullprocname(false));
|
if not is_objccategory(_class) then
|
||||||
|
MessagePos1(pd.fileinfo,parser_h_should_use_override_objc,pd.fullprocname(false))
|
||||||
|
else
|
||||||
|
MessagePos1(pd.fileinfo,parser_h_should_use_reintroduce_objc,pd.fullprocname(false));
|
||||||
{ no new entry, but copy the message name if any from
|
{ no new entry, but copy the message name if any from
|
||||||
the procdef in the parent class }
|
the procdef in the parent class }
|
||||||
check_msg_str(vmtpd,pd);
|
check_msg_str(vmtpd,pd);
|
||||||
|
@ -56,13 +56,16 @@ implementation
|
|||||||
tobjcrttiwriter = class
|
tobjcrttiwriter = class
|
||||||
protected
|
protected
|
||||||
fabi: tobjcabi;
|
fabi: tobjcabi;
|
||||||
classdefs: tfpobjectlist;
|
classdefs,
|
||||||
classsyms: tfpobjectlist;
|
catdefs: tfpobjectlist;
|
||||||
|
classsyms,
|
||||||
|
catsyms: tfpobjectlist;
|
||||||
procedure gen_objc_methods(list: tasmlist; objccls: tobjectdef; out methodslabel: tasmlabel; classmethods, iscategory: Boolean);
|
procedure gen_objc_methods(list: tasmlist; objccls: tobjectdef; out methodslabel: tasmlabel; classmethods, iscategory: Boolean);
|
||||||
procedure gen_objc_protocol_list(list:TAsmList; protolist: TFPObjectList; out protolistsym: TAsmLabel);
|
procedure gen_objc_protocol_list(list:TAsmList; protolist: TFPObjectList; out protolistsym: TAsmLabel);
|
||||||
procedure gen_objc_cat_methods(list:TAsmList; items: TFPObjectList; section: tasmsectiontype;const sectname: string; out listsym: TAsmLabel);
|
procedure gen_objc_cat_methods(list:TAsmList; items: TFPObjectList; section: tasmsectiontype;const sectname: string; out listsym: TAsmLabel);
|
||||||
|
|
||||||
procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);virtual;abstract;
|
procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);virtual;abstract;
|
||||||
|
procedure gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);virtual;abstract;
|
||||||
procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);virtual;abstract;
|
procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);virtual;abstract;
|
||||||
procedure gen_objc_info_sections(list: tasmlist);virtual;abstract;
|
procedure gen_objc_info_sections(list: tasmlist);virtual;abstract;
|
||||||
public
|
public
|
||||||
@ -78,6 +81,7 @@ implementation
|
|||||||
protected
|
protected
|
||||||
procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel);
|
procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel);
|
||||||
procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override;
|
procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override;
|
||||||
|
procedure gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);override;
|
||||||
procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);override;
|
procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);override;
|
||||||
procedure gen_objc_info_sections(list: tasmlist);override;
|
procedure gen_objc_info_sections(list: tasmlist);override;
|
||||||
public
|
public
|
||||||
@ -96,6 +100,7 @@ implementation
|
|||||||
|
|
||||||
procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel);
|
procedure gen_objc_ivars(list: TAsmList; objccls: tobjectdef; out ivarslabel: TAsmLabel);
|
||||||
procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override;
|
procedure gen_objc_protocol(list:TAsmList; protocol: tobjectdef; out protocollabel: TAsmSymbol);override;
|
||||||
|
procedure gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);override;
|
||||||
procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);override;
|
procedure gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);override;
|
||||||
procedure gen_objc_info_sections(list: tasmlist);override;
|
procedure gen_objc_info_sections(list: tasmlist);override;
|
||||||
public
|
public
|
||||||
@ -277,7 +282,7 @@ procedure tobjcrttiwriter.gen_objc_methods(list: tasmlist; objccls: tobjectdef;
|
|||||||
for i:=0 to objccls.vmtentries.count-1 do
|
for i:=0 to objccls.vmtentries.count-1 do
|
||||||
begin
|
begin
|
||||||
def:=pvmtentry(objccls.vmtentries[i])^.procdef;
|
def:=pvmtentry(objccls.vmtentries[i])^.procdef;
|
||||||
if Assigned(def.procstarttai) and
|
if (def.owner.defowner=objccls) and
|
||||||
(classmethods = (po_classmethod in def.procoptions)) then
|
(classmethods = (po_classmethod in def.procoptions)) then
|
||||||
begin
|
begin
|
||||||
defs[mcnt].def:=def;
|
defs[mcnt].def:=def;
|
||||||
@ -290,9 +295,9 @@ procedure tobjcrttiwriter.gen_objc_methods(list: tasmlist; objccls: tobjectdef;
|
|||||||
exit;
|
exit;
|
||||||
|
|
||||||
if iscategory then
|
if iscategory then
|
||||||
new_section(list,clsSectType[classmethods],clsSectName[classmethods],sizeof(ptrint))
|
new_section(list,catSectType[classmethods],catSectName[classmethods],sizeof(ptrint))
|
||||||
else
|
else
|
||||||
new_section(list,catSectType[classmethods],catSectName[classmethods],sizeof(ptrint));
|
new_section(list,clsSectType[classmethods],clsSectName[classmethods],sizeof(ptrint));
|
||||||
|
|
||||||
current_asmdata.getlabel(methodslabel,alt_data);
|
current_asmdata.getlabel(methodslabel,alt_data);
|
||||||
list.Concat(tai_label.Create(methodslabel));
|
list.Concat(tai_label.Create(methodslabel));
|
||||||
@ -441,9 +446,18 @@ procedure tobjcrttiwriter.gen_objc_rtti_sections(list:TAsmList; st:TSymtable);
|
|||||||
if is_objcclass(def) and
|
if is_objcclass(def) and
|
||||||
not(oo_is_external in tobjectdef(def).objectoptions) then
|
not(oo_is_external in tobjectdef(def).objectoptions) then
|
||||||
begin
|
begin
|
||||||
gen_objc_classes_sections(list,tobjectdef(def),sym);
|
if not(oo_is_classhelper in tobjectdef(def).objectoptions) then
|
||||||
classsyms.add(sym);
|
begin
|
||||||
classdefs.add(def);
|
gen_objc_classes_sections(list,tobjectdef(def),sym);
|
||||||
|
classsyms.add(sym);
|
||||||
|
classdefs.add(def);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
gen_objc_category_sections(list,tobjectdef(def),sym);
|
||||||
|
catsyms.add(sym);
|
||||||
|
catdefs.add(def);
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -454,6 +468,8 @@ constructor tobjcrttiwriter.create(_abi: tobjcabi);
|
|||||||
fabi:=_abi;
|
fabi:=_abi;
|
||||||
classdefs:=tfpobjectlist.create(false);
|
classdefs:=tfpobjectlist.create(false);
|
||||||
classsyms:=tfpobjectlist.create(false);
|
classsyms:=tfpobjectlist.create(false);
|
||||||
|
catdefs:=tfpobjectlist.create(false);
|
||||||
|
catsyms:=tfpobjectlist.create(false);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -461,6 +477,8 @@ destructor tobjcrttiwriter.destroy;
|
|||||||
begin
|
begin
|
||||||
classdefs.free;
|
classdefs.free;
|
||||||
classsyms.free;
|
classsyms.free;
|
||||||
|
catdefs.free;
|
||||||
|
catsyms.free;
|
||||||
inherited destroy;
|
inherited destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -584,6 +602,61 @@ procedure tobjcrttiwriter_fragile.gen_objc_protocol(list:TAsmList; protocol: tob
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
(*
|
||||||
|
From Clang:
|
||||||
|
|
||||||
|
struct _objc_category {
|
||||||
|
char *category_name;
|
||||||
|
char *class_name;
|
||||||
|
struct _objc_method_list *instance_methods;
|
||||||
|
struct _objc_method_list *class_methods;
|
||||||
|
struct _objc_protocol_list *protocols;
|
||||||
|
uint32_t size; // <rdar://4585769>
|
||||||
|
struct _objc_property_list *instance_properties;
|
||||||
|
};
|
||||||
|
*)
|
||||||
|
|
||||||
|
{ Generate rtti for an Objective-C class and its meta-class. }
|
||||||
|
procedure tobjcrttiwriter_fragile.gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);
|
||||||
|
var
|
||||||
|
instmthdlist,
|
||||||
|
clsmthdlist,
|
||||||
|
protolistsym : TAsmLabel;
|
||||||
|
catstrsym,
|
||||||
|
clsstrsym,
|
||||||
|
catsym : TAsmSymbol;
|
||||||
|
begin
|
||||||
|
{ the category name }
|
||||||
|
catstrsym:=objcreatestringpoolentry(objccat.objextname^,sp_objcclassnames,sec_objc_class_names);
|
||||||
|
|
||||||
|
{ the name of the class it extends }
|
||||||
|
clsstrsym:=objcreatestringpoolentry(objccat.childof.objextname^,sp_objcclassnames,sec_objc_class_names);
|
||||||
|
|
||||||
|
{ generate the methods lists }
|
||||||
|
gen_objc_methods(list,objccat,instmthdlist,false,true);
|
||||||
|
gen_objc_methods(list,objccat,clsmthdlist,true,true);
|
||||||
|
|
||||||
|
{ generate implemented protocols list }
|
||||||
|
gen_objc_protocol_list(list,objccat.ImplementedInterfaces,protolistsym);
|
||||||
|
|
||||||
|
{ category declaration section }
|
||||||
|
new_section(list,sec_objc_category,'_OBJC_CATEGORY',sizeof(pint));
|
||||||
|
catsym:=current_asmdata.DefineAsmSymbol(objccat.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA);
|
||||||
|
list.Concat(tai_symbol.Create(catsym,0));
|
||||||
|
|
||||||
|
list.Concat(Tai_const.Create_sym(catstrsym));
|
||||||
|
list.Concat(Tai_const.Create_sym(clsstrsym));
|
||||||
|
ConcatSymOrNil(list,instmthdlist);
|
||||||
|
ConcatSymOrNil(list,clsmthdlist);
|
||||||
|
ConcatSymOrNil(list,protolistsym);
|
||||||
|
{ size of this structure }
|
||||||
|
list.Concat(Tai_const.Create_32bit(28));
|
||||||
|
{ properties, not yet supported }
|
||||||
|
list.Concat(Tai_const.Create_32bit(0));
|
||||||
|
|
||||||
|
catlabel:=catsym;
|
||||||
|
end;
|
||||||
|
|
||||||
(*
|
(*
|
||||||
From Clang:
|
From Clang:
|
||||||
|
|
||||||
@ -604,6 +677,8 @@ From Clang:
|
|||||||
};
|
};
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ Generate rtti for an Objective-C class and its meta-class. }
|
{ Generate rtti for an Objective-C class and its meta-class. }
|
||||||
procedure tobjcrttiwriter_fragile.gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);
|
procedure tobjcrttiwriter_fragile.gen_objc_classes_sections(list:TAsmList; objclss: tobjectdef; out classlabel: TAsmSymbol);
|
||||||
const
|
const
|
||||||
@ -705,7 +780,7 @@ procedure tobjcrttiwriter_fragile.gen_objc_classes_sections(list:TAsmList; objcl
|
|||||||
clssym:=current_asmdata.DefineAsmSymbol(objclss.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA);
|
clssym:=current_asmdata.DefineAsmSymbol(objclss.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA);
|
||||||
list.Concat(tai_symbol.Create(clssym,0));
|
list.Concat(tai_symbol.Create(clssym,0));
|
||||||
|
|
||||||
{ for class declaration: the is points to the meta-class declaration }
|
{ for class declaration: the isa points to the meta-class declaration }
|
||||||
list.Concat(Tai_const.Create_sym(metasym));
|
list.Concat(Tai_const.Create_sym(metasym));
|
||||||
{ pointer to the super_class name if any, nil otherwise }
|
{ pointer to the super_class name if any, nil otherwise }
|
||||||
if assigned(superStrSym) then
|
if assigned(superStrSym) then
|
||||||
@ -752,7 +827,8 @@ procedure tobjcrttiwriter_fragile.gen_objc_info_sections(list: tasmlist);
|
|||||||
parent: tobjectdef;
|
parent: tobjectdef;
|
||||||
superclasses: tfpobjectlist;
|
superclasses: tfpobjectlist;
|
||||||
begin
|
begin
|
||||||
if (classsyms.count<>0) then
|
if (classsyms.count<>0) or
|
||||||
|
(catsyms.count<>0) then
|
||||||
begin
|
begin
|
||||||
new_section(list,sec_objc_symbols,'_OBJC_SYMBOLS',sizeof(pint));
|
new_section(list,sec_objc_symbols,'_OBJC_SYMBOLS',sizeof(pint));
|
||||||
sym := current_asmdata.DefineAsmSymbol(target_asm.labelprefix+'_OBJC_SYMBOLS_$',AB_LOCAL,AT_DATA);
|
sym := current_asmdata.DefineAsmSymbol(target_asm.labelprefix+'_OBJC_SYMBOLS_$',AB_LOCAL,AT_DATA);
|
||||||
@ -766,11 +842,13 @@ procedure tobjcrttiwriter_fragile.gen_objc_info_sections(list: tasmlist);
|
|||||||
{ From Clang: number of defined classes }
|
{ From Clang: number of defined classes }
|
||||||
list.Concat(Tai_const.Create_16bit(classsyms.count));
|
list.Concat(Tai_const.Create_16bit(classsyms.count));
|
||||||
{ From Clang: number of defined categories }
|
{ From Clang: number of defined categories }
|
||||||
list.Concat(Tai_const.Create_16bit(0));
|
list.Concat(Tai_const.Create_16bit(catsyms.count));
|
||||||
{ first all classes }
|
{ first all classes }
|
||||||
for i:=0 to classsyms.count-1 do
|
for i:=0 to classsyms.count-1 do
|
||||||
list.Concat(Tai_const.Create_sym(tasmsymbol(classsyms[i])));
|
list.Concat(Tai_const.Create_sym(tasmsymbol(classsyms[i])));
|
||||||
{ then all categories }
|
{ then all categories }
|
||||||
|
for i:=0 to catsyms.count-1 do
|
||||||
|
list.Concat(Tai_const.Create_sym(tasmsymbol(catsyms[i])));
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
sym:=nil;
|
sym:=nil;
|
||||||
@ -801,10 +879,25 @@ procedure tobjcrttiwriter_fragile.gen_objc_info_sections(list: tasmlist);
|
|||||||
superclasses.add(parent);
|
superclasses.add(parent);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
for i:=0 to catdefs.count-1 do
|
||||||
|
begin
|
||||||
|
parent:=tobjectdef(catdefs[i]).childof;
|
||||||
|
{ warning: linear search, performance hazard if large number of subclasses }
|
||||||
|
if assigned(parent) and
|
||||||
|
(superclasses.indexof(parent)=-1) then
|
||||||
|
begin
|
||||||
|
list.concat(tai_directive.create(asd_lazy_reference,'.objc_class_name_'+parent.objextname^));
|
||||||
|
superclasses.add(parent);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
superclasses.free;
|
superclasses.free;
|
||||||
{ reference symbols for all classes defined in this unit }
|
{ reference symbols for all classes and categories defined in this unit }
|
||||||
for i:=0 to classdefs.count-1 do
|
for i:=0 to classdefs.count-1 do
|
||||||
list.concat(tai_symbol.Createname_global_value('.objc_class_name_'+tobjectdef(classdefs[i]).objextname^,AT_DATA,0,0));
|
list.concat(tai_symbol.Createname_global_value('.objc_class_name_'+tobjectdef(classdefs[i]).objextname^,AT_DATA,0,0));
|
||||||
|
for i:=0 to catdefs.count-1 do
|
||||||
|
list.concat(tai_symbol.Createname_global_value('.objc_category_name_'+
|
||||||
|
tobjectdef(catdefs[i]).childof.objextname^+'_'+
|
||||||
|
tobjectdef(catdefs[i]).objextname^,AT_DATA,0,0));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -1043,6 +1136,55 @@ procedure tobjcrttiwriter_nonfragile.gen_objc_protocol(list: tasmlist; protocol:
|
|||||||
list.Concat(tai_directive.Create(asd_weak_definition,listsym.name));
|
list.Concat(tai_directive.Create(asd_weak_definition,listsym.name));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
(*
|
||||||
|
From Clang:
|
||||||
|
/// struct _category_t {
|
||||||
|
/// const char * const name;
|
||||||
|
/// struct _class_t *const cls;
|
||||||
|
/// const struct _method_list_t * const instance_methods;
|
||||||
|
/// const struct _method_list_t * const class_methods;
|
||||||
|
/// const struct _protocol_list_t * const protocols;
|
||||||
|
/// const struct _prop_list_t * const properties;
|
||||||
|
/// }
|
||||||
|
*)
|
||||||
|
procedure tobjcrttiwriter_nonfragile.gen_objc_category_sections(list:TAsmList; objccat: tobjectdef; out catlabel: TAsmSymbol);
|
||||||
|
var
|
||||||
|
instmthdlist,
|
||||||
|
clsmthdlist,
|
||||||
|
protolistsym : TAsmLabel;
|
||||||
|
catstrsym,
|
||||||
|
clssym,
|
||||||
|
catsym : TAsmSymbol;
|
||||||
|
begin
|
||||||
|
{ the category name }
|
||||||
|
catstrsym:=objcreatestringpoolentry(objccat.objextname^,sp_objcclassnames,sec_objc_class_names);
|
||||||
|
|
||||||
|
{ the class it extends }
|
||||||
|
clssym:=current_asmdata.RefAsmSymbol(objccat.childof.rtti_mangledname(objcclassrtti));
|
||||||
|
|
||||||
|
{ generate the methods lists }
|
||||||
|
gen_objc_methods(list,objccat,instmthdlist,false,true);
|
||||||
|
gen_objc_methods(list,objccat,clsmthdlist,true,true);
|
||||||
|
|
||||||
|
{ generate implemented protocols list }
|
||||||
|
gen_objc_protocol_list(list,objccat.ImplementedInterfaces,protolistsym);
|
||||||
|
|
||||||
|
{ category declaration section }
|
||||||
|
new_section(list,sec_objc_const,'_OBJC_CATEGORY',sizeof(pint));
|
||||||
|
catsym:=current_asmdata.DefineAsmSymbol(objccat.rtti_mangledname(objcclassrtti),AB_LOCAL,AT_DATA);
|
||||||
|
list.Concat(tai_symbol.Create(catsym,0));
|
||||||
|
|
||||||
|
list.Concat(Tai_const.Create_sym(catstrsym));
|
||||||
|
list.Concat(Tai_const.Create_sym(clssym));
|
||||||
|
ConcatSymOrNil(list,instmthdlist);
|
||||||
|
ConcatSymOrNil(list,clsmthdlist);
|
||||||
|
ConcatSymOrNil(list,protolistsym);
|
||||||
|
{ properties, not yet supported }
|
||||||
|
list.Concat(Tai_const.Create_pint(0));
|
||||||
|
|
||||||
|
catlabel:=catsym;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
(*
|
(*
|
||||||
From Clang:
|
From Clang:
|
||||||
@ -1363,45 +1505,58 @@ procedure tobjcrttiwriter_nonfragile.addclasslist(list: tasmlist; section: tasms
|
|||||||
|
|
||||||
procedure tobjcrttiwriter_nonfragile.gen_objc_info_sections(list: tasmlist);
|
procedure tobjcrttiwriter_nonfragile.gen_objc_info_sections(list: tasmlist);
|
||||||
|
|
||||||
|
function collectnonlazyclasses(classes: tfpobjectlist): tfpobjectlist;
|
||||||
|
var
|
||||||
|
symentry : tsym;
|
||||||
|
procdef : tprocdef;
|
||||||
|
i,j : longint;
|
||||||
|
begin
|
||||||
|
{ non-lazy classes are all classes that define a class method with the
|
||||||
|
selector called "load" (simply inheriting this class method is not enough,
|
||||||
|
they have to implement it themselves)
|
||||||
|
|
||||||
|
-- TODO: this currently only works if the Pascal identifier is also 'load'! }
|
||||||
|
result:=tfpobjectlist.create(false);
|
||||||
|
for i:=0 to classes.count-1 do
|
||||||
|
begin
|
||||||
|
symentry:=tsym(tobjectsymtable(tobjectdef(classes[i]).symtable).find('LOAD'));
|
||||||
|
if assigned(symentry) and
|
||||||
|
(symentry.typ=procsym) then
|
||||||
|
begin
|
||||||
|
for j:=0 to tprocsym(symentry).ProcdefList.count do
|
||||||
|
begin
|
||||||
|
procdef:=tprocdef(tprocsym(symentry).ProcdefList[0]);
|
||||||
|
if ((po_classmethod in procdef.procoptions) and
|
||||||
|
(procdef.messageinf.str^='load')) then
|
||||||
|
begin
|
||||||
|
result.add(classes[i]);
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
i,j : longint;
|
nonlazyclasses,
|
||||||
symentry : tsym;
|
nonlazycategories : tfpobjectlist;
|
||||||
procdef : tprocdef;
|
|
||||||
nonlazyclasses : tfpobjectlist;
|
|
||||||
begin
|
begin
|
||||||
if (classsyms.count=0) then
|
if (classdefs.count=0) and
|
||||||
|
(catdefs.count=0) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
{ non-lazy classes are all classes that define a class method with the
|
nonlazyclasses:=collectnonlazyclasses(classdefs);
|
||||||
selector called "load" (simply inheriting this class method is not enough,
|
nonlazycategories:=collectnonlazyclasses(catdefs);
|
||||||
they have to implement it themselves)
|
|
||||||
|
|
||||||
-- TODO: this currently only works if the Pascal identifier is also 'load'! }
|
|
||||||
nonlazyclasses:=tfpobjectlist.create(false);
|
|
||||||
for i:=0 to classdefs.count-1 do
|
|
||||||
begin
|
|
||||||
symentry:=tsym(tobjectsymtable(tobjectdef(classdefs[i]).symtable).find('LOAD'));
|
|
||||||
if assigned(symentry) and
|
|
||||||
(symentry.typ=procsym) then
|
|
||||||
begin
|
|
||||||
for j:=0 to tprocsym(symentry).ProcdefList.count do
|
|
||||||
begin
|
|
||||||
procdef:=tprocdef(tprocsym(symentry).ProcdefList[0]);
|
|
||||||
if ((po_classmethod in procdef.procoptions) and
|
|
||||||
(procdef.messageinf.str^='load')) then
|
|
||||||
begin
|
|
||||||
nonlazyclasses.add(classdefs[i]);
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ this list has to include all classes, also the non-lazy ones }
|
{ this list has to include all classes, also the non-lazy ones }
|
||||||
addclasslist(list,sec_objc_classlist,target_asm.labelprefix+'_OBJC_LABEL_CLASS_$',classdefs);
|
addclasslist(list,sec_objc_classlist,target_asm.labelprefix+'_OBJC_LABEL_CLASS_$',classdefs);
|
||||||
addclasslist(list,sec_objc_nlclasslist,target_asm.labelprefix+'_OBJC_LABEL_NONLAZY_CLASS_$',nonlazyclasses);
|
addclasslist(list,sec_objc_nlclasslist,target_asm.labelprefix+'_OBJC_LABEL_NONLAZY_CLASS_$',nonlazyclasses);
|
||||||
{ TODO: category and non-lazy category lists }
|
{ category and non-lazy category lists }
|
||||||
|
addclasslist(list,sec_objc_catlist,target_asm.labelprefix+'_OBJC_LABEL_CATEGORY_$',catdefs);
|
||||||
|
addclasslist(list,sec_objc_nlcatlist,target_asm.labelprefix+'_OBJC_LABEL_NONLAZY_CATEGORY_$',nonlazycategories);
|
||||||
|
|
||||||
|
nonlazyclasses.free;
|
||||||
|
nonlazycategories.free;
|
||||||
{ the non-fragile abi doesn't have any module info, nor lazy references
|
{ the non-fragile abi doesn't have any module info, nor lazy references
|
||||||
to used classes or to parent classes }
|
to used classes or to parent classes }
|
||||||
end;
|
end;
|
||||||
@ -1431,7 +1586,7 @@ procedure MaybeGenerateObjectiveCImageInfo(globalst, localst: tsymtable);
|
|||||||
current_asmdata.asmlists[al_objc_data].concat(Tai_symbol.Createname(target_asm.labelprefix+'_OBJC_IMAGE_INFO',AT_LABEL,sizeof(pint)));
|
current_asmdata.asmlists[al_objc_data].concat(Tai_symbol.Createname(target_asm.labelprefix+'_OBJC_IMAGE_INFO',AT_LABEL,sizeof(pint)));
|
||||||
current_asmdata.asmlists[al_objc_data].concat(Tai_const.Create_64bit(0));
|
current_asmdata.asmlists[al_objc_data].concat(Tai_const.Create_64bit(0));
|
||||||
|
|
||||||
{ generate rtti for all obj-c classes, protocols and categories (todo)
|
{ generate rtti for all obj-c classes, protocols and categories
|
||||||
defined in this module. }
|
defined in this module. }
|
||||||
if not(target_info.system in system_objc_nfabi) then
|
if not(target_info.system in system_objc_nfabi) then
|
||||||
objcrttiwriter:=tobjcrttiwriter_fragile.create
|
objcrttiwriter:=tobjcrttiwriter_fragile.create
|
||||||
|
@ -117,11 +117,22 @@ end;
|
|||||||
objcsuperclassnode
|
objcsuperclassnode
|
||||||
*******************************************************************}
|
*******************************************************************}
|
||||||
|
|
||||||
|
function objcloadbasefield(n: tnode; const fieldname: string): tnode;
|
||||||
|
var
|
||||||
|
vs : tsym;
|
||||||
|
begin
|
||||||
|
result:=ctypeconvnode.create_internal(cderefnode.create(ctypeconvnode.create_internal(n,voidpointertype)),objc_objecttype);
|
||||||
|
vs:=tsym(tabstractrecorddef(objc_objecttype).symtable.Find(fieldname));
|
||||||
|
if not assigned(vs) or
|
||||||
|
(vs.typ<>fieldvarsym) then
|
||||||
|
internalerror(200911301);
|
||||||
|
result:=csubscriptnode.create(vs,result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function objcsuperclassnode(def: tdef): tnode;
|
function objcsuperclassnode(def: tdef): tnode;
|
||||||
var
|
var
|
||||||
para : tcallparanode;
|
para : tcallparanode;
|
||||||
class_type : tdef;
|
|
||||||
vs : tsym;
|
|
||||||
begin
|
begin
|
||||||
{ only valid for Objective-C classes and classrefs }
|
{ only valid for Objective-C classes and classrefs }
|
||||||
if not is_objcclass(def) and
|
if not is_objcclass(def) and
|
||||||
@ -131,11 +142,30 @@ end;
|
|||||||
requires extra node types. Maybe later. }
|
requires extra node types. Maybe later. }
|
||||||
if is_objcclassref(def) then
|
if is_objcclassref(def) then
|
||||||
begin
|
begin
|
||||||
para:=ccallparanode.create(cstringconstnode.createstr(tobjectdef(tclassrefdef(def).pointeddef).objextname^),nil);
|
if (oo_is_classhelper in tobjectdef(tclassrefdef(def).pointeddef).objectoptions) then
|
||||||
result:=ccallnode.createinternfromunit('OBJC','OBJC_GETMETACLASS',para);
|
begin
|
||||||
|
{ in case we are in a category method, we need the metaclass of the
|
||||||
|
superclass class extended by this category (= metaclass of superclass of superclass) }
|
||||||
|
result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof.childof));
|
||||||
|
result:=objcloadbasefield(result,'ISA');
|
||||||
|
typecheckpass(result);
|
||||||
|
{ we're done }
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{ otherwise we need the superclass of the metaclass }
|
||||||
|
para:=ccallparanode.create(cstringconstnode.createstr(tobjectdef(tclassrefdef(def).pointeddef).objextname^),nil);
|
||||||
|
result:=ccallnode.createinternfromunit('OBJC','OBJC_GETMETACLASS',para);
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
result:=cloadvmtaddrnode.create(ctypenode.create(def));
|
begin
|
||||||
|
if not(oo_is_classhelper in tobjectdef(def).objectoptions) then
|
||||||
|
result:=cloadvmtaddrnode.create(ctypenode.create(def))
|
||||||
|
else
|
||||||
|
result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(def).childof))
|
||||||
|
end;
|
||||||
|
|
||||||
{$if defined(onlymacosx10_6) or defined(arm) }
|
{$if defined(onlymacosx10_6) or defined(arm) }
|
||||||
{ For the non-fragile ABI, the superclass send2 method itself loads the
|
{ For the non-fragile ABI, the superclass send2 method itself loads the
|
||||||
@ -145,15 +175,7 @@ end;
|
|||||||
(but also on all iPhone SDK revisions we support) }
|
(but also on all iPhone SDK revisions we support) }
|
||||||
if not(target_info.system in system_objc_nfabi) then
|
if not(target_info.system in system_objc_nfabi) then
|
||||||
{$endif onlymacosx10_6 or arm}
|
{$endif onlymacosx10_6 or arm}
|
||||||
begin
|
result:=objcloadbasefield(result,'SUPERCLASS');
|
||||||
class_type:=search_named_unit_globaltype('OBJC','OBJC_OBJECT').typedef;
|
|
||||||
result:=ctypeconvnode.create_internal(cderefnode.create(ctypeconvnode.create_internal(result,voidpointertype)),class_type);
|
|
||||||
vs:=tsym(tabstractrecorddef(class_type).symtable.Find('SUPERCLASS'));
|
|
||||||
if not assigned(vs) or
|
|
||||||
(vs.typ<>fieldvarsym) then
|
|
||||||
internalerror(200909301);
|
|
||||||
result:=csubscriptnode.create(vs,result);
|
|
||||||
end;
|
|
||||||
typecheckpass(result);
|
typecheckpass(result);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -440,7 +440,8 @@ implementation
|
|||||||
(token=_INTERFACE) or
|
(token=_INTERFACE) or
|
||||||
(token=_DISPINTERFACE) or
|
(token=_DISPINTERFACE) or
|
||||||
(token=_OBJCCLASS) or
|
(token=_OBJCCLASS) or
|
||||||
(token=_OBJCPROTOCOL)) and
|
(token=_OBJCPROTOCOL) or
|
||||||
|
(token=_OBJCCATEGORY)) and
|
||||||
(assigned(ttypesym(sym).typedef)) and
|
(assigned(ttypesym(sym).typedef)) and
|
||||||
is_class_or_interface_or_dispinterface_or_objc(ttypesym(sym).typedef) and
|
is_class_or_interface_or_dispinterface_or_objc(ttypesym(sym).typedef) and
|
||||||
(oo_is_forward in tobjectdef(ttypesym(sym).typedef).objectoptions) then
|
(oo_is_forward in tobjectdef(ttypesym(sym).typedef).objectoptions) then
|
||||||
@ -455,7 +456,8 @@ implementation
|
|||||||
objecttype:=odt_interfacecorba;
|
objecttype:=odt_interfacecorba;
|
||||||
_DISPINTERFACE :
|
_DISPINTERFACE :
|
||||||
objecttype:=odt_dispinterface;
|
objecttype:=odt_dispinterface;
|
||||||
_OBJCCLASS :
|
_OBJCCLASS,
|
||||||
|
_OBJCCATEGORY :
|
||||||
objecttype:=odt_objcclass;
|
objecttype:=odt_objcclass;
|
||||||
_OBJCPROTOCOL :
|
_OBJCPROTOCOL :
|
||||||
objecttype:=odt_objcprotocol;
|
objecttype:=odt_objcprotocol;
|
||||||
|
@ -313,15 +313,20 @@ implementation
|
|||||||
hasparentdefined:=false;
|
hasparentdefined:=false;
|
||||||
|
|
||||||
{ reads the parent class }
|
{ reads the parent class }
|
||||||
if try_to_consume(_LKLAMMER) then
|
if (token=_LKLAMMER) or
|
||||||
|
is_objccategory(current_objectdef) then
|
||||||
begin
|
begin
|
||||||
|
consume(_LKLAMMER);
|
||||||
{ use single_type instead of id_type for specialize support }
|
{ use single_type instead of id_type for specialize support }
|
||||||
single_type(hdef,false,false);
|
single_type(hdef,false,false);
|
||||||
if (not assigned(hdef)) or
|
if (not assigned(hdef)) or
|
||||||
(hdef.typ<>objectdef) then
|
(hdef.typ<>objectdef) then
|
||||||
begin
|
begin
|
||||||
if assigned(hdef) then
|
if assigned(hdef) then
|
||||||
Message1(type_e_class_type_expected,hdef.typename);
|
Message1(type_e_class_type_expected,hdef.typename)
|
||||||
|
else if is_objccategory(current_objectdef) then
|
||||||
|
{ a category must specify the class to extend }
|
||||||
|
Message(type_e_objcclass_type_expected);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
@ -358,13 +363,20 @@ implementation
|
|||||||
if not(is_cppclass(childof)) then
|
if not(is_cppclass(childof)) then
|
||||||
Message(parser_e_mix_of_classes_and_objects);
|
Message(parser_e_mix_of_classes_and_objects);
|
||||||
odt_objcclass:
|
odt_objcclass:
|
||||||
if not(is_objcclass(childof)) then
|
if not(is_objcclass(childof) or
|
||||||
|
is_objccategory(childof)) then
|
||||||
begin
|
begin
|
||||||
if is_objcprotocol(childof) then
|
if is_objcprotocol(childof) then
|
||||||
begin
|
begin
|
||||||
intfchildof:=childof;
|
if not(oo_is_classhelper in current_objectdef.objectoptions) then
|
||||||
childof:=nil;
|
begin
|
||||||
CGMessage(parser_h_no_objc_parent);
|
intfchildof:=childof;
|
||||||
|
childof:=nil;
|
||||||
|
CGMessage(parser_h_no_objc_parent);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
{ a category must specify the class to extend }
|
||||||
|
CGMessage(type_e_objcclass_type_expected);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Message(parser_e_mix_of_classes_and_objects);
|
Message(parser_e_mix_of_classes_and_objects);
|
||||||
@ -562,7 +574,7 @@ implementation
|
|||||||
_PRIVATE :
|
_PRIVATE :
|
||||||
begin
|
begin
|
||||||
if is_interface(current_objectdef) or
|
if is_interface(current_objectdef) or
|
||||||
is_objcprotocol(current_objectdef) then
|
is_objc_protocol_or_category(current_objectdef) then
|
||||||
Message(parser_e_no_access_specifier_in_interfaces);
|
Message(parser_e_no_access_specifier_in_interfaces);
|
||||||
consume(_PRIVATE);
|
consume(_PRIVATE);
|
||||||
current_objectdef.symtable.currentvisibility:=vis_private;
|
current_objectdef.symtable.currentvisibility:=vis_private;
|
||||||
@ -572,7 +584,7 @@ implementation
|
|||||||
_PROTECTED :
|
_PROTECTED :
|
||||||
begin
|
begin
|
||||||
if is_interface(current_objectdef) or
|
if is_interface(current_objectdef) or
|
||||||
is_objcprotocol(current_objectdef) then
|
is_objc_protocol_or_category(current_objectdef) then
|
||||||
Message(parser_e_no_access_specifier_in_interfaces);
|
Message(parser_e_no_access_specifier_in_interfaces);
|
||||||
consume(_PROTECTED);
|
consume(_PROTECTED);
|
||||||
current_objectdef.symtable.currentvisibility:=vis_protected;
|
current_objectdef.symtable.currentvisibility:=vis_protected;
|
||||||
@ -582,7 +594,7 @@ implementation
|
|||||||
_PUBLIC :
|
_PUBLIC :
|
||||||
begin
|
begin
|
||||||
if is_interface(current_objectdef) or
|
if is_interface(current_objectdef) or
|
||||||
is_objcprotocol(current_objectdef) then
|
is_objc_protocol_or_category(current_objectdef) then
|
||||||
Message(parser_e_no_access_specifier_in_interfaces);
|
Message(parser_e_no_access_specifier_in_interfaces);
|
||||||
consume(_PUBLIC);
|
consume(_PUBLIC);
|
||||||
current_objectdef.symtable.currentvisibility:=vis_public;
|
current_objectdef.symtable.currentvisibility:=vis_public;
|
||||||
@ -593,8 +605,7 @@ implementation
|
|||||||
{ we've to check for a pushlished section in non- }
|
{ we've to check for a pushlished section in non- }
|
||||||
{ publishable classes later, if a real declaration }
|
{ publishable classes later, if a real declaration }
|
||||||
{ this is the way, delphi does it }
|
{ this is the way, delphi does it }
|
||||||
if is_interface(current_objectdef) or
|
if is_interface(current_objectdef) then
|
||||||
is_objcprotocol(current_objectdef) then
|
|
||||||
Message(parser_e_no_access_specifier_in_interfaces);
|
Message(parser_e_no_access_specifier_in_interfaces);
|
||||||
{ Objective-C classes do not support "published",
|
{ Objective-C classes do not support "published",
|
||||||
as basically everything is published. }
|
as basically everything is published. }
|
||||||
@ -607,7 +618,7 @@ implementation
|
|||||||
_STRICT :
|
_STRICT :
|
||||||
begin
|
begin
|
||||||
if is_interface(current_objectdef) or
|
if is_interface(current_objectdef) or
|
||||||
is_objcprotocol(current_objectdef) then
|
is_objc_protocol_or_category(current_objectdef) then
|
||||||
Message(parser_e_no_access_specifier_in_interfaces);
|
Message(parser_e_no_access_specifier_in_interfaces);
|
||||||
consume(_STRICT);
|
consume(_STRICT);
|
||||||
if token=_ID then
|
if token=_ID then
|
||||||
@ -638,7 +649,7 @@ implementation
|
|||||||
if object_member_blocktype=bt_general then
|
if object_member_blocktype=bt_general then
|
||||||
begin
|
begin
|
||||||
if is_interface(current_objectdef) or
|
if is_interface(current_objectdef) or
|
||||||
is_objcprotocol(current_objectdef) then
|
is_objc_protocol_or_category(current_objectdef) then
|
||||||
Message(parser_e_no_vars_in_interfaces);
|
Message(parser_e_no_vars_in_interfaces);
|
||||||
|
|
||||||
if (current_objectdef.symtable.currentvisibility=vis_published) and
|
if (current_objectdef.symtable.currentvisibility=vis_published) and
|
||||||
@ -871,6 +882,13 @@ implementation
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
|
{ change objccategories into objcclass helpers }
|
||||||
|
if (objecttype=odt_objccategory) then
|
||||||
|
begin
|
||||||
|
current_objectdef.objecttype:=odt_objcclass;
|
||||||
|
include(current_objectdef.objectoptions,oo_is_classhelper);
|
||||||
|
end;
|
||||||
|
|
||||||
{ parse list of options (abstract / sealed) }
|
{ parse list of options (abstract / sealed) }
|
||||||
parse_object_options;
|
parse_object_options;
|
||||||
|
|
||||||
|
@ -1413,7 +1413,9 @@ begin
|
|||||||
if pd.typ<>procdef then
|
if pd.typ<>procdef then
|
||||||
internalerror(2003042611);
|
internalerror(2003042611);
|
||||||
if not(is_class_or_interface_or_objc(tprocdef(pd)._class)) then
|
if not(is_class_or_interface_or_objc(tprocdef(pd)._class)) then
|
||||||
Message(parser_e_no_object_override);
|
Message(parser_e_no_object_override)
|
||||||
|
else if is_objccategory(tprocdef(pd)._class) then
|
||||||
|
Message(parser_e_no_category_override);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure pd_overload(pd:tabstractprocdef);
|
procedure pd_overload(pd:tabstractprocdef);
|
||||||
@ -1483,7 +1485,8 @@ procedure pd_reintroduce(pd:tabstractprocdef);
|
|||||||
begin
|
begin
|
||||||
if pd.typ<>procdef then
|
if pd.typ<>procdef then
|
||||||
internalerror(200401211);
|
internalerror(200401211);
|
||||||
if not(is_class_or_interface_or_object(tprocdef(pd)._class)) then
|
if not(is_class_or_interface_or_object(tprocdef(pd)._class)) and
|
||||||
|
not(is_objccategory(tprocdef(pd)._class)) then
|
||||||
Message(parser_e_no_object_reintroduce);
|
Message(parser_e_no_object_reintroduce);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2036,7 +2039,7 @@ const
|
|||||||
mutexclpo : [po_external]
|
mutexclpo : [po_external]
|
||||||
),(
|
),(
|
||||||
idtok:_REINTRODUCE;
|
idtok:_REINTRODUCE;
|
||||||
pd_flags : [pd_interface,pd_object,pd_notobjintf];
|
pd_flags : [pd_interface,pd_object,pd_notobjintf,pd_objcclass];
|
||||||
handler : @pd_reintroduce;
|
handler : @pd_reintroduce;
|
||||||
pocall : pocall_none;
|
pocall : pocall_none;
|
||||||
pooption : [po_reintroduce];
|
pooption : [po_reintroduce];
|
||||||
|
@ -493,7 +493,12 @@ implementation
|
|||||||
begin
|
begin
|
||||||
Message(parser_e_no_generics_as_types);
|
Message(parser_e_no_generics_as_types);
|
||||||
def:=generrordef;
|
def:=generrordef;
|
||||||
end;
|
end
|
||||||
|
else if is_objccategory(def) then
|
||||||
|
begin
|
||||||
|
Message(parser_e_no_category_as_types);
|
||||||
|
def:=generrordef
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -622,7 +627,12 @@ implementation
|
|||||||
begin
|
begin
|
||||||
Message(parser_e_no_generics_as_types);
|
Message(parser_e_no_generics_as_types);
|
||||||
def:=generrordef;
|
def:=generrordef;
|
||||||
end;
|
end
|
||||||
|
else if is_objccategory(def) then
|
||||||
|
begin
|
||||||
|
Message(parser_e_no_category_as_types);
|
||||||
|
def:=generrordef
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -1023,6 +1033,14 @@ implementation
|
|||||||
consume(token);
|
consume(token);
|
||||||
def:=object_dec(odt_objcprotocol,name,genericdef,genericlist,nil);
|
def:=object_dec(odt_objcprotocol,name,genericdef,genericlist,nil);
|
||||||
end;
|
end;
|
||||||
|
_OBJCCATEGORY :
|
||||||
|
begin
|
||||||
|
if not(m_objectivec1 in current_settings.modeswitches) then
|
||||||
|
Message(parser_f_need_objc);
|
||||||
|
|
||||||
|
consume(token);
|
||||||
|
def:=object_dec(odt_objccategory,name,genericdef,genericlist,nil);
|
||||||
|
end;
|
||||||
_OBJECT :
|
_OBJECT :
|
||||||
begin
|
begin
|
||||||
consume(token);
|
consume(token);
|
||||||
|
@ -117,6 +117,9 @@ const
|
|||||||
paranr_syscall_legacy = high(word)-2;
|
paranr_syscall_legacy = high(word)-2;
|
||||||
paranr_result_leftright = high(word)-1;
|
paranr_result_leftright = high(word)-1;
|
||||||
|
|
||||||
|
{ prefix for names of class helper procsyms added to regular symtables }
|
||||||
|
class_helper_prefix = 'CH$';
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
{ keep this in sync with TIntfFlag in rtl/objpas/typinfo.pp }
|
{ keep this in sync with TIntfFlag in rtl/objpas/typinfo.pp }
|
||||||
@ -302,7 +305,8 @@ type
|
|||||||
odt_cppclass,
|
odt_cppclass,
|
||||||
odt_dispinterface,
|
odt_dispinterface,
|
||||||
odt_objcclass,
|
odt_objcclass,
|
||||||
odt_objcprotocol
|
odt_objcprotocol,
|
||||||
|
odt_objccategory { note that these are changed into odt_class afterwards }
|
||||||
);
|
);
|
||||||
|
|
||||||
{ Variations in interfaces implementation }
|
{ Variations in interfaces implementation }
|
||||||
@ -335,7 +339,8 @@ type
|
|||||||
oo_has_enumerator_movenext,
|
oo_has_enumerator_movenext,
|
||||||
oo_has_enumerator_current,
|
oo_has_enumerator_current,
|
||||||
oo_is_external, { the class is externally implemented (objcclass, cppclass) }
|
oo_is_external, { the class is externally implemented (objcclass, cppclass) }
|
||||||
oo_is_anonymous { the class is only formally defined in this module (objcclass x = class; external;) }
|
oo_is_anonymous, { the class is only formally defined in this module (objcclass x = class; external;) }
|
||||||
|
oo_is_classhelper { objcclasses that represent categories, and Delpi-style class helpers, are marked like this }
|
||||||
);
|
);
|
||||||
tobjectoptions=set of tobjectoption;
|
tobjectoptions=set of tobjectoption;
|
||||||
|
|
||||||
|
@ -685,6 +685,7 @@ interface
|
|||||||
objc_superclasstype,
|
objc_superclasstype,
|
||||||
objc_idtype,
|
objc_idtype,
|
||||||
objc_seltype : tpointerdef;
|
objc_seltype : tpointerdef;
|
||||||
|
objc_objecttype : trecorddef;
|
||||||
{ base type of @protocol(protocolname) Objective-C statements }
|
{ base type of @protocol(protocolname) Objective-C statements }
|
||||||
objc_protocoltype : tobjectdef;
|
objc_protocoltype : tobjectdef;
|
||||||
|
|
||||||
@ -739,7 +740,9 @@ interface
|
|||||||
function is_objcclass(def: tdef): boolean;
|
function is_objcclass(def: tdef): boolean;
|
||||||
function is_objcclassref(def: tdef): boolean;
|
function is_objcclassref(def: tdef): boolean;
|
||||||
function is_objcprotocol(def: tdef): boolean;
|
function is_objcprotocol(def: tdef): boolean;
|
||||||
|
function is_objccategory(def: tdef): boolean;
|
||||||
function is_objc_class_or_protocol(def: tdef): boolean;
|
function is_objc_class_or_protocol(def: tdef): boolean;
|
||||||
|
function is_objc_protocol_or_category(def: tdef): boolean;
|
||||||
function is_class_or_interface(def: tdef): boolean;
|
function is_class_or_interface(def: tdef): boolean;
|
||||||
function is_class_or_interface_or_objc(def: tdef): boolean;
|
function is_class_or_interface_or_objc(def: tdef): boolean;
|
||||||
function is_class_or_interface_or_object(def: tdef): boolean;
|
function is_class_or_interface_or_object(def: tdef): boolean;
|
||||||
@ -3582,12 +3585,19 @@ implementation
|
|||||||
|
|
||||||
|
|
||||||
function tprocdef.objcmangledname : string;
|
function tprocdef.objcmangledname : string;
|
||||||
|
var
|
||||||
|
manglednamelen: longint;
|
||||||
|
iscatmethod : boolean;
|
||||||
begin
|
begin
|
||||||
if not (po_msgstr in procoptions) then
|
if not (po_msgstr in procoptions) then
|
||||||
internalerror(2009030901);
|
internalerror(2009030901);
|
||||||
{ we may very well need longer strings to handle these... }
|
{ we may very well need longer strings to handle these... }
|
||||||
if ((255-length(tobjectdef(procsym.owner.defowner).objextname^)
|
manglednamelen:=length(tobjectdef(procsym.owner.defowner).objextname^)+
|
||||||
-length('+"[ ]"')-length(messageinf.str^)) < 0) then
|
length('+"[ ]"')+length(messageinf.str^);
|
||||||
|
iscatmethod:=oo_is_classhelper in tobjectdef(procsym.owner.defowner).objectoptions;
|
||||||
|
if (iscatmethod) then
|
||||||
|
inc(manglednamelen,length(tobjectdef(procsym.owner.defowner).childof.objextname^)+length('()'));
|
||||||
|
if manglednamelen>255 then
|
||||||
Message1(parser_e_objc_message_name_too_long,messageinf.str^);
|
Message1(parser_e_objc_message_name_too_long,messageinf.str^);
|
||||||
if not(po_classmethod in procoptions) then
|
if not(po_classmethod in procoptions) then
|
||||||
result:='"-['
|
result:='"-['
|
||||||
@ -3596,9 +3606,12 @@ implementation
|
|||||||
{ quotes are necessary because the +/- otherwise confuse the assembler
|
{ quotes are necessary because the +/- otherwise confuse the assembler
|
||||||
into expecting a number
|
into expecting a number
|
||||||
}
|
}
|
||||||
result:=
|
if iscatmethod then
|
||||||
result+tobjectdef(procsym.owner.defowner).objextname^+' '+
|
result:=result+tobjectdef(procsym.owner.defowner).childof.objextname^+'(';
|
||||||
messageinf.str^+']"';
|
result:=result+tobjectdef(procsym.owner.defowner).objextname^;
|
||||||
|
if iscatmethod then
|
||||||
|
result:=result+')';
|
||||||
|
result:=result+' '+messageinf.str^+']"';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -4082,6 +4095,36 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure create_class_helper_for_procdef(def: tobject; arg: pointer);
|
||||||
|
var
|
||||||
|
pd: tprocdef absolute def;
|
||||||
|
st: tsymtable;
|
||||||
|
psym: tsym;
|
||||||
|
nname: TIDString;
|
||||||
|
begin
|
||||||
|
if (tdef(def).typ<>procdef) then
|
||||||
|
exit;
|
||||||
|
{ pd.owner = objcclass symtable -> defowner = objcclassdef ->
|
||||||
|
owner = symtable in which objcclassdef is defined
|
||||||
|
}
|
||||||
|
st:=pd.owner.defowner.owner;
|
||||||
|
nname:=class_helper_prefix+tprocsym(pd.procsym).name;
|
||||||
|
{ check for an existing procsym with our special name }
|
||||||
|
psym:=tsym(st.find(nname));
|
||||||
|
if not assigned(psym) then
|
||||||
|
begin
|
||||||
|
psym:=tprocsym.create(nname);
|
||||||
|
{ avoid warning about this symbol being unused }
|
||||||
|
psym.IncRefCount;
|
||||||
|
st.insert(psym,true);
|
||||||
|
end
|
||||||
|
else if (psym.typ<>procsym) then
|
||||||
|
internalerror(2009111501);
|
||||||
|
{ add ourselves to this special procsym }
|
||||||
|
tprocsym(psym).procdeflist.add(def);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure tobjectdef.buildderefimpl;
|
procedure tobjectdef.buildderefimpl;
|
||||||
begin
|
begin
|
||||||
inherited buildderefimpl;
|
inherited buildderefimpl;
|
||||||
@ -4095,6 +4138,10 @@ implementation
|
|||||||
inherited derefimpl;
|
inherited derefimpl;
|
||||||
if not (df_copied_def in defoptions) then
|
if not (df_copied_def in defoptions) then
|
||||||
tstoredsymtable(symtable).derefimpl;
|
tstoredsymtable(symtable).derefimpl;
|
||||||
|
{ the procdefs are not owned by the class helper procsyms, so they
|
||||||
|
are not stored/restored either -> re-add them here }
|
||||||
|
if (oo_is_classhelper in objectoptions) then
|
||||||
|
symtable.DefList.ForEachCall(@create_class_helper_for_procdef,nil);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -4385,9 +4432,15 @@ implementation
|
|||||||
begin
|
begin
|
||||||
case rt of
|
case rt of
|
||||||
objcclassrtti:
|
objcclassrtti:
|
||||||
result:=result+'_OBJC_CLASS_';
|
if not(oo_is_classhelper in objectoptions) then
|
||||||
|
result:=result+'_OBJC_CLASS_'
|
||||||
|
else
|
||||||
|
result:=result+'_OBJC_CATEGORY_';
|
||||||
objcmetartti:
|
objcmetartti:
|
||||||
result:=result+'_OBJC_METACLASS_';
|
if not(oo_is_classhelper in objectoptions) then
|
||||||
|
result:=result+'_OBJC_METACLASS_'
|
||||||
|
else
|
||||||
|
internalerror(2009111511);
|
||||||
else
|
else
|
||||||
internalerror(2009092302);
|
internalerror(2009092302);
|
||||||
end;
|
end;
|
||||||
@ -4401,9 +4454,15 @@ implementation
|
|||||||
case objecttype of
|
case objecttype of
|
||||||
odt_objcclass:
|
odt_objcclass:
|
||||||
begin
|
begin
|
||||||
|
if (oo_is_classhelper in objectoptions) and
|
||||||
|
(rt<>objcclassrtti) then
|
||||||
|
internalerror(2009111512);
|
||||||
case rt of
|
case rt of
|
||||||
objcclassrtti:
|
objcclassrtti:
|
||||||
result:='_OBJC_CLASS_$_';
|
if not(oo_is_classhelper in objectoptions) then
|
||||||
|
result:='_OBJC_CLASS_$_'
|
||||||
|
else
|
||||||
|
result:='_OBJC_$_CATEGORY_';
|
||||||
objcmetartti:
|
objcmetartti:
|
||||||
result:='_OBJC_METACLASS_$_';
|
result:='_OBJC_METACLASS_$_';
|
||||||
objcclassrortti:
|
objcclassrortti:
|
||||||
@ -4656,35 +4715,43 @@ implementation
|
|||||||
begin
|
begin
|
||||||
if (def.typ=procdef) then
|
if (def.typ=procdef) then
|
||||||
begin
|
begin
|
||||||
|
{ add all messages also under a dummy name to the symtable in
|
||||||
|
which the objcclass/protocol/category is declared, so they can
|
||||||
|
be called via id.<name>
|
||||||
|
}
|
||||||
|
create_class_helper_for_procdef(pd,nil);
|
||||||
|
|
||||||
{ we have to wait until now to set the mangled name because it
|
{ we have to wait until now to set the mangled name because it
|
||||||
depends on the (possibly external) class name, which is defined
|
depends on the (possibly external) class name, which is defined
|
||||||
at the very end. }
|
at the very end. }
|
||||||
if (po_msgstr in pd.procoptions) then
|
if not(po_msgstr in pd.procoptions) then
|
||||||
begin
|
begin
|
||||||
{ Mangled name is already set in case this is a copy of
|
CGMessagePos(pd.fileinfo,parser_e_objc_requires_msgstr);
|
||||||
another type. }
|
{ recover to avoid internalerror later on }
|
||||||
if not(po_has_mangledname in pd.procoptions) then
|
include(pd.procoptions,po_msgstr);
|
||||||
begin
|
pd.messageinf.str:=stringdup('MissingDeclaration');
|
||||||
{ check whether the number of formal parameters is correct }
|
end;
|
||||||
paracount:=0;
|
{ Mangled name is already set in case this is a copy of
|
||||||
for i:=1 to length(pd.messageinf.str^) do
|
another type. }
|
||||||
if pd.messageinf.str^[i]=':' then
|
if not(po_has_mangledname in pd.procoptions) then
|
||||||
inc(paracount);
|
begin
|
||||||
for i:=0 to pd.paras.count-1 do
|
{ check whether the number of formal parameters is correct }
|
||||||
if not(vo_is_hidden_para in tparavarsym(pd.paras[i]).varoptions) and
|
paracount:=0;
|
||||||
not is_array_of_const(tparavarsym(pd.paras[i]).vardef) then
|
for i:=1 to length(pd.messageinf.str^) do
|
||||||
dec(paracount);
|
if pd.messageinf.str^[i]=':' then
|
||||||
if (paracount<>0) then
|
inc(paracount);
|
||||||
MessagePos(pd.fileinfo,sym_e_objc_para_mismatch);
|
for i:=0 to pd.paras.count-1 do
|
||||||
|
if not(vo_is_hidden_para in tparavarsym(pd.paras[i]).varoptions) and
|
||||||
|
not is_array_of_const(tparavarsym(pd.paras[i]).vardef) then
|
||||||
|
dec(paracount);
|
||||||
|
if (paracount<>0) then
|
||||||
|
MessagePos(pd.fileinfo,sym_e_objc_para_mismatch);
|
||||||
|
|
||||||
pd.setmangledname(pd.objcmangledname);
|
pd.setmangledname(pd.objcmangledname);
|
||||||
end
|
|
||||||
else
|
|
||||||
{ all checks already done }
|
|
||||||
exit;
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
MessagePos(pd.fileinfo,parser_e_objc_requires_msgstr);
|
{ all checks already done }
|
||||||
|
exit;
|
||||||
if not(oo_is_external in pd._class.objectoptions) then
|
if not(oo_is_external in pd._class.objectoptions) then
|
||||||
begin
|
begin
|
||||||
if (po_varargs in pd.procoptions) then
|
if (po_varargs in pd.procoptions) then
|
||||||
@ -5065,6 +5132,18 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function is_objccategory(def: tdef): boolean;
|
||||||
|
begin
|
||||||
|
result:=
|
||||||
|
assigned(def) and
|
||||||
|
(def.typ=objectdef) and
|
||||||
|
{ if used as a forward type }
|
||||||
|
((tobjectdef(def).objecttype=odt_objccategory) or
|
||||||
|
{ if used as after it has been resolved }
|
||||||
|
((tobjectdef(def).objecttype=odt_objcclass) and
|
||||||
|
(oo_is_classhelper in tobjectdef(def).objectoptions)));
|
||||||
|
end;
|
||||||
|
|
||||||
function is_objc_class_or_protocol(def: tdef): boolean;
|
function is_objc_class_or_protocol(def: tdef): boolean;
|
||||||
begin
|
begin
|
||||||
result:=
|
result:=
|
||||||
@ -5074,6 +5153,17 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function is_objc_protocol_or_category(def: tdef): boolean;
|
||||||
|
begin
|
||||||
|
result:=
|
||||||
|
assigned(def) and
|
||||||
|
(def.typ=objectdef) and
|
||||||
|
((tobjectdef(def).objecttype = odt_objcprotocol) or
|
||||||
|
((tobjectdef(def).objecttype = odt_objcclass) and
|
||||||
|
(oo_is_classhelper in tobjectdef(def).objectoptions)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function is_class_or_interface(def: tdef): boolean;
|
function is_class_or_interface(def: tdef): boolean;
|
||||||
begin
|
begin
|
||||||
result:=
|
result:=
|
||||||
@ -5125,6 +5215,7 @@ implementation
|
|||||||
objc_superclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_SUPER').typedef);
|
objc_superclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_SUPER').typedef);
|
||||||
objc_idtype:=tpointerdef(search_named_unit_globaltype('OBJC','ID').typedef);
|
objc_idtype:=tpointerdef(search_named_unit_globaltype('OBJC','ID').typedef);
|
||||||
objc_seltype:=tpointerdef(search_named_unit_globaltype('OBJC','SEL').typedef);
|
objc_seltype:=tpointerdef(search_named_unit_globaltype('OBJC','SEL').typedef);
|
||||||
|
objc_objecttype:=trecorddef(search_named_unit_globaltype('OBJC','OBJC_OBJECT').typedef);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -204,6 +204,7 @@ interface
|
|||||||
function search_class_member(pd : tobjectdef;const s : string):tsym;
|
function search_class_member(pd : tobjectdef;const s : string):tsym;
|
||||||
function search_assignment_operator(from_def,to_def:Tdef):Tprocdef;
|
function search_assignment_operator(from_def,to_def:Tdef):Tprocdef;
|
||||||
function search_enumerator_operator(type_def:Tdef):Tprocdef;
|
function search_enumerator_operator(type_def:Tdef):Tprocdef;
|
||||||
|
function search_class_helper(pd : tobjectdef;const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean;
|
||||||
{Looks for macro s (must be given in upper case) in the macrosymbolstack, }
|
{Looks for macro s (must be given in upper case) in the macrosymbolstack, }
|
||||||
{and returns it if found. Returns nil otherwise.}
|
{and returns it if found. Returns nil otherwise.}
|
||||||
function search_macro(const s : string):tsym;
|
function search_macro(const s : string):tsym;
|
||||||
@ -1674,6 +1675,16 @@ implementation
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
{ also search for class helpers }
|
||||||
|
if (srsymtable.symtabletype=objectsymtable) and
|
||||||
|
is_objcclass(tdef(srsymtable.defowner)) then
|
||||||
|
begin
|
||||||
|
if search_class_helper(tobjectdef(srsymtable.defowner),s,srsym,srsymtable) then
|
||||||
|
begin
|
||||||
|
result:=true;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
stackitem:=stackitem^.next;
|
stackitem:=stackitem^.next;
|
||||||
end;
|
end;
|
||||||
srsym:=nil;
|
srsym:=nil;
|
||||||
@ -1810,7 +1821,9 @@ implementation
|
|||||||
function searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
|
function searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
|
||||||
var
|
var
|
||||||
hashedid : THashedIDString;
|
hashedid : THashedIDString;
|
||||||
|
orgclass : tobjectdef;
|
||||||
begin
|
begin
|
||||||
|
orgclass:=classh;
|
||||||
{ The contextclassh is used for visibility. The classh must be equal to
|
{ The contextclassh is used for visibility. The classh must be equal to
|
||||||
or be a parent of contextclassh. E.g. for inherited searches the classh is the
|
or be a parent of contextclassh. E.g. for inherited searches the classh is the
|
||||||
parent. }
|
parent. }
|
||||||
@ -1832,8 +1845,13 @@ implementation
|
|||||||
end;
|
end;
|
||||||
classh:=classh.childof;
|
classh:=classh.childof;
|
||||||
end;
|
end;
|
||||||
srsym:=nil;
|
if is_objcclass(orgclass) then
|
||||||
srsymtable:=nil;
|
result:=search_class_helper(orgclass,s,srsym,srsymtable)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
srsym:=nil;
|
||||||
|
srsymtable:=nil;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -1993,8 +2011,6 @@ implementation
|
|||||||
|
|
||||||
function search_named_unit_globaltype(const unitname, typename: TIDString): ttypesym;
|
function search_named_unit_globaltype(const unitname, typename: TIDString): ttypesym;
|
||||||
var
|
var
|
||||||
contextobjdef : tobjectdef;
|
|
||||||
stackitem : psymtablestackitem;
|
|
||||||
srsymtable: tsymtable;
|
srsymtable: tsymtable;
|
||||||
sym: tsym;
|
sym: tsym;
|
||||||
begin
|
begin
|
||||||
@ -2012,14 +2028,71 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function search_class_helper(pd : tobjectdef;const s : string; out srsym: tsym; out srsymtable: tsymtable):boolean;
|
||||||
|
var
|
||||||
|
hashedid : THashedIDString;
|
||||||
|
stackitem : psymtablestackitem;
|
||||||
|
i : longint;
|
||||||
|
begin
|
||||||
|
hashedid.id:=class_helper_prefix+s;
|
||||||
|
stackitem:=symtablestack.stack;
|
||||||
|
while assigned(stackitem) do
|
||||||
|
begin
|
||||||
|
srsymtable:=stackitem^.symtable;
|
||||||
|
srsym:=tsym(srsymtable.FindWithHash(hashedid));
|
||||||
|
if assigned(srsym) then
|
||||||
|
begin
|
||||||
|
if not(srsymtable.symtabletype in [globalsymtable,staticsymtable]) or
|
||||||
|
not(srsym.owner.symtabletype in [globalsymtable,staticsymtable]) or
|
||||||
|
(srsym.typ<>procsym) then
|
||||||
|
internalerror(2009111505);
|
||||||
|
{ check whether this procsym includes a helper for this particular class }
|
||||||
|
for i:=0 to tprocsym(srsym).procdeflist.count-1 do
|
||||||
|
begin
|
||||||
|
{ does pd inherit from (or is the same as) the class
|
||||||
|
that this method's category extended?
|
||||||
|
}
|
||||||
|
if pd.is_related(tobjectdef(tprocdef(tprocsym(srsym).procdeflist[i]).owner.defowner).childof) then
|
||||||
|
begin
|
||||||
|
{ no need to keep looking. There might be other
|
||||||
|
categories that extend this, a parent or child
|
||||||
|
class with a method with the same name (either
|
||||||
|
overriding this one, or overridden by this one),
|
||||||
|
but that doesn't matter as far as the basic
|
||||||
|
procsym is concerned.
|
||||||
|
}
|
||||||
|
srsym:=tprocdef(tprocsym(srsym).procdeflist[i]).procsym;
|
||||||
|
srsymtable:=srsym.owner;
|
||||||
|
{ we need to know if a procedure references symbols
|
||||||
|
in the static symtable, because then it can't be
|
||||||
|
inlined from outside this unit }
|
||||||
|
if assigned(current_procinfo) and
|
||||||
|
(srsym.owner.symtabletype=staticsymtable) then
|
||||||
|
include(current_procinfo.flags,pi_uses_static_symtable);
|
||||||
|
addsymref(srsym);
|
||||||
|
result:=true;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
stackitem:=stackitem^.next;
|
||||||
|
end;
|
||||||
|
srsym:=nil;
|
||||||
|
srsymtable:=nil;
|
||||||
|
result:=false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function search_class_member(pd : tobjectdef;const s : string):tsym;
|
function search_class_member(pd : tobjectdef;const s : string):tsym;
|
||||||
{ searches n in symtable of pd and all anchestors }
|
{ searches n in symtable of pd and all anchestors }
|
||||||
var
|
var
|
||||||
hashedid : THashedIDString;
|
hashedid : THashedIDString;
|
||||||
srsym : tsym;
|
srsym : tsym;
|
||||||
|
orgpd : tobjectdef;
|
||||||
|
srsymtable : tsymtable;
|
||||||
begin
|
begin
|
||||||
hashedid.id:=s;
|
hashedid.id:=s;
|
||||||
|
orgpd:=pd;
|
||||||
while assigned(pd) do
|
while assigned(pd) do
|
||||||
begin
|
begin
|
||||||
srsym:=tsym(pd.symtable.FindWithHash(hashedid));
|
srsym:=tsym(pd.symtable.FindWithHash(hashedid));
|
||||||
@ -2030,9 +2103,15 @@ implementation
|
|||||||
end;
|
end;
|
||||||
pd:=pd.childof;
|
pd:=pd.childof;
|
||||||
end;
|
end;
|
||||||
search_class_member:=nil;
|
|
||||||
|
{ not found, now look for class helpers }
|
||||||
|
if is_objcclass(pd) then
|
||||||
|
search_class_helper(orgpd,s,result,srsymtable)
|
||||||
|
else
|
||||||
|
result:=nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function search_macro(const s : string):tsym;
|
function search_macro(const s : string):tsym;
|
||||||
var
|
var
|
||||||
stackitem : psymtablestackitem;
|
stackitem : psymtablestackitem;
|
||||||
|
@ -250,6 +250,7 @@ type
|
|||||||
_EXPERIMENTAL,
|
_EXPERIMENTAL,
|
||||||
_FINALIZATION,
|
_FINALIZATION,
|
||||||
_NOSTACKFRAME,
|
_NOSTACKFRAME,
|
||||||
|
_OBJCCATEGORY,
|
||||||
_OBJCPROTOCOL,
|
_OBJCPROTOCOL,
|
||||||
_WEAKEXTERNAL,
|
_WEAKEXTERNAL,
|
||||||
_DISPINTERFACE,
|
_DISPINTERFACE,
|
||||||
@ -510,6 +511,7 @@ const
|
|||||||
(str:'EXPERIMENTAL' ;special:false;keyword:m_all;op:NOTOKEN),
|
(str:'EXPERIMENTAL' ;special:false;keyword:m_all;op:NOTOKEN),
|
||||||
(str:'FINALIZATION' ;special:false;keyword:m_initfinal;op:NOTOKEN),
|
(str:'FINALIZATION' ;special:false;keyword:m_initfinal;op:NOTOKEN),
|
||||||
(str:'NOSTACKFRAME' ;special:false;keyword:m_none;op:NOTOKEN),
|
(str:'NOSTACKFRAME' ;special:false;keyword:m_none;op:NOTOKEN),
|
||||||
|
(str:'OBJCCATEGORY' ;special:false;keyword:m_objectivec1;op:NOTOKEN), { Objective-C category }
|
||||||
(str:'OBJCPROTOCOL' ;special:false;keyword:m_objectivec1;op:NOTOKEN), { Objective-C protocol }
|
(str:'OBJCPROTOCOL' ;special:false;keyword:m_objectivec1;op:NOTOKEN), { Objective-C protocol }
|
||||||
(str:'WEAKEXTERNAL' ;special:false;keyword:m_none;op:NOTOKEN),
|
(str:'WEAKEXTERNAL' ;special:false;keyword:m_none;op:NOTOKEN),
|
||||||
(str:'DISPINTERFACE' ;special:false;keyword:m_class;op:NOTOKEN),
|
(str:'DISPINTERFACE' ;special:false;keyword:m_class;op:NOTOKEN),
|
||||||
|
@ -1390,7 +1390,8 @@ type
|
|||||||
oo_has_enumerator_movenext,
|
oo_has_enumerator_movenext,
|
||||||
oo_has_enumerator_current,
|
oo_has_enumerator_current,
|
||||||
oo_is_external, { the class is externally implemented (objcclass, cppclass) }
|
oo_is_external, { the class is externally implemented (objcclass, cppclass) }
|
||||||
oo_is_anonymous { the class is only formally defined in this module (objcclass x = class; external;) }
|
oo_is_anonymous, { the class is only formally defined in this module (objcclass x = class; external;) }
|
||||||
|
oo_is_classhelper { objcclasses that represent categories, and Delpi-style class helpers, are marked like this }
|
||||||
);
|
);
|
||||||
tobjectoptions=set of tobjectoption;
|
tobjectoptions=set of tobjectoption;
|
||||||
tsymopt=record
|
tsymopt=record
|
||||||
@ -1418,7 +1419,8 @@ const
|
|||||||
(mask:oo_has_enumerator_movenext; str:'HasEnumeratorMoveNext'),
|
(mask:oo_has_enumerator_movenext; str:'HasEnumeratorMoveNext'),
|
||||||
(mask:oo_has_enumerator_current; str:'HasEnumeratorCurrent'),
|
(mask:oo_has_enumerator_current; str:'HasEnumeratorCurrent'),
|
||||||
(mask:oo_is_external; str:'External'),
|
(mask:oo_is_external; str:'External'),
|
||||||
(mask:oo_is_anonymous; str:'Anonymous'));
|
(mask:oo_is_anonymous; str:'Anonymous'),
|
||||||
|
(mask:oo_is_classhelper; str:'Class Helper/Category'));
|
||||||
var
|
var
|
||||||
symoptions : tobjectoptions;
|
symoptions : tobjectoptions;
|
||||||
i : longint;
|
i : longint;
|
||||||
|
16
tests/test/tobjc24.pp
Normal file
16
tests/test/tobjc24.pp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{ %fail }
|
||||||
|
{ %target=darwin }
|
||||||
|
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
|
||||||
|
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
uses
|
||||||
|
uobjc24;
|
||||||
|
|
||||||
|
var
|
||||||
|
a: ta;
|
||||||
|
|
||||||
|
begin
|
||||||
|
{ category is in implementation -> should not be visible here }
|
||||||
|
ta.implementationcategorymethod;
|
||||||
|
end.
|
122
tests/test/tobjc25.pp
Normal file
122
tests/test/tobjc25.pp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
{ %target=darwin }
|
||||||
|
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
|
||||||
|
|
||||||
|
{$mode objfpc}
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
type
|
||||||
|
tbaseclass = objccategory(NSObject)
|
||||||
|
function tabaseproc(cp: longint): double; message 'tabaseproc:';
|
||||||
|
class function taclassproc: longint; message 'taclassproc';
|
||||||
|
end;
|
||||||
|
|
||||||
|
ta = objcclass(NSObject)
|
||||||
|
a: longint;
|
||||||
|
procedure taproc; message 'taproc';
|
||||||
|
function tabaseproc(cp: longint): double; message 'tabaseproc:'; //override; -- override doesn't work, the compiler doesn't treat the category as part of NSObject
|
||||||
|
class function taclassproc: longint; message 'taclassproc'; //override; -- idem
|
||||||
|
end;
|
||||||
|
|
||||||
|
ca = objccategory(ta)
|
||||||
|
procedure categorymethod; message 'categorymethod';
|
||||||
|
function tabaseproc(cp: longint): double; reintroduce;
|
||||||
|
end;
|
||||||
|
|
||||||
|
da = objccategory(ta)
|
||||||
|
procedure anothercategorymethod; message 'anothercategorymethod';
|
||||||
|
class function taclassproc: longint; reintroduce;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function tbaseclass.taclassproc: longint;
|
||||||
|
begin
|
||||||
|
writeln('tbaseclass.taclassproc');
|
||||||
|
result:=654321;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function tbaseclass.tabaseproc(cp: longint): double;
|
||||||
|
begin
|
||||||
|
writeln('tbaseclass.tabaseproc');
|
||||||
|
if (cp<>98765) then
|
||||||
|
halt(12);
|
||||||
|
result:=1234.875;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ta.taproc;
|
||||||
|
begin
|
||||||
|
a:=0;
|
||||||
|
categorymethod;
|
||||||
|
if (a<>1) then
|
||||||
|
halt(1);
|
||||||
|
anothercategorymethod;
|
||||||
|
if (a<>2) then
|
||||||
|
halt(2);
|
||||||
|
if taclassproc<>123456 then
|
||||||
|
halt(5);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ta.tabaseproc(cp: longint): double;
|
||||||
|
begin
|
||||||
|
{ should be replaced/hidden by ca.tabaseproc }
|
||||||
|
halt(9);
|
||||||
|
result:=-1.0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function ta.taclassproc: longint;
|
||||||
|
begin
|
||||||
|
{ should be replaced/hidden by da.taclassproc }
|
||||||
|
halt(3);
|
||||||
|
result:=0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ca.categorymethod;
|
||||||
|
begin
|
||||||
|
a:=1;
|
||||||
|
if tabaseproc(555) <> 1.0 then
|
||||||
|
halt(16);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ca.tabaseproc(cp: longint): double;
|
||||||
|
begin
|
||||||
|
writeln('start ca.tabaseproc');
|
||||||
|
if (cp<>555) then
|
||||||
|
halt(13);
|
||||||
|
if inherited tabaseproc(98765)<>1234.875 then
|
||||||
|
halt(11);
|
||||||
|
writeln('end ca.tabaseproc');
|
||||||
|
result:=1.0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure da.anothercategorymethod;
|
||||||
|
begin
|
||||||
|
a:=2;
|
||||||
|
if tabaseproc(555)<>1.0 then
|
||||||
|
halt(15);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function da.taclassproc: longint;
|
||||||
|
begin
|
||||||
|
writeln('start da.taclassproc, calling inherited');
|
||||||
|
if inherited taclassproc<>654321 then
|
||||||
|
halt(4);
|
||||||
|
writeln('end da.taclassproc');
|
||||||
|
result:=123456;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
a: ta;
|
||||||
|
begin
|
||||||
|
a:=ta(ta.alloc).init;
|
||||||
|
a.taproc;
|
||||||
|
a.a:=0;
|
||||||
|
a.categorymethod;
|
||||||
|
if (a.a<>1) then
|
||||||
|
halt(6);
|
||||||
|
a.anothercategorymethod;
|
||||||
|
if (a.a<>2) then
|
||||||
|
halt(7);
|
||||||
|
if a.taclassproc<>123456 then
|
||||||
|
halt(8);
|
||||||
|
if (a.tabaseproc(555)<>1.0) then
|
||||||
|
halt(14);
|
||||||
|
a.release;
|
||||||
|
end.
|
18
tests/test/tobjc26.pp
Normal file
18
tests/test/tobjc26.pp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{ %fail }
|
||||||
|
{ %target=darwin }
|
||||||
|
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
|
||||||
|
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
uses
|
||||||
|
uobjc26;
|
||||||
|
|
||||||
|
var
|
||||||
|
a: ta;
|
||||||
|
|
||||||
|
begin
|
||||||
|
a:=ta(ta.alloc).init;
|
||||||
|
// should not be visible
|
||||||
|
a.implementationcategorymethod;
|
||||||
|
a.release
|
||||||
|
end.
|
16
tests/test/tobjc26a.pp
Normal file
16
tests/test/tobjc26a.pp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{ %target=darwin }
|
||||||
|
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
|
||||||
|
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
uses
|
||||||
|
uobjc26;
|
||||||
|
|
||||||
|
var
|
||||||
|
a: ta;
|
||||||
|
|
||||||
|
begin
|
||||||
|
a:=ta(ta.alloc).init;
|
||||||
|
a.taproc;
|
||||||
|
a.release
|
||||||
|
end.
|
26
tests/test/tobjc27a.pp
Normal file
26
tests/test/tobjc27a.pp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{ %target=darwin }
|
||||||
|
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
|
||||||
|
{ %recompile }
|
||||||
|
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
uses
|
||||||
|
uobjc27a,uobjc27b;
|
||||||
|
|
||||||
|
var
|
||||||
|
a: ta;
|
||||||
|
c: tachild;
|
||||||
|
|
||||||
|
begin
|
||||||
|
a:=ta(ta.alloc).init;
|
||||||
|
if a.da_categorymethod<>2 then
|
||||||
|
halt(1);
|
||||||
|
a.release;
|
||||||
|
|
||||||
|
c:=tachild(tachild.alloc).init;
|
||||||
|
if c.da_categorymethod<>2 then
|
||||||
|
halt(2);
|
||||||
|
if c.eachild_categorymethod<>3 then
|
||||||
|
halt(3);
|
||||||
|
c.release;
|
||||||
|
end.
|
17
tests/test/tobjc27b.pp
Normal file
17
tests/test/tobjc27b.pp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{ %target=darwin }
|
||||||
|
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
|
||||||
|
{ %fail }
|
||||||
|
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
uses
|
||||||
|
uobjc27a;
|
||||||
|
|
||||||
|
var
|
||||||
|
a: ta;
|
||||||
|
|
||||||
|
begin
|
||||||
|
{ da_category method is declared in uobjc27a, which is used in the
|
||||||
|
implementation of uobjc27b -> should not be visible here }
|
||||||
|
a.da_categorymethod;
|
||||||
|
end.
|
25
tests/test/tobjc28.pp
Normal file
25
tests/test/tobjc28.pp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{ %target=darwin }
|
||||||
|
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
|
||||||
|
{ %fail }
|
||||||
|
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
type
|
||||||
|
ta = objcclass(NSObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
ca = objccategory(ta)
|
||||||
|
procedure categorymethod; message 'categorymethod';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ca.categorymethod;
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
a: NSObject;
|
||||||
|
begin
|
||||||
|
a:=ta(ta.alloc).init;
|
||||||
|
{ should fail because the category is for ta, not for nsobject }
|
||||||
|
a.categorymethod;
|
||||||
|
end.
|
22
tests/test/uobjc24.pp
Normal file
22
tests/test/uobjc24.pp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
unit uobjc24;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
type
|
||||||
|
ta = objcclass(NSObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
type
|
||||||
|
ca = objccategory(ta)
|
||||||
|
procedure implementationcategorymethod;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ca.implementationcategorymethod;
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
33
tests/test/uobjc26.pp
Normal file
33
tests/test/uobjc26.pp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
unit uobjc26;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
type
|
||||||
|
ta = objcclass(NSObject)
|
||||||
|
l: longint;
|
||||||
|
procedure taproc; message 'taproc';
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
type
|
||||||
|
ca = objccategory(ta)
|
||||||
|
procedure implementationcategorymethod; message 'implementationcategorymethod';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ca.implementationcategorymethod;
|
||||||
|
begin
|
||||||
|
l:=1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ta.taproc;
|
||||||
|
begin
|
||||||
|
l:=0;
|
||||||
|
implementationcategorymethod;
|
||||||
|
if l<>1 then
|
||||||
|
halt(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
27
tests/test/uobjc27a.pp
Normal file
27
tests/test/uobjc27a.pp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{$mode objfpc}
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
unit uobjc27a;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
type
|
||||||
|
ta = objcclass(NSObject)
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
ca = objccategory(ta)
|
||||||
|
function ca_categorymethod: longint; message 'ca_categorymethod';
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
uobjc27b;
|
||||||
|
|
||||||
|
function ca.ca_categorymethod: longint;
|
||||||
|
begin
|
||||||
|
result:=da_categorymethod-1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
35
tests/test/uobjc27b.pp
Normal file
35
tests/test/uobjc27b.pp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{$mode objfpc}
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
|
||||||
|
unit uobjc27b;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses uobjc27a;
|
||||||
|
|
||||||
|
type
|
||||||
|
tachild = objcclass(ta)
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
eachild = objccategory(tachild)
|
||||||
|
function eachild_categorymethod: longint; message 'eachild_categorymethod';
|
||||||
|
end;
|
||||||
|
|
||||||
|
da = objccategory(ta)
|
||||||
|
function da_categorymethod: longint; message 'da_categorymethod';
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
function eachild.eachild_categorymethod: longint;
|
||||||
|
begin
|
||||||
|
result:=ca_categorymethod+2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function da.da_categorymethod: longint;
|
||||||
|
begin
|
||||||
|
result:=2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user