瀏覽代碼

pexpr.pas:
* postfixoperators: generate specialize nodes in mode Delphi
* factor: don't call postfixoperators() if returned node is a specialize node
* sub_expr: handle specialize nodes
* sub_expr: extract common code handling specializations in < and as/is into a nested function

git-svn-id: trunk@31859 -

svenbarth 9 年之前
父節點
當前提交
bb873c93af
共有 1 個文件被更改,包括 205 次插入62 次删除
  1. 205 62
      compiler/pexpr.pas

+ 205 - 62
compiler/pexpr.pas

@@ -2277,8 +2277,13 @@ implementation
                              searchsym_in_record(structh,pattern,srsym,srsymtable);
                              searchsym_in_record(structh,pattern,srsym,srsymtable);
                              if assigned(srsym) then
                              if assigned(srsym) then
                                begin
                                begin
-                                 check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
+                                 old_current_filepos:=current_filepos;
                                  consume(_ID);
                                  consume(_ID);
+                                 if not (sp_generic_dummy in srsym.symoptions) or
+                                     not (token in [_LT,_LSHARPBRACKET]) then
+                                   check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg,old_current_filepos)
+                                 else
+                                   p1:=cspecializenode.create(p1,getaddr,srsym);
                                  erroroutp1:=false;
                                  erroroutp1:=false;
                                end
                                end
                              else
                              else
@@ -2294,7 +2299,8 @@ implementation
                              p1:=cerrornode.create;
                              p1:=cerrornode.create;
                            end
                            end
                          else
                          else
-                           do_member_read(structh,getaddr,srsym,p1,again,[],spezcontext);
+                           if p1.nodetype<>specializen then
+                             do_member_read(structh,getaddr,srsym,p1,again,[],spezcontext);
                        end
                        end
                      else
                      else
                      consume(_ID);
                      consume(_ID);
@@ -2424,8 +2430,13 @@ implementation
                               searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,[ssf_search_helper]);
                               searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,[ssf_search_helper]);
                               if assigned(srsym) then
                               if assigned(srsym) then
                                 begin
                                 begin
-                                  check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
+                                  old_current_filepos:=current_filepos;
                                   consume(_ID);
                                   consume(_ID);
+                                  if not (sp_generic_dummy in srsym.symoptions) or
+                                      not (token in [_LT,_LSHARPBRACKET]) then
+                                    check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg,old_current_filepos)
+                                  else
+                                    p1:=cspecializenode.create(p1,getaddr,srsym);
                                   erroroutp1:=false;
                                   erroroutp1:=false;
                                 end
                                 end
                               else
                               else
@@ -2441,7 +2452,8 @@ implementation
                               p1:=cerrornode.create;
                               p1:=cerrornode.create;
                             end
                             end
                           else
                           else
-                            do_member_read(structh,getaddr,srsym,p1,again,[],spezcontext);
+                            if p1.nodetype<>specializen then
+                              do_member_read(structh,getaddr,srsym,p1,again,[],spezcontext);
                         end
                         end
                       else { Error }
                       else { Error }
                         Consume(_ID);
                         Consume(_ID);
@@ -2472,8 +2484,13 @@ implementation
                               searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,[ssf_search_helper]);
                               searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,[ssf_search_helper]);
                               if assigned(srsym) then
                               if assigned(srsym) then
                                 begin
                                 begin
-                                   check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
+                                   old_current_filepos:=current_filepos;
                                    consume(_ID);
                                    consume(_ID);
+                                   if not (sp_generic_dummy in srsym.symoptions) or
+                                       not (token in [_LT,_LSHARPBRACKET]) then
+                                     check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg,old_current_filepos)
+                                   else
+                                     p1:=cspecializenode.create(p1,getaddr,srsym);
                                    erroroutp1:=false;
                                    erroroutp1:=false;
                                 end
                                 end
                               else
                               else
@@ -2489,7 +2506,8 @@ implementation
                               p1:=cerrornode.create;
                               p1:=cerrornode.create;
                             end
                             end
                           else
                           else
-                            do_member_read(structh,getaddr,srsym,p1,again,[],spezcontext);
+                            if p1.nodetype<>specializen then
+                              do_member_read(structh,getaddr,srsym,p1,again,[],spezcontext);
                         end
                         end
                       else { Error }
                       else { Error }
                         Consume(_ID);
                         Consume(_ID);
