Explorar el Código

+ support for "final" fields in *external* (Java and other) classes, enabled
via {$modeswitch finalfields} (on by default on the JVM target). The
meaning is the same as in Java: a final (class) field can only be set
in a (class) constructor of the class it's defined in, and can only be
written once there (and *must* be set there). They are currently only
supported for external classes since that basically turns them into
constants, since for non-external classes we need full dataflow analysis
o refactored pdecobj.parse_object_members() a bit in the process to reduce
the amount of repetition (which would have been further increased for
the support for final fields)
o made error message about "wrong use of absolute" for fields etc generic,
so it gives a proper error depending on which token was used (it had
to be made generic for "final" support, but already was used for other
things that were wrongly reported as "absolute" misusages)

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

Jonas Maebe hace 14 años
padre
commit
37b5c061e3

+ 6 - 2
compiler/globtype.pas

@@ -288,7 +288,10 @@ interface
          m_nested_procvars,     { support nested procedural variables }
          m_nested_procvars,     { support nested procedural variables }
          m_non_local_goto,      { support non local gotos (like iso pascal) }
          m_non_local_goto,      { support non local gotos (like iso pascal) }
          m_advanced_records,    { advanced record syntax with visibility sections, methods and properties }
          m_advanced_records,    { advanced record syntax with visibility sections, methods and properties }
-         m_isolike_unary_minus  { unary minus like in iso pascal: same precedence level as binary minus/plus }
+         m_isolike_unary_minus, { unary minus like in iso pascal: same precedence level as binary minus/plus }
+         m_final_fields         { allows declaring fields as "final", which means they must be initialised
+                                  in the (class) constructor and are constant from then on (same as final
+                                  fields in Java) }
        );
        );
        tmodeswitches = set of tmodeswitch;
        tmodeswitches = set of tmodeswitch;
 
 
@@ -440,7 +443,8 @@ interface
          'NESTEDPROCVARS',
          'NESTEDPROCVARS',
          'NONLOCALGOTO',
          'NONLOCALGOTO',
          'ADVANCEDRECORDS',
          'ADVANCEDRECORDS',
-         'ISOUNARYMINUS');
+         'ISOUNARYMINUS',
+         'FINALFIELDS');
 
 
 
 
      type
      type

+ 37 - 8
compiler/htypechk.pas

@@ -983,6 +983,11 @@ implementation
                  if (tloadnode(p).symtableentry.typ in [localvarsym,paravarsym,staticvarsym]) then
                  if (tloadnode(p).symtableentry.typ in [localvarsym,paravarsym,staticvarsym]) then
                    begin
                    begin
                      hsym:=tabstractvarsym(tloadnode(p).symtableentry);
                      hsym:=tabstractvarsym(tloadnode(p).symtableentry);
+                     { this check requires proper data flow analysis... }
+(*                     if (hsym.varspez=vs_final) and
+                        (hsym.varstate in [vs_written,vs_readwritten]) and
+                        (newstate in [vs_written,vs_readwritten]) then
+                       CGMessagePos1(p.fileinfo,sym_e_final_write_once); *)
                      if (vsf_must_be_valid in varstateflags) and
                      if (vsf_must_be_valid in varstateflags) and
                         (hsym.varstate in [vs_declared,vs_read_not_warned,vs_referred_not_inited]) then
                         (hsym.varstate in [vs_declared,vs_read_not_warned,vs_referred_not_inited]) then
                        begin
                        begin
@@ -1080,6 +1085,32 @@ implementation
         todef    : tdef;
         todef    : tdef;
         errmsg,
         errmsg,
         temp     : longint;
         temp     : longint;
