FreeBASIC  0.91.0
ast-node-typeini.bas
Go to the documentation of this file.
1 '' AST type initializer nodes
2 '' tree : l = head; r = (when constructing: tail, when updating: base var)
3 '' expr node: l = expr; r = next
4 '' pad node : l = NULL; r = next
5 ''
6 '' chng: mar/2006 written [v1ctor]
7 
8 
9 #include once "fb.bi"
10 #include once "fbint.bi"
11 #include once "parser.bi"
12 #include once "ir.bi"
13 #include once "ast.bi"
14 
15 '':::::
16 function astTypeIniBegin _
17  ( _
18  byval dtype as integer, _
19  byval subtype as FBSYMBOL ptr, _
20  byval is_local as integer, _
21  byval ofs as longint _
22  ) as ASTNODE ptr
23 
24  dim as ASTNODE ptr n = any
25 
26  '' alloc new node
27  n = astNewNode( AST_NODECLASS_TYPEINI, _
28  dtype, _
29  subtype )
30  function = n
31 
32  n->typeini.ofs = ofs
33 
34  dim as integer add_scope = FALSE
35  if( is_local = FALSE ) then
36  if( symbIsScope( parser.currblock ) ) then
37  add_scope = not astIsTYPEINI( parser.currblock->scp.backnode )
38  else
39  add_scope = TRUE
40  end if
41  end if
42 
43  if( add_scope ) then
44  '' create a new scope block to handle temp vars allocated inside the
45  '' tree - with shared vars, the temps must be moved to another function
46  n->typeini.scp = astTempScopeBegin( n->typeini.lastscp, n )
47  else
48  n->typeini.scp = NULL
49  end if
50 
51 end function
52 
53 '':::::
54 sub astTypeIniEnd _
55  ( _
56  byval tree as ASTNODE ptr, _
57  byval is_initializer as integer _
58  )
59 
60  dim as ASTNODE ptr n = any, p = any, l = any, r = any
61  dim as longint ofs = any
62  dim as FBSYMBOL ptr sym = any
63 
64  '' can't leave r pointing to the any node as the
65  '' tail node is linked already
66  tree->r = NULL
67 
68  if( is_initializer = FALSE ) then
69  ast.typeinicount += 1
70  end if
71 
72  '' merge nested type ini trees
73  p = NULL
74  n = tree->l
75  do while( n <> NULL )
76  '' expression node?
77  if( n->class = AST_NODECLASS_TYPEINI_ASSIGN ) then
78  l = n->l
79  '' is it an ini tree too?
80  if( astIsTYPEINI( l ) ) then
81  ast.typeinicount -= 1
82 
83  ofs = n->typeini.ofs
84 
85  r = n->r
86  astDelNode( n )
87  n = l->l
88  astDelNode( l )
89 
90  '' relink
91  if( p <> NULL ) then
92  p->r = n
93  else
94  tree->l = n
95  end if
96 
97  '' update the offset, using the parent's
98  do while( n->r <> NULL )
99  n->typeini.ofs += ofs
100  n = n->r
101  loop
102  n->typeini.ofs += ofs
103 
104  n->r = r
105  end if
106  end if
107 
108  '' next
109  p = n
110  n = n->r
111  loop
112 
113  '' close the scope block
114  if( tree->typeini.scp <> NULL ) then
115  astTempScopeEnd( tree->typeini.scp, tree->typeini.lastscp )
116  end if
117 
118 end sub
119 
120 '':::::
121 function hAddNode _
122  ( _
123  byval tree as ASTNODE ptr, _
124  byval class_ as AST_NODECLASS, _
125  byval dtype as FB_DATATYPE, _
126  byval subtype as FBSYMBOL ptr _
127  ) as ASTNODE ptr static
128 
129  dim as ASTNODE ptr n
130 
131  n = astNewNode( class_, dtype, subtype )
132 
133  if( tree->r <> NULL ) then
134  tree->r->r = n
135  else
136  tree->l = n
137  end if
138 
139  tree->r = n
140 
141  function = n
142 
143 end function
144 
145 function astTypeIniAddPad _
146  ( _
147  byval tree as ASTNODE ptr, _
148  byval bytes as longint _
149  ) as ASTNODE ptr
150 
151  dim as ASTNODE ptr n = any
152 
153  n = hAddNode( tree, _
154  AST_NODECLASS_TYPEINI_PAD, _
155  FB_DATATYPE_INVALID, _
156  NULL )
157 
158  n->typeini.bytes = bytes
159  n->typeini.ofs = tree->typeini.ofs
160 
161  function = n
162 
163 end function
164 
165 '':::::
166 function astTypeIniAddAssign _
167  ( _
168  byval tree as ASTNODE ptr, _
169  byval expr as ASTNODE ptr, _
170  byval sym as FBSYMBOL ptr _
171  ) as ASTNODE ptr
172 
173  dim as ASTNODE ptr n = any
174 
175  n = hAddNode( tree, _
176  AST_NODECLASS_TYPEINI_ASSIGN, _
177  symbGetFullType( sym ), _
178  symbGetSubtype( sym ) )
179 
180  n->l = expr
181  n->sym = sym
182  n->typeini.ofs = tree->typeini.ofs
183 
184  tree->typeini.ofs += symbGetLen( sym )
185 
186  function = n
187 
188 end function
189 
190 '':::::
191 function astTypeIniAddCtorCall _
192  ( _
193  byval tree as ASTNODE ptr, _
194  byval sym as FBSYMBOL ptr, _
195  byval procexpr as ASTNODE ptr _
196  ) as ASTNODE ptr
197 
198  dim as ASTNODE ptr n = any
199 
200  n = hAddNode( tree, _
201  AST_NODECLASS_TYPEINI_CTORCALL, _
202  symbGetFullType( sym ), _
203  symbGetSubtype( sym ) )
204 
205  n->sym = sym
206  n->typeini.ofs = tree->typeini.ofs
207  n->l = procexpr
208 
209  tree->typeini.ofs += symbGetLen( sym )
210 
211  function = n
212 
213 end function
214 
215 function astTypeIniAddCtorList _
216  ( _
217  byval tree as ASTNODE ptr, _
218  byval sym as FBSYMBOL ptr, _
219  byval elements as longint _
220  ) as ASTNODE ptr
221 
222  dim as ASTNODE ptr n = any
223 
224  n = hAddNode( tree, _
225  AST_NODECLASS_TYPEINI_CTORLIST, _
226  symbGetFullType( sym ), _
227  symbGetSubtype( sym ) )
228 
229  n->sym = sym
230  n->typeini.ofs = tree->typeini.ofs
231  n->typeini.elements = elements
232 
233  tree->typeini.ofs += symbGetLen( sym ) * elements
234 
235  function = n
236 end function
237 
238 '':::::
239 function astTypeIniScopeBegin _
240  ( _
241  byval tree as ASTNODE ptr, _
242  byval sym as FBSYMBOL ptr _
243  ) as ASTNODE ptr
244 
245  dim as ASTNODE ptr n = any
246 
247  n = hAddNode( tree, _
248  AST_NODECLASS_TYPEINI_SCOPEINI, _
249  FB_DATATYPE_INVALID, _
250  NULL )
251 
252  n->sym = sym
253 
254  function = n
255 
256 end function
257 
258 '':::::
259 function astTypeIniScopeEnd _
260  ( _
261  byval tree as ASTNODE ptr, _
262  byval sym as FBSYMBOL ptr _
263  ) as ASTNODE ptr
264 
265  dim as ASTNODE ptr n = any
266 
267  n = hAddNode( tree, _
268  AST_NODECLASS_TYPEINI_SCOPEEND, _
269  FB_DATATYPE_INVALID, _
270  NULL )
271 
272  n->sym = sym
273 
274  function = n
275 
276 end function
277 
278 '' Takes an array elements initializer and adds the same TYPEINI_ASSIGN's to
279 '' the new typeini tree (duplicating the expressions),
280 '' but not the TYPEINI_SCOPEINI/TYPEINI_SCOPEEND,
281 '' and assuming there are only TYPEINI_ASSIGN's and no ctorcalls or padding etc.
282 '' "beginindex" is the index of the first TYPEINI_ASSIGN that should be copied,
283 '' this allows to skip some array elements at the front.
285  ( _
286  byval tree as ASTNODE ptr, _
287  byval source as ASTNODE ptr, _
288  byval beginindex as integer _
289  )
290 
291  dim as integer i = any
292 
293  assert( astIsTYPEINI( source ) )
294  source = source->l
295 
296  assert( source->class = AST_NODECLASS_TYPEINI_SCOPEINI )
297  source = source->r
298 
299  i = 0
300  while( source->class = AST_NODECLASS_TYPEINI_ASSIGN )
301  if( i >= beginindex ) then
302  astTypeIniAddAssign( tree, astCloneTree( source->l ), source->sym )
303  end if
304  source = source->r
305  i += 1
306  wend
307 
308  assert( source->class = AST_NODECLASS_TYPEINI_SCOPEEND )
309 end sub
310 
312  ( _
313  byval tree as ASTNODE ptr, _
314  byval element as integer, _
315  byval expr as ASTNODE ptr _
316  )
317 
318  '' Walk through the TYPEINI tree until the assign at index "element"
319  '' is reached, then replace the expression.
320  '' assumptions:
321  '' - tree is an array initializer,
322  '' - there are only TYPEINI_ASSIGN's, no ctorcalls/padding
323 
324  dim as integer i = any
325 
326  assert( astIsTYPEINI( tree ) )
327  tree = tree->l
328 
329  assert( tree->class = AST_NODECLASS_TYPEINI_SCOPEINI )
330  tree = tree->r
331 
332  i = 0
333  while( tree->class = AST_NODECLASS_TYPEINI_ASSIGN )
334  if( i = element ) then
335  astDelTree( tree->l )
336  tree->l = expr
337  exit sub
338  end if
339  tree = tree->r
340  i += 1
341  wend
342 
343  '' should always be found
344  assert( FALSE )
345 end sub
346 
347 '':::::
348 function hCallCtor _
349  ( _
350  byval flush_tree as ASTNODE ptr, _
351  byval n as ASTNODE ptr, _
352  byval basesym as FBSYMBOL ptr _
353  ) as ASTNODE ptr
354 
355  dim as FBSYMBOL ptr fld = any
356  dim as longint ofs = n->typeini.ofs
357 
358  fld = n->sym
359  if( fld <> NULL ) then
360  if( symbIsField( fld ) = FALSE ) then
361  fld = NULL
362  else
363  '' Hack'ish, but astBuildVarField() adds
364  '' this back on if fld <> NULL even
365  '' n->typeini.ofs is the offset needed.
366  ofs -= symbGetOfs( fld )
367  end if
368  end if
369 
370  '' replace the instance pointer
371  n->l = astPatchCtorCall( n->l, _
372  astBuildVarField( basesym, fld, ofs ) )
373 
374  '' do call
375  flush_tree = astNewLINK( flush_tree, n->l )
376 
377  function = flush_tree
378 
379 end function
380 
381 '':::::
382 function hCallCtorList _
383  ( _
384  byval flush_tree as ASTNODE ptr, _
385  byval n as ASTNODE ptr, _
386  byval basesym as FBSYMBOL ptr _
387  ) as ASTNODE ptr
388 
389  dim as FBSYMBOL ptr subtype = any, fld = any
390  dim as ASTNODE ptr fldexpr = any
391  dim as integer dtype = any
392  dim as longint elements = any
393 
394  fld = n->sym
395  if( fld <> NULL ) then
396  if( symbIsField( fld ) = FALSE ) then
397  fld = NULL
398  end if
399  end if
400 
401  dtype = astGetDataType( n )
402  subtype = n->subtype
403  elements = n->typeini.elements
404 
405  '' iter = *cast( subtype ptr, cast( byte ptr, @array(0) ) + ofs) )
406  fldexpr = astBuildVarField( basesym, fld, n->typeini.ofs )
407 
408  if( elements > 1 ) then
409  dim as FBSYMBOL ptr cnt, label, iter
410 
411  cnt = symbAddTempVar( FB_DATATYPE_INTEGER )
412  label = symbAddLabel( NULL )
413  iter = symbAddTempVar( typeAddrOf( dtype ), subtype )
414 
415  flush_tree = astNewLINK( flush_tree, astBuildVarAssign( iter, astNewADDROF( fldexpr ) ) )
416 
417  '' for cnt = 0 to elements-1
418  flush_tree = astBuildForBegin( flush_tree, cnt, label, 0 )
419 
420  '' ctor( *iter )
421  flush_tree = astNewLINK( flush_tree, astBuildCtorCall( subtype, astBuildVarDeref( iter ) ) )
422 
423  '' iter += 1
424  flush_tree = astNewLINK( flush_tree, astBuildVarInc( iter, 1 ) )
425 
426  '' next
427  flush_tree = astBuildForEnd( flush_tree, cnt, label, astNewCONSTi( elements ) )
428  else
429  '' ctor( this )
430  flush_tree = astNewLINK( flush_tree, astBuildCtorCall( subtype, fldexpr ) )
431  end if
432 
433  function = flush_tree
434 
435 end function
436 
437 '':::::
438 function hFlushTree _
439  ( _
440  byval tree as ASTNODE ptr, _
441  byval basesym as FBSYMBOL ptr, _
442  byval do_deref as integer _
443  ) as ASTNODE ptr
444 
445  dim as ASTNODE ptr n = any, nxt = any, flush_tree = any, lside = any
446  dim as FBSYMBOL ptr bitfield = any
447  dim as integer dtype = any
448 
449  flush_tree = NULL
450  n = tree->l
451  do while( n <> NULL )
452  nxt = n->r
453 
454  select case as const n->class
455  case AST_NODECLASS_TYPEINI_ASSIGN
456  ''
457  '' basesym is the initialization target,
458  '' either the object itself or a pointer to the target.
459  ''
460  '' n->sym (symbol associated with the TYPEINI_ASSIGN) is
461  '' the symbol that's directly initialized by this
462  '' TYPEINI_ASSIGN.
463  '' It can be the same as basesym, e.g. when initializing
464  '' a simple integer, or it can be a field while basesym
465  '' is the UDT or a pointer to it, and it can be NULL too,
466  '' at least with some parameter initializers.
467  ''
468 
469  if( symbIsParamInstance( basesym ) ) then
470  '' Assigning to object through THIS pointer, a DEREF is done.
471  lside = astBuildInstPtrAtOffset( basesym, n->sym, n->typeini.ofs )
472  else
473  '' Note: n->sym may be NULL from a astReplaceSymbolOnTree(),
474  '' so n's dtype/subtype are used instead.
475 
476  if( do_deref ) then
477  '' Assigning to object through pointer, a DEREF is done.
478  assert( typeIsPtr( symbGetType( basesym ) ) )
479 
480  ''
481  '' Must make sure to have the proper type on the DEREF,
482  '' otherwise the ASSIGN to it will fail or be wrong and
483  '' possibly cause trouble with the backends.
484  ''
485  '' We need to do a typeDeref() if it's the basesym pointer,
486  '' but not if it's something else (e.g. a field).
487  '' TODO: is this check correct/enough?
488  ''
489  dtype = n->dtype
490  if( n->sym = basesym ) then
491  assert( typeIsPtr( dtype ) )
492  dtype = typeDeref( dtype )
493  end if
494 
495  lside = astNewDEREF( astNewVAR( basesym ), dtype, n->subtype, n->typeini.ofs )
496  else
497  '' Assigning to object directly
498  lside = astNewVAR( basesym, n->typeini.ofs, astGetFullType( n ), n->subtype )
499  end if
500 
501  if( n->sym ) then
502  '' Field?
503  if( symbIsField( n->sym ) ) then
504  '' If it's a bitfield, clear the whole field containing this bitfield,
505  '' otherwise the bitfield assignment(s) would leave unused bits
506  '' uninitialized.
507 
508  '' Bitfield?
509  if( astGetDataType( lside ) = FB_DATATYPE_BITFIELD ) then
510  bitfield = astGetSubType( lside )
511  assert( symbIsBitfield( bitfield ) )
512  assert( typeGetClass( symbGetType( bitfield ) ) = FB_DATACLASS_INTEGER )
513 
514  '' Beginning of a field containing one or more bitfields?
515  if( bitfield->bitfld.bitpos = 0 ) then
516  flush_tree = astNewLINK( flush_tree, _
517  astNewMEM( AST_OP_MEMCLEAR, _
518  astCloneTree( lside ), _
519  astNewCONSTi( typeGetSize( symbGetType( bitfield ) ) ) ) )
520  end if
521  end if
522 
523  lside = astNewFIELD( lside, n->sym )
524  end if
525  end if
526  end if
527 
528  lside = astNewASSIGN( lside, n->l, AST_OPOPT_ISINI or AST_OPOPT_DONTCHKPTR )
529  assert( lside <> NULL )
530  flush_tree = astNewLINK( flush_tree, lside )
531 
532  case AST_NODECLASS_TYPEINI_PAD
533  '' Clear some padding bytes...
534  if( symbIsParamInstance( basesym ) ) then
535  '' through THIS pointer
536  lside = astBuildInstPtrAtOffset( basesym, NULL, n->typeini.ofs )
537  else
538  if( do_deref ) then
539  '' through a pointer
540  assert( typeIsPtr( symbGetFullType( basesym ) ) )
541  lside = astNewDEREF( astNewVAR( basesym ), , , n->typeini.ofs )
542  else
543  '' directly
544  lside = astNewVAR( basesym, n->typeini.ofs )
545  end if
546  end if
547 
548  flush_tree = astNewLINK( flush_tree, _
549  astNewMEM( AST_OP_MEMCLEAR, lside, astNewCONSTi( n->typeini.bytes ) ) )
550 
551  case AST_NODECLASS_TYPEINI_CTORCALL
552  flush_tree = hCallCtor( flush_tree, n, basesym )
553 
554  case AST_NODECLASS_TYPEINI_CTORLIST
555  flush_tree = hCallCtorList( flush_tree, n, basesym )
556 
557  end select
558 
559  astDelNode( n )
560  n = nxt
561  loop
562 
563  function = flush_tree
564 end function
565 
566 '':::::
567 function hFlushExprStatic _
568  ( _
569  byval n as ASTNODE ptr, _
570  byval basesym as FBSYMBOL ptr _
571  ) as integer
572 
573  dim as ASTNODE ptr expr = any
574  dim as integer edtype = any, sdtype = any
575  dim as FBSYMBOL ptr sym = any, litsym = any
576 
577  function = FALSE
578 
579  expr = n->l
580  sym = n->sym
581  edtype = astGetDataType( expr )
582  sdtype = symbGetType( sym )
583 
584  litsym = NULL
585  select case edtype
586  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
587  litsym = astGetStrLitSymbol( expr )
588  end select
589 
590  '' not a literal string?
591  if( litsym = NULL ) then
592  '' offset?
593  if( astIsOFFSET( expr ) ) then
594  irEmitVARINIOFS( astGetSymbol( expr ), expr->ofs.ofs )
595  '' anything else
596  else
597  '' different types?
598  if( edtype <> sdtype ) then
599  expr = astNewCONV( symbGetFullType( sym ), symbGetSubtype( sym ), expr, AST_CONVOPT_DONTCHKPTR )
600  assert( expr <> NULL )
601  end if
602 
603  assert( astIsCONST( expr ) )
604  if( typeGetClass( sdtype ) = FB_DATACLASS_FPOINT ) then
605  irEmitVARINIf( sym, astConstGetFloat( expr ) )
606  else
607  irEmitVARINIi( sym, astConstGetInt( expr ) )
608  end if
609  end if
610 
611  '' literal string..
612  else
613  '' not a wstring?
614  if( sdtype <> FB_DATATYPE_WCHAR ) then
615 
616  '' convert?
617  if( edtype <> FB_DATATYPE_WCHAR ) then
618  '' less the null-char
619  irEmitVARINISTR( symbGetStrLen( sym ) - 1, _
620  symbGetVarLitText( litsym ), _
621  symbGetStrLen( litsym ) - 1 )
622  else
623  '' ditto
624  irEmitVARINISTR( symbGetStrLen( sym ) - 1, _
625  str( *symbGetVarLitTextW( litsym ) ), _
626  symbGetWstrLen( litsym ) - 1 )
627  end if
628 
629 
630  '' wstring..
631  else
632 
633  '' convert?
634  if( edtype <> FB_DATATYPE_WCHAR ) then
635  '' less the null-char
636  irEmitVARINIWSTR( symbGetWstrLen( sym ) - 1, _
637  wstr( *symbGetVarLitText( litsym ) ), _
638  symbGetStrLen( litsym ) - 1 )
639  else
640  '' ditto
641  irEmitVARINIWSTR( symbGetWstrLen( sym ) - 1, _
642  symbGetVarLitTextW( litsym ), _
643  symbGetWstrLen( litsym ) - 1 )
644  end if
645 
646  end if
647 
648  end if
649 
650  astDelTree( n->l )
651  n->l = NULL
652 
653  function = TRUE
654 
655 end function
656 
657 '':::::
658 function hFlushTreeStatic _
659  ( _
660  byval tree as ASTNODE ptr, _
661  byval basesym as FBSYMBOL ptr _
662  ) as integer
663 
664  dim as ASTNODE ptr n = any, nxt = any
665 
666  function = FALSE
667 
668  irEmitVARINIBEGIN( basesym )
669 
670  n = tree->l
671  do while( n <> NULL )
672  nxt = n->r
673 
674  select case as const n->class
675  case AST_NODECLASS_TYPEINI_PAD
676  irEmitVARINIPAD( n->typeini.bytes )
677 
678  case AST_NODECLASS_TYPEINI_SCOPEINI
679  irEmitVARINISCOPEBEGIN( )
680 
681  case AST_NODECLASS_TYPEINI_SCOPEEND
682  irEmitVARINISCOPEEND( )
683 
684  case else
685  hFlushExprStatic( n, basesym )
686  end select
687 
688  astDelNode( n )
689  n = nxt
690  loop
691 
692  irEmitVARINIEND( basesym )
693 
694  function = TRUE
695 
696 end function
697 
698 function astTypeIniFlush _
699  ( _
700  byval tree as ASTNODE ptr, _
701  byval basesym as FBSYMBOL ptr, _
702  byval options as AST_INIOPT _
703  ) as ASTNODE ptr
704 
705  '' quick workaround for #2688314: tree can be null in some cases, so can't do assert
706  '' TODO: find out why, but for now, only cases seem to be when errors exceed -maxerr
707  #if 0
708  assert( tree <> NULL )
709  #else
710  if( tree = NULL ) then return NULL
711  #endif
712 
713  if( (options and AST_INIOPT_ISINI) = 0 ) then
714  ast.typeinicount -= 1
715  end if
716 
717  if( (options and AST_INIOPT_ISSTATIC) <> 0 ) then
718  hFlushTreeStatic( tree, basesym )
719  function = NULL
720  else
721  function = hFlushTree( tree, basesym, ((options and AST_INIOPT_DODEREF) <> 0) )
722  end if
723 
724  astDelNode( tree )
725 
726 end function
727 
728 '':::::
729 function hExprIsConst _
730  ( _
731  byval n as ASTNODE ptr _
732  ) as integer
733 
734  dim as FBSYMBOL ptr sym = any, litsym = any
735  dim as ASTNODE ptr expr = any
736  dim as integer sdtype = any, edtype = any
737 
738  sym = n->sym
739  expr = n->l
740 
741  sdtype = symbGetType( sym )
742  edtype = astGetDataType( expr )
743 
744  '' check if it's a literal string
745  litsym = NULL
746  select case edtype
747  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
748  litsym = astGetStrLitSymbol( expr )
749  end select
750 
751  '' not a literal string?
752  if( litsym = NULL ) then
753 
754  '' string?
755  if( symbIsString( sdtype ) ) then
756  if( symbIsString( edtype ) ) then
757  errReport( FB_ERRMSG_EXPECTEDCONST, TRUE )
758  else
759  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
760  end if
761  exit function
762 
763  elseif( symbIsString( edtype ) ) then
764  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
765  exit function
766  end if
767 
768  '' bit field?
769  if( symbIsField( sym ) ) then
770  if( symbGetType( sym ) = FB_DATATYPE_BITFIELD ) then
771  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
772  exit function
773  end if
774  end if
775 
776  '' offset?
777  if( astIsOFFSET( expr ) ) then
778  '' different types?
779  if( (typeGetClass( sdtype ) <> FB_DATACLASS_INTEGER) or _
780  (typeGetSize( sdtype ) <> env.pointersize) ) then
781  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
782  exit function
783  end if
784  else
785  '' not a constant?
786  if( astIsCONST( expr ) = FALSE ) then
787  errReport( FB_ERRMSG_EXPECTEDCONST, TRUE )
788  exit function
789  end if
790  end if
791 
792  '' literal string..
793  else
794  '' not a string?
795  if( symbIsString( sdtype ) = FALSE ) then
796  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
797  exit function
798  end if
799 
800  '' can't be a variable-len string
801  if( sdtype = FB_DATATYPE_STRING ) then
802  errReport( FB_ERRMSG_CANTINITDYNAMICSTRINGS, TRUE )
803  exit function
804  end if
805 
806  end if
807 
808  function = TRUE
809 
810 end function
811 
812 '':::::
813 function astTypeIniIsConst _
814  ( _
815  byval tree as ASTNODE ptr _
816  ) as integer
817 
818  dim as ASTNODE ptr n = any
819 
820  function = FALSE
821 
822  n = tree->l
823  do while( n <> NULL )
824 
825  select case n->class
826  case AST_NODECLASS_TYPEINI_ASSIGN
827  if( hExprIsConst( n ) = FALSE ) then
828  exit function
829  end if
830 
831  case AST_NODECLASS_TYPEINI_CTORCALL, AST_NODECLASS_TYPEINI_CTORLIST
832  exit function
833  end select
834 
835  n = n->r
836  loop
837 
838  function = TRUE
839 
840 end function
841 
842 function astTypeIniUsesLocals _
843  ( _
844  byval n as ASTNODE ptr, _
845  byval ignoreattrib as integer _
846  ) as integer
847 
848  if( n = NULL ) then
849  return FALSE
850  end if
851 
852  #if __FB_DEBUG__
853  static as integer reclevel
854  if( reclevel = 0 ) then
855  assert( astIsTYPEINI( n ) )
856  end if
857  #endif
858 
859  '' Some TYPEINI expressions (like param/field initializers) can not
860  '' reference local vars because they may be duplicated into other scope
861  '' contexts, where those locals do not exist. In their case, only temp
862  '' vars/descriptors can be allowed, because they're handled by the
863  '' TYPEINI's implicit scope and will be duplicated along with the
864  '' expression. Local STATICs can be allowed too, because they're not
865  '' allocated on stack but instead as globals.
866  ''
867  '' For other TYPEINI expressions such as global var initializers,
868  '' no locals (including local statics) can be allowed at all, because by
869  '' the time the global vars will be emitted, procs and their locals are
870  '' emitted and deleted already.
871  ''
872  '' TYPEINI expressions for local vars don't even need to be checked with
873  '' this function because they stay in the scope where they are found
874  '' and thus can use as many locals as they want.
875 
876  if( astIsVAR( n ) ) then
877  '' ignoreattrib = the "good" attributes that should be allowed,
878  '' i.e. don't count as "locals" to this function. If we find
879  '' a LOCAL here, we only report it back to the caller if it
880  '' has none of these attributes.
881  if( symbIsLocal( n->sym ) and _
882  ((symbGetAttrib( n->sym ) and ignoreattrib) = 0) ) then
883  return TRUE
884  end if
885  end if
886 
887  #if __FB_DEBUG__
888  reclevel += 1
889  #endif
890 
891  '' walk
892  function = astTypeIniUsesLocals( n->l, ignoreattrib ) or _
893  astTypeIniUsesLocals( n->r, ignoreattrib )
894 
895  #if __FB_DEBUG__
896  reclevel -= 1
897  #endif
898 end function
899 
900 function hWalk _
901  ( _
902  byval n as ASTNODE ptr, _
903  byval parent as ASTNODE ptr _
904  ) as ASTNODE ptr
905 
906  dim as ASTNODE ptr expr = any
907  dim as FBSYMBOL ptr sym = any
908 
909  if( n = NULL ) then
910  return NULL
911  end if
912 
913  if( astIsTYPEINI( n ) ) then
914  '' Create a temporary variable which is initialized by the
915  '' astTypeIniFlush() below.
916  sym = symbAddTempVar( astGetFullType( n ), n->subtype )
917  astDtorListAdd( sym )
918 
919  '' Update the parent node in the original tree to access the
920  '' temporary variable, instead of the TYPEINI. (it could be an
921  '' ASSIGN, ADDROF, ARG, etc, or a fake temporary parent node in
922  '' case that TYPEINI was the root of the original tree)
923  expr = astNewVAR( sym )
924  if( parent->l = n ) then
925  parent->l = expr
926  else
927  parent->r = expr
928  end if
929 
930  '' Turn this TYPEINI into real code
931  n = astTypeIniFlush( n, sym, AST_INIOPT_NONE )
932 
933  '' Also update any nested TYPEINIs, for example this can be a
934  '' TYPEINI CTORCALL, which carries a CALL with ARGs that can
935  '' have TYPEINIs themselves.
936  return astTypeIniUpdate( n )
937  end if
938 
939  '' walk
940  return astNewLINK( hWalk( n->l, n ), hWalk( n->r, n ) )
941 end function
942 
943 #if __FB_DEBUG__
944 '' Count the TYPEINI nodes in a tree
945 function astCountTypeinis( byval n as ASTNODE ptr ) as integer
946  dim as integer count = any
947 
948  count = 0
949 
950  if( n ) then
951  if( astIsTYPEINI( n ) ) then
952  count += 1
953  end if
954 
955  count += astCountTypeinis( n->l )
956  count += astCountTypeinis( n->r )
957  end if
958 
959  function = count
960 end function
961 #endif
962 
963 function astTypeIniUpdate( byval tree as ASTNODE ptr ) as ASTNODE ptr
964  dim as ASTNODE ptr tempvarinitcode = any
965  dim as ASTNODE treeparent = any
966 
967  '' Shouldn't miss any TYPEINIs
968  assert( astCountTypeinis( tree ) <= ast.typeinicount )
969 
970  '' Shortcut if there are no TYPEINIs
971  if( ast.typeinicount <= 0 ) then
972  return tree
973  end if
974 
975  '' Wrap the tree in a fake temporary parent node, so hWalk() has a
976  '' parent node to update in case the tree's root already is a TYPEINI.
977  '' (Set it to NOP, to add some consistency with real ASTNODEs, better
978  '' than nothing. NOPs don't require any other ASTNODE fields to be set)
979  astInitNode( (@treeparent), AST_NODECLASS_NOP, FB_DATATYPE_INVALID, NULL )
980  treeparent.l = tree
981 
982  '' Walk to expand any TYPEINIs. Note that the original tree will be
983  '' updated too, and both are needed. The new tree built up by hWalk()
984  '' initializes the temp var with the TYPEINI data; the original tree
985  '' must be updated to now access that temp var instead of the TYPEINI.
986  tempvarinitcode = hWalk( tree, @treeparent )
987 
988  '' The temp var initialization must be first in the LINK because it must
989  '' be executed before the tree which accesses that temp var. The LINK
990  '' as a whole should still return the result of the tree though, so that
991  '' astTypeIniUpdate() can be used in the middle of an expression.
992  function = astNewLINK( tempvarinitcode, treeparent.l, FALSE )
993 end function
994 
995 '' Duplicates a TYPEINI initializer into the current context. The cloned TYPEINI
996 '' won't have a temp scope on its own; instead any temp symbols from the
997 '' original TYPEINI's temp scope are duplicated into the current scope context.
998 function astTypeIniClone( byval tree as ASTNODE ptr ) as ASTNODE ptr
999  dim as ASTNODE ptr clonetree = any
1000 
1001  assert( astIsTYPEINI( tree ) )
1002 
1003  clonetree = astCloneTree( tree )
1004 
1005  if( tree->typeini.scp ) then
1006  astTempScopeClone( tree->typeini.scp, clonetree )
1007  end if
1008 
1009  function = clonetree
1010 end function
1011 
1012 '' If it's only a TYPEINI_ASSIGN, and not for an UDT with a single field,
1013 '' then just remove the TYPEINI( TYPEINI_ASSIGN( foo ) ) and return only foo.
1014 function astTypeIniTryRemove( byval tree as ASTNODE ptr ) as ASTNODE ptr
1015  assert( astIsTYPEINI( tree ) )
1016 
1017  function = tree
1018 
1019  '' More than one node?
1020  if( tree->l->r ) then
1021  exit function
1022  end if
1023 
1024  '' First node is not a TYPEINI_ASSIGN?
1025  if( tree->l->class <> AST_NODECLASS_TYPEINI_ASSIGN ) then
1026  exit function
1027  end if
1028 
1029  '' Not the same type (detects the case when the TYPEINI is for an UDT,
1030  '' and the first TYPEINI_ASSIGN is for the first field)
1031  if( (astGetDataType( tree ) <> astGetDataType( tree->l )) or _
1032  (tree->subtype <> tree->l->subtype) ) then
1033  exit function
1034  end if
1035 
1036  function = tree->l->l
1037  astDelNode( tree->l )
1038  astDelNode( tree )
1039  ast.typeinicount -= 1
1040 end function
1041 
1042 '' For deleting param/var/field initializer TYPEINIs and their temp scope
1043 sub astTypeIniDelete( byval tree as ASTNODE ptr )
1044  assert( astIsTYPEINI( tree ) )
1045 
1046  if( tree->typeini.scp ) then
1047  astTempScopeDelete( tree->typeini.scp )
1048  tree->typeini.scp = NULL
1049  end if
1050 
1051  astDelTree( tree )
1052 end sub
1053