mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 06:19:37 +01:00 
			
		
		
		
	compiler:
- implement class properties: properties which can access only static fields and static class methods - tests - fix a possibility to call an instance method from the class method git-svn-id: trunk@14585 -
This commit is contained in:
		
							parent
							
								
									5d87461507
								
							
						
					
					
						commit
						3ed4c58502
					
				
							
								
								
									
										3
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							@ -9222,6 +9222,9 @@ tests/test/tset7.pp svneol=native#text/plain
 | 
			
		||||
tests/test/tsetsize.pp svneol=native#text/plain
 | 
			
		||||
tests/test/tstack.pp svneol=native#text/plain
 | 
			
		||||
tests/test/tstatic1.pp svneol=native#text/pascal
 | 
			
		||||
tests/test/tstatic2.pp svneol=native#text/pascal
 | 
			
		||||
tests/test/tstatic3.pp svneol=native#text/pascal
 | 
			
		||||
tests/test/tstatic4.pp svneol=native#text/pascal
 | 
			
		||||
tests/test/tstprocv.pp svneol=native#text/plain
 | 
			
		||||
tests/test/tstring1.pp svneol=native#text/plain
 | 
			
		||||
tests/test/tstring10.pp svneol=native#text/plain
 | 
			
		||||
 | 
			
		||||
@ -366,7 +366,7 @@ scan_w_multiple_main_name_overrides=02086_W_Overriding name of "main" procedure
 | 
			
		||||
#
 | 
			
		||||
# Parser
 | 
			
		||||
#
 | 
			
		||||
# 03282 is the last used one
 | 
			
		||||
# 03284 is the last used one
 | 
			
		||||
#
 | 
			
		||||
% \section{Parser messages}
 | 
			
		||||
% This section lists all parser messages. The parser takes care of the
 | 
			
		||||
@ -514,7 +514,7 @@ parser_e_fail_only_in_constructor=03051_E_FAIL can be used in constructors only
 | 
			
		||||
parser_e_no_paras_for_destructor=03052_E_Destructors can't have parameters
 | 
			
		||||
% You are declaring a destructor with a parameter list. Destructor methods
 | 
			
		||||
% cannot have parameters.
 | 
			
		||||
parser_e_only_class_methods_via_class_ref=03053_E_Only class methods can be referred with class references
 | 
			
		||||
parser_e_only_class_members_via_class_ref=03053_E_Only class methods, class properties and class variables can be referred with class references
 | 
			
		||||
% This error occurs in a situation like the following:
 | 
			
		||||
% \begin{verbatim}
 | 
			
		||||
% Type :
 | 
			
		||||
@ -528,7 +528,7 @@ parser_e_only_class_methods_via_class_ref=03053_E_Only class methods can be refe
 | 
			
		||||
% \end{verbatim}
 | 
			
		||||
% \var{Free} is not a class method and hence cannot be called with a class
 | 
			
		||||
% reference.
 | 
			
		||||
parser_e_only_class_methods=03054_E_Only class methods can be accessed in class methods
 | 
			
		||||
parser_e_only_class_members=03054_E_Only class class methods, class properties and class variables can be accessed in class methods
 | 
			
		||||
% This is related to the previous error. You cannot call a method of an object
 | 
			
		||||
% from inside a class method. The following code would produce this error:
 | 
			
		||||
% \begin{verbatim}
 | 
			
		||||
 | 
			
		||||
@ -151,8 +151,8 @@ const
 | 
			
		||||
  parser_e_error_in_real=03050;
 | 
			
		||||
  parser_e_fail_only_in_constructor=03051;
 | 
			
		||||
  parser_e_no_paras_for_destructor=03052;
 | 
			
		||||
  parser_e_only_class_methods_via_class_ref=03053;
 | 
			
		||||
  parser_e_only_class_methods=03054;
 | 
			
		||||
  parser_e_only_class_members_via_class_ref=03053;
 | 
			
		||||
  parser_e_only_class_members=03054;
 | 
			
		||||
  parser_e_case_mismatch=03055;
 | 
			
		||||
  parser_e_illegal_symbol_exported=03056;
 | 
			
		||||
  parser_w_should_use_override=03057;
 | 
			
		||||