+
+        function constaccessok(vs: tabstractvarsym): boolean;
+          begin
+            result:=false;
+            { allow p^:= constructions with p is const parameter }
+            if gotderef or gotdynarray or (Valid_Const in opts) or
+              (nf_isinternal_ignoreconst in hp.flags) then
+              result:=true
+            { final (class) fields can only be initialised in the (class) constructors of
+              class in which they have been declared (not in descendent constructors) }
+            else if vs.varspez=vs_final then
+              begin
+                if (current_procinfo.procdef.owner=vs.owner) then
+                  if sp_static in vs.symoptions then
+                    result:=current_procinfo.procdef.proctypeoption=potype_class_constructor
+                  else
+                    result:=current_procinfo.procdef.proctypeoption=potype_constructor;
+                if not result and
+                   report_errors then
+                  CGMessagePos(hp.fileinfo,type_e_invalid_final_assignment);
+              end
+            else
+              if report_errors then
+                CGMessagePos(hp.fileinfo,type_e_no_assign_to_const);
+          end;
+
       begin
       begin
         if valid_const in opts then
         if valid_const in opts then
           errmsg:=type_e_variable_id_expected
           errmsg:=type_e_variable_id_expected
@@ -1316,6 +1347,10 @@ implementation
                          CGMessagePos(hp.fileinfo,parser_e_packed_element_no_var_addr);
                          CGMessagePos(hp.fileinfo,parser_e_packed_element_no_var_addr);
                      exit;
                      exit;
                    end;
                    end;
+                 { check for final fields }
+                 if (tsubscriptnode(hp).vs.varspez=vs_final) and
+                    not constaccessok(tsubscriptnode(hp).vs) then
+                   exit;
                  gotsubscript:=true;
                  gotsubscript:=true;
                  { loop counter? }
                  { loop counter? }
                  if not(Valid_Const in opts) and
                  if not(Valid_Const in opts) and
@@ -1480,15 +1515,9 @@ implementation
                            exit;
                            exit;
                          end;
                          end;
                        { read-only variable? }
                        { read-only variable? }
-                       if (tabstractvarsym(tloadnode(hp).symtableentry).varspez in [vs_const,vs_constref]) then
+                       if (tabstractvarsym(tloadnode(hp).symtableentry).varspez in [vs_const,vs_constref,vs_final]) then
                         begin
                         begin
-                          { allow p^:= constructions with p is const parameter }
-                          if gotderef or gotdynarray or (Valid_Const in opts) or
-                            (nf_isinternal_ignoreconst in tloadnode(hp).flags) then
-                            result:=true
-                          else
-                            if report_errors then
-                              CGMessagePos(tloadnode(hp).fileinfo,type_e_no_assign_to_const);
+                          result:=constaccessok(tabstractvarsym(tloadnode(hp).symtableentry));
                           exit;
                           exit;
                         end;
                         end;
                        result:=true;
                        result:=true;

+ 15 - 5
compiler/msg/errore.msg

@@ -375,7 +375,7 @@ scanner_e_illegal_alignment_directive=02088_E_Illegal alignment directive
 #
 #
 # Parser
 # Parser
 #
 #
-# 03310 is the last used one
+# 03315 is the last used one
 #
 #
 % \section{Parser messages}
 % \section{Parser messages}
 % This section lists all parser messages. The parser takes care of the
 % This section lists all parser messages. The parser takes care of the
@@ -675,9 +675,10 @@ parser_e_mix_of_classes_and_objects=03093_E_The mix of different kind of objects
 % a class cannot have an object as parent and vice versa.
 % a class cannot have an object as parent and vice versa.
 parser_w_unknown_proc_directive_ignored=03094_W_Unknown procedure directive had to be ignored: "$1"
 parser_w_unknown_proc_directive_ignored=03094_W_Unknown procedure directive had to be ignored: "$1"
 % The procedure directive you specified is unknown.
 % The procedure directive you specified is unknown.
-parser_e_absolute_only_one_var=03095_E_absolute can only be associated to one variable
-% You cannot specify more than one variable before the \var{absolute} directive.
-% Thus, the following construct will provide this error:
+parser_e_directive_only_one_var=03095_E_$1 can be associated with only one variable
+% You cannot specify more than one variable before the \var{absolute}, \var{export}, \var{external},
+% \var{weakexternal}, \var{public} and \var{cvar} directives.
+% As a result, for example the following construct will provide this error:
 % \begin{verbatim}
 % \begin{verbatim}
 % Var Z : Longint;
 % Var Z : Longint;
 %     X,Y : Longint absolute Z;
 %     X,Y : Longint absolute Z;