@@ -3173,25 +3191,29 @@ implementation
               filepos:=current_tokenpos;
               filepos:=current_tokenpos;
             end;
             end;
            { handle post fix operators }
            { handle post fix operators }
-           if (m_delphi in current_settings.modeswitches) and
-               (block_type=bt_body) and
-               (token in [_LT,_LSHARPBRACKET]) then
-             begin
-               if p1.nodetype=typen then
-                 idstr:=ttypenode(p1).typesym.name
-               else
-                 if (p1.nodetype=loadvmtaddrn) and
-                     (tloadvmtaddrnode(p1).left.nodetype=typen) then
-                   idstr:=ttypenode(tloadvmtaddrnode(p1).left).typesym.name
+           if (p1.nodetype=specializen) then
+             { post fix operators are handled after specialization }
+             dopostfix:=false
+           else
+             if (m_delphi in current_settings.modeswitches) and
+                 (block_type=bt_body) and
+                 (token in [_LT,_LSHARPBRACKET]) then
+               begin
+                 if p1.nodetype=typen then
+                   idstr:=ttypenode(p1).typesym.name
                  else
                  else
-                   if (p1.nodetype=loadn) then
-                     idstr:=tloadnode(p1).symtableentry.name
+                   if (p1.nodetype=loadvmtaddrn) and
+                       (tloadvmtaddrnode(p1).left.nodetype=typen) then
+                     idstr:=ttypenode(tloadvmtaddrnode(p1).left).typesym.name
                    else
                    else
-                     idstr:='';
-               { if this is the case then the postfix handling is done in
-                 sub_expr if necessary }
-               dopostfix:=not could_be_generic(idstr);
-             end;
+                     if (p1.nodetype=loadn) then
+                       idstr:=tloadnode(p1).symtableentry.name
+                     else
+                       idstr:='';
+                 { if this is the case then the postfix handling is done in
+                   sub_expr if necessary }
+                 dopostfix:=not could_be_generic(idstr);
+               end;
            { maybe an additional parameter instead of misusing hadspezialize? }
            { maybe an additional parameter instead of misusing hadspezialize? }
            if dopostfix and not hadspecialize then
            if dopostfix and not hadspecialize then
              updatefpos:=postfixoperators(p1,again,getaddr);
              updatefpos:=postfixoperators(p1,again,getaddr);
@@ -3727,7 +3749,7 @@ implementation
                     );
                     );
         end;
         end;
 
 
-      function gettypedef(n:tnode):tdef;inline;
+      (*function gettypedef(n:tnode):tdef;inline;
       { This returns the typedef that belongs to the given typenode or
       { This returns the typedef that belongs to the given typenode or
         loadvmtaddrnode. n must not be Nil! }
         loadvmtaddrnode. n must not be Nil! }
         begin
         begin
@@ -3735,6 +3757,19 @@ implementation
             result:=ttypenode(n).typedef
             result:=ttypenode(n).typedef
           else
           else
             result:=ttypenode(tloadvmtaddrnode(n).left).typedef;
             result:=ttypenode(tloadvmtaddrnode(n).left).typedef;
+        end;*)
+
+      function gettypedef(sym:tsym):tdef;inline;
+        begin
+          result:=nil;
+          case sym.typ of
+            typesym:
+              result:=ttypesym(sym).typedef;
+            procsym:
+              result:=tdef(tprocsym(sym).procdeflist[0]);
+            else
+              internalerror(2015092701);
+          end;
         end;
         end;
 
 
       function getgenericsym(n:tnode;out srsym:tsym):boolean;
       function getgenericsym(n:tnode;out srsym:tsym):boolean;
@@ -3750,18 +3785,146 @@ implementation
             loadn:
             loadn:
               if not searchsym_with_symoption(tloadnode(n).symtableentry.Name,srsym,srsymtable,sp_generic_dummy) then
               if not searchsym_with_symoption(tloadnode(n).symtableentry.Name,srsym,srsymtable,sp_generic_dummy) then
                 srsym:=nil;
                 srsym:=nil;
+            specializen:
+              srsym:=tspecializenode(n).sym;
             { TODO : handle const nodes }
             { TODO : handle const nodes }
           end;
           end;
           result:=assigned(srsym);
           result:=assigned(srsym);
         end;
         end;
 
 
