Integrated the changes from trunks's postfixoperators into my own and removed the local version again.

git-svn-id: branches/svenbarth/generics@17997 -
This commit is contained in:
svenbarth 2011-07-16 14:08:49 +00:00
parent 7a401d6f00
commit 6a60f9d42a

View File

@ -1568,7 +1568,7 @@ implementation
is_dispinterface(p1.resultdef) or is_record(p1.resultdef) then
begin
{ default property }
protsym:=search_default_property(tobjectdef(p1.resultdef));
protsym:=search_default_property(tabstractrecorddef(p1.resultdef));
if not(assigned(protsym)) then
begin
p1.destroy;
@ -2298,539 +2298,6 @@ implementation
end;
{---------------------------------------------
PostFixOperators
---------------------------------------------}
{ returns whether or not p1 has been changed }
function postfixoperators(var p1:tnode;var again:boolean): boolean;
{ tries to avoid syntax errors after invalid qualifiers }
procedure recoverconsume_postfixops;
begin
repeat
if not try_to_consume(_CARET) then
if try_to_consume(_POINT) then
try_to_consume(_ID)
else if try_to_consume(_LECKKLAMMER) then
begin
repeat
comp_expr(true,false);
until not try_to_consume(_COMMA);
consume(_RECKKLAMMER);
end
else if try_to_consume(_LKLAMMER) then
begin
repeat
comp_expr(true,false);
until not try_to_consume(_COMMA);
consume(_RKLAMMER);
end
else
break;
until false;
end;
procedure handle_variantarray;
var
p4 : tnode;
newstatement : tstatementnode;
tempresultvariant,
temp : ttempcreatenode;
paras : tcallparanode;
newblock : tnode;
countindices : aint;
begin
{ create statements with call initialize the arguments and
call fpc_dynarr_setlength }
newblock:=internalstatements(newstatement);
{ get temp for array of indicies,
we set the real size later }
temp:=ctempcreatenode.create(s32inttype,4,tt_persistent,false);
addstatement(newstatement,temp);
countindices:=0;
repeat
p4:=comp_expr(true,false);
addstatement(newstatement,cassignmentnode.create(
ctemprefnode.create_offset(temp,countindices*s32inttype.size),p4));
inc(countindices);
until not try_to_consume(_COMMA);
{ set real size }
temp.size:=countindices*s32inttype.size;
consume(_RECKKLAMMER);
{ we need only a write access if a := follows }
if token=_ASSIGNMENT then
begin
consume(_ASSIGNMENT);
p4:=comp_expr(true,false);
{ create call to fpc_vararray_put }
paras:=ccallparanode.create(cordconstnode.create
(countindices,s32inttype,true),
ccallparanode.create(caddrnode.create_internal
(ctemprefnode.create(temp)),
ccallparanode.create(ctypeconvnode.create_internal(p4,cvarianttype),
ccallparanode.create(ctypeconvnode.create_internal(p1,cvarianttype)
,nil))));
addstatement(newstatement,ccallnode.createintern('fpc_vararray_put',paras));
addstatement(newstatement,ctempdeletenode.create(temp));
end
else
begin
{ create temp for result }
tempresultvariant:=ctempcreatenode.create(cvarianttype,cvarianttype.size,tt_persistent,true);
addstatement(newstatement,tempresultvariant);
{ create call to fpc_vararray_get }
paras:=ccallparanode.create(cordconstnode.create
(countindices,s32inttype,true),
ccallparanode.create(caddrnode.create_internal
(ctemprefnode.create(temp)),
ccallparanode.create(p1,
ccallparanode.create(
ctemprefnode.create(tempresultvariant)
,nil))));
addstatement(newstatement,ccallnode.createintern('fpc_vararray_get',paras));
addstatement(newstatement,ctempdeletenode.create(temp));
{ the last statement should return the value as
location and type, this is done be referencing the
temp and converting it first from a persistent temp to
normal temp }
addstatement(newstatement,ctempdeletenode.create_normal_temp(tempresultvariant));
addstatement(newstatement,ctemprefnode.create(tempresultvariant));
end;
p1:=newblock;
end;
var
protsym : tpropertysym;
p2,p3 : tnode;
srsym : tsym;
srsymtable : TSymtable;
structh : tabstractrecorddef;
{ shouldn't be used that often, so the extra overhead is ok to save
stack space }
dispatchstring : ansistring;
nodechanged : boolean;
calltype: tdispcalltype;
label
skipreckklammercheck;
begin
result:=false;
again:=true;
while again do
begin
{ we need the resultdef }
do_typecheckpass_changed(p1,nodechanged);
result:=result or nodechanged;
if codegenerror then
begin
recoverconsume_postfixops;
exit;
end;
{ handle token }
case token of
_CARET:
begin
consume(_CARET);
{ support tp/mac procvar^ if the procvar returns a
pointer type }
if ((m_tp_procvar in current_settings.modeswitches) or
(m_mac_procvar in current_settings.modeswitches)) and
(p1.resultdef.typ=procvardef) and
(tprocvardef(p1.resultdef).returndef.typ=pointerdef) then
begin
p1:=ccallnode.create_procvar(nil,p1);
typecheckpass(p1);
end;
if (p1.resultdef.typ<>pointerdef) then
begin
{ ^ as binary operator is a problem!!!! (FK) }
again:=false;
Message(parser_e_invalid_qualifier);
recoverconsume_postfixops;
p1.destroy;
p1:=cerrornode.create;
end
else
p1:=cderefnode.create(p1);
end;
_LECKKLAMMER:
begin
if is_class_or_interface_or_object(p1.resultdef) or
is_dispinterface(p1.resultdef) or is_record(p1.resultdef) then
begin
{ default property }
protsym:=search_default_property(tabstractrecorddef(p1.resultdef));
if not(assigned(protsym)) then
begin
p1.destroy;
p1:=cerrornode.create;
again:=false;
message(parser_e_no_default_property_available);
end
else
begin
{ The property symbol is referenced indirect }
protsym.IncRefCount;
handle_propertysym(protsym,protsym.owner,p1);
end;
end
else
begin
consume(_LECKKLAMMER);
repeat
{ in all of the cases below, p1 is changed }
case p1.resultdef.typ of
pointerdef:
begin
{ support delphi autoderef }
if (tpointerdef(p1.resultdef).pointeddef.typ=arraydef) and
(m_autoderef in current_settings.modeswitches) then
p1:=cderefnode.create(p1);
p2:=comp_expr(true,false);
{ Support Pbytevar[0..9] which returns array [0..9].}
if try_to_consume(_POINTPOINT) then
p2:=crangenode.create(p2,comp_expr(true,false));
p1:=cvecnode.create(p1,p2);
end;
variantdef:
begin
handle_variantarray;
{ the RECKKLAMMER is already read }
goto skipreckklammercheck;
end;
stringdef :
begin
p2:=comp_expr(true,false);
{ Support string[0..9] which returns array [0..9] of char.}
if try_to_consume(_POINTPOINT) then
p2:=crangenode.create(p2,comp_expr(true,false));
p1:=cvecnode.create(p1,p2);
end;
arraydef:
begin
p2:=comp_expr(true,false);
{ support SEG:OFS for go32v2 Mem[] }
if (target_info.system in [system_i386_go32v2,system_i386_watcom]) and
(p1.nodetype=loadn) and
assigned(tloadnode(p1).symtableentry) and
assigned(tloadnode(p1).symtableentry.owner.name) and
(tloadnode(p1).symtableentry.owner.name^='SYSTEM') and
((tloadnode(p1).symtableentry.name='MEM') or
(tloadnode(p1).symtableentry.name='MEMW') or
(tloadnode(p1).symtableentry.name='MEML')) then
begin
if try_to_consume(_COLON) then
begin
p3:=caddnode.create(muln,cordconstnode.create($10,s32inttype,false),p2);
p2:=comp_expr(true,false);
p2:=caddnode.create(addn,p2,p3);
if try_to_consume(_POINTPOINT) then
{ Support mem[$a000:$0000..$07ff] which returns array [0..$7ff] of memtype.}
p2:=crangenode.create(p2,caddnode.create(addn,comp_expr(true,false),p3.getcopy));
p1:=cvecnode.create(p1,p2);
include(tvecnode(p1).flags,nf_memseg);
include(tvecnode(p1).flags,nf_memindex);
end
else
begin
if try_to_consume(_POINTPOINT) then
{ Support mem[$80000000..$80000002] which returns array [0..2] of memtype.}
p2:=crangenode.create(p2,comp_expr(true,false));
p1:=cvecnode.create(p1,p2);
include(tvecnode(p1).flags,nf_memindex);
end;
end
else
begin
if try_to_consume(_POINTPOINT) then
{ Support arrayvar[0..9] which returns array [0..9] of arraytype.}
p2:=crangenode.create(p2,comp_expr(true,false));
p1:=cvecnode.create(p1,p2);
end;
end;
else
begin
if p1.resultdef.typ<>undefineddef then
Message(parser_e_invalid_qualifier);
p1.destroy;
p1:=cerrornode.create;
comp_expr(true,false);
again:=false;
end;
end;
do_typecheckpass(p1);
until not try_to_consume(_COMMA);
consume(_RECKKLAMMER);
{ handle_variantarray eats the RECKKLAMMER and jumps here }
skipreckklammercheck:
end;
end;
_POINT :
begin
consume(_POINT);
if (p1.resultdef.typ=pointerdef) and
(m_autoderef in current_settings.modeswitches) and
{ don't auto-deref objc.id, because then the code
below for supporting id.anyobjcmethod isn't triggered }
(p1.resultdef<>objc_idtype) then
begin
p1:=cderefnode.create(p1);
do_typecheckpass(p1);
end;
{ procvar.<something> can never mean anything so always
try to call it in case it returns a record/object/... }
maybe_call_procvar(p1,false);
case p1.resultdef.typ of
recorddef:
begin
if token=_ID then
begin
structh:=tabstractrecorddef(p1.resultdef);
searchsym_in_record(structh,pattern,srsym,srsymtable);
if assigned(srsym) then
begin
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
consume(_ID);
do_member_read(structh,getaddr,srsym,p1,again,[]);
end
else
begin
Message1(sym_e_id_no_member,orgpattern);
p1.destroy;
p1:=cerrornode.create;
{ try to clean up }
consume(_ID);
end;
end
else
consume(_ID);
end;
enumdef:
begin
if token=_ID then
begin
srsym:=tsym(tenumdef(p1.resultdef).symtable.Find(pattern));
p1.destroy;
if assigned(srsym) and (srsym.typ=enumsym) then
begin
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
p1:=genenumnode(tenumsym(srsym));
end
else
begin
Message1(sym_e_id_no_member,orgpattern);
p1:=cerrornode.create;
end;
end;
consume(_ID);
end;
variantdef:
begin
{ dispatch call? }
{ lhs := v.ident[parameters] -> property get
lhs := v.ident(parameters) -> method call
v.ident[parameters] := rhs -> property put
v.ident(parameters) := rhs -> also property put }
if token=_ID then
begin
dispatchstring:=orgpattern;
consume(_ID);
calltype:=dct_method;
if try_to_consume(_LKLAMMER) then
begin
p2:=parse_paras(false,true,_RKLAMMER);
consume(_RKLAMMER);
end
else if try_to_consume(_LECKKLAMMER) then
begin
p2:=parse_paras(false,true,_RECKKLAMMER);
consume(_RECKKLAMMER);
calltype:=dct_propget;
end
else
p2:=nil;
{ property setter? }
if (token=_ASSIGNMENT) and not(afterassignment) then
begin
consume(_ASSIGNMENT);
{ read the expression }
p3:=comp_expr(true,false);
{ concat value parameter too }
p2:=ccallparanode.create(p3,p2);
p1:=translate_disp_call(p1,p2,dct_propput,dispatchstring,0,voidtype);
end
else
{ this is only an approximation
setting useresult if not necessary is only a waste of time, no more, no less (FK) }
if afterassignment or in_args or (token<>_SEMICOLON) then
p1:=translate_disp_call(p1,p2,calltype,dispatchstring,0,cvarianttype)
else
p1:=translate_disp_call(p1,p2,calltype,dispatchstring,0,voidtype);
end
else { Error }
Consume(_ID);
end;
classrefdef:
begin
if token=_ID then
begin
structh:=tobjectdef(tclassrefdef(p1.resultdef).pointeddef);
searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,true);
if assigned(srsym) then
begin
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
consume(_ID);
do_member_read(structh,getaddr,srsym,p1,again,[]);
end
else
begin
Message1(sym_e_id_no_member,orgpattern);
p1.destroy;
p1:=cerrornode.create;
{ try to clean up }
consume(_ID);
end;
end
else { Error }
Consume(_ID);
end;
objectdef:
begin
if token=_ID then
begin
structh:=tobjectdef(p1.resultdef);
searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,true);
if assigned(srsym) then
begin
check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
consume(_ID);
do_member_read(structh,getaddr,srsym,p1,again,[]);
end
else
begin
Message1(sym_e_id_no_member,orgpattern);
p1.destroy;
p1:=cerrornode.create;
{ try to clean up }
consume(_ID);
end;
end
else { Error }
Consume(_ID);
end;
pointerdef:
begin
if (p1.resultdef=objc_idtype) then
begin
{ objc's id type can be used to call any
Objective-C method of any Objective-C class
type that's currently in scope }
if search_objc_method(pattern,srsym,srsymtable) then
begin
consume(_ID);
do_proc_call(srsym,srsymtable,nil,
(getaddr and not(token in [_CARET,_POINT])),
again,p1,[cnf_objc_id_call]);
{ we need to know which procedure is called }
do_typecheckpass(p1);
end
else
begin
consume(_ID);
Message(parser_e_methode_id_expected);
end;
end
else
begin
Message(parser_e_invalid_qualifier);
if tpointerdef(p1.resultdef).pointeddef.typ in [recorddef,objectdef,classrefdef] then
Message(parser_h_maybe_deref_caret_missing);
end
end;
else
begin
if p1.resultdef.typ<>undefineddef then
Message(parser_e_invalid_qualifier);
p1.destroy;
p1:=cerrornode.create;
{ Error }
consume(_ID);
end;
end;
end;
else
begin
{ is this a procedure variable ? }
if assigned(p1.resultdef) and
(p1.resultdef.typ=procvardef) then
begin
{ Typenode for typecasting or expecting a procvar }
if (p1.nodetype=typen) or
(
assigned(getprocvardef) and
equal_defs(p1.resultdef,getprocvardef)
) then
begin
if try_to_consume(_LKLAMMER) then
begin
p1:=comp_expr(true,false);
consume(_RKLAMMER);
p1:=ctypeconvnode.create_explicit(p1,p1.resultdef);
end
else
again:=false
end
else
begin
if try_to_consume(_LKLAMMER) then
begin
p2:=parse_paras(false,false,_RKLAMMER);
consume(_RKLAMMER);
p1:=ccallnode.create_procvar(p2,p1);
{ proc():= is never possible }
if token=_ASSIGNMENT then
begin
Message(parser_e_illegal_expression);
p1.free;
p1:=cerrornode.create;
again:=false;
end;
end
else
again:=false;
end;
end
else
again:=false;
end;
end;
{ we only try again if p1 was changed }
if again or
(p1.nodetype=errorn) then
result:=true;
end; { while again }
end;
{---------------------------------------------
Factor (Main)
---------------------------------------------}