Browse Source

* symcreat functionality to use the parser from inside the compiler for
artificially generated stuff rather than directly working with defs/syms
problems
o scanner state saving/restoring, and avoiding problems in case of
errors in the injected strings
o in case of the actual application (adding overriding constructors):
the parameters may be of types not visible in the current unit to
newly written code -> can't just use the scanner...

git-svn-id: branches/jvmbackend@18427 -

Jonas Maebe 14 years ago
parent
commit
019ca93a04
9 changed files with 529 additions and 202 deletions
  1. 1 0
      .gitattributes
  2. 201 179
      compiler/pdecobj.pas
  3. 6 1
      compiler/pmodules.pas
  4. 10 1
      compiler/psub.pas
  5. 45 5
      compiler/scanner.pas
  6. 3 1
      compiler/symconst.pas
  7. 215 0
      compiler/symcreat.pas
  8. 1 1
      compiler/symdef.pas
  9. 47 14
      compiler/symsym.pas

+ 1 - 0
.gitattributes

@@ -553,6 +553,7 @@ compiler/sparc/strinst.inc svneol=native#text/plain
 compiler/switches.pas svneol=native#text/plain
 compiler/switches.pas svneol=native#text/plain
 compiler/symbase.pas svneol=native#text/plain
 compiler/symbase.pas svneol=native#text/plain
 compiler/symconst.pas svneol=native#text/plain
 compiler/symconst.pas svneol=native#text/plain
+compiler/symcreat.pas svneol=native#text/plain
 compiler/symdef.pas svneol=native#text/plain
 compiler/symdef.pas svneol=native#text/plain
 compiler/symnot.pas svneol=native#text/plain
 compiler/symnot.pas svneol=native#text/plain
 compiler/symsym.pas svneol=native#text/plain
 compiler/symsym.pas svneol=native#text/plain

+ 201 - 179
compiler/pdecobj.pas

@@ -32,6 +32,9 @@ interface
     { parses a object declaration }
     { parses a object declaration }
     function object_dec(objecttype:tobjecttyp;const n:tidstring;genericdef:tstoreddef;genericlist:TFPObjectList;fd : tobjectdef;helpertype:thelpertype) : tobjectdef;
     function object_dec(objecttype:tobjecttyp;const n:tidstring;genericdef:tstoreddef;genericlist:TFPObjectList;fd : tobjectdef;helpertype:thelpertype) : tobjectdef;
 
 
+    { parses a (class) method declaration }
+    function method_dec(astruct: tabstractrecorddef; is_classdef: boolean): tprocdef;
+
     function class_constructor_head:tprocdef;
     function class_constructor_head:tprocdef;
     function class_destructor_head:tprocdef;
     function class_destructor_head:tprocdef;
     function constructor_head:tprocdef;
     function constructor_head:tprocdef;
@@ -43,7 +46,7 @@ implementation
     uses
     uses
       sysutils,cutils,
       sysutils,cutils,
       globals,verbose,systems,tokens,
       globals,verbose,systems,tokens,
-      symbase,symsym,symtable,
+      symbase,symsym,symtable,symcreat,
       node,nld,nmem,ncon,ncnv,ncal,
       node,nld,nmem,ncon,ncnv,ncal,
       fmodule,scanner,
       fmodule,scanner,
       pbase,pexpr,pdecsub,pdecvar,ptype,pdecl,ppu
       pbase,pexpr,pdecsub,pdecvar,ptype,pdecl,ppu
@@ -704,7 +707,8 @@ implementation
           message(parser_e_dispinterface_needs_a_guid);
           message(parser_e_dispinterface_needs_a_guid);
       end;
       end;
 
 
-    procedure parse_object_members;
+
+    function method_dec(astruct: tabstractrecorddef; is_classdef: boolean): tprocdef;
 
 
       procedure chkobjc(pd: tprocdef);
       procedure chkobjc(pd: tprocdef);
         begin
         begin
@@ -733,28 +737,195 @@ implementation
             { nothing currently }
             { nothing currently }
           end;
           end;
 
 
+
         procedure maybe_parse_hint_directives(pd:tprocdef);
         procedure maybe_parse_hint_directives(pd:tprocdef);
-        var
-          dummysymoptions : tsymoptions;
-          deprecatedmsg : pshortstring;
-        begin
-          dummysymoptions:=[];
-          deprecatedmsg:=nil;
-          while try_consume_hintdirective(dummysymoptions,deprecatedmsg) do
-            Consume(_SEMICOLON);
-          if assigned(pd) then
+          var
+            dummysymoptions : tsymoptions;
+            deprecatedmsg : pshortstring;
+          begin
+            dummysymoptions:=[];
+            deprecatedmsg:=nil;
+            while try_consume_hintdirective(dummysymoptions,deprecatedmsg) do
+              Consume(_SEMICOLON);
+            if assigned(pd) then
+              begin
+                pd.symoptions:=pd.symoptions+dummysymoptions;
+                pd.deprecatedmsg:=deprecatedmsg;
+              end
+            else
+              stringdispose(deprecatedmsg);
+          end;
+
+      var
+        oldparse_only: boolean;
+      begin
+        case token of
+          _PROCEDURE,
+          _FUNCTION:
             begin
             begin
