mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-13 17:59:27 +02:00
+ support for Objective-Pascal for-in loops ("fast enumerations")
+ {$modeswitch objectivec2}, which is required before you can use Objective-C 2.0 features (such as the above). It automatically also implies {$modeswitch objectivec1} + genloadfield() helper to load a field of a node representing a record/object/class git-svn-id: trunk@15460 -
This commit is contained in:
parent
25561d0f71
commit
835899524b
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -9294,6 +9294,8 @@ tests/test/tobjc31.pp svneol=native#text/plain
|
||||
tests/test/tobjc32.pp svneol=native#text/plain
|
||||
tests/test/tobjc32a.pp svneol=native#text/plain
|
||||
tests/test/tobjc32b.pp svneol=native#text/plain
|
||||
tests/test/tobjc33.pp svneol=native#text/plain
|
||||
tests/test/tobjc33a.pp svneol=native#text/plain
|
||||
tests/test/tobjc4.pp svneol=native#text/plain
|
||||
tests/test/tobjc4a.pp svneol=native#text/plain
|
||||
tests/test/tobjc5.pp svneol=native#text/plain
|
||||
|
@ -270,7 +270,8 @@ interface
|
||||
m_property, { allow properties }
|
||||
m_default_inline, { allow inline proc directive }
|
||||
m_except, { allow exception-related keywords }
|
||||
m_objectivec1 { support interfacing with Objective-C (1.0) }
|
||||
m_objectivec1, { support interfacing with Objective-C (1.0) }
|
||||
m_objectivec2 { support interfacing with Objective-C (2.0) }
|
||||
);
|
||||
tmodeswitches = set of tmodeswitch;
|
||||
|
||||
@ -387,7 +388,8 @@ interface
|
||||
'PROPERTIES',
|
||||
'ALLOWINLINE',
|
||||
'EXCEPTIONS',
|
||||
'OBJECTIVEC1');
|
||||
'OBJECTIVEC1',
|
||||
'OBJECTIVEC2');
|
||||
|
||||
|
||||
type
|
||||
|
@ -368,7 +368,7 @@ scanner_w_illegal_warn_identifier=02087_W_Illegal identifier "$1" for $WARN dire
|
||||
#
|
||||
# Parser
|
||||
#
|
||||
# 03293 is the last used one
|
||||
# 03295 is the last used one
|
||||
#
|
||||
% \section{Parser messages}
|
||||
% This section lists all parser messages. The parser takes care of the
|
||||
@ -1315,6 +1315,16 @@ parser_e_widestring_to_ansi_compile_time=03293_E_Unicodechar/string constants ca
|
||||
% constant expressions that have to be converted into an ansistring or shortstring
|
||||
% at compile time, for example inside typed constants. The reason is that the
|
||||
% compiler cannot know what the actual ansi encoding will be at run time.
|
||||
parser_e_objc_enumerator_2_0=03294_E_For-in Objective-Pascal loops require \{\$modeswitch ObjectiveC1\} to be active
|
||||
% Objective-C ``fast enumeration'' support was added in Objective-C 2.0, and
|
||||
% hence the appropriate modeswitch has to be activated to expose this feature.
|
||||
% Note that Objective-C 2.0 programs require Mac OS X 10.5 or later.
|
||||
parser_e_objc_missing_enumeration_defs=03295_E_The compiler cannot find the NSFastEnumerationProtocol or NSFastEnumerationState type in the CocoaAll unit
|
||||
% Objective-C for-in loops (fast enumeration) require that the compiler can
|
||||
% find a unit called CocoaAll that contains definitions for the
|
||||
% NSFastEnumerationProtocol and NSFastEnumerationState types. If you get this
|
||||
% error, most likely the compiler is finding and loading an alternate CocoaAll
|
||||
% unit.
|
||||
#
|
||||
# Type Checking
|
||||
#
|
||||
|
@ -382,6 +382,8 @@ const
|
||||
parser_e_no_paras_for_class_destructor=03291;
|
||||
parser_f_modeswitch_objc_required=03292;
|
||||
parser_e_widestring_to_ansi_compile_time=03293;
|
||||
parser_e_objc_enumerator_2_0=03294;
|
||||
parser_e_objc_missing_enumeration_defs=03295;
|
||||
type_e_mismatch=04000;
|
||||
type_e_incompatible_types=04001;
|
||||
type_e_not_equal_types=04002;
|
||||
@ -860,9 +862,9 @@ const
|
||||
option_info=11024;
|
||||
option_help_pages=11025;
|
||||
|
||||
MsgTxtSize = 56492;
|
||||
MsgTxtSize = 56695;
|
||||
|
||||
MsgIdxMax : array[1..20] of longint=(
|
||||
24,88,294,96,80,51,110,22,202,63,
|
||||
24,88,296,96,80,51,110,22,202,63,
|
||||
49,20,1,1,1,1,1,1,1,1
|
||||
);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1859,7 +1859,7 @@ implementation
|
||||
if (cnf_inherited in callnodeflags) then
|
||||
begin
|
||||
block:=internalstatements(statements);
|
||||
objcsupertype:=search_named_unit_globaltype('OBJC','OBJC_SUPER').typedef;
|
||||
objcsupertype:=search_named_unit_globaltype('OBJC','OBJC_SUPER',true).typedef;
|
||||
if (objcsupertype.typ<>recorddef) then
|
||||
internalerror(2009032901);
|
||||
{ temp for the for the objc_super record }
|
||||
|
@ -251,6 +251,232 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function create_objc_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
||||
var
|
||||
mainstatement, outerloopbodystatement, innerloopbodystatement, tempstatement: tstatementnode;
|
||||
state, mutationcheck, currentamount, innerloopcounter, items, expressiontemp: ttempcreatenode;
|
||||
outerloop, innerloop, hp: tnode;
|
||||
itemsarraydef: tarraydef;
|
||||
sym: tsym;
|
||||
begin
|
||||
{ Objective-C enumerators require Objective-C 2.0 }
|
||||
if not(m_objectivec2 in current_settings.modeswitches) then
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
MessagePos(expr.fileinfo,parser_e_objc_enumerator_2_0);
|
||||
exit;
|
||||
end;
|
||||
{ Requires the NSFastEnumeration protocol and NSFastEnumerationState
|
||||
record }
|
||||
maybeloadcocoatypes;
|
||||
if not assigned(objc_fastenumeration) or
|
||||
not assigned(objc_fastenumerationstate) then
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
MessagePos(expr.fileinfo,parser_e_objc_missing_enumeration_defs);
|
||||
exit;
|
||||
end;
|
||||
|
||||
(* Original code:
|
||||
for hloopvar in expression do
|
||||
<hloopbody>
|
||||
|
||||
Pascal code equivalent into which it has to be transformed
|
||||
(sure would be nice if the compiler had some kind of templates ;) :
|
||||
var
|
||||
state: NSFastEnumerationState;
|
||||
expressiontemp: NSFastEnumerationProtocol;
|
||||
mutationcheck,
|
||||
currentamount,
|
||||
innerloopcounter: culong;
|
||||
{ size can be increased/decreased if desired }
|
||||
items: array[1..16] of id;
|
||||
begin
|
||||
fillchar(state,sizeof(state),0);
|
||||
expressiontemp:=expression;
|
||||
repeat
|
||||
currentamount:=expressiontemp.countByEnumeratingWithState_objects_count(@state,@items,length(items));
|
||||
if currentamount=0 then
|
||||
begin
|
||||
{ "The iterating variable is set to nil when the loop ends by
|
||||
exhausting the source pool of objects" }
|
||||
hloopvar:=nil;
|
||||
break;
|
||||
end;
|
||||
mutationcheck:=state.mutationsptr^;
|
||||
innerloopcounter:=culong(-1);
|
||||
repeat
|
||||
{ at the start so that "continue" in <loopbody> works correctly }
|
||||
{ don't use for-loop, because then the value of the iteration
|
||||
counter is undefined on exit and we have to check it in the
|
||||
outer repeat/until condition }
|
||||
{$push}
|
||||
{$r-,q-}
|
||||
inc(innerloopcounter);
|
||||
{$pop}
|
||||
if innerloopcounter=currentamount then
|
||||
break;
|
||||
if mutationcheck<>state.mutationsptr^ then
|
||||
{ raises Objective-C exception... }
|
||||
objc_enumerationMutation(expressiontemp);
|
||||
hloopvar:=state.itemsPtr[innerloopcounter];
|
||||
{ if continue in loopbody -> jumps to start, increases count and checks }
|
||||
{ if break in loopbody: goes to outer repeat/until and innerloopcount
|
||||
will be < currentamount -> stops }
|
||||
<hloopbody>
|
||||
until false;
|
||||
{ if the inner loop terminated early, "break" was used and we have
|
||||
to stop }
|
||||
{ "If the loop is terminated early, the iterating variable is left
|
||||
pointing to the last iteration item." }
|
||||
until innerloopcounter<currentamount;
|
||||
end;
|
||||
*)
|
||||
|
||||
result:=internalstatements(mainstatement);
|
||||
{ the fast enumeration state }
|
||||
state:=ctempcreatenode.create(objc_fastenumerationstate,objc_fastenumerationstate.size,tt_persistent,false);
|
||||
typecheckpass(tnode(state));
|
||||
addstatement(mainstatement,state);
|
||||
{ the temporary items array }
|
||||
itemsarraydef:=tarraydef.create(1,16,u32inttype);
|
||||
itemsarraydef.elementdef:=objc_idtype;
|
||||
items:=ctempcreatenode.create(itemsarraydef,itemsarraydef.size,tt_persistent,false);
|
||||
addstatement(mainstatement,items);
|
||||
typecheckpass(tnode(items));
|
||||
{ temp for the expression/collection through which we iterate }
|
||||
expressiontemp:=ctempcreatenode.create(objc_fastenumeration,objc_fastenumeration.size,tt_persistent,true);
|
||||
addstatement(mainstatement,expressiontemp);
|
||||
{ currentamount temp (not really clean: we use ptruint instead of
|
||||
culong) }
|
||||
currentamount:=ctempcreatenode.create(ptruinttype,ptruinttype.size,tt_persistent,true);
|
||||
typecheckpass(tnode(currentamount));
|
||||
addstatement(mainstatement,currentamount);
|
||||
{ mutationcheck temp (idem) }
|
||||
mutationcheck:=ctempcreatenode.create(ptruinttype,ptruinttype.size,tt_persistent,true);
|
||||
typecheckpass(tnode(mutationcheck));
|
||||
addstatement(mainstatement,mutationcheck);
|
||||
{ innerloopcounter temp (idem) }
|
||||
innerloopcounter:=ctempcreatenode.create(ptruinttype,ptruinttype.size,tt_persistent,true);
|
||||
typecheckpass(tnode(innerloopcounter));
|
||||
addstatement(mainstatement,innerloopcounter);
|
||||
{ initialise the state with 0 }
|
||||
addstatement(mainstatement,ccallnode.createinternfromunit('SYSTEM','FILLCHAR',
|
||||
ccallparanode.create(genintconstnode(0),
|
||||
ccallparanode.create(genintconstnode(objc_fastenumerationstate.size),
|
||||
ccallparanode.create(ctemprefnode.create(state),nil)
|
||||
)
|
||||
)
|
||||
));
|
||||
{ this will also check whether the expression (potentially) conforms
|
||||
to the NSFastEnumeration protocol (use expr.getcopy, because the
|
||||
caller will free expr) }
|
||||
addstatement(mainstatement,cassignmentnode.create(ctemprefnode.create(expressiontemp),expr.getcopy));
|
||||
|
||||
{ we add the "repeat..until" afterwards, now just create the body }
|
||||
outerloop:=internalstatements(outerloopbodystatement);
|
||||
{ the countByEnumeratingWithState_objects_count call }
|
||||
hp:=ccallparanode.create(cinlinenode.create(in_length_x,false,ctypenode.create(itemsarraydef)),
|
||||
ccallparanode.create(caddrnode.create(ctemprefnode.create(items)),
|
||||
ccallparanode.create(caddrnode.create(ctemprefnode.create(state)),nil)
|
||||
)
|
||||
);
|
||||
sym:=search_class_member(objc_fastenumeration,'COUNTBYENUMERATINGWITHSTATE_OBJECTS_COUNT');
|
||||
if not assigned(sym) or
|
||||
(sym.typ<>procsym) then
|
||||
internalerror(2010061901);
|
||||
hp:=ccallnode.create(hp,tprocsym(sym),sym.owner,ctemprefnode.create(expressiontemp),[]);
|
||||
addstatement(outerloopbodystatement,cassignmentnode.create(
|
||||
ctemprefnode.create(currentamount),hp));
|
||||
{ if currentamount = 0, bail out (use copy of hloopvar, because we
|
||||
have to use it again below) }
|
||||
hp:=internalstatements(tempstatement);
|
||||
addstatement(tempstatement,cassignmentnode.create(
|
||||
hloopvar.getcopy,cnilnode.create));
|
||||
addstatement(tempstatement,cbreaknode.create);
|
||||
addstatement(outerloopbodystatement,cifnode.create(
|
||||
caddnode.create(equaln,ctemprefnode.create(currentamount),genintconstnode(0)),
|
||||
hp,nil));
|
||||
{ initial value of mutationcheck }
|
||||
hp:=ctemprefnode.create(state);
|
||||
typecheckpass(hp);
|
||||
hp:=cderefnode.create(genloadfield(hp,'MUTATIONSPTR'));
|
||||
addstatement(outerloopbodystatement,cassignmentnode.create(
|
||||
ctemprefnode.create(mutationcheck),hp));
|
||||
{ initialise innerloopcounter }
|
||||
addstatement(outerloopbodystatement,cassignmentnode.create(
|
||||
ctemprefnode.create(innerloopcounter),cordconstnode.create(-1,ptruinttype,false)));
|
||||
|
||||
{ and now the inner loop, again adding the repeat/until afterwards }
|
||||
innerloop:=internalstatements(innerloopbodystatement);
|
||||
{ inc(innerloopcounter) without range/overflowchecking (because
|
||||
we go from culong(-1) to 0 during the first iteration }
|
||||
hp:=cinlinenode.create(
|
||||
in_inc_x,false,ccallparanode.create(
|
||||
ctemprefnode.create(innerloopcounter),nil));
|
||||
hp.localswitches:=hp.localswitches-[cs_check_range,cs_check_overflow];
|
||||
addstatement(innerloopbodystatement,hp);
|
||||
{ if innerloopcounter=currentamount then break to the outer loop }
|
||||
addstatement(innerloopbodystatement,cifnode.create(
|
||||
caddnode.create(equaln,
|
||||
ctemprefnode.create(innerloopcounter),
|
||||
ctemprefnode.create(currentamount)),
|
||||
cbreaknode.create,
|
||||
nil));
|
||||
{ verify that the collection didn't change in the mean time }
|
||||
hp:=ctemprefnode.create(state);
|
||||
typecheckpass(hp);
|
||||
addstatement(innerloopbodystatement,cifnode.create(
|
||||
caddnode.create(unequaln,
|
||||
ctemprefnode.create(mutationcheck),
|
||||
cderefnode.create(genloadfield(hp,'MUTATIONSPTR'))
|
||||
),
|
||||
ccallnode.createinternfromunit('OBJC','OBJC_ENUMERATIONMUTATION',
|
||||
ccallparanode.create(ctemprefnode.create(expressiontemp),nil)),
|
||||
nil));
|
||||
{ finally: actually get the next element }
|
||||
hp:=ctemprefnode.create(state);
|
||||
typecheckpass(hp);
|
||||
hp:=genloadfield(hp,'ITEMSPTR');
|
||||
typecheckpass(hp);
|
||||
{ don't simply use a vecn, because indexing a pointer won't work in
|
||||
non-FPC modes }
|
||||
if hp.resultdef.typ<>pointerdef then
|
||||
internalerror(2010061904);
|
||||
inserttypeconv(hp,
|
||||
tarraydef.create_from_pointer(tpointerdef(hp.resultdef).pointeddef));
|
||||
hp:=cvecnode.create(hp,ctemprefnode.create(innerloopcounter));
|
||||
addstatement(innerloopbodystatement,
|
||||
cassignmentnode.create(hloopvar,hp));
|
||||
{ the actual loop body! }
|
||||
addstatement(innerloopbodystatement,hloopbody);
|
||||
|
||||
{ create the inner repeat/until and add it to the body of the outer
|
||||
one }
|
||||
hp:=cwhilerepeatnode.create(
|
||||
{ repeat .. until false }
|
||||
cordconstnode.create(0,booltype,false),innerloop,false,true);
|
||||
addstatement(outerloopbodystatement,hp);
|
||||
|
||||
{ create the outer repeat/until and add it to the the main body }
|
||||
hp:=cwhilerepeatnode.create(
|
||||
{ repeat .. until innerloopcounter<currentamount }
|
||||
caddnode.create(ltn,
|
||||
ctemprefnode.create(innerloopcounter),
|
||||
ctemprefnode.create(currentamount)),
|
||||
outerloop,false,true);
|
||||
addstatement(mainstatement,hp);
|
||||
|
||||
{ release the temps }
|
||||
addstatement(mainstatement,ctempdeletenode.create(state));
|
||||
addstatement(mainstatement,ctempdeletenode.create(mutationcheck));
|
||||
addstatement(mainstatement,ctempdeletenode.create(currentamount));
|
||||
addstatement(mainstatement,ctempdeletenode.create(innerloopcounter));
|
||||
addstatement(mainstatement,ctempdeletenode.create(items));
|
||||
addstatement(mainstatement,ctempdeletenode.create(expressiontemp));
|
||||
end;
|
||||
|
||||
|
||||
function create_string_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
||||
var
|
||||
loopstatement, loopbodystatement: tstatementnode;
|
||||
@ -616,50 +842,64 @@ implementation
|
||||
else
|
||||
begin
|
||||
{ loop is made for an expression }
|
||||
// search for operator first
|
||||
pd:=search_enumerator_operator(expr.resultdef);
|
||||
// if there is no operator then search for class/object enumerator method
|
||||
if (pd=nil) and (expr.resultdef.typ=objectdef) then
|
||||
pd:=tobjectdef(expr.resultdef).search_enumerator_get;
|
||||
if pd<>nil then
|
||||
// Objective-C uses different conventions (and it's only supported for Objective-C 2.0)
|
||||
if is_objc_class_or_protocol(hloopvar.resultdef) or
|
||||
is_objc_class_or_protocol(expr.resultdef) then
|
||||
begin
|
||||
// seach movenext and current symbols
|
||||
movenext:=tobjectdef(pd.returndef).search_enumerator_move;
|
||||
if movenext = nil then
|
||||
result:=create_objc_for_in_loop(hloopvar,hloopbody,expr);
|
||||
if result.nodetype=errorn then
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
hloopvar.free;
|
||||
hloopbody.free;
|
||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator_move,pd.returndef.GetTypeName);
|
||||
end
|
||||
else
|
||||
begin
|
||||
current:=tpropertysym(tobjectdef(pd.returndef).search_enumerator_current);
|
||||
if current = nil then
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
hloopvar.free;
|
||||
hloopbody.free;
|
||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator_current,pd.returndef.GetTypeName);
|
||||
end
|
||||
else
|
||||
result:=create_enumerator_for_in_loop(hloopvar, hloopbody, expr, pd, movenext, current);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
case expr.resultdef.typ of
|
||||
stringdef: result:=create_string_for_in_loop(hloopvar, hloopbody, expr);
|
||||
arraydef: result:=create_array_for_in_loop(hloopvar, hloopbody, expr);
|
||||
setdef: result:=create_set_for_in_loop(hloopvar, hloopbody, expr);
|
||||
// search for operator first
|
||||
pd:=search_enumerator_operator(expr.resultdef);
|
||||
// if there is no operator then search for class/object enumerator method
|
||||
if (pd=nil) and (expr.resultdef.typ=objectdef) then
|
||||
pd:=tobjectdef(expr.resultdef).search_enumerator_get;
|
||||
if pd<>nil then
|
||||
begin
|
||||
// seach movenext and current symbols
|
||||
movenext:=tobjectdef(pd.returndef).search_enumerator_move;
|
||||
if movenext = nil then
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
hloopvar.free;
|
||||
hloopbody.free;
|
||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator_move,pd.returndef.GetTypeName);
|
||||
end
|
||||
else
|
||||
begin
|
||||
current:=tpropertysym(tobjectdef(pd.returndef).search_enumerator_current);
|
||||
if current = nil then
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
hloopvar.free;
|
||||
hloopbody.free;
|
||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator_current,pd.returndef.GetTypeName);
|
||||
end
|
||||
else
|
||||
result:=create_enumerator_for_in_loop(hloopvar, hloopbody, expr, pd, movenext, current);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
hloopvar.free;
|
||||
hloopbody.free;
|
||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator,expr.resultdef.GetTypeName);
|
||||
case expr.resultdef.typ of
|
||||
stringdef: result:=create_string_for_in_loop(hloopvar, hloopbody, expr);
|
||||
arraydef: result:=create_array_for_in_loop(hloopvar, hloopbody, expr);
|
||||
setdef: result:=create_set_for_in_loop(hloopvar, hloopbody, expr);
|
||||
else
|
||||
begin
|
||||
result:=cerrornode.create;
|
||||
hloopvar.free;
|
||||
hloopbody.free;
|
||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator,expr.resultdef.GetTypeName);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
current_filepos:=storefilepos;
|
||||
|
@ -96,6 +96,11 @@ interface
|
||||
bitpacked structure }
|
||||
function is_bitpacked_access(n: tnode): boolean;
|
||||
|
||||
{ creates a load of field 'fieldname' in the record/class/...
|
||||
represented by n; assumes the resultdef of n is set }
|
||||
function genloadfield(n: tnode; const fieldname: string): tnode;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
@ -1095,6 +1100,18 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function genloadfield(n: tnode; const fieldname: string): tnode;
|
||||
var
|
||||
vs : tsym;
|
||||
begin
|
||||
vs:=tsym(tabstractrecorddef(n.resultdef).symtable.find(fieldname));
|
||||
if not assigned(vs) or
|
||||
(vs.typ<>fieldvarsym) then
|
||||
internalerror(2010061902);
|
||||
result:=csubscriptnode.create(vs,n);
|
||||
end;
|
||||
|
||||
|
||||
function has_no_code(n : tnode) : boolean;
|
||||
begin
|
||||
if n=nil then
|
||||
|
@ -308,7 +308,7 @@ procedure tobjcrttiwriter.gen_objc_methods(list: tasmlist; objccls: tobjectdef;
|
||||
else
|
||||
begin
|
||||
{ size of each entry -- always 32 bit value }
|
||||
mtype:=search_named_unit_globaltype('OBJC','OBJC_METHOD').typedef;
|
||||
mtype:=search_named_unit_globaltype('OBJC','OBJC_METHOD',true).typedef;
|
||||
list.Concat(tai_const.Create_32bit(mtype.size));
|
||||
end;
|
||||
{ number of objc_method entries in the method_list array -- always 32 bit}
|
||||
@ -411,7 +411,7 @@ begin
|
||||
if (abi=oa_nonfragile) then
|
||||
begin
|
||||
{ size of each entry -- always 32 bit value }
|
||||
mtype:=search_named_unit_globaltype('OBJC','OBJC_METHOD').typedef;
|
||||
mtype:=search_named_unit_globaltype('OBJC','OBJC_METHOD',true).typedef;
|
||||
list.Concat(tai_const.Create_32bit(mtype.size));
|
||||
end;
|
||||
list.Concat(Tai_const.Create_32bit(items.count));
|
||||
@ -1001,7 +1001,7 @@ procedure tobjcrttiwriter_nonfragile.gen_objc_ivars(list: tasmlist; objccls: tob
|
||||
list.Concat(tai_label.Create(ivarslabel));
|
||||
|
||||
{ size of each entry -- always 32 bit value }
|
||||
ivtype:=search_named_unit_globaltype('OBJC','OBJC_IVAR').typedef;
|
||||
ivtype:=search_named_unit_globaltype('OBJC','OBJC_IVAR',true).typedef;
|
||||
list.concat(tai_const.Create_32bit(ivtype.size));
|
||||
{ number of entries -- always 32 bit value }
|
||||
list.Concat(tai_const.Create_32bit(vcnt));
|
||||
@ -1129,7 +1129,7 @@ procedure tobjcrttiwriter_nonfragile.gen_objc_protocol(list: tasmlist; protocol:
|
||||
{ TODO: properties }
|
||||
list.Concat(Tai_const.Create_pint(0));
|
||||
{ size of this type }
|
||||
prottype:=search_named_unit_globaltype('OBJC','OBJC_PROTOCOL').typedef;
|
||||
prottype:=search_named_unit_globaltype('OBJC','OBJC_PROTOCOL',true).typedef;
|
||||
list.concat(tai_const.Create_32bit(prottype.size));
|
||||
{ flags }
|
||||
list.concat(tai_const.Create_32bit(0));
|
||||
@ -1330,7 +1330,7 @@ procedure tobjcrttiwriter_nonfragile.gen_objc_class_ro_part(list: tasmlist; objc
|
||||
flags:=flags or CLS_META;
|
||||
rttitype:=objcmetarortti;
|
||||
{ metaclass size/start: always size of objc_object }
|
||||
class_type:=search_named_unit_globaltype('OBJC','OBJC_OBJECT').typedef;
|
||||
class_type:=search_named_unit_globaltype('OBJC','OBJC_OBJECT',true).typedef;
|
||||
start:=class_type.size;
|
||||
size:=start;
|
||||
end
|
||||
|
@ -689,7 +689,7 @@ implementation
|
||||
{ Macpas unit? }
|
||||
if m_mac in current_settings.modeswitches then
|
||||
AddUnit('macpas');
|
||||
{ Objective-C 1.0 support unit? }
|
||||
{ Objective-C support unit? }
|
||||
if (m_objectivec1 in current_settings.modeswitches) then
|
||||
begin
|
||||
{ interface to Objective-C run time }
|
||||
|
@ -467,12 +467,9 @@ implementation
|
||||
for i:=m_class to high(tmodeswitch) do
|
||||
if s=modeswitchstr[i] then
|
||||
begin
|
||||
{ Objective-C is currently only supported for 32 bit Darwin targets
|
||||
(and Objective-C 2.0 will be required for 64 bit ones)
|
||||
Not yet tested for ARM either.
|
||||
}
|
||||
{ Objective-C is currently only supported for Darwin targets }
|
||||
if doinclude and
|
||||
(i=m_objectivec1) and
|
||||
(i in [m_objectivec1,m_objectivec2]) and
|
||||
not(target_info.system in systems_objc_supported) then
|
||||
begin
|
||||
Message1(option_unsupported_target_for_feature,'Objective-C');
|
||||
@ -485,13 +482,19 @@ implementation
|
||||
if doinclude then
|
||||
begin
|
||||
include(current_settings.modeswitches,i);
|
||||
if (i=m_objectivec1) then
|
||||
{ Objective-C 2.0 support implies 1.0 support }
|
||||
if (i=m_objectivec2) then
|
||||
include(current_settings.modeswitches,m_objectivec1);
|
||||
if (i in [m_objectivec1,m_objectivec2]) then
|
||||
include(current_settings.modeswitches,m_class);
|
||||
end
|
||||
else
|
||||
begin
|
||||
exclude(current_settings.modeswitches,i);
|
||||
if (i=m_objectivec1) and
|
||||
{ Objective-C 2.0 support implies 1.0 support }
|
||||
if (i=m_objectivec2) then
|
||||
exclude(current_settings.modeswitches,m_objectivec1);
|
||||
if (i in [m_objectivec1,m_objectivec2]) and
|
||||
([m_delphi,m_objfpc]*current_settings.modeswitches=[]) then
|
||||
exclude(current_settings.modeswitches,m_class);
|
||||
end;
|
||||
|
@ -700,10 +700,13 @@ interface
|
||||
objc_metaclasstype,
|
||||
objc_superclasstype,
|
||||
objc_idtype,
|
||||
objc_seltype : tpointerdef;
|
||||
objc_objecttype : trecorddef;
|
||||
objc_seltype : tpointerdef;
|
||||
objc_objecttype : trecorddef;
|
||||
{ base type of @protocol(protocolname) Objective-C statements }
|
||||
objc_protocoltype : tobjectdef;
|
||||
objc_protocoltype : tobjectdef;
|
||||
{ helper types for for-in "fast enumeration" support in Objective-C 2.0 }
|
||||
objc_fastenumeration : tobjectdef;
|
||||
objc_fastenumerationstate : trecorddef;
|
||||
|
||||
const
|
||||
{$ifdef i386}
|
||||
@ -767,6 +770,7 @@ interface
|
||||
function is_class_or_object(def: tdef): boolean;
|
||||
|
||||
procedure loadobjctypes;
|
||||
procedure maybeloadcocoatypes;
|
||||
|
||||
function use_vectorfpu(def : tdef) : boolean;
|
||||
|
||||
@ -5387,11 +5391,30 @@ implementation
|
||||
|
||||
procedure loadobjctypes;
|
||||
begin
|
||||
objc_metaclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_CLASS').typedef);
|
||||
objc_superclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_SUPER').typedef);
|
||||
objc_idtype:=tpointerdef(search_named_unit_globaltype('OBJC','ID').typedef);
|
||||
objc_seltype:=tpointerdef(search_named_unit_globaltype('OBJC','SEL').typedef);
|
||||
objc_objecttype:=trecorddef(search_named_unit_globaltype('OBJC','OBJC_OBJECT').typedef);
|
||||
objc_metaclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_CLASS',true).typedef);
|
||||
objc_superclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_SUPER',true).typedef);
|
||||
objc_idtype:=tpointerdef(search_named_unit_globaltype('OBJC','ID',true).typedef);
|
||||
objc_seltype:=tpointerdef(search_named_unit_globaltype('OBJC','SEL',true).typedef);
|
||||
objc_objecttype:=trecorddef(search_named_unit_globaltype('OBJC','OBJC_OBJECT',true).typedef);
|
||||
end;
|
||||
|
||||
|
||||
procedure maybeloadcocoatypes;
|
||||
var
|
||||
tsym: ttypesym;
|
||||
begin
|
||||
if assigned(objc_fastenumeration) then
|
||||
exit;
|
||||
tsym:=search_named_unit_globaltype('COCOAALL','NSFASTENUMERATIONPROTOCOL',false);
|
||||
if assigned(tsym) then
|
||||
objc_fastenumeration:=tobjectdef(tsym.typedef)
|
||||
else
|
||||
objc_fastenumeration:=nil;
|
||||
tsym:=search_named_unit_globaltype('COCOAALL','NSFASTENUMERATIONSTATE',false);
|
||||
if assigned(tsym) then
|
||||
objc_fastenumerationstate:=trecorddef(tsym.typedef)
|
||||
else
|
||||
objc_fastenumerationstate:=nil;
|
||||
end;
|
||||
|
||||
|
||||
|
@ -209,7 +209,7 @@ interface
|
||||
function searchsym_in_class_by_msgint(classh:tobjectdef;msgid:longint;out srdef : tdef;out srsym:tsym;out srsymtable:TSymtable):boolean;
|
||||
function searchsym_in_class_by_msgstr(classh:tobjectdef;const s:string;out srsym:tsym;out srsymtable:TSymtable):boolean;
|
||||
function search_system_type(const s: TIDString): ttypesym;
|
||||
function search_named_unit_globaltype(const unitname, typename: TIDString): ttypesym;
|
||||
function search_named_unit_globaltype(const unitname, typename: TIDString; throwerror: boolean): ttypesym;
|
||||
function search_class_member(pd : tobjectdef;const s : string):tsym;
|
||||
function search_assignment_operator(from_def,to_def:Tdef):Tprocdef;
|
||||
function search_enumerator_operator(type_def:Tdef):Tprocdef;
|
||||
@ -2194,7 +2194,7 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function search_named_unit_globaltype(const unitname, typename: TIDString): ttypesym;
|
||||
function search_named_unit_globaltype(const unitname, typename: TIDString; throwerror: boolean): ttypesym;
|
||||
var
|
||||
srsymtable: tsymtable;
|
||||
sym: tsym;
|
||||
@ -2207,7 +2207,8 @@ implementation
|
||||
end
|
||||
else
|
||||
begin
|
||||
cgmessage2(cg_f_unknown_type_in_unit,typename,unitname);
|
||||
if throwerror then
|
||||
cgmessage2(cg_f_unknown_type_in_unit,typename,unitname);
|
||||
result:=nil;
|
||||
end;
|
||||
end;
|
||||
|
42
tests/test/tobjc33.pp
Normal file
42
tests/test/tobjc33.pp
Normal file
@ -0,0 +1,42 @@
|
||||
{ %target=darwin }
|
||||
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
|
||||
|
||||
{ Written by Jonas Maebe in 2010, released into the public domain }
|
||||
|
||||
{$mode delphi}
|
||||
{$modeswitch objectivec2}
|
||||
|
||||
uses
|
||||
CocoaAll;
|
||||
|
||||
var
|
||||
arr: NSMutableArray;
|
||||
element: NSString;
|
||||
pool: NSAutoreleasePool;
|
||||
i: longint;
|
||||
begin
|
||||
pool:=NSAutoreleasePool.alloc.init;
|
||||
arr:=NSMutableArray.arrayWithObjects(
|
||||
NSSTR('One'),
|
||||
NSSTR('Two'),
|
||||
NSSTR('Three'),
|
||||
NSSTR('Four'),
|
||||
NSSTR('Five'),
|
||||
NSSTR('Six'),
|
||||
NSSTR('Seven'),
|
||||
nil);
|
||||
|
||||
i:=0;
|
||||
for element in arr do
|
||||
begin
|
||||
inc(i);
|
||||
if i=2 then
|
||||
continue;
|
||||
if i=5 then
|
||||
break;
|
||||
if i in [2,5..10] then
|
||||
halt(1);
|
||||
NSLog(NSSTR('element: %@'),element);
|
||||
end;
|
||||
pool.release;
|
||||
end.
|
43
tests/test/tobjc33a.pp
Normal file
43
tests/test/tobjc33a.pp
Normal file
@ -0,0 +1,43 @@
|
||||
{ %fail }
|
||||
{ %target=darwin }
|
||||
{ %cpu=powerpc,powerpc64,i386,x86_64,arm }
|
||||
|
||||
{ Written by Jonas Maebe in 2010, released into the public domain }
|
||||
|
||||
{$mode delphi}
|
||||
{$modeswitch objectivec1}
|
||||
|
||||
uses
|
||||
CocoaAll;
|
||||
|
||||
var
|
||||
arr: NSMutableArray;
|
||||
element: NSString;
|
||||
pool: NSAutoreleasePool;
|
||||
i: longint;
|
||||
begin
|
||||
pool:=NSAutoreleasePool.alloc.init;
|
||||
arr:=NSMutableArray.arrayWithObjects(
|
||||
NSSTR('One'),
|
||||
NSSTR('Two'),
|
||||
NSSTR('Three'),
|
||||
NSSTR('Four'),
|
||||
NSSTR('Five'),
|
||||
NSSTR('Six'),
|
||||
NSSTR('Seven'),
|
||||
nil);
|
||||
|
||||
i:=0;
|
||||
for element in arr do
|
||||
begin
|
||||
inc(i);
|
||||
if i=2 then
|
||||
continue;
|
||||
if i=5 then
|
||||
break;
|
||||
if i in [2,5..10] then
|
||||
halt(1);
|
||||
NSLog(NSSTR('element: %@'),element);
|
||||
end;
|
||||
pool.release;
|
||||
end.
|
Loading…
Reference in New Issue
Block a user