FreeBASIC  0.91.0
symb-proc.bas
Go to the documentation of this file.
1 '' symbol table module for procedures
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 '' jan/2005 updated to use real linked-lists [v1ctor]
5 
6 
7 #include once "fb.bi"
8 #include once "fbint.bi"
9 #include once "parser.bi"
10 #include once "hash.bi"
11 #include once "list.bi"
12 #include once "ast.bi"
13 
14 declare function hMangleFunctionPtr _
15  ( _
16  byval proc as FBSYMBOL ptr, _
17  byval dtype as integer, _
18  byval subtype as FBSYMBOL ptr, _
19  byval attrib as integer, _
20  byval mode as integer _
21  ) as zstring ptr
22 
23 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
24 '' init
25 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
26 
27 '':::::
29 
30  symb.globctorlist.head = NULL
31  symb.globctorlist.tail = NULL
32  listInit( @symb.globctorlist.list, 8, len( FB_GLOBCTORLIST_ITEM ), LIST_FLAGS_NOCLEAR )
33 
34  symb.globdtorlist.head = NULL
35  symb.globdtorlist.tail = NULL
36  listInit( @symb.globdtorlist.list, 8, len( FB_GLOBCTORLIST_ITEM ), LIST_FLAGS_NOCLEAR )
37 
38 end sub
39 
40 '':::::
42 
43  listEnd( @symb.globdtorlist.list )
44  listEnd( @symb.globctorlist.list )
45 
46 end sub
47 
48 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
49 '' add
50 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
51 
52 sub symbProcAllocExt( byval proc as FBSYMBOL ptr )
53  assert( symbIsProc( proc ) )
54  if( proc->proc.ext = NULL ) then
55  proc->proc.ext = xcallocate( sizeof( FB_PROCEXT ) )
56  end if
57 end sub
58 
59 sub symbProcFreeExt( byval proc as FBSYMBOL ptr )
60  if( proc->proc.ext ) then
61  deallocate( proc->proc.ext )
62  proc->proc.ext = NULL
63  end if
64 end sub
65 
66 function symbProcReturnsOnStack( byval proc as FBSYMBOL ptr ) as integer
67  assert( symbIsProc( proc ) )
68 
69  '' BYREF result never is on stack, instead it's always a pointer,
70  '' which will always be returned in registers
71  if( symbProcReturnsByref( proc ) ) then
72  exit function
73  end if
74 
75  '' UDT result?
76  if( symbGetType( proc ) = FB_DATATYPE_STRUCT ) then
77  '' Real type is an UDT pointer (instead of INTEGER/LONGINT)?
78  '' Then it's returned on stack (instead of in registers)
79  function = (typeGetDtAndPtrOnly( symbGetProcRealType( proc ) ) = typeAddrOf( FB_DATATYPE_STRUCT ))
80  end if
81 end function
82 
83 function hAlignToPow2 _
84  ( _
85  byval value as longint, _
86  byval align as integer _
87  ) as longint
88  function = (value + (align-1)) and (not (align-1))
89 end function
90 
91 function symbCalcArgLen _
92  ( _
93  byval dtype as integer, _
94  byval subtype as FBSYMBOL ptr, _
95  byval mode as integer _
96  ) as longint
97 
98  select case( mode )
99  case FB_PARAMMODE_BYREF, FB_PARAMMODE_BYDESC
100  return env.pointersize
101  end select
102 
103  '' BYVAL/VARARG
104 
105  select case( typeGetDtAndPtrOnly( dtype ) )
106  case FB_DATATYPE_STRING
107  '' BYVAL strings passed as pointer instead
108  return env.pointersize
109  case FB_DATATYPE_STRUCT
110  '' BYVAL non-trivial UDTs passed BYREF implicitly
111  if( symbCompIsTrivial( subtype ) = FALSE ) then
112  return env.pointersize
113  end if
114  end select
115 
116  function = hAlignToPow2( symbCalcLen( dtype, subtype ), env.pointersize )
117 end function
118 
119 function symbCalcParamLen _
120  ( _
121  byval dtype as integer, _
122  byval subtype as FBSYMBOL ptr, _
123  byval mode as FB_PARAMMODE _
124  ) as longint
125 
126  '' VARARG params have 0 length for now,
127  '' only the VARARG args later have > 0 length...
128  if( mode = FB_PARAMMODE_VARARG ) then
129  function = 0
130  else
131  function = symbCalcArgLen( dtype, subtype, mode )
132  end if
133 
134 end function
135 
136 function symbCalcProcParamsLen( byval proc as FBSYMBOL ptr ) as longint
137  dim as longint length = any
138  dim as FBSYMBOL ptr param = any
139 
140  '' Calculate the sum of the sizes of all "normal" parameters,
141  '' - ignoring any vararg param,
142  '' - including THIS param,
143  '' - excluding the hidden struct result param, if any,
144  '' instead it's handled separately where needed.
145 
146  param = symbGetProcHeadParam( proc )
147  length = 0
148 
149  while( param )
150  '' VARARG params will have 0 (unknown) length,
151  '' thus they do not affect the sum.
152  assert( iif( symbGetParamMode( param ) = FB_PARAMMODE_VARARG, symbGetLen( param ) = 0, TRUE ) )
153 
154  length += symbGetLen( param )
155 
156  param = param->next
157  wend
158 
159  function = length
160 end function
161 
162 '':::::
163 function symbAddProcParam _
164  ( _
165  byval proc as FBSYMBOL ptr, _
166  byval id as zstring ptr, _
167  byval dtype as integer, _
168  byval subtype as FBSYMBOL ptr, _
169  byval mode as integer, _
170  byval attrib as FB_SYMBATTRIB _
171  ) as FBSYMBOL ptr
172 
173  dim as FBSYMBOL ptr param = any
174 
175  function = NULL
176 
177  param = symbNewSymbol( FB_SYMBOPT_PRESERVECASE, NULL, _
178  @proc->proc.paramtb, NULL, _
179  FB_SYMBCLASS_PARAM, _
180  id, NULL, dtype, subtype, attrib )
181  if( param = NULL ) then
182  exit function
183  end if
184 
185  proc->proc.params += 1
186 
187  param->lgt = symbCalcParamLen( dtype, subtype, mode )
188  param->param.mode = mode
189  param->param.optexpr = NULL
190 
191  '' for UDTs, check if not including a byval param to self
192  if( typeGet( dtype ) = FB_DATATYPE_STRUCT ) then
193  if( mode = FB_PARAMMODE_BYVAL ) then
194  if( subtype = symbGetCurrentNamespc( ) ) then
195  symbSetUdtHasRecByvalParam( subtype )
196  end if
197  end if
198  end if
199 
200  function = param
201 end function
202 
204  ( _
205  byval proc as FBSYMBOL ptr, _
206  byval param as FBSYMBOL ptr, _
207  byval optexpr as ASTNODE ptr _
208  )
209 
210  assert( symbIsProc( proc ) )
211  assert( param->class = FB_SYMBCLASS_PARAM )
212 
213  if( optexpr = NULL ) then
214  exit sub
215  end if
216 
217  param->attrib or= FB_SYMBATTRIB_OPTIONAL
218  param->param.optexpr = optexpr
219  proc->proc.optparams += 1
220 
221 end sub
222 
223 '':::::
224 function symbIsProcOverloadOf _
225  ( _
226  byval proc as FBSYMBOL ptr, _
227  byval head_proc as FBSYMBOL ptr _
228  ) as integer
229 
230  dim as FBSYMBOL ptr f = any
231 
232  '' no parent?
233  if( head_proc = NULL ) then
234  return FALSE
235  end if
236 
237  '' same?
238  if( proc = head_proc ) then
239  return TRUE
240  end if
241 
242  '' not overloaded?
243  if( symbIsOverloaded( head_proc ) = FALSE ) then
244  return FALSE
245  end if
246 
247  '' for each overloaded proc..
248  f = symbGetProcOvlNext( head_proc )
249  do while( f <> NULL )
250 
251  '' same?
252  if( proc = f ) then
253  return TRUE
254  end if
255 
256  f = symbGetProcOvlNext( f )
257  loop
258 
259  '' none found..
260  return FALSE
261 
262 end function
263 
264 sub symbProcRecalcRealType( byval proc as FBSYMBOL ptr )
265  dim as integer dtype = any
266  dim as FBSYMBOL ptr subtype = any
267 
268  dtype = symbGetFullType( proc )
269  subtype = symbGetSubtype( proc )
270 
271  if( symbProcReturnsByref( proc ) ) then
272  dtype = typeAddrOf( dtype )
273  end if
274 
275  select case( typeGetDtAndPtrOnly( dtype ) )
276  '' string?
277  case FB_DATATYPE_STRING, FB_DATATYPE_WCHAR
278  '' It's actually a pointer to a string descriptor,
279  '' or in case of wstring, a pointer to a wchar buffer.
280  dtype = typeAddrOf( dtype )
281 
282  '' UDT? follow GCC 3.x's ABI
283  case FB_DATATYPE_STRUCT
284  '' still parsing the struct? patch it later..
285  if( subtype = symbGetCurrentNamespc( ) ) then
286  symbSetUdtHasRecByvalRes( subtype )
287  else
288  dtype = symbGetUDTRetType( subtype )
289 
290  '' If it became an integer or float, forget the subtype,
291  '' that should only be preserved for UDTs and UDT ptrs.
292  if( typeGetDtOnly( dtype ) <> FB_DATATYPE_STRUCT ) then
293  subtype = NULL
294  end if
295  end if
296 
297  end select
298 
299  proc->proc.realdtype = dtype
300  proc->proc.realsubtype = subtype
301 end sub
302 
303 '':::::
304 function hCanOverload _
305  ( _
306  byval proc as FBSYMBOL ptr _
307  ) as integer
308 
309  dim as FBSYMBOL ptr pparam = any
310 
311  '' arg-less?
312  if( symbGetProcParams( proc ) = 0 ) then
313  return TRUE
314  end if
315 
316  '' can't be vararg..
317  pparam = symbGetProcTailParam( proc )
318  if( pparam->param.mode = FB_PARAMMODE_VARARG ) then
319  return FALSE
320  end if
321 
322  '' any AS ANY param?
323  do while( pparam <> NULL )
324  if( pparam->typ = FB_DATATYPE_VOID ) then
325  return FALSE
326  end if
327 
328  pparam = pparam->prev
329  loop
330 
331  function = TRUE
332 
333 end function
334 
335 '':::::
336 function hAddOvlProc _
337  ( _
338  byval proc as FBSYMBOL ptr, _
339  byval ovl_head_proc as FBSYMBOL ptr, _
340  byval symtb as FBSYMBOLTB ptr, _
341  byval hashtb as FBHASHTB ptr, _
342  byval id as const zstring ptr, _
343  byval id_alias as const zstring ptr, _
344  byval dtype as integer, _
345  byval subtype as FBSYMBOL ptr, _
346  byval attrib as FB_SYMBATTRIB, _
347  byval preservecase as integer _
348  ) as FBSYMBOL ptr
349 
350  dim as FBSYMBOL ptr ovl = any, ovl_param = any, param = any
351  dim as integer ovl_params = any, params = any
352 
353  function = NULL
354 
355  if( ovl_head_proc = NULL ) then
356  exit function
357  end if
358 
359  '' only one them is a property?
360  if( ((attrib and FB_SYMBATTRIB_PROPERTY) <> 0) <> symbIsProperty( ovl_head_proc ) ) then
361  exit function
362  end if
363 
364  '' not arg-less?
365  params = symbGetProcParams( proc )
366  if( (attrib and FB_SYMBATTRIB_METHOD) <> 0 ) then
367  params -= 1
368  end if
369 
370  if( params > 0 ) then
371  '' can't be vararg..
372  param = symbGetProcTailParam( proc )
373  if( param->param.mode = FB_PARAMMODE_VARARG ) then
374  exit function
375  end if
376 
377  '' any AS ANY param?
378  do while( param <> NULL )
379  if( param->typ = FB_DATATYPE_VOID ) then
380  exit function
381  end if
382 
383  param = param->prev
384  loop
385  end if
386 
387  '' for each overloaded proc..
388  ovl = ovl_head_proc
389  do
390  ovl_params = ovl->proc.params
391  if( symbIsMethod( ovl ) ) then
392  ovl_params -= 1
393  end if
394 
395  '' property? handle get/set accessors dups
396  if( (attrib and FB_SYMBATTRIB_PROPERTY) <> 0 ) then
397  '' get?
398  if( dtype <> FB_DATATYPE_VOID ) then
399  '' don't check if it's set
400  if( symbGetType( ovl ) = FB_DATATYPE_VOID ) then
401  ovl_params = -1
402  end if
403  '' set..
404  else
405  '' don't check if it's get
406  if( symbGetType( ovl ) <> FB_DATATYPE_VOID ) then
407  ovl_params = -1
408  end if
409  end if
410  end if
411 
412  '' same number of params?
413  if( ovl_params = params ) then
414  '' both arg-less?
415  if( params = 0 ) then
416  exit function
417  end if
418 
419  '' for each arg..
420  '' (note: cycling backwards, starting with the tail param,
421  '' because a THIS instance param may have been removed from
422  '' the ovl_params count above)
423  param = symbGetProcTailParam( proc )
424  ovl_param = symbGetProcTailParam( ovl )
425 
426  do
427  '' different modes?
428  if( param->param.mode <> ovl_param->param.mode ) then
429  '' one is by desc? allow byref and byval args
430  '' with the same type or subtype
431  if( param->param.mode = FB_PARAMMODE_BYDESC ) then
432  exit do
433  elseif( ovl_param->param.mode = FB_PARAMMODE_BYDESC ) then
434  exit do
435  end if
436  end if
437 
438  dim as integer pdtype = param->typ
439  dim as integer odtype = ovl_param->typ
440 
441  '' check the const qualifier
442  if( (typeGetConstMask( pdtype ) or _
443  typeGetConstMask( odtype )) <> 0 ) then
444 
445  '' both byref?
446  if( (param->param.mode = FB_PARAMMODE_BYREF ) _
447  and (ovl_param->param.mode = FB_PARAMMODE_BYREF )) then
448 
449  if( typeGetConstMask( pdtype ) <> _
450  typeGetConstMask( odtype ) ) then
451  exit do
452  end if
453 
454  endif
455 
456  '' else only matters if it's a 'const ptr' (as in C++)
457  if( typeGetPtrConstMask( pdtype ) <> _
458  typeGetPtrConstMask( odtype ) ) then
459  exit do
460  end if
461 
462  pdtype = typeGetDtAndPtrOnly( pdtype )
463  odtype = typeGetDtAndPtrOnly( odtype )
464  end if
465 
466  '' not the same type? check next proc..
467  if( pdtype <> odtype ) then
468 
469  '' handle special cases: zstring ptr and string args
470  select case pdtype
471  case typeAddrOf( FB_DATATYPE_CHAR )
472  if( odtype <> FB_DATATYPE_STRING ) then
473  exit do
474  end if
475 
476  case FB_DATATYPE_STRING
477  if( odtype <> typeAddrOf( FB_DATATYPE_CHAR ) ) then
478  exit do
479  end if
480 
481  case else
482  exit do
483  end select
484  end if
485 
486  if( param->subtype <> ovl_param->subtype ) then
487  exit do
488  end if
489 
490  param = param->prev
491  ovl_param = ovl_param->prev
492 
493  ovl_params -= 1
494  loop while( ovl_params > 0 )
495 
496  '' all params equal? can't overload..
497  if( ovl_params = 0 ) then
498  exit function
499  end if
500  end if
501 
502  ovl = symbGetProcOvlNext( ovl )
503  loop while( ovl <> NULL )
504 
505  '' add the new proc symbol, w/o adding it to the hash table
506  proc = symbNewSymbol( iif( preservecase, FB_SYMBOPT_PRESERVECASE, FB_SYMBOPT_NONE ), _
507  proc, symtb, hashtb, FB_SYMBCLASS_PROC, id, id_alias, dtype, subtype, attrib )
508  if( proc = NULL ) then
509  exit function
510  end if
511 
512  '' add to hash chain list, as they share the same name
513  if( id <> NULL ) then
514  dim as FBSYMBOL ptr nxt = any
515 
516  proc->hash.index = ovl_head_proc->hash.index
517  proc->hash.item = ovl_head_proc->hash.item
518 
519  nxt = ovl_head_proc->hash.next
520  ovl_head_proc->hash.next = proc
521 
522  proc->hash.prev = ovl_head_proc
523  proc->hash.next = nxt
524  if( nxt <> NULL ) then
525  nxt->hash.prev = proc
526  end if
527  end if
528 
529  function = proc
530 
531 end function
532 
533 '':::::
534 function hAddOpOvlProc _
535  ( _
536  byval proc as FBSYMBOL ptr, _
537  byval ovl_head_proc as FBSYMBOL ptr, _
538  byval symtb as FBSYMBOLTB ptr, _
539  byval hashtb as FBHASHTB ptr, _
540  byval op as AST_OP, _
541  byval id_alias as const zstring ptr, _
542  byval dtype as integer, _
543  byval subtype as FBSYMBOL ptr, _
544  byval attrib as FB_SYMBATTRIB _
545  ) as FBSYMBOL ptr
546 
547  dim as FBSYMBOL ptr ovl = any
548 
549  '' if it's not the type casting op, overloaded as an ordinary proc
550  if( op <> AST_OP_CAST ) then
551  return hAddOvlProc( proc, ovl_head_proc, symtb, hashtb, NULL, id_alias, _
552  dtype, subtype, attrib, FALSE )
553  end if
554 
555  '' type casting, must check the return type, not the parameter..
556 
557  '' for each overloaded proc..
558  ovl = ovl_head_proc
559  do while( ovl <> NULL )
560 
561  '' same type?
562  if( proc->typ = ovl->typ ) then
563  '' and sub-type?
564  if( proc->subtype = ovl->subtype ) then
565  '' dup definition..
566  return NULL
567  end if
568  end if
569 
570  '' next
571  ovl = symbGetProcOvlNext( ovl )
572  loop
573 
574  '' add it
575  proc = symbNewSymbol( FB_SYMBOPT_NONE, proc, symtb, hashtb, _
576  FB_SYMBCLASS_PROC, NULL, id_alias, dtype, subtype, attrib )
577 
578  '' there's no id so it can't be added to the chain list
579 
580  function = proc
581 
582 end function
583 
584 function hSetupProc _
585  ( _
586  byval sym as FBSYMBOL ptr, _
587  byval parent as FBSYMBOL ptr, _
588  byval symtb as FBSYMBOLTB ptr, _
589  byval hashtb as FBHASHTB ptr, _
590  byval id as const zstring ptr, _
591  byval id_alias as const zstring ptr, _
592  byval dtype as integer, _
593  byval subtype as FBSYMBOL ptr, _
594  byval attrib as integer, _
595  byval mode as integer, _
596  byval options as FB_SYMBOPT _
597  ) as FBSYMBOL ptr
598 
599  dim as integer stats = any, preserve_case = any, lookupoptions = any
600  dim as FBSYMBOL ptr proc = any, head_proc = any, overridden = any
601 
602  function = NULL
603 
604 #if __FB_DEBUG__
605  '' Member procs generally must have either STATIC or METHOD attributes,
606  '' and cannot have both, but there can be proc symbols added to an
607  '' UDT namespace that have neither, for example proc symbols backing
608  '' procptrs or the dtor call wrapper procs created for static vars
609  '' declared inside methods.
610  if( attrib and FB_SYMBATTRIB_METHOD ) then
611  assert( (attrib and FB_SYMBATTRIB_STATIC) = 0 )
612  assert( symbIsStruct( parent ) )
613  elseif( attrib and FB_SYMBATTRIB_STATIC ) then
614  assert( (attrib and FB_SYMBATTRIB_METHOD) = 0 )
615  assert( symbIsStruct( parent ) )
616  end if
617 #endif
618 
619  ''
620  if( dtype = FB_DATATYPE_INVALID ) then
621  dtype = symbGetDefType( id )
622  subtype = NULL
623  end if
624 
625  '' no explict alias?
626  if( id_alias = NULL ) then
627  '' only preserve a case-sensitive version if in BASIC mangling
628  if( parser.mangling <> FB_MANGLING_BASIC ) then
629  id_alias = id
630  end if
631  stats = 0
632  else
633  stats = FB_SYMBSTATS_HASALIAS
634  end if
635 
636  head_proc = NULL
637 
638  '' ctor/dtor?
639  if( (attrib and (FB_SYMBATTRIB_CONSTRUCTOR or _
640  FB_SYMBATTRIB_DESTRUCTOR)) <> 0 ) then
641 
642  assert( attrib and FB_SYMBATTRIB_METHOD )
643 
644  '' ctor?
645  if( (attrib and FB_SYMBATTRIB_CONSTRUCTOR) <> 0 ) then
646  head_proc = symbGetCompCtorHead( parent )
647  else
648  head_proc = symbGetCompDtor( parent )
649  end if
650 
651  '' not overloaded yet? just add it
652  if( head_proc = NULL ) then
653  proc = symbNewSymbol( FB_SYMBOPT_NONE, sym, symtb, hashtb, _
654  FB_SYMBCLASS_PROC, NULL, id_alias, _
655  FB_DATATYPE_VOID, NULL, attrib )
656 
657  '' ctor?
658  if( (attrib and FB_SYMBATTRIB_CONSTRUCTOR) <> 0 ) then
660  else
662  end if
663  '' otherwise, try to overload
664  else
665  '' dtor?
666  if( (attrib and FB_SYMBATTRIB_DESTRUCTOR) <> 0 ) then
667  '' can't overload
668  return NULL
669  end if
670 
671  proc = hAddOvlProc( sym, head_proc, symtb, hashtb, NULL, id_alias, _
672  FB_DATATYPE_VOID, NULL, attrib, FALSE )
673  if( proc = NULL ) then
674  exit function
675  end if
676  end if
677 
678  '' ctor? check for special ctors..
679  if( (attrib and FB_SYMBATTRIB_CONSTRUCTOR) <> 0 ) then
681  end if
682 
683  '' operator?
684  elseif( (attrib and FB_SYMBATTRIB_OPERATOR) <> 0 ) then
685 
686  '' op not set? (because error recovery)
687  if( sym->proc.ext = NULL ) then
688  goto add_proc
689  end if
690 
691  dim as AST_OP op
692 
693  op = symbGetProcOpOvl( sym )
694 
695  head_proc = symbGetCompOpOvlHead( parent, op )
696 
697  '' not overloaded yet? just add it
698  if( head_proc = NULL ) then
699  proc = symbNewSymbol( FB_SYMBOPT_NONE, sym, symtb, hashtb, _
700  FB_SYMBCLASS_PROC, NULL, id_alias, _
701  dtype, subtype, attrib )
702 
704 
705  '' otherwise, try to overload
706  else
707  proc = hAddOpOvlProc( sym, head_proc, symtb, hashtb, op, id_alias, _
708  dtype, subtype, attrib )
709  if( proc = NULL ) then
710  exit function
711  end if
712 
713  '' assign? could be a clone..
714  if( op = AST_OP_ASSIGN ) then
716  end if
717  end if
718 
719  '' ordinary proc..
720  else
721 add_proc:
722 
723  preserve_case = (options and FB_SYMBOPT_PRESERVECASE) <> 0
724 
725  proc = symbNewSymbol( options or FB_SYMBOPT_DOHASH, sym, symtb, hashtb, _
726  FB_SYMBCLASS_PROC, id, id_alias, dtype, subtype, attrib )
727 
728  '' dup def?
729  if( proc = NULL ) then
730  '' is the dup a proc symbol?
731  head_proc = symbLookupByNameAndClass( parent, id, FB_SYMBCLASS_PROC, preserve_case, FALSE )
732  if( head_proc = NULL ) then
733  exit function
734  end if
735 
736  '' proc was defined as overloadable?
737  if( symbIsOverloaded( head_proc ) = FALSE ) then
738  if( fbLangOptIsSet( FB_LANG_OPT_ALWAYSOVL ) = FALSE ) then
739  exit function
740  end if
741  end if
742 
743  '' try to overload..
744  proc = hAddOvlProc( sym, head_proc, symtb, hashtb, id, id_alias, _
745  dtype, subtype, attrib, preserve_case )
746  if( proc = NULL ) then
747  exit function
748  end if
749 
750  proc->attrib or= FB_SYMBATTRIB_OVERLOADED
751 
752  else
753  '' only if not the RTL
754  if( (options and FB_SYMBOPT_RTL) = 0 ) then
755  '' check overloading
756  if( (attrib and FB_SYMBATTRIB_OVERLOADED) <> 0 ) then
757  if( hCanOverload( sym ) = FALSE ) then
758  exit function
759  end if
760 
761  elseif( fbLangOptIsSet( FB_LANG_OPT_ALWAYSOVL ) ) then
762  if( hCanOverload( sym ) ) then
763  proc->attrib or= FB_SYMBATTRIB_OVERLOADED
764  end if
765  end if
766  end if
767  end if
768 
769  end if
770 
771  if( (options and FB_SYMBOPT_RTL) <> 0 ) then
772  stats or= FB_SYMBSTATS_RTL
773  end if
774 
775  ''
776  proc->proc.mode = mode
777 
778  '' last compound was an EXTERN?
779  if( fbGetCompStmtId( ) = FB_TK_EXTERN ) then
780  '' don't add parent when mangling, even if inside an UDT, unless
781  '' it's in "c++" mode
782  if( parser.mangling <> FB_MANGLING_CPP ) then
783  stats or= FB_SYMBSTATS_EXCLPARENT
784  end if
785  end if
786 
788 
789  if( (options and FB_SYMBOPT_DECLARING) <> 0 ) then
790  stats or= FB_SYMBSTATS_DECLARED
791  end if
792 
793  proc->proc.rtl.callback = NULL
794 
795  '' if overloading, update the linked-list
796  if( symbIsOverloaded( proc ) ) then
797  dim as integer params = symbGetProcParams( proc )
798 
799  '' note: min and max params don't count the instance ptr
800  if( symbIsMethod( proc ) ) then
801  params -= 1
802  end if
803 
804  if( head_proc <> NULL ) then
805  proc->proc.ovl.next = head_proc->proc.ovl.next
806  head_proc->proc.ovl.next = proc
807 
808  if( params < symGetProcOvlMinParams( head_proc ) ) then
809  symGetProcOvlMinParams( head_proc ) = params
810  end if
811 
812  if( params > symGetProcOvlMaxParams( head_proc ) ) then
813  symGetProcOvlMaxParams( head_proc ) = params
814  end if
815 
816  else
817  proc->proc.ovl.next = NULL
818  symGetProcOvlMinParams( proc ) = params
819  symGetProcOvlMaxParams( proc ) = params
820  end if
821  end if
822 
823  proc->stats or= stats
824 
825  '' Adding method to UDT?
826  if( symbIsMethod( proc ) ) then
827  assert( symbIsStruct( parent ) )
828 
829  '' Adding an ABSTRACT? Increase ABSTRACT count
830  if( symbIsAbstract( proc ) ) then
831  parent->udt.ext->abstractcount += 1
832  end if
833 
834  '' Only check if this really is a derived UDT
835  overridden = NULL
836  if( parent->udt.base ) then
837  '' Destructor?
838  if( symbIsDestructor( proc ) ) then
839  '' There can always only be one, so there is no
840  '' need to do a lookup and/or overload checks.
841  overridden = symbGetCompDtor( parent->udt.base->subtype )
842  elseif( symbIsOperator( proc ) ) then
843  '' Get the corresponding operator from the base
844  '' (actually a chain of overloads for that particular operator)
845  overridden = symbGetCompOpOvlHead( parent->udt.base->subtype, _
846  symbGetProcOpOvl( proc ) )
847 
848  '' Find the overload with the exact same signature
849  overridden = symbFindOpOvlProc( symbGetProcOpOvl( proc ), overridden, proc )
850  elseif( id ) then
851  '' If this method has the same id and signature as
852  '' a virtual derived from some base, it overrides that
853  '' virtual, by being assigned the same vtable index.
854 
855  '' Find a method in the base with the same name
856  overridden = symbLookupByNameAndClass( _
857  parent->udt.base->subtype, _
858  id, FB_SYMBCLASS_PROC, _
859  ((options and FB_SYMBOPT_PRESERVECASE) <> 0), _
860  TRUE ) '' search NSIMPORTs (bases)
861 
862  '' Property getters need this special flag to be looked up
863  lookupoptions = 0
864  if( symbIsProperty( proc ) ) then
865  '' Not a sub?
866  if( symbGetType( proc ) <> FB_DATATYPE_VOID ) then
867  '' then it's a getter
868  lookupoptions = FB_SYMBLOOKUPOPT_PROPGET
869  end if
870  end if
871 
872  '' Find the overload with the exact same signature
873  overridden = symbFindOverloadProc( overridden, proc, lookupoptions )
874  end if
875 
876  '' Found anything?
877  if( overridden ) then
878  '' Only override if the found overload really is a virtual
879  if( symbIsVirtual( overridden ) = FALSE ) then
880  overridden = NULL
881  end if
882  end if
883  end if
884 
885  if( overridden ) then
886  '' Overriding an ABSTRACT? Decrease ABSTRACT count
887  if( symbIsAbstract( overridden ) ) then
888  parent->udt.ext->abstractcount -= 1
889  end if
890 
891  '' Use the same vtable slot as the virtual that's being overridden
893  proc->proc.ext->overridden = overridden
894  else
895  '' Allocate a *new* vtable slot, but only if this is a virtual,
896  '' and it didn't override anything (thus doesn't reuse a vtable slot).
897  if( symbIsVirtual( proc ) ) then
899  end if
900  end if
901  end if
902 
903  function = proc
904 end function
905 
906 function symbAddProc _
907  ( _
908  byval proc as FBSYMBOL ptr, _
909  byval id as const zstring ptr, _
910  byval id_alias as const zstring ptr, _
911  byval dtype as integer, _
912  byval subtype as FBSYMBOL ptr, _
913  byval attrib as integer, _
914  byval mode as integer, _
915  byval options as FB_SYMBOPT _
916  ) as FBSYMBOL ptr
917 
918  dim as FBSYMBOL ptr parent = any
919  dim as FBSYMBOLTB ptr symtb = any
920  dim as FBHASHTB ptr hashtb = any
921 
922  '' Procedure prototypes are always added to the current namespace,
923  '' the current scope is ignored here -- they're not allowed inside
924  '' scopes anyways.
925  parent = symbGetCurrentNamespc( )
926  symtb = @symbGetCompSymbTb( parent )
927  hashtb = @symbGetCompHashTb( parent )
928 
929  '' Procedures are always "globals", assuming that local/nested
930  '' procedures aren't allowed
931  attrib or= FB_SYMBATTRIB_SHARED
932  assert( (proc->attrib and FB_SYMBATTRIB_LOCAL) = 0 )
933  assert( (attrib and FB_SYMBATTRIB_LOCAL) = 0 )
934 
935  function = hSetupProc( proc, parent, symtb, hashtb, id, id_alias, _
936  dtype, subtype, attrib, mode, options )
937 
938 end function
939 
940 function symbAddOperator _
941  ( _
942  byval proc as FBSYMBOL ptr, _
943  byval op as AST_OP, _
944  byval id_alias as zstring ptr, _
945  byval dtype as integer, _
946  byval subtype as FBSYMBOL ptr, _
947  byval attrib as integer, _
948  byval mode as integer, _
949  byval options as FB_SYMBOPT _
950  ) as FBSYMBOL ptr
951 
952  dim as FBSYMBOL ptr sym = any
953 
955  proc->proc.ext->opovl.op = op
956 
957  sym = symbAddProc( proc, NULL, id_alias, dtype, subtype, attrib, mode, options )
958  if( sym = NULL ) then
960  exit function
961  end if
962 
963  function = sym
964 end function
965 
966 function symbAddCtor _
967  ( _
968  byval proc as FBSYMBOL ptr, _
969  byval id_alias as zstring ptr, _
970  byval attrib as integer, _
971  byval mode as integer, _
972  byval options as FB_SYMBOPT _
973  ) as FBSYMBOL ptr
974  function = symbAddProc( proc, NULL, id_alias, FB_DATATYPE_VOID, NULL, attrib, mode, options )
975 end function
976 
977 function symbAddProcPtr _
978  ( _
979  byval proc as FBSYMBOL ptr, _
980  byval dtype as integer, _
981  byval subtype as FBSYMBOL ptr, _
982  byval attrib as integer, _
983  byval mode as integer _
984  ) as FBSYMBOL ptr
985 
986  dim as zstring ptr id = any
987  dim as FBSYMCHAIN ptr chain_ = any
988  dim as FBSYMBOL ptr sym = any, parent = any
989  dim as FBSYMBOLTB ptr symtb = any
990  dim as FBHASHTB ptr hashtb = any
991 
992  ''
993  '' The procptr prototypes are mangled, allowing them to be re-used.
994  ''
995  '' This must be done in order to make equal procptrs use the same proto
996  '' symbol for their subtype, because we're doing type equality checks
997  '' via "dtype = dtype" and "subtype = subtype". There is no special
998  '' equality check for procptrs, hence this mangling must ensure that
999  '' equal procptrs re-use the same proto symbols.
1000  ''
1001  '' New procptr PROC symbols should be added to the current scope,
1002  '' because they themselves may reference symbols from the current scope,
1003  '' e.g. UDTs used in parameters/result type. It wouldn't be safe to
1004  '' add them to the global namespace in this case, because the symbols
1005  '' in a scope do not live as long as those from the global namespace.
1006  ''
1007  '' Besides that, the mangling below doesn't differentiate between two
1008  '' UDTs with the same name but from different scopes, so it may produce
1009  '' the same mangled id for two procptrs that have different type. This
1010  '' also requires them to be scoped locally.
1011  ''
1012 
1013  id = hMangleFunctionPtr( proc, dtype, subtype, attrib, mode )
1014 
1015  if( parser.scope = FB_MAINSCOPE ) then
1016  '' When outside scopes, it's a global, because whichever symbol
1017  '' uses this procptr proto can be globally visible (global vars,
1018  '' procs, etc.)
1019  parent = @symbGetGlobalNamespc( )
1020  symtb = @symbGetCompSymbTb( parent )
1021  hashtb = @symbGetCompHashTb( parent )
1022 
1023  attrib or= FB_SYMBATTRIB_SHARED
1024  assert( (proc->attrib and FB_SYMBATTRIB_LOCAL) = 0 )
1025  assert( (attrib and FB_SYMBATTRIB_LOCAL) = 0 )
1026  else
1027  '' If inside a scope, make the procptr proto local too, because
1028  '' it could use local symbols, while it itself can only be used
1029  '' by local symbols, not by globals (globals cannot be declared
1030  '' inside scopes).
1031  parent = symbGetCurrentNamespc( )
1032  symtb = symb.symtb '' symtb of current scope
1033  hashtb = @symbGetCompHashTb( parent ) '' hashtb of current namespace
1034  assert( hashtb = symb.hashtb )
1035 
1036  attrib or= FB_SYMBATTRIB_LOCAL
1037  assert( (proc->attrib and FB_SYMBATTRIB_SHARED) = 0 )
1038  assert( (attrib and FB_SYMBATTRIB_SHARED) = 0 )
1039  end if
1040 
1041  '' already exists? (it's ok to use LookupAt, literal str's are always
1042  '' prefixed with {fbsc}, there will be no clashes with func ptr mangled names)
1043  chain_ = symbLookupAt( parent, id, TRUE, FALSE )
1044  if( chain_ <> NULL ) then
1045  return chain_->sym
1046  end if
1047 
1048  '' create a new prototype
1049  sym = hSetupProc( proc, parent, symtb, hashtb, id, symbUniqueId( ), _
1050  dtype, subtype, attrib, mode, _
1051  FB_SYMBOPT_DECLARING or FB_SYMBOPT_PRESERVECASE )
1052 
1053  if( sym <> NULL ) then
1054  symbSetIsFuncPtr( sym )
1055  end if
1056 
1057  function = sym
1058 end function
1059 
1060 '':::::
1062  ( _
1063  byval base_proc as FBSYMBOL ptr _
1064  ) as FBSYMBOL ptr
1065 
1066  var proc = symbPreAddProc( NULL )
1067 
1068  proc->proc.returnMethod = base_proc->proc.returnMethod
1069 
1070  '' params
1071  var param = symbGetProcHeadParam( base_proc )
1072  do while( param <> NULL )
1073  var p = symbAddProcParam( proc, NULL, _
1074  symbGetFullType( param ), _
1075  symbGetSubtype( param ), _
1076  symbGetParamMode( param ), _
1077  symbGetAttrib( param ) )
1078 
1079  if( symbGetDontInit( param ) ) then
1080  symbSetDontInit( p )
1081  end if
1082 
1083  symbMakeParamOptional( proc, p, param->param.optexpr )
1084 
1085  param = param->next
1086  loop
1087 
1088  function = symbAddProcPtr( proc, _
1089  symbGetFullType( base_proc ), symbGetSubtype( base_proc ), _
1090  base_proc->attrib and FB_SYMBATTRIB_RETURNSBYREF, _ '' preserve RETURNSBYREF
1091  symbGetProcMode( base_proc ) )
1092 
1093 end function
1094 
1095 function symbPreAddProc( byval symbol as zstring ptr ) as FBSYMBOL ptr
1096  dim as FBSYMBOL ptr proc = any
1097 
1098  proc = listNewNode( @symb.symlist )
1099 
1100  proc->class = FB_SYMBCLASS_PROC
1101  proc->attrib = 0
1102  proc->stats = 0
1103  proc->id.name = symbol
1104  proc->id.alias = NULL
1105  proc->id.mangled = NULL
1106  proc->typ = FB_DATATYPE_INVALID
1107  proc->subtype = NULL
1108  proc->scope = 0
1109  proc->mangling = FB_MANGLING_BASIC
1110  proc->lgt = 0
1111  proc->ofs = 0
1112 
1113  proc->proc.params = 0
1114  proc->proc.optparams = 0
1115  symbSymbTbInit( proc->proc.paramtb, proc )
1116  proc->proc.mode = env.target.fbcall
1117  proc->proc.realdtype = FB_DATATYPE_INVALID
1118  proc->proc.realsubtype = NULL
1119  proc->proc.returnMethod = FB_RETURN_FPU
1120  proc->proc.rtl.callback = NULL
1121  proc->proc.ovl.minparams = 0
1122  proc->proc.ovl.maxparams = 0
1123  proc->proc.ovl.next = NULL
1124  proc->proc.ext = NULL
1125 
1126  '' to allow getNamespace() and GetParent() to work
1127  proc->symtb = @symbGetCompSymbTb( symbGetCurrentNamespc( ) )
1128  proc->hash.tb = @symbGetCompHashTb( symbGetCurrentNamespc( ) )
1129  proc->hash.item = NULL
1130  proc->hash.index = 0
1131  proc->hash.prev = NULL
1132  proc->hash.next = NULL
1133 
1134  proc->parent = NULL
1135  proc->prev = NULL
1136  proc->next = NULL
1137 
1138  function = proc
1139 end function
1140 
1142  ( _
1143  byval parammode as integer, _
1144  byref dtype as integer, _
1145  byref subtype as FBSYMBOL ptr _
1146  )
1147 
1148  select case( parammode )
1149  case FB_PARAMMODE_BYVAL
1150  select case( dtype )
1151  '' byval string? it's actually an pointer to a zstring
1152  case FB_DATATYPE_STRING
1153  dtype = typeAddrOf( FB_DATATYPE_CHAR )
1154 
1155  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
1156  '' non-trivial classes are always passed byref
1157  if( symbCompIsTrivial( subtype ) = FALSE ) then
1158  dtype = typeAddrOf( dtype )
1159  end if
1160  end select
1161 
1162  case FB_PARAMMODE_BYREF
1163  dtype = typeAddrOf( dtype )
1164 
1165  case FB_PARAMMODE_BYDESC
1166  dtype = typeAddrOf( FB_DATATYPE_STRUCT )
1167  subtype = symb.fbarray
1168  end select
1169 
1170 end sub
1171 
1172 function symbAddVarForParam( byval param as FBSYMBOL ptr ) as FBSYMBOL ptr
1173  dim as FBARRAYDIM dTB(0) = any
1174  dim as FBSYMBOL ptr s = any
1175  dim as integer attrib = any, dtype = any
1176 
1177  function = NULL
1178 
1179  dtype = symbGetFullType( param )
1180 
1181  select case as const param->param.mode
1182  case FB_PARAMMODE_BYVAL
1183  attrib = FB_SYMBATTRIB_PARAMBYVAL
1184 
1185  select case( symbGetType( param ) )
1186  '' byval string? it's actually an pointer to a zstring
1187  case FB_DATATYPE_STRING
1188  attrib = FB_SYMBATTRIB_PARAMBYREF
1189  dtype = typeJoin( dtype, FB_DATATYPE_CHAR )
1190 
1191  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
1192  '' has a dtor, copy ctor or virtual methods? it's a copy..
1193  if( symbCompIsTrivial( symbGetSubtype( param ) ) = FALSE ) then
1194  attrib = FB_SYMBATTRIB_PARAMBYREF
1195  end if
1196  end select
1197 
1198  case FB_PARAMMODE_BYREF
1199  attrib = FB_SYMBATTRIB_PARAMBYREF
1200 
1201  case FB_PARAMMODE_BYDESC
1202  attrib = FB_SYMBATTRIB_PARAMBYDESC
1203 
1204  case else
1205  exit function
1206  end select
1207 
1208  '' "this"?
1209  if( symbIsParamInstance( param ) ) then
1210  attrib or= FB_SYMBATTRIB_PARAMINSTANCE
1211  end if
1212 
1213  '' QB quirk..
1214  if( symbIsSuffixed( param ) ) then
1215  attrib or= FB_SYMBATTRIB_SUFFIXED
1216  end if
1217 
1218  s = symbAddVar( symbGetName( param ), NULL, dtype, param->subtype, 0, 0, dTB(), attrib )
1219  if( s = NULL ) then
1220  exit function
1221  end if
1222 
1223  '' declare it or arrays passed by descriptor will be initialized when REDIM'd
1224  symbSetIsDeclared( s )
1225 
1226  if( symbGetDontInit( param ) ) then
1227  symbSetDontInit( s )
1228  end if
1229 
1230  function = s
1231 end function
1232 
1233 function symbAddProcResultParam( byval proc as FBSYMBOL ptr ) as FBSYMBOL ptr
1234  dim as FBARRAYDIM dTB(0) = any
1235  dim as FBSYMBOL ptr s = any
1236  static as string id
1237 
1238  if( symbProcReturnsOnStack( proc ) = FALSE ) then
1239  return NULL
1240  end if
1241 
1242  id = *symbUniqueId( )
1243  s = symbAddVar( id, NULL, FB_DATATYPE_STRUCT, proc->subtype, 0, _
1244  0, dTB(), FB_SYMBATTRIB_PARAMBYREF, FB_SYMBOPT_PRESERVECASE )
1245 
1247  proc->proc.ext->res = s
1248 
1249  symbSetIsDeclared( s )
1250  symbSetIsImplicit( s )
1251 
1252  function = s
1253 end function
1254 
1255 function symbAddProcResult( byval proc as FBSYMBOL ptr ) as FBSYMBOL ptr
1256  dim as FBARRAYDIM dTB(0) = any
1257  dim as FBSYMBOL ptr res = any
1258  dim as integer dtype = any
1259  dim as const zstring ptr id = any
1260 
1261  '' UDT on stack? No local result var needs to be added;
1262  '' the hidden result param is used instead.
1263  if( symbProcReturnsOnStack( proc ) ) then
1264  return symbGetProcResult( proc )
1265  end if
1266 
1267  dtype = proc->typ
1268 
1269  '' Returning byref? Then the implicit result var is actually a pointer.
1270  if( symbProcReturnsByref( proc ) ) then
1271  dtype = typeAddrOf( dtype )
1272  end if
1273 
1274  res = symbAddVar( @"fb$result", NULL, dtype, proc->subtype, 0, _
1275  0, dTB(), FB_SYMBATTRIB_FUNCRESULT, FB_SYMBOPT_PRESERVECASE )
1276 
1278 
1279  proc->proc.ext->res = res
1280 
1281  '' clear up the result
1282  astAdd( astNewDECL( res, TRUE ) )
1283 
1284  symbSetIsDeclared( res )
1285  symbSetIsImplicit( res )
1286 
1287  function = res
1288 end function
1289 
1290 '':::::
1292  ( _
1293  byval parent as FBSYMBOL ptr, _
1294  byval proc as FBSYMBOL ptr _
1295  )
1296 
1297  dim as integer dtype = any
1298  select case symbGetClass( parent )
1299  case FB_SYMBCLASS_STRUCT
1300  dtype = FB_DATATYPE_STRUCT
1301  case FB_SYMBCLASS_CLASS
1302  'dtype = FB_DATATYPE_CLASS
1303  end select
1304 
1305  if( symbIsConstant( proc ) ) then
1306  dtype = typeSetIsConst( dtype )
1307  end if
1308 
1309  symbAddProcParam( proc, FB_INSTANCEPTR, dtype, parent, _
1310  FB_PARAMMODE_BYREF, FB_SYMBATTRIB_PARAMINSTANCE )
1311 end sub
1312 
1313 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1314 '' lookup
1315 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1316 
1317 '':::::
1318 function symbFindOverloadProc _
1319  ( _
1320  byval ovl_head_proc as FBSYMBOL ptr, _
1321  byval proc as FBSYMBOL ptr, _
1322  byval options as FB_SYMBLOOKUPOPT _
1323  ) as FBSYMBOL ptr
1324 
1325  dim as FBSYMBOL ptr ovl = any, ovl_param = any, param = any
1326  dim as FBSYMBOL ptr ovl_subtype = any, subtype = any
1327  dim as integer ovl_params = any, params = any, i = any
1328 
1329  ''
1330  if( (ovl_head_proc = NULL) or (proc = NULL) ) then
1331  return NULL
1332  end if
1333 
1334  '' procs?
1335  if( (symbGetClass( ovl_head_proc ) <> FB_SYMBCLASS_PROC) or _
1336  (symbGetClass( proc ) <> FB_SYMBCLASS_PROC) ) then
1337  return NULL
1338  end if
1339 
1340  params = symbGetProcParams( proc )
1341  if( symbIsMethod( proc ) ) then
1342  params -= 1
1343  end if
1344 
1345  dim as integer is_property = symbIsProperty( ovl_head_proc )
1346 
1347  '' for each proc starting from parent..
1348  ovl = ovl_head_proc
1349  do
1350 
1351  ovl_params = ovl->proc.params
1352  if( symbIsMethod( ovl ) ) then
1353  ovl_params -= 1
1354  end if
1355 
1356  '' property? handle get/set accessors dups
1357  if( is_property ) then
1358  '' get?
1359  if( (options and FB_SYMBLOOKUPOPT_PROPGET) <> 0 ) then
1360  '' don't check if it's set
1361  if( symbGetType( ovl ) = FB_DATATYPE_VOID ) then
1362  ovl_params = -1
1363  end if
1364  '' set..
1365  else
1366  '' don't check if it's get
1367  if( symbGetType( ovl ) <> FB_DATATYPE_VOID ) then
1368  ovl_params = -1
1369  end if
1370  end if
1371  end if
1372 
1373  if( params = ovl_params ) then
1374 
1375  '' arg-less?
1376  if( params = 0 ) then
1377  return ovl
1378  end if
1379 
1380  '' for each arg..
1381  '' (Note: cycling backwards, ditto)
1382  ovl_param = symbGetProcTailParam( ovl )
1383  param = symbGetProcTailParam( proc )
1384  do
1385  '' different modes?
1386  if( param->param.mode <> ovl_param->param.mode ) then
1387  '' one is by desc? can't be the same..
1388  if( param->param.mode = FB_PARAMMODE_BYDESC ) then
1389  exit do
1390  elseif( ovl_param->param.mode = FB_PARAMMODE_BYDESC ) then
1391  exit do
1392  end if
1393  end if
1394 
1395  '' not the same type? check next proc..
1396  if( param->typ <> ovl_param->typ ) then
1397  exit do
1398  end if
1399 
1400  if( param->subtype <> ovl_param->subtype ) then
1401  exit do
1402  end if
1403 
1404  param = param->prev
1405  ovl_param = ovl_param->prev
1406 
1407  ovl_params -= 1
1408  loop while( ovl_params > 0 )
1409 
1410  '' all args equal?
1411  if( ovl_params = 0 ) then
1412  return ovl
1413  end if
1414  end if
1415 
1416  ovl = symbGetProcOvlNext( ovl )
1417  loop while( ovl <> NULL )
1418 
1419  function = NULL
1420 
1421 end function
1422 
1423 '':::::
1424 function symbFindOpOvlProc _
1425  ( _
1426  byval op as AST_OP, _
1427  byval ovl_head_proc as FBSYMBOL ptr, _
1428  byval proc as FBSYMBOL ptr _
1429  ) as FBSYMBOL ptr
1430 
1431  dim as FBSYMBOL ptr ovl = any
1432 
1433  '' if it's not type casting op, handle is as an ordinary proc
1434  if( op <> AST_OP_CAST ) then
1435  return symbFindOverloadProc( ovl_head_proc, proc )
1436  end if
1437 
1438  '' for each proc starting from parent..
1439  ovl = ovl_head_proc
1440  do while( ovl <> NULL )
1441 
1442  '' same return type?
1443  if( proc->typ = ovl->typ ) then
1444  if( proc->subtype = ovl->subtype ) then
1445  return ovl
1446  end if
1447  end if
1448 
1449  ovl = symbGetProcOvlNext( ovl )
1450  loop
1451 
1452  function = NULL
1453 
1454 end function
1455 
1456 '':::::
1457 function symbFindCtorProc _
1458  ( _
1459  byval ovl_head_proc as FBSYMBOL ptr, _
1460  byval proc as FBSYMBOL ptr _
1461  ) as FBSYMBOL ptr
1462 
1463  '' dtor? can't overload..
1464  if( symbIsDestructor( ovl_head_proc ) ) then
1465  return ovl_head_proc
1466  else
1467  return symbFindOverloadProc( ovl_head_proc, proc )
1468  end if
1469 
1470 end function
1471 
1472 
1475 
1476 '':::::
1477 #macro hCheckCtorOvl _
1478  ( _
1480  param_subtype, _
1481  arg_expr, _
1482  arg_mode _
1483  )
1484 
1485  if( rec_cnt = 0 ) then
1486  dim as integer err_num = any
1487  dim as FBSYMBOL ptr proc = any
1488 
1489  rec_cnt += 1
1490  proc = symbFindCtorOvlProc( param_subtype, arg_expr, arg_mode, @err_num )
1491  rec_cnt -= 1
1492 
1493  if( proc <> NULL ) then
1494  return FB_OVLPROC_HALFMATCH - FB_DATATYPE_STRUCT
1495  end if
1496  end if
1497 #endmacro
1498 
1500  ( _
1502  param_dtype, _
1503  param_subtype, _
1504  arg_expr _
1505  )
1506 
1507  if( rec_cnt = 0 ) then
1508  dim as integer err_num = any
1509  dim as FBSYMBOL ptr proc = any
1510 
1511  rec_cnt += 1
1513  param_subtype, _
1514  arg_expr, _
1515  @err_num )
1516  rec_cnt -= 1
1517 
1518  if( proc <> NULL ) then
1519  return FB_OVLPROC_HALFMATCH - FB_DATATYPE_STRUCT
1520  end if
1521  end if
1522 #endmacro
1523 
1524 '':::::
1525 function hCalcTypesDiff _
1526  ( _
1527  byval param_dtype as integer, _
1528  byval param_subtype as FBSYMBOL ptr, _
1529  byval param_ptrcnt as integer, _
1530  byval arg_dtype as integer, _
1531  byval arg_subtype as FBSYMBOL ptr, _
1532  byval arg_expr as ASTNODE ptr, _
1533  byval mode as FB_PARAMMODE = 0 _
1534  ) as integer
1535 
1536  dim as integer arg_dclass = any
1537 
1538  function = 0
1539 
1540  '' don't take the const qualifier into account
1541  param_dtype = typeGetDtAndPtrOnly( param_dtype )
1542  arg_dtype = typeGetDtAndPtrOnly( arg_dtype )
1543 
1544  arg_dclass = typeGetClass( arg_dtype )
1545 
1546  '' check classes
1547  select case as const typeGetClass( param_dtype )
1548  '' integer?
1549  case FB_DATACLASS_INTEGER
1550 
1551  select case as const arg_dclass
1552  '' another integer..
1553  case FB_DATACLASS_INTEGER
1554 
1555  '' z/wstring param:
1556  '' - allow any z/wstring arg, doesn't matter whether
1557  '' it's a DEREF or not (it can all be treated as string)
1558  '' - disallow other args (passing BYVAL explicitly
1559  '' should be handled by caller already)
1560  select case( param_dtype )
1561  case FB_DATATYPE_CHAR
1562  select case( arg_dtype )
1563  case FB_DATATYPE_CHAR
1564  return FB_OVLPROC_FULLMATCH
1565  case FB_DATATYPE_WCHAR
1566  return FB_OVLPROC_HALFMATCH
1567  end select
1568  return 0
1569  case FB_DATATYPE_WCHAR
1570  select case( arg_dtype )
1571  case FB_DATATYPE_CHAR
1572  return FB_OVLPROC_HALFMATCH
1573  case FB_DATATYPE_WCHAR
1574  return FB_OVLPROC_FULLMATCH
1575  end select
1576  return 0
1577 
1578  '' z/wstring ptr params:
1579  '' - allow z/wstring or z/wstring ptr args, corresponding
1580  '' to hStrArgToStrPtrParam(), explicitly here
1581  '' - leave rest to pointer checks below
1582  case typeAddrOf( FB_DATATYPE_CHAR )
1583  select case( arg_dtype )
1584  case FB_DATATYPE_CHAR
1585  return FB_OVLPROC_FULLMATCH
1586  case FB_DATATYPE_WCHAR
1587  return FB_OVLPROC_HALFMATCH
1588  end select
1589  case typeAddrOf( FB_DATATYPE_WCHAR )
1590  select case( arg_dtype )
1591  case FB_DATATYPE_CHAR
1592  return FB_OVLPROC_HALFMATCH
1593  case FB_DATATYPE_WCHAR
1594  return FB_OVLPROC_FULLMATCH
1595  end select
1596 
1597  '' Any other non-z/wstring param from FB_DATACLASS_INTEGER:
1598  '' - Only allow z/wstring arg if it's a DEREF that can
1599  '' be treated as integer
1600  case else
1601  select case( arg_dtype )
1602  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
1603  if( arg_expr = NULL ) then
1604  return 0
1605  end if
1606 
1607  if( astIsDEREF( arg_expr ) = FALSE ) then
1608  return 0
1609  end if
1610  end select
1611  end select
1612 
1613  '' Remap bitfields/enums
1614  select case( arg_dtype )
1615  case FB_DATATYPE_BITFIELD, FB_DATATYPE_ENUM
1616  '' enum args can be passed to integer params (as in C++)
1617  arg_dtype = typeRemap( arg_dtype, arg_subtype )
1618  end select
1619 
1620  '' check pointers..
1621  if( typeIsPtr( param_dtype ) ) then
1622  '' isn't arg a pointer too?
1623  if( typeIsPtr( arg_dtype ) = FALSE ) then
1624  '' not an expression?
1625  if( arg_expr = NULL ) then
1626  return 0
1627  end if
1628 
1629  '' not a numeric constant?
1630  if( astIsCONST( arg_expr ) = FALSE ) then
1631  return 0
1632  end if
1633 
1634  '' not 0 (NULL)?
1635  if( astConstEqZero( arg_expr ) = FALSE ) then
1636  return 0
1637  end if
1638 
1639  '' not native pointer width?
1640  if( typeGetSize( arg_dtype ) <> env.pointersize ) then
1641  return 0
1642  end if
1643 
1644  return FB_OVLPROC_HALFMATCH
1645  end if
1646 
1647  '' Both are pointers (but they're different,
1648  '' full match is already handled)
1649  assert( arg_dtype <> param_dtype )
1650 
1651  '' Any Ptr parameters can accept all pointer arguments, as in C++.
1652  '' Additionally we also allow Any Ptr arguments to match all
1653  '' pointer parameters, because we also allow such assignments,
1654  '' unlike C++.
1655  if( (param_dtype = typeAddrOf( FB_DATATYPE_VOID )) or _
1656  (arg_dtype = typeAddrOf( FB_DATATYPE_VOID )) ) then
1657  return FB_OVLPROC_HALFMATCH
1658  end if
1659 
1660  '' Different pointer types aren't compatible at all though,
1661  '' that would be dangerous.
1662  return 0
1663 
1664  elseif( typeIsPtr( arg_dtype ) ) then
1665  '' Param isn't a pointer, but arg is:
1666  '' no match -- pointers don't match integers
1667  return 0
1668  end if
1669 
1670  return FB_OVLPROC_HALFMATCH - symb_dtypeMatchTB( typeGet( arg_dtype ), typeGet( param_dtype ) )
1671 
1672  '' float? (ok due the auto-coercion, unless it's a pointer)
1673  case FB_DATACLASS_FPOINT
1674  if( typeIsPtr( param_dtype ) ) then
1675  return 0
1676  end if
1677 
1678  return FB_OVLPROC_HALFMATCH - symb_dtypeMatchTB( typeGet( arg_dtype ), typeGet( param_dtype ) )
1679 
1680  '' string arg to integer param? only if the param is a w|zstring
1681  '' (treated as strings) or w|zstring ptr (auto string to ptr conversion,
1682  '' corresponding to hStrArgToStrPtrParam())
1683  case FB_DATACLASS_STRING
1684  select case param_dtype
1685  case FB_DATATYPE_CHAR, typeAddrOf( FB_DATATYPE_CHAR )
1686  return FB_OVLPROC_FULLMATCH
1687  case FB_DATATYPE_WCHAR, typeAddrOf( FB_DATATYPE_WCHAR )
1688  return FB_OVLPROC_HALFMATCH
1689  end select
1690 
1691  end select
1692 
1693  '' floating-point?
1694  case FB_DATACLASS_FPOINT
1695 
1696  select case as const arg_dclass
1697  '' only accept if it's an integer (but pointers)
1698  case FB_DATACLASS_INTEGER
1699  if( typeIsPtr( arg_dtype ) ) then
1700  return 0
1701  end if
1702 
1703  '' remap to real type if it's a bitfield..
1704  select case arg_dtype
1705  case FB_DATATYPE_BITFIELD, FB_DATATYPE_ENUM
1706  '' enum args can be passed to fpoint params (as in C++)
1707  arg_dtype = typeRemap( arg_dtype, arg_subtype )
1708  end select
1709 
1710  return FB_OVLPROC_HALFMATCH - symb_dtypeMatchTB( typeGet( arg_dtype ), typeGet( param_dtype ) )
1711 
1712  '' or if another float..
1713  case FB_DATACLASS_FPOINT
1714  return FB_OVLPROC_HALFMATCH - symb_dtypeMatchTB( typeGet( arg_dtype ), typeGet( param_dtype ) )
1715 
1716  end select
1717 
1718  '' string?
1719  case FB_DATACLASS_STRING
1720 
1721  select case arg_dclass
1722  '' okay if it's a fixed-len string
1723  case FB_DATACLASS_STRING
1724  function = FB_OVLPROC_FULLMATCH
1725 
1726  '' integer if it's a z/wstring (no matter whether a
1727  '' variable/literal or DEREF, it can all be treated as string)
1728  case FB_DATACLASS_INTEGER
1729  select case arg_dtype
1730  case FB_DATATYPE_CHAR
1731  function = FB_OVLPROC_FULLMATCH
1732  case FB_DATATYPE_WCHAR
1733  function = FB_OVLPROC_HALFMATCH
1734  end select
1735 
1736  end select
1737 
1738  end select
1739 
1740 end function
1741 
1742 '':::::
1743 function hCheckOvlParam _
1744  ( _
1745  byval parent as FBSYMBOL ptr, _
1746  byval param as FBSYMBOL ptr, _
1747  byval arg_expr as ASTNODE ptr, _
1748  byval arg_mode as integer, _
1749  byref constonly_diff as integer _
1750  ) as integer
1751 
1752  dim as integer param_dtype = any, arg_dtype = any, param_ptrcnt = any
1753  dim as FBSYMBOL ptr param_subtype = any, arg_subtype = any
1754 
1755  constonly_diff = FALSE
1756 
1757  '' arg not passed?
1758  if( arg_expr = NULL ) then
1759  '' is param optional?
1760  if( symbGetIsOptional( param ) ) then
1761  return FB_OVLPROC_FULLMATCH
1762  else
1763  return 0
1764  end if
1765  end if
1766 
1767  param_dtype = symbGetFullType( param )
1768  param_subtype = symbGetSubType( param )
1769  param_ptrcnt = symbGetPtrCnt( param )
1770 
1771  arg_dtype = astGetFullType( arg_expr )
1772  arg_subtype = astGetSubType( arg_expr )
1773 
1774  select case symbGetParamMode( param )
1775  '' by descriptor param?
1776  case FB_PARAMMODE_BYDESC
1777  '' but arg isn't?
1778  if( arg_mode <> FB_PARAMMODE_BYDESC ) then
1779  return 0
1780  end if
1781 
1782  '' not a full match?
1783  if( param_dtype <> arg_dtype ) then
1784  return 0
1785  end if
1786 
1787  if( param_subtype <> arg_subtype ) then
1788  return 0
1789  end if
1790 
1791  return FB_OVLPROC_FULLMATCH
1792 
1793  '' byref param?
1794  case FB_PARAMMODE_BYREF
1795  '' arg being passed by value?
1796  if( arg_mode = FB_PARAMMODE_BYVAL ) then
1797  '' invalid type? refuse..
1798  if( (typeGetClass( arg_dtype ) <> FB_DATACLASS_INTEGER) or _
1799  (typeGetSize( arg_dtype ) <> env.pointersize) ) then
1800  return 0
1801  end if
1802 
1803  '' pretend param is a pointer
1804  param_dtype = typeAddrOf( param_dtype )
1805  param_ptrcnt += 1
1806  end if
1807  end select
1808 
1809  '' arg passed by descriptor? refuse..
1810  if( arg_mode = FB_PARAMMODE_BYDESC ) then
1811  return 0
1812  end if
1813 
1814  static as integer cast_rec_cnt = 0, ctor_rec_cnt = 0
1815 
1816  '' same types?
1817  if( typeGetDtAndPtrOnly( param_dtype ) = typeGetDtAndPtrOnly( arg_dtype ) ) then
1818  if( typeGetConstMask( param_dtype ) = typeGetConstMask( arg_dtype ) ) then
1819  '' same subtype? full match..
1820  if( param_subtype = arg_subtype ) then
1821  return FB_OVLPROC_FULLMATCH
1822  else
1823  '' is param type a base type of the argument type?
1824  if( param_subtype <> NULL ) then
1825  select case symbGetType( param_subtype )
1826  case FB_DATATYPE_STRUCT '' , FB_DATATYPE_CLASS
1827  var level = symbGetUDTBaseLevel( arg_subtype, param_subtype )
1828  if( level > 0 ) then
1829  return FB_OVLPROC_FULLMATCH - level
1830  End If
1831  End Select
1832  end if
1833  end if
1834  elseif( typeGetConstMask( param_dtype ) ) then
1835  '' same subtype? ..
1836  if( param_subtype = arg_subtype ) then
1837  '' param is const but arg isn't?
1838  if( symbCheckConstAssign( param_dtype, arg_dtype, param_subtype, arg_subtype ) ) then
1839  constonly_diff = TRUE
1840  return FB_OVLPROC_HALFMATCH
1841  end if
1842  end if
1843  end if
1844 
1845  '' if it's rtl, only if explicitly set
1846  if( (symbGetIsRTL( parent ) = FALSE) or (symbGetIsRTLConst( param )) ) then
1847  dim as integer const_matches = any
1848  if( symbCheckConstAssign( param_dtype, arg_dtype, param_subtype, arg_subtype, symbGetParamMode( param ), const_matches ) = FALSE ) then
1849  return 0
1850  else
1851  if( const_matches ) then
1852  dim as integer ptrcnt = typeGetPtrCnt( arg_dtype )
1853  return (FB_OVLPROC_HALFMATCH / (ptrcnt+2)) * const_matches
1854  end if
1855  end if
1856  end if
1857 
1858  '' pointer? check if valid (could be a NULL)
1859  if( typeIsPtr( param_dtype ) ) then
1860  if( astPtrCheck( param_dtype, _
1861  param_subtype, _
1862  arg_expr, _
1863  TRUE ) ) then
1864 
1865  return FB_OVLPROC_FULLMATCH
1866  end if
1867  return 0
1868  end if
1869  end if
1870 
1871  '' different types..
1872 
1873  select case param_dtype
1874  '' UDT? try to find a ctor
1875  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
1876  hCheckCtorOvl( ctor_rec_cnt, param_subtype, arg_expr, arg_mode )
1877 
1878  '' and at last, try implicit casting..
1880  return 0
1881 
1882  '' enum param? refuse any other argument type, even integers,
1883  '' or operator overloading wouldn't work (as in C++)
1884  case FB_DATATYPE_ENUM
1885  return 0
1886 
1887  case else
1888  select case arg_dtype
1889  '' UDT arg? try implicit casting..
1890  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
1891  hCheckCastOvlEx( cast_rec_cnt, symbGetFullType( param ), param_subtype, arg_expr )
1892  return 0
1893  end select
1894  end select
1895 
1896  '' last resource, calc the differences
1897  function = hCalcTypesDiff( symbGetFullType( param ), _
1898  param_subtype, _
1899  param_ptrcnt, _
1900  astGetFullType( arg_expr ), _
1901  arg_subtype, _
1902  arg_expr, _
1903  symbGetParamMode( param ) )
1904 
1905 end function
1906 
1907 '':::::
1908 function symbFindClosestOvlProc _
1909  ( _
1910  byval ovl_head_proc as FBSYMBOL ptr, _
1911  byval args as integer, _
1912  byval arg_head as FB_CALL_ARG ptr, _
1913  byval err_num as FB_ERRMSG ptr, _
1914  byval options as FB_SYMBLOOKUPOPT _
1915  ) as FBSYMBOL ptr
1916 
1917  dim as FBSYMBOL ptr ovl = any, closest_proc = any, param = any
1918  dim as integer arg_matches = any, matches = any
1919  dim as integer max_matches = any, exact_matches = any
1920  dim as integer matchcount = any
1921  dim as integer constonly_diff = any
1922  dim as FB_CALL_ARG ptr arg = any
1923 
1924  *err_num = FB_ERRMSG_OK
1925 
1926  if( ovl_head_proc = NULL ) then
1927  return NULL
1928  end if
1929 
1930  closest_proc = NULL
1931  max_matches = 0
1932  matchcount = 0 '' number of matching procedures found
1933 
1934  dim as integer is_property = symbIsProperty( ovl_head_proc )
1935 
1936  '' for each proc..
1937  ovl = ovl_head_proc
1938  do
1939  dim as integer params = symbGetProcParams( ovl )
1940  if( symbIsMethod( ovl ) ) then
1941  params -= 1
1942  end if
1943 
1944  '' property? handle get/set accessors dups
1945  if( is_property ) then
1946  '' get?
1947  if( (options and FB_SYMBLOOKUPOPT_PROPGET) <> 0 ) then
1948  '' don't check if it's set
1949  if( symbGetType( ovl ) = FB_DATATYPE_VOID ) then
1950  params = -1
1951  end if
1952  '' set..
1953  else
1954  '' don't check if it's get
1955  if( symbGetType( ovl ) <> FB_DATATYPE_VOID ) then
1956  params = -1
1957  end if
1958  end if
1959  end if
1960 
1961  '' Only consider overloads with enough params
1962  if( args <= params ) then
1963  param = symbGetProcHeadParam( ovl )
1964  if( symbIsMethod( ovl ) ) then
1965  param = param->next
1966  end if
1967 
1968  matches = 0
1969  exact_matches = 0
1970 
1971  '' for each arg..
1972  arg = arg_head
1973  for i as integer = 0 to args-1
1974  arg_matches = hCheckOvlParam( ovl, param, arg->expr, arg->mode, constonly_diff )
1975  if( arg_matches = 0 ) then
1976  matches = 0
1977  exit for
1978  end if
1979 
1980  '' exact checks are required for operator overload candidates
1981  if( options and FB_SYMBLOOKUPOPT_BOP_OVL ) then
1982  if( arg_matches = FB_OVLPROC_FULLMATCH ) then
1983  exact_matches += 1
1984  end if
1985  end if
1986 
1987  matches += arg_matches
1988 
1989  '' next param
1990  param = param->next
1991  arg = arg->next
1992  next
1993 
1994  '' If there were no args, then assume it's a match and
1995  '' then check the remaining params, if any.
1996  var is_match = (args = 0) or (matches > 0)
1997 
1998  '' Fewer args than params? Check whether the missing ones are optional.
1999  for i as integer = args to params-1
2000  '' not optional? exit
2001  if( symbGetIsOptional( param ) = FALSE ) then
2002  '' Missing arg for this param - not a match afterall.
2003  is_match = FALSE
2004  exit for
2005  end if
2006 
2007  '' next param
2008  param = param->next
2009  next
2010 
2011  if( is_match ) then
2012  '' First match, or better match than any previous overload?
2013  if( (matchcount = 0) or (matches > max_matches) ) then
2014  dim as integer eligible = TRUE
2015 
2016  '' an operator overload candidate is only eligible if
2017  '' there is at least one exact arg match
2018  if( options and FB_SYMBLOOKUPOPT_BOP_OVL ) then
2019  if( exact_matches = 0 and constonly_diff = FALSE ) then
2020  eligible = FALSE
2021  end if
2022  end if
2023 
2024  '' it's eligible, update
2025  if( eligible ) then
2026  closest_proc = ovl
2027  max_matches = matches
2028  matchcount = 1
2029  end if
2030 
2031  '' Same score than best previous overload?
2032  elseif( matches = max_matches ) then
2033  matchcount += 1
2034  end if
2035  end if
2036  end if
2037 
2038  '' next overloaded proc
2039  ovl = symbGetProcOvlNext( ovl )
2040  loop while( ovl <> NULL )
2041 
2042  '' more than one possibility?
2043  if( matchcount > 1 ) then
2044  *err_num = FB_ERRMSG_AMBIGUOUSCALLTOPROC
2045  function = NULL
2046  else
2047  function = closest_proc
2048  end if
2049 
2050 end function
2051 
2052 '':::::
2053 function symbFindBopOvlProc _
2054  ( _
2055  byval op as AST_OP, _
2056  byval l as ASTNODE ptr, _
2057  byval r as ASTNODE ptr, _
2058  byval err_num as FB_ERRMSG ptr _
2059  ) as FBSYMBOL ptr
2060 
2061  dim as FB_CALL_ARG arg1 = any, arg2 = any
2062  dim as FBSYMBOL ptr proc = any
2063 
2064  *err_num = FB_ERRMSG_OK
2065 
2066  '' at least one must be an UDT
2067  select case astGetDataType( l )
2068  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM
2069 
2070  case else
2071  '' try the 2nd one..
2072  select case astGetDataType( r )
2073  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM
2074 
2075  case else
2076  return NULL
2077  end select
2078  end select
2079 
2080  '' try (l, r)
2081  arg1.expr = l
2082  arg1.mode = INVALID
2083  arg1.next = @arg2
2084 
2085  arg2.expr = r
2086  arg2.mode = INVALID
2087  arg2.next = NULL
2088 
2089  proc = symbFindClosestOvlProc( symb.globOpOvlTb(op).head, 2, @arg1, err_num, FB_SYMBLOOKUPOPT_BOP_OVL )
2090 
2091  if( proc = NULL ) then
2092  if( *err_num <> FB_ERRMSG_OK ) then
2093  errReport( *err_num, TRUE )
2094  end if
2095  end if
2096 
2097  function = proc
2098 
2099 end function
2100 
2101 '':::::
2102 function symbFindSelfBopOvlProc _
2103  ( _
2104  byval op as AST_OP, _
2105  byval l as ASTNODE ptr, _
2106  byval r as ASTNODE ptr, _
2107  byval err_num as FB_ERRMSG ptr _
2108  ) as FBSYMBOL ptr
2109 
2110  dim as FB_CALL_ARG arg1 = any
2111  dim as FBSYMBOL ptr proc = any, head_proc = any
2112 
2113  *err_num = FB_ERRMSG_OK
2114 
2115  '' lhs must be an UDT
2116  select case astGetDataType( l )
2117  case FB_DATATYPE_STRUCT
2118  dim as FBSYMBOL ptr subtype = astGetSubType( l )
2119 
2120  if( subtype->udt.ext = NULL ) then
2121  return NULL
2122  end if
2123 
2124  head_proc = symbGetUDTOpOvlTb( subtype )(op - AST_OP_SELFBASE)
2125 
2126  'case FB_DATATYPE_CLASS
2127 
2128  case else
2129  return NULL
2130  end select
2131 
2132  if( head_proc = NULL ) then
2133  return NULL
2134  end if
2135 
2136  '' try (l, r) -- don't pass the instance ptr
2137  arg1.expr = r
2138  arg1.mode = INVALID
2139  arg1.next = NULL
2140 
2141  proc = symbFindClosestOvlProc( head_proc, 1, @arg1, err_num )
2142 
2143  if( proc = NULL ) then
2144  if( *err_num <> FB_ERRMSG_OK ) then
2145  errReport( *err_num, TRUE )
2146  end if
2147  else
2148  '' check visibility
2149  if( symbCheckAccess( proc ) = FALSE ) then
2150  *err_num = FB_ERRMSG_ILLEGALMEMBERACCESS
2151  errReportEx( FB_ERRMSG_ILLEGALMEMBERACCESS, _
2153 
2154  proc = NULL
2155  end if
2156  end if
2157 
2158  function = proc
2159 
2160 end function
2161 
2162 '':::::
2163 function symbFindUopOvlProc _
2164  ( _
2165  byval op as AST_OP, _
2166  byval l as ASTNODE ptr, _
2167  byval err_num as FB_ERRMSG ptr _
2168  ) as FBSYMBOL ptr
2169 
2170  dim as FB_CALL_ARG arg1 = any
2171  dim as FBSYMBOL ptr proc = any
2172 
2173  *err_num = FB_ERRMSG_OK
2174 
2175  '' arg must be an UDT
2176  select case astGetDataType( l )
2177  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM
2178 
2179  case else
2180  '' note: the CAST op shouldn't be passed to this function
2181  return NULL
2182  end select
2183 
2184  arg1.expr = l
2185  arg1.mode = INVALID
2186  arg1.next = NULL
2187 
2188  proc = symbFindClosestOvlProc( symb.globOpOvlTb(op).head, 1, @arg1, err_num )
2189 
2190  if( proc = NULL ) then
2191  if( *err_num <> FB_ERRMSG_OK ) then
2192  errReport( *err_num, TRUE )
2193  end if
2194  end if
2195 
2196  function = proc
2197 
2198 end function
2199 
2200 '':::::
2201 function symbFindSelfUopOvlProc _
2202  ( _
2203  byval op as AST_OP, _
2204  byval l as ASTNODE ptr, _
2205  byval err_num as FB_ERRMSG ptr _
2206  ) as FBSYMBOL ptr
2207 
2208  dim as FBSYMBOL ptr proc = any, head_proc = any
2209 
2210  *err_num = FB_ERRMSG_OK
2211 
2212  '' lhs must be an UDT
2213  select case astGetDataType( l )
2214  case FB_DATATYPE_STRUCT
2215  dim as FBSYMBOL ptr subtype = astGetSubType( l )
2216 
2217  if( subtype->udt.ext = NULL ) then
2218  return NULL
2219  end if
2220 
2221  head_proc = symbGetUDTOpOvlTb( subtype )(op - AST_OP_SELFBASE)
2222 
2223  'case FB_DATATYPE_CLASS
2224 
2225  case else
2226  return NULL
2227  end select
2228 
2229  if( head_proc = NULL ) then
2230  return NULL
2231  end if
2232 
2233  '' try (l) -- don't pass the instance ptr
2234 
2235  proc = symbFindClosestOvlProc( head_proc, 0, NULL, err_num )
2236 
2237  if( proc = NULL ) then
2238  if( *err_num <> FB_ERRMSG_OK ) then
2239  errReport( *err_num, TRUE )
2240  end if
2241 
2242  else
2243  '' check visibility
2244  if( symbCheckAccess( proc ) = FALSE ) then
2245  *err_num = FB_ERRMSG_ILLEGALMEMBERACCESS
2246  errReportEx( FB_ERRMSG_ILLEGALMEMBERACCESS, _
2248 
2249  proc = NULL
2250  end if
2251  end if
2252 
2253  function = proc
2254 
2255 end function
2256 
2257 '':::::
2258 function hCheckCastOvl _
2259  ( _
2260  byval proc as FBSYMBOL ptr, _
2261  byval to_dtype as integer, _
2262  byval to_subtype as FBSYMBOL ptr _
2263  ) as integer
2264 
2265  dim as integer proc_dtype = any
2266  dim as FBSYMBOL ptr proc_subtype = any
2267 
2268  proc_dtype = symbGetFullType( proc )
2269  proc_subtype = symbGetSubType( proc )
2270 
2271  '' same types?
2272  if( typeGetDtAndPtrOnly( proc_dtype ) = typeGetDtAndPtrOnly( to_dtype ) ) then
2273  '' same subtype?
2274  if( proc_subtype = to_subtype ) then
2275  return FB_OVLPROC_FULLMATCH
2276  end if
2277 
2278  if( typeIsPtr( proc_dtype ) ) then
2279  return 0
2280  end if
2281  end if
2282 
2283  '' different types..
2284 
2285  select case typeGet( proc_dtype )
2286  '' UDT or enum? can't be different (this is the last resource,
2287  '' don't try to do coercion inside a casting routine)
2288  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM ', FB_DATATYPE_CLASS
2289  return 0
2290 
2291  case else
2292  select case typeGet( to_dtype )
2293  '' UDT arg? refuse
2294  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
2295  return 0
2296  end select
2297 
2298  end select
2299 
2300  '' last resource, calc the differences
2301  function = hCalcTypesDiff( proc_dtype, _
2302  proc_subtype, _
2303  symbGetPtrCnt( proc ), _
2304  to_dtype, _
2305  to_subtype, _
2306  NULL )
2307 
2308 end function
2309 
2310 '':::::
2311 function symbFindCastOvlProc _
2312  ( _
2313  byval to_dtype as integer, _
2314  byval to_subtype as FBSYMBOL ptr, _
2315  byval l as ASTNODE ptr, _
2316  byval err_num as FB_ERRMSG ptr _
2317  ) as FBSYMBOL ptr
2318 
2319  dim as FBSYMBOL ptr proc_head = any
2320 
2321  *err_num = FB_ERRMSG_OK
2322 
2323  '' arg must be an UDT
2324  select case astGetDataType( l )
2325  case FB_DATATYPE_STRUCT
2326  dim as FBSYMBOL ptr subtype = astGetSubType( l )
2327  if( subtype = NULL ) then
2328  return NULL
2329  end if
2330 
2331  if( subtype->udt.ext = NULL ) then
2332  return NULL
2333  end if
2334 
2335  proc_head = symbGetUDTOpOvlTb( subtype )(AST_OP_CAST - AST_OP_SELFBASE)
2336 
2337  case else
2338  return NULL
2339  end select
2340 
2341  if( proc_head = NULL ) then
2342  return NULL
2343  end if
2344 
2345  dim as FBSYMBOL ptr p = any, proc = any, closest_proc = any
2346  dim as integer matches = any, max_matches = any, matchcount = any
2347 
2348  '' must check the return type, not the parameter..
2349  closest_proc = NULL
2350  max_matches = 0
2351  matchcount = 0
2352 
2353  if( typeGet( to_dtype ) <> FB_DATATYPE_VOID ) then
2354  '' for each overloaded proc..
2355  proc = proc_head
2356  do while( proc <> NULL )
2357 
2358  matches = hCheckCastOvl( proc, to_dtype, to_subtype )
2359  if( matches > max_matches ) then
2360  closest_proc = proc
2361  max_matches = matches
2362  matchcount = 1
2363 
2364  '' same? ambiguity..
2365  elseif( matches = max_matches ) then
2366  if( max_matches > 0 ) then
2367  matchcount += 1
2368  end if
2369  end if
2370 
2371  '' next
2372  proc = symbGetProcOvlNext( proc )
2373  loop
2374 
2375  '' find the most precise possible..
2376  else
2377  '' for each overloaded proc..
2378  proc = proc_head
2379  do while( proc <> NULL )
2380 
2381  '' simple type?
2382  if( symbGetSubType( proc ) = NULL ) then
2383  if( symbGetType( proc ) <= FB_DATATYPE_DOUBLE ) then
2384  '' more precise than the last?
2385  if( symbGetType( proc ) > to_dtype ) then
2386  closest_proc = proc
2387  to_dtype = symbGetType( proc )
2388  end if
2389  end if
2390  end if
2391 
2392  '' next
2393  proc = symbGetProcOvlNext( proc )
2394  loop
2395 
2396  end if
2397 
2398  '' more than one possibility?
2399  if( matchcount > 1 ) then
2400  *err_num = FB_ERRMSG_AMBIGUOUSCALLTOPROC
2401  errReportParam( proc_head, 0, NULL, FB_ERRMSG_AMBIGUOUSCALLTOPROC )
2402  closest_proc = NULL
2403  else
2404  if( closest_proc <> NULL ) then
2405  '' check visibility
2406  if( symbCheckAccess( closest_proc ) = FALSE ) then
2407  *err_num = FB_ERRMSG_ILLEGALMEMBERACCESS
2408  errReportEx( FB_ERRMSG_ILLEGALMEMBERACCESS, _
2409  symbGetFullProcName( closest_proc ) )
2410  closest_proc = NULL
2411  end if
2412  end if
2413  end if
2414 
2415  function = closest_proc
2416 
2417 end function
2418 
2419 '':::::
2420 function symbFindCtorOvlProc _
2421  ( _
2422  byval sym as FBSYMBOL ptr, _
2423  byval expr as ASTNODE ptr, _
2424  byval arg_mode as FB_PARAMMODE, _
2425  byval err_num as FB_ERRMSG ptr _
2426  ) as FBSYMBOL ptr
2427 
2428  dim as FB_CALL_ARG arg1 = any
2429 
2430  '' don't pass the instance ptr
2431  arg1.expr = expr
2432  arg1.mode = arg_mode
2433  arg1.next = NULL
2434 
2435  function = symbFindClosestOvlProc( symbGetCompCtorHead( sym ), _
2436  1, _
2437  @arg1, _
2438  err_num )
2439 
2440 end function
2441 
2442 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2443 '' del
2444 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2445 
2446 sub hDelParams( byval proc as FBSYMBOL ptr )
2447  dim as FBSYMBOL ptr param = any, nxt = any
2448 
2449  param = proc->proc.paramtb.head
2450  while( param )
2451  nxt = param->next
2452 
2453  '' Note: astEnd() will already free the optexpr
2454  symbFreeSymbol( param )
2455 
2456  param = nxt
2457  wend
2458 end sub
2459 
2460 sub symbDelPrototype( byval s as FBSYMBOL ptr )
2461  '' del args..
2462  if( s->proc.params > 0 ) then
2463  hDelParams( s )
2464  end if
2465 
2466  symbProcFreeExt( s )
2467 
2468  symbFreeSymbol( s )
2469 
2470  '' note: can't delete the next overloaded procs in the list here
2471  '' because global operators can be declared inside namespaces,
2472  '' but they will be linked together
2473 end sub
2474 
2475 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2476 '' global ctors
2477 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2478 
2479 '':::::
2480 function hAddToGlobCtorList _
2481  ( _
2482  byval list as FB_GLOBCTORLIST ptr, _
2483  byval proc as FBSYMBOL ptr _
2484  ) as FB_GLOBCTORLIST_ITEM ptr
2485 
2486  dim as FB_GLOBCTORLIST_ITEM ptr n = any
2487 
2488  n = listNewNode( @list->list )
2489 
2490  '' add to list
2491  if( list->tail <> NULL ) then
2492  list->tail->next = n
2493  else
2494  list->head = n
2495  end if
2496 
2497  n->next = NULL
2498  list->tail = n
2499 
2500  ''
2501  n->sym = proc
2502 
2503  function = n
2504 
2505 end function
2506 
2507 function symbAddGlobalCtor( byval proc as FBSYMBOL ptr ) as FB_GLOBCTORLIST_ITEM ptr
2508  symbSetIsGlobalCtor( proc )
2509  function = hAddToGlobCtorList( @symb.globctorlist, proc )
2510 end function
2511 
2512 function symbAddGlobalDtor( byval proc as FBSYMBOL ptr ) as FB_GLOBCTORLIST_ITEM ptr
2513  symbSetIsGlobalDtor( proc )
2514  function = hAddToGlobCtorList( @symb.globdtorlist, proc )
2515 end function
2516 
2517 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2518 '' misc
2519 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2520 
2521 function hAreMethodsCompatible _
2522  ( _
2523  byval v as FBSYMBOL ptr, _ '' The virtual that's overridden
2524  byval o as FBSYMBOL ptr _ '' The override
2525  ) as integer
2526 
2527  dim as FBSYMBOL ptr vparam = any, oparam = any
2528 
2529  assert( symbIsProc( v ) and symbIsMethod( v ) )
2530  assert( symbIsProc( o ) and symbIsMethod( o ) )
2531 
2532  '' Different result type? (Note: SUBs have VOID result type)
2533  if( (symbGetType ( v ) <> symbGetType ( o )) or _
2534  (symbGetSubtype( v ) <> symbGetSubtype( o )) ) then
2535  return FB_ERRMSG_OVERRIDERETTYPEDIFFERS
2536  end if
2537 
2538  '' Does one have a BYREF result, but not the other?
2539  if( symbProcReturnsByref( v ) <> symbProcReturnsByref( o ) ) then
2540  return FB_ERRMSG_OVERRIDERETTYPEDIFFERS
2541  end if
2542 
2543  '' Different calling convention?
2544  if( symbAreProcModesEqual( v, o ) = FALSE ) then
2545  return FB_ERRMSG_OVERRIDECALLCONVDIFFERS
2546  end if
2547 
2548  '' Different parameter count?
2549  if( symbGetProcParams( v ) <> symbGetProcParams( o ) ) then
2550  return FB_ERRMSG_OVERRIDEPARAMSDIFFER
2551  end if
2552 
2553  '' Check each parameter's mode and type
2554  vparam = symbGetProcLastParam( v )
2555  oparam = symbGetProcLastParam( o )
2556 
2557  '' But skip THIS ptr; virtual/override will have a different types here,
2558  '' their parent classes respectively. Since this virtual was found to
2559  '' be overridden by this override, we know that the override's THIS
2560  '' type is derived from the virtual's THIS type.
2561  assert( symbIsParamInstance( vparam ) )
2562  assert( symbIsParamInstance( oparam ) )
2563  vparam = vparam->next
2564  oparam = oparam->next
2565 
2566  while( vparam )
2567  if( (symbGetParamMode( vparam ) <> symbGetParamMode( oparam )) or _
2568  (symbGetFullType ( vparam ) <> symbGetFullType ( oparam )) or _
2569  (symbGetSubtype ( vparam ) <> symbGetSubtype ( oparam )) ) then
2570  return FB_ERRMSG_OVERRIDEPARAMSDIFFER
2571  end if
2572  vparam = vparam->next
2573  oparam = oparam->next
2574  wend
2575 
2576  function = FB_ERRMSG_OK
2577 end function
2578 
2580  ( _
2581  byval proc as FBSYMBOL ptr, _
2582  byval is_implicit as integer _
2583  )
2584 
2585  dim as FBSYMBOL ptr overridden = any
2586  dim as integer errmsg = any
2587 
2588  overridden = symbProcGetOverridden( proc )
2589 
2590  '' Overriding anything?
2591  if( overridden ) then
2592  '' Check whether override and overridden have different return
2593  '' type or calling convention etc., this must be disallowed
2594  '' (unlike with overloading) because the function signatures
2595  '' aren't really compatible (e.g. return on stack vs. return
2596  '' in registers).
2597 
2598  errmsg = hAreMethodsCompatible( overridden, proc )
2599  if( errmsg <> FB_ERRMSG_OK ) then
2600  if( is_implicit and _
2601  (errmsg = FB_ERRMSG_OVERRIDECALLCONVDIFFERS) ) then
2602  '' symbUdtAddDefaultMembers() uses this to check
2603  '' implicit dtors and LET overloads. Since they
2604  '' are not visible in the original code,
2605  '' the error message must have more info.
2606  if( symbIsDestructor( proc ) ) then
2607  errmsg = FB_ERRMSG_IMPLICITDTOROVERRIDECALLCONVDIFFERS
2608  else
2609  errmsg = FB_ERRMSG_IMPLICITLETOVERRIDECALLCONVDIFFERS
2610  end if
2611  end if
2612 
2613  errReport( errmsg )
2614  end if
2615 
2616  end if
2617 
2618 end sub
2619 
2620 sub symbProcSetVtableIndex( byval proc as FBSYMBOL ptr, byval i as integer )
2622  proc->proc.ext->vtableindex = i
2623 end sub
2624 
2625 function symbProcGetVtableIndex( byval proc as FBSYMBOL ptr ) as integer
2626  if( proc->proc.ext ) then
2627  function = proc->proc.ext->vtableindex
2628  end if
2629 end function
2630 
2631 function symbProcGetOverridden( byval proc as FBSYMBOL ptr ) as FBSYMBOL ptr
2632  if( proc->proc.ext ) then
2633  function = proc->proc.ext->overridden
2634  end if
2635 end function
2636 
2637 function symbGetProcResult( byval proc as FBSYMBOL ptr ) as FBSYMBOL ptr
2638  if( proc->proc.ext ) then
2639  function = proc->proc.ext->res
2640  end if
2641 end function
2642 
2643 '':::::
2644 function hMangleFunctionPtr _
2645  ( _
2646  byval proc as FBSYMBOL ptr, _
2647  byval dtype as integer, _
2648  byval subtype as FBSYMBOL ptr, _
2649  byval attrib as integer, _
2650  byval mode as integer _
2651  ) as zstring ptr
2652 
2653  static as string id
2654  dim as integer i = any
2655  dim as FBSYMBOL ptr param = any
2656 
2657  '' cheapo and fast internal mangling..
2658  id = "{fbfp}("
2659 
2661 
2662  '' for each param..
2663  param = symbGetProcHeadParam( proc )
2664  for i = 0 to symbGetProcParams( proc )-1
2665  if( i > 0 ) then
2666  id += ","
2667  end if
2668 
2669  '' not an UDT?
2670  if( param->subtype = NULL ) then
2671  id += hex( param->typ ) + "M" + hex( cint(param->param.mode) )
2672  else
2673  '' notes:
2674  '' - can't use hex( param->subtype ), because slots can be
2675  '' reused if fwd types were resolved and removed
2676  '' - can't use only the param->id.name because UDT's with the same
2677  '' name declared inside different namespaces
2678  symbMangleParam( id, param )
2679  end if
2680 
2681  param = symbGetParamNext( param )
2682  next
2683 
2684  '' return type
2685  id += ")"
2686  if( subtype = NULL ) then
2687  id += hex( dtype )
2688  else
2689  '' see the notes above
2690  symbMangleType( id, dtype, subtype )
2691  end if
2692 
2694 
2695  '' return BYREF? - must be mangled explicitly, to distinguish it from
2696  '' other function pointers with same types & parameters, that are not
2697  '' returning BYREF though.
2698  if( attrib and FB_SYMBATTRIB_RETURNSBYREF ) then
2699  id += "$" '' prevent the R from looking like part of the previous type id (if any)
2700  id += "R" '' R for reference, as in C++ mangling
2701  end if
2702 
2703  '' calling convention
2704  id += "$"
2705  id += hex( mode )
2706 
2707  function = strptr( id )
2708 end function
2709 
2710 sub hSubOrFuncToStr( byref s as string, byval proc as FBSYMBOL ptr )
2711  if( symbGetType( proc ) = FB_DATATYPE_VOID ) then
2712  s += "sub"
2713  else
2714  s += "function"
2715  end if
2716 end sub
2717 
2718 '' Append calling convention, if it differs from the default
2719 sub hProcModeToStr( byref s as string, byval proc as FBSYMBOL ptr )
2720  '' Ctors/Dtors currently always default to CDECL, see cProcHeader()
2721  if( symbIsConstructor( proc ) or symbIsDestructor( proc ) ) then
2722  select case( symbGetProcMode( proc ) )
2723  case FB_FUNCMODE_STDCALL, FB_FUNCMODE_STDCALL_MS
2724  s += " stdcall"
2725  case FB_FUNCMODE_PASCAL
2726  s += " pascal"
2727  end select
2728  else
2729  '' Others default to FBCALL
2730  select case( symbGetProcMode( proc ) )
2731  case FB_FUNCMODE_STDCALL, FB_FUNCMODE_STDCALL_MS
2732  select case( env.target.fbcall )
2733  case FB_FUNCMODE_STDCALL, FB_FUNCMODE_STDCALL_MS
2734 
2735  case else
2736  s += " stdcall"
2737  end select
2738  case FB_FUNCMODE_PASCAL
2739  if( env.target.fbcall <> FB_FUNCMODE_PASCAL ) then
2740  s += " pascal"
2741  end if
2742  case FB_FUNCMODE_CDECL
2743  if( env.target.fbcall <> FB_FUNCMODE_CDECL ) then
2744  s += " cdecl"
2745  end if
2746  end select
2747  end if
2748 end sub
2749 
2750 sub hParamsToStr( byref s as string, byval proc as FBSYMBOL ptr )
2751  s += "("
2752 
2753  var param = symbGetProcHeadParam( proc )
2754 
2755  '' Method? Skip the instance pointer
2756  if( (param <> NULL) and symbIsMethod( proc ) ) then
2757  param = symbGetParamNext( param )
2758  end if
2759 
2760  while( param )
2761  var parammode = symbGetParamMode( param )
2762  select case( parammode )
2763  case FB_PARAMMODE_BYVAL, FB_PARAMMODE_BYREF
2764  '' Byval/Byref, if different from default, at least in -lang fb.
2765  '' In other -langs it depends on OPTION BYVAL, and it seems best to
2766  '' always include Byval/Byref in that case, otherwise it'd depend on
2767  '' source code context.
2768  if( fbLangIsSet( FB_LANG_FB ) and _
2769  (symbGetDefaultCallConv( symbGetType( param ), param->subtype ) <> parammode) ) then
2770  if( parammode = FB_PARAMMODE_BYVAL ) then
2771  s += "byval "
2772  else
2773  s += "byref "
2774  end if
2775  end if
2776 
2777  case FB_PARAMMODE_BYDESC
2778  case FB_PARAMMODE_VARARG
2779  end select
2780 
2781  if( parammode = FB_PARAMMODE_VARARG ) then
2782  s += "..."
2783  else
2784  '' Array parentheses, instead of "Bydesc"
2785  if( parammode = FB_PARAMMODE_BYDESC ) then
2786  s += "() "
2787  end if
2788 
2789  '' Parameter's data type
2790  s += "as " + symbTypeToStr( param->typ, param->subtype )
2791  end if
2792 
2793  param = symbGetParamNext( param )
2794  if( param ) then
2795  s += ", "
2796  end if
2797  wend
2798 
2799  s += ")"
2800 end sub
2801 
2802 sub hResultToStr( byref s as string, byval proc as FBSYMBOL ptr )
2803  '' Function result
2804  if( symbGetType( proc ) <> FB_DATATYPE_VOID ) then
2805  if( symbProcReturnsByref( proc ) ) then
2806  s += " byref"
2807  end if
2808  s += " as " + symbTypeToStr( proc->typ, proc->subtype )
2809  end if
2810 end sub
2811 
2812 function symbProcPtrToStr( byval proc as FBSYMBOL ptr ) as string
2813  dim s as string
2814 
2815  hSubOrFuncToStr( s, proc )
2816  hProcModeToStr( s, proc )
2817  hParamsToStr( s, proc )
2818  hResultToStr( s, proc )
2819 
2820  function = s
2821 end function
2822 
2823 function symbGetFullProcName( byval proc as FBSYMBOL ptr ) as zstring ptr
2824  static as string res
2825 
2826  res = ""
2827 
2828  dim as FBSYMBOL ptr ns = symbGetNamespace( proc )
2829 
2830  do while( ns <> @symbGetGlobalNamespc( ) )
2831  res = *symbGetName( ns ) + "." + res
2832  ns = symbGetNamespace( ns )
2833  loop
2834 
2835  if( symbIsConstructor( proc ) ) then
2836  res += "constructor"
2837  elseif( symbIsDestructor( proc ) ) then
2838  res += "destructor"
2839  elseif( symbIsOperator( proc ) ) then
2840  res += "operator."
2841  if( proc->proc.ext <> NULL ) then
2842  res += *astGetOpId( symbGetProcOpOvl( proc ) )
2843  end if
2844  elseif( symbIsProperty( proc ) ) then
2845  res += *symbGetName( proc )
2846  res += ".property."
2847  if( symbGetType( proc ) <> FB_DATATYPE_VOID ) then
2848  res += "get"
2849  else
2850  res += "set"
2851  end if
2852  else
2853  res += *symbGetName( proc )
2854  end if
2855 
2856  function = strptr( res )
2857 end function
2858 
2859 function symbMethodToStr( byval proc as FBSYMBOL ptr ) as string
2860  var s = *symbGetFullProcName( proc )
2861  hProcModeToStr( s, proc )
2862  hParamsToStr( s, proc )
2863  hResultToStr( s, proc )
2864  function = s
2865 end function
2866 
2867 '':::::
2868 function symbGetDefaultCallConv _
2869  ( _
2870  byval dtype as integer, _
2871  byval subtype as FBSYMBOL ptr _
2872  ) as integer
2873 
2874  '' assumes dtype has const info stripped
2875 
2876  select case as const dtype
2877  case FB_DATATYPE_FWDREF, _
2878  FB_DATATYPE_FIXSTR, FB_DATATYPE_STRING, _
2879  FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR, _
2880  FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
2881 
2882  return FB_PARAMMODE_BYREF
2883 
2884  case else
2885  return FB_PARAMMODE_BYVAL
2886 
2887  end select
2888 
2889 
2890 end function
2891 
2892 '' Check whether the procedures' calling conventions are compatible
2893 function symbAreProcModesEqual _
2894  ( _
2895  byval proca as FBSYMBOL ptr, _
2896  byval procb as FBSYMBOL ptr _
2897  ) as integer
2898 
2899  dim as integer a = any, b = any
2900 
2901  a = symbGetProcMode( proca )
2902  b = symbGetProcMode( procb )
2903 
2904  '' STDCALL and STDCALL_MS are technically compatible, only the mangling
2905  '' is different - but that doesn't concern function pointers.
2906  select case( a )
2907  case FB_FUNCMODE_STDCALL, FB_FUNCMODE_STDCALL_MS
2908  select case( b )
2909  case FB_FUNCMODE_STDCALL, FB_FUNCMODE_STDCALL_MS
2910  return TRUE
2911  end select
2912  end select
2913 
2914  function = (a = b)
2915 end function
2916 
2917 '':::::
2918 function symbAllocOvlCallArg _
2919  ( _
2920  byval list as TLIST ptr, _
2921  byval arg_list as FB_CALL_ARG_LIST ptr, _
2922  byval to_head as integer _
2923  ) as FB_CALL_ARG ptr
2924 
2925  dim as FB_CALL_ARG ptr arg = listNewNode( list )
2926 
2927  if( to_head = FALSE ) then
2928  if( arg_list->head = NULL ) then
2929  arg_list->head = arg
2930  else
2931  arg_list->tail->next = arg
2932  end if
2933 
2934  arg->next = NULL
2935  arg_list->tail = arg
2936 
2937  else
2938  if( arg_list->tail = NULL ) then
2939  arg_list->tail = arg
2940  end if
2941 
2942  arg->next = arg_list->head
2943  arg_list->head = arg
2944  end if
2945 
2946  arg_list->args += 1
2947 
2948  function = arg
2949 
2950 end function
2951 
2952 '':::::
2954  ( _
2955  byval list as TLIST ptr, _
2956  byval arg_list as FB_CALL_ARG_LIST ptr _
2957  )
2958 
2959  dim as FB_CALL_ARG ptr arg, nxt
2960 
2961  arg = arg_list->head
2962  do while( arg <> NULL )
2963  nxt = arg->next
2964  symbFreeOvlCallArg( list, arg )
2965  arg = nxt
2966  loop
2967 
2968 end sub
2969 
2970