"Fossies" - the Fresh Open Source Software Archive

Member "FreeBASIC-1.07.1-source/src/compiler/symb-proc.bas" (27 Sep 2019, 83220 Bytes) of package /linux/privat/FreeBASIC-1.07.1-source.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Visual Basic source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "symb-proc.bas": 1.07.0_vs_1.07.1.

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