@@ -1400,10 +1401,16 @@ parser_e_mapping_no_implements=03312_E_Interface "$1" can't be delegated by "$2"
 % has to implement the interface directly. Delegation is not possible.
 % has to implement the interface directly. Delegation is not possible.
 parser_e_implements_no_mapping=03313_E_Interface "$1" can't have method resolutions, "$2" already delegates it
 parser_e_implements_no_mapping=03313_E_Interface "$1" can't have method resolutions, "$2" already delegates it
 % Method resoulution is only possible for interfaces that are implemented directly, not by delegation.
 % Method resoulution is only possible for interfaces that are implemented directly, not by delegation.
+parser_e_final_only_const_var=03314_E_Only fields (var-sections) and constants can be final in object types
+% A final (class) field must be assigned a single value in the (class) constructor, and cannot
+% be overwritten afterwards. A final (typed) constant is read-only.
+parser_e_final_only_external=03315_E_Final fields are currently only supported for external classes
+% Support for final fields in non-external classes requires a full data flow
+% analysis implementation in FPC, which it currently still lacks.
 % \end{description}
 % \end{description}
 # Type Checking
 # Type Checking
 #
 #
-# 04103 is the last used one
+# 04104 is the last used one
 #
 #
 % \section{Type checking errors}
 % \section{Type checking errors}
 % This section lists all errors that can occur when type checking is
 % This section lists all errors that can occur when type checking is
@@ -1764,6 +1771,9 @@ type_e_record_helper_must_extend_same_record=04102_E_Derived record helper must
 type_e_java_class_method_not_static=04103_E_Java class methods have to be static
 type_e_java_class_method_not_static=04103_E_Java class methods have to be static
 % All methods in Java are either regular (virtual) methods, or static class
 % All methods in Java are either regular (virtual) methods, or static class
 % methods. It is not possible to declare non-static class methods.
 % methods. It is not possible to declare non-static class methods.
+type_e_invalid_final_assignment=04104_E_Final (class) fields can only be assigned in their class' (class) constructor
+% It is only possible to assign a value to a final (class) field inside a (class) constructor of its owning class.
+%
 %
 %
 % \end{description}
 % \end{description}
 #
 #

+ 6 - 3
compiler/msgidx.inc

@@ -194,7 +194,7 @@ const
   parser_f_unsupported_feature=03092;
   parser_f_unsupported_feature=03092;
   parser_e_mix_of_classes_and_objects=03093;
   parser_e_mix_of_classes_and_objects=03093;
   parser_w_unknown_proc_directive_ignored=03094;
   parser_w_unknown_proc_directive_ignored=03094;
-  parser_e_absolute_only_one_var=03095;
+  parser_e_directive_only_one_var=03095;
   parser_e_absolute_only_to_var_or_const=03096;
   parser_e_absolute_only_to_var_or_const=03096;
   parser_e_initialized_only_one_var=03097;
   parser_e_initialized_only_one_var=03097;
   parser_e_abstract_no_definition=03098;
   parser_e_abstract_no_definition=03098;
@@ -405,6 +405,8 @@ const
   parser_e_duplicate_implements_clause=03311;
   parser_e_duplicate_implements_clause=03311;
   parser_e_mapping_no_implements=03312;
   parser_e_mapping_no_implements=03312;
   parser_e_implements_no_mapping=03313;
   parser_e_implements_no_mapping=03313;
+  parser_e_final_only_const_var=03314;
+  parser_e_final_only_external=03315;
   type_e_mismatch=04000;
   type_e_mismatch=04000;
   type_e_incompatible_types=04001;
   type_e_incompatible_types=04001;
   type_e_not_equal_types=04002;
   type_e_not_equal_types=04002;
@@ -499,6 +501,7 @@ const
   type_e_class_helper_must_extend_subclass=04101;
   type_e_class_helper_must_extend_subclass=04101;
   type_e_record_helper_must_extend_same_record=04102;
   type_e_record_helper_must_extend_same_record=04102;
   type_e_java_class_method_not_static=04103;
   type_e_java_class_method_not_static=04103;
