소스 검색

Implement advanced class helper syntax which allows "inheritance" of class helpers. This is not the same as normal class inheritance as its only used to extend the scope to other class helpers (that pseudo heritage line) when searching for a symbol. The real parent is always the extended class.

- compiler/symdef.pas: add "helperparent" which contains the class helper the current class helper "inherits" from (its real parent is the extended class); it's saved to ppu as well
- compiler/ppu.pas: increase ppu version
- compiler/pdecobj.pas: 
* parse the "parent" of a class helper before parsing the extended class (the real parent)
* also disallow to inherit from class helpers for normal class (and to extend class helpers for class helpers)
* disallow the declarations of fields
* disallow the use of destructors
* don't parse abstract/sealed for class helpers
- compiler/ptyp.pas: _FOR is now parsed inside pdecobj.pas
- compiler/msg*: 
* extended some messages for class helpers
* added some class helper related messages (perhaps the one or other will vanish again...)

git-svn-id: branches/svenbarth/classhelpers@16792 -
svenbarth 14 년 전
부모
커밋
d4be11cb42
7개의 변경된 파일334개의 추가작업 그리고 270개의 파일을 삭제
  1. 18 7
      compiler/msg/errore.msg
  2. 6 2
      compiler/msgidx.inc
  3. 238 234
      compiler/msgtxt.inc
  4. 55 25
      compiler/pdecobj.pas
  5. 1 1
      compiler/ppu.pas
  6. 0 1
      compiler/ptype.pas
  7. 16 0
      compiler/symdef.pas

+ 18 - 7
compiler/msg/errore.msg

@@ -368,7 +368,7 @@ scanner_w_illegal_warn_identifier=02087_W_Illegal identifier "$1" for $WARN dire
 #
 # Parser
 #
-# 03304 is the last used one
+# 03308 is the last used one
 #
 % \section{Parser messages}
 % This section lists all parser messages. The parser takes care of the
@@ -917,9 +917,9 @@ parser_e_no_access_specifier_in_interfaces=03172_E_Access specifiers can't be us
 % The access specifiers \var{public}, \var{private}, \var{protected} and
 % \var{published} can't be used in interfaces, Objective-C protocols and categories because all methods
 % of an interface/protocol/category must be public.
-parser_e_no_vars_in_interfaces=03173_E_An interface or Objective-C protocol or category cannot contain fields
-% Declarations of fields are not allowed in interfaces and Objective-C protocols and categories.
-% An interface/protocol/category can contain only methods and properties with method read/write specifiers.
+parser_e_no_vars_in_interfaces=03173_E_An interface or class helper or Objective-C protocol or category cannot contain fields
+% Declarations of fields are not allowed in interfaces, class helpers and Objective-C protocols and categories.
+% An interface/class helper/protocol/category can contain only methods and properties with method read/write specifiers.
 parser_e_no_local_proc_external=03174_E_Can't declare local procedure as EXTERNAL
 % Declaring local procedures as external is not possible. Local procedures
 % get hidden parameters that will make the chance of errors very high.
@@ -1352,8 +1352,8 @@ parser_e_forward_protocol_declaration_must_be_resolved=03298_E_Forward declarati
 % where \var{MyProtocol} is declared but not defined.
 parser_e_no_record_published=03299_E_Record types cannot have published sections
 % Published sections can be used only inside classes.
-parser_e_no_destructor_in_records=03300_E_Destructors aren't allowed in records
-% Destructor declarations aren't allowed in records.
+parser_e_no_destructor_in_records=03300_E_Destructors aren't allowed in records or class helpers
+% Destructor declarations aren't allowed in records or class helpers.
 parser_e_class_methods_only_static_in_records=03301_E_Class methods must be static in records
 % Class methods declarations aren't allowed in records without static modifier.
 % Records have no inheritance and therefore non static class methods have no sence for them.
@@ -1365,7 +1365,18 @@ parser_e_at_least_one_argument_must_be_of_type=03303_E_At least one argument mus
 % For example class operators must contain at least one argument of the structure where they are defined.
 parser_e_cant_use_type_parameters_here=03304_E_Type parameters may require initialization/finalization - can't be used in variant records
 % Type parameters may be specialized with types which (e.g. \var{ansistring}) need initialization/finalization