-              pd.symoptions:=pd.symoptions+dummysymoptions;
-              pd.deprecatedmsg:=deprecatedmsg;
-            end
+              if (astruct.symtable.currentvisibility=vis_published) and
+                 not(oo_can_have_published in astruct.objectoptions) then
+                Message(parser_e_cant_have_published);
+
+              oldparse_only:=parse_only;
+              parse_only:=true;
+              result:=parse_proc_dec(is_classdef,astruct);
+
+              { this is for error recovery as well as forward }
+              { interface mappings, i.e. mapping to a method  }
+              { which isn't declared yet                      }
+              if assigned(result) then
+                begin
+                  parse_object_proc_directives(result);
+
+                  { check if dispid is set }
+                  if is_dispinterface(result.struct) and not (po_dispid in result.procoptions) then
+                    begin
+                      result.dispid:=tobjectdef(result.struct).get_next_dispid;
+                      include(result.procoptions, po_dispid);
+                    end;
+
+                  { all Macintosh Object Pascal methods are virtual.  }
+                  { this can't be a class method, because macpas mode }
+                  { has no m_class                                    }
+                  if (m_mac in current_settings.modeswitches) then
+                    include(result.procoptions,po_virtualmethod);
+
+                  { for record helpers only static class methods are allowed }
+                  if is_objectpascal_helper(astruct) and
+                     is_record(tobjectdef(astruct).extendeddef) and
+                     is_classdef and not (po_staticmethod in result.procoptions) then
+                    MessagePos(result.fileinfo,parser_e_class_methods_only_static_in_records);
+
+                  handle_calling_convention(result);
+
+                  { add definition to procsym }
+                  proc_add_definition(result);
+
+                  { add procdef options to objectdef options }
+                  if (po_msgint in result.procoptions) then
+                    include(astruct.objectoptions,oo_has_msgint);
+                  if (po_msgstr in result.procoptions) then
+                    include(astruct.objectoptions,oo_has_msgstr);
+                  if (po_virtualmethod in result.procoptions) then
+                    include(astruct.objectoptions,oo_has_virtual);
+
+                  chkcpp(result);
+                  chkobjc(result);
+                  chkjava(result);
+                end;
+
+              maybe_parse_hint_directives(result);
+
+              parse_only:=oldparse_only;
+            end;
+          _CONSTRUCTOR :
+            begin
+              if (astruct.symtable.currentvisibility=vis_published) and
+                not(oo_can_have_published in astruct.objectoptions) then
+                Message(parser_e_cant_have_published);
+
+              if not is_classdef and not(astruct.symtable.currentvisibility in [vis_public,vis_published]) then
+                Message(parser_w_constructor_should_be_public);
+
+              if is_interface(astruct) then
+                Message(parser_e_no_con_des_in_interfaces);
+
+              { Objective-C does not know the concept of a constructor }
+              if is_objc_class_or_protocol(astruct) then
+                Message(parser_e_objc_no_constructor_destructor);
+
+              if is_objectpascal_helper(astruct) then
+                if is_classdef then
+                  { class constructors are not allowed in class helpers }
+                  Message(parser_e_no_class_constructor_in_helpers)
+                else if is_record(tobjectdef(astruct).extendeddef) then
+                  { as long as constructors aren't allowed in records they
+                    aren't allowed in helpers either }
+                  Message(parser_e_no_constructor_in_records);
+
+              { only 1 class constructor is allowed }
+              if is_classdef and (oo_has_class_constructor in astruct.objectoptions) then
+                Message1(parser_e_only_one_class_constructor_allowed, astruct.objrealname^);
+
+              oldparse_only:=parse_only;
+              parse_only:=true;
+              if is_classdef then
+                result:=class_constructor_head
+              else
+                result:=constructor_head;
+              parse_object_proc_directives(result);
+              handle_calling_convention(result);
+
+              { add definition to procsym }
+              proc_add_definition(result);
+
+              { add procdef options to objectdef options }
+              if (po_virtualmethod in result.procoptions) then
+                include(astruct.objectoptions,oo_has_virtual);
+              chkcpp(result);
+              maybe_parse_hint_directives(result);
+
+              parse_only:=oldparse_only;
+            end;
+          _DESTRUCTOR :
+            begin
+              if (astruct.symtable.currentvisibility=vis_published) and
+                 not(oo_can_have_published in astruct.objectoptions) then
+                Message(parser_e_cant_have_published);
+
+              if not is_classdef then
+                if (oo_has_destructor in astruct.objectoptions) then
+                  Message(parser_n_only_one_destructor);
+
+              if is_interface(astruct) then
+                Message(parser_e_no_con_des_in_interfaces);
+
+              { (class) destructors are not allowed in class helpers }
+              if is_objectpascal_helper(astruct) then
+                Message(parser_e_no_destructor_in_records);
+
+              if not is_classdef and (astruct.symtable.currentvisibility<>vis_public) then
+                Message(parser_w_destructor_should_be_public);
+
+              { Objective-C does not know the concept of a destructor }
+              if is_objc_class_or_protocol(astruct) then
+                Message(parser_e_objc_no_constructor_destructor);
+
+              { only 1 class destructor is allowed }
+              if is_classdef and (oo_has_class_destructor in astruct.objectoptions) then
+                Message1(parser_e_only_one_class_destructor_allowed, astruct.objrealname^);
+
+              oldparse_only:=parse_only;
+              parse_only:=true;
+              if is_classdef then
+                result:=class_destructor_head
+              else
+                result:=destructor_head;
+              parse_object_proc_directives(result);
+              handle_calling_convention(result);
+
+              { add definition to procsym }
+              proc_add_definition(result);
+
+              { add procdef options to objectdef options }
+              if (po_virtualmethod in result.procoptions) then
+                include(astruct.objectoptions,oo_has_virtual);
+
+              chkcpp(result);
+              maybe_parse_hint_directives(result);
+
+              parse_only:=oldparse_only;
+            end;
           else
           else
-            stringdispose(deprecatedmsg);
+            internalerror(2011032102);
         end;
         end;
+      end;
+
+
+    procedure parse_object_members;
 
 
       var
       var
-        pd : tprocdef;
-        has_destructor,
-        oldparse_only,
         typedconstswritable: boolean;
         typedconstswritable: boolean;
         object_member_blocktype : tblock_type;
         object_member_blocktype : tblock_type;
         fields_allowed, is_classdef, class_fields, is_final, final_fields: boolean;
         fields_allowed, is_classdef, class_fields, is_final, final_fields: boolean;
@@ -846,7 +1017,6 @@ implementation
           current_structdef.symtable.currentvisibility:=vis_published
           current_structdef.symtable.currentvisibility:=vis_published
         else
         else
           current_structdef.symtable.currentvisibility:=vis_public;
           current_structdef.symtable.currentvisibility:=vis_public;
-        has_destructor:=false;
         fields_allowed:=true;
         fields_allowed:=true;
         is_classdef:=false;
         is_classdef:=false;
         class_fields:=false;
         class_fields:=false;
@@ -1003,168 +1173,11 @@ implementation
                 parse_class;
                 parse_class;
               end;
               end;
             _PROCEDURE,
             _PROCEDURE,
-            _FUNCTION:
-              begin
-                if (current_structdef.symtable.currentvisibility=vis_published) and
-                   not(oo_can_have_published in current_structdef.objectoptions) then
-                  Message(parser_e_cant_have_published);
-
-                oldparse_only:=parse_only;
-                parse_only:=true;
-                pd:=parse_proc_dec(is_classdef,current_structdef);
-
-                { this is for error recovery as well as forward }
-                { interface mappings, i.e. mapping to a method  }
-                { which isn't declared yet                      }
-                if assigned(pd) then
-                  begin
-                    parse_object_proc_directives(pd);
-
-                    { check if dispid is set }
-                    if is_dispinterface(pd.struct) and not (po_dispid in pd.procoptions) then
-                      begin
-                        pd.dispid:=tobjectdef(pd.struct).get_next_dispid;
-                        include(pd.procoptions, po_dispid);
-                      end;
-
-                    { all Macintosh Object Pascal methods are virtual.  }
-                    { this can't be a class method, because macpas mode }
-                    { has no m_class                                    }
-                    if (m_mac in current_settings.modeswitches) then
-                      include(pd.procoptions,po_virtualmethod);
-
-                    { for record helpers only static class methods are allowed }
-                    if is_objectpascal_helper(current_structdef) and
-                        is_record(current_objectdef.extendeddef) and
-                        is_classdef and not (po_staticmethod in pd.procoptions) then
-                      MessagePos(pd.fileinfo, parser_e_class_methods_only_static_in_records);
-
-                    handle_calling_convention(pd);
-
-                    { add definition to procsym }
-                    proc_add_definition(pd);
-
-                    { add procdef options to objectdef options }
-                    if (po_msgint in pd.procoptions) then
-                      include(current_structdef.objectoptions,oo_has_msgint);
-                    if (po_msgstr in pd.procoptions) then
-                      include(current_structdef.objectoptions,oo_has_msgstr);
-                    if (po_virtualmethod in pd.procoptions) then
-                      include(current_structdef.objectoptions,oo_has_virtual);
-
-                    chkcpp(pd);
-                    chkobjc(pd);
-                    chkjava(pd);
-                  end;
-
-                maybe_parse_hint_directives(pd);
-
-                parse_only:=oldparse_only;
-                fields_allowed:=false;
-                is_classdef:=false;
-              end;
-            _CONSTRUCTOR :
-              begin
-                if (current_structdef.symtable.currentvisibility=vis_published) and
-                  not(oo_can_have_published in current_structdef.objectoptions) then
-                  Message(parser_e_cant_have_published);
-
-                if not is_classdef and not(current_structdef.symtable.currentvisibility in [vis_public,vis_published]) then
-                  Message(parser_w_constructor_should_be_public);
-
-                if is_interface(current_structdef) then
-                  Message(parser_e_no_con_des_in_interfaces);
-
-                { Objective-C does not know the concept of a constructor }
-                if is_objc_class_or_protocol(current_structdef) then
-                  Message(parser_e_objc_no_constructor_destructor);
-
-                if is_objectpascal_helper(current_structdef) then
-                  if is_classdef then
-                    { class constructors are not allowed in class helpers }
-                    Message(parser_e_no_class_constructor_in_helpers)
-                  else
-                  if is_record(current_objectdef.extendeddef) then
-                    { as long as constructors aren't allowed in records they
-                      aren't allowed in helpers either }
-                    Message(parser_e_no_constructor_in_records);
-
-                { only 1 class constructor is allowed }
-                if is_classdef and (oo_has_class_constructor in current_structdef.objectoptions) then
-                  Message1(parser_e_only_one_class_constructor_allowed, current_structdef.objrealname^);
-
-                oldparse_only:=parse_only;
-                parse_only:=true;
-                if is_classdef then
-                  pd:=class_constructor_head
-                else
-                  pd:=constructor_head;
-                parse_object_proc_directives(pd);
-                handle_calling_convention(pd);
-
-                { add definition to procsym }
-                proc_add_definition(pd);
-
-                { add procdef options to objectdef options }
-                if (po_virtualmethod in pd.procoptions) then
-                  include(current_structdef.objectoptions,oo_has_virtual);
-                chkcpp(pd);
-                maybe_parse_hint_directives(pd);
-
-                parse_only:=oldparse_only;
-                fields_allowed:=false;
-                is_classdef:=false;
-              end;
+            _FUNCTION,
+            _CONSTRUCTOR,
             _DESTRUCTOR :
             _DESTRUCTOR :
               begin
               begin
-                if (current_structdef.symtable.currentvisibility=vis_published) and
-                   not(oo_can_have_published in current_structdef.objectoptions) then
-                  Message(parser_e_cant_have_published);
-
-                if not is_classdef then
-                  if has_destructor then
-                    Message(parser_n_only_one_destructor)
-                  else
-                    has_destructor:=true;
-
-                if is_interface(current_structdef) then
-                  Message(parser_e_no_con_des_in_interfaces);
-
-                { (class) destructors are not allowed in class helpers }
-                if is_objectpascal_helper(current_structdef) then
-                  Message(parser_e_no_destructor_in_records);
-
-                if not is_classdef and (current_structdef.symtable.currentvisibility<>vis_public) then
-                  Message(parser_w_destructor_should_be_public);
-
-                { Objective-C does not know the concept of a destructor }
-                if is_objc_class_or_protocol(current_structdef) then
-                  Message(parser_e_objc_no_constructor_destructor);
-
-                { only 1 class destructor is allowed }
-                if is_classdef and (oo_has_class_destructor in current_structdef.objectoptions) then
-                  Message1(parser_e_only_one_class_destructor_allowed, current_structdef.objrealname^);
-
-                oldparse_only:=parse_only;
-                parse_only:=true;
-                if is_classdef then
-                  pd:=class_destructor_head
-                else
-                  pd:=destructor_head;
-                parse_object_proc_directives(pd);
-                handle_calling_convention(pd);
-
-                { add definition to procsym }
-                proc_add_definition(pd);
-
-                { add procdef options to objectdef options }
-                if (po_virtualmethod in pd.procoptions) then
-                  include(current_structdef.objectoptions,oo_has_virtual);
-
-                chkcpp(pd);
-                maybe_parse_hint_directives(pd);
-
-                parse_only:=oldparse_only;
+                method_dec(current_structdef,is_classdef);
                 fields_allowed:=false;
                 fields_allowed:=false;
                 is_classdef:=false;
                 is_classdef:=false;
               end;
               end;
@@ -1330,6 +1343,15 @@ implementation
 
 
             { parse and insert object members }
             { parse and insert object members }
             parse_object_members;
             parse_object_members;
+
+            { In Java, constructors are not automatically inherited (so you can
+              hide them). Emulate the Pascal behaviour for classes implemented
+              in Pascal (we cannot do it for classes implemented in Java, since
+              we obviously cannot add constructors to those) }
+            if is_javaclass(current_structdef) and
+               not(oo_is_external in current_structdef.objectoptions) then
+              add_missing_parent_constructors_intf(tobjectdef(current_structdef));
+
             symtablestack.pop(current_structdef.symtable);
             symtablestack.pop(current_structdef.symtable);
           end;
           end;
 
 

+ 6 - 1
compiler/pmodules.pas

@@ -36,7 +36,7 @@ implementation
        globtype,version,systems,tokens,
        globtype,version,systems,tokens,
        cutils,cfileutl,cclasses,comphook,
        cutils,cfileutl,cclasses,comphook,
        globals,verbose,fmodule,finput,fppu,
        globals,verbose,fmodule,finput,fppu,
-       symconst,symbase,symtype,symdef,symsym,symtable,
+       symconst,symbase,symtype,symdef,symsym,symtable,symcreat,
        wpoinfo,
        wpoinfo,
        aasmtai,aasmdata,aasmcpu,aasmbase,
        aasmtai,aasmdata,aasmcpu,aasmbase,
        cgbase,cgobj,
        cgbase,cgobj,
@@ -1041,6 +1041,7 @@ implementation
         until false;
         until false;
       end;
       end;
 
 
+
     procedure proc_unit;
     procedure proc_unit;
 
 
       function is_assembler_generated:boolean;
       function is_assembler_generated:boolean;
@@ -1267,6 +1268,10 @@ implementation
              init_procinfo.parse_body;
              init_procinfo.parse_body;
              { save file pos for debuginfo }
              { save file pos for debuginfo }
              current_module.mainfilepos:=init_procinfo.entrypos;
              current_module.mainfilepos:=init_procinfo.entrypos;
+             { add implementations for synthetic method declarations added by
+               the compiler }
+             add_synthetic_method_implementations(current_module.globalsymtable);
+             add_synthetic_method_implementations(current_module.localsymtable);
            end;
            end;
 
 
          { Generate specializations of objectdefs methods }
          { Generate specializations of objectdefs methods }

+ 10 - 1
compiler/psub.pas

@@ -66,6 +66,11 @@ interface
     { reads declarations in the interface part of a unit }
     { reads declarations in the interface part of a unit }
     procedure read_interface_declarations;
     procedure read_interface_declarations;
 
 
+    { reads any routine in the implementation, or a non-method routine
+      declaration in the interface (depending on whether or not parse_only is
+      true) }
+    procedure read_proc(isclassmethod:boolean);
+
     procedure generate_specialization_procs;
     procedure generate_specialization_procs;
 
 
 
 
@@ -81,7 +86,7 @@ implementation
        { aasm }
        { aasm }
        cpuinfo,cpubase,aasmbase,aasmtai,aasmdata,
        cpuinfo,cpubase,aasmbase,aasmtai,aasmdata,
        { symtable }
        { symtable }
-       symconst,symbase,symsym,symtype,symtable,defutil,
+       symconst,symbase,symsym,symtype,symtable,defutil,symcreat,
        paramgr,
        paramgr,
        ppu,fmodule,
        ppu,fmodule,
        { pass 1 }
        { pass 1 }
@@ -1946,6 +1951,10 @@ implementation
            end;
            end;
          until false;
          until false;
 
 
+         { add implementations for synthetic method declarations added by
+           the compiler }
+         add_synthetic_method_implementations(current_procinfo.procdef.localst);
+
          { check for incomplete class definitions, this is only required
          { check for incomplete class definitions, this is only required
            for fpc modes }
            for fpc modes }
          if (m_fpc in current_settings.modeswitches) then
          if (m_fpc in current_settings.modeswitches) then

+ 45 - 5
compiler/scanner.pas

@@ -78,8 +78,14 @@ interface
 
 
        tspecialgenerictoken = (ST_LOADSETTINGS,ST_LINE,ST_COLUMN,ST_FILEINDEX);
        tspecialgenerictoken = (ST_LOADSETTINGS,ST_LINE,ST_COLUMN,ST_FILEINDEX);
 
 
-       { tscannerfile }
+       tscannerstate = record
+         lasttokenpos: longint;
+         current_tokenpos,
+         current_filepos: tfileposinfo;
+         token: ttoken;
+       end;
 
 
+       { tscannerfile }
        tscannerfile = class
        tscannerfile = class
        private
        private
          procedure do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
          procedure do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
@@ -145,7 +151,12 @@ interface
           procedure nextfile;
           procedure nextfile;
           procedure addfile(hp:tinputfile);
           procedure addfile(hp:tinputfile);
           procedure reload;
           procedure reload;
-          procedure insertmacro(const macname:string;p:pchar;len,line,fileindex:longint);
+          { replaces current token with the text in p }
+          procedure substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint);
+          { inserts the text in p before the current token; the current token
+            will be restored afterwards }
+          procedure inserttext_begin(const macname: string; const str: ansistring; out scannerstate: tscannerstate);
+          procedure inserttext_end(const scannerstate: tscannerstate);
         { Scanner things }
         { Scanner things }
           procedure gettokenpos;
           procedure gettokenpos;
           procedure inc_comment_level;
           procedure inc_comment_level;
@@ -1753,7 +1764,7 @@ In case not, the value returned can be arbitrary.
             Message1(scan_w_include_env_not_found,path);
             Message1(scan_w_include_env_not_found,path);
            { make it a stringconst }
            { make it a stringconst }
            hs:=''''+hs+'''';
            hs:=''''+hs+'''';
-           current_scanner.insertmacro(path,@hs[1],length(hs),
+           current_scanner.substitutemacro(path,@hs[1],length(hs),
             current_scanner.line_no,current_scanner.inputfile.ref_index);
             current_scanner.line_no,current_scanner.inputfile.ref_index);
          end
          end
         else
         else
@@ -2423,7 +2434,7 @@ In case not, the value returned can be arbitrary.
       end;
       end;
 
 
 
 
-    procedure tscannerfile.insertmacro(const macname:string;p:pchar;len,line,fileindex:longint);
+    procedure tscannerfile.substitutemacro(const macname:string;p:pchar;len,line,fileindex:longint);
       var
       var
         hp : tinputfile;
         hp : tinputfile;
       begin
       begin
@@ -2454,6 +2465,35 @@ In case not, the value returned can be arbitrary.
       end;
       end;
 
 
 
 
+    procedure tscannerfile.inserttext_begin(const macname: string; const str: ansistring; out scannerstate: tscannerstate);
+      begin
+        if (nexttoken<>NOTOKEN) then
+          internalerror(2011032103);
+        scannerstate.lasttokenpos:=lasttokenpos;
+        scannerstate.token:=token;
+        scannerstate.current_tokenpos:=current_tokenpos;
+        scannerstate.current_filepos:=current_filepos;
+
+        current_scanner.substitutemacro(macname,@str[1],length(str),
+          current_scanner.line_no,current_scanner.inputfile.ref_index);
+        current_scanner.readtoken(false);
+      end;
+
+
+    procedure tscannerfile.inserttext_end(const scannerstate: tscannerstate);
+      begin
+        if nexttoken<>NOTOKEN then
+          internalerror(2011032104);
+        nexttoken:=token;
+        cachenexttokenpos;
+
+        lasttokenpos:=scannerstate.lasttokenpos;
+        token:=scannerstate.token;
+        current_tokenpos:=scannerstate.current_tokenpos;
+        current_filepos:=scannerstate.current_filepos;
+      end;
+
+
     procedure tscannerfile.do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
     procedure tscannerfile.do_gettokenpos(out tokenpos: longint; out filepos: tfileposinfo);
       begin
       begin
         tokenpos:=inputstart+(inputpointer-inputbuffer);
         tokenpos:=inputstart+(inputpointer-inputbuffer);
@@ -3539,7 +3579,7 @@ In case not, the value returned can be arbitrary.
                      begin
                      begin
                        mac.is_used:=true;
                        mac.is_used:=true;
                        inc(yylexcount);
                        inc(yylexcount);
-                       insertmacro(pattern,mac.buftext,mac.buflen,
+                       substitutemacro(pattern,mac.buftext,mac.buflen,
                          mac.fileinfo.line,mac.fileinfo.fileindex);
                          mac.fileinfo.line,mac.fileinfo.fileindex);
                      { handle empty macros }
                      { handle empty macros }
                        if c=#0 then
                        if c=#0 then

+ 3 - 1
compiler/symconst.pas

@@ -316,7 +316,9 @@ type
        up the stack will also remain balanced) }
        up the stack will also remain balanced) }
     po_delphi_nested_cc,
     po_delphi_nested_cc,
     { Java method }
     { Java method }
-    po_java
+    po_java,
+    { synthetic method, not parsed from source but inserted by compiler }
+    po_synthetic
   );
   );
   tprocoptions=set of tprocoption;
   tprocoptions=set of tprocoption;
 
 

