mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-27 10:52:50 +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/tobjc32.pp svneol=native#text/plain
|
||||||
tests/test/tobjc32a.pp svneol=native#text/plain
|
tests/test/tobjc32a.pp svneol=native#text/plain
|
||||||
tests/test/tobjc32b.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/tobjc4.pp svneol=native#text/plain
|
||||||
tests/test/tobjc4a.pp svneol=native#text/plain
|
tests/test/tobjc4a.pp svneol=native#text/plain
|
||||||
tests/test/tobjc5.pp svneol=native#text/plain
|
tests/test/tobjc5.pp svneol=native#text/plain
|
||||||
|
@ -270,7 +270,8 @@ interface
|
|||||||
m_property, { allow properties }
|
m_property, { allow properties }
|
||||||
m_default_inline, { allow inline proc directive }
|
m_default_inline, { allow inline proc directive }
|
||||||
m_except, { allow exception-related keywords }
|
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;
|
tmodeswitches = set of tmodeswitch;
|
||||||
|
|
||||||
@ -387,7 +388,8 @@ interface
|
|||||||
'PROPERTIES',
|
'PROPERTIES',
|
||||||
'ALLOWINLINE',
|
'ALLOWINLINE',
|
||||||
'EXCEPTIONS',
|
'EXCEPTIONS',
|
||||||
'OBJECTIVEC1');
|
'OBJECTIVEC1',
|
||||||
|
'OBJECTIVEC2');
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -368,7 +368,7 @@ scanner_w_illegal_warn_identifier=02087_W_Illegal identifier "$1" for $WARN dire
|
|||||||
#
|
#
|
||||||
# Parser
|
# Parser
|
||||||
#
|
#
|
||||||
# 03293 is the last used one
|
# 03295 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
|
||||||
@ -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
|
% 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
|
% 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.
|
% 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
|
# Type Checking
|
||||||
#
|
#
|
||||||
|
@ -382,6 +382,8 @@ const
|
|||||||
parser_e_no_paras_for_class_destructor=03291;
|
parser_e_no_paras_for_class_destructor=03291;
|
||||||
parser_f_modeswitch_objc_required=03292;
|
parser_f_modeswitch_objc_required=03292;
|
||||||
parser_e_widestring_to_ansi_compile_time=03293;
|
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_mismatch=04000;
|
||||||
type_e_incompatible_types=04001;
|
type_e_incompatible_types=04001;
|
||||||
type_e_not_equal_types=04002;
|
type_e_not_equal_types=04002;
|
||||||
@ -860,9 +862,9 @@ const
|
|||||||
option_info=11024;
|
option_info=11024;
|
||||||
option_help_pages=11025;
|
option_help_pages=11025;
|
||||||
|
|
||||||
MsgTxtSize = 56492;
|
MsgTxtSize = 56695;
|
||||||
|
|
||||||
MsgIdxMax : array[1..20] of longint=(
|
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
|
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
|
if (cnf_inherited in callnodeflags) then
|
||||||
begin
|
begin
|
||||||
block:=internalstatements(statements);
|
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
|
if (objcsupertype.typ<>recorddef) then
|
||||||
internalerror(2009032901);
|
internalerror(2009032901);
|
||||||
{ temp for the for the objc_super record }
|
{ temp for the for the objc_super record }
|
||||||
|
@ -251,6 +251,232 @@ implementation
|
|||||||
end;
|
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;
|
function create_string_for_in_loop(hloopvar, hloopbody, expr: tnode): tnode;
|
||||||
var
|
var
|
||||||
loopstatement, loopbodystatement: tstatementnode;
|
loopstatement, loopbodystatement: tstatementnode;
|
||||||
@ -616,50 +842,64 @@ implementation
|
|||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
{ loop is made for an expression }
|
{ loop is made for an expression }
|
||||||
// search for operator first
|
// Objective-C uses different conventions (and it's only supported for Objective-C 2.0)
|
||||||
pd:=search_enumerator_operator(expr.resultdef);
|
if is_objc_class_or_protocol(hloopvar.resultdef) or
|
||||||
// if there is no operator then search for class/object enumerator method
|
is_objc_class_or_protocol(expr.resultdef) then
|
||||||
if (pd=nil) and (expr.resultdef.typ=objectdef) then
|
|
||||||
pd:=tobjectdef(expr.resultdef).search_enumerator_get;
|
|
||||||
if pd<>nil then
|
|
||||||
begin
|
begin
|
||||||
// seach movenext and current symbols
|
result:=create_objc_for_in_loop(hloopvar,hloopbody,expr);
|
||||||
movenext:=tobjectdef(pd.returndef).search_enumerator_move;
|
if result.nodetype=errorn then
|
||||||
if movenext = nil then
|
|
||||||
begin
|
begin
|
||||||
result:=cerrornode.create;
|
|
||||||
hloopvar.free;
|
hloopvar.free;
|
||||||
hloopbody.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;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
case expr.resultdef.typ of
|
// search for operator first
|
||||||
stringdef: result:=create_string_for_in_loop(hloopvar, hloopbody, expr);
|
pd:=search_enumerator_operator(expr.resultdef);
|
||||||
arraydef: result:=create_array_for_in_loop(hloopvar, hloopbody, expr);
|
// if there is no operator then search for class/object enumerator method
|
||||||
setdef: result:=create_set_for_in_loop(hloopvar, hloopbody, expr);
|
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
|
else
|
||||||
begin
|
begin
|
||||||
result:=cerrornode.create;
|
case expr.resultdef.typ of
|
||||||
hloopvar.free;
|
stringdef: result:=create_string_for_in_loop(hloopvar, hloopbody, expr);
|
||||||
hloopbody.free;
|
arraydef: result:=create_array_for_in_loop(hloopvar, hloopbody, expr);
|
||||||
MessagePos1(expr.fileinfo,sym_e_no_enumerator,expr.resultdef.GetTypeName);
|
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;
|
end;
|
||||||
end;
|
end;
|
||||||
current_filepos:=storefilepos;
|
current_filepos:=storefilepos;
|
||||||
|
@ -96,6 +96,11 @@ interface
|
|||||||
bitpacked structure }
|
bitpacked structure }
|
||||||
function is_bitpacked_access(n: tnode): boolean;
|
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
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
@ -1095,6 +1100,18 @@ implementation
|
|||||||
end;
|
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;
|
function has_no_code(n : tnode) : boolean;
|
||||||
begin
|
begin
|
||||||
if n=nil then
|
if n=nil then
|
||||||
|
@ -308,7 +308,7 @@ procedure tobjcrttiwriter.gen_objc_methods(list: tasmlist; objccls: tobjectdef;
|
|||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
{ size of each entry -- always 32 bit value }
|
{ 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));
|
list.Concat(tai_const.Create_32bit(mtype.size));
|
||||||
end;
|
end;
|
||||||
{ number of objc_method entries in the method_list array -- always 32 bit}
|
{ number of objc_method entries in the method_list array -- always 32 bit}
|
||||||
@ -411,7 +411,7 @@ begin
|
|||||||
if (abi=oa_nonfragile) then
|
if (abi=oa_nonfragile) then
|
||||||
begin
|
begin
|
||||||
{ size of each entry -- always 32 bit value }
|
{ 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));
|
list.Concat(tai_const.Create_32bit(mtype.size));
|
||||||
end;
|
end;
|
||||||
list.Concat(Tai_const.Create_32bit(items.count));
|
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));
|
list.Concat(tai_label.Create(ivarslabel));
|
||||||
|
|
||||||
{ size of each entry -- always 32 bit value }
|
{ 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));
|
list.concat(tai_const.Create_32bit(ivtype.size));
|
||||||
{ number of entries -- always 32 bit value }
|
{ number of entries -- always 32 bit value }
|
||||||
list.Concat(tai_const.Create_32bit(vcnt));
|
list.Concat(tai_const.Create_32bit(vcnt));
|
||||||
@ -1129,7 +1129,7 @@ procedure tobjcrttiwriter_nonfragile.gen_objc_protocol(list: tasmlist; protocol:
|
|||||||
{ TODO: properties }
|
{ TODO: properties }
|
||||||
list.Concat(Tai_const.Create_pint(0));
|
list.Concat(Tai_const.Create_pint(0));
|
||||||
{ size of this type }
|
{ 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));
|
list.concat(tai_const.Create_32bit(prottype.size));
|
||||||
{ flags }
|
{ flags }
|
||||||
list.concat(tai_const.Create_32bit(0));
|
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;
|
flags:=flags or CLS_META;
|
||||||
rttitype:=objcmetarortti;
|
rttitype:=objcmetarortti;
|
||||||
{ metaclass size/start: always size of objc_object }
|
{ 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;
|
start:=class_type.size;
|
||||||
size:=start;
|
size:=start;
|
||||||
end
|
end
|
||||||
|
@ -689,7 +689,7 @@ implementation
|
|||||||
{ Macpas unit? }
|
{ Macpas unit? }
|
||||||
if m_mac in current_settings.modeswitches then
|
if m_mac in current_settings.modeswitches then
|
||||||
AddUnit('macpas');
|
AddUnit('macpas');
|
||||||
{ Objective-C 1.0 support unit? }
|
{ Objective-C support unit? }
|
||||||
if (m_objectivec1 in current_settings.modeswitches) then
|
if (m_objectivec1 in current_settings.modeswitches) then
|
||||||
begin
|
begin
|
||||||
{ interface to Objective-C run time }
|
{ interface to Objective-C run time }
|
||||||
|
@ -467,12 +467,9 @@ implementation
|
|||||||
for i:=m_class to high(tmodeswitch) do
|
for i:=m_class to high(tmodeswitch) do
|
||||||
if s=modeswitchstr[i] then
|
if s=modeswitchstr[i] then
|
||||||
begin
|
begin
|
||||||
{ Objective-C is currently only supported for 32 bit Darwin targets
|
{ Objective-C is currently only supported for Darwin targets }
|
||||||
(and Objective-C 2.0 will be required for 64 bit ones)
|
|
||||||
Not yet tested for ARM either.
|
|
||||||
}
|
|
||||||
if doinclude and
|
if doinclude and
|
||||||
(i=m_objectivec1) and
|
(i in [m_objectivec1,m_objectivec2]) and
|
||||||
not(target_info.system in systems_objc_supported) then
|
not(target_info.system in systems_objc_supported) then
|
||||||
begin
|
begin
|
||||||
Message1(option_unsupported_target_for_feature,'Objective-C');
|
Message1(option_unsupported_target_for_feature,'Objective-C');
|
||||||
@ -485,13 +482,19 @@ implementation
|
|||||||
if doinclude then
|
if doinclude then
|
||||||
begin
|
begin
|
||||||
include(current_settings.modeswitches,i);
|
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);
|
include(current_settings.modeswitches,m_class);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
exclude(current_settings.modeswitches,i);
|
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
|
([m_delphi,m_objfpc]*current_settings.modeswitches=[]) then
|
||||||
exclude(current_settings.modeswitches,m_class);
|
exclude(current_settings.modeswitches,m_class);
|
||||||
end;
|
end;
|
||||||
|
@ -700,10 +700,13 @@ interface
|
|||||||
objc_metaclasstype,
|
objc_metaclasstype,
|
||||||
objc_superclasstype,
|
objc_superclasstype,
|
||||||
objc_idtype,
|
objc_idtype,
|
||||||
objc_seltype : tpointerdef;
|
objc_seltype : tpointerdef;
|
||||||
objc_objecttype : trecorddef;
|
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;
|
||||||
|
{ helper types for for-in "fast enumeration" support in Objective-C 2.0 }
|
||||||
|
objc_fastenumeration : tobjectdef;
|
||||||
|
objc_fastenumerationstate : trecorddef;
|
||||||
|
|
||||||
const
|
const
|
||||||
{$ifdef i386}
|
{$ifdef i386}
|
||||||
@ -767,6 +770,7 @@ interface
|
|||||||
function is_class_or_object(def: tdef): boolean;
|
function is_class_or_object(def: tdef): boolean;
|
||||||
|
|
||||||
procedure loadobjctypes;
|
procedure loadobjctypes;
|
||||||
|
procedure maybeloadcocoatypes;
|
||||||
|
|
||||||
function use_vectorfpu(def : tdef) : boolean;
|
function use_vectorfpu(def : tdef) : boolean;
|
||||||
|
|
||||||
@ -5387,11 +5391,30 @@ implementation
|
|||||||
|
|
||||||
procedure loadobjctypes;
|
procedure loadobjctypes;
|
||||||
begin
|
begin
|
||||||
objc_metaclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_CLASS').typedef);
|
objc_metaclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_CLASS',true).typedef);
|
||||||
objc_superclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_SUPER').typedef);
|
objc_superclasstype:=tpointerdef(search_named_unit_globaltype('OBJC','POBJC_SUPER',true).typedef);
|
||||||
objc_idtype:=tpointerdef(search_named_unit_globaltype('OBJC','ID').typedef);
|
objc_idtype:=tpointerdef(search_named_unit_globaltype('OBJC','ID',true).typedef);
|
||||||
objc_seltype:=tpointerdef(search_named_unit_globaltype('OBJC','SEL').typedef);
|
objc_seltype:=tpointerdef(search_named_unit_globaltype('OBJC','SEL',true).typedef);
|
||||||
objc_objecttype:=trecorddef(search_named_unit_globaltype('OBJC','OBJC_OBJECT').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;
|
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_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 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_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_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;
|
||||||
@ -2194,7 +2194,7 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function search_named_unit_globaltype(const unitname, typename: TIDString): ttypesym;
|
function search_named_unit_globaltype(const unitname, typename: TIDString; throwerror: boolean): ttypesym;
|
||||||
var
|
var
|
||||||
srsymtable: tsymtable;
|
srsymtable: tsymtable;
|
||||||
sym: tsym;
|
sym: tsym;
|
||||||
@ -2207,7 +2207,8 @@ implementation
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
cgmessage2(cg_f_unknown_type_in_unit,typename,unitname);
|
if throwerror then
|
||||||
|
cgmessage2(cg_f_unknown_type_in_unit,typename,unitname);
|
||||||
result:=nil;
|
result:=nil;
|
||||||
end;
|
end;
|
||||||
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