+      function generate_inline_specialization(gendef:tdef;n:tnode;filepos:tfileposinfo;parseddef:tdef;gensym:tsym;p2:tnode):tnode;
+        var
+          again,
+          getaddr : boolean;
+          pload : tnode;
+          spezcontext : tspecializationcontext;
+          structdef : tabstractrecorddef;
+        begin
+          if n.nodetype=specializen then
+            begin
+              getaddr:=tspecializenode(n).getaddr;
+              pload:=tspecializenode(n).left;
+              tspecializenode(n).left:=nil;
+            end
+          else
+            begin
+              getaddr:=false;
+              pload:=nil;
+            end;
+
+          if assigned(parseddef) and assigned(gensym) and assigned(p2) then
+            gendef:=generate_specialization_phase1(spezcontext,gendef,parseddef,gensym.realname,p2.fileinfo)
+          else
+            gendef:=generate_specialization_phase1(spezcontext,gendef);
+          case gendef.typ of
+            errordef:
+              begin
+                spezcontext.free;
+                spezcontext:=nil;
+                gensym:=generrorsym;
+              end;
+            objectdef,
+            recorddef,
+            procvardef,
+            arraydef:
+              begin
+                gendef:=generate_specialization_phase2(spezcontext,tstoreddef(gendef),false,'');
+                spezcontext.free;
+                spezcontext:=nil;
+                gensym:=gendef.typesym;
+              end;
+            procdef:
+              begin
+                if block_type<>bt_body then
+                  begin
+                    message(parser_e_illegal_expression);
+                    gensym:=generrorsym;
+                  end
+                else
+                  begin
+                    gensym:=tprocdef(gendef).procsym;
+                  end;
+              end;
+            else
+              internalerror(2015092702);
+          end;
+
+          { in case of a class or a record the specialized generic
+            is always a classrefdef }
+          again:=false;
+
+          if assigned(pload) then
+            begin
+              result:=pload;
+              structdef:=nil;
+              case result.resultdef.typ of
+                objectdef,
+                recorddef:
+                  begin
+                    structdef:=tabstractrecorddef(result.resultdef);
+                  end;
+                classrefdef:
+                  begin
+                    structdef:=tabstractrecorddef(tclassrefdef(result.resultdef).pointeddef);
+                  end;
+                else
+                  internalerror(2015092703);
+              end;
+              do_member_read(structdef,getaddr,gensym,result,again,[],spezcontext);
+            end
+          else
+            begin
+              result:=nil;
+              { check if it's a method/class method }
+              if is_member_read(gensym,gensym.owner,result,parseddef) then
+                begin
+                  { if we are accessing a owner procsym from the nested }
+                  { class we need to call it as a class member }
+                  if (gensym.owner.symtabletype in [ObjectSymtable,recordsymtable]) and
+                      assigned(current_structdef) and (current_structdef<>parseddef) and is_owned_by(current_structdef,parseddef) then
+                    begin
+                      result:=cloadvmtaddrnode.create(ctypenode.create(parseddef));
+                      { not srsymtable.symtabletype since that can be }
+                      { withsymtable as well                          }
+                      if (gensym.owner.symtabletype in [ObjectSymtable,recordsymtable]) then
+                        begin
+                          do_member_read(tabstractrecorddef(parseddef),getaddr,gensym,result,again,[],spezcontext);
+                          spezcontext:=nil;
+                        end
+                      else
+                        { no procsyms in records (yet) }
+                        internalerror(2015092704);
+                    end
+                  else
+                    begin
+                      { regular procedure/function call }
+                      do_proc_call(gensym,gensym.owner,nil,
+                                   (getaddr and not(token in [_CARET,_POINT,_LECKKLAMMER])),
+                                   again,result,[],spezcontext);
+                      spezcontext:=nil;
+                    end;
+                  end
+                else
+                  { handle potential typecasts, etc }
+                  result:=handle_factor_typenode(gendef,false,again,nil,false);
+            end;
+
+          { parse postfix operators }
+          if postfixoperators(result,again,false) then
+            if assigned(result) then
+              result.fileinfo:=filepos
+            else
+              result:=cerrornode.create;
+
+          spezcontext.free;
+        end;
+
       label
       label
         SubExprStart;
         SubExprStart;
       var
       var
-        p1,p2   : tnode;
+        p1,p2,ptmp : tnode;
         oldt    : Ttoken;
         oldt    : Ttoken;
         filepos : tfileposinfo;
         filepos : tfileposinfo;
-        again   : boolean;
         gendef,parseddef : tdef;
         gendef,parseddef : tdef;
         gensym : tsym;
         gensym : tsym;
       begin
       begin
@@ -3820,32 +3983,22 @@ implementation
                        { this is an inline specialization }
                        { this is an inline specialization }
 
 
                        { retrieve the defs of two nodes }
                        { retrieve the defs of two nodes }
-                       gendef:=nil;
+                       if p1.nodetype=specializen then
+                         gendef:=gettypedef(tspecializenode(p1).sym)
+                       else
+                         gendef:=nil;
                        parseddef:=gettypedef(p2);
                        parseddef:=gettypedef(p2);
 
 
-                       if parseddef.typesym.typ<>typesym then
-                         Internalerror(2011051001);
-
                        { check the hints for parseddef }
                        { check the hints for parseddef }
-                       check_hints(parseddef.typesym,parseddef.typesym.symoptions,parseddef.typesym.deprecatedmsg);
+                       check_hints(parseddef.typesym,parseddef.typesym.symoptions,parseddef.typesym.deprecatedmsg,p1.fileinfo);
 
 
-                       { generate the specialization }
-                       generate_specialization(gendef,false,'',parseddef,gensym.RealName,p2.fileinfo);
+                       ptmp:=generate_inline_specialization(gendef,p1,filepos,parseddef,gensym,p2);
 
 
-                       { we don't need the old left and right nodes anymore }
-                       p1.Free;
-                       p2.Free;
-                       { in case of a class or a record the specialized generic
-                         is always a classrefdef }
-                       again:=false;
-                       { handle potential typecasts, etc }
-                       p1:=handle_factor_typenode(gendef,false,again,nil,false);
-                       { parse postfix operators }
-                       if postfixoperators(p1,again,false) then
-                         if assigned(p1) then
-                           p1.fileinfo:=filepos
-                         else
-                           p1:=cerrornode.create;
+                       { we don't need these nodes anymore }
+                       p1.free;
+                       p2.free;
+
+                       p1:=ptmp;
 
 
                        { with p1 now set we are in reality directly behind the
                        { with p1 now set we are in reality directly behind the
                          call to "factor" thus we need to call down to that
                          call to "factor" thus we need to call down to that
@@ -3912,7 +4065,9 @@ implementation
                _OP_AS,
                _OP_AS,
                _OP_IS :
                _OP_IS :
                  begin
                  begin
-                   if token in [_LT, _LSHARPBRACKET] then
+                   if (m_delphi in current_settings.modeswitches) and
+                       (token in [_LT, _LSHARPBRACKET]) and
+                       getgenericsym(p2,gensym) then
                      begin
                      begin
                        { for now we're handling this as a generic declaration;
                        { for now we're handling this as a generic declaration;
                          there could be cases though (because of operator
                          there could be cases though (because of operator
@@ -3921,24 +4076,12 @@ implementation
                                 point to a variable, etc }
                                 point to a variable, etc }
                        gendef:=gettypedef(p2);
                        gendef:=gettypedef(p2);
 
 
-                       if gendef.typesym.typ<>typesym then
-                         Internalerror(2011071401);
-
-                       { generate the specialization }
-                       generate_specialization(gendef,false,'');
+                       ptmp:=generate_inline_specialization(gendef,p2,filepos,nil,nil,nil);
 
 
                        { we don't need the old p2 anymore }
                        { we don't need the old p2 anymore }
                        p2.Free;
                        p2.Free;
 
 
-                       again:=false;
-                       { handle potential typecasts, etc }
-                       p2:=handle_factor_typenode(gendef,false,again,nil,false);
-                       { parse postfix operators }
-                       if postfixoperators(p2,again,false) then
-                         if assigned(p2) then
-                           p2.fileinfo:=filepos
-                         else
-                           p2:=cerrornode.create;
+                       p2:=ptmp;
 
 
                        { here we don't need to call back down to "factor", thus
                        { here we don't need to call back down to "factor", thus
                          no "goto" }
                          no "goto" }