@ -840,7 +840,7 @@ const
 | 
			
		||||
  option_info=11024;
 | 
			
		||||
  option_help_pages=11025;
 | 
			
		||||
 | 
			
		||||
  MsgTxtSize = 55145;
 | 
			
		||||
  MsgTxtSize = 55227;
 | 
			
		||||
 | 
			
		||||
  MsgIdxMax : array[1..20] of longint=(
 | 
			
		||||
    24,87,285,95,71,51,110,22,202,63,
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -2771,6 +2771,14 @@ implementation
 | 
			
		||||
                while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn]) do
 | 
			
		||||
                  hpt:=tunarynode(hpt).left;
 | 
			
		||||
 | 
			
		||||
                if ((hpt.nodetype=loadvmtaddrn) or
 | 
			
		||||
                   ((hpt.nodetype=loadn) and assigned(tloadnode(hpt).resultdef) and (tloadnode(hpt).resultdef.typ=classrefdef))) and
 | 
			
		||||
                   not (procdefinition.proctypeoption=potype_constructor) and
 | 
			
		||||
                   not (po_classmethod in procdefinition.procoptions) and
 | 
			
		||||
                   not (po_staticmethod in procdefinition.procoptions) then
 | 
			
		||||
                  { error: we are calling instance method from the class method/static method }
 | 
			
		||||
                  CGMessage(parser_e_only_class_members);
 | 
			
		||||
 | 
			
		||||
               if (procdefinition.proctypeoption=potype_constructor) and
 | 
			
		||||
                  assigned(symtableproc) and
 | 
			
		||||
                  (symtableproc.symtabletype=withsymtable) and
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ interface
 | 
			
		||||
    procedure types_dec;
 | 
			
		||||
    procedure var_dec;
 | 
			
		||||
    procedure threadvar_dec;
 | 
			
		||||
    procedure property_dec;
 | 
			
		||||
    procedure property_dec(is_classpropery: boolean);
 | 
			
		||||
    procedure resourcestring_dec;
 | 
			
		||||
 | 
			
		||||
implementation
 | 
			
		||||
@ -642,7 +642,7 @@ implementation
 | 
			
		||||
      end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    procedure property_dec;
 | 
			
		||||
    procedure property_dec(is_classpropery: boolean);
 | 
			
		||||
      var
 | 
			
		||||
         old_block_type : tblock_type;
 | 
			
		||||
      begin
 | 
			
		||||
@ -652,7 +652,7 @@ implementation
 | 
			
		||||
         old_block_type:=block_type;
 | 
			
		||||
         block_type:=bt_const;
 | 
			
		||||
         repeat
 | 
			
		||||
           read_property_dec(nil);
 | 
			
		||||
           read_property_dec(is_classpropery, nil);
 | 
			
		||||
           consume(_SEMICOLON);
 | 
			
		||||
         until token<>_ID;
 | 
			
		||||
         block_type:=old_block_type;
 | 
			
		||||
 | 
			
		||||
@ -82,7 +82,7 @@ implementation
 | 
			
		||||
      end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    procedure property_dec;
 | 
			
		||||
    procedure property_dec(is_classproperty:boolean);
 | 
			
		||||
      var
 | 
			
		||||
        p : tpropertysym;
 | 
			
		||||
      begin
 | 
			
		||||
@ -91,7 +91,7 @@ implementation
 | 
			
		||||
           (not(m_tp7 in current_settings.modeswitches) and (is_object(current_objectdef)))) then
 | 
			
		||||
          Message(parser_e_syntax_error);
 | 
			
		||||
        consume(_PROPERTY);
 | 
			
		||||
        p:=read_property_dec(current_objectdef);
 | 
			
		||||
        p:=read_property_dec(is_classproperty, current_objectdef);
 | 
			
		||||
        consume(_SEMICOLON);
 | 
			
		||||
        if try_to_consume(_DEFAULT) then
 | 
			
		||||
          begin
 | 
			
		||||
@ -526,7 +526,7 @@ implementation
 | 
			
		||||
        oldparse_only,
 | 
			
		||||
        old_parse_generic : boolean;
 | 
			
		||||
        object_member_blocktype : tblock_type;
 | 
			
		||||
        fields_allowed: boolean;
 | 
			
		||||
        fields_allowed, is_classdef: boolean;
 | 
			
		||||
      begin
 | 
			
		||||
        { empty class declaration ? }
 | 
			
		||||
        if (current_objectdef.objecttype in [odt_class,odt_objcclass]) and
 | 
			
		||||
@ -544,6 +544,7 @@ implementation
 | 
			
		||||
        testcurobject:=1;
 | 
			
		||||
        has_destructor:=false;
 | 
			
		||||
        fields_allowed:=true;
 | 
			
		||||
        is_classdef:=false;
 | 
			
		||||
        object_member_blocktype:=bt_general;
 | 
			
		||||
        repeat
 | 
			
		||||
          case token of
 | 
			
		||||