-% code which is implicitly generated by the compiler. 
+% code which is implicitly generated by the compiler.
+parser_e_classhelper_id_expected=03305_E_Class helper identifier expected
+% A class helper can only inherit from another class helper.
+parser_e_classhelper_must_extend_subclass=03306_E_Derived class helper must extend a subclass of the class extended by the parent class helper
+% When a class helper inherits from another class helper the extended class must
+% extend either the same class as the parent class helper or a subclass of it
+parser_e_classhelper_not_allowed_here=03307_E_A class helper is not allowed here
+% A class helper can only be referenced when inheriting from it. All other uses
+% (like variable type, field type, parameter type, with clause) are disallowed.
+parser_e_not_allowed_in_classhelper=03308_E_"$1" is not allowed in class helpers
+% Some directives and specifiers like "virtual", "dynamic", "published" aren't
+% allowed inside class helpers in mode ObjFPC (they are ignored in mode Delphi).
 #
 # Type Checking
 #

+ 6 - 2
compiler/msgidx.inc

@@ -393,6 +393,10 @@ const
   parser_e_no_constructor_in_records=03302;
   parser_e_at_least_one_argument_must_be_of_type=03303;
   parser_e_cant_use_type_parameters_here=03304;
+  parser_e_classhelper_id_expected=03305;
+  parser_e_classhelper_must_extend_subclass=03306;
+  parser_e_classhelper_not_allowed_here=03307;
+  parser_e_not_allowed_in_classhelper=03308;
   type_e_mismatch=04000;
   type_e_incompatible_types=04001;
   type_e_not_equal_types=04002;
@@ -882,9 +886,9 @@ const
   option_info=11024;
   option_help_pages=11025;
 
-  MsgTxtSize = 58664;
+  MsgTxtSize = 58927;
 
   MsgIdxMax : array[1..20] of longint=(
-    24,88,305,99,84,54,111,22,202,63,
+    24,88,309,99,84,54,111,22,202,63,
     49,20,1,1,1,1,1,1,1,1
   );

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 238 - 234
compiler/msgtxt.inc


+ 55 - 25
compiler/pdecobj.pas

@@ -436,12 +436,30 @@ implementation
         intfchildof:=nil;
         hasparentdefined:=false;
 
