+ 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:
Jonas Maebe 2010-06-20 12:38:45 +00:00
parent 25561d0f71
commit 835899524b
15 changed files with 746 additions and 357 deletions

2
.gitattributes vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
View 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
View 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.