+ 215 - 0
compiler/symcreat.pas

@@ -0,0 +1,215 @@
+{
+    Copyright (c) 2011 by Jonas Maebe
+
+    This unit provides helpers for creating new syms/defs based on string
+    representations.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+{$i fpcdefs.inc}
+
+unit symcreat;
+
+interface
+
+  uses
+    finput,
+    symconst,symdef,symbase;
+
+  { in the JVM, constructors are not automatically inherited (so you can hide
+    them). To emulate the Pascal behaviour, we have to automatically add
+    all parent constructors to the current class as well. }
+  procedure add_missing_parent_constructors_intf(obj: tobjectdef);
+  procedure add_missing_parent_constructors_impl(obj: tobjectdef);
+
+  { parses a (class or regular) method/constructor/destructor declaration from
+    str, as if it were declared in astruct's declaration body }
+  function str_parse_method_dec(str: ansistring; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;
+
+  { parses a (class or regular)  method/constructor/destructor implementation
+    from str, as if it appeared in the current unit's implementation section }
+  function str_parse_method_impl(str: ansistring; is_classdef: boolean):boolean;
+
+  { goes through all defs in st to add implementations for synthetic methods
+    added earlier }
+  procedure add_synthetic_method_implementations(st: tsymtable);
+
+implementation
+
+  uses
+    verbose,systems,
+    tokens,scanner,
+    symtype,symsym,symtable,
+    pbase,pdecobj,psub,
+    defcmp;
+
+
+  function str_parse_method_dec(str: ansistring; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;
+    var
+      oldparse_only: boolean;
+      scannerstate: tscannerstate;
+    begin
+      oldparse_only:=parse_only;
+      parse_only:=true;
+      result:=false;
+      { inject the string in the scanner }
+      str:=str+'end;';
+      current_scanner.substitutemacro('meth_head_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index);
+      current_scanner.readtoken(false);
+      { and parse it... }
+      pd:=method_dec(astruct,is_classdef);
+      if assigned(pd) then
+        begin
+          include(pd.procoptions,po_synthetic);
+          result:=true;
+        end;
+      parse_only:=oldparse_only;
+//      current_scanner.inserttext_end(scannerstate);
+    end;
+
+
+  function str_parse_method_impl(str: ansistring; is_classdef: boolean):boolean;
+     var
+       oldparse_only: boolean;
+       scannerstate: tscannerstate;
+     begin
+       str:=str+'end;';
+     (*
+       oldparse_only:=parse_only;
+       parse_only:=false;
+      { inject the string in the scanner }
+      current_scanner.inserttext_begin('meth_impl_macro',str,scannerstate);
+      dec(current_scanner.yylexcount);
+      read_proc(is_classdef);
+      parse_only:=oldparse_only;
+      result:=true;
+      current_scanner.inserttext_end(scannerstate);
+      *)
+     end;
+
+
+  procedure add_missing_parent_constructors_intf(obj: tobjectdef);
+    var
+      parent: tobjectdef;
+      psym: tprocsym;
+      def: tdef;
+      pd: tprocdef;
+      newpd,
+      parentpd: tprocdef;
+      i: longint;
+      srsym: tsym;
+      srsymtable: tsymtable;
+      isclassmethod: boolean;
+      str: ansistring;
+      old_scanner: tscannerfile;
+    begin
+      if not assigned(obj.childof) then
+        exit;
+      old_scanner:=nil;
+      parent:=obj.childof;
+      { find all constructor in the parent }
+      for i:=0 to tobjectsymtable(parent.symtable).deflist.count-1 do
+        begin
+          def:=tdef(tobjectsymtable(parent.symtable).deflist[i]);
+          if (def.typ<>procdef) or
+             (tprocdef(def).proctypeoption<>potype_constructor) then
+            continue;
+          pd:=tprocdef(def);
+          { do we have this constructor too? (don't use
+            search_struct_member/searchsym_in_class, since those will
+            search parents too) }
+          if searchsym_in_record(obj,pd.procsym.name,srsym,srsymtable) then
+            begin
+              { there's a symbol with the same name, is it a constructor
+                with the same parameters? }
+              if srsym.typ=procsym then
+                begin
+                  parentpd:=tprocsym(srsym).find_procdef_bytype_and_para(
+                    potype_constructor,pd.paras,tprocdef(def).returndef,
+                    [cpo_ignorehidden,cpo_ignoreuniv,cpo_openequalisexact]);
+                  if assigned(parentpd) then
+                    continue;
+                end;
+            end;
+          { if we get here, we did not find it in the current objectdef ->
+            add }
+          if not assigned(old_scanner) then
+            begin
+              old_scanner:=current_scanner;
+              current_scanner:=tscannerfile.Create('_Macro_.parent_constructors_intf');
+            end;
+          isclassmethod:=
+            (po_classmethod in tprocdef(pd).procoptions) and
+            not(tprocdef(pd).proctypeoption in [potype_constructor,potype_destructor]);
+          { + 'overload' for Delphi modes }
+          str:=tprocdef(pd).customprocname([pno_proctypeoption,pno_paranames,pno_noclassmarker])+'overload;';
+          if not str_parse_method_dec(str,isclassmethod,obj,newpd) then
+            internalerror(2011032001);
+          include(newpd.procoptions,po_synthetic);
+        end;
+      if assigned(old_scanner) then
+        begin
+          current_scanner.free;
+          current_scanner:=old_scanner;
+          current_scanner.readtoken(false);
+        end;
+    end;
+
+
+  procedure add_missing_parent_constructors_impl(obj: tobjectdef);
+    var
+      i: longint;
+      def: tdef;
+      str: ansistring;
+      isclassmethod: boolean;
+    begin
+      for i:=0 to tobjectsymtable(obj.symtable).deflist.count-1 do
+        begin
+          def:=tdef(tobjectsymtable(obj.symtable).deflist[i]);
+          if (def.typ<>procdef) or
+             not(po_synthetic in tprocdef(def).procoptions) then
+            continue;
+          isclassmethod:=
+            (po_classmethod in tprocdef(def).procoptions) and
+            not(tprocdef(def).proctypeoption in [potype_constructor,potype_destructor]);
+          str:=tprocdef(def).customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker]);
+          str:=str+'overload; begin inherited end;';
+          str_parse_method_impl(str,isclassmethod);
+        end;
+    end;
+
+
+  procedure add_synthetic_method_implementations(st: tsymtable);
+    var
+      i: longint;
+      def: tdef;
+    begin
+      { only necessary for the JVM target currently }
+      if not (target_info.system in [system_jvm_java32]) then
+        exit;
+      for i:=0 to st.deflist.count-1 do
+        begin
+          def:=tdef(st.deflist[i]);
+          if is_javaclass(def) and
+             not(oo_is_external in tobjectdef(def).objectoptions) then
+            add_missing_parent_constructors_impl(tobjectdef(def));
+        end;
+    end;
+
+
+end.
+

+ 1 - 1
compiler/symdef.pas

@@ -3338,7 +3338,7 @@ implementation
                   first:=false;
                   first:=false;
                 end
                 end
                else
                else
-                s:=s+',';
+                s:=s+';';
                if vo_is_hidden_para in hp.varoptions then
                if vo_is_hidden_para in hp.varoptions then
                  s:=s+'<';
                  s:=s+'<';
                case hp.varspez of
                case hp.varspez of

+ 47 - 14
compiler/symsym.pas

@@ -102,6 +102,7 @@ interface
           procedure deref;override;
           procedure deref;override;
           function find_procdef_bytype(pt:Tproctypeoption):Tprocdef;
           function find_procdef_bytype(pt:Tproctypeoption):Tprocdef;
           function find_procdef_bypara(para:TFPObjectList;retdef:tdef;cpoptions:tcompare_paras_options):Tprocdef;
           function find_procdef_bypara(para:TFPObjectList;retdef:tdef;cpoptions:tcompare_paras_options):Tprocdef;
+          function find_procdef_bytype_and_para(pt:Tproctypeoption;para:TFPObjectList;retdef:tdef;cpoptions:tcompare_paras_options):Tprocdef;
           function find_procdef_byoptions(ops:tprocoptions): Tprocdef;
           function find_procdef_byoptions(ops:tprocoptions): Tprocdef;
           function find_procdef_byprocvardef(d:Tprocvardef):Tprocdef;
           function find_procdef_byprocvardef(d:Tprocvardef):Tprocdef;
           function find_procdef_assignment_operator(fromdef,todef:tdef;var besteq:tequaltype):Tprocdef;
           function find_procdef_assignment_operator(fromdef,todef:tdef;var besteq:tequaltype):Tprocdef;
@@ -652,35 +653,67 @@ implementation
       end;
       end;
 
 
 
 
+    function check_procdef_paras(pd:tprocdef;para:TFPObjectList;retdef:tdef;
+                                            cpoptions:tcompare_paras_options): tprocdef;
+      var
+        eq: tequaltype;
+      begin
+        result:=nil;
+        if assigned(retdef) then
+          eq:=compare_defs(retdef,pd.returndef,nothingn)
+        else
+          eq:=te_equal;
+        if (eq>=te_equal) or
+           ((cpo_allowconvert in cpoptions) and (eq>te_incompatible)) then
+          begin
+            eq:=compare_paras(para,pd.paras,cp_value_equal_const,cpoptions);
+            if (eq>=te_equal) or
+               ((cpo_allowconvert in cpoptions) and (eq>te_incompatible)) then
+              begin
+                result:=pd;
+                exit;
+              end;
+          end;
+      end;
+
+
     function Tprocsym.Find_procdef_bypara(para:TFPObjectList;retdef:tdef;
     function Tprocsym.Find_procdef_bypara(para:TFPObjectList;retdef:tdef;
                                             cpoptions:tcompare_paras_options):Tprocdef;
                                             cpoptions:tcompare_paras_options):Tprocdef;
       var
       var
         i  : longint;
         i  : longint;
         pd : tprocdef;
         pd : tprocdef;
-        eq : tequaltype;
       begin
       begin
         result:=nil;
         result:=nil;
         for i:=0 to ProcdefList.Count-1 do
         for i:=0 to ProcdefList.Count-1 do
           begin
           begin
             pd:=tprocdef(ProcdefList[i]);
             pd:=tprocdef(ProcdefList[i]);
-            if assigned(retdef) then
-              eq:=compare_defs(retdef,pd.returndef,nothingn)
-            else
-              eq:=te_equal;
-            if (eq>=te_equal) or
-               ((cpo_allowconvert in cpoptions) and (eq>te_incompatible)) then
+            result:=check_procdef_paras(pd,para,retdef,cpoptions);
+            if assigned(result) then
+              exit;
+          end;
+      end;
+
+
+    function Tprocsym.find_procdef_bytype_and_para(pt:Tproctypeoption;
+               para:TFPObjectList;retdef:tdef;cpoptions:tcompare_paras_options):Tprocdef;
+      var
+        i  : longint;
+        pd : tprocdef;
+      begin
+        result:=nil;
+        for i:=0 to ProcdefList.Count-1 do
+          begin
+            pd:=tprocdef(ProcdefList[i]);
+            if pd.proctypeoption=pt then
               begin
               begin
-                eq:=compare_paras(para,pd.paras,cp_value_equal_const,cpoptions);
-                if (eq>=te_equal) or
-                   ((cpo_allowconvert in cpoptions) and (eq>te_incompatible)) then
-                  begin
-                    result:=pd;
-                    exit;
-                  end;
+                result:=check_procdef_paras(pd,para,retdef,cpoptions);
+                if assigned(result) then
+                  exit;
               end;
               end;
           end;
           end;
       end;
       end;
 
 
+
     function tprocsym.find_procdef_byoptions(ops: tprocoptions): Tprocdef;
     function tprocsym.find_procdef_byoptions(ops: tprocoptions): Tprocdef;
       var
       var
         i  : longint;
         i  : longint;