+        { the "parent" of a class helper is not really treated as its parent;
+          it's only used to extend the searched scope }
+        if is_objectpascal_classhelper(current_structdef) then
+          begin
+            if try_to_consume(_LKLAMMER) then
+              begin
+                { TODO : check what these flags mean }
+                single_type(hdef,[stoAllowTypeDef, stoParseClassParent]);
+                if not is_objectpascal_classhelper(hdef) then
+                  begin
+                    Message(parser_e_classhelper_id_expected);
+                    hdef:=nil;
+                  end;
+                current_objectdef.helperparent:=tobjectdef(hdef);
+                consume(_RKLAMMER);
+              end;
+            consume(_FOR);
+          end;
+
         { reads the parent class }
         if (token=_LKLAMMER) or
-           is_objccategory(current_structdef) or
-           is_objectpascal_classhelper(current_structdef) then
+           is_classhelper(current_structdef) then
           begin
-            if not is_objectpascal_classhelper(current_objectdef) then
+            if not is_objectpascal_classhelper(current_structdef) then
               consume(_LKLAMMER);
             { use single_type instead of id_type for specialize support }
             single_type(hdef,[stoAllowTypeDef, stoParseClassParent]);
@@ -464,23 +482,29 @@ implementation
                   isn't allowed }
                 case current_objectdef.objecttype of
                    odt_class:
-                     if not(is_class(childof)) then
-                       begin
-                          if is_interface(childof) then
-                            begin
-                               { we insert the interface after the child
-                                 is set, see below
-                               }
-                               intfchildof:=childof;
-                               childof:=class_tobject;
-                            end
-                          else
-                            Message(parser_e_mix_of_classes_and_objects);
-                       end
+                     if is_objectpascal_classhelper(childof) then
+                       { a class helper is not allowed as parent or extended
+                         class
+                       }
+                       Message(parser_e_classhelper_not_allowed_here)
                      else
-                       if (oo_is_sealed in childof.objectoptions) and
-                           not is_objectpascal_classhelper(current_objectdef) then
-                         Message1(parser_e_sealed_descendant,childof.typename);
+                       if not(is_class(childof)) then
+                         begin
+                            if is_interface(childof) then
+                              begin
+                                 { we insert the interface after the child
+                                   is set, see below
+                                 }
+                                 intfchildof:=childof;
+                                 childof:=class_tobject;
+                              end
+                            else
+                              Message(parser_e_mix_of_classes_and_objects);
+                         end
+                       else
+                         if (oo_is_sealed in childof.objectoptions) and
+                             not is_objectpascal_classhelper(current_structdef) then
+                           Message1(parser_e_sealed_descendant,childof.typename);
                    odt_interfacecorba,
                    odt_interfacecom:
                      begin
@@ -564,7 +588,8 @@ implementation
         { remove forward flag, is resolved }
         exclude(current_structdef.objectoptions,oo_is_forward);
 
-        if hasparentdefined then
+        if hasparentdefined and
+            not is_objectpascal_classhelper(current_structdef) then
           begin
             if current_objectdef.objecttype in [odt_class,odt_objcclass,odt_objcprotocol] then
               begin
@@ -575,8 +600,7 @@ implementation
                     handleImplementedProtocol(intfchildof);
                 readImplementedInterfacesAndProtocols(current_objectdef.objecttype=odt_class);
               end;
-            if not is_objectpascal_classhelper(current_objectdef) then
-              consume(_RKLAMMER);
+            consume(_RKLAMMER);
           end;
       end;
 
@@ -780,7 +804,8 @@ implementation
                         if object_member_blocktype=bt_general then
                           begin
                             if is_interface(current_structdef) or
-                               is_objc_protocol_or_category(current_structdef) then
+                               is_objc_protocol_or_category(current_structdef) or
+                               is_objectpascal_classhelper(current_structdef) then
                               Message(parser_e_no_vars_in_interfaces);
 
                             if (current_structdef.symtable.currentvisibility=vis_published) and
@@ -938,6 +963,10 @@ implementation
                 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_classhelper(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);
 
@@ -1089,7 +1118,7 @@ implementation
                 include(current_structdef.objectoptions,oo_is_classhelper);
               end;
 
-            { change classhepers into Delphi type class helpers }
+            { change classhelpers into Object Pascal style class helpers }
             if (objecttype=odt_classhelper) then
               begin
                 current_objectdef.objecttype:=odt_class;
@@ -1097,7 +1126,8 @@ implementation
               end;
 
             { parse list of options (abstract / sealed) }
-            if not(objecttype in [odt_objcclass,odt_objcprotocol,odt_objccategory]) then
+            if not(objecttype in [odt_objcclass,odt_objcprotocol,odt_objccategory]) and
+                not is_objectpascal_classhelper(current_objectdef) then
               parse_object_options;
 
             symtablestack.push(current_structdef.symtable);

+ 1 - 1
compiler/ppu.pas

@@ -43,7 +43,7 @@ type
 {$endif Test_Double_checksum}
 
 const
-  CurrentPPUVersion = 126;
+  CurrentPPUVersion = 127;
 
 { buffer sizes }
   maxentrysize = 1024;

+ 0 - 1
compiler/ptype.pas

@@ -1546,7 +1546,6 @@ implementation
                 if (idtoken=_HELPER) then
                   begin
                     consume(_HELPER);
-                    consume(_FOR);
                     def:=object_dec(odt_classhelper,name,genericdef,genericlist,nil);
                   end
                 else

+ 16 - 0
compiler/symdef.pas

@@ -255,6 +255,12 @@ interface
           childof        : tobjectdef;
           childofderef   : tderef;
 
+          { for Object Pascal class helpers: the parent class helper is only
+            used to extend the scope of a used class helper by another class
+            helper for the same extended class or a superclass (which is defined
+            by childof }
+          helperparent   : tobjectdef;
+          helperparentderef: tderef;
           { for C++ classes: name of the library this class is imported from }
           import_lib,
           { for Objective-C: protocols and classes can have the same name there }
@@ -4095,6 +4101,9 @@ implementation
               iidstr:=stringdup(ppufile.getstring);
            end;
 
+         if oo_is_classhelper in objectoptions then
+           ppufile.getderef(helperparentderef);
+
          vmtentries:=TFPList.Create;
          vmtentries.count:=ppufile.getlongint;
          for i:=0 to vmtentries.count-1 do
@@ -4253,6 +4262,8 @@ implementation
               ppufile.putguid(iidguid^);
               ppufile.putstring(iidstr^);
            end;
+         if oo_is_classhelper in objectoptions then
+           ppufile.putderef(helperparentderef);
 
          ppufile.putlongint(vmtentries.count);
          for i:=0 to vmtentries.count-1 do
@@ -4311,6 +4322,9 @@ implementation
          else
            tstoredsymtable(symtable).buildderef;
 
+         if oo_is_classhelper in objectoptions then
+           helperparentderef.build(helperparent);
+
          for i:=0 to vmtentries.count-1 do
            begin
              vmtentry:=pvmtentry(vmtentries[i]);
@@ -4339,6 +4353,8 @@ implementation
            end
          else
            tstoredsymtable(symtable).deref;
+         if oo_is_classhelper in objectoptions then
+           helperparent:=tobjectdef(helperparentderef.resolve);
          for i:=0 to vmtentries.count-1 do
            begin
              vmtentry:=pvmtentry(vmtentries[i]);

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.