@ -667,12 +668,29 @@ implementation
 | 
			
		||||
              end;
 | 
			
		||||
            _PROPERTY :
 | 
			
		||||
              begin
 | 
			
		||||
                property_dec;
 | 
			
		||||
                property_dec(is_classdef);
 | 
			
		||||
                fields_allowed:=false;
 | 
			
		||||
                is_classdef:=false;
 | 
			
		||||
              end;
 | 
			
		||||
            _CLASS:
 | 
			
		||||
              begin
 | 
			
		||||
                is_classdef:=false;
 | 
			
		||||
                { read class method }
 | 
			
		||||
                if try_to_consume(_CLASS) then
 | 
			
		||||
                 begin
 | 
			
		||||
                   { class method only allowed for procedures and functions }
 | 
			
		||||
                   if not(token in [_FUNCTION,_PROCEDURE,_PROPERTY]) then
 | 
			
		||||
                     Message(parser_e_procedure_or_function_expected);
 | 
			
		||||
 | 
			
		||||
                   if is_interface(current_objectdef) then
 | 
			
		||||
                     Message(parser_e_no_static_method_in_interfaces)
 | 
			
		||||
                   else
 | 
			
		||||
                     { class methods are also allowed for Objective-C protocols }
 | 
			
		||||
                     is_classdef:=true;
 | 
			
		||||
                 end;
 | 
			
		||||
              end;
 | 
			
		||||
            _PROCEDURE,
 | 
			
		||||
            _FUNCTION,
 | 
			
		||||
            _CLASS :
 | 
			
		||||
            _FUNCTION:
 | 
			
		||||
              begin
 | 
			
		||||
                if (current_objectdef.symtable.currentvisibility=vis_published) and
 | 
			
		||||
                   not(oo_can_have_published in current_objectdef.objectoptions) then
 | 
			
		||||
@ -680,7 +698,7 @@ implementation
 | 
			
		||||
 | 
			
		||||
                oldparse_only:=parse_only;
 | 
			
		||||
                parse_only:=true;
 | 
			
		||||
                pd:=parse_proc_dec(current_objectdef);
 | 
			
		||||
                pd:=parse_proc_dec(is_classdef, current_objectdef);
 | 
			
		||||
 | 
			
		||||
                { this is for error recovery as well as forward }
 | 
			
		||||
                { interface mappings, i.e. mapping to a method  }
 | 
			
		||||
@ -716,6 +734,7 @@ implementation
 | 
			
		||||
 | 
			
		||||
                parse_only:=oldparse_only;
 | 
			
		||||
                fields_allowed:=false;
 | 
			
		||||
                is_classdef:=false;
 | 
			
		||||
              end;
 | 
			
		||||
            _CONSTRUCTOR :
 | 
			
		||||
              begin
 | 
			
		||||
 | 
			
		||||
@ -60,7 +60,7 @@ interface
 | 
			
		||||
    procedure parse_var_proc_directives(sym:tsym);
 | 
			
		||||
    procedure parse_object_proc_directives(pd:tabstractprocdef);
 | 
			
		||||
    function  parse_proc_head(aclass:tobjectdef;potype:tproctypeoption;var pd:tprocdef):boolean;
 | 
			
		||||
    function  parse_proc_dec(aclass:tobjectdef):tprocdef;
 | 
			
		||||
    function  parse_proc_dec(isclassmethod:boolean; aclass:tobjectdef):tprocdef;
 | 
			
		||||
 | 
			
		||||
implementation
 | 
			
		||||
 | 
			
		||||
@ -948,30 +948,15 @@ implementation
 | 
			
		||||
      end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    function parse_proc_dec(aclass:tobjectdef):tprocdef;
 | 
			
		||||
    function parse_proc_dec(isclassmethod:boolean; aclass:tobjectdef):tprocdef;
 | 
			
		||||
      var
 | 
			
		||||
        pd : tprocdef;
 | 
			
		||||
        isclassmethod : boolean;
 | 
			
		||||
        locationstr: string;
 | 
			
		||||
        old_parse_generic,
 | 
			
		||||
        popclass           : boolean;
 | 
			
		||||
      begin
 | 
			
		||||
        locationstr:='';
 | 
			
		||||
        pd:=nil;
 | 
			
		||||
        isclassmethod:=false;
 | 
			
		||||
        { read class method }
 | 
			
		||||
        if try_to_consume(_CLASS) then
 | 
			
		||||
         begin
 | 
			
		||||
           { class method only allowed for procedures and functions }
 | 
			
		||||
           if not(token in [_FUNCTION,_PROCEDURE]) then
 | 
			
		||||
             Message(parser_e_procedure_or_function_expected);
 | 
			
		||||
 | 
			
		||||
           if is_interface(aclass) then
 | 
			
		||||
             Message(parser_e_no_static_method_in_interfaces)
 | 
			
		||||
           else
 | 
			
		||||
             { class methods are also allowed for Objective-C protocols }
 | 
			
		||||
             isclassmethod:=true;
 | 
			
		||||
         end;
 | 
			
		||||
        case token of
 | 
			
		||||
          _FUNCTION :
 | 
			
		||||
            begin
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ interface
 | 
			
		||||
      tvar_dec_option=(vd_record,vd_object,vd_threadvar);
 | 
			
		||||
      tvar_dec_options=set of tvar_dec_option;
 | 
			
		||||
 | 
			
		||||
    function  read_property_dec(aclass:tobjectdef):tpropertysym;
 | 
			
		||||
    function  read_property_dec(is_classproperty:boolean; aclass:tobjectdef):tpropertysym;
 | 
			
		||||
 | 
			
		||||
    procedure read_var_decls(options:Tvar_dec_options);
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ implementation
 | 
			
		||||
       ;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    function read_property_dec(aclass:tobjectdef):tpropertysym;
 | 
			
		||||
    function read_property_dec(is_classproperty:boolean; aclass:tobjectdef):tpropertysym;
 | 
			
		||||
 | 
			
		||||
        { convert a node tree to symlist and return the last
 | 
			
		||||
          symbol }
 | 
			
		||||
@ -269,8 +269,8 @@ implementation
 | 
			
		||||
         writeprocdef:=tprocvardef.create(normal_function_level);
 | 
			
		||||
         storedprocdef:=tprocvardef.create(normal_function_level);
 | 
			
		||||
 | 
			
		||||
         { make it method pointers }
 | 
			
		||||
         if assigned(aclass) then
 | 
			
		||||
         { make them method pointers }
 | 
			
		||||
         if assigned(aclass) and not is_classproperty then
 | 
			
		||||
           begin
 | 
			
		||||
             include(readprocdef.procoptions,po_methodpointer);
 | 
			
		||||
             include(writeprocdef.procoptions,po_methodpointer);
 | 
			
		||||
@ -290,6 +290,8 @@ implementation
 | 
			
		||||
         p:=tpropertysym.create(orgpattern);
 | 
			
		||||
         p.visibility:=symtablestack.top.currentvisibility;
 | 
			
		||||
         p.default:=longint($80000000);
 | 
			
		||||
         if is_classproperty then
 | 
			
		||||
           include(p.symoptions, sp_static);
 | 
			
		||||
         symtablestack.top.insert(p);
 | 
			
		||||
         consume(_ID);
 | 
			
		||||
         { property parameters ? }
 | 
			
		||||
@ -461,8 +463,9 @@ implementation
 | 
			
		||||
                               the parameter.
 | 
			
		||||
                               Note: In the help of Kylix it is written
 | 
			
		||||
                               that it isn't allowed, but the compiler accepts it (PFV) }
 | 
			
		||||
                             if (ppo_hasparameters in p.propoptions) then
 | 
			
		||||
                              Message(parser_e_ill_property_access_sym);
 | 
			
		||||
                             if (ppo_hasparameters in p.propoptions) or
 | 
			
		||||
                                ((sp_static in p.symoptions) <> (sp_static in sym.symoptions)) then
 | 
			
		||||
                               Message(parser_e_ill_property_access_sym);
 | 
			
		||||
                           end
 | 
			
		||||
                          else
 | 
			
		||||
                           IncompatibleTypes(def,p.propdef);
 | 
			
		||||
@ -505,7 +508,8 @@ implementation
 | 
			
		||||
                               the parameter.
 | 
			
		||||
                               Note: In the help of Kylix it is written
 | 
			
		||||
                               that it isn't allowed, but the compiler accepts it (PFV) }
 | 
			
		||||
                             if (ppo_hasparameters in p.propoptions) then
 | 
			
		||||
                             if (ppo_hasparameters in p.propoptions) or
 | 
			
		||||
                                ((sp_static in p.symoptions) <> (sp_static in sym.symoptions)) then
 | 
			
		||||
                              Message(parser_e_ill_property_access_sym);
 | 
			
		||||
                           end
 | 
			
		||||
                          else
 | 
			
		||||
@ -536,7 +540,7 @@ implementation
 | 
			
		||||
               end;
 | 
			
		||||
           end;
 | 
			
		||||
 | 
			
		||||
         if assigned(aclass) and not(is_dispinterface(aclass)) then
 | 
			
		||||
         if assigned(aclass) and not(is_dispinterface(aclass)) and not is_classproperty then
 | 
			
		||||
           begin
 | 
			
		||||
             { ppo_stored is default on for not overriden properties }
 | 
			
		||||
             if not assigned(p.overridenpropsym) then
 | 
			
		||||
 | 
			
		||||
@ -1028,6 +1028,9 @@ implementation
 | 
			
		||||
         membercall : boolean;
 | 
			
		||||
         callflags  : tcallnodeflags;
 | 
			
		||||
         propaccesslist : tpropaccesslist;
 | 
			
		||||
         static_name : shortstring;
 | 
			
		||||
         sym: tsym;
 | 
			
		||||
         srsymtable : tsymtable;
 | 
			
		||||
      begin
 | 
			
		||||
         { property parameters? read them only if the property really }
 | 
			
		||||
         { has parameters                                             }
 | 
			
		||||
@ -1052,7 +1055,8 @@ implementation
 | 
			
		||||
           begin
 | 
			
		||||
              if getpropaccesslist(propsym,palt_write,propaccesslist) then
 | 
			
		||||
                begin
 | 
			
		||||
                   case propaccesslist.firstsym^.sym.typ of
 | 
			
		||||
                   sym:=propaccesslist.firstsym^.sym;
 | 
			
		||||
                   case sym.typ of
 | 
			
		||||
                     procsym :
 | 
			
		||||
                       begin
 | 
			
		||||
                         callflags:=[];
 | 
			
		||||
@ -1060,8 +1064,8 @@ implementation
 | 
			
		||||
                         membercall:=maybe_load_methodpointer(st,p1);
 | 
			
		||||
                         if membercall then
 | 
			
		||||
                           include(callflags,cnf_member_call);
 | 
			
		||||
                         p1:=ccallnode.create(paras,tprocsym(propaccesslist.firstsym^.sym),st,p1,callflags);
 | 
			
		||||
                         addsymref(propaccesslist.firstsym^.sym);
 | 
			
		||||
                         p1:=ccallnode.create(paras,tprocsym(sym),st,p1,callflags);
 | 
			
		||||
                         addsymref(sym);
 | 
			
		||||
                         paras:=nil;
 | 
			
		||||
                         consume(_ASSIGNMENT);
 | 
			
		||||
                         { read the expression }
 | 
			
		||||
@ -1078,7 +1082,19 @@ implementation
 | 
			
		||||
                     fieldvarsym :
 | 
			
		||||
                       begin
 | 
			
		||||
                         { generate access code }
 | 
			
		||||
                         propaccesslist_to_node(p1,st,propaccesslist);
 | 
			
		||||
                         if (sp_static in sym.symoptions) then
 | 
			
		||||
                           begin
 | 
			
		||||
                             static_name:=lower(sym.owner.name^)+'_'+sym.name;
 | 
			
		||||
                             searchsym_in_class(tobjectdef(sym.owner.defowner),tobjectdef(sym.owner.defowner),static_name,sym,srsymtable);
 | 
			
		||||
                             if assigned(sym) then
 | 
			
		||||
                               check_hints(sym,sym.symoptions,sym.deprecatedmsg);
 | 
			
		||||
                             p1.free;
 | 
			
		||||
                             p1:=nil;
 | 
			
		||||
                             { static syms are always stored as absolutevarsym to handle scope and storage properly }
 | 
			
		||||
                             propaccesslist_to_node(p1,nil,tabsolutevarsym(sym).ref);
 | 
			
		||||
                           end
 | 
			
		||||
                         else
 | 
			
		||||
                           propaccesslist_to_node(p1,st,propaccesslist);
 | 
			
		||||
                         include(p1.flags,nf_isproperty);
 | 
			
		||||
                         consume(_ASSIGNMENT);
 | 
			
		||||
                         { read the expression }
 | 
			
		||||
@ -1102,12 +1118,25 @@ implementation
 | 
			
		||||
           begin
 | 
			
		||||
              if getpropaccesslist(propsym,palt_read,propaccesslist) then
 | 
			
		||||
                begin
 | 
			
		||||
                   case propaccesslist.firstsym^.sym.typ of
 | 
			
		||||
                   sym := propaccesslist.firstsym^.sym;
 | 
			
		||||
                   case sym.typ of
 | 
			
		||||
                     fieldvarsym :
 | 
			
		||||
                       begin
 | 
			
		||||
                          { generate access code }
 | 
			
		||||
                          propaccesslist_to_node(p1,st,propaccesslist);
 | 
			
		||||
                          include(p1.flags,nf_isproperty);
 | 
			
		||||
                         { generate access code }
 | 
			
		||||
                         if (sp_static in sym.symoptions) then
 | 
			
		||||
                           begin
 | 
			
		||||
                             static_name:=lower(sym.owner.name^)+'_'+sym.name;
 | 
			
		||||
                             searchsym_in_class(tobjectdef(sym.owner.defowner),tobjectdef(sym.owner.defowner),static_name,sym,srsymtable);
 | 
			
		||||
                             if assigned(sym) then
 | 
			
		||||
                               check_hints(sym,sym.symoptions,sym.deprecatedmsg);
 | 
			
		||||
                             p1.free;
 | 
			
		||||
                             p1:=nil;
 | 
			
		||||
                             { static syms are always stored as absolutevarsym to handle scope and storage properly }
 | 
			
		||||
                             propaccesslist_to_node(p1,nil,tabsolutevarsym(sym).ref);
 | 
			
		||||
                           end
 | 
			
		||||
                         else
 | 
			
		||||
                           propaccesslist_to_node(p1,st,propaccesslist);
 | 
			
		||||
                         include(p1.flags,nf_isproperty);
 | 
			
		||||
                       end;
 | 
			
		||||
                     procsym :
 | 
			
		||||
                       begin
 | 
			
		||||
@ -1116,7 +1145,7 @@ implementation
 | 
			
		||||
                          membercall:=maybe_load_methodpointer(st,p1);
 | 
			
		||||
                          if membercall then
 | 
			
		||||
                            include(callflags,cnf_member_call);
 | 
			
		||||
                          p1:=ccallnode.create(paras,tprocsym(propaccesslist.firstsym^.sym),st,p1,callflags);
 | 
			
		||||
                          p1:=ccallnode.create(paras,tprocsym(sym),st,p1,callflags);
 | 
			
		||||
                          paras:=nil;
 | 
			
		||||
                          include(p1.flags,nf_isproperty);
 | 
			
		||||
                       end
 | 
			
		||||
@ -1184,7 +1213,7 @@ implementation
 | 
			
		||||
                         assigned(tcallnode(p1).procdefinition) and
 | 
			
		||||
                         not(po_classmethod in tcallnode(p1).procdefinition.procoptions) and
 | 
			
		||||
                         not(tcallnode(p1).procdefinition.proctypeoption=potype_constructor) then
 | 
			
		||||
                        Message(parser_e_only_class_methods_via_class_ref);
 | 
			
		||||
                        Message(parser_e_only_class_members_via_class_ref);
 | 
			
		||||
                   end;
 | 
			
		||||
                 fieldvarsym:
 | 
			
		||||
                   begin
 | 
			
		||||
@ -1203,17 +1232,20 @@ implementation
 | 
			
		||||
                        begin
 | 
			
		||||
                          if isclassref then
 | 
			
		||||
                            if assigned(p1) and
 | 
			
		||||
                               is_self_node(p1) then
 | 
			
		||||
                              Message(parser_e_only_class_methods)
 | 
			
		||||
                              (
 | 
			
		||||
                                is_self_node(p1) or
 | 
			
		||||
                                (assigned(current_procinfo) and ([po_staticmethod,po_classmethod] <= current_procinfo.procdef.procoptions) and
 | 
			
		||||
                                 (current_procinfo.procdef._class = classh))) then
 | 
			
		||||
                              Message(parser_e_only_class_members)
 | 
			
		||||
                            else
 | 
			
		||||
                              Message(parser_e_only_class_methods_via_class_ref);
 | 
			
		||||
                              Message(parser_e_only_class_members_via_class_ref);
 | 
			
		||||
                          p1:=csubscriptnode.create(sym,p1);
 | 
			
		||||
                        end;
 | 
			
		||||
                   end;
 | 
			
		||||
                 propertysym:
 | 
			
		||||
                   begin
 | 
			
		||||
                      if isclassref then
 | 
			
		||||
                        Message(parser_e_only_class_methods_via_class_ref);
 | 
			
		||||
                      if isclassref and not (sp_static in sym.symoptions) then
 | 
			
		||||
                        Message(parser_e_only_class_members_via_class_ref);
 | 
			
		||||
                      handle_propertysym(tpropertysym(sym),sym.owner,p1);
 | 
			
		||||
                   end;
 | 
			
		||||
                 typesym:
 | 
			
		||||
@ -1595,7 +1627,11 @@ implementation
 | 
			
		||||
                    if is_member_read(srsym,srsymtable,p1,hdef) then
 | 
			
		||||
                      begin
 | 
			
		||||
                        if (srsymtable.symtabletype=ObjectSymtable) then
 | 
			
		||||
                          p1:=load_self_node;
 | 
			
		||||
                           if (assigned(current_procinfo) and ([po_staticmethod,po_classmethod] <= current_procinfo.procdef.procoptions)) then
 | 
			
		||||
                          { no self node in static class methods }
 | 
			
		||||
                            p1:=cloadvmtaddrnode.create(ctypenode.create(hdef))
 | 
			
		||||
                          else
 | 
			
		||||
                            p1:=load_self_node;
 | 
			
		||||
                        { not srsymtable.symtabletype since that can be }
 | 
			
		||||
                        { withsymtable as well                          }
 | 
			
		||||
                        if (srsym.owner.symtabletype=ObjectSymtable) then
 | 
			
		||||
 | 
			
		||||
@ -1545,7 +1545,7 @@ implementation
 | 
			
		||||
      end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    procedure read_proc;
 | 
			
		||||
    procedure read_proc(isclassmethod:boolean);
 | 
			
		||||
      {
 | 
			
		||||
        Parses the procedure directives, then parses the procedure body, then
 | 
			
		||||
        generates the code for it
 | 
			
		||||
@ -1568,7 +1568,7 @@ implementation
 | 
			
		||||
         current_objectdef:=nil;
 | 
			
		||||
 | 
			
		||||
         { parse procedure declaration }
 | 
			
		||||
         pd:=parse_proc_dec(old_current_objectdef);
 | 
			
		||||
         pd:=parse_proc_dec(isclassmethod, old_current_objectdef);
 | 
			
		||||
 | 
			
		||||
         { set the default function options }
 | 
			
		||||
         if parse_only then
 | 
			
		||||
@ -1713,8 +1713,11 @@ implementation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    procedure read_declarations(islibrary : boolean);
 | 
			
		||||
      var
 | 
			
		||||
        is_classdef:boolean;
 | 
			
		||||
      begin
 | 
			
		||||
         repeat
 | 
			
		||||
        is_classdef:=false;
 | 
			
		||||
        repeat
 | 
			
		||||
           if not assigned(current_procinfo) then
 | 
			
		||||
             internalerror(200304251);
 | 
			
		||||
           case token of
 | 
			
		||||
@ -1728,13 +1731,31 @@ implementation
 | 
			
		||||
                var_dec;
 | 
			
		||||
              _THREADVAR:
 | 
			
		||||
                threadvar_dec;
 | 
			
		||||
              _CLASS:
 | 
			
		||||
                begin
 | 
			
		||||
                  is_classdef:=false;
 | 
			
		||||
                  if try_to_consume(_CLASS) then
 | 
			
		||||
                   begin
 | 
			
		||||
                     { class method only allowed for procedures and functions }
 | 
			
		||||
                     if not(token in [_FUNCTION,_PROCEDURE,_PROPERTY]) then
 | 
			
		||||
                       Message(parser_e_procedure_or_function_expected);
 | 
			
		||||
 | 
			
		||||
                     if is_interface(current_objectdef) then
 | 
			
		||||
                       Message(parser_e_no_static_method_in_interfaces)
 | 
			
		||||
                     else
 | 
			
		||||
                       { class methods are also allowed for Objective-C protocols }
 | 
			
		||||
                       is_classdef:=true;
 | 
			
		||||
                   end;
 | 
			
		||||
                end;
 | 
			
		||||
              _CONSTRUCTOR,
 | 
			
		||||
              _DESTRUCTOR,
 | 
			
		||||
              _FUNCTION,
 | 
			
		||||
              _PROCEDURE,
 | 
			
		||||
              _OPERATOR,
 | 
			
		||||
              _CLASS:
 | 
			
		||||
                read_proc;
 | 
			
		||||
              _OPERATOR:
 | 
			
		||||
                begin
 | 
			
		||||
                  read_proc(is_classdef);
 | 
			
		||||
                  is_classdef:=false;
 | 
			
		||||
                end;
 | 
			
		||||
              _EXPORTS:
 | 
			
		||||
                begin
 | 
			
		||||
                   if (current_procinfo.procdef.localst.symtablelevel>main_program_level) then
 | 
			
		||||
@ -1766,7 +1787,10 @@ implementation
 | 
			
		||||
                    _PROPERTY:
 | 
			
		||||
                      begin
 | 
			
		||||
                        if (m_fpc in current_settings.modeswitches) then
 | 
			
		||||
                          property_dec
 | 
			
		||||
                        begin
 | 
			
		||||
                          property_dec(is_classdef);
 | 
			
		||||
                          is_classdef:=false;
 | 
			
		||||
                        end
 | 
			
		||||
                        else
 | 
			
		||||
                          break;
 | 
			
		||||
                      end;
 | 
			
		||||
@ -1799,7 +1823,7 @@ implementation
 | 
			
		||||
             _FUNCTION,
 | 
			
		||||
             _PROCEDURE,
 | 
			
		||||
             _OPERATOR :
 | 
			
		||||
               read_proc;
 | 
			
		||||
               read_proc(false);
 | 
			
		||||
             else
 | 
			
		||||
               begin
 | 
			
		||||
                 case idtoken of
 | 
			
		||||
@ -1808,7 +1832,7 @@ implementation
 | 
			
		||||
                   _PROPERTY:
 | 
			
		||||
                     begin
 | 
			
		||||
                       if (m_fpc in current_settings.modeswitches) then
 | 
			
		||||
                         property_dec
 | 
			
		||||
                         property_dec(false)
 | 
			
		||||
                       else
 | 
			
		||||
                         break;
 | 
			
		||||
                     end;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										34
									
								
								tests/test/tstatic2.pp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tests/test/tstatic2.pp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
program tstatic2;
 | 
			
		||||
{$APPTYPE console}
 | 
			
		||||
{$ifdef fpc}
 | 
			
		||||
  {$mode delphi}{$H+}
 | 
			
		||||
{$endif}
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
  TSomeClass = class
 | 
			
		||||
  private
 | 
			
		||||
    {$ifndef fpc}class var{$endif}FSomethingStatic: Integer; {$ifdef fpc}static;{$endif}
 | 
			
		||||
  public
 | 
			
		||||
    class procedure SetSomethingStatic(AValue: Integer); static;
 | 
			
		||||
    class property SomethingStatic: Integer read FSomethingStatic write SetSomethingStatic;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  TAnotherClass = class(TSomeClass)
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
{ TSomeClass }
 | 
			
		||||
 | 
			
		||||
class procedure TSomeClass.SetSomethingStatic(AValue: Integer);
 | 
			
		||||
begin
 | 
			
		||||
  FSomethingStatic := AValue;
 | 
			
		||||
  WriteLn('SomethingStatic:', SomethingStatic);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
  TSomeClass.SomethingStatic := 4;
 | 
			
		||||
  if TSomeClass.SomethingStatic <> 4 then
 | 
			
		||||
    halt(1);
 | 
			
		||||
  TAnotherClass.SomethingStatic := 10;
 | 
			
		||||
  if TSomeClass.SomethingStatic <> 10 then
 | 
			
		||||
    halt(2); // outputs 10
 | 
			
		||||
end.
 | 
			
		||||
							
								
								
									
										27
									
								
								tests/test/tstatic3.pp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								tests/test/tstatic3.pp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
{ %FAIL}
 | 
			
		||||
program tstatic3;
 | 
			
		||||
{$APPTYPE console}
 | 
			
		||||
{$ifdef fpc}
 | 
			
		||||
  {$mode delphi}{$H+}
 | 
			
		||||
{$endif}
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
  TSomeClass = class
 | 
			
		||||
  private
 | 
			
		||||
    {$ifndef fpc}class var{$endif}FSomethingStatic: Integer;
 | 
			
		||||
    {$ifndef fpc}var{$endif} FSomethingRegular: Integer;
 | 
			
		||||
    class procedure SetSomethingStatic(AValue: Integer); static;
 | 
			
		||||
  public
 | 
			
		||||
    class property SomethingStatic: Integer read FSomethingStatic write SetSomethingStatic;
 | 
			
		||||
    property SomethingRegular: Integer read FSomethingRegular write FSomethingRegular;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
{ TSomeClass }
 | 
			
		||||
 | 
			
		||||
class procedure TSomeClass.SetSomethingStatic(AValue: Integer);
 | 
			
		||||
begin
 | 
			
		||||
  FSomethingRegular := AValue;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
end.
 | 
			
		||||
							
								
								
									
										32
									
								
								tests/test/tstatic4.pp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/test/tstatic4.pp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
{ %FAIL}
 | 
			
		||||
program tstatic4;
 | 
			
		||||
{$APPTYPE console}
 | 
			
		||||
{$ifdef fpc}
 | 
			
		||||
  {$mode delphi}{$H+}
 | 
			
		||||
{$endif}
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
 | 
			
		||||
  { TSomeClass }
 | 
			
		||||
 | 
			
		||||
  TSomeClass = class
 | 
			
		||||
  public
 | 
			
		||||
    class procedure StaticProc; static;
 | 
			
		||||
    procedure RegularProc;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{ TSomeClass }
 | 
			
		||||
 | 
			
		||||
procedure TSomeClass.RegularProc;
 | 
			
		||||
begin
 | 
			
		||||
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
class procedure TSomeClass.StaticProc;
 | 
			
		||||
begin
 | 
			
		||||
  RegularProc;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
end.
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user