+  type_e_invalid_final_assignment=04104;
   sym_e_id_not_found=05000;
   sym_e_id_not_found=05000;
   sym_f_internal_error_in_symtablestack=05001;
   sym_f_internal_error_in_symtablestack=05001;
   sym_e_duplicate_id=05002;
   sym_e_duplicate_id=05002;
@@ -901,9 +904,9 @@ const
   option_info=11024;
   option_info=11024;
   option_help_pages=11025;
   option_help_pages=11025;
 
 
-  MsgTxtSize = 61050;
+  MsgTxtSize = 61281;
 
 
   MsgIdxMax : array[1..20] of longint=(
   MsgIdxMax : array[1..20] of longint=(
-    26,89,314,104,85,54,111,23,202,63,
+    26,89,316,105,85,54,111,23,202,63,
     49,20,1,1,1,1,1,1,1,1
     49,20,1,1,1,1,1,1,1,1
   );
   );

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 238 - 230
compiler/msgtxt.inc


+ 10 - 2
compiler/pdecl.pas

@@ -290,7 +290,11 @@ implementation
                 { generate an error }
                 { generate an error }
                 consume(_EQ);
                 consume(_EQ);
            end;
            end;
-         until (token<>_ID)or(in_structure and (idtoken in [_PRIVATE,_PROTECTED,_PUBLIC,_PUBLISHED,_STRICT]));
+         until (token<>_ID) or
+               (in_structure and
+                ((idtoken in [_PRIVATE,_PROTECTED,_PUBLIC,_PUBLISHED,_STRICT]) or
+                 ((m_final_fields in current_settings.modeswitches) and
+                  (idtoken=_FINAL))));
          block_type:=old_block_type;
          block_type:=old_block_type;
       end;
       end;
 
 
@@ -666,7 +670,11 @@ implementation
                hdef.typesym:=newtype;
                hdef.typesym:=newtype;
                generictypelist.free;
                generictypelist.free;
              end;
              end;
-         until (token<>_ID)or(in_structure and (idtoken in [_PRIVATE,_PROTECTED,_PUBLIC,_PUBLISHED,_STRICT]));
+         until (token<>_ID) or
+               (in_structure and
+                ((idtoken in [_PRIVATE,_PROTECTED,_PUBLIC,_PUBLISHED,_STRICT]) or
+                 ((m_final_fields in current_settings.modeswitches) and
+                  (idtoken=_FINAL))));
          { resolve type block forward declarations and restore a unit
          { resolve type block forward declarations and restore a unit
            container for them }
            container for them }
          resolve_forward_types;
          resolve_forward_types;

+ 118 - 79
compiler/pdecobj.pas

@@ -754,10 +754,81 @@ implementation
       var
       var
         pd : tprocdef;
         pd : tprocdef;
         has_destructor,
         has_destructor,
-        oldparse_only: boolean;
+        oldparse_only,
+        typedconstswritable: boolean;
         object_member_blocktype : tblock_type;
         object_member_blocktype : tblock_type;
-        fields_allowed, is_classdef, classfields: boolean;
+        fields_allowed, is_classdef, class_fields, is_final, final_fields: boolean;
         vdoptions: tvar_dec_options;
         vdoptions: tvar_dec_options;
