FreeBASIC  0.91.0
ast-node-assign.bas
Go to the documentation of this file.
1 '' AST assignment nodes
2 '' l = destine; r = source
3 ''
4 '' chng: sep/2004 written [v1ctor]
5 
6 #include once "fb.bi"
7 #include once "fbint.bi"
8 #include once "ir.bi"
9 #include once "rtl.bi"
10 #include once "ast.bi"
11 
12 function hCheckStringOps _
13  ( _
14  byval l as ASTNODE ptr, _
15  byval ldclass as FB_DATACLASS, _
16  byval r as ASTNODE ptr, _
17  byval rdclass as FB_DATACLASS _
18  ) as integer
19 
20  dim as ASTNODE ptr other = any
21 
22  function = FALSE
23 
24  '' Other operand must be a z/wstring then
25  '' (since they're not both strings)
26  if( ldclass = FB_DATACLASS_STRING ) then
27  other = r
28  else
29  other = l
30  end if
31 
32  select case( astGetDataType( other ) )
33  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
34 
35  case else
36  exit function
37  end select
38 
39  function = TRUE
40 end function
41 
42 '':::::
43 function hCheckUDTOps _
44  ( _
45  byval l as ASTNODE ptr, _
46  byval ldclass as FB_DATACLASS, _
47  byref r as ASTNODE ptr, _
48  byval rdclass as FB_DATACLASS, _
49  byval checkOnly as integer = TRUE _
50  ) as integer
51 
52  dim as FBSYMBOL ptr proc = any
53 
54  function = FALSE
55 
56  '' l node must be an UDT's,
57  if( astGetDataType( l ) <> FB_DATATYPE_STRUCT ) then
58  exit function
59  else
60  '' "udtfunct() = udt" is not allowed, l node must be a variable
61  if( l->class = AST_NODECLASS_CALL ) then
62  exit function
63  end if
64  end if
65 
66  '' is r an UDT?
67  if( astGetDataType( r ) <> FB_DATATYPE_STRUCT ) then
68  exit function
69  end if
70 
71  '' different subtypes?
72  if( l->subtype <> r->subtype ) then
73  '' check if lhs is a base type of rhs
74  if( symbGetUDTBaseLevel( r->subtype, l->subtype ) = 0 ) then
75  exit function
76  End If
77 
78  '' cast to the base type
79  if( checkOnly = FALSE ) then
80  r = astNewCONV( astGetDataType( l ), l->subtype, r )
81  end if
82  end if
83 
84  function = TRUE
85 
86 end function
87 
88 '':::::
89 function hCheckWstringOps _
90  ( _
91  byval l as ASTNODE ptr, _
92  byref ldfull as integer, _
93  byval r as ASTNODE ptr, _
94  byref rdfull as integer, _
95  byref is_zstr as integer _
96  ) as integer
97 
98  function = FALSE
99 
100  dim as integer ldtype = any, rdtype = any
101 
102  ldtype = typeGet( ldfull )
103  rdtype = typeGet( rdfull )
104 
105  '' left?
106  if( ldtype = FB_DATATYPE_WCHAR ) then
107  '' is right a zstring? (fixed- or
108  '' var-len strings won't reach here)
109  is_zstr = (rdtype = FB_DATATYPE_CHAR)
110  '' right?
111  else
112  '' is left a zstring?
113  is_zstr = (ldtype = FB_DATATYPE_CHAR)
114  end if
115 
116  if( is_zstr ) then
117  return TRUE
118  end if
119 
120  '' one is not a string, nor a udt, treat as
121  '' numeric type, let emit convert them if needed..
122  if( ldtype = FB_DATATYPE_WCHAR ) then
123  '' don't allow, unless it's a pointer
124  if( astIsDEREF( l ) = FALSE ) then
125  exit function
126  end if
127 
128  '' remap the type or the optimizer will
129  '' assume it's a string assignment
130  ldfull = typeJoin( ldfull, env.target.wchar )
131  else
132  '' same as above..
133  if( astIsDEREF( r ) = FALSE ) then
134  exit function
135  end if
136 
137  rdfull = typeJoin( rdfull, env.target.wchar )
138  end if
139 
140  function = TRUE
141 end function
142 
143 function hCheckZstringOps _
144  ( _
145  byval l as ASTNODE ptr, _
146  byref ldfull as integer, _
147  byval r as ASTNODE ptr, _
148  byref rdfull as integer _
149  ) as integer
150 
151  function = FALSE
152 
153  '' same as for wstring's..
154  if( typeGet( ldfull ) = FB_DATATYPE_CHAR ) then
155  '' don't allow, unless it's a pointer
156  if( astIsDEREF( l ) = FALSE ) then
157  exit function
158  end if
159 
160  ldfull = typeJoin( ldfull, FB_DATATYPE_UBYTE )
161  else
162  '' same as above..
163  if( astIsDEREF( r ) = FALSE ) then
164  exit function
165  end if
166 
167  rdfull = typeJoin( rdfull, FB_DATATYPE_UBYTE )
168  end if
169 
170  function = TRUE
171 end function
172 
173 '':::::
174 sub hCheckEnumOps _
175  ( _
176  byval l as ASTNODE ptr, _
177  byval ldclass as FB_DATACLASS, _
178  byval r as ASTNODE ptr, _
179  byval rdclass as FB_DATACLASS _
180  )
181 
182  '' not the same?
183  if( astGetDataType( l ) <> astGetDataType( r ) ) then
184  if( (ldclass <> FB_DATACLASS_INTEGER) or _
185  (rdclass <> FB_DATACLASS_INTEGER) ) then
186  errReportWarn( FB_WARNINGMSG_IMPLICITCONVERSION )
187  end if
188  end if
189 
190 end sub
191 
192 function hCheckConstAndPointerOps _
193  ( _
194  byval l as ASTNODE ptr, _
195  byval ldtype as FB_DATATYPE, _
196  byval r as ASTNODE ptr, _
197  byval rdtype as FB_DATATYPE _
198  ) as integer
199 
200  function = FALSE
201 
202  '' lhs marked CONST? disallow the assignment then.
203  if( symbCheckConstAssign( ldtype, rdtype, l->subtype, r->subtype ) = FALSE ) then
204  errReport( FB_ERRMSG_ILLEGALASSIGNMENT, TRUE )
205  exit function
206  end if
207 
208  if( typeIsPtr( ldtype ) ) then
209  '' Disallow ptr = float
210  if( typeGetClass( rdtype ) = FB_DATACLASS_FPOINT ) then
211  exit function
212  end if
213 
214  if( astPtrCheck( ldtype, l->subtype, r ) = FALSE ) then
215  '' if both are UDT, a derived lhs can't be assigned from a base rhs
216  if( typeGetDtOnly( ldtype ) = FB_DATATYPE_STRUCT and typeGetDtOnly( rdtype ) = FB_DATATYPE_STRUCT ) then
217  if( symbGetUDTBaseLevel( astGetSubType( l ), astGetSubType( r ) ) > 0 ) then
218  errReport( FB_ERRMSG_ILLEGALASSIGNMENT, TRUE )
219  exit function
220  end if
221  end if
222 
223  '' Only show the warning if the coming astNewCONV() will probably succeed
224  if( astCheckCONV( l->dtype, l->subtype, r ) ) then
225  errReportWarn( FB_WARNINGMSG_SUSPICIOUSPTRASSIGN )
226  end if
227  end if
228 
229  '' r-side expr is a ptr?
230  elseif( typeIsPtr( rdtype ) ) then
231  '' Disallow float = ptr
232  if( typeGetClass( ldtype ) = FB_DATACLASS_FPOINT ) then
233  exit function
234  end if
235  errReportWarn( FB_WARNINGMSG_IMPLICITCONVERSION )
236  end if
237 
238  function = TRUE
239 end function
240 
241 '':::::
242 function astCheckASSIGN _
243  ( _
244  byval l as ASTNODE ptr, _
245  byval r as ASTNODE ptr _
246  ) as integer
247 
248  dim as ASTNODE ptr n = any
249  dim as FB_DATATYPE ldtype = any, rdtype = any, ldfull = any, rdfull = any
250  dim as FB_DATACLASS ldclass = any, rdclass = any
251 
252  function = FALSE
253 
254  ldfull = astGetFullType( l )
255  rdfull = astGetFullType( r )
256  ldtype = typeGet( ldfull )
257  rdtype = typeGet( rdfull )
258  ldclass = typeGetClass( ldtype )
259  rdclass = typeGetClass( rdtype )
260 
261  '' strings?
262  if( (ldclass = FB_DATACLASS_STRING) or _
263  (rdclass = FB_DATACLASS_STRING) ) then
264 
265  '' both not strings?
266  if( ldclass <> rdclass ) then
267  if( hCheckStringOps( l, ldclass, r, rdclass ) = FALSE ) then
268  exit function
269  end if
270  end if
271 
272  return TRUE
273 
274  '' UDT's?
275  elseif( (ldtype = FB_DATATYPE_STRUCT) or _
276  (rdtype = FB_DATATYPE_STRUCT) ) then
277 
278  if( hCheckUDTOps( l, ldclass, r, rdclass, TRUE ) = FALSE ) then
279  exit function
280  end if
281 
282  return TRUE
283 
284  '' wstrings?
285  elseif( (ldtype = FB_DATATYPE_WCHAR) or _
286  (rdtype = FB_DATATYPE_WCHAR) ) then
287 
288  '' both = wstrings?
289  if( ldtype <> rdtype ) then
290  dim as integer is_zstr
291  if( hCheckWstringOps( l, ldfull, r, rdfull, is_zstr ) = FALSE ) then
292  exit function
293  end if
294 
295  if( is_zstr ) then
296  return TRUE
297  end if
298 
299  '' hCheckWstringOps() may have remapped the types
300  ldclass = typeGetClass( ldfull )
301  rdclass = typeGetClass( rdfull )
302  ldtype = typeGet( ldfull )
303  rdtype = typeGet( rdfull )
304  end if
305 
306  '' zstrings?
307  elseif( (ldtype = FB_DATATYPE_CHAR) or _
308  (rdtype = FB_DATATYPE_CHAR) ) then
309 
310  '' both zstrings?
311  if( ldtype = rdtype ) then
312  return TRUE
313  end if
314 
315  if( hCheckZstringOps( l, ldfull, r, rdfull ) = FALSE ) then
316  exit function
317  end if
318 
319  '' hCheckZstringOps() may have remapped the types
320  ldclass = typeGetClass( ldfull )
321  rdclass = typeGetClass( rdfull )
322  ldtype = typeGet( ldfull )
323  rdtype = typeGet( rdfull )
324 
325  '' enums?
326  elseif( (ldtype = FB_DATATYPE_ENUM) or _
327  (rdtype = FB_DATATYPE_ENUM) ) then
328  hCheckEnumOps( l, ldclass, r, rdclass )
329  end if
330 
331  '' check pointers
332  if( hCheckConstAndPointerOps( l, ldfull, r, rdfull ) = FALSE ) then
333  exit function
334  end if
335 
336  '' convert types if needed
337  if( ldtype <> rdtype ) then
338  '' don't convert strings
339  if( rdclass <> FB_DATACLASS_STRING ) then
340  '' constant?
341  if( astIsCONST( r ) ) then
342  r = astNewCONV( ldfull, l->subtype, r )
343  if( r = NULL ) then
344  exit function
345  end if
346  end if
347 
348  if( astCheckCONV( ldfull, l->subtype, r ) = FALSE ) then
349  exit function
350  end if
351  end if
352  end if
353 
354  function = TRUE
355 end function
356 
357 function astCheckASSIGNToType _
358  ( _
359  byval ldtype as integer, _
360  byval lsubtype as FBSYMBOL ptr, _
361  byval r as ASTNODE ptr _
362  ) as integer
363 
364  dim as ASTNODE ptr l = any
365 
366  l = astNewVAR( NULL, 0, ldtype, lsubtype )
367 
368  function = astCheckASSIGN( l, r )
369 
370  astDelTree( l )
371 end function
372 
373 '':::::
374 function astNewASSIGN _
375  ( _
376  byval l as ASTNODE ptr, _
377  byval r as ASTNODE ptr, _
378  byval options as AST_OPOPT _
379  ) as ASTNODE ptr
380 
381  dim as ASTNODE ptr n = any
382  dim as FB_DATATYPE ldtype = any, rdtype = any, ldfull = any, rdfull = any
383  dim as FB_DATACLASS ldclass = any, rdclass = any
384  dim as FBSYMBOL ptr lsubtype = any, proc = any
385  dim as FB_ERRMSG err_num = any
386  dim as integer do_move = any
387 
388  function = NULL
389 
390  if( (l = NULL) or (r = NULL) ) then
391  exit function
392  end if
393 
394  ldfull = astGetFullType( l )
395  ldtype = typeGet( ldfull )
396  ldclass = typeGetClass( ldtype )
397  lsubtype = l->subtype
398 
399  rdfull = astGetFullType( r )
400  rdtype = typeGet( rdfull )
401  rdclass = typeGetClass( rdtype )
402 
403  '' 1st) check assign op overloading (unless the types are the same and
404  '' there's no clone function: just do a shallow copy)
405  if( (options and AST_OPOPT_DONTCHKOPOVL) = 0 ) then
406 
407  dim as integer check_letop = TRUE
408 
409  select case as const ldtype
410  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
411  if( ldtype = rdtype ) then
412  if( l->subtype = r->subtype ) then
413 
414  '' Only invoke the LET operator if it's not an
415  '' initialization. The initializer should be
416  '' a fully constructed object.
417  if( (options and AST_OPOPT_ISINI) = 0 ) then
418  check_letop = (symbGetCompCloneProc( l->subtype ) <> NULL)
419  else
420  check_letop = FALSE
421  end if
422  end if
423  end if
424  end select
425 
426  if( check_letop ) then
427  proc = symbFindSelfBopOvlProc( AST_OP_ASSIGN, l, r, @err_num )
428  if( proc <> NULL ) then
429  dim as ASTNODE ptr result = any
430 
431  '' if this is a variable initialization, we have to
432  '' ensure that the variable is zeroed in memory,
433  '' because operator let could do nothing.
434  if( (options and AST_OPOPT_ISINI) <> 0 ) then
435  if( symbGetCompDefCtor( l->subtype ) <> NULL ) then
436  result = astBuildCtorCall( l->subtype, astCloneTree( l ) )
437  else
438  result = astNewMEM( AST_OP_MEMCLEAR, _
439  astCloneTree( l ), _
440  astNewCONSTi( symbGetLen( l->subtype ) ) )
441  end if
442  else
443  result = NULL
444  end if
445 
446  '' build a proc call
447  return astNewLINK( result, astBuildCall( proc, l, r ) )
448  end if
449 
450  if( err_num <> FB_ERRMSG_OK ) then
451  return NULL
452  end if
453  end if
454  end if
455 
456  '' 2nd) implicit casting op overloading
457  if( (options and AST_OPOPT_DONTCHKOPOVL) = 0 ) then
458  proc = symbFindCastOvlProc( ldfull, lsubtype, r, @err_num )
459  if( proc <> NULL ) then
460 
461  '' we don't have to worry about initializing the lhs
462  '' in case of an initialization, this is because in
463  '' parser-decl-symb-init.bas::hDoAssign( ), the node
464  '' has already been converted if necessary, therefore
465  '' it would fall back on either a shallow copy, or the
466  '' operator LET, which was handled just above.
467 
468  '' build a proc call
469  r = astBuildCall( proc, r )
470  else
471  if( err_num <> FB_ERRMSG_OK ) then
472  return NULL
473  end if
474  end if
475  end if
476 
477  rdfull = astGetFullType( r )
478  rdtype = typeGet( rdfull )
479  rdclass = typeGetClass( rdtype )
480 
481  '' strings?
482  if( (ldclass = FB_DATACLASS_STRING) or _
483  (rdclass = FB_DATACLASS_STRING) ) then
484 
485  '' both not strings?
486  if( ldclass <> rdclass ) then
487  if( hCheckStringOps( l, ldclass, r, rdclass ) = FALSE ) then
488  exit function
489  end if
490 
491  return rtlStrAssign( l, r, (options and AST_OPOPT_ISINI) <> 0 )
492  end if
493 
494  '' otherwise, don't do any assignment by now to allow optimizations..
495  if( (options and AST_OPOPT_ISINI) <> 0 ) then
496  '' unless it's an initialization
497  return rtlStrAssign( l, r, TRUE )
498  end if
499 
500  '' UDT's?
501  elseif( (ldtype = FB_DATATYPE_STRUCT) or _
502  (rdtype = FB_DATATYPE_STRUCT) ) then
503 
504  if( hCheckUDTOps( l, ldclass, r, rdclass, FALSE ) = FALSE ) then
505  exit function
506  end if
507 
508  '' type ini tree?
509  if( astIsTYPEINI( r ) ) then
510  '' skip any casting if they won't do any conversion
511  dim as ASTNODE ptr t = l
512  if( l->class = AST_NODECLASS_CONV ) then
513  if( l->cast.doconv = FALSE ) then
514  t = l->l
515  end if
516  end if
517 
518  '' Initialize the lhs with the TYPEINI directly,
519  '' instead of using a temp var and then copying that,
520  '' unless there are ctors/dtors (let/cast overloads were
521  '' already handled above).
522  '' FIXME: This currently only works with VAR on the lhs,
523  '' because astTypeIniFlush() takes a symbol, not an expression...
524  if( t->class = AST_NODECLASS_VAR ) then
525  if( (symbHasCtor( t->sym ) or symbHasDtor( t->sym )) = FALSE ) then
526  return astTypeIniFlush( r, t->sym, AST_INIOPT_NONE )
527  end if
528  end if
529  end if
530 
531  '' Do a shallow copy
532 
533  if( astIsCALL( r ) ) then
534  do_move = symbProcReturnsOnStack( r->sym )
535  if( do_move ) then
536  '' Returning on stack, copy from the temp result var
537  r = astBuildCallResultVar( r )
538  else
539  assert( symbProcReturnsByref( r->sym ) = FALSE )
540 
541  '' Returning in registers, patch the types and do a normal ASSIGN
542  ldfull = symbGetProcRealType( r->sym )
543  ldtype = typeGet( ldfull )
544  lsubtype = symbGetProcRealSubtype( r->sym )
545  ldclass = typeGetClass( ldtype )
546  astSetType( l, ldfull, lsubtype )
547 
548  rdfull = ldfull
549  rdtype = ldtype
550  rdclass = ldclass
551  astSetType( r, rdfull, lsubtype )
552  end if
553  else
554  '' Not a CALL, it must be an UDT in memory, copy from that
555  do_move = TRUE
556  end if
557 
558  if( do_move ) then
559  return astNewMEM( AST_OP_MEMMOVE, l, r, symbGetLen( l->subtype ) )
560  end if
561 
562  '' wstrings?
563  elseif( (ldtype = FB_DATATYPE_WCHAR) or _
564  (rdtype = FB_DATATYPE_WCHAR) ) then
565 
566  '' both not wstrings? otherwise don't do any assignment by now
567  '' to allow optimizations..
568  if( ldtype <> rdtype ) then
569  dim as integer is_zstr
570 
571  if( hCheckWstringOps( l, ldfull, r, rdfull, is_zstr ) = FALSE ) then
572  exit function
573  end if
574 
575  '' one of them is an ascii string, just assign
576  if( is_zstr ) then
577  return rtlWstrAssign( l, r, (options and AST_OPOPT_ISINI) <> 0 )
578  end if
579 
580  '' hCheckWstringOps() may have remapped the types
581  ldclass = typeGetClass( ldfull )
582  rdclass = typeGetClass( rdfull )
583  ldtype = typeGet( ldfull )
584  rdtype = typeGet( rdfull )
585  end if
586 
587  '' unless it's an initialization
588  if( (options and AST_OPOPT_ISINI) <> 0 ) then
589  return rtlWstrAssign( l, r, TRUE )
590  end if
591 
592  '' zstrings?
593  elseif( (ldtype = FB_DATATYPE_CHAR) or _
594  (rdtype = FB_DATATYPE_CHAR) ) then
595 
596  '' both the same? assign as string..
597  if( ldtype = rdtype ) then
598  return rtlStrAssign( l, r )
599  end if
600 
601  if( hCheckZstringOps( l, ldfull, r, rdfull ) = FALSE ) then
602  exit function
603  end if
604 
605  '' hCheckZstringOps() may have remapped the types
606  ldclass = typeGetClass( ldfull )
607  rdclass = typeGetClass( rdfull )
608  ldtype = typeGet( ldfull )
609  rdtype = typeGet( rdfull )
610 
611  '' enums?
612  elseif( (ldtype = FB_DATATYPE_ENUM) or _
613  (rdtype = FB_DATATYPE_ENUM) ) then
614  hCheckEnumOps( l, ldclass, r, rdclass )
615  end if
616 
617  '' check pointers
618  if( (options and AST_OPOPT_DONTCHKPTR) = 0 ) then
619  if( hCheckConstAndPointerOps( l, ldfull, r, rdfull ) = FALSE ) then
620  exit function
621  end if
622  end if
623 
624  '' convert types if needed
625  if( ldtype <> rdtype ) then
626  '' don't convert strings
627  if( rdclass <> FB_DATACLASS_STRING ) then
628  '' constant?
629  if( astIsCONST( r ) ) then
630  r = astNewCONV( ldfull, lsubtype, r, _
631  iif( options and AST_OPOPT_DONTCHKPTR, AST_CONVOPT_DONTCHKPTR, 0 ) )
632  if( r = NULL ) then
633  exit function
634  end if
635  end if
636 
637  '' let the fpu do the conversion if any operand
638  '' is a float (unless a special case must be handled)
639  dim as integer doconv = TRUE
640  if( env.clopt.backend = FB_BACKEND_GAS ) then
641  if( (ldclass = FB_DATACLASS_FPOINT) or (rdclass = FB_DATACLASS_FPOINT) ) then
642  if( ldtype <> FB_DATATYPE_ULONGINT ) then
643  doconv = irGetOption( IR_OPT_FPUCONV )
644  end if
645  end if
646  end if
647 
648  if( doconv ) then
649  r = astNewCONV( ldfull, l->subtype, r, _
650  iif( options and AST_OPOPT_DONTCHKPTR, AST_CONVOPT_DONTCHKPTR, 0 ) )
651  if( r = NULL ) then
652  exit function
653  end if
654  end if
655  end if
656  end if
657 
658  '' alloc new node
659  n = astNewNode( AST_NODECLASS_ASSIGN, ldfull, lsubtype )
660 
661  n->l = l
662  n->r = r
663 
664  function = n
665 
666 end function
667 
668 function astLoadASSIGN( byval n as ASTNODE ptr ) as IRVREG ptr
669  dim as ASTNODE ptr l = any, r = any
670  dim as IRVREG ptr vs = any, vr = any
671 
672  l = n->l
673  r = n->r
674  if( (l = NULL) or (r = NULL) ) then
675  return NULL
676  end if
677 
678  if( r->class = AST_NODECLASS_CONV ) then
679  astUpdateCONVFD2FS( r, l->dtype, FALSE )
680  end if
681 
682  vs = astLoad( r )
683  vr = astLoad( l )
684 
685  if( ast.doemit ) then
686  irEmitSTORE( vr, vs )
687  end if
688 
689  astDelNode( l )
690  astDelNode( r )
691 
692  function = vr
693 end function
694