FreeBASIC  0.91.0
symb-comp.bas
Go to the documentation of this file.
1 '' complex/compound/composite symbols helper functions
2 ''
3 '' chng: sep/2006 written [v1ctor]
4 
5 
6 #include once "fb.bi"
7 #include once "fbint.bi"
8 
10  sym as FBSYMBOL ptr
11  symtb as FBSYMBOLTB ptr '' prev symbol tb
12  hashtb as FBHASHTB ptr '' prev hash tb
13  ns as FBSYMBOL ptr '' prev namespace
14 end type
15 
17  for i as integer = 0 to AST_OPCODES-1
18  symb.globOpOvlTb(i).head = NULL
19  next
20 
21  stackNew( @symb.neststk, 16, len( FB_SYMBNEST ), FALSE )
22 end sub
23 
25  stackFree( @symb.neststk )
26 end sub
27 
28 sub symbUdtAllocExt( byval udt as FBSYMBOL ptr )
29  assert( symbIsStruct( udt ) )
30  if( udt->udt.ext = NULL ) then
31  udt->udt.ext = xcallocate( sizeof( FB_STRUCTEXT ) )
32  end if
33 end sub
34 
35 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
36 '' default ctors
37 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
38 
39 function hDeclareProc _
40  ( _
41  byval udt as FBSYMBOL ptr, _
42  byval op as AST_OP, _
43  byval add_rhs as integer, _
44  byval attrib as FB_SYMBATTRIB _
45  ) as FBSYMBOL ptr
46 
47  dim as FBSYMBOL ptr proc = any
48 
49  '' Into the UDT namespace
50  symbNestBegin( udt, TRUE )
51 
52  proc = symbPreAddProc( NULL )
53 
54  '' add "this"
56 
57  '' add right-side hand param?
58  if( add_rhs ) then
59  assert( symbIsStruct( udt ) )
60  symbAddProcParam( proc, "__FB_RHS__", FB_DATATYPE_STRUCT, udt, _
61  FB_PARAMMODE_BYREF, FB_SYMBATTRIB_NONE )
62  end if
63 
64  attrib or= FB_SYMBATTRIB_METHOD
65  attrib or= FB_SYMBATTRIB_PRIVATE
66 
67  '' cons|destructor?
68  if( op = INVALID ) then
69  proc = symbAddCtor( proc, NULL, attrib, _
70  FB_FUNCMODE_CDECL, FB_SYMBOPT_DECLARING )
71  '' op..
72  else
73  proc = symbAddOperator( proc, op, NULL, FB_DATATYPE_VOID, NULL, attrib, _
74  FB_FUNCMODE_CDECL, FB_SYMBOPT_DECLARING )
75  end if
76 
77  '' Close the namespace again
78  symbNestEnd( TRUE )
79 
80  function = proc
81 end function
82 
83 sub hSetMinimumVtableSize( byval udt as FBSYMBOL ptr )
84  '' vtables always have at least 2 elements (following GCC):
85  '' index 0: a NULL pointer
86  '' index 1: the pointer to this type's RTTI table
87  '' Slots for the pointers for virtual methods start at index 2.
88  ''
89  '' Note: A vtable must be generated even if there are no virtuals,
90  '' to support RTTI. In that case it will only have the first two
91  '' elements (null and rtti pointers).
92 
93  if( udt->udt.ext->vtableelements = 0 ) then
94  udt->udt.ext->vtableelements = 2
95  end if
96 end sub
97 
98 sub hBuildRtti( byval udt as FBSYMBOL ptr )
99  static as FBARRAYDIM dTB(0)
100  dim as ASTNODE ptr initree = any, rttibase = any
101  dim as FBSYMBOL ptr rtti = any, fld = any
102 
103  '' static shared UDT.rtti as $fb_RTTI
104  '' (real identifier given later during mangling)
105  symbNestBegin( udt, TRUE )
106  rtti = symbAddVar( NULL, NULL, FB_DATATYPE_STRUCT, symb.rtti.fb_rtti, 0, 0, dTB(), _
107  FB_SYMBATTRIB_CONST or FB_SYMBATTRIB_STATIC or FB_SYMBATTRIB_SHARED, _
108  FB_SYMBOPT_PRESERVECASE )
109  rtti->stats or= FB_SYMBSTATS_RTTITABLE
110  symbNestEnd( TRUE )
111  udt->udt.ext->rtti = rtti
112 
113  '' initializer
114  initree = astTypeIniBegin( FB_DATATYPE_STRUCT, symb.rtti.fb_rtti, FALSE, 0 )
115  astTypeIniScopeBegin( initree, rtti )
116 
117  '' stdlibvtable = NULL
118  fld = symbUdtGetFirstField( symb.rtti.fb_rtti )
119  astTypeIniAddAssign( initree, astNewCONSTi( 0, typeAddrOf( FB_DATATYPE_VOID ), NULL ), fld )
120 
121  '' id = @"mangled name"
122  fld = symbUdtGetNextInitableField( fld )
124 
125  '' rttibase = @(base's RTTI data) or NULL if there is no base
126  fld = symbUdtGetNextInitableField( fld )
127  if( udt->udt.base ) then
128  rttibase = astNewADDROF( astNewVAR( udt->udt.base->subtype->udt.ext->rtti ) )
129  else
130  rttibase = astNewCONSTi( 0, typeAddrOf( FB_DATATYPE_VOID ) )
131  end if
132  astTypeIniAddAssign( initree, rttibase, fld )
133 
134  astTypeIniScopeEnd( initree, rtti )
135  astTypeIniEnd( initree, TRUE )
136 
137  symbSetTypeIniTree( rtti, initree )
138  symbSetIsInitialized( rtti )
139 end sub
140 
141 sub hBuildVtable( byval udt as FBSYMBOL ptr )
142  static as FBARRAYDIM dTB(0)
143  dim as ASTNODE ptr initree = any, basevtableinitree = any
144  dim as FBSYMBOL ptr member = any, rtti = any, vtable = any
145  dim as integer i = any, basevtableelements = any
146 
147  '' The vtable is an array of pointers:
148  '' 0. null pointer (why? just following GCC...)
149  '' 1. rtti pointer
150  '' 2. and following: procptrs corresponding to virtual methods
151  '' in the order they were parsed.
152 
153  assert( udt->udt.ext->vtableelements >= 2 )
154 
155  '' static shared UDT.vtable(0 to elements-1) as any ptr
156  '' (real identifier given later during mangling)
157  symbNestBegin( udt, TRUE )
158  dTB(0).upper = udt->udt.ext->vtableelements - 1
159  vtable = symbAddVar( NULL, NULL, typeAddrOf( FB_DATATYPE_VOID ), NULL, 0, 1, dTB(), _
160  FB_SYMBATTRIB_CONST or FB_SYMBATTRIB_STATIC or FB_SYMBATTRIB_SHARED, _
161  FB_SYMBOPT_PRESERVECASE )
162  vtable->stats or= FB_SYMBSTATS_VTABLE
163  symbNestEnd( TRUE )
164 
165  '' Find information about the base UDT's vtable:
166  '' the number of elements,
167  '' and the initree (so it can be copied into the new vtable)
168  ''
169  '' - If the base has no virtuals, vtableelements will be 2
170  '' (due to hSetMinimumVtableSize())
171  '' - If the base is OBJECT, the vtable is hidden in the rtlib,
172  '' thus there is no initree for us to use. Luckily we don't need it
173  '' anyways, since OBJECT doesn't have any virtuals.
174  assert( symbIsField( udt->udt.base ) )
175  assert( symbGetType( udt->udt.base ) = FB_DATATYPE_STRUCT )
176  assert( symbIsStruct( udt->udt.base->subtype ) )
177  basevtableelements = udt->udt.base->subtype->udt.ext->vtableelements
178  '' Any virtuals (more than the default 2 elements)?
179  if( basevtableelements > 2 ) then
180  assert( symbIsVar( udt->udt.base->subtype->udt.ext->vtable ) )
181  basevtableinitree = udt->udt.base->subtype->udt.ext->vtable->var_.initree
182  else
183  basevtableinitree = NULL
184  end if
185 
186  '' {
187  initree = astTypeIniBegin( typeAddrOf( FB_DATATYPE_VOID ), NULL, FALSE, 0 )
188  astTypeIniScopeBegin( initree, vtable )
189 
190  '' 0. null pointer = NULL
191  astTypeIniAddAssign( initree, astNewCONSTi( 0, typeAddrOf( FB_DATATYPE_VOID ) ), vtable )
192 
193  '' 1. rtti pointer = @rtti
194  rtti = udt->udt.ext->rtti
195  astTypeIniAddAssign( initree, astNewADDROF( astNewVAR( rtti ) ), vtable )
196 
197  '' initialize inherited procptrs, to the same expression as in the
198  '' base vtable's initializer
199  i = 2
200  if( basevtableinitree ) then
201  '' Copy the typeini assigns from the base vtable's initializer,
202  '' except the first 2 (they are set above already)
203  astTypeIniCopyElements( initree, basevtableinitree, 2 )
204  assert( basevtableelements > 2 )
205  i += (basevtableelements - 2)
206  end if
207 
208  '' Fill new vtable entries with NULLs first, to be safe, and also to
209  '' initialize any new unimplemented pure-virtual slots.
210  '' We could let them point to __cxa_pure_virtual() like gcc,
211  '' but with a NULL pointer crash instead of the abort() we'll actually
212  '' get a more useful run-time error under -exx.
213  while( i <= dTB(0).upper )
214  astTypeIniAddAssign( initree, astNewCONSTi( 0, typeAddrOf( FB_DATATYPE_VOID ) ), vtable )
215  i += 1
216  wend
217 
218  '' }
219  astTypeIniScopeEnd( initree, vtable )
220  astTypeIniEnd( initree, TRUE )
221 
222  symbSetTypeIniTree( vtable, initree )
223  symbSetIsInitialized( vtable )
224 
225  '' 1. new (and not inherited) entries for ...
226  '' - virtuals: must be set to point to their bodies for now.
227  '' (not yet overridden)
228  '' - abstracts: are set to point to fb_AbstractStub() (our version
229  '' of GCC's __cxa_pure_virtual()), which will show a run-time
230  '' error message and abort the program.
231  ''
232  '' 2. any entries for inherited virtuals/abstracts that were overridden
233  '' by a normal method must be updated to point to the normal method.
234 
235  '' For each member of this UDT (does not include inherited members)
236  member = symbGetCompSymbTb( udt ).head
237  while( member )
238  '' procedure?
239  if( symbIsProc( member ) ) then
240  i = symbProcGetVtableIndex( member )
241  if( (i > 0) and (not symbIsAbstract( member )) ) then
242  astTypeIniReplaceElement( initree, i, astBuildProcAddrof( member ) )
243  end if
244  end if
245  member = member->next
246  wend
247 
248  udt->udt.ext->vtable = vtable
249 end sub
250 
251 sub hProcBegin( byval udt as FBSYMBOL ptr, byval proc as FBSYMBOL ptr )
252  '' constructor|destructor|operator parent[.let]( ... )
253  symbNestBegin( udt, TRUE )
254  astProcBegin( proc, FALSE )
255 end sub
256 
257 sub hProcEnd( )
258  '' end constructor|destructor|operator
259  astProcEnd( FALSE )
260  symbNestEnd( TRUE )
261 end sub
262 
263 sub hAddCtorBody _
264  ( _
265  byval udt as FBSYMBOL ptr, _
266  byval proc as FBSYMBOL ptr, _
267  byval is_copyctor as integer _
268  )
269 
270  dim as FBSYMBOL ptr this_ = any, src = any
271 
272  '' The AST will add any implicit base/field construction/destruction
273  '' code automatically
274  hProcBegin( udt, proc )
275 
276  if( is_copyctor ) then
277  this_ = symbGetParamVar( symbGetProcHeadParam( proc ) )
278  src = symbGetParamVar( symbGetProcTailParam( proc ) )
279 
280  '' assign op overload will do the rest
281  astAdd( astNewASSIGN( astBuildInstPtr( this_ ), astBuildInstPtr( src ) ) )
282  end if
283 
284  hProcEnd( )
285 
286  symbSetCantUndef( udt )
287 end sub
288 
289 '':::::
290 sub hAssignList _
291  ( _
292  byval fld as FBSYMBOL ptr, _
293  byval dstexpr as ASTNODE ptr, _
294  byval srcexpr as ASTNODE ptr _
295  ) static
296 
297  dim as FBSYMBOL ptr cnt, label, dst, src, subtype
298 
299  subtype = symbGetSubtype( fld )
300 
301  cnt = symbAddTempVar( FB_DATATYPE_INTEGER )
302  label = symbAddLabel( NULL )
303  dst = symbAddTempVar( typeAddrOf( symbGetType( fld ) ), subtype )
304  src = symbAddTempVar( typeAddrOf( symbGetType( fld ) ), subtype )
305 
306  '' dst = @this.dst(0)
307  astAdd( astBuildVarAssign( dst, astNewADDROF( dstexpr ) ) )
308  '' src = @this.src(0)
309  astAdd( astBuildVarAssign( src, astNewADDROF( srcexpr ) ) )
310 
311  '' for cnt = 0 to symbGetArrayElements( dst )-1
312  astAdd( astBuildForBegin( NULL, cnt, label, 0 ) )
313 
314  '' *dst = *src
316 
317  '' dst += 1
318  astAdd( astBuildVarInc( dst, 1 ) )
319  '' src += 1
320  astAdd( astBuildVarInc( src, 1 ) )
321 
322  '' next
323  astAdd( astBuildForEnd( NULL, cnt, label, astNewCONSTi( symbGetArrayElements( fld ) ) ) )
324 
325 end sub
326 
327 '':::::
328 function hCopyUnionFields _
329  ( _
330  byval this_ as FBSYMBOL ptr, _
331  byval rhs as FBSYMBOL ptr, _
332  byval base_fld as FBSYMBOL ptr _
333  ) as FBSYMBOL ptr
334 
335  dim as FBSYMBOL ptr fld = any
336  dim as longint bytes = any, lgt = any, base_ofs = any
337 
338  '' merge all union fields
339  fld = base_fld
340  bytes = 0
341  base_ofs = symbGetOfs( base_fld )
342 
343  do
344  lgt = (symbGetLen( fld ) * symbGetArrayElements( fld )) + _
345  (symbGetOfs( fld ) - base_ofs)
346  if( lgt > bytes ) then
347  bytes = lgt
348  end if
349 
350  fld = fld->next
351  if( fld = NULL ) then
352  exit do
353  end if
354  loop while( symbGetIsUnionField( fld ) )
355 
356  '' copy all them at once
357  astAdd( astNewMEM( AST_OP_MEMMOVE, _
358  astBuildInstPtr( this_, base_fld ), _
359  astBuildInstPtr( rhs, base_fld ), _
360  bytes ) )
361 
362  function = fld
363 end function
364 
365 sub hAddLetOpBody _
366  ( _
367  byval udt as FBSYMBOL ptr, _
368  byval letproc as FBSYMBOL ptr _
369  )
370 
371  dim as FBSYMBOL ptr fld = any, this_ = any, rhs = any
372  dim as ASTNODE ptr dstexpr = any, srcexpr = any
373 
374  hProcBegin( udt, letproc )
375 
376  this_ = symbGetParamVar( symbGetProcHeadParam( letproc ) )
377  rhs = symbGetParamVar( symbGetProcTailParam( letproc ) )
378 
379  '' for each field
380  fld = symbGetCompSymbTb( udt ).head
381  while( fld )
382  if( symbIsField( fld ) ) then
383  '' part of an union?
384  if( symbGetIsUnionField( fld ) ) then
385  fld = hCopyUnionFields( this_, rhs, fld )
386  continue while
387  end if
388 
389  dstexpr = astBuildInstPtr( this_, fld )
390  srcexpr = astBuildInstPtr( rhs, fld )
391 
392  '' not an array?
393  if( (symbGetArrayDimensions( fld ) = 0) or _
394  (symbGetArrayElements( fld ) = 1) ) then
395  '' this.field = rhs.field
396  astAdd( astNewASSIGN( dstexpr, srcexpr ) )
397  '' array..
398  else
399  hAssignList( fld, dstexpr, srcexpr )
400  end if
401  end if
402 
403  fld = fld->next
404  wend
405 
406  hProcEnd( )
407 
408  symbSetCantUndef( udt )
409 
410 end sub
411 
412 '' Declare & add any implicit/default members and global vars if needed
413 sub symbUdtAddDefaultMembers( byval udt as FBSYMBOL ptr )
414  dim as FBSYMBOL ptr defctor = any, copyctor = any, letop = any, dtor = any
415  dim as integer base_without_defaultctor = any
416 
417  ''
418  '' If this UDT has fields with ctors, we have to make sure to add
419  '' default and copy ctors aswell as a dtor and a Let operator to the
420  '' parent, if the user didn't do that yet. This ensures the fields'
421  '' ctors/dtors will be called and also that they will be copied
422  '' correctly: In case they have Let overloads themselves, we can't just
423  '' do the default memcpy(). (If the parent already has a Let overload,
424  '' we can assume it's correct already)
425  ''
426  '' Besides that, in case there were any field initializers specified,
427  '' we want to add a default constructor if there isn't any constructor
428  '' yet, to ensure the field initializers are getting used.
429  ''
430 
431  '' Derived?
432  if( udt->udt.base ) then
433  assert( symbIsField( udt->udt.base ) )
434  assert( symbGetType( udt->udt.base ) = FB_DATATYPE_STRUCT )
435  assert( symbIsStruct( udt->udt.base->subtype ) )
436  '' No default ctor?
437  base_without_defaultctor = (symbGetCompDefCtor( udt->udt.base->subtype ) = NULL)
438  else
439  base_without_defaultctor = FALSE
440  end if
441 
442  defctor = NULL
443  copyctor = NULL
444  letop = NULL
445  dtor = NULL
446 
447  '' Ctor/inited fields and no ctor yet?
448  if( (symbGetUDTHasCtorField( udt ) or symbGetUDTHasInitedField( udt )) and _
449  (symbGetCompCtorHead( udt ) = NULL) ) then
450  if( base_without_defaultctor ) then
451  '' Cannot implicitly generate a default ctor,
452  '' show a nicer error message than astProcEnd() would.
453  '' It would report the missing BASE() initializer,
454  '' but from here we can show a more useful error.
455  errReport( FB_ERRMSG_NEEDEXPLICITDEFCTOR )
456  else
457  '' Add default ctor
458  defctor = hDeclareProc( udt, INVALID, FALSE, FB_SYMBATTRIB_OVERLOADED or FB_SYMBATTRIB_CONSTRUCTOR )
459  end if
460  end if
461 
462  if( symbGetUDTHasCtorField( udt ) ) then
463  '' Let operator (must be defined before the copy ctor)
464  if( symbGetCompCloneProc( udt ) = NULL ) then
465  letop = hDeclareProc( udt, AST_OP_ASSIGN, TRUE, FB_SYMBATTRIB_OVERLOADED or FB_SYMBATTRIB_OPERATOR )
466 
467  '' Don't allow the implicit LET to override a FINAL LET from the base
468  symbProcCheckOverridden( letop, TRUE )
469  end if
470 
471  '' Copy ctor
472  if( symbGetCompCopyCtor( udt ) = NULL ) then
473  if( base_without_defaultctor ) then
474  '' Cannot implicitly generate a copy ctor,
475  '' same as with default ctor above.
476  errReport( FB_ERRMSG_NEEDEXPLICITCOPYCTOR )
477  else
478  copyctor = hDeclareProc( udt, INVALID, TRUE, FB_SYMBATTRIB_OVERLOADED or FB_SYMBATTRIB_CONSTRUCTOR )
479  end if
480  end if
481  end if
482 
483  '' has fields with dtors?
484  if( symbGetUDTHasDtorField( udt ) ) then
485  '' no default dtor explicitly defined?
486  if( symbGetCompDtor( udt ) = NULL ) then
487  '' Dtor
488  dtor = hDeclareProc( udt, INVALID, FALSE, FB_SYMBATTRIB_DESTRUCTOR )
489 
490  '' Don't allow the implicit dtor to override a FINAL dtor from the base
491  symbProcCheckOverridden( dtor, TRUE )
492  end if
493  end if
494 
495  ''
496  '' Add vtable and rtti global variables
497  ''
498  '' - The vtable can only be created once all methods are known,
499  '' how many virtuals there are, which method overrides virtuals
500  '' from the base, etc.
501  '' Even the implicit destructor (if any) must be declared before
502  '' the vtable is added, in case it should override a virtual dtor.
503  ''
504  '' - Creating the vtable depends on FBSYMBOL.udt.ext->rtti being set,
505  '' because the vtable includes a pointer to the rtti table,
506  '' thus the rtti table should be added before the vtable.
507  ''
508  '' - Any constructor body depends on FBSYMBOL.udt.ext->vtable being set,
509  '' so the vtable must be added before any constructor bodies.
510  ''
511  if( symbGetHasRTTI( udt ) ) then
512  symbUdtAllocExt( udt )
513  hSetMinimumVtableSize( udt )
514 
515  '' only if it isn't FB's own Object base super class
516  '' (for which the rtlib already contains these declarations)
517  if( udt <> symb.rtti.fb_object ) then
518  hBuildRtti( udt )
519  hBuildVtable( udt )
520  end if
521  end if
522 
523  ''
524  '' Add bodies if any implicit ctor/dtor/let procs were declared above
525  ''
526  if( defctor ) then
527  hAddCtorBody( udt, defctor, FALSE )
528  end if
529 
530  if( copyctor ) then
531  hAddCtorBody( udt, copyctor, TRUE )
532  end if
533 
534  if( letop ) then
535  hAddLetOpBody( udt, letop )
536  end if
537 
538  if( dtor ) then
539  hAddCtorBody( udt, dtor, FALSE )
540  end if
541 end sub
542 
543 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
544 '' getters/setters
545 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
546 
547 '':::::
548 function hIsLhsEqRhs _
549  ( _
550  byval parent as FBSYMBOL ptr, _
551  byval proc as FBSYMBOL ptr _
552  ) as integer static
553 
554  dim as FBSYMBOL ptr param, subtype
555 
556  function = FALSE
557 
558  param = symbGetProcTailParam( proc )
559  if( symbGetParamMode( param ) = FB_PARAMMODE_BYREF ) then
560  subtype = symbGetSubtype( param )
561 
562  if( subtype = NULL ) then
563  return FALSE
564  end if
565 
566  '' forward?
567  if( symbGetClass( subtype ) = FB_SYMBCLASS_FWDREF ) then
568  '' not a pointer?
569  if( symbGetType( param ) = FB_DATATYPE_FWDREF ) then
570  '' same name?
571  if( subtype->hash.index = parent->hash.index ) then
572  return TRUE
573  end if
574  end if
575 
576  return FALSE
577  end if
578 
579  if( subtype = parent ) then
580  select case symbGetClass( parent )
581  case FB_SYMBCLASS_STRUCT
582  function = ( symbGetType( param ) = FB_DATATYPE_STRUCT )
583 
584  case FB_SYMBCLASS_CLASS
585  '...
586  end select
587  end if
588  end if
589 
590 end function
591 
592 '' Check whether UDT doesn't have either of dtor/copy ctor/virtual methods
593 '' (UDTs that have any of these are handled specially by BYVAL params and
594 '' function results. For example, BYVAL params do copy construction, and use
595 '' this function to check whether there is a copyctor and whether a temp copy
596 '' to be passed byref must be used or not)
597 function symbCompIsTrivial( byval sym as FBSYMBOL ptr ) as integer
598  function = ((symbGetCompCopyCtor( sym ) = NULL) and _
599  (symbGetCompDtor( sym ) = NULL) and _
600  (not symbGetHasRTTI( sym )))
601 end function
602 
603 sub symbSetCompCtorHead( byval sym as FBSYMBOL ptr, byval proc as FBSYMBOL ptr )
604  if( symbIsStruct( sym ) ) then
605  assert( symbIsConstructor( proc ) )
606 
608  if( sym->udt.ext->ctorhead = NULL ) then
609  '' Add ctor head (first overload)
610  sym->udt.ext->ctorhead = proc
611  end if
612  end if
613 end sub
614 
615 sub symbCheckCompCtor( byval sym as FBSYMBOL ptr, byval proc as FBSYMBOL ptr )
616  if( symbIsStruct( sym ) ) then
617  select case( symbGetProcParams( proc ) )
618  '' default?
619  case 1
620  '' only the THIS param - it's a default ctor
621  '' (this takes precedence over other ctors with all optional params)
622  sym->udt.ext->defctor = proc
623  '' copy?
624  case 2
625  '' 2 params - it could be a copy ctor
626  if( sym->udt.ext->copyctor = NULL ) then
627  if( hIsLhsEqRhs( sym, proc ) ) then
628  sym->udt.ext->copyctor = proc
629  end if
630  end if
631  end select
632 
633  '' all params optional? then it can be used as default ctor
634  if( sym->udt.ext->defctor = NULL ) then
635  if( symbGetProcOptParams( proc ) = symbGetProcParams( proc ) - 1 ) then
636  sym->udt.ext->defctor = proc
637  end if
638  end if
639  end if
640 end sub
641 
642 sub symbSetCompDtor( byval sym as FBSYMBOL ptr, byval proc as FBSYMBOL ptr )
643  if( symbIsStruct( sym ) ) then
644  assert( symbIsDestructor( proc ) )
646  if( sym->udt.ext->dtor = NULL ) then
647  '' Add dtor
648  sym->udt.ext->dtor = proc
649  end if
650  end if
651 end sub
652 
653 function symbGetCompCtorHead( byval sym as FBSYMBOL ptr ) as FBSYMBOL ptr
654  if( sym ) then
655  if( symbIsStruct( sym ) ) then
656  if( sym->udt.ext ) then
657  function = sym->udt.ext->ctorhead
658  end if
659  end if
660  end if
661 end function
662 
663 function symbGetCompDefCtor( byval sym as FBSYMBOL ptr ) as FBSYMBOL ptr
664  if( sym ) then
665  if( symbIsStruct( sym ) ) then
666  if( sym->udt.ext ) then
667  function = sym->udt.ext->defctor
668  end if
669  end if
670  end if
671 end function
672 
673 function symbGetCompCopyCtor( byval sym as FBSYMBOL ptr ) as FBSYMBOL ptr
674  if( sym ) then
675  if( symbIsStruct( sym ) ) then
676  if( sym->udt.ext ) then
677  function = sym->udt.ext->copyctor
678  end if
679  end if
680  end if
681 end function
682 
683 function symbGetCompDtor( byval sym as FBSYMBOL ptr ) as FBSYMBOL ptr
684  if( sym ) then
685  if( symbIsStruct( sym ) ) then
686  if( sym->udt.ext ) then
687  function = sym->udt.ext->dtor
688  end if
689  end if
690  end if
691 end function
692 
693 sub symbCheckCompClone( byval sym as FBSYMBOL ptr, byval proc as FBSYMBOL ptr )
694  if( symbIsStruct( sym ) ) then
695  '' clone?
696  if( hIsLhsEqRhs( sym, proc ) ) then
698  sym->udt.ext->clone = proc
699  end if
700  end if
701 end sub
702 
703 function symbGetCompCloneProc( byval sym as FBSYMBOL ptr ) as FBSYMBOL ptr
704  if( sym ) then
705  if( symbIsStruct( sym ) ) then
706  if( sym->udt.ext ) then
707  function = sym->udt.ext->clone
708  end if
709  end if
710  end if
711 end function
712 
713 '':::::
714 function symbGetCompOpOvlHead _
715  ( _
716  byval sym as FBSYMBOL ptr, _
717  byval op as AST_OP _
718  ) as FBSYMBOL ptr
719 
720  '' self?
721  if( astGetOpIsSelf( op ) ) then
722  select case symbGetClass( sym )
723  case FB_SYMBCLASS_STRUCT
724  if( sym->udt.ext = NULL ) then
725  return NULL
726  end if
727 
728  function = symbGetUDTOpOvlTb(sym)(op - AST_OP_SELFBASE)
729 
730  case FB_SYMBCLASS_ENUM
731  function = NULL
732 
733  case FB_SYMBCLASS_CLASS
734  '' ...
735 
736  end select
737 
738  '' not self..
739  else
740  function = symb.globOpOvlTb(op).head
741  end if
742 
743 end function
744 
745 '':::::
747  ( _
748  byval sym as FBSYMBOL ptr, _
749  byval proc as FBSYMBOL ptr _
750  )
751 
752  dim as AST_OP op = symbGetProcOpOvl( proc )
753 
754  '' self?
755  if( astGetOpIsSelf( op ) ) then
756  if( symbIsStruct( sym ) ) then
758  symbGetUDTOpOvlTb(sym)(op - AST_OP_SELFBASE) = proc
759  end if
760 
761  '' assign?
762  if( op = AST_OP_ASSIGN ) then
764  end if
765  '' not self..
766  else
767  symb.globOpOvlTb(op).head = proc
768  end if
769 
770 end sub
771 
772 '' Returns vtable index for new virtual method
773 function symbCompAddVirtual( byval udt as FBSYMBOL ptr ) as integer
774  '' Virtuals require the vptr, i.e. the UDT must extend OBJECT
775  assert( symbGetHasRTTI( udt ) )
776 
777  symbUdtAllocExt( udt )
778 
779  hSetMinimumVtableSize( udt )
780 
781  function = udt->udt.ext->vtableelements
782  udt->udt.ext->vtableelements += 1
783 end function
784 
785 function symbCompGetAbstractCount( byval udt as FBSYMBOL ptr ) as integer
786  assert( symbIsStruct( udt ) )
787  if( udt->udt.ext ) then
788  function = udt->udt.ext->abstractcount
789  end if
790 end function
791 
792 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
793 '' nesting
794 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
795 
796 /'private sub hDumpHashTb
797  dim as FBHASHTB ptr hashtb = symb.hashlist.tail
798  do
799  dim as zstring ptr id = symbGetName( hashtb->owner )
800  hashtb = hashtb->prev
801 
802  print *iif( id, id, @"main" );
803  if( hashtb = NULL ) then
804  exit do
805  end if
806  print ,
807  loop
808 
809  print
810 end sub'/
811 
812 '':::::
813 sub hInsertNested _
814  ( _
815  byval sym as FBSYMBOL ptr, _
816  byval lasttb as FBHASHTB ptr, _
817  byval base_ns as FBSYMBOL ptr _
818  )
819 
820  dim as FBHASHTB ptr hashtb = any
821 
822  '' add all parents to hash list, but the base one
823 
824  dim as FBSYMBOL ptr ns = symbGetNamespace( sym )
825  do until( ns = base_ns )
826  hashtb = @symbGetCompHashTb( ns )
827 
828  if( symbGetCompExt( ns ) = NULL ) then
829  symbGetCompExt( ns ) = symbCompAllocExt( )
830  end if
831 
832  symbGetCompExt( ns )->cnt += 1
833  if( symbGetCompExt( ns )->cnt <> 1 ) then
834  '' remove from import hash tb list
836  end if
837 
838  '' add to nested hash tb list
839  '' (in reverse other, child ns must be the tail, parents follow)
840  symbHashListAddBefore( lasttb, hashtb )
841 
842  lasttb = hashtb
843 
844  ns = symbGetNamespace( ns )
845  loop
846 
847 end sub
848 
849 '':::::
850 sub hRemoveNested _
851  ( _
852  byval sym as FBSYMBOL ptr, _
853  byval base_ns as FBSYMBOL ptr _
854  )
855 
856  '' remove all parents from the hash list, but the base one
857 
858  dim as FBSYMBOL ptr ns = symbGetNamespace( sym )
859  do until( ns = base_ns )
860  symbGetCompExt( ns )->cnt -= 1
861 
862  '' remove from nested hash tb list
863  symbHashListDel( @symbGetCompHashTb( ns ) )
864 
865  if( symbGetCompExt( ns )->cnt <> 0 ) then
866  '' add to import hash tb list
868  symbGetCompSymbTb( ns ).head )
869  end if
870 
871  ns = symbGetNamespace( ns )
872  loop
873 
874 end sub
875 
876 '':::::
877 sub hInsertImported _
878  ( _
879  byval sym as FBSYMBOL ptr _
880  )
881 
882  if( symbGetCompExt( sym ) = NULL ) then
883  exit sub
884  end if
885 
886  dim as FBSYMBOL ptr imp_ = symbGetCompImportHead( sym )
887  do while( imp_ <> NULL )
888  dim as FBSYMBOL ptr ns = symbGetImportNamespc( imp_ )
889 
890  if( ns <> NULL ) then
891  symbGetCompExt( ns )->cnt += 1
892  if( symbGetCompExt( ns )->cnt = 1 ) then
893  '' add to import hash tb list
895  symbGetCompSymbTb( ns ).head )
896  end if
897  end if
898 
899  imp_ = symbGetImportNext( imp_ )
900  loop
901 
902 end sub
903 
904 '':::::
905 sub hRemoveImported _
906  ( _
907  byval sym as FBSYMBOL ptr _
908  )
909 
910  if( symbGetCompExt( sym ) = NULL ) then
911  exit sub
912  end if
913 
914  dim as FBSYMBOL ptr imp_ = symbGetCompImportHead( sym )
915  do while( imp_ <> NULL )
916  dim as FBSYMBOL ptr ns = symbGetImportNamespc( imp_ )
917 
918  if( ns <> NULL ) then
919  symbGetCompExt( ns )->cnt -= 1
920  if( symbGetCompExt( ns )->cnt = 0 ) then
921  '' remove from import hash tb list
923  end if
924  end if
925 
926  imp_ = symbGetImportNext( imp_ )
927  loop
928 
929 end sub
930 
931 '':::::
932 sub symbNestBegin _
933  ( _
934  byval sym as FBSYMBOL ptr, _
935  byval insert_chain as integer _
936  )
937 
938  dim as FB_SYMBNEST ptr n = any
939  dim as FBHASHTB ptr hashtb = any
940  dim as FBSYMBOLTB ptr symbtb = any
941 
942  n = stackPush( @symb.neststk )
943 
944  n->sym = sym
945  n->symtb = symbGetCurrentSymTb( )
946  n->hashtb = symbGetCurrentHashTb( )
947 
948  if( symbGetClass( sym ) = FB_SYMBCLASS_PROC ) then
949  symbtb = @symbGetProcSymbTb( sym )
950  hashtb = NULL
951  else
952  symbtb = @symbGetCompSymbTb( sym )
953  hashtb = @symbGetCompHashTb( sym )
954  end if
955 
956  symbSetCurrentSymTb( symbtb )
957 
958  if( hashtb <> NULL ) then
959  n->ns = symbGetCurrentNamespc( )
960  symbSetCurrentNamespc( sym )
961 
962  symbSetCurrentHashTb( hashtb )
963 
964  if( symbGetCompExt( sym ) = NULL ) then
965  symbGetCompExt( sym ) = symbCompAllocExt( )
966  end if
967 
968  symbGetCompExt( sym )->cnt += 1
969  if( symbGetCompExt( sym )->cnt <> 1 ) then
970  '' remove from import hash tb list
972  end if
973 
974  '' add to the nested hash tb list
976 
977  if( insert_chain ) then
978  hInsertNested( sym, hashtb, n->ns )
979  end if
980 
981  '' add all USING's
983  end if
984 
985 end sub
986 
987 '':::::
988 sub symbNestEnd _
989  ( _
990  byval remove_chain as integer _
991  )
992 
993  dim as FB_SYMBNEST ptr n = any
994  dim as FBHASHTB ptr hashtb = any
995  dim as FBSYMBOL ptr sym = any
996 
997  n = stackGetTOS( @symb.neststk )
998 
999  sym = n->sym
1000 
1001  if( symbGetClass( sym ) = FB_SYMBCLASS_PROC ) then
1002  hashtb = NULL
1003  else
1004  hashtb = @symbGetCompHashTb( sym )
1005  end if
1006 
1007  symbSetCurrentSymTb( n->symtb )
1008 
1009  if( hashtb <> NULL ) then
1010  '' removed all USING's
1011  hRemoveImported( sym )
1012 
1013  if( remove_chain ) then
1014  hRemoveNested( sym, n->ns )
1015  end if
1016 
1017  symbGetCompExt( sym )->cnt -= 1
1018 
1019  '' remove from nested hash tb list
1021 
1022  if( symbGetCompExt( sym )->cnt <> 0 ) then
1023  '' add to import hash tb list
1025  symbGetCompSymbTb( sym ).head )
1026  end if
1027 
1028  symbSetCurrentHashTb( n->hashtb )
1029 
1030  symbSetCurrentNamespc( n->ns )
1031  end if
1032 
1033  stackPop( @symb.neststk )
1034 
1035 end sub
1036 
1037 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1038 '' import and export lists (USING stuff)
1039 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1040 
1041 '':::::
1043  ( _
1044  byval imp_ as FBSYMBOL ptr _
1045  )
1046 
1047  dim as FBSYMBOL ptr ns = symbGetExportNamespc( imp_ )
1048 
1049  if( symbGetCompExt( ns ) = NULL ) then
1050  symbGetCompExt( ns ) = symbCompAllocExt( )
1051  end if
1052 
1053  if( symbGetCompExt( ns )->implist.tail <> NULL ) then
1054  symbGetCompExt( ns )->implist.tail->nsimp.imp_next = imp_
1055  else
1056  symbGetCompExt( ns )->implist.head = imp_
1057  end if
1058 
1059  imp_->nsimp.imp_prev = symbGetCompExt( ns )->implist.tail
1060  imp_->nsimp.imp_next = NULL
1061 
1062  symbGetCompExt( ns )->implist.tail = imp_
1063 
1064 end sub
1065 
1066 '':::::
1068  ( _
1069  byval imp_ as FBSYMBOL ptr _
1070  )
1071 
1072  dim as FBSYMBOL ptr ns = symbGetExportNamespc( imp_ )
1073 
1074  if( imp_->nsimp.imp_prev = NULL ) then
1075  symbGetCompExt( ns )->implist.head = imp_->nsimp.imp_next
1076  else
1077  imp_->nsimp.imp_prev->nsimp.imp_next = imp_->nsimp.imp_next
1078  end if
1079 
1080  if( imp_->nsimp.imp_next = NULL ) then
1081  symbGetCompExt( ns )->implist.tail = imp_->nsimp.imp_prev
1082  else
1083  imp_->nsimp.imp_next->nsimp.imp_prev = imp_->nsimp.imp_prev
1084  end if
1085 
1086 end sub
1087 
1088 '':::::
1090  ( _
1091  byval imp_ as FBSYMBOL ptr _
1092  )
1093 
1094  dim as FBSYMBOL ptr ns = symbGetImportNamespc( imp_ )
1095 
1096  if( symbGetCompExt( ns ) = NULL ) then
1097  symbGetCompExt( ns ) = symbCompAllocExt( )
1098  end if
1099 
1100  if( symbGetCompExt( ns )->explist.tail <> NULL ) then
1101  symbGetCompExt( ns )->explist.tail->nsimp.exp_next = imp_
1102  else
1103  symbGetCompExt( ns )->explist.head = imp_
1104  end if
1105 
1106  imp_->nsimp.exp_prev = symbGetCompExt( ns )->explist.tail
1107  imp_->nsimp.exp_next = NULL
1108 
1109  symbGetCompExt( ns )->explist.tail = imp_
1110 
1111 end sub
1112 
1113 '':::::
1115  ( _
1116  byval imp_ as FBSYMBOL ptr _
1117  )
1118 
1119  dim as FBSYMBOL ptr ns = symbGetImportNamespc( imp_ )
1120 
1121  if( imp_->nsimp.exp_prev = NULL ) then
1122  symbGetCompExt( ns )->explist.head = imp_->nsimp.exp_next
1123  else
1124  imp_->nsimp.exp_prev->nsimp.exp_next = imp_->nsimp.exp_next
1125  end if
1126 
1127  if( imp_->nsimp.exp_next = NULL ) then
1128  symbGetCompExt( ns )->explist.tail = imp_->nsimp.exp_prev
1129  else
1130  imp_->nsimp.exp_next->nsimp.exp_prev = imp_->nsimp.exp_prev
1131  end if
1132 
1133 end sub
1134 
1135 '':::::
1137  ( _
1138  byval sym as FBSYMBOL ptr _
1139  )
1140 
1141  if( symbGetCompExt( sym ) = NULL ) then
1142  exit sub
1143  end if
1144 
1145  '' for each namespace importing this ns (because one ns, when
1146  '' re-implemented, can include another ns that will be removed
1147  '' first)
1148  dim as FBSYMBOL ptr exp_ = symbGetCompExportHead( sym )
1149  do while( exp_ <> NULL )
1150 
1152 
1153  dim as FBSYMBOL ptr nxt = symbGetExportNext( exp_ )
1155 
1156  '' not a type, that's to tell NamespaceRemove() to not remove the same ns again
1157  symbGetImportNamespc( exp_ ) = NULL
1158 
1159  exp_ = nxt
1160  loop
1161 
1162 end sub
1163 
1164 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1165 '' RTTI
1166 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1167 
1169  dim as FBSYMBOL ptr rttitype = any, objtype = any, objrtti = any, ctor = any
1170 
1171  static as FBARRAYDIM dTB(0)
1172 
1173  '' type $fb_RTTI
1174  rttitype = symbStructBegin( NULL, NULL, "$fb_RTTI", "$fb_RTTI", FALSE, 0, NULL, 0 )
1175  symb.rtti.fb_rtti = rttitype
1176 
1177  '' stdlibvtable as any ptr
1178  symbAddField( rttitype, "stdlibvtable", 0, dTB(), typeAddrOf( FB_DATATYPE_VOID ), NULL, 0, 0 )
1179 
1180  '' dim id as zstring ptr
1181  symbAddField( rttitype, "id", 0, dTB(), typeAddrOf( FB_DATATYPE_CHAR ), NULL, 0, 0 )
1182 
1183  '' dim rttibase as $fb_RTTI ptr
1184  symbAddField( rttitype, "rttibase", 0, dTB(), typeAddrOf( FB_DATATYPE_STRUCT ), rttitype, 0, 0 )
1185 
1186  '' end type
1187  symbStructEnd( rttitype )
1188 
1189  '' type object
1190  dim as const zstring ptr ptypename = any
1191  if( fbLangIsSet( FB_LANG_QB ) ) then
1192  ptypename = @"__OBJECT"
1193  else
1194  ptypename = @"OBJECT"
1195  end if
1196  objtype = symbStructBegin( NULL, NULL, ptypename, "$fb_Object", FALSE, 0, NULL, 0 )
1197  symb.rtti.fb_object = objtype
1198  symbSetHasRTTI( objtype )
1199  symbSetIsUnique( objtype )
1200  symbNestBegin( objtype, FALSE )
1201 
1202  '' vptr as any ptr
1203  symbAddField( objtype, "$vptr", 0, dTB(), typeAddrOf( FB_DATATYPE_VOID ), NULL, 0, 0 )
1204 
1205  '' declare constructor( )
1206  ctor = symbPreAddProc( NULL )
1207  symbAddProcInstancePtr( objtype, ctor )
1208  symbAddCtor( ctor, NULL, FB_SYMBATTRIB_METHOD or FB_SYMBATTRIB_CONSTRUCTOR _
1209  or FB_SYMBATTRIB_OVERLOADED, FB_FUNCMODE_CDECL )
1210 
1211  '' end type
1212  symbStructEnd( objtype, TRUE )
1213 
1214  '' declare extern shared as $fb_RTTI __fb_ZTS6Object (the Object class RTTI instance created in C)
1215  objrtti = symbAddVar( NULL, "__fb_ZTS6Object", FB_DATATYPE_STRUCT, symb.rtti.fb_rtti, 0, 0, dTB(), _
1216  FB_SYMBATTRIB_EXTERN or FB_SYMBATTRIB_SHARED, FB_SYMBOPT_PRESERVECASE )
1217 
1218  '' update the obj struct RTTI (used to create the link with base classes)
1219  symbUdtAllocExt( objtype )
1220  objtype->udt.ext->rtti = objrtti
1221 end sub
1222 
1224 end sub
1225