+
+
+      procedure parse_const;
+        begin
+          if not(current_objectdef.objecttype in [odt_class,odt_object,odt_helper,odt_javaclass]) then
+            Message(parser_e_type_var_const_only_in_records_and_classes);
+          consume(_CONST);
+          object_member_blocktype:=bt_const;
+          final_fields:=is_final;
+          is_final:=false;
+        end;
+
+
+      procedure parse_var;
+        begin
+          if not(current_objectdef.objecttype in [odt_class,odt_object,odt_helper,odt_javaclass]) then
+            Message(parser_e_type_var_const_only_in_records_and_classes);
+          consume(_VAR);
+          fields_allowed:=true;
+          object_member_blocktype:=bt_general;
+          class_fields:=is_classdef;
+          final_fields:=is_final;
+          is_classdef:=false;
+          is_final:=false;
+        end;
+
+
+      procedure parse_class;
+        begin
+          is_classdef:=false;
+          { read class method/field/property }
+          consume(_CLASS);
+          { class modifier is only allowed for procedures, functions, }
+          { constructors, destructors, fields and properties          }
+          if not(token in [_FUNCTION,_PROCEDURE,_PROPERTY,_VAR,_CONSTRUCTOR,_DESTRUCTOR]) then
+            Message(parser_e_procedure_or_function_expected);
+
+          if is_interface(current_structdef) or
+             is_javainterface(current_structdef) then
+            Message(parser_e_no_static_method_in_interfaces)
+          else
+            { class methods are also allowed for Objective-C protocols }
+            is_classdef:=true;
+        end;
+
+
+      procedure parse_visibility(vis: tvisibility; oo: tobjectoption);
+        begin
+          { Objective-C and Java classes do not support "published",
+            as basically everything is published.  }
+          if (vis=vis_published) and
+             (is_objc_class_or_protocol(current_structdef) or
+              is_java_class_or_interface(current_structdef)) then
+             Message(parser_e_no_objc_published)
+          else if is_interface(current_structdef) or
+             is_objc_protocol_or_category(current_structdef) or
+             is_javainterface(current_structdef) then
+            Message(parser_e_no_access_specifier_in_interfaces);
+          current_structdef.symtable.currentvisibility:=vis;
+          consume(token);
+          if (oo<>oo_none) then
+            include(current_structdef.objectoptions,oo);
+          fields_allowed:=true;
+          is_classdef:=false;
+          class_fields:=false;
+          is_final:=false;
+          object_member_blocktype:=bt_general;
+        end;
+
+
       begin
       begin
         { empty class declaration ? }
         { empty class declaration ? }
         if (current_objectdef.objecttype in [odt_class,odt_objcclass,odt_javaclass]) and
         if (current_objectdef.objecttype in [odt_class,odt_objcclass,odt_javaclass]) and
@@ -772,7 +843,9 @@ implementation
         has_destructor:=false;
         has_destructor:=false;
         fields_allowed:=true;
         fields_allowed:=true;
         is_classdef:=false;
         is_classdef:=false;
-        classfields:=false;
+        class_fields:=false;
+        is_final:=false;
+        final_fields:=false;
         object_member_blocktype:=bt_general;
         object_member_blocktype:=bt_general;
         repeat
         repeat
           case token of
           case token of
@@ -785,20 +858,11 @@ implementation
               end;
               end;
             _VAR :
             _VAR :
               begin
               begin
-                if not(current_objectdef.objecttype in [odt_class,odt_object,odt_helper,odt_javaclass]) then
-                  Message(parser_e_type_var_const_only_in_records_and_classes);
-                consume(_VAR);
-                fields_allowed:=true;
-                object_member_blocktype:=bt_general;
-                classfields:=is_classdef;
-                is_classdef:=false;
+                parse_var;
               end;
               end;
             _CONST:
             _CONST:
               begin
               begin
-                if not(current_objectdef.objecttype in [odt_class,odt_object,odt_helper,odt_javaclass]) then
-                  Message(parser_e_type_var_const_only_in_records_and_classes);
-                consume(_CONST);
-                object_member_blocktype:=bt_const;
+                parse_const
               end;
               end;
             _ID :
             _ID :
               begin
               begin
@@ -812,63 +876,19 @@ implementation
                 else case idtoken of
                 else case idtoken of
                   _PRIVATE :
                   _PRIVATE :
                     begin
                     begin
-                      if is_interface(current_structdef) or
-                         is_objc_protocol_or_category(current_structdef) or
-                         is_javainterface(current_structdef) then
-                        Message(parser_e_no_access_specifier_in_interfaces);
-                       consume(_PRIVATE);
-                       current_structdef.symtable.currentvisibility:=vis_private;
-                       include(current_structdef.objectoptions,oo_has_private);
-                       fields_allowed:=true;
-                       is_classdef:=false;
-                       classfields:=false;
-                       object_member_blocktype:=bt_general;
+                      parse_visibility(vis_private,oo_has_private);
                      end;
                      end;
                    _PROTECTED :
                    _PROTECTED :
                      begin
                      begin
-                       if is_interface(current_structdef) or
-                          is_objc_protocol_or_category(current_structdef) or
-                          is_javainterface(current_structdef) then
-                         Message(parser_e_no_access_specifier_in_interfaces);
-                       consume(_PROTECTED);
-                       current_structdef.symtable.currentvisibility:=vis_protected;
-                       include(current_structdef.objectoptions,oo_has_protected);
-                       fields_allowed:=true;
-                       is_classdef:=false;
-                       classfields:=false;
-                       object_member_blocktype:=bt_general;
+                       parse_visibility(vis_protected,oo_has_protected);
                      end;
                      end;
                    _PUBLIC :
                    _PUBLIC :
                      begin
                      begin
-                       if is_interface(current_structdef) or
-                          is_objc_protocol_or_category(current_structdef) or
-                          is_javainterface(current_structdef) then
-                         Message(parser_e_no_access_specifier_in_interfaces);
-                       consume(_PUBLIC);
-                       current_structdef.symtable.currentvisibility:=vis_public;
-                       fields_allowed:=true;
-                       is_classdef:=false;
-                       classfields:=false;
-                       object_member_blocktype:=bt_general;
+                       parse_visibility(vis_public,oo_none);
                      end;
                      end;
                    _PUBLISHED :
                    _PUBLISHED :
                      begin
                      begin
-                       { we've to check for a pushlished section in non-  }
-                       { publishable classes later, if a real declaration }
-                       { this is the way, delphi does it                  }
-                       if is_interface(current_structdef) then
-                         Message(parser_e_no_access_specifier_in_interfaces);
-                       { Objective-C and Java classes do not support "published",
-                         as basically everything is published.  }
-                       if is_objc_class_or_protocol(current_structdef) or
-                          is_java_class_or_interface(current_structdef) then
-                         Message(parser_e_no_objc_published);
-                       consume(_PUBLISHED);
-                       current_structdef.symtable.currentvisibility:=vis_published;
-                       fields_allowed:=true;
-                       is_classdef:=false;
-                       classfields:=false;
-                       object_member_blocktype:=bt_general;
+                       parse_visibility(vis_published,oo_none);
                      end;
                      end;
                    _STRICT :
                    _STRICT :
                      begin
                      begin
@@ -900,9 +920,27 @@ implementation
                           message(parser_e_protected_or_private_expected);
                           message(parser_e_protected_or_private_expected);
                         fields_allowed:=true;
                         fields_allowed:=true;
                         is_classdef:=false;
                         is_classdef:=false;
-                        classfields:=false;
+                        class_fields:=false;
+                        is_final:=false;
+                        final_fields:=false;
                         object_member_blocktype:=bt_general;
                         object_member_blocktype:=bt_general;
                      end
                      end
+                    else if (m_final_fields in current_settings.modeswitches) and
+                            (token=_ID) and
+                            (idtoken=_FINAL) then
+                      begin
+                        { currently only supported for external classes, because
+                          requires fully working DFA otherwise }
+                        if (current_structdef.typ<>objectdef) or
+                           not(oo_is_external in tobjectdef(current_structdef).objectoptions) then
+                          Message(parser_e_final_only_external);
+                        consume(_final);
+                        is_final:=true;
+                        if token=_CLASS then
+                          parse_class;
+                        if not(token in [_CONST,_VAR]) then
+                          message(parser_e_final_only_const_var);
+                      end
                     else
                     else
                       begin
                       begin
                         if object_member_blocktype=bt_general then
                         if object_member_blocktype=bt_general then
@@ -920,14 +958,28 @@ implementation
                               Message(parser_e_field_not_allowed_here);
                               Message(parser_e_field_not_allowed_here);
 
 
                             vdoptions:=[vd_object];
                             vdoptions:=[vd_object];
-                            if classfields then
+                            if class_fields then
                               include(vdoptions,vd_class);
                               include(vdoptions,vd_class);
+                            if final_fields then
+                              include(vdoptions,vd_final);
                             read_record_fields(vdoptions);
                             read_record_fields(vdoptions);
                           end
                           end
                         else if object_member_blocktype=bt_type then
                         else if object_member_blocktype=bt_type then
                           types_dec(true)
                           types_dec(true)
                         else if object_member_blocktype=bt_const then
                         else if object_member_blocktype=bt_const then
-                          consts_dec(true)
+                          begin
+                            if final_fields then
+                              begin
+                                { the value of final fields cannot be changed
+                                  once they've been assigned a value }
+                                typedconstswritable:=cs_typed_const_writable in current_settings.localswitches;
+                                exclude(current_settings.localswitches,cs_typed_const_writable);
+                              end;
+                            consts_dec(true);
+                            if final_fields and
+                               typedconstswritable then
+                              include(current_settings.localswitches,cs_typed_const_writable);
+                          end
                         else
                         else
                           internalerror(201001110);
                           internalerror(201001110);
                       end;
                       end;
@@ -941,20 +993,7 @@ implementation
               end;
               end;
             _CLASS:
             _CLASS:
               begin
               begin
-                is_classdef:=false;
-                { read class method/field/property }
-                consume(_CLASS);
-                { class modifier is only allowed for procedures, functions, }
-                { constructors, destructors, fields and properties          }
-                if not(token in [_FUNCTION,_PROCEDURE,_PROPERTY,_VAR,_CONSTRUCTOR,_DESTRUCTOR]) then
-                  Message(parser_e_procedure_or_function_expected);
-
-                if is_interface(current_structdef) or
-                   is_javainterface(current_structdef) then
-                  Message(parser_e_no_static_method_in_interfaces)
-                else
-                  { class methods are also allowed for Objective-C protocols }
-                  is_classdef:=true;
+                parse_class;
               end;
               end;
             _PROCEDURE,
             _PROCEDURE,
             _FUNCTION:
             _FUNCTION:

+ 18 - 5
compiler/pdecvar.pas

@@ -30,7 +30,7 @@ interface
       symsym,symdef;
       symsym,symdef;
 
 
     type
     type
-      tvar_dec_option=(vd_record,vd_object,vd_threadvar,vd_class);
+      tvar_dec_option=(vd_record,vd_object,vd_threadvar,vd_class,vd_final);
       tvar_dec_options=set of tvar_dec_option;
       tvar_dec_options=set of tvar_dec_option;
 
 
     function  read_property_dec(is_classproperty:boolean;astruct:tabstractrecorddef):tpropertysym;
     function  read_property_dec(is_classproperty:boolean;astruct:tabstractrecorddef):tpropertysym;
@@ -925,7 +925,7 @@ implementation
       { only allowed for one var }
       { only allowed for one var }
       vs:=tabstractvarsym(sc[0]);
       vs:=tabstractvarsym(sc[0]);
       if sc.count>1 then
       if sc.count>1 then
-        Message(parser_e_absolute_only_one_var);
+        Message1(parser_e_directive_only_one_var,arraytokeninfo[idtoken].str);
       read_public_and_external(vs);
       read_public_and_external(vs);
     end;
     end;
 
 
@@ -1127,7 +1127,7 @@ implementation
           C_Name:=get_stringconst;
           C_Name:=get_stringconst;
           vs:=tabstractnormalvarsym(sc[0]);
           vs:=tabstractnormalvarsym(sc[0]);
           if sc.count>1 then
           if sc.count>1 then
-            Message(parser_e_absolute_only_one_var);
+            Message(parser_e_directive_only_one_var,'ABSOLUTE');
           if vs.typ=staticvarsym then
           if vs.typ=staticvarsym then
             begin
             begin
               tstaticvarsym(vs).set_mangledname(C_Name);
               tstaticvarsym(vs).set_mangledname(C_Name);
@@ -1152,7 +1152,7 @@ implementation
           { only allowed for one var }
           { only allowed for one var }
           vs:=tabstractvarsym(sc[0]);
           vs:=tabstractvarsym(sc[0]);
           if sc.count>1 then
           if sc.count>1 then
-            Message(parser_e_absolute_only_one_var);
+            Message1(parser_e_directive_only_one_var,'ABSOLUTE');
           if vo_is_typed_const in vs.varoptions then
           if vo_is_typed_const in vs.varoptions then
             Message(parser_e_initialized_not_for_external);
             Message(parser_e_initialized_not_for_external);
           { parse the rest }
           { parse the rest }
@@ -1525,7 +1525,9 @@ implementation
          while (token=_ID) and
          while (token=_ID) and
             not(((vd_object in options) or
             not(((vd_object in options) or
                  ((vd_record in options) and (m_advanced_records in current_settings.modeswitches))) and
                  ((vd_record in options) and (m_advanced_records in current_settings.modeswitches))) and
-                (idtoken in [_PUBLIC,_PRIVATE,_PUBLISHED,_PROTECTED,_STRICT])) do
+                ((idtoken in [_PUBLIC,_PRIVATE,_PUBLISHED,_PROTECTED,_STRICT]) or
+                 ((m_final_fields in current_settings.modeswitches) and
+                  (idtoken=_FINAL)))) do
            begin
            begin
              visibility:=symtablestack.top.currentvisibility;
              visibility:=symtablestack.top.currentvisibility;
              semicoloneaten:=false;
              semicoloneaten:=false;
@@ -1688,12 +1690,23 @@ implementation
                      fieldvs.Rename(internal_static_field_name(fieldvs.name));
                      fieldvs.Rename(internal_static_field_name(fieldvs.name));
                      recst.insert(hstaticvs);
                      recst.insert(hstaticvs);
 {$endif not jvm}
 {$endif not jvm}
+                     if vd_final in options then
+                       hstaticvs.varspez:=vs_final;
                      { generate the symbol for the access }
                      { generate the symbol for the access }
                      sl:=tpropaccesslist.create;
                      sl:=tpropaccesslist.create;
                      sl.addsym(sl_load,hstaticvs);
                      sl.addsym(sl_load,hstaticvs);
                      recst.insert(tabsolutevarsym.create_ref('$'+static_name,hdef,sl));
                      recst.insert(tabsolutevarsym.create_ref('$'+static_name,hdef,sl));
                    end;
                    end;
                end;
                end;
+             if vd_final in options then
+               begin
+                 { add final flag }
+                 for i:=0 to sc.count-1 do
+                   begin
+                     fieldvs:=tfieldvarsym(sc[i]);
+                     fieldvs.varspez:=vs_final;
+                   end;
+               end;
              if (visibility=vis_published) and
              if (visibility=vis_published) and
                 not(is_class(hdef)) then
                 not(is_class(hdef)) then
                begin
                begin

+ 5 - 0
compiler/scanner.pas

@@ -356,6 +356,11 @@ implementation
         else
         else
          b:=false;
          b:=false;
 
 
+{$ifdef jvm}
+          { enable final fields by default for the JVM targets }
+          include(current_settings.modeswitches,m_final_fields);
+{$endif jvm}
+
         if b and changeInit then
         if b and changeInit then
           init_settings.modeswitches := current_settings.modeswitches;
           init_settings.modeswitches := current_settings.modeswitches;
 
 

+ 1 - 1
compiler/symconst.pas

@@ -517,7 +517,7 @@ type
     vs_referred_not_inited,vs_written,vs_readwritten
     vs_referred_not_inited,vs_written,vs_readwritten
   );
   );
 
 
-  tvarspez = (vs_value,vs_const,vs_var,vs_out,vs_constref);
+  tvarspez = (vs_value,vs_const,vs_var,vs_out,vs_constref,vs_final);
 
 
   absolutetyp = (tovar,toasm,toaddr);
   absolutetyp = (tovar,toasm,toaddr);
 
 

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio