FreeBASIC  0.91.0
parser-proc.bas
Go to the documentation of this file.
1 '' proc (SUB, FUNCTION, OPERATOR, PROPERTY, CTOR/DTOR) header and body parsing
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 
5 
6 #include once "fb.bi"
7 #include once "fbint.bi"
8 #include once "parser.bi"
9 #include once "rtl.bi"
10 #include once "ast.bi"
11 
12 '' [ALIAS "id"]
13 function cAliasAttribute( ) as zstring ptr
14  static as zstring * FB_MAXNAMELEN+1 aliasid
15 
16  if( lexGetToken( ) = FB_TK_ALIAS ) then
17  lexSkipToken( )
18 
19  if( lexGetClass( ) = FB_TKCLASS_STRLITERAL ) then
20  aliasid = *lexGetText( )
21  lexSkipToken( )
22 
23  if( len( aliasid ) > 0 ) then
24  function = @aliasid
25  else
26  errReport( FB_ERRMSG_EMPTYALIASSTRING )
27  end if
28  else
29  errReport( FB_ERRMSG_SYNTAXERROR )
30  end if
31  end if
32 end function
33 
34 '' [LIB "string"]
36  dim as zstring ptr libname = any
37 
38  if( lexGetToken( ) = FB_TK_LIB ) then
39  lexSkipToken( )
40 
41  if( lexGetClass( ) = FB_TKCLASS_STRLITERAL ) then
42  libname = lexGetText( )
43 
44  if( len( *libname ) > 0 ) then
45  fbAddLib( libname )
46  else
47  errReport( FB_ERRMSG_EMPTYLIBSTRING )
48  end if
49 
50  lexSkipToken( )
51  else
52  errReport( FB_ERRMSG_SYNTAXERROR )
53  end if
54  end if
55 end sub
56 
58  ( _
59  byval parent as FBSYMBOL ptr, _
60  byref attrib as integer _
61  )
62 
63  '' STATIC?
64  if( hMatch( FB_TK_STATIC ) ) then
65  attrib or= FB_SYMBATTRIB_STATIC
66  '' STATIC methods can't be any of the below
67  exit sub
68  end if
69 
70  '' CONST?
71  if( hMatch( FB_TK_CONST ) ) then
72  attrib or= FB_SYMBATTRIB_CONST
73  end if
74 
75  '' (ABSTRACT|VIRTUAL)?
76  select case( lexGetToken( ) )
77  case FB_TK_ABSTRACT
78  attrib or= FB_SYMBATTRIB_VIRTUAL or FB_SYMBATTRIB_ABSTRACT
79 
80  '' Abstracts can only be allowed in UDTs that extend OBJECT,
81  '' because that is what provides the needed vtable ptr.
82  if( parent ) then
83  if( symbGetHasRTTI( parent ) = FALSE ) then
84  errReport( FB_ERRMSG_ABSTRACTWITHOUTRTTI )
85  attrib and= not (FB_SYMBATTRIB_VIRTUAL or FB_SYMBATTRIB_ABSTRACT)
86  end if
87  end if
88 
89  lexSkipToken( )
90 
91  case FB_TK_VIRTUAL
92  attrib or= FB_SYMBATTRIB_VIRTUAL
93 
94  '' ditto for virtuals
95  if( parent ) then
96  if( symbGetHasRTTI( parent ) = FALSE ) then
97  errReport( FB_ERRMSG_VIRTUALWITHOUTRTTI )
98  attrib and= not FB_SYMBATTRIB_VIRTUAL
99  end if
100  end if
101 
102  lexSkipToken( )
103 
104  end select
105 
106 end sub
107 
108 '':::::
109 sub hParamError _
110  ( _
111  byval proc as FBSYMBOL ptr, _
112  byval argnum as integer, _
113  byval errnum as integer = FB_ERRMSG_PARAMTYPEMISMATCHAT _
114  )
115 
116  errReportParam( proc, argnum, NULL, errnum )
117 
118 end sub
119 
120 '':::::
121 function hCheckPrototype _
122  ( _
123  byval proto as FBSYMBOL ptr, _
124  byval proc as FBSYMBOL ptr, _
125  byval palias as zstring ptr, _
126  byval proc_dtype as integer, _
127  byval proc_subtype as FBSYMBOL ptr, _
128  byval mode as integer _
129  ) as integer
130 
131  dim as FBSYMBOL ptr param = any, proto_param = any
132  dim as integer params = any, proto_params = any, i = any
133 
134  function = FALSE
135 
136  '' Check ALIAS id
137  if( (palias <> NULL) and ((proto->stats and FB_SYMBSTATS_HASALIAS) <> 0) ) then
138  if( *palias <> *proto->id.alias ) then
139  errReportEx( FB_ERRMSG_DIFFERENTALIASTHANPROTO, """" + *palias + """" )
140  exit function
141  end if
142  end if
143 
144  '' check arg count
145  param = symbGetProcHeadParam( proc )
146  params = symbGetProcParams( proc )
147  if( symbIsMethod( proc ) ) then
148  params -= 1
149  param = param->next
150  end if
151 
152  proto_param = symbGetProcHeadParam( proto )
153  proto_params = symbGetProcParams( proto )
154  if( symbIsMethod( proto ) ) then
155  proto_params -= 1
156  proto_param = proto_param->next
157  end if
158 
159  if( proto_params <> params ) then
160  errReport( FB_ERRMSG_ARGCNTMISMATCH, TRUE )
161  '' no error recovery: caller will take care
162  exit function
163  end if
164 
165  '' check return type
166  if( symbGetFullType( proto ) <> proc_dtype ) then
167  errReport( FB_ERRMSG_TYPEMISMATCH, TRUE )
168  '' no error recovery: ditto
169  exit function
170  end if
171 
172  '' and sub type
173  if( symbGetSubtype( proto ) <> proc_subtype ) then
174  errReport( FB_ERRMSG_TYPEMISMATCH, TRUE )
175  '' no error recovery: ditto
176  exit function
177  end if
178 
179  '' check return method
180  if( proc->proc.returnMethod <> FB_RETURN_DEFAULT) and _
181  ( proto->proc.returnMethod <> proc->proc.returnMethod ) then
182  errReportWarn( FB_WARNINGMSG_RETURNMETHODMISMATCH )
183  end if
184 
185  '' check calling convention
186  if( symbGetProcMode( proto ) <> mode ) then
187  errReport( FB_ERRMSG_ILLEGALPARAMSPEC, TRUE )
188  exit function
189  end if
190 
191  '' check each arg
192  for i = 1 to params
193  dim as integer dtype = symbGetFullType( proto_param )
194 
195  '' convert any AS ANY arg to the final one
196  if( typeGet( dtype ) = FB_DATATYPE_VOID ) then
197  proto_param->typ = param->typ
198  proto_param->subtype = param->subtype
199 
200  '' check if types don't conflit
201  else
202  if( param->typ <> dtype ) then
203  hParamError( proc, i )
204  '' no error recovery: caller will take care
205  exit function
206 
207  elseif( param->subtype <> symbGetSubtype( proto_param ) ) then
208  hParamError( proc, i )
209  '' no error recovery: ditto
210  exit function
211  end if
212  end if
213 
214  '' and mode
215  if( param->param.mode <> symbGetParamMode( proto_param ) ) then
216  hParamError( proc, i )
217  '' no error recovery: ditto
218  exit function
219  end if
220 
221  '' check names and change to the new one if needed
222  if( param->param.mode <> FB_PARAMMODE_VARARG ) then
223  symbSetName( proto_param, symbGetName( param ) )
224 
225  '' as both have the same type, re-set the suffix, because for example
226  '' "a as integer" on the prototype and "a%" or just "a" on the proc
227  '' declaration when in a defint context is allowed in QB
228  if( symbIsSuffixed( param ) ) then
229  symbGetAttrib( proto_param ) or= FB_SYMBATTRIB_SUFFIXED
230  else
231  symbGetAttrib( proto_param ) and = not FB_SYMBATTRIB_SUFFIXED
232  end if
233  end if
234 
235  '' Warn about mismatching param initializers?
236  '' If both params are optional, compare the two initializers
237  if( symbGetIsOptional( proto_param ) and symbGetIsOptional( param ) ) then
238  if( astIsEqualParamInit( proto_param->param.optexpr, param->param.optexpr ) = FALSE ) then
239  errReportParamWarn( proc, i, NULL, FB_WARNINGMSG_MISMATCHINGPARAMINIT )
240  exit function
241  end if
242  end if
243 
244  '' next arg
245  proto_param = proto_param->next
246  param = param->next
247  next
248 
249  ''
250  function = TRUE
251 
252 end function
253 
254 sub hCheckAttribs _
255  ( _
256  byval proto as FBSYMBOL ptr, _
257  byval attrib as FB_SYMBATTRIB _
258  )
259 
260  '' if one returns BYREF, the other must too
261  if( ((attrib and FB_SYMBATTRIB_RETURNSBYREF) <> 0) <> symbProcReturnsByref( proto ) ) then
262  errReport( FB_ERRMSG_TYPEMISMATCH, TRUE )
263  '' Error recovery: if the proto had BYREF, add it for the body
264  '' too, otherwise remove it from the body
265  if( symbProcReturnsByref( proto ) ) then
266  attrib or= FB_SYMBATTRIB_RETURNSBYREF
267  else
268  attrib and= not FB_SYMBATTRIB_RETURNSBYREF
269  end if
270  end if
271 
272  '' the body can only be STATIC if the proto is too
273  if( (attrib and FB_SYMBATTRIB_STATIC) and (not symbIsStatic( proto )) ) then
274  errReport( FB_ERRMSG_PROCPROTOTYPENOTSTATIC )
275  end if
276 
277  '' same for CONST
278  if( (attrib and FB_SYMBATTRIB_CONST) and (not symbIsConstant( proto )) ) then
279  errReport( FB_ERRMSG_PROCPROTOTYPENOTCONST )
280  end if
281 
282  '' and ABSTRACT (abstracts are VIRTUAL too, so checking them first)
283  if( (attrib and FB_SYMBATTRIB_ABSTRACT) and (not symbIsAbstract( proto )) ) then
284  errReport( FB_ERRMSG_PROCPROTOTYPENOTABSTRACT )
285  '' and VIRTUAL
286  elseif( (attrib and FB_SYMBATTRIB_VIRTUAL) and (not symbIsVirtual( proto )) ) then
287  errReport( FB_ERRMSG_PROCPROTOTYPENOTVIRTUAL )
288  end if
289 
290  symbGetAttrib( proto ) or= attrib
291 
292 end sub
293 
294 function hCheckIdToken( byval has_parent as integer ) as integer
295  function = FALSE
296 
297  select case as const( lexGetClass( ) )
298  case FB_TKCLASS_IDENTIFIER
299  if( fbLangOptIsSet( FB_LANG_OPT_PERIODS ) ) then
300  '' if inside a namespace, symbols can't contain periods (.)'s
301  if( symbIsGlobalNamespc( ) = FALSE ) then
302  if( lexGetPeriodPos( ) > 0 ) then
303  errReport( FB_ERRMSG_CANTINCLUDEPERIODS )
304  end if
305  end if
306  end if
307 
308  case FB_TKCLASS_QUIRKWD
309  if( env.clopt.lang <> FB_LANG_QB ) then
310  '' only if inside a ns and if not local
311  if( (not has_parent) or (parser.scope > FB_MAINSCOPE) ) then
312  errReport( FB_ERRMSG_DUPDEFINITION )
313  exit function
314  end if
315  end if
316 
317  case FB_TKCLASS_KEYWORD, FB_TKCLASS_OPERATOR
318  if( env.clopt.lang <> FB_LANG_QB ) then
319  errReport( FB_ERRMSG_DUPDEFINITION )
320  exit function
321  end if
322 
323  case else
324  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
325  exit function
326  end select
327 
328  function = TRUE
329 end function
330 
331 function hGetId _
332  ( _
333  byval parent as FBSYMBOL ptr, _
334  byval id as zstring ptr, _
335  byval dtype as integer ptr, _
336  byval is_sub as integer _
337  ) as FBSYMBOL ptr
338 
339  dim as FBSYMCHAIN ptr chain_ = any
340  dim as FBSYMBOL ptr sym = any
341 
342  function = NULL
343 
344  '' No parent?
345  if( parent = NULL ) then
346  '' Read as-is
347  chain_ = lexGetSymChain( )
348  else
349  '' Otherwise, lookup in that namespace
350  chain_ = symbLookupAt( parent, lexGetText( ), FALSE, FALSE )
351  end if
352 
353  '' Any symbol found?
354  if( chain_ ) then
355  '' same class?
356  sym = symbFindByClass( chain_, FB_SYMBCLASS_PROC )
357  else
358  sym = NULL
359  end if
360 
361  if( hCheckIdToken( (parent <> NULL) ) = FALSE ) then
362  '' error recovery: fake an id, skip until next '('
363  *id = *symbUniqueLabel( )
364  *dtype = FB_DATATYPE_INVALID
365  hSkipUntil( CHAR_LPRNT )
366  exit function
367  end if
368 
369  *id = *lexGetText( )
370  *dtype = lexGetType( )
371 
372  '' Disallow type suffix on SUBs
373  if( is_sub ) then
374  if( *dtype <> FB_DATATYPE_INVALID ) then
375  errReport( FB_ERRMSG_INVALIDCHARACTER )
376  *dtype = FB_DATATYPE_INVALID
377  end if
378  end if
379 
380  '' Check whether type suffix is allowed by the -lang mode
381  hCheckSuffix( *dtype )
382 
383  '' ID
384  lexSkipToken( )
385 
386  function = sym
387 end function
388 
389 sub cProcRetType _
390  ( _
391  byval attrib as integer, _
392  byval proc as FBSYMBOL ptr, _
393  byval is_proto as integer, _
394  byref dtype as integer, _
395  byref subtype as FBSYMBOL ptr _
396  )
397 
398  dim as integer options = any
399 
400  '' AS
401  lexSkipToken( )
402 
403  options = FB_SYMBTYPEOPT_DEFAULT
404 
405  '' Returns BYREF?
406  if( attrib and FB_SYMBATTRIB_RETURNSBYREF ) then
407  '' In prototypes, allow BYREF AS FWDREF
408  if( is_proto ) then
409  options or= FB_SYMBTYPEOPT_ALLOWFORWARD
410  end if
411 
412  '' Then allow BYREF AS Z/WSTRING as the type
413  options and= not FB_SYMBTYPEOPT_CHECKSTRPTR
414  end if
415 
416  if( cSymbolType( dtype, subtype, 0, options ) = FALSE ) then
417  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
418  '' error recovery: fake a type
419  dtype = FB_DATATYPE_INTEGER
420  subtype = NULL
421  else
422  '' check for invalid types
423  select case( typeGetDtAndPtrOnly( dtype ) )
424  case FB_DATATYPE_FIXSTR, FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
425  '' FIXSTR is never allowed; ZSTRING/WSTRING only if BYREF
426  if( ((attrib and FB_SYMBATTRIB_RETURNSBYREF) = 0) or _
427  (typeGetDtAndPtrOnly( dtype ) = FB_DATATYPE_FIXSTR) ) then
428  errReport( FB_ERRMSG_CANNOTRETURNFIXLENFROMFUNCTS )
429  '' error recovery: fake a type
430  dtype = FB_DATATYPE_STRING
431  subtype = NULL
432  end if
433 
434  case FB_DATATYPE_VOID
435  '' Not even allowed when returning BYREF, because of
436  '' the implicit DEREF on the CALL, but we cannot DEREF
437  '' an ANY PTR...
438  errReport( FB_ERRMSG_INVALIDDATATYPES )
439  '' error recovery: fake a type
440  dtype = typeAddrOf( dtype )
441  subtype = NULL
442  end select
443 
444  if( (attrib and FB_SYMBATTRIB_RETURNSBYREF) = 0 ) then
445  '' Disallow BYVAL return of objects of abstract classes
446  hComplainIfAbstractClass( dtype, subtype )
447  end if
448  end if
449 
450  proc->proc.returnMethod = cProcReturnMethod( dtype )
451 
452 end sub
453 
454 sub hParseAttributes _
455  ( _
456  byref attrib as FB_SYMBATTRIB, _
457  byval stats as FB_SYMBSTATS, _
458  byref priority as integer _
459  )
460 
461  priority = 0
462 
463  '' Priority?
464  if( lexGetClass( ) = FB_TKCLASS_NUMLITERAL ) then
465  '' not ctor or dtor?
466  if( (stats and (FB_SYMBSTATS_GLOBALCTOR or FB_SYMBSTATS_GLOBALDTOR)) = 0 ) then
467  errReport( FB_ERRMSG_SYNTAXERROR )
468  '' error recovery: skip token
469  lexSkipToken( )
470  '' not an integer
471  elseif( lexGetType( ) <> FB_DATATYPE_INTEGER ) then
472  errReport( FB_ERRMSG_INVALIDPRIORITY )
473  '' error recovery: skip token
474  lexSkipToken( )
475  else
476  priority = valint( *lexGetText() )
477  if priority < 101 or priority > 65535 then
478  errReport( FB_ERRMSG_INVALIDPRIORITY )
479  '' error recovery: skip token
480  lexSkipToken( )
481  else
482  priority and= &hffff
483  lexSkipToken( )
484  end if
485  end if
486  end if
487 
488  '' STATIC?
489  if( lexGetToken( ) = FB_TK_STATIC ) then
490  lexSkipToken( )
491  attrib or= FB_SYMBATTRIB_STATICLOCALS
492  end if
493 
494  '' EXPORT?
495  if( lexGetToken( ) = FB_TK_EXPORT ) then
496  '' ctor or dtor?
497  if( (stats and (FB_SYMBSTATS_GLOBALCTOR or FB_SYMBSTATS_GLOBALDTOR)) <> 0 ) then
498  errReport( FB_ERRMSG_SYNTAXERROR )
499  '' error recovery: skip token
500  lexSkipToken( )
501  return
502  end if
503 
504  '' private?
505  if( (attrib and FB_SYMBATTRIB_PRIVATE) > 0 ) then
506  errReport( FB_ERRMSG_SYNTAXERROR )
507  '' error recovery: make it public
508  attrib and= not FB_SYMBATTRIB_PRIVATE
509  end if
510 
511  lexSkipToken( )
512 
513  fbSetOption( FB_COMPOPT_EXPORT, TRUE )
514  '''''if( fbGetOption( FB_COMPOPT_EXPORT ) = FALSE ) then
515  ''''' errReportWarn( FB_WARNINGMSG_CANNOTEXPORT )
516  '''''end if
517  attrib or= FB_SYMBATTRIB_EXPORT or FB_SYMBATTRIB_PUBLIC
518  end if
519 end sub
520 
521 function cProcReturnMethod( byval dtype as FB_DATATYPE ) as FB_PROC_RETURN_METHOD
522  '' (OPTION(LIT_STRING))?
523 
524  dim as string returnMethod
525 
526  function = FB_RETURN_DEFAULT
527 
528  '' not allowed for non floating-point types
529  if( typeGetClass( dtype ) <> FB_DATACLASS_FPOINT ) then exit function
530 
531  if( lexGetToken( ) = FB_TK_OPTION ) then
532  lexSkipToken( )
533  hMatchLPRNT( )
534  if( lexGetClass( ) <> FB_TKCLASS_STRLITERAL ) then
535  errReport( FB_ERRMSG_SYNTAXERROR )
536  else
537  returnMethod = trim( ucase( *lexGetText( ) ) )
538  if( returnMethod = "SSE" ) then
539  function = FB_RETURN_SSE
540  elseif( returnMethod = "FPU" ) then
541  function = FB_RETURN_FPU
542  end if
544  end if
545  hMatchRPRNT( )
546  end if
547 end function
548 
549 function cProcCallingConv( byval default as FB_FUNCMODE ) as FB_FUNCMODE
550  '' Use the default FBCALL?
551  if( default = FB_FUNCMODE_FBCALL ) then
552  default = env.target.fbcall
553  end if
554 
555  '' (CDECL|STDCALL|PASCAL)?
556  select case as const lexGetToken( )
557  case FB_TK_CDECL
558  function = FB_FUNCMODE_CDECL
559  lexSkipToken( )
560 
561  case FB_TK_STDCALL
562  '' FB_FUNCMODE_STDCALL may be remapped to FB_FUNCMODE_STDCALL_MS
563  '' for targets that do not support the @N suffix
564  function = env.target.stdcall
565  lexSkipToken( )
566 
567  case FB_TK_PASCAL
568  function = FB_FUNCMODE_PASCAL
569  lexSkipToken( )
570 
571  case else
572  select case as const parser.mangling
573  case FB_MANGLING_BASIC
574  function = default
575 
576  case FB_MANGLING_CDECL, FB_MANGLING_CPP
577  function = FB_FUNCMODE_CDECL
578 
579  case FB_MANGLING_STDCALL
580  '' FB_FUNCMODE_STDCALL may be remapped to FB_FUNCMODE_STDCALL_MS
581  '' for targets that do not support the @N suffix
582  function = env.target.stdcall
583 
584  case FB_MANGLING_STDCALL_MS
585  function = FB_FUNCMODE_STDCALL_MS
586  end select
587  end select
588 end function
589 
590 sub cNakedAttribute( byref attrib as integer )
591  if( ucase( *lexGetText( ) ) = "NAKED" ) then
592  lexSkipToken( )
593  attrib or= FB_SYMBATTRIB_NAKED
594  end if
595 end sub
596 
597 '' OVERRIDE?
598 sub cOverrideAttribute( byval proc as FBSYMBOL ptr )
599  '' Check that this method really is allowed to override the overridden method
600  symbProcCheckOverridden( proc, FALSE )
601 
602  '' Don't bother doing the text comparisons below if at EOL (common case)
603  if( lexGetToken( ) = FB_TK_EOL ) then
604  exit sub
605  end if
606 
607  '' OVERRIDE?
608  if( ucase( *lexGetText( ) ) = "OVERRIDE" ) then
609  if( symbProcGetOverridden( proc ) = NULL ) then
610  errReport( FB_ERRMSG_OVERRIDINGNOTHING )
611  end if
612  lexSkipToken( )
613  end if
614 end sub
615 
616 sub cByrefAttribute( byref attrib as integer, byval is_func as integer )
617  '' BYREF?
618  if( lexGetToken( ) = FB_TK_BYREF ) then
619  if( is_func = FALSE ) then
620  errReport( FB_ERRMSG_SYNTAXERROR )
621  end if
622  lexSkipToken( )
623  attrib or= FB_SYMBATTRIB_RETURNSBYREF
624  end if
625 end sub
626 
627 sub hCheckAttrib _
628  ( _
629  byref attrib as integer, _
630  byval attr as integer, _
631  byval errmsg as integer _
632  )
633 
634  if( attrib and attr ) then
635  errReport( errmsg, TRUE )
636  attrib and= not attr
637  end if
638 
639 end sub
640 
641 function hCheckOpOvlParams _
642  ( _
643  byval parent as FBSYMBOL ptr, _
644  byval op as integer, _
645  byval proc as FBSYMBOL ptr _
646  ) as integer
647 
648  dim as integer found_mismatch = any
649  dim as integer is_method = symbIsMethod( proc )
650 
651 #macro hCheckParam( proc, param, num )
652  '' vararg?
653  if( symbGetParamMode( param ) = FB_PARAMMODE_VARARG ) then
654  hParamError( proc, num, FB_ERRMSG_VARARGPARAMNOTALLOWED )
655  exit function
656  end if
657 
658  '' optional?
659  if( symbGetIsOptional( param ) ) then
660  hParamError( proc, num, FB_ERRMSG_PARAMCANTBEOPTIONAL )
661  exit function
662  end if
663 #endmacro
664 
665  function = FALSE
666 
667  '' check the number of params
668  dim as integer min_params = any, max_params = any
669  select case as const astGetOpClass( op )
670  case AST_NODECLASS_UOP, AST_NODECLASS_ADDROF
671  min_params = iif( astGetOpIsSelf( op ), 0, 1 )
672  max_params = min_params
673 
674  case AST_NODECLASS_CONV
675  min_params = 0
676  max_params = min_params
677 
678  case AST_NODECLASS_ASSIGN, AST_NODECLASS_MEM
679  min_params = 1
680  max_params = min_params
681 
682  case AST_NODECLASS_COMP
683  '' self only if FOR, STEP and NEXT
684  if( astGetOpIsSelf( op ) ) then
685  min_params = 0
686  ' min_params = iif( op = AST_OP_NEXT, 1, 0 )
687  max_params = 1
688  if( op = AST_OP_NEXT ) then
689  min_params += 1
690  max_params += 1
691  end if
692  else
693  min_params = 2
694  max_params = min_params
695  end if
696 
697  '' bop..
698  case else
699  min_params = iif( astGetOpIsSelf( op ), 1, 2 )
700  max_params = min_params
701  end select
702 
703  dim as integer params = symbGetProcParams( proc )
704  dim as integer real_params = params - iif( is_method, 1, 0 )
705  if( (real_params < min_params) or (real_params > max_params) ) then
706  errReport( FB_ERRMSG_ARGCNTMISMATCH, TRUE )
707  exit function
708  end if
709 
710  if( params > 0 ) then
711  '' check the params, at least one param must be an UDT
712  dim as FBSYMBOL ptr param = symbGetProcHeadParam( proc )
713 
714  hCheckParam( proc, param, 1 )
715 
716  select case as const astGetOpClass( op )
717  '' unary, cast or addressing?
718  case AST_NODECLASS_UOP, AST_NODECLASS_CONV, AST_NODECLASS_ADDROF
719  '' is the param an UDT?
720  select case symbGetType( param )
721  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM ', FB_DATATYPE_CLASS
722 
723  case else
724  hParamError( proc, 1, FB_ERRMSG_ATLEASTONEPARAMMUSTBEANUDT )
725  exit function
726  end select
727 
728  '' binary?
729  case AST_NODECLASS_BOP
730  if( params > 1 ) then
731  dim as FBSYMBOL ptr nxtparam = param->next
732 
733  hCheckParam( proc, nxtparam, 2 )
734 
735  '' is the 1st param an UDT?
736  select case symbGetType( param )
737  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM ', FB_DATATYPE_CLASS
738 
739  case else
740  '' try the 2nd one..
741  select case symbGetType( nxtparam )
742  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM ', FB_DATATYPE_CLASS
743 
744  case else
745  hParamError( proc, 2, FB_ERRMSG_ATLEASTONEPARAMMUSTBEANUDT )
746  exit function
747  end select
748  end select
749  end if
750 
751  '' NEW or DELETE?
752  case AST_NODECLASS_MEM
753  select case op
754  case AST_OP_NEW_SELF, AST_OP_NEW_VEC_SELF
755  '' must be an integer
756  if( typeGetClass( symbGetType( param ) ) = FB_DATACLASS_INTEGER ) then
757  dim as integer is_integer = TRUE
758  if( typeIsPtr( symbGetType( param ) ) ) then
759  is_integer = FALSE
760  end if
761  select case symbGetType( param )
762  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
763  is_integer = FALSE
764  end select
765  if( is_integer = FALSE ) then
766  hParamError( proc, 1, FB_ERRMSG_PARAMMUSTBEANINTEGER )
767  exit function
768  end if
769  else
770  hParamError( proc, 1, FB_ERRMSG_PARAMMUSTBEANINTEGER )
771  exit function
772  end if
773 
774  case else
775  '' must be a pointer
776  if( typeGetClass( symbGetType( param ) ) = FB_DATACLASS_INTEGER ) then
777  if( typeIsPtr( symbGetType( param ) ) = FALSE ) then
778  hParamError( proc, 1, FB_ERRMSG_PARAMMUSTBEAPOINTER )
779  exit function
780  end if
781  else
782  hParamError( proc, 1, FB_ERRMSG_PARAMMUSTBEAPOINTER )
783  exit function
784  end if
785 
786  end select
787 
788  '' FOR, STEP or NEXT?
789  case AST_NODECLASS_COMP
790  select case as const op
791  '' relational? it must return an integer
792  case AST_OP_EQ, AST_OP_NE, AST_OP_GT, AST_OP_LT, AST_OP_GE, AST_OP_LE
793  if( params > 1 ) then
794  dim as FBSYMBOL ptr nxtparam = param->next
795 
796  hCheckParam( proc, nxtparam, 2 )
797 
798  '' is the 1st param an UDT?
799  select case symbGetType( param )
800  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM ', FB_DATATYPE_CLASS
801 
802  case else
803  '' try the 2nd one..
804  select case symbGetType( nxtparam )
805  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM ', FB_DATATYPE_CLASS
806 
807  case else
808  hParamError( proc, 2, FB_ERRMSG_ATLEASTONEPARAMMUSTBEANUDT )
809  exit function
810  end select
811  end select
812  end if
813 
814  '' FOR, STEP or NEXT?
815  case AST_OP_FOR, AST_OP_STEP, AST_OP_NEXT
816  if( astGetOpIsSelf( op ) ) then
817  if( params > 1 ) then
818  '' skip the instance ptr
819  if( is_method ) then
820  param = param->next
821  end if
822 
823  '' must be of the same type as parent
824  if( (param = NULL) or (parent = NULL) ) then
825  hParamError( proc, 1, FB_ERRMSG_PARAMTYPEINCOMPATIBLEWITHPARENT )
826  exit function
827  end if
828 
829  hCheckParam( proc, param, 1 )
830 
831  '' same type?
832  if( (symbGetType( param ) <> symbGetType( parent )) or _
833  (symbGetSubtype( param ) <> parent) ) then
834  hParamError( proc, 1, FB_ERRMSG_PARAMTYPEINCOMPATIBLEWITHPARENT )
835  exit function
836  end if
837  end if
838  end if
839  case else
840  assert( FALSE )
841  end select
842  end select
843  end if
844 
845  '' check the result
846  found_mismatch = FALSE
847 
848  select case astGetOpClass( op )
849  case AST_NODECLASS_CONV
850  '' return and param types can't be the same
851  if( symbGetSubtype( proc ) = parent ) then
852  errReport( FB_ERRMSG_SAMEPARAMANDRESULTTYPES, TRUE )
853  exit function
854  end if
855 
856  '' return type can't be a void
857  found_mismatch = (symbGetType( proc ) = FB_DATATYPE_VOID)
858 
859  '' unary?
860  case AST_NODECLASS_UOP
861  '' return type can't be a void
862  found_mismatch = (symbGetType( proc ) = FB_DATATYPE_VOID)
863 
864  '' assignment?
865  case AST_NODECLASS_ASSIGN
866  '' it must be a SUB
867  found_mismatch = (symbGetType( proc ) <> FB_DATATYPE_VOID)
868 
869  '' addressing?
870  case AST_NODECLASS_ADDROF
871  select case op
872  case AST_OP_ADDROF
873  '' return type must be a pointer
874  found_mismatch = not typeIsPtr( symbGetType( proc ) )
875 
876  case AST_OP_FLDDEREF
877  '' return type must be an UDT
878  found_mismatch = (symbGetType( proc ) <> FB_DATATYPE_STRUCT)
879 
880  case else
881  assert( op = AST_OP_DEREF )
882  '' Must be a function, not a sub
883  found_mismatch = (symbGetType( proc ) = FB_DATATYPE_VOID)
884 
885  end select
886 
887  '' mem?
888  case AST_NODECLASS_MEM
889  select case op
890  case AST_OP_NEW_SELF, AST_OP_NEW_VEC_SELF
891  '' should return a pointer
892  found_mismatch = not typeIsPtr( symbGetType( proc ) )
893 
894  case else
895  '' should not return anything
896  found_mismatch = (symbGetType( proc ) <> FB_DATATYPE_VOID)
897  end select
898 
899  '' binary?
900  case AST_NODECLASS_BOP
901  select case as const op
902  '' relational? it must return an integer
903  case AST_OP_EQ, AST_OP_NE, AST_OP_GT, AST_OP_LT, AST_OP_GE, AST_OP_LE
904  found_mismatch = (symbGetType( proc ) <> FB_DATATYPE_INTEGER)
905  case AST_OP_PTRINDEX
906  '' Must be a function, not a sub
907  found_mismatch = (symbGetType( proc ) = FB_DATATYPE_VOID)
908  case else
909  '' self? must be a SUB
910  if( astGetOpIsSelf( op ) ) then
911  found_mismatch = (symbGetType( proc ) <> FB_DATATYPE_VOID)
912  '' anything else, it can't be a void
913  else
914  found_mismatch = (symbGetType( proc ) = FB_DATATYPE_VOID)
915  end if
916  end select
917 
918  case AST_NODECLASS_COMP
919  '' FOR, STEP or NEXT?
920  if( astGetOpIsSelf( op ) ) then
921  '' it must return an integer (if NEXT) or void otherwise
922  if( op = AST_OP_NEXT ) then
923  found_mismatch = (symbGetType( proc ) <> FB_DATATYPE_INTEGER)
924  else
925  found_mismatch = (symbGetType( proc ) <> FB_DATATYPE_VOID)
926  end if
927  '' anything else, it can't be a void
928  else
929  found_mismatch = (symbGetType( proc ) = FB_DATATYPE_VOID)
930  end if
931 
932  end select
933 
934  if( found_mismatch ) then
935  errReport( FB_ERRMSG_INVALIDRESULTTYPEFORTHISOP, TRUE )
936  exit function
937  end if
938 
939  function = TRUE
940 end function
941 
942 function hCheckIsSelfCloneByval _
943  ( _
944  byval parent as FBSYMBOL ptr, _
945  byval proc as FBSYMBOL ptr, _
946  byval options as integer _
947  ) as integer
948 
949  function = FALSE
950 
951  dim as FBSYMBOL ptr param = symbGetProcHeadParam( proc )
952 
953  '' if it's a proto, skip the instance param
954  if( options and FB_PROCOPT_ISPROTO ) then
955  param = param->next
956  end if
957 
958  if( param = NULL ) then
959  exit function
960  end if
961 
962  '' struct?
963  if( symbGetType( param ) <> FB_DATATYPE_STRUCT ) then
964  exit function
965  end if
966 
967  '' same parent?
968  if( symbGetSubtype( param ) <> parent ) then
969  exit function
970  end if
971 
972  '' byval?
973  if( symbGetParamMode( param ) <> FB_PARAMMODE_BYVAL ) then
974  exit function
975  end if
976 
977  '' pointer?
978  if( typeGetClass( symbGetType( param ) ) = FB_DATACLASS_INTEGER ) then
979  if( typeIsPtr( symbGetType( param ) ) ) then
980  exit function
981  end if
982  end if
983 
984  '' At least one additional non-optional parameter?
985  param = param->next
986  while( param <> NULL )
987  if( symbGetIsOptional( param ) = FALSE ) then
988  exit function
989  end if
990  param = param->next
991  wend
992 
993  function = TRUE
994 
995 end function
996 
997 sub hCheckPropParams _
998  ( _
999  byval proc as FBSYMBOL ptr, _
1000  byval is_get as integer _
1001  )
1002 
1003  dim as integer min_params = any, max_params = any, i = any
1004  dim as FBSYMBOL ptr param = any
1005 
1006  if( is_get ) then
1007  min_params = 0
1008  max_params = 1
1009  else
1010  min_params = 1
1011  max_params = 2
1012  end if
1013 
1014  if ((symbGetProcParams( proc ) < 1 + min_params) or _
1015  (symbGetProcParams( proc ) > 1 + max_params)) then
1016  errReport( iif( is_get, _
1017  FB_ERRMSG_PARAMCNTFORPROPGET, _
1018  FB_ERRMSG_PARAMCNTFORPROPSET ), TRUE )
1019  end if
1020 
1021  '' any optional param?
1022  param = symbGetProcHeadParam( proc )
1023  i = 0
1024  while( param )
1025  if( symbGetIsOptional( param ) ) then
1026  hParamError( proc, 1+i, FB_ERRMSG_PARAMCANTBEOPTIONAL )
1027  end if
1028 
1029  i += 1
1030  param = param->next
1031  wend
1032 end sub
1033 
1035  ( _
1036  byval parent as FBSYMBOL ptr, _
1037  byval is_indexed as integer, _
1038  byval is_get as integer _
1039  )
1040 
1041  if( is_indexed ) then
1042  if( is_get = FALSE ) then
1043  symbSetUDTHasIdxSetProp( parent )
1044  else
1045  symbSetUDTHasIdxGetProp( parent )
1046  end if
1047  else
1048  if( is_get = FALSE ) then
1049  symbSetUDTHasSetProp( parent )
1050  else
1051  symbSetUDTHasGetProp( parent )
1052  end if
1053  end if
1054 
1055 end sub
1056 
1057 '' ProcHeader =
1058 '' ParentID? (ID|Operator)? CallConvention? OVERLOAD? (ALIAS LIT_STRING)?
1059 '' Parameters? BYREF? (AS SymbolType)?
1060 '' (CONSTRUCTOR|DESTRUCTOR)? Priority? STATIC? EXPORT?
1061 function cProcHeader _
1062  ( _
1063  byval attrib as FB_SYMBATTRIB, _
1064  byref is_nested as integer, _
1065  byval options as FB_PROCOPT, _
1066  byval tk as integer _
1067  ) as FBSYMBOL ptr
1068 
1069  #define CREATEFAKE( ) _
1070  symbAddProc( proc, symbUniqueLabel( ), NULL, dtype, subtype, _
1071  attrib, mode, FB_SYMBOPT_DECLARING )
1072 
1073  static as zstring * FB_MAXNAMELEN+1 id
1074  dim as zstring ptr palias = any
1075  dim as FBSYMBOL ptr head_proc = any, proc = any, parent = any, subtype = any
1076  dim as FBSYMBOL ptr param = any
1077  dim as integer dtype = any, is_outside = any, is_memberproc = any
1078  dim as integer mode = any, stats = any, op = any, is_get = any, is_indexed = any
1079  dim as integer priority = any, idopt = any
1080 
1081  is_nested = FALSE
1082  is_outside = FALSE
1083  is_memberproc = FALSE
1084  is_get = FALSE
1085  is_indexed = FALSE
1086  dtype = FB_DATATYPE_INVALID
1087  subtype = NULL
1088  stats = 0
1089 
1090  select case( tk )
1091  case FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR
1092  '' Ctors/dtors always are methods
1093  attrib or= FB_SYMBATTRIB_METHOD
1094 
1095  '' Ctors always are overloaded by default,
1096  '' dtors are not (they cannot have params anyways)
1097  if( tk = FB_TK_CONSTRUCTOR ) then
1098  attrib or= FB_SYMBATTRIB_CONSTRUCTOR or FB_SYMBATTRIB_OVERLOADED
1099  else
1100  attrib or= FB_SYMBATTRIB_DESTRUCTOR
1101  end if
1102 
1103  case FB_TK_OPERATOR
1104  '' Operators are always overloaded
1105  attrib or= FB_SYMBATTRIB_OPERATOR or FB_SYMBATTRIB_OVERLOADED
1106 
1107  case FB_TK_PROPERTY
1108  '' Properties are always methods and overloaded
1109  attrib or= FB_SYMBATTRIB_PROPERTY or FB_SYMBATTRIB_METHOD or _
1110  FB_SYMBATTRIB_OVERLOADED
1111 
1112  end select
1113 
1114  '' Parent UDT/namespace ID (if allowed)
1115  '' Inside UDT body?
1116  if( options and FB_PROCOPT_HASPARENT ) then
1117  '' No explicit parent ID allowed
1118  parent = NULL
1119  else
1120  '' Parent/namespace ID
1121  idopt = FB_IDOPT_ISDECL or FB_IDOPT_SHOWERROR or FB_IDOPT_ALLOWSTRUCT
1122  select case( tk )
1123  case FB_TK_OPERATOR
1124  idopt or= FB_IDOPT_ISOPERATOR
1125  case FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR
1126  idopt or= FB_IDOPT_DONTCHKPERIOD
1127  end select
1128  parent = cParentId( idopt )
1129  end if
1130 
1131  '' Namespace prefix explicitly given?
1132  if( parent ) then
1133  '' Note: we assume to be outside this namespace's block;
1134  '' it's not allowed to explicitly specify the namespace
1135  '' while inside its block.
1136  if( options and FB_PROCOPT_ISPROTO ) then
1137  '' An explicit namespace isn't allowed on prototypes,
1138  '' declarations should be put in the namespace block,
1139  '' only bodies can be written outside.
1140  errReport( FB_ERRMSG_DECLOUTSIDECLASS )
1141  else
1142  '' Proc body with explicitly specified parent:
1143  '' outside of the original namespace
1144  is_outside = TRUE
1145  end if
1146  else
1147  '' Use the "default" namespace:
1148  '' If inside a namespace block, use that as parent.
1149  '' If at toplevel, the proc doesn't have a parent.
1150  if( symbGetCurrentNamespc( ) <> @symbGetGlobalNamespc( ) ) then
1151  parent = symbGetCurrentNamespc( )
1152  end if
1153  end if
1154 
1155  if( parent ) then
1156  '' Parent namespace is a UDT?
1157  is_memberproc = symbIsStruct( parent )
1158  end if
1159 
1160  if( is_memberproc ) then
1161  '' prototypes inside UDTs that are not STATIC are METHODs
1162  '' (for bodies it depends on the attributes inherited
1163  '' from the corresponding prototype)
1164  if( ((options and FB_PROCOPT_ISPROTO) <> 0) and _
1165  ((attrib and FB_SYMBATTRIB_STATIC) = 0) ) then
1166  attrib or= FB_SYMBATTRIB_METHOD
1167  end if
1168  else
1169  '' Ctors/dtors/properties must always have an UDT parent
1170  select case( tk )
1171  case FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR, FB_TK_PROPERTY
1172  if( parent = NULL ) then
1173  errReport( FB_ERRMSG_EXPECTEDCLASSID )
1174  elseif( symbIsStruct( parent ) = FALSE ) then
1175  errReport( FB_ERRMSG_PARENTISNOTACLASS )
1176  end if
1177 
1178  if( options and FB_PROCOPT_ISPROTO ) then
1179  hSkipStmt( )
1180  else
1181  hSkipCompound( tk )
1182  end if
1183 
1184  exit function
1185  end select
1186 
1187  '' Check whether STATIC, CONST, ABSTRACT and VIRTUAL were used correctly
1188  hCheckAttrib( attrib, FB_SYMBATTRIB_STATIC , FB_ERRMSG_STATICNONMEMBERPROC )
1189  hCheckAttrib( attrib, FB_SYMBATTRIB_CONST , FB_ERRMSG_CONSTNONMEMBERPROC )
1190  hCheckAttrib( attrib, FB_SYMBATTRIB_ABSTRACT, FB_ERRMSG_ABSTRACTNONMEMBERPROC )
1191  hCheckAttrib( attrib, FB_SYMBATTRIB_VIRTUAL , FB_ERRMSG_VIRTUALNONMEMBERPROC )
1192  end if
1193 
1194  select case( tk )
1195  case FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR
1196  '' Ctors/dtors don't have an ID on their own
1197  proc = symbPreAddProc( NULL )
1198 
1199  case FB_TK_OPERATOR
1200  '' Operator (instead of an ID)
1201  op = cOperator( TRUE )
1202  select case( op )
1203  case INVALID, _
1204  AST_OP_ANDALSO, AST_OP_ANDALSO_SELF, _
1205  AST_OP_ORELSE, AST_OP_ORELSE_SELF
1206  errReport( FB_ERRMSG_EXPECTEDOPERATOR )
1207  '' error recovery: fake an op
1208  op = AST_OP_ADD
1209  end select
1210 
1211  '' self-op?
1212  if( astGetOpIsSelf( op ) ) then
1213  '' Must always be a member procedure
1214  if( is_memberproc = FALSE ) then
1215  errReport( FB_ERRMSG_OPMUSTBEAMETHOD, TRUE )
1216  '' error recovery: Change to a non-self op
1217  op = AST_OP_ADD
1218  end if
1219  else
1220  '' non-self op in a type declaration... !!WRITEME!! static global operators should be allowed?
1221  if( is_memberproc ) then
1222  errReport( FB_ERRMSG_OPCANNOTBEAMETHOD, TRUE, " (TODO)" )
1223  end if
1224  end if
1225 
1226  select case as const( op )
1227  case AST_OP_NEW_SELF, AST_OP_NEW_VEC_SELF, _
1228  AST_OP_DEL_SELF, AST_OP_DEL_VEC_SELF
1229  '' These ops are made STATIC implicitly
1230  attrib or= FB_SYMBATTRIB_STATIC
1231  attrib and= not FB_SYMBATTRIB_METHOD
1232 
1233  case else
1234  if( is_memberproc ) then
1235  if( attrib and FB_SYMBATTRIB_STATIC ) then
1236  errReport( FB_ERRMSG_OPERATORCANTBESTATIC, TRUE )
1237  attrib and= not FB_SYMBATTRIB_STATIC
1238  end if
1239  '' Then it must be a method
1240  attrib or= FB_SYMBATTRIB_METHOD
1241  end if
1242  end select
1243 
1244  proc = symbPreAddProc( NULL )
1245 
1246  case else
1247  '' Procedure/property ID
1248  head_proc = hGetId( parent, @id, @dtype, _
1249  (tk = FB_TK_SUB) or (tk = FB_TK_PROPERTY) )
1250 
1251  proc = symbPreAddProc( @id )
1252  end select
1253 
1254  '' [NAKED]
1255  cNakedAttribute( attrib )
1256 
1257  '' CallConvention?
1258  select case( tk )
1259  case FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR
1260  '' ctors/dtors default to CDECL, so they can be passed to
1261  '' the rtlib's REDIM or ERASE functions by procptr
1262  mode = FB_FUNCMODE_CDECL
1263  case else
1264  mode = FB_FUNCMODE_FBCALL
1265  end select
1266  mode = cProcCallingConv( mode )
1267 
1268  '' OVERLOAD?
1269  if( lexGetToken( ) = FB_TK_OVERLOAD ) then
1270  if( fbLangOptIsSet( FB_LANG_OPT_FUNCOVL ) = FALSE ) then
1271  errReportNotAllowed( FB_LANG_OPT_FUNCOVL )
1272  else
1273  attrib or= FB_SYMBATTRIB_OVERLOADED
1274  end if
1275  lexSkipToken( )
1276  end if
1277 
1278  if( options and FB_PROCOPT_ISPROTO ) then
1279  '' [LIB "string"]
1280  cLibAttribute( )
1281  end if
1282 
1283  '' [ALIAS "id"]
1284  palias = cAliasAttribute( )
1285 
1286  '' If this is a proc body (not a proto), then we'll open a new scope
1287  '' with astProcBegin(), and additionally we may have to re-open the
1288  '' proc's namespace, in case it's being declared outside the original
1289  '' namespace where we found the prototype.
1290  ''
1291  '' This ensures the proc and code in it behaves as if it was written
1292  '' in the original namespace to begin with. For example, it must be
1293  '' possible to access symbols from that namespace without using the
1294  '' namespace prefix explicitly, even if the body is written outside
1295  '' the namespace block that contains the prototype.
1296  ''
1297  '' Note: Even parameter initializers are affected, thus this must be
1298  '' done even before parsing the parameter list.
1299  if( ((options and FB_PROCOPT_ISPROTO) = 0) and (parent <> NULL) ) then
1300  if( parent <> symbGetCurrentNamespc( ) ) then
1301  symbNestBegin( parent, TRUE )
1302  is_nested = TRUE
1303  end if
1304  end if
1305 
1306  symbGetAttrib( proc ) = attrib
1307 
1308  '' Parameters?
1309  cParameters( parent, proc, mode, ((options and FB_PROCOPT_ISPROTO) <> 0) )
1310 
1311  select case( tk )
1312  case FB_TK_DESTRUCTOR
1313  if( symbGetProcParams( proc ) > 1 ) then
1314  errReport( FB_ERRMSG_DTORCANTCONTAINPARAMS )
1315  end if
1316 
1317  dtype = FB_DATATYPE_VOID
1318  subtype = NULL
1319 
1320  case FB_TK_CONSTRUCTOR
1321  '' ctor can't take a byval arg of its own type as only non-optional arg
1322  if( hCheckIsSelfCloneByval( parent, proc, options ) ) then
1323  errReport( FB_ERRMSG_CLONECANTTAKESELFBYVAL, TRUE )
1324  exit function
1325  end if
1326 
1327  '' vararg?
1328  if( symbGetParamMode( symbGetProcTailParam( proc ) ) = FB_PARAMMODE_VARARG ) then
1329  hParamError( proc, 0, FB_ERRMSG_VARARGPARAMNOTALLOWED )
1330  '' error recovery: remove the param
1331  param = symbGetProcTailParam( proc )
1332  symbGetProcTailParam( proc ) = param->prev
1333  if( param->prev <> NULL ) then
1334  param->prev->next = NULL
1335  end if
1336  symbGetProcParams( proc ) -= 1
1337  symbFreeSymbol( param )
1338  end if
1339 
1340  dtype = FB_DATATYPE_VOID
1341  subtype = NULL
1342 
1343  case FB_TK_OPERATOR
1344  '' special cases, '-' or '+' with just one param are actually unary ops
1345  select case op
1346  case AST_OP_SUB
1347  if( symbGetProcParams( proc ) = 1 ) then
1348  op = AST_OP_NEG
1349  end if
1350 
1351  case AST_OP_ADD
1352  if( symbGetProcParams( proc ) = 1 ) then
1353  op = AST_OP_PLUS
1354  end if
1355 
1356  '' '*' with one param is actually a deref
1357  case AST_OP_MUL
1358  if( symbGetProcParams( proc ) = 1 ) then
1359  op = AST_OP_DEREF
1360  end if
1361 
1362  end select
1363 
1364  '' self? (but type casting)
1365  if( astGetOpNoResult( op ) ) then
1366  dtype = FB_DATATYPE_VOID
1367  else
1368  '' BYREF?
1369  cByrefAttribute( attrib, TRUE )
1370 
1371  '' AS SymbolType
1372  if( lexGetToken( ) = FB_TK_AS ) then
1373  cProcRetType( attrib, proc, ((options and FB_PROCOPT_ISPROTO) <> 0), _
1374  dtype, subtype )
1375  else
1376  errReport( FB_ERRMSG_EXPECTEDRESTYPE )
1377  '' error recovery: fake a type
1378  dtype = FB_DATATYPE_INTEGER
1379  end if
1380  end if
1381 
1382  symbGetFullType( proc ) = dtype
1383  symbGetSubtype( proc ) = subtype
1384 
1385  symbSetProcOpOvl( proc, op )
1386 
1387  '' operator LET can't take a byval arg of its own type
1388  if( op = AST_OP_ASSIGN ) then
1389  if( hCheckIsSelfCloneByval( parent, proc, options ) ) then
1390  errReport( FB_ERRMSG_CLONECANTTAKESELFBYVAL, TRUE )
1391  exit function
1392  end if
1393  end if
1394 
1395  '' check params
1397 
1398  case FB_TK_PROPERTY
1399  '' BYREF?
1400  cByrefAttribute( attrib, TRUE )
1401 
1402  '' (AS SymbolType)?
1403  if( lexGetToken( ) = FB_TK_AS ) then
1404  cProcRetType( attrib, proc, ((options and FB_PROCOPT_ISPROTO) <> 0), _
1405  dtype, subtype )
1406  is_indexed = (symbGetProcParams( proc ) = 1+1)
1407  is_get = TRUE
1408  else
1409  '' found BYREF before?
1410  if( attrib and FB_SYMBATTRIB_RETURNSBYREF ) then
1411  errReport( FB_ERRMSG_EXPECTEDRESTYPE )
1412  '' error recovery: remove BYREF attribute and treat as setter
1413  attrib and= not FB_SYMBATTRIB_RETURNSBYREF
1414  end if
1415  dtype = FB_DATATYPE_VOID
1416  is_indexed = (symbGetProcParams( proc ) = 1+2)
1417  end if
1418 
1419  symbGetFullType( proc ) = dtype
1420  symbGetSubType( proc ) = subtype
1421  hCheckPropParams( proc, is_get )
1422 
1423  case else
1424  '' Member procedures are overloaded by default, unless they're vararg
1425  if( is_memberproc ) then
1426  if( (symbGetProcParams( proc ) <= 0) orelse _
1427  (symbGetProcTailParam( proc )->param.mode <> FB_PARAMMODE_VARARG) ) then
1428  attrib or= FB_SYMBATTRIB_OVERLOADED
1429  end if
1430  end if
1431 
1432  '' BYREF?
1433  cByrefAttribute( attrib, (tk = FB_TK_FUNCTION) )
1434 
1435  '' (AS SymbolType)?
1436  if( lexGetToken( ) = FB_TK_AS ) then
1437  if( (dtype <> FB_DATATYPE_INVALID) or (tk = FB_TK_SUB) ) then
1438  errReport( FB_ERRMSG_SYNTAXERROR )
1439  end if
1440  cProcRetType( attrib, proc, ((options and FB_PROCOPT_ISPROTO) <> 0), _
1441  dtype, subtype )
1442  else
1443  if( tk = FB_TK_FUNCTION ) then
1444  if( fbLangOptIsSet( FB_LANG_OPT_DEFTYPE ) ) then
1445  '' No suffix yet?
1446  if( dtype = FB_DATATYPE_INVALID ) then
1447  '' Then use type from DEF*
1448  dtype = symbGetDefType( id )
1449  end if
1450  else
1451  errReportNotAllowed( FB_LANG_OPT_DEFTYPE, FB_ERRMSG_DEFTYPEONLYVALIDINLANG )
1452  '' error recovery: fake a type
1453  dtype = FB_DATATYPE_INTEGER
1454  end if
1455  else
1456  '' SUB
1457  dtype = FB_DATATYPE_VOID
1458  end if
1459  end if
1460 
1461  '' (CONSTRUCTOR | DESTRUCTOR)?
1462  select case( lexGetToken( ) )
1463  case FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR
1464  '' A module ctor/dtor must be a sub with no params,
1465  '' it cannot be a method or function.
1466  '' (static member procs are ok though)
1467  if( ((attrib and FB_SYMBATTRIB_METHOD) <> 0) or _
1468  (tk = FB_TK_FUNCTION) ) then
1469  errReport( FB_ERRMSG_SYNTAXERROR, TRUE )
1470  elseif( symbGetProcParams( proc ) <> 0 ) then
1471  errReport( FB_ERRMSG_ARGCNTMISMATCH, TRUE )
1472  else
1473  if( lexGetToken( ) = FB_TK_CONSTRUCTOR ) then
1474  stats or= FB_SYMBSTATS_GLOBALCTOR
1475  else
1476  stats or= FB_SYMBSTATS_GLOBALDTOR
1477  end if
1478  end if
1479 
1480  lexSkipToken( )
1481  end select
1482 
1483  end select
1484 
1485  '' Prototype?
1486  if( options and FB_PROCOPT_ISPROTO ) then
1487  select case( tk )
1488  case FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR
1489  proc = symbAddCtor( proc, palias, attrib, mode )
1490  case FB_TK_OPERATOR
1491  proc = symbAddOperator( proc, op, palias, dtype, subtype, attrib, mode )
1492  case else
1493  proc = symbAddProc( proc, @id, palias, dtype, subtype, attrib, mode, FB_SYMBOPT_NONE )
1494  end select
1495 
1496  if( proc = NULL ) then
1497  errReport( FB_ERRMSG_DUPDEFINITION )
1498  exit function
1499  end if
1500 
1501  '' OVERRIDE?
1502  '' - Only allowed inside the TYPE compound, since it's a
1503  '' compile-time check in the inheritance hierarchy, and does
1504  '' not affect the method at all
1505  '' - Not allowed on ctors, since they cannot be VIRTUAL
1506  if( ((options and FB_PROCOPT_HASPARENT) <> 0) and _
1507  (tk <> FB_TK_CONSTRUCTOR) ) then
1509  end if
1510 
1511  if( tk = FB_TK_PROPERTY ) then
1512  hSetUdtPropertyFlags( parent, is_indexed, is_get )
1513  end if
1514 
1515  return proc
1516  end if
1517 
1518  '' Body
1519  hParseAttributes( attrib, stats, priority )
1520 
1521  select case( tk )
1522  case FB_TK_CONSTRUCTOR
1523  head_proc = symbGetCompCtorHead( parent )
1524  case FB_TK_DESTRUCTOR
1525  head_proc = symbGetCompDtor( parent )
1526  case FB_TK_OPERATOR
1527  head_proc = symbGetCompOpOvlHead( parent, op )
1528  end select
1529 
1530  '' No preview proc (forward CALL?) or existing prototype found in
1531  '' the parent namespace?
1532  if( head_proc = NULL ) then
1533  '' Body outside its parent namespace block?
1534  if( is_outside ) then
1535  errReport( FB_ERRMSG_DECLOUTSIDECLASS )
1536  end if
1537 
1538  '' Add new proc based on the body
1539  select case( tk )
1540  case FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR
1541  head_proc = symbAddCtor( proc, palias, attrib, mode, FB_SYMBOPT_DECLARING )
1542  case FB_TK_OPERATOR
1543  head_proc = symbAddOperator( proc, op, palias, dtype, subtype, _
1544  attrib, mode, FB_SYMBOPT_DECLARING )
1545  case else
1546  head_proc = symbAddProc( proc, @id, palias, dtype, subtype, _
1547  attrib, mode, FB_SYMBOPT_DECLARING )
1548  end select
1549 
1550  if( head_proc = NULL ) then
1551  errReport( FB_ERRMSG_DUPDEFINITION, TRUE )
1552  proc = CREATEFAKE( )
1553  else
1554  proc = head_proc
1555  end if
1556  else
1557  '' A proc or proto with this name already exists, this is
1558  '' either a duplicate definition or the corresponding body.
1559 
1560  '' non-properties cannot implement properties, and vice-versa
1561  if( symbIsProperty( head_proc ) <> (tk = FB_TK_PROPERTY) ) then
1562  errReport( FB_ERRMSG_DUPDEFINITION, TRUE )
1563  return CREATEFAKE( )
1564  end if
1565 
1566  '' overloaded?
1567  if( symbGetProcIsOverloaded( head_proc ) ) then
1568  '' Try to find a prototype with the same signature
1569  select case( tk )
1570  case FB_TK_CONSTRUCTOR
1571  head_proc = symbFindCtorProc( head_proc, proc )
1572  case FB_TK_OPERATOR
1573  head_proc = symbFindOpOvlProc( op, head_proc, proc )
1574  case else
1575  head_proc = symbFindOverloadProc( head_proc, proc, _
1576  iif( is_get, FB_SYMBLOOKUPOPT_PROPGET, FB_SYMBLOOKUPOPT_NONE ) )
1577  end select
1578  attrib or= FB_SYMBATTRIB_OVERLOADED
1579  end if
1580 
1581  '' No prototype with the same signature found?
1582  if( head_proc = NULL ) then
1583  if( is_outside ) then
1584  errReport( FB_ERRMSG_DECLOUTSIDECLASS )
1585  end if
1586 
1587  '' Then try to add the new overload
1588  select case( tk )
1589  case FB_TK_CONSTRUCTOR, FB_TK_DESTRUCTOR
1590  head_proc = symbAddCtor( proc, palias, attrib, mode, FB_SYMBOPT_DECLARING )
1591  case FB_TK_OPERATOR
1592  head_proc = symbAddOperator( proc, op, palias, dtype, subtype, _
1593  attrib, mode, FB_SYMBOPT_DECLARING )
1594  case else
1595  head_proc = symbAddProc( proc, @id, palias, dtype, subtype, _
1596  attrib, mode, FB_SYMBOPT_DECLARING )
1597  end select
1598 
1599  '' dup def?
1600  if( head_proc = NULL ) then
1601  errReport( FB_ERRMSG_DUPDEFINITION, TRUE )
1602  return CREATEFAKE( )
1603  end if
1604 
1605  proc = head_proc
1606  else
1607  '' already parsed?
1608  if( symbGetIsDeclared( head_proc ) ) then
1609  errReport( FB_ERRMSG_DUPDEFINITION, TRUE )
1610  return CREATEFAKE( )
1611  end if
1612 
1613  '' There already is a prototype for this proc, check for
1614  '' declaration conflicts and fix up the parameters
1615  if( hCheckPrototype( head_proc, proc, palias, dtype, subtype, mode ) = FALSE ) then
1616  return CREATEFAKE( )
1617  end if
1618 
1619  '' use the prototype
1620  proc = head_proc
1621 
1622  hCheckAttribs( proc, attrib )
1623 
1624  symbSetIsDeclared( proc )
1625  end if
1626  end if
1627 
1628  '' Register global ctors/dtors
1629  if( stats and FB_SYMBSTATS_GLOBALCTOR ) then
1631  symbSetProcPriority( proc, priority )
1632  elseif( stats and FB_SYMBSTATS_GLOBALDTOR ) then
1634  symbSetProcPriority( proc, priority )
1635  end if
1636 
1637  if( tk = FB_TK_PROPERTY ) then
1638  hSetUdtPropertyFlags( parent, is_indexed, is_get )
1639  end if
1640 
1641  function = proc
1642 end function
1643 
1644 sub hDisallowStaticAttrib( byref attrib as integer )
1645  if( (attrib and FB_SYMBATTRIB_STATIC) <> 0 ) then
1646  errReport( FB_ERRMSG_MEMBERCANTBESTATIC )
1647  attrib and= not FB_SYMBATTRIB_STATIC
1648  end if
1649 end sub
1650 
1651 sub hDisallowVirtualCtor( byref attrib as integer )
1652  '' Constructors cannot be virtual (they initialize the vptr
1653  '' needed for virtual calls, chicken-egg problem)
1654  if( attrib and (FB_SYMBATTRIB_ABSTRACT or FB_SYMBATTRIB_VIRTUAL) ) then
1655  if( attrib and FB_SYMBATTRIB_ABSTRACT ) then
1656  errReport( FB_ERRMSG_ABSTRACTCTOR )
1657  else
1658  errReport( FB_ERRMSG_VIRTUALCTOR )
1659  end if
1660  attrib and= not (FB_SYMBATTRIB_ABSTRACT or FB_ERRMSG_VIRTUALCTOR)
1661  end if
1662 end sub
1663 
1664 sub hDisallowAbstractDtor( byref attrib as integer )
1665  '' Destructors cannot be abstract; they need to have a body to ensure
1666  '' that base and field destructors are called.
1667  if( attrib and FB_SYMBATTRIB_ABSTRACT ) then
1668  errReport( FB_ERRMSG_ABSTRACTDTOR )
1669  attrib and= not FB_SYMBATTRIB_ABSTRACT
1670  end if
1671 end sub
1672 
1673 sub hDisallowConstCtorDtor( byval tk as integer, byref attrib as integer )
1674  '' It doesn't make sense for ctors/dtors to be CONST. It's a ctor's
1675  '' purpose to initialize an object and it couldn't do that if it used
1676  '' a CONST This. And as for dtors, they need to be able to destroy all
1677  '' objects, CONST or not. It doesn't matter whether the dtor modifies
1678  '' the object in the process since it's dead afterwards anyways.
1679  if( attrib and FB_SYMBATTRIB_CONST ) then
1680  errReport( iif( tk = FB_TK_CONSTRUCTOR, _
1681  FB_ERRMSG_CONSTCTOR, FB_ERRMSG_CONSTDTOR ) )
1682  attrib and= not FB_SYMBATTRIB_CONST
1683  end if
1684 end sub
1685 
1686 '' ProcStmtBegin = (PRIVATE|PUBLIC)? (STATIC? | CONST? VIRTUAL?)
1687 '' (SUB|FUNCTION|CONSTRUCTOR|DESTRUCTOR|OPERATOR) ProcHeader .
1688 sub cProcStmtBegin( byval attrib as integer )
1689  dim as integer tkn = any, is_nested = any
1690  dim as FBSYMBOL ptr proc = any
1691  dim as FB_CMPSTMTSTK ptr stk = any
1692 
1693  if( (attrib and (FB_SYMBATTRIB_PUBLIC or FB_SYMBATTRIB_PRIVATE)) = 0 ) then
1694  if( env.opt.procpublic ) then
1695  attrib or= FB_SYMBATTRIB_PUBLIC
1696  else
1697  attrib or= FB_SYMBATTRIB_PRIVATE
1698  end if
1699  end if
1700 
1701  cMethodAttributes( NULL, attrib )
1702 
1703  '' SUB|FUNCTION|CONSTRUCTOR|DESTRUCTOR|OPERATOR
1704  tkn = lexGetToken( )
1705  select case as const tkn
1706  case FB_TK_SUB, FB_TK_FUNCTION
1707 
1708  case FB_TK_CONSTRUCTOR
1709  if( fbLangOptIsSet( FB_LANG_OPT_CLASS ) = FALSE ) then
1710  errReportNotAllowed( FB_LANG_OPT_CLASS )
1711  else
1712  attrib or= FB_SYMBATTRIB_CONSTRUCTOR
1713  end if
1714 
1715  hDisallowStaticAttrib( attrib )
1716  hDisallowVirtualCtor( attrib )
1717  hDisallowConstCtorDtor( tkn, attrib )
1718 
1719  case FB_TK_DESTRUCTOR
1720  if( fbLangOptIsSet( FB_LANG_OPT_CLASS ) = FALSE ) then
1721  errReportNotAllowed( FB_LANG_OPT_CLASS )
1722  else
1723  attrib or= FB_SYMBATTRIB_DESTRUCTOR
1724  end if
1725 
1726  hDisallowStaticAttrib( attrib )
1727  hDisallowAbstractDtor( attrib )
1728  hDisallowConstCtorDtor( tkn, attrib )
1729 
1730  case FB_TK_OPERATOR
1731  if( fbLangOptIsSet( FB_LANG_OPT_OPEROVL ) = FALSE ) then
1732  errReportNotAllowed( FB_LANG_OPT_OPEROVL )
1733  end if
1734 
1735  case FB_TK_PROPERTY
1736  if( fbLangOptIsSet( FB_LANG_OPT_CLASS ) = FALSE ) then
1737  errReportNotAllowed( FB_LANG_OPT_CLASS )
1738  end if
1739 
1740  hDisallowStaticAttrib( attrib )
1741 
1742  case else
1743  errReport( FB_ERRMSG_SYNTAXERROR )
1744  hSkipStmt( )
1745  exit sub
1746  end select
1747 
1748  if( cCompStmtIsAllowed( FB_CMPSTMT_MASK_PROC ) = FALSE ) then
1749  '' error recovery: skip the whole compound stmt
1750  hSkipCompound( tkn )
1751  exit sub
1752  end if
1753 
1754  lexSkipToken( )
1755 
1756  '' ProcHeader
1757  proc = cProcHeader( attrib, is_nested, FB_PROCOPT_NONE, tkn )
1758  if( proc = NULL ) then
1759  exit sub
1760  end if
1761 
1762  '' ABSTRACTs shouldn't have a body implemented, VIRTUAL should be used instead
1763  if( symbIsAbstract( proc ) ) then
1764  errReport( FB_ERRMSG_ABSTRACTBODY )
1765  end if
1766 
1767  '' emit proc setup
1768  astProcBegin( proc, FALSE )
1769 
1770  '' push to stmt stack
1771  stk = cCompStmtPush( FB_TK_FUNCTION, FB_CMPSTMT_MASK_DEFAULT or FB_CMPSTMT_MASK_DATA )
1772  stk->proc.tkn = tkn
1773  stk->proc.is_nested = is_nested
1774  stk->proc.endlabel = astGetProcExitlabel( ast.proc.curr )
1775 end sub
1776 
1777 '' ProcStmtEnd = END (SUB | FUNCTION) .
1779  dim as FB_CMPSTMTSTK ptr stk = any
1780  dim as FBSYMBOL ptr proc_res = any
1781 
1782  stk = cCompStmtGetTOS( FB_TK_FUNCTION )
1783  if( stk = NULL ) then
1784  hSkipStmt( )
1785  exit sub
1786  end if
1787 
1788  '' END
1789  lexSkipToken( )
1790 
1791  '' SUB | FUNCTION | ...
1792  if( hMatch( stk->proc.tkn ) = FALSE ) then
1793  select case stk->proc.tkn
1794  case FB_TK_SUB
1795  errReport( FB_ERRMSG_EXPECTEDENDSUB )
1796  case FB_TK_FUNCTION
1797  errReport( FB_ERRMSG_EXPECTEDENDFUNCTION )
1798  case FB_TK_CONSTRUCTOR
1799  errReport( FB_ERRMSG_EXPECTEDENDCTOR )
1800  case FB_TK_DESTRUCTOR
1801  errReport( FB_ERRMSG_EXPECTEDENDDTOR )
1802  case FB_TK_OPERATOR
1803  errReport( FB_ERRMSG_EXPECTEDENDOPERATOR )
1804  case FB_TK_PROPERTY
1805  errReport( FB_ERRMSG_EXPECTEDENDPROPERTY )
1806  end select
1807  end if
1808 
1809  '' function and the result wasn't set?
1810  proc_res = symbGetProcResult( parser.currproc )
1811  if( proc_res <> NULL ) then
1812  if( symbGetIsAccessed( proc_res ) = FALSE ) then
1813  if( symbIsNaked( parser.currproc ) = FALSE ) then
1814  errReportWarn( FB_WARNINGMSG_NOFUNCTIONRESULT )
1815  end if
1816  end if
1817  end if
1818 
1819  '' always finish
1820  astProcEnd( FALSE )
1821 
1822  '' was the namespace changed?
1823  if( stk->proc.is_nested ) then
1824  symbNestEnd( TRUE )
1825  end if
1826 
1827  '' pop from stmt stack
1828  cCompStmtPop( stk )
1829 end sub
1830