compiler/libec: (#1042) Fixed missing parentheses indexing Array::array
[sdk] / compiler / libec / src / pass15.ec
1 import "ecdefs"
2
3 // UNTIL IMPLEMENTED IN GRAMMAR
4 #define ACCESS_CLASSDATA(_class, baseClass) \
5    (_class ? ((void *)(((char *)_class.data) + baseClass.offsetClass)) : null)
6
7 #define YYLTYPE Location
8 #include "grammar.h"
9
10 extern OldList * ast;
11 extern int returnCode;
12 extern Expression parsedExpression;
13 extern bool yydebug;
14 public void SetYydebug(bool b) { yydebug = b; }
15 extern bool echoOn;
16
17 void resetScanner();
18
19 // TODO: Reset this to 0 on reinitialization
20 int propWatcherID;
21
22 int expression_yyparse();
23 static Statement curCompound;
24 External curExternal, afterExternal;
25 static Type curSwitchType;
26 static Class currentClass;
27 Class thisClass;
28 public void SetThisClass(Class c) { thisClass = c; } public Class GetThisClass() { return thisClass; }
29 static char * thisNameSpace;
30 /*static */Class containerClass;
31 bool thisClassParams = true;
32
33 uint internalValueCounter;
34
35 #ifdef _DEBUG
36 Time findSymbolTotalTime;
37 #endif
38
39 // WARNING: PrintExpression CONCATENATES to string. Please initialize.
40 /*static */public void PrintExpression(Expression exp, char * string)
41 {
42    //if(inCompiler)
43    {
44       TempFile f { };
45       int count;
46       bool backOutputLineNumbers = outputLineNumbers;
47       outputLineNumbers = false;
48
49       if(exp)
50          OutputExpression(exp, f);
51       f.Seek(0, start);
52       count = strlen(string);
53       count += f.Read(string + count, 1, 1023);
54       string[count] = '\0';
55       delete f;
56
57       outputLineNumbers = backOutputLineNumbers;
58    }
59 }
60
61 Type ProcessTemplateParameterType(TemplateParameter param)
62 {
63    if(param && param.type == TemplateParameterType::type && (param.dataType || param.dataTypeString))
64    {
65       // TOFIX: Will need to free this Type
66       if(!param.baseType)
67       {
68          if(param.dataTypeString)
69             param.baseType = ProcessTypeString(param.dataTypeString, false);
70          else
71             param.baseType = ProcessType(param.dataType.specifiers, param.dataType.decl);
72       }
73       return param.baseType;
74    }
75    return null;
76 }
77
78 bool NeedCast(Type type1, Type type2)
79 {
80    if(!type1 || !type2 || type1.keepCast || type2.keepCast) return true;
81
82    if(type1.kind == templateType && type2.kind == int64Type && type2.passAsTemplate == false)
83    {
84       return false;
85    }
86
87    if(type1.kind == type2.kind && type1.isLong == type2.isLong)
88    {
89       switch(type1.kind)
90       {
91          case _BoolType:
92          case charType:
93          case shortType:
94          case intType:
95          case int64Type:
96          case intPtrType:
97          case intSizeType:
98             if(type1.passAsTemplate && !type2.passAsTemplate)
99                return true;
100             return type1.isSigned != type2.isSigned;
101          case classType:
102             return type1._class != type2._class;
103          case pointerType:
104             return (type1.type && type2.type && type1.type.constant != type2.type.constant) || NeedCast(type1.type, type2.type);
105          default:
106             return true; //false; ????
107       }
108    }
109    return true;
110 }
111
112 static void ReplaceClassMembers(Expression exp, Class _class)
113 {
114    if(exp.type == identifierExp && exp.identifier)
115    {
116       Identifier id = exp.identifier;
117       Context ctx;
118       Symbol symbol = null;
119       if(!id._class || !id._class.name || strcmp(id._class.name, "property"))
120       {
121          // First, check if the identifier is declared inside the function
122          for(ctx = curContext; ctx != topContext.parent && !symbol; ctx = ctx.parent)
123          {
124             if(!ctx) break;   // This happened opening old mapTileCache.ec from archives?
125             symbol = (Symbol)ctx.symbols.FindString(id.string);
126             if(symbol) break;
127          }
128       }
129
130       // If it is not, check if it is a member of the _class
131       if(!symbol && ((!id._class || (id._class.name && !strcmp(id._class.name, "property"))) || (id.classSym && eClass_IsDerived(_class, id.classSym.registered))))
132       {
133          Property prop = eClass_FindProperty(_class, id.string, privateModule);
134          Method method = null;
135          DataMember member = null;
136          ClassProperty classProp = null;
137          if(!prop)
138          {
139             method = eClass_FindMethod(_class, id.string, privateModule);
140          }
141          if(!prop && !method)
142             member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
143          if(!prop && !method && !member)
144          {
145             classProp = eClass_FindClassProperty(_class, id.string);
146          }
147          if(prop || method || member || classProp)
148          {
149             // Replace by this.[member]
150             exp.type = memberExp;
151             exp.member.member = id;
152             exp.member.memberType = unresolvedMember;
153             exp.member.exp = QMkExpId("this");
154             //exp.member.exp.loc = exp.loc;
155             exp.addedThis = true;
156          }
157          else if(_class && _class.templateParams.first)
158          {
159             Class sClass;
160             for(sClass = _class; sClass; sClass = sClass.base)
161             {
162                if(sClass.templateParams.first)
163                {
164                   ClassTemplateParameter param;
165                   for(param = sClass.templateParams.first; param; param = param.next)
166                   {
167                      if(param.type == expression && !strcmp(param.name, id.string))
168                      {
169                         Expression argExp = GetTemplateArgExpByName(param.name, _class, TemplateParameterType::expression);
170
171                         if(argExp)
172                         {
173                            Declarator decl;
174                            OldList * specs = MkList();
175
176                            FreeIdentifier(exp.member.member);
177
178                            ProcessExpressionType(argExp);
179
180                            decl = SpecDeclFromString(param.dataTypeString, specs, null);
181
182                            exp.expType = ProcessType(specs, decl);
183
184                            // *[expType] *[argExp]
185                            exp.type = bracketsExp;
186                            exp.list = MkListOne(MkExpOp(null, '*',
187                               MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpOp(null, '&', argExp))));
188                         }
189                      }
190                   }
191                }
192             }
193          }
194       }
195    }
196 }
197
198 ////////////////////////////////////////////////////////////////////////
199 // PRINTING ////////////////////////////////////////////////////////////
200 ////////////////////////////////////////////////////////////////////////
201
202 public char * PrintInt(int64 result)
203 {
204    char temp[100];
205    if(result > MAXINT)
206       sprintf(temp, FORMAT64HEX /*"0x%I64XLL"*/, result);
207    else
208       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
209    if(result > MAXINT || result < MININT)
210       strcat(temp, "LL");
211    return CopyString(temp);
212 }
213
214 public char * PrintUInt(uint64 result)
215 {
216    char temp[100];
217    if(result > MAXDWORD)
218       sprintf(temp, FORMAT64HEXLL /*"0x%I64X"*/, result);
219    else if(result > MAXINT)
220       sprintf(temp, FORMAT64HEX /*"0x%I64X"*/, result);
221    else
222       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
223    return CopyString(temp);
224 }
225
226 public char *  PrintInt64(int64 result)
227 {
228    char temp[100];
229    if(result > MAXINT || result < MININT)
230       sprintf(temp, FORMAT64DLL /*"%I64d"*/, result);
231    else
232       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
233    return CopyString(temp);
234 }
235
236 public char * PrintUInt64(uint64 result)
237 {
238    char temp[100];
239    if(result > MAXDWORD)
240       sprintf(temp, FORMAT64HEXLL /*"0x%I64XLL"*/, result);
241    else if(result > MAXINT)
242       sprintf(temp, FORMAT64HEX /*"0x%I64XLL"*/, result);
243    else
244       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
245    return CopyString(temp);
246 }
247
248 public char * PrintHexUInt(uint64 result)
249 {
250    char temp[100];
251    if(result > MAXDWORD)
252       sprintf(temp, FORMAT64HEX /*"0x%I64xLL"*/, result);
253    else
254       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
255    if(result > MAXDWORD)
256       strcat(temp, "LL");
257    return CopyString(temp);
258 }
259
260 public char * PrintHexUInt64(uint64 result)
261 {
262    char temp[100];
263    if(result > MAXDWORD)
264       sprintf(temp, FORMAT64HEXLL /*"0x%I64xLL"*/, result);
265    else
266       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
267    return CopyString(temp);
268 }
269
270 public char * PrintShort(short result)
271 {
272    char temp[100];
273    sprintf(temp, "%d", (unsigned short)result);
274    return CopyString(temp);
275 }
276
277 public char * PrintUShort(unsigned short result)
278 {
279    char temp[100];
280    if(result > 32767)
281       sprintf(temp, "0x%X", (int)result);
282    else
283       sprintf(temp, "%d", (int)result);
284    return CopyString(temp);
285 }
286
287 public char * PrintChar(char result)
288 {
289    char temp[100];
290    if(result > 0 && isprint(result))
291       sprintf(temp, "'%c'", result);
292    else if(result < 0)
293       sprintf(temp, "%d", (int)result);
294    else
295       //sprintf(temp, "%#X", result);
296       sprintf(temp, "0x%X", (unsigned char)result);
297    return CopyString(temp);
298 }
299
300 public char * PrintUChar(unsigned char result)
301 {
302    char temp[100];
303    sprintf(temp, "0x%X", result);
304    return CopyString(temp);
305 }
306
307 public char * PrintFloat(float result)
308 {
309    char temp[350];
310    if(result.isInf)
311    {
312       if(result.signBit)
313          strcpy(temp, "-inf");
314       else
315          strcpy(temp, "inf");
316    }
317    else if(result.isNan)
318    {
319       if(result.signBit)
320          strcpy(temp, "-nan");
321       else
322          strcpy(temp, "nan");
323    }
324    else
325       sprintf(temp, "%.16ff", result);
326    return CopyString(temp);
327 }
328
329 public char * PrintDouble(double result)
330 {
331    char temp[350];
332    if(result.isInf)
333    {
334       if(result.signBit)
335          strcpy(temp, "-inf");
336       else
337          strcpy(temp, "inf");
338    }
339    else if(result.isNan)
340    {
341       if(result.signBit)
342          strcpy(temp, "-nan");
343       else
344          strcpy(temp, "nan");
345    }
346    else
347       sprintf(temp, "%.16f", result);
348    return CopyString(temp);
349 }
350
351 ////////////////////////////////////////////////////////////////////////
352 ////////////////////////////////////////////////////////////////////////
353
354 //public Operand GetOperand(Expression exp);
355
356 #define GETVALUE(name, t) \
357    public bool GetOp##name(Operand op2, t * value2) \
358    {                                                        \
359       if(op2.kind == intType && op2.type.isSigned) *value2 = (t) op2.i; \
360       else if(op2.kind == intType) *value2 = (t) op2.ui;                 \
361       else if(op2.kind == int64Type && op2.type.isSigned) *value2 = (t) op2.i64; \
362       else if(op2.kind == int64Type) *value2 = (t) op2.ui64;                 \
363       else if(op2.kind == intSizeType && op2.type.isSigned) *value2 = (t) op2.i64; \
364       else if(op2.kind == intSizeType) *value2 = (t) op2.ui64; \
365       else if(op2.kind == intPtrType && op2.type.isSigned) *value2 = (t) op2.i64; \
366       else if(op2.kind == intPtrType) *value2 = (t) op2.ui64;                 \
367       else if(op2.kind == shortType && op2.type.isSigned) *value2 = (t) op2.s;   \
368       else if(op2.kind == shortType) *value2 = (t) op2.us;                        \
369       else if(op2.kind == charType && op2.type.isSigned) *value2 = (t) op2.c;    \
370       else if(op2.kind == _BoolType || op2.kind == charType) *value2 = (t) op2.uc; \
371       else if(op2.kind == floatType) *value2 = (t) op2.f;                         \
372       else if(op2.kind == doubleType) *value2 = (t) op2.d;                        \
373       else if(op2.kind == pointerType) *value2 = (t) op2.ui64;                    \
374       else                                                                          \
375          return false;                                                              \
376       return true;                                                                  \
377    } \
378    public bool Get##name(Expression exp, t * value2) \
379    {                                                        \
380       Operand op2 = GetOperand(exp);                        \
381       return GetOp##name(op2, value2); \
382    }
383
384 // To help the debugger currently not preprocessing...
385 #define HELP(x) x
386
387 GETVALUE(Int, HELP(int));
388 GETVALUE(UInt, HELP(unsigned int));
389 GETVALUE(Int64, HELP(int64));
390 GETVALUE(UInt64, HELP(uint64));
391 GETVALUE(IntPtr, HELP(intptr));
392 GETVALUE(UIntPtr, HELP(uintptr));
393 GETVALUE(IntSize, HELP(intsize));
394 GETVALUE(UIntSize, HELP(uintsize));
395 GETVALUE(Short, HELP(short));
396 GETVALUE(UShort, HELP(unsigned short));
397 GETVALUE(Char, HELP(char));
398 GETVALUE(UChar, HELP(unsigned char));
399 GETVALUE(Float, HELP(float));
400 GETVALUE(Double, HELP(double));
401
402 void ComputeExpression(Expression exp);
403
404 void ComputeClassMembers(Class _class, bool isMember)
405 {
406    DataMember member = isMember ? (DataMember) _class : null;
407    Context context = isMember ? null : SetupTemplatesContext(_class);
408    if(member || ((_class.type == bitClass || _class.type == normalClass || _class.type == structClass || _class.type == noHeadClass) &&
409                  (_class.type == bitClass || (!_class.structSize || _class.structSize == _class.offset)) && _class.computeSize))
410    {
411       int unionMemberOffset = 0;
412       int bitFields = 0;
413
414       /*
415       if(!member && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass) && _class.memberOffset && _class.memberOffset > _class.base.structSize)
416          _class.memberOffset = (_class.base && _class.base.type != systemClass) ? _class.base.structSize : 0;
417       */
418
419       if(member)
420       {
421          member.memberOffset = 0;
422          if(targetBits < sizeof(void *) * 8)
423             member.structAlignment = 0;
424       }
425       else if(targetBits < sizeof(void *) * 8)
426          _class.structAlignment = 0;
427
428       // Confusion here: non struct classes seem to have their memberOffset restart at 0 at each hierarchy level
429       if(!member && ((_class.type == normalClass || _class.type == noHeadClass) || (_class.type == structClass && _class.memberOffset && _class.memberOffset > _class.base.structSize)))
430          _class.memberOffset = (_class.base && _class.type == structClass) ? _class.base.structSize : 0;
431
432       if(!member && _class.destructionWatchOffset)
433          _class.memberOffset += sizeof(OldList);
434
435       // To avoid reentrancy...
436       //_class.structSize = -1;
437
438       {
439          DataMember dataMember;
440          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
441          {
442             if(!dataMember.isProperty)
443             {
444                if(dataMember.type == normalMember && dataMember.dataTypeString && !dataMember.dataType)
445                {
446                   dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
447                   /*if(!dataMember.dataType)
448                      dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
449                      */
450                }
451             }
452          }
453       }
454
455       {
456          DataMember dataMember;
457          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
458          {
459             if(!dataMember.isProperty && (dataMember.type != normalMember || dataMember.dataTypeString))
460             {
461                if(!isMember && _class.type == bitClass && dataMember.dataType)
462                {
463                   BitMember bitMember = (BitMember) dataMember;
464                   uint64 mask = 0;
465                   int d;
466
467                   ComputeTypeSize(dataMember.dataType);
468
469                   if(bitMember.pos == -1) bitMember.pos = _class.memberOffset;
470                   if(!bitMember.size) bitMember.size = dataMember.dataType.size * 8;
471
472                   _class.memberOffset = bitMember.pos + bitMember.size;
473                   for(d = 0; d<bitMember.size; d++)
474                   {
475                      if(d)
476                         mask <<= 1;
477                      mask |= 1;
478                   }
479                   bitMember.mask = mask << bitMember.pos;
480                }
481                else if(dataMember.type == normalMember && dataMember.dataType)
482                {
483                   int size;
484                   int alignment = 0;
485
486                   // Prevent infinite recursion
487                   if(dataMember.dataType.kind != classType ||
488                      ((!dataMember.dataType._class || !dataMember.dataType._class.registered || dataMember.dataType._class.registered != _class ||
489                      _class.type != structClass)))
490                      ComputeTypeSize(dataMember.dataType);
491
492                   if(dataMember.dataType.bitFieldCount)
493                   {
494                      bitFields += dataMember.dataType.bitFieldCount;
495                      size = 0;
496                   }
497                   else
498                   {
499                      if(bitFields)
500                      {
501                         int size = (bitFields + 7) / 8;
502
503                         if(isMember)
504                         {
505                            // TESTING THIS PADDING CODE
506                            if(alignment)
507                            {
508                               member.structAlignment = Max(member.structAlignment, alignment);
509
510                               if(member.memberOffset % alignment)
511                                  member.memberOffset += alignment - (member.memberOffset % alignment);
512                            }
513
514                            dataMember.offset = member.memberOffset;
515                            if(member.type == unionMember)
516                               unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
517                            else
518                            {
519                               member.memberOffset += size;
520                            }
521                         }
522                         else
523                         {
524                            // TESTING THIS PADDING CODE
525                            if(alignment)
526                            {
527                               _class.structAlignment = Max(_class.structAlignment, alignment);
528
529                               if(_class.memberOffset % alignment)
530                                  _class.memberOffset += alignment - (_class.memberOffset % alignment);
531                            }
532
533                            dataMember.offset = _class.memberOffset;
534                            _class.memberOffset += size;
535                         }
536                         bitFields = 0;
537                      }
538                      size = dataMember.dataType.size;
539                      alignment = dataMember.dataType.alignment;
540                   }
541
542                   if(isMember)
543                   {
544                      // TESTING THIS PADDING CODE
545                      if(alignment)
546                      {
547                         member.structAlignment = Max(member.structAlignment, alignment);
548
549                         if(member.memberOffset % alignment)
550                            member.memberOffset += alignment - (member.memberOffset % alignment);
551                      }
552
553                      dataMember.offset = member.memberOffset;
554                      if(member.type == unionMember)
555                         unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
556                      else
557                      {
558                         member.memberOffset += size;
559                      }
560                   }
561                   else
562                   {
563                      // TESTING THIS PADDING CODE
564                      if(alignment)
565                      {
566                         _class.structAlignment = Max(_class.structAlignment, alignment);
567
568                         if(_class.memberOffset % alignment)
569                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
570                      }
571
572                      dataMember.offset = _class.memberOffset;
573                      _class.memberOffset += size;
574                   }
575                }
576                else
577                {
578                   int alignment;
579
580                   ComputeClassMembers((Class)dataMember, true);
581                   alignment = dataMember.structAlignment;
582
583                   if(isMember)
584                   {
585                      if(alignment)
586                      {
587                         if(member.memberOffset % alignment)
588                            member.memberOffset += alignment - (member.memberOffset % alignment);
589
590                         member.structAlignment = Max(member.structAlignment, alignment);
591                      }
592                      dataMember.offset = member.memberOffset;
593                      if(member.type == unionMember)
594                         unionMemberOffset = Max(unionMemberOffset, dataMember.memberOffset);
595                      else
596                         member.memberOffset += dataMember.memberOffset;
597                   }
598                   else
599                   {
600                      if(alignment)
601                      {
602                         if(_class.memberOffset % alignment)
603                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
604                         _class.structAlignment = Max(_class.structAlignment, alignment);
605                      }
606                      dataMember.offset = _class.memberOffset;
607                      _class.memberOffset += dataMember.memberOffset;
608                   }
609                }
610             }
611          }
612          if(bitFields)
613          {
614             int alignment = 0;
615             int size = (bitFields + 7) / 8;
616
617             if(isMember)
618             {
619                // TESTING THIS PADDING CODE
620                if(alignment)
621                {
622                   member.structAlignment = Max(member.structAlignment, alignment);
623
624                   if(member.memberOffset % alignment)
625                      member.memberOffset += alignment - (member.memberOffset % alignment);
626                }
627
628                if(member.type == unionMember)
629                   unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
630                else
631                {
632                   member.memberOffset += size;
633                }
634             }
635             else
636             {
637                // TESTING THIS PADDING CODE
638                if(alignment)
639                {
640                   _class.structAlignment = Max(_class.structAlignment, alignment);
641
642                   if(_class.memberOffset % alignment)
643                      _class.memberOffset += alignment - (_class.memberOffset % alignment);
644                }
645                _class.memberOffset += size;
646             }
647             bitFields = 0;
648          }
649       }
650       if(member && member.type == unionMember)
651       {
652          member.memberOffset = unionMemberOffset;
653       }
654
655       if(!isMember)
656       {
657          /*if(_class.type == structClass)
658             _class.size = _class.memberOffset;
659          else
660          */
661
662          if(_class.type != bitClass)
663          {
664             int extra = 0;
665             if(_class.structAlignment)
666             {
667                if(_class.memberOffset % _class.structAlignment)
668                   extra += _class.structAlignment - (_class.memberOffset % _class.structAlignment);
669             }
670             _class.structSize = (_class.base ? (_class.base.templateClass ?
671                (_class.base.type == noHeadClass ? _class.base.templateClass.memberOffset : _class.base.templateClass.structSize) :
672                   (_class.base.type == noHeadClass ? _class.base.memberOffset : _class.base.structSize) ) : 0) + _class.memberOffset + extra;
673             if(!member)
674             {
675                Property prop;
676                for(prop = _class.membersAndProperties.first; prop; prop = prop.next)
677                {
678                   if(prop.isProperty && prop.isWatchable)
679                   {
680                      prop.watcherOffset = _class.structSize;
681                      _class.structSize += sizeof(OldList);
682                   }
683                }
684             }
685
686             // Fix Derivatives
687             {
688                OldLink derivative;
689                for(derivative = _class.derivatives.first; derivative; derivative = derivative.next)
690                {
691                   Class deriv = derivative.data;
692
693                   if(deriv.computeSize)
694                   {
695                      // TESTING THIS NEW CODE HERE... TRYING TO FIX ScrollBar MEMBERS DEBUGGING
696                      deriv.offset = /*_class.offset + */(_class.type == noHeadClass ? _class.memberOffset : _class.structSize);
697                      deriv.memberOffset = 0;
698                      // ----------------------
699
700                      deriv.structSize = deriv.offset;
701
702                      ComputeClassMembers(deriv, false);
703                   }
704                }
705             }
706          }
707       }
708    }
709    if(context)
710       FinishTemplatesContext(context);
711 }
712
713 public void ComputeModuleClasses(Module module)
714 {
715    Class _class;
716    OldLink subModule;
717
718    for(subModule = module.modules.first; subModule; subModule = subModule.next)
719       ComputeModuleClasses(subModule.data);
720    for(_class = module.classes.first; _class; _class = _class.next)
721       ComputeClassMembers(_class, false);
722 }
723
724
725 public int ComputeTypeSize(Type type)
726 {
727    uint size = type ? type.size : 0;
728    if(!size && type && !type.computing)
729    {
730       type.computing = true;
731       switch(type.kind)
732       {
733          case _BoolType: type.alignment = size = sizeof(char); break;   // Assuming 1 byte _Bool
734          case charType: type.alignment = size = sizeof(char); break;
735          case intType: type.alignment = size = sizeof(int); break;
736          case int64Type: type.alignment = size = sizeof(int64); break;
737          case intPtrType: type.alignment = size = targetBits / 8; type.pointerAlignment = true; break;
738          case intSizeType: type.alignment = size = targetBits / 8; type.pointerAlignment = true; break;
739          case longType: type.alignment = size = sizeof(long); break;
740          case shortType: type.alignment = size = sizeof(short); break;
741          case floatType: type.alignment = size = sizeof(float); break;
742          case doubleType: type.alignment = size = sizeof(double); break;
743          case classType:
744          {
745             Class _class = type._class ? type._class.registered : null;
746
747             if(_class && _class.type == structClass)
748             {
749                // Ensure all members are properly registered
750                ComputeClassMembers(_class, false);
751                type.alignment = _class.structAlignment;
752                type.pointerAlignment = (bool)_class.pointerAlignment;
753                size = _class.structSize;
754                if(type.alignment && size % type.alignment)
755                   size += type.alignment - (size % type.alignment);
756
757             }
758             else if(_class && (_class.type == unitClass ||
759                    _class.type == enumClass ||
760                    _class.type == bitClass))
761             {
762                if(!_class.dataType)
763                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
764                size = type.alignment = ComputeTypeSize(_class.dataType);
765             }
766             else
767             {
768                size = type.alignment = targetBits / 8; // sizeof(Instance *);
769                type.pointerAlignment = true;
770             }
771             break;
772          }
773          case pointerType: case subClassType: size = type.alignment = targetBits / 8; /*sizeof(void *); */ type.pointerAlignment = true; break;
774          case arrayType:
775             if(type.arraySizeExp)
776             {
777                ProcessExpressionType(type.arraySizeExp);
778                ComputeExpression(type.arraySizeExp);
779                if(!type.arraySizeExp.isConstant || (type.arraySizeExp.expType.kind != intType &&
780                   type.arraySizeExp.expType.kind != shortType &&
781                   type.arraySizeExp.expType.kind != charType &&
782                   type.arraySizeExp.expType.kind != longType &&
783                   type.arraySizeExp.expType.kind != int64Type &&
784                   type.arraySizeExp.expType.kind != intSizeType &&
785                   type.arraySizeExp.expType.kind != intPtrType &&
786                   type.arraySizeExp.expType.kind != enumType &&
787                   (type.arraySizeExp.expType.kind != classType || !type.arraySizeExp.expType._class.registered || type.arraySizeExp.expType._class.registered.type != enumClass)))
788                {
789                   Location oldLoc = yylloc;
790                   // bool isConstant = type.arraySizeExp.isConstant;
791                   char expression[10240];
792                   expression[0] = '\0';
793                   type.arraySizeExp.expType = null;
794                   yylloc = type.arraySizeExp.loc;
795                   if(inCompiler)
796                      PrintExpression(type.arraySizeExp, expression);
797                   Compiler_Error($"Array size not constant int (%s)\n", expression);
798                   yylloc = oldLoc;
799                }
800                GetInt(type.arraySizeExp, &type.arraySize);
801             }
802             else if(type.enumClass)
803             {
804                if(type.enumClass && type.enumClass.registered && type.enumClass.registered.type == enumClass)
805                {
806                   type.arraySize = (int)eClass_GetProperty(type.enumClass.registered, "enumSize");
807                }
808                else
809                   type.arraySize = 0;
810             }
811             else
812             {
813                // Unimplemented auto size
814                type.arraySize = 0;
815             }
816
817             size = ComputeTypeSize(type.type) * type.arraySize;
818             if(type.type)
819             {
820                type.alignment = type.type.alignment;
821                type.pointerAlignment = type.type.pointerAlignment;
822             }
823
824             break;
825          case structType:
826          {
827             if(!type.members.first && type.enumName)
828             {
829                Symbol symbol = FindStruct(curContext, type.enumName);
830                if(symbol && symbol.type)
831                {
832                   ComputeTypeSize(symbol.type);
833                   size = symbol.type.size;
834                }
835             }
836             else
837             {
838                Type member;
839                for(member = type.members.first; member; member = member.next)
840                {
841                   uint addSize = ComputeTypeSize(member);
842
843                   member.offset = size;
844                   if(member.alignment && size % member.alignment)
845                      member.offset += member.alignment - (size % member.alignment);
846                   size = member.offset;
847
848                   if(member.pointerAlignment && type.size <= 4)
849                      type.pointerAlignment = true;
850                   else if(!member.pointerAlignment && member.alignment >= 8)
851                      type.pointerAlignment = false;
852
853                   type.alignment = Max(type.alignment, member.alignment);
854                   size += addSize;
855                }
856                if(type.alignment && size % type.alignment)
857                   size += type.alignment - (size % type.alignment);
858             }
859             break;
860          }
861          case unionType:
862          {
863             if(!type.members.first && type.enumName)
864             {
865                Symbol symbol = FindStruct(curContext, type.enumName);
866                if(symbol && symbol.type)
867                {
868                   ComputeTypeSize(symbol.type);
869                   size = symbol.type.size;
870                   type.alignment = symbol.type.alignment;
871                }
872             }
873             else
874             {
875                Type member;
876                for(member = type.members.first; member; member = member.next)
877                {
878                   uint addSize = ComputeTypeSize(member);
879
880                   member.offset = size;
881                   if(member.alignment && size % member.alignment)
882                      member.offset += member.alignment - (size % member.alignment);
883                   size = member.offset;
884
885                   if(member.pointerAlignment && type.size <= 4)
886                      type.pointerAlignment = true;
887                   else if(!member.pointerAlignment && member.alignment >= 8)
888                      type.pointerAlignment = false;
889
890                   type.alignment = Max(type.alignment, member.alignment);
891
892                   size = Max(size, addSize);
893                }
894                if(type.alignment && size % type.alignment)
895                   size += type.alignment - (size % type.alignment);
896             }
897             break;
898          }
899          case templateType:
900          {
901             TemplateParameter param = type.templateParameter;
902             Type baseType = ProcessTemplateParameterType(param);
903             if(baseType)
904             {
905                size = ComputeTypeSize(baseType);
906                type.alignment = baseType.alignment;
907                type.pointerAlignment = baseType.pointerAlignment;
908             }
909             else
910                type.alignment = size = sizeof(uint64);
911             break;
912          }
913          case enumType:
914          {
915             type.alignment = size = sizeof(enum { test });
916             break;
917          }
918          case thisClassType:
919          {
920             type.alignment = size = targetBits / 8; //sizeof(void *);
921             type.pointerAlignment = true;
922             break;
923          }
924       }
925       type.size = size;
926       type.computing = false;
927    }
928    return size;
929 }
930
931
932 /*static */int AddMembers(External neededBy, OldList * declarations, Class _class, bool isMember, uint * retSize, Class topClass, bool *addedPadding)
933 {
934    // This function is in need of a major review when implementing private members etc.
935    DataMember topMember = isMember ? (DataMember) _class : null;
936    uint totalSize = 0;
937    uint maxSize = 0;
938    int alignment;
939    uint size;
940    DataMember member;
941    int anonID = 1;
942    Context context = isMember ? null : SetupTemplatesContext(_class);
943    if(addedPadding)
944       *addedPadding = false;
945
946    if(!isMember && _class.base)
947    {
948       maxSize = _class.structSize;
949       //if(_class.base.type != systemClass) // Commented out with new Instance _class
950       {
951          // DANGER: Testing this noHeadClass here...
952          if(_class.type == structClass || _class.type == noHeadClass)
953             /*totalSize = */AddMembers(neededBy, declarations, _class.base, false, &totalSize, topClass, null);
954          else
955          {
956             uint baseSize = _class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize;
957             if(maxSize > baseSize)
958                maxSize -= baseSize;
959             else
960                maxSize = 0;
961          }
962       }
963    }
964
965    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
966    {
967       if(!member.isProperty)
968       {
969          switch(member.type)
970          {
971             case normalMember:
972             {
973                if(member.dataTypeString)
974                {
975                   OldList * specs = MkList(), * decls = MkList();
976                   Declarator decl;
977
978                   decl = SpecDeclFromString(member.dataTypeString, specs,
979                      MkDeclaratorIdentifier(MkIdentifier(member.name)));
980                   ListAdd(decls, MkStructDeclarator(decl, null));
981                   ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, decls, null)));
982
983                   if(!member.dataType)
984                      member.dataType = ProcessType(specs, decl);
985
986                   ReplaceThisClassSpecifiers(specs, topClass /*member._class*/);
987
988                   {
989                      Type type = ProcessType(specs, decl);
990                      DeclareType(neededBy, member.dataType, true, false);
991                      FreeType(type);
992                   }
993                   /*
994                   if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
995                      member.dataType._class.registered && member.dataType._class.registered.type == structClass)
996                      DeclareStruct(member.dataType._class.string, false);
997                   */
998
999                   ComputeTypeSize(member.dataType);
1000                   size = member.dataType.size;
1001                   alignment = member.dataType.alignment;
1002
1003                   if(alignment)
1004                   {
1005                      if(totalSize % alignment)
1006                         totalSize += alignment - (totalSize % alignment);
1007                   }
1008                   totalSize += size;
1009                }
1010                break;
1011             }
1012             case unionMember:
1013             case structMember:
1014             {
1015                OldList * specs = MkList(), * list = MkList();
1016                char id[100];
1017                sprintf(id, "__anon%d", anonID++);
1018
1019                size = 0;
1020                AddMembers(neededBy, list, (Class)member, true, &size, topClass, null);
1021                ListAdd(specs,
1022                   MkStructOrUnion((member.type == unionMember)?unionSpecifier:structSpecifier, null, list));
1023                ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, MkListOne(MkDeclaratorIdentifier(MkIdentifier(id))),null)));
1024                alignment = member.structAlignment;
1025
1026                if(alignment)
1027                {
1028                   if(totalSize % alignment)
1029                      totalSize += alignment - (totalSize % alignment);
1030                }
1031                totalSize += size;
1032                break;
1033             }
1034          }
1035       }
1036    }
1037    if(retSize)
1038    {
1039       if(topMember && topMember.type == unionMember)
1040          *retSize = Max(*retSize, totalSize);
1041       else
1042          *retSize += totalSize;
1043    }
1044    else if(totalSize < maxSize && _class.type != systemClass)
1045    {
1046       int autoPadding = 0;
1047       if(!isMember && _class.structAlignment && totalSize % _class.structAlignment)
1048          autoPadding = _class.structAlignment - (totalSize % _class.structAlignment);
1049       if(totalSize + autoPadding < maxSize)
1050       {
1051          char sizeString[50];
1052          sprintf(sizeString, "%d", maxSize - totalSize);
1053          ListAdd(declarations,
1054             MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(CHAR)),
1055             MkListOne(MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__ecere_padding")), MkExpConstant(sizeString))), null)));
1056          if(addedPadding)
1057             *addedPadding = true;
1058       }
1059    }
1060    if(context)
1061       FinishTemplatesContext(context);
1062    return topMember ? topMember.memberID : _class.memberID;
1063 }
1064
1065 static int DeclareMembers(External neededBy, Class _class, bool isMember)
1066 {
1067    DataMember topMember = isMember ? (DataMember) _class : null;
1068    DataMember member;
1069    Context context = isMember ? null : SetupTemplatesContext(_class);
1070
1071    if(!isMember && (_class.type == structClass || _class.type == noHeadClass) && _class.base.type != systemClass)
1072       DeclareMembers(neededBy, _class.base, false);
1073
1074    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
1075    {
1076       if(!member.isProperty)
1077       {
1078          switch(member.type)
1079          {
1080             case normalMember:
1081             {
1082                if(!member.dataType && member.dataTypeString)
1083                   member.dataType = ProcessTypeString(member.dataTypeString, false);
1084                if(member.dataType)
1085                   DeclareType(neededBy, member.dataType, true, false);
1086                break;
1087             }
1088             case unionMember:
1089             case structMember:
1090             {
1091                DeclareMembers(neededBy, (Class)member, true);
1092                break;
1093             }
1094          }
1095       }
1096    }
1097    if(context)
1098       FinishTemplatesContext(context);
1099
1100    return topMember ? topMember.memberID : _class.memberID;
1101 }
1102
1103 static void IdentifyAnonStructs(OldList/*<ClassDef>*/ *  definitions)
1104 {
1105    ClassDef def;
1106    int anonID = 1;
1107    for(def = definitions->first; def; def = def.next)
1108    {
1109       if(def.type == declarationClassDef)
1110       {
1111          Declaration decl = def.decl;
1112          if(decl && decl.specifiers)
1113          {
1114             Specifier spec;
1115             bool isStruct = false;
1116             for(spec = decl.specifiers->first; spec; spec = spec.next)
1117             {
1118                if(spec.type == structSpecifier || spec.type == unionSpecifier)
1119                {
1120                   if(spec.definitions)
1121                      IdentifyAnonStructs(spec.definitions);
1122                   isStruct = true;
1123                }
1124             }
1125             if(isStruct)
1126             {
1127                Declarator d = null;
1128                if(decl.declarators)
1129                {
1130                   for(d = decl.declarators->first; d; d = d.next)
1131                   {
1132                      Identifier idDecl = GetDeclId(d);
1133                      if(idDecl)
1134                         break;
1135                   }
1136                }
1137                if(!d)
1138                {
1139                   char id[100];
1140                   sprintf(id, "__anon%d", anonID++);
1141                   if(!decl.declarators)
1142                      decl.declarators = MkList();
1143                   ListAdd(decl.declarators, MkDeclaratorIdentifier(MkIdentifier(id)));
1144                }
1145             }
1146          }
1147       }
1148    }
1149 }
1150
1151 External DeclareStruct(External neededBy, const char * name, bool skipNoHead, bool needDereference)
1152 {
1153    return _DeclareStruct(neededBy, name, skipNoHead, needDereference, false);
1154 }
1155
1156 External _DeclareStruct(External neededBy, const char * name, bool skipNoHead, bool needDereference, bool fwdDecl)
1157 {
1158    External external = null;
1159    Symbol classSym = FindClass(name);
1160    OldList * curDeclarations = null;
1161
1162    if(!inCompiler || !classSym) return null;
1163
1164    // We don't need any declaration for bit classes...
1165    if(classSym.registered &&
1166       (classSym.registered.type == bitClass || classSym.registered.type == unitClass || classSym.registered.type == enumClass))
1167       return null;
1168
1169    if(!classSym.registered || (classSym.registered.type == normalClass && classSym.registered.structSize && classSym.registered.base && classSym.registered.base.base))
1170       _DeclareStruct(neededBy, "ecere::com::Instance", false, true, fwdDecl);
1171
1172    external = classSym.structExternal;
1173
1174    if(external && external.declaration)
1175    {
1176       Specifier spec;
1177       for(spec = external.declaration.specifiers ? external.declaration.specifiers->first : null; spec; spec = spec.next)
1178          if(spec.type == structSpecifier || spec.type == unionSpecifier)
1179          {
1180             curDeclarations = spec.definitions;
1181             break;
1182          }
1183    }
1184
1185    if(classSym.registered && !classSym.declaring && classSym.imported && (!classSym.declaredStructSym || (classSym.registered.type == noHeadClass && !skipNoHead && external && !curDeclarations)))
1186    {
1187       OldList * specifiers, * declarators;
1188       OldList * declarations = null;
1189       char structName[1024];
1190       bool addedPadding = false;
1191       Specifier curSpec = null;
1192
1193       classSym.declaring++;
1194
1195       if(strchr(classSym.string, '<'))
1196       {
1197          if(classSym.registered.templateClass)
1198             external = _DeclareStruct(neededBy, classSym.registered.templateClass.fullName, skipNoHead, needDereference, fwdDecl);
1199          classSym.declaring--;
1200          return external;
1201       }
1202
1203       structName[0] = 0;
1204       FullClassNameCat(structName, name, false);
1205
1206       classSym.declaredStructSym = true;
1207       if(!external || (classSym.registered.type == noHeadClass && !skipNoHead && !curDeclarations))
1208       {
1209          bool add = false;
1210          if(!external)
1211          {
1212             external = MkExternalDeclaration(null);
1213             classSym.structExternal = external;
1214             external.symbol = classSym;
1215
1216             add = true;
1217          }
1218
1219          if(!skipNoHead)
1220          {
1221             declarations = MkList();
1222             AddMembers(external, declarations, classSym.registered, false, null, classSym.registered, &addedPadding);
1223          }
1224
1225          if(external.declaration)
1226          {
1227             Specifier spec;
1228             for(spec = external.declaration.specifiers ? external.declaration.specifiers->first : null; spec; spec = spec.next)
1229                if(spec.type == structSpecifier || spec.type == unionSpecifier)
1230                {
1231                   curSpec = spec;
1232                   curDeclarations = spec.definitions;
1233                   break;
1234                }
1235          }
1236
1237          if(declarations && (!declarations->count || (declarations->count == 1 && addedPadding)))
1238          {
1239             FreeList(declarations, FreeClassDef);
1240             declarations = null;
1241          }
1242
1243          if(classSym.registered.type != noHeadClass && !declarations)
1244          {
1245             FreeExternal(external);
1246             external = null;
1247             classSym.structExternal = null;
1248          }
1249          else
1250          {
1251             if(curSpec)
1252                curSpec.definitions = declarations;
1253             else
1254             {
1255                specifiers = MkList();
1256                declarators = MkList();
1257                ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), declarations));
1258                external.declaration = MkDeclaration(specifiers, declarators);
1259             }
1260             if(add)
1261                ast->Add(external);
1262          }
1263       }
1264       classSym.declaring--;
1265    }
1266    else if(!classSym.declaredStructSym && classSym.structExternal)
1267    {
1268       classSym.declaredStructSym = true;
1269
1270       if(classSym.registered)
1271          DeclareMembers(classSym.structExternal, classSym.registered, false);
1272
1273       if(classSym.structExternal.declaration && classSym.structExternal.declaration.specifiers)
1274       {
1275          Specifier spec;
1276          for(spec = classSym.structExternal.declaration.specifiers->first; spec; spec = spec.next)
1277          {
1278             if(spec.definitions)
1279                IdentifyAnonStructs(spec.definitions);
1280          }
1281       }
1282    }
1283    if(inCompiler && neededBy && (external || !classSym.imported))
1284    {
1285       if(!external)
1286       {
1287          classSym.structExternal = external = MkExternalDeclaration(null);
1288          external.symbol = classSym;
1289          ast->Add(external);
1290       }
1291       if(reachedPass15 && !external.declaration && classSym.registered && classSym.registered.type == noHeadClass)
1292       {
1293          // Declare nohead classes without definitions here (e.g. IteratorPointer)
1294          char structName[1024];
1295          OldList * specifiers, * declarators;
1296          structName[0] = 0;
1297          FullClassNameCat(structName, name, false);
1298          specifiers = MkList();
1299          declarators = MkList();
1300          ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), null));
1301          external.declaration = MkDeclaration(specifiers, declarators);
1302       }
1303       if(fwdDecl)
1304       {
1305          External e = external.fwdDecl ? external.fwdDecl : external;
1306          if(e.incoming.count)
1307             neededBy.CreateUniqueEdge(e, !needDereference && !external.fwdDecl);
1308       }
1309       else
1310          neededBy.CreateUniqueEdge(external, !needDereference);
1311    }
1312    return external;
1313 }
1314
1315 void DeclareProperty(External neededBy, Property prop, char * setName, char * getName)
1316 {
1317    Symbol symbol = prop.symbol;
1318    bool imported = false;
1319    bool dllImport = false;
1320    External structExternal = null;
1321    External instExternal = null;
1322
1323    strcpy(setName, "__ecereProp_");
1324    FullClassNameCat(setName, prop._class.fullName, false);
1325    strcat(setName, "_Set_");
1326    FullClassNameCat(setName, prop.name, true);
1327
1328    strcpy(getName, "__ecereProp_");
1329    FullClassNameCat(getName, prop._class.fullName, false);
1330    strcat(getName, "_Get_");
1331    FullClassNameCat(getName, prop.name, true);
1332
1333    if(!symbol || symbol._import)
1334    {
1335       if(!symbol)
1336       {
1337          Symbol classSym;
1338
1339          if(!prop._class.symbol)
1340             prop._class.symbol = FindClass(prop._class.fullName);
1341          classSym = prop._class.symbol;
1342          if(classSym && !classSym._import)
1343          {
1344             ModuleImport module;
1345
1346             if(prop._class.module)
1347                module = FindModule(prop._class.module);
1348             else
1349                module = mainModule;
1350
1351             classSym._import = ClassImport
1352             {
1353                name = CopyString(prop._class.fullName);
1354                isRemote = prop._class.isRemote;
1355             };
1356             module.classes.Add(classSym._import);
1357          }
1358          symbol = prop.symbol = Symbol { };
1359          symbol._import = (ClassImport)PropertyImport
1360          {
1361             name = CopyString(prop.name);
1362             isVirtual = false; //prop.isVirtual;
1363             hasSet = prop.Set ? true : false;
1364             hasGet = prop.Get ? true : false;
1365          };
1366          if(classSym)
1367             classSym._import.properties.Add(symbol._import);
1368       }
1369       imported = true;
1370       // Ugly work around for isNan properties declared within float/double classes which are initialized with ecereCOM
1371       if((prop._class.module != privateModule || !strcmp(prop._class.name, "float") || !strcmp(prop._class.name, "double")) &&
1372          prop._class.module.importType != staticImport)
1373          dllImport = true;
1374    }
1375
1376    if(!symbol.type)
1377    {
1378       Context context = SetupTemplatesContext(prop._class);
1379       symbol.type = ProcessTypeString(prop.dataTypeString, false);
1380       FinishTemplatesContext(context);
1381    }
1382
1383    if((prop.Get && !symbol.externalGet) || (prop.Set && !symbol.externalSet))
1384    {
1385       if(prop._class.type == normalClass && prop._class.structSize)
1386          instExternal = DeclareStruct(null, "ecere::com::Instance", false, true);
1387       structExternal = DeclareStruct(null, prop._class.fullName, prop._class.type != structClass /*true*/, false);
1388    }
1389
1390    // Get
1391    if(prop.Get && !symbol.externalGet)
1392    {
1393       Declaration decl;
1394       OldList * specifiers, * declarators;
1395       Declarator d;
1396       OldList * params;
1397       Specifier spec = null;
1398       External external;
1399       Declarator typeDecl;
1400       bool simple = false;
1401       bool needReference;
1402
1403       specifiers = MkList();
1404       declarators = MkList();
1405       params = MkList();
1406
1407       ListAdd(params, MkTypeName(MkListOne(MkSpecifierName(prop._class.fullName)),
1408          MkDeclaratorIdentifier(MkIdentifier("this"))));
1409
1410       d = MkDeclaratorIdentifier(MkIdentifier(getName));
1411       //if(imported)
1412       if(dllImport)
1413          d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1414
1415       {
1416          Context context = SetupTemplatesContext(prop._class);
1417          typeDecl = SpecDeclFromString(prop.dataTypeString, specifiers, null);
1418          FinishTemplatesContext(context);
1419       }
1420
1421       // Make sure the simple _class's type is declared
1422       needReference = !typeDecl || typeDecl.type == identifierDeclarator;
1423       for(spec = specifiers->first; spec; spec = spec.next)
1424       {
1425          if(spec.type == nameSpecifier)
1426          {
1427             Symbol classSym = spec.symbol;
1428             if(needReference)
1429             {
1430                symbol._class = classSym.registered;
1431                if(classSym.registered && classSym.registered.type == structClass)
1432                   simple = true;
1433             }
1434             break;
1435          }
1436       }
1437
1438       if(!simple)
1439          d = PlugDeclarator(typeDecl, d);
1440       else
1441       {
1442          ListAdd(params, MkTypeName(specifiers,
1443             PlugDeclarator(typeDecl, MkDeclaratorIdentifier(MkIdentifier("value")))));
1444          specifiers = MkList();
1445       }
1446
1447       d = MkDeclaratorFunction(d, params);
1448
1449       //if(imported)
1450       if(dllImport)
1451          specifiers->Insert(null, MkSpecifier(EXTERN));
1452       else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1453          specifiers->Insert(null, MkSpecifier(STATIC));
1454       if(simple)
1455          ListAdd(specifiers, MkSpecifier(VOID));
1456
1457       ListAdd(declarators, MkInitDeclarator(d, null));
1458
1459       decl = MkDeclaration(specifiers, declarators);
1460
1461       external = MkExternalDeclaration(decl);
1462
1463       if(structExternal)
1464          external.CreateEdge(structExternal, false);
1465       if(instExternal)
1466          external.CreateEdge(instExternal, false);
1467
1468       if(spec)
1469          DeclareStruct(external, spec.name, false, needReference);
1470
1471       ast->Add(external);
1472       external.symbol = symbol;
1473       symbol.externalGet = external;
1474
1475       ReplaceThisClassSpecifiers(specifiers, prop._class);
1476
1477       if(typeDecl)
1478          FreeDeclarator(typeDecl);
1479    }
1480
1481    // Set
1482    if(prop.Set && !symbol.externalSet)
1483    {
1484       Declaration decl;
1485       OldList * specifiers, * declarators;
1486       Declarator d;
1487       OldList * params;
1488       Specifier spec = null;
1489       External external;
1490       Declarator typeDecl;
1491       bool needReference;
1492
1493       declarators = MkList();
1494       params = MkList();
1495
1496       if(!prop.conversion || prop._class.type == structClass)
1497       {
1498          ListAdd(params, MkTypeName(MkListOne(MkSpecifierName(prop._class.fullName)),
1499             MkDeclaratorIdentifier(MkIdentifier("this"))));
1500       }
1501
1502       specifiers = MkList();
1503
1504       {
1505          Context context = SetupTemplatesContext(prop._class);
1506          typeDecl = d = SpecDeclFromString(prop.dataTypeString, specifiers,
1507             MkDeclaratorIdentifier(MkIdentifier("value")));
1508          FinishTemplatesContext(context);
1509       }
1510       if(!strcmp(prop._class.base.fullName, "eda::Row") || !strcmp(prop._class.base.fullName, "eda::Id"))
1511          specifiers->Insert(null, MkSpecifier(CONST));
1512
1513       ListAdd(params, MkTypeName(specifiers, d));
1514
1515       d = MkDeclaratorIdentifier(MkIdentifier(setName));
1516       if(dllImport)
1517          d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1518       d = MkDeclaratorFunction(d, params);
1519
1520       // Make sure the simple _class's type is declared
1521       needReference = !typeDecl || typeDecl.type == identifierDeclarator;
1522       for(spec = specifiers->first; spec; spec = spec.next)
1523       {
1524          if(spec.type == nameSpecifier)
1525          {
1526             Symbol classSym = spec.symbol;
1527             if(needReference)
1528                symbol._class = classSym.registered;
1529             break;
1530          }
1531       }
1532
1533       ListAdd(declarators, MkInitDeclarator(d, null));
1534
1535       specifiers = MkList();
1536       if(dllImport)
1537          specifiers->Insert(null, MkSpecifier(EXTERN));
1538       else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1539          specifiers->Insert(null, MkSpecifier(STATIC));
1540
1541       if(!prop.conversion || prop._class.type == structClass)
1542          ListAdd(specifiers, MkSpecifier(VOID));
1543       else
1544          ListAdd(specifiers, MkSpecifierName(prop._class.fullName));
1545
1546       decl = MkDeclaration(specifiers, declarators);
1547
1548       external = MkExternalDeclaration(decl);
1549
1550       if(structExternal)
1551          external.CreateEdge(structExternal, false);
1552       if(instExternal)
1553          external.CreateEdge(instExternal, false);
1554
1555       if(spec)
1556          DeclareStruct(external, spec.name, false, needReference);
1557
1558       ast->Add(external);
1559       external.symbol = symbol;
1560       symbol.externalSet = external;
1561
1562       ReplaceThisClassSpecifiers(specifiers, prop._class);
1563    }
1564
1565    // Property (for Watchers)
1566    if(!symbol.externalPtr)
1567    {
1568       Declaration decl;
1569       External external;
1570       OldList * specifiers = MkList();
1571       char propName[1024];
1572
1573       if(imported)
1574          specifiers->Insert(null, MkSpecifier(EXTERN));
1575       else
1576       {
1577          specifiers->Insert(null, MkSpecifier(STATIC));
1578          specifiers->Add(MkSpecifierExtended(MkExtDeclAttrib(MkAttrib(ATTRIB, MkListOne(MkAttribute(CopyString("unused"), null))))));
1579       }
1580
1581       ListAdd(specifiers, MkSpecifierName("Property"));
1582
1583       strcpy(propName, "__ecereProp_");
1584       FullClassNameCat(propName, prop._class.fullName, false);
1585       strcat(propName, "_");
1586       FullClassNameCat(propName, prop.name, true);
1587
1588       {
1589          OldList * list = MkList();
1590          ListAdd(list, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(propName)), null));
1591
1592          if(!imported)
1593          {
1594             strcpy(propName, "__ecerePropM_");
1595             FullClassNameCat(propName, prop._class.fullName, false);
1596             strcat(propName, "_");
1597             FullClassNameCat(propName, prop.name, true);
1598
1599             ListAdd(list, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(propName)), null));
1600          }
1601          decl = MkDeclaration(specifiers, list);
1602       }
1603
1604       external = MkExternalDeclaration(decl);
1605       ast->Insert(curExternal.prev, external);
1606       external.symbol = symbol;
1607       symbol.externalPtr = external;
1608    }
1609
1610    if(inCompiler && neededBy)
1611    {
1612       // Could improve this to create edge on only what is needed...
1613       if(symbol.externalPtr)
1614          neededBy.CreateUniqueEdge(symbol.externalPtr, false);
1615
1616       if(symbol.externalGet)
1617          neededBy.CreateUniqueEdge(symbol.externalGet, symbol.externalGet.type == functionExternal);
1618
1619       if(symbol.externalSet)
1620          neededBy.CreateUniqueEdge(symbol.externalSet, symbol.externalSet.type == functionExternal);
1621
1622       // IsSet ?
1623    }
1624 }
1625
1626 // ***************** EXPRESSION PROCESSING ***************************
1627 public Type Dereference(Type source)
1628 {
1629    Type type = null;
1630    if(source)
1631    {
1632       if(source.kind == pointerType || source.kind == arrayType)
1633       {
1634          type = source.type;
1635          source.type.refCount++;
1636       }
1637       else if(source.kind == classType && !strcmp(source._class.string, "String"))
1638       {
1639          type = Type
1640          {
1641             kind = charType;
1642             refCount = 1;
1643          };
1644       }
1645       // Support dereferencing of no head classes for now...
1646       else if(source.kind == classType && source._class && source._class.registered && source._class.registered.type == noHeadClass)
1647       {
1648          type = source;
1649          source.refCount++;
1650       }
1651       else
1652          Compiler_Error($"cannot dereference type\n");
1653    }
1654    return type;
1655 }
1656
1657 static Type Reference(Type source)
1658 {
1659    Type type = null;
1660    if(source)
1661    {
1662       type = Type
1663       {
1664          kind = pointerType;
1665          type = source;
1666          refCount = 1;
1667       };
1668       source.refCount++;
1669    }
1670    return type;
1671 }
1672
1673 void ProcessMemberInitData(MemberInit member, Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
1674 {
1675    Identifier ident = member.identifiers ? member.identifiers->first : null;
1676    bool found = false;
1677    DataMember dataMember = null;
1678    Method method = null;
1679    bool freeType = false;
1680
1681    yylloc = member.loc;
1682
1683    if(!ident)
1684    {
1685       if(curMember)
1686       {
1687          eClass_FindNextMember(_class, curClass, curMember, subMemberStack, subMemberStackPos);
1688          if(*curMember)
1689          {
1690             found = true;
1691             dataMember = *curMember;
1692          }
1693       }
1694    }
1695    else
1696    {
1697       DataMember thisMember = (DataMember)eClass_FindProperty(_class, ident.string, privateModule);
1698       DataMember _subMemberStack[256];
1699       int _subMemberStackPos = 0;
1700
1701       // FILL MEMBER STACK
1702       if(!thisMember)
1703          thisMember = eClass_FindDataMember(_class, ident.string, privateModule, _subMemberStack, &_subMemberStackPos);
1704       if(thisMember)
1705       {
1706          dataMember = thisMember;
1707          if(curMember && thisMember.memberAccess == publicAccess)
1708          {
1709             *curMember = thisMember;
1710             *curClass = thisMember._class;
1711             memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
1712             *subMemberStackPos = _subMemberStackPos;
1713          }
1714          found = true;
1715       }
1716       else
1717       {
1718          // Setting a method
1719          method = eClass_FindMethod(_class, ident.string, privateModule);
1720          if(method && method.type == virtualMethod)
1721             found = true;
1722          else
1723             method = null;
1724       }
1725    }
1726
1727    if(found)
1728    {
1729       Type type = null;
1730       if(dataMember)
1731       {
1732          if(!dataMember.dataType && dataMember.dataTypeString)
1733          {
1734             //Context context = SetupTemplatesContext(dataMember._class);
1735             Context context = SetupTemplatesContext(_class);
1736             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
1737             FinishTemplatesContext(context);
1738          }
1739          type = dataMember.dataType;
1740       }
1741       else if(method)
1742       {
1743          // This is for destination type...
1744          if(!method.dataType)
1745             ProcessMethodType(method);
1746          //DeclareMethod(method);
1747          // method.dataType = ((Symbol)method.symbol)->type;
1748          type = method.dataType;
1749       }
1750
1751       if(ident && ident.next)
1752       {
1753          for(ident = ident.next; ident && type; ident = ident.next)
1754          {
1755             if(type.kind == classType)
1756             {
1757                dataMember = (DataMember)eClass_FindProperty(type._class.registered, ident.string, privateModule);
1758                if(!dataMember)
1759                   dataMember = eClass_FindDataMember(type._class.registered, ident.string, privateModule, null, null);
1760                if(dataMember)
1761                   type = dataMember.dataType;
1762             }
1763             else if(type.kind == structType || type.kind == unionType)
1764             {
1765                Type memberType;
1766                for(memberType = type.members.first; memberType; memberType = memberType.next)
1767                {
1768                   if(!strcmp(memberType.name, ident.string))
1769                   {
1770                      type = memberType;
1771                      break;
1772                   }
1773                }
1774             }
1775          }
1776       }
1777
1778       // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
1779       if(type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type && _class.templateArgs /* TODO: Watch out for these _class.templateClass*/)
1780       {
1781          int id = 0;
1782          ClassTemplateParameter curParam = null;
1783          Class sClass;
1784          for(sClass = _class; sClass; sClass = sClass.base)
1785          {
1786             id = 0;
1787             if(sClass.templateClass) sClass = sClass.templateClass;
1788             for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
1789             {
1790                if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
1791                {
1792                   for(sClass = sClass.base; sClass; sClass = sClass.base)
1793                   {
1794                      if(sClass.templateClass) sClass = sClass.templateClass;
1795                      id += sClass.templateParams.count;
1796                   }
1797                   break;
1798                }
1799                id++;
1800             }
1801             if(curParam) break;
1802          }
1803
1804          if(curParam)
1805          {
1806             ClassTemplateArgument arg = _class.templateArgs[id];
1807             if(arg.dataTypeString)
1808             {
1809                bool constant = type.constant;
1810                // FreeType(type);
1811                type = ProcessTypeString(arg.dataTypeString, false);
1812                if(type.kind == classType && constant) type.constant = true;
1813                else if(type.kind == pointerType)
1814                {
1815                   Type t = type.type;
1816                   while(t.kind == pointerType) t = t.type;
1817                   if(constant) t.constant = constant;
1818                }
1819                freeType = true;
1820                if(type && _class.templateClass)
1821                   type.passAsTemplate = true;
1822                if(type)
1823                {
1824                   // type.refCount++;
1825                   /*if(!exp.destType)
1826                   {
1827                      exp.destType = ProcessTypeString(arg.dataTypeString, false);
1828                      exp.destType.refCount++;
1829                   }*/
1830                }
1831             }
1832          }
1833       }
1834       if(type && type.kind == classType && type._class && type._class.registered && strchr(type._class.registered.fullName, '<'))
1835       {
1836          Class expClass = type._class.registered;
1837          Class cClass = null;
1838          int paramCount = 0;
1839          int lastParam = -1;
1840
1841          char templateString[1024];
1842          ClassTemplateParameter param;
1843          sprintf(templateString, "%s<", expClass.templateClass.fullName);
1844          for(cClass = expClass; cClass; cClass = cClass.base)
1845          {
1846             int p = 0;
1847             if(cClass.templateClass) cClass = cClass.templateClass;
1848             for(param = cClass.templateParams.first; param; param = param.next)
1849             {
1850                int id = p;
1851                Class sClass;
1852                ClassTemplateArgument arg;
1853                for(sClass = cClass.base; sClass; sClass = sClass.base)
1854                {
1855                   if(sClass.templateClass) sClass = sClass.templateClass;
1856                   id += sClass.templateParams.count;
1857                }
1858                arg = expClass.templateArgs[id];
1859
1860                for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
1861                {
1862                   ClassTemplateParameter cParam;
1863                   //int p = numParams - sClass.templateParams.count;
1864                   int p = 0;
1865                   Class nextClass;
1866                   if(sClass.templateClass) sClass = sClass.templateClass;
1867
1868                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
1869                   {
1870                      if(nextClass.templateClass) nextClass = nextClass.templateClass;
1871                      p += nextClass.templateParams.count;
1872                   }
1873
1874                   for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
1875                   {
1876                      if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
1877                      {
1878                         if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1879                         {
1880                            arg.dataTypeString = _class.templateArgs[p].dataTypeString;
1881                            arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
1882                            break;
1883                         }
1884                      }
1885                   }
1886                }
1887
1888                {
1889                   char argument[256];
1890                   argument[0] = '\0';
1891                   /*if(arg.name)
1892                   {
1893                      strcat(argument, arg.name.string);
1894                      strcat(argument, " = ");
1895                   }*/
1896                   switch(param.type)
1897                   {
1898                      case expression:
1899                      {
1900                         // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
1901                         char expString[1024];
1902                         OldList * specs = MkList();
1903                         Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
1904                         Expression exp;
1905                         char * string = PrintHexUInt64(arg.expression.ui64);
1906                         exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
1907                         delete string;
1908
1909                         ProcessExpressionType(exp);
1910                         ComputeExpression(exp);
1911                         expString[0] = '\0';
1912                         PrintExpression(exp, expString);
1913                         strcat(argument, expString);
1914                         //delete exp;
1915                         FreeExpression(exp);
1916                         break;
1917                      }
1918                      case identifier:
1919                      {
1920                         strcat(argument, arg.member.name);
1921                         break;
1922                      }
1923                      case TemplateParameterType::type:
1924                      {
1925                         if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1926                            strcat(argument, arg.dataTypeString);
1927                         break;
1928                      }
1929                   }
1930                   if(argument[0])
1931                   {
1932                      if(paramCount) strcat(templateString, ", ");
1933                      if(lastParam != p - 1)
1934                      {
1935                         strcat(templateString, param.name);
1936                         strcat(templateString, " = ");
1937                      }
1938                      strcat(templateString, argument);
1939                      paramCount++;
1940                      lastParam = p;
1941                   }
1942                   p++;
1943                }
1944             }
1945          }
1946          {
1947             int len = strlen(templateString);
1948             if(templateString[len-1] == '<')
1949                len--;
1950             else
1951             {
1952                if(templateString[len-1] == '>')
1953                   templateString[len++] = ' ';
1954                templateString[len++] = '>';
1955             }
1956             templateString[len++] = '\0';
1957          }
1958          {
1959             Context context = SetupTemplatesContext(_class);
1960             if(freeType) FreeType(type);
1961             type = ProcessTypeString(templateString, false);
1962             freeType = true;
1963             FinishTemplatesContext(context);
1964          }
1965       }
1966
1967       if(method && member.initializer && member.initializer.type == expInitializer && member.initializer.exp)
1968       {
1969          ProcessExpressionType(member.initializer.exp);
1970          if(!member.initializer.exp.expType)
1971          {
1972             if(inCompiler)
1973             {
1974                char expString[10240];
1975                expString[0] = '\0';
1976                PrintExpression(member.initializer.exp, expString);
1977                ChangeCh(expString, '\n', ' ');
1978                Compiler_Error($"unresolved symbol used as an instance method %s\n", expString);
1979             }
1980          }
1981          //else if(!MatchTypes(member.exp.expType, type, null, _class, null, true, true, false, false))
1982          else if(!MatchTypes(member.initializer.exp.expType, type, null, null, _class, true, true, false, false, true))
1983          {
1984             Compiler_Error($"incompatible instance method %s\n", ident.string);
1985          }
1986       }
1987       else if(member.initializer)
1988       {
1989          /*
1990          FreeType(member.exp.destType);
1991          member.exp.destType = type;
1992          if(member.exp.destType)
1993             member.exp.destType.refCount++;
1994          ProcessExpressionType(member.exp);
1995          */
1996
1997          ProcessInitializer(member.initializer, type);
1998       }
1999       if(freeType) FreeType(type);
2000    }
2001    else
2002    {
2003       if(_class && _class.type == unitClass)
2004       {
2005          if(member.initializer)
2006          {
2007             /*
2008             FreeType(member.exp.destType);
2009             member.exp.destType = MkClassType(_class.fullName);
2010             ProcessExpressionType(member.initializer, type);
2011             */
2012             Type type = MkClassType(_class.fullName);
2013             ProcessInitializer(member.initializer, type);
2014             FreeType(type);
2015          }
2016       }
2017       else
2018       {
2019          if(member.initializer)
2020          {
2021             //ProcessExpressionType(member.exp);
2022             ProcessInitializer(member.initializer, null);
2023          }
2024          if(ident)
2025          {
2026             if(method)
2027             {
2028                Compiler_Error($"couldn't find virtual method %s in class %s\n", ident.string, _class.fullName);
2029             }
2030             else if(_class)
2031             {
2032                Compiler_Error($"couldn't find member %s in class %s\n", ident.string, _class.fullName);
2033                if(inCompiler)
2034                   eClass_AddDataMember(_class, ident.string, "int", 0, 0, publicAccess);
2035             }
2036          }
2037          else if(_class)
2038             Compiler_Error($"too many initializers for instantiation of class %s\n", _class.fullName);
2039       }
2040    }
2041 }
2042
2043 void ProcessInstantiationType(Instantiation inst)
2044 {
2045    yylloc = inst.loc;
2046    if(inst._class)
2047    {
2048       MembersInit members;
2049       Symbol classSym;
2050       Class _class;
2051
2052       classSym = inst._class.symbol;
2053       _class = classSym ? classSym.registered : null;
2054
2055       if(!_class || _class.type != noHeadClass)
2056          DeclareStruct(curExternal, inst._class.name, false, true);
2057
2058       afterExternal = afterExternal ? afterExternal : curExternal;
2059
2060       if(inst.exp)
2061          ProcessExpressionType(inst.exp);
2062
2063       inst.isConstant = true;
2064       if(inst.members)
2065       {
2066          DataMember curMember = null;
2067          Class curClass = null;
2068          DataMember subMemberStack[256];
2069          int subMemberStackPos = 0;
2070
2071          for(members = inst.members->first; members; members = members.next)
2072          {
2073             switch(members.type)
2074             {
2075                case methodMembersInit:
2076                {
2077                   char name[1024];
2078                   static uint instMethodID = 0;
2079                   External external = curExternal;
2080                   Context context = curContext;
2081                   Declarator declarator = members.function.declarator;
2082                   Identifier nameID = GetDeclId(declarator);
2083                   char * unmangled = nameID ? nameID.string : null;
2084                   Expression exp;
2085                   External createdExternal = null;
2086
2087                   if(inCompiler)
2088                   {
2089                      char number[16];
2090                      strcpy(name, "__ecereInstMeth_");
2091                      FullClassNameCat(name, _class ? _class.fullName : "_UNKNOWNCLASS", false);
2092                      strcat(name, "_");
2093                      strcat(name, nameID.string);
2094                      strcat(name, "_");
2095                      sprintf(number, "_%08d", instMethodID++);
2096                      strcat(name, number);
2097                      nameID.string = CopyString(name);
2098                   }
2099
2100                   // Do modifications here...
2101                   if(declarator)
2102                   {
2103                      Symbol symbol = declarator.symbol;
2104                      Method method = eClass_FindMethod(_class, unmangled, privateModule);
2105
2106                      if(method && method.type == virtualMethod)
2107                      {
2108                         symbol.method = method;
2109                         ProcessMethodType(method);
2110
2111                         if(!symbol.type.thisClass)
2112                         {
2113                            if(method.dataType.thisClass && currentClass &&
2114                               eClass_IsDerived(currentClass, method.dataType.thisClass.registered))
2115                            {
2116                               if(!currentClass.symbol)
2117                                  currentClass.symbol = FindClass(currentClass.fullName);
2118                               symbol.type.thisClass = currentClass.symbol;
2119                            }
2120                            else
2121                            {
2122                               if(!_class.symbol)
2123                                  _class.symbol = FindClass(_class.fullName);
2124                               symbol.type.thisClass = _class.symbol;
2125                            }
2126                         }
2127                         DeclareType(curExternal, symbol.type, true, true);
2128
2129                      }
2130                      else if(classSym)
2131                      {
2132                         Compiler_Error($"couldn't find virtual method %s in class %s\n",
2133                            unmangled, classSym.string);
2134                      }
2135                   }
2136
2137                   createdExternal = ProcessClassFunction(classSym ? classSym.registered : null, members.function, ast, afterExternal, true);
2138
2139                   if(nameID)
2140                   {
2141                      FreeSpecifier(nameID._class);
2142                      nameID._class = null;
2143                   }
2144
2145                   curExternal = createdExternal;
2146                   if(inCompiler)
2147                   {
2148                      if(createdExternal.function)
2149                         ProcessFunction(createdExternal.function);
2150                   }
2151                   else if(declarator)
2152                   {
2153                      curExternal = declarator.symbol.pointerExternal;
2154                      ProcessFunction((FunctionDefinition)members.function);
2155                   }
2156                   curExternal = external;
2157                   curContext = context;
2158
2159                   if(inCompiler)
2160                   {
2161                      FreeClassFunction(members.function);
2162
2163                      // In this pass, turn this into a MemberInitData
2164                      exp = QMkExpId(name);
2165                      members.type = dataMembersInit;
2166                      members.dataMembers = MkListOne(MkMemberInit(MkListOne(MkIdentifier(unmangled)), MkInitializerAssignment(exp)));
2167
2168                      delete unmangled;
2169                   }
2170                   break;
2171                }
2172                case dataMembersInit:
2173                {
2174                   if(members.dataMembers && classSym)
2175                   {
2176                      MemberInit member;
2177                      Location oldyyloc = yylloc;
2178                      for(member = members.dataMembers->first; member; member = member.next)
2179                      {
2180                         ProcessMemberInitData(member, classSym.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
2181                         if(member.initializer && !member.initializer.isConstant)
2182                            inst.isConstant = false;
2183                      }
2184                      yylloc = oldyyloc;
2185                   }
2186                   break;
2187                }
2188             }
2189          }
2190       }
2191    }
2192 }
2193
2194 void DeclareType(External neededFor, Type type, bool needDereference, bool forFunctionDef)
2195 {
2196    _DeclareType(neededFor, type, needDereference, forFunctionDef, false);
2197 }
2198
2199 void DeclareTypeForwardDeclare(External neededFor, Type type, bool needDereference, bool forFunctionDef)
2200 {
2201    _DeclareType(neededFor, type, needDereference, forFunctionDef, true);
2202 }
2203
2204 static void _DeclareType(External neededFor, Type type, bool needDereference, bool forFunctionDef, bool fwdDecl)
2205 {
2206    if(inCompiler)
2207    {
2208       if(type.kind == functionType)
2209       {
2210          Type param;
2211          for(param = type.params.first; param; param = param.next)
2212             _DeclareType(neededFor, param, forFunctionDef, false, fwdDecl);
2213          _DeclareType(neededFor, type.returnType, forFunctionDef, false, fwdDecl);
2214       }
2215       else if(type.kind == pointerType)
2216          _DeclareType(neededFor, type.type, false, false, fwdDecl);
2217       else if(type.kind == classType)
2218       {
2219          Class c = type._class.registered;
2220          _DeclareStruct(neededFor, c ? c.fullName : "ecere::com::Instance", c ? c.type == noHeadClass : false, needDereference && c && c.type == structClass, fwdDecl);
2221       }
2222       else if(type.kind == structType || type.kind == unionType)
2223       {
2224          Type member;
2225          for(member = type.members.first; member; member = member.next)
2226             _DeclareType(neededFor, member, needDereference, forFunctionDef, fwdDecl);
2227       }
2228       else if(type.kind == arrayType)
2229          _DeclareType(neededFor, type.arrayType, true, false, fwdDecl);
2230    }
2231 }
2232
2233 ClassTemplateArgument * FindTemplateArg(Class _class, TemplateParameter param)
2234 {
2235    ClassTemplateArgument * arg = null;
2236    int id = 0;
2237    ClassTemplateParameter curParam = null;
2238    Class sClass;
2239    for(sClass = _class; sClass; sClass = sClass.base)
2240    {
2241       id = 0;
2242       if(sClass.templateClass) sClass = sClass.templateClass;
2243       for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
2244       {
2245          if(curParam.type == TemplateParameterType::type && !strcmp(param.identifier.string, curParam.name))
2246          {
2247             for(sClass = sClass.base; sClass; sClass = sClass.base)
2248             {
2249                if(sClass.templateClass) sClass = sClass.templateClass;
2250                id += sClass.templateParams.count;
2251             }
2252             break;
2253          }
2254          id++;
2255       }
2256       if(curParam) break;
2257    }
2258    if(curParam)
2259    {
2260       arg = &_class.templateArgs[id];
2261       if(arg && param.type == type)
2262          arg->dataTypeClass = eSystem_FindClass(_class.module, arg->dataTypeString);
2263    }
2264    return arg;
2265 }
2266
2267 public Context SetupTemplatesContext(Class _class)
2268 {
2269    Context context = PushContext();
2270    context.templateTypesOnly = true;
2271    if(_class.symbol && ((Symbol)_class.symbol).templateParams)
2272    {
2273       TemplateParameter param = ((Symbol)_class.symbol).templateParams->first;
2274       for(; param; param = param.next)
2275       {
2276          if(param.type == type && param.identifier)
2277          {
2278             TemplatedType type { key = (uintptr)param.identifier.string, param = param };
2279             curContext.templateTypes.Add((BTNode)type);
2280          }
2281       }
2282    }
2283    else if(_class)
2284    {
2285       Class sClass;
2286       for(sClass = _class; sClass; sClass = sClass.base)
2287       {
2288          ClassTemplateParameter p;
2289          for(p = sClass.templateParams.first; p; p = p.next)
2290          {
2291             //OldList * specs = MkList();
2292             //Declarator decl = null;
2293             //decl = SpecDeclFromString(p.dataTypeString, specs, null);
2294             if(p.type == type)
2295             {
2296                TemplateParameter param = p.param;
2297                TemplatedType type;
2298                if(!param)
2299                {
2300                   // ADD DATA TYPE HERE...
2301                   p.param = param = TemplateParameter
2302                   {
2303                      identifier = MkIdentifier(p.name), type = p.type,
2304                      dataTypeString = p.dataTypeString /*, dataType = { specs, decl }*/
2305                   };
2306                }
2307                type = TemplatedType { key = (uintptr)p.name, param = param };
2308                curContext.templateTypes.Add((BTNode)type);
2309             }
2310          }
2311       }
2312    }
2313    return context;
2314 }
2315
2316 public void FinishTemplatesContext(Context context)
2317 {
2318    PopContext(context);
2319    FreeContext(context);
2320    delete context;
2321 }
2322
2323 public void ProcessMethodType(Method method)
2324 {
2325    if(!method.dataType)
2326    {
2327       Context context = SetupTemplatesContext(method._class);
2328
2329       method.dataType = ProcessTypeString(method.dataTypeString, false);
2330
2331       FinishTemplatesContext(context);
2332
2333       if(method.type != virtualMethod && method.dataType)
2334       {
2335          if(!method.dataType.thisClass && !method.dataType.staticMethod)
2336          {
2337             if(!method._class.symbol)
2338                method._class.symbol = FindClass(method._class.fullName);
2339             method.dataType.thisClass = method._class.symbol;
2340          }
2341       }
2342
2343       // Why was this commented out? Working fine without now...
2344
2345       /*
2346       if(method.dataType.kind == functionType && !method.dataType.staticMethod && !method.dataType.thisClass)
2347          method.dataType.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2348          */
2349    }
2350
2351    /*
2352    if(type)
2353    {
2354       char * par = strstr(type, "(");
2355       char * classOp = null;
2356       int classOpLen = 0;
2357       if(par)
2358       {
2359          int c;
2360          for(c = par-type-1; c >= 0; c++)
2361          {
2362             if(type[c] == ':' && type[c+1] == ':')
2363             {
2364                classOp = type + c - 1;
2365                for(c = c-1; c >=0 && !isspace(type[c]); c--)
2366                {
2367                   classOp--;
2368                   classOpLen++;
2369                }
2370                break;
2371             }
2372             else if(!isspace(type[c]))
2373                break;
2374          }
2375       }
2376       if(classOp)
2377       {
2378          char temp[1024];
2379          int typeLen = strlen(type);
2380          memcpy(temp, classOp, classOpLen);
2381          temp[classOpLen] = '\0';
2382          if(temp[0])
2383             _class = eSystem_FindClass(module, temp);
2384          else
2385             _class = null;
2386          method.dataTypeString = new char[typeLen - classOpLen + 1];
2387          memcpy(method.dataTypeString, type, classOp - type);
2388          memcpy(method.dataTypeString + (classOp - type), classOp + classOpLen, typeLen - (classOp - type + classOpLen));
2389       }
2390       else
2391          method.dataTypeString = type;
2392    }
2393    */
2394 }
2395
2396
2397 public void ProcessPropertyType(Property prop)
2398 {
2399    if(!prop.dataType)
2400    {
2401       Context context = SetupTemplatesContext(prop._class);
2402       prop.dataType = ProcessTypeString(prop.dataTypeString, false);
2403       FinishTemplatesContext(context);
2404    }
2405 }
2406
2407 public void DeclareMethod(External neededFor, Method method, const char * name)
2408 {
2409    Symbol symbol = method.symbol;
2410    if(!symbol || (!symbol.pointerExternal && (!symbol.methodCodeExternal || method.type == virtualMethod)))
2411    {
2412       bool dllImport = false;
2413
2414       if(!method.dataType)
2415          method.dataType = ProcessTypeString(method.dataTypeString, false);
2416
2417       //if(!symbol || symbol._import || method.type == virtualMethod)
2418       {
2419          if(!symbol || method.type == virtualMethod)
2420          {
2421             Symbol classSym;
2422             if(!method._class.symbol)
2423                method._class.symbol = FindClass(method._class.fullName);
2424             classSym = method._class.symbol;
2425             if(!classSym._import)
2426             {
2427                ModuleImport module;
2428
2429                if(method._class.module && method._class.module.name)
2430                   module = FindModule(method._class.module);
2431                else
2432                   module = mainModule;
2433                classSym._import = ClassImport
2434                {
2435                   name = CopyString(method._class.fullName);
2436                   isRemote = method._class.isRemote;
2437                };
2438                module.classes.Add(classSym._import);
2439             }
2440             if(!symbol)
2441             {
2442                symbol = method.symbol = Symbol { };
2443             }
2444             if(!symbol._import)
2445             {
2446                symbol._import = (ClassImport)MethodImport
2447                {
2448                   name = CopyString(method.name);
2449                   isVirtual = method.type == virtualMethod;
2450                };
2451                classSym._import.methods.Add(symbol._import);
2452             }
2453             if(!symbol)
2454             {
2455                symbol.type = method.dataType;
2456                if(symbol.type) symbol.type.refCount++;
2457             }
2458          }
2459          if(!method.dataType.dllExport)
2460          {
2461             if((method._class.module != privateModule || !strcmp(method._class.name, "float") || !strcmp(method._class.name, "double")) && method._class.module.importType != staticImport)
2462                dllImport = true;
2463          }
2464       }
2465
2466       if(inCompiler)
2467       {
2468          // We need a declaration here :)
2469          Declaration decl;
2470          OldList * specifiers, * declarators;
2471          Declarator d;
2472          Declarator funcDecl;
2473          External external;
2474
2475          specifiers = MkList();
2476          declarators = MkList();
2477
2478          if(dllImport)
2479             ListAdd(specifiers, MkSpecifier(EXTERN));
2480          else if(method._class.symbol && ((Symbol)method._class.symbol).isStatic)
2481             ListAdd(specifiers, MkSpecifier(STATIC));
2482
2483          if(method.type == virtualMethod)
2484          {
2485             ListAdd(specifiers, MkSpecifier(INT));
2486             d = MkDeclaratorIdentifier(MkIdentifier(name));
2487          }
2488          else
2489          {
2490             d = MkDeclaratorIdentifier(MkIdentifier(name));
2491             if(dllImport)
2492                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2493             {
2494                Context context = SetupTemplatesContext(method._class);
2495                d = SpecDeclFromString(method.dataTypeString, specifiers, d);
2496                FinishTemplatesContext(context);
2497             }
2498             funcDecl = GetFuncDecl(d);
2499
2500             if(dllImport)
2501             {
2502                Specifier spec, next;
2503                for(spec = specifiers->first; spec; spec = next)
2504                {
2505                   next = spec.next;
2506                   if(spec.type == extendedSpecifier)
2507                   {
2508                      specifiers->Remove(spec);
2509                      FreeSpecifier(spec);
2510                   }
2511                }
2512             }
2513
2514             // Add this parameter if not a static method
2515             if(method.dataType && !method.dataType.staticMethod)
2516             {
2517                if(funcDecl && funcDecl.function.parameters && funcDecl.function.parameters->count)
2518                {
2519                   Class _class = method.dataType.thisClass ? method.dataType.thisClass.registered : method._class;
2520                   TypeName thisParam = MkTypeName(MkListOne(
2521                      MkSpecifierName(method.dataType.thisClass ? method.dataType.thisClass.string : method._class.fullName)),
2522                      (_class && _class.type == systemClass) ? MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("this"))) : MkDeclaratorIdentifier(MkIdentifier("this")));
2523                   TypeName firstParam = ((TypeName)funcDecl.function.parameters->first);
2524                   Specifier firstSpec = firstParam.qualifiers ? firstParam.qualifiers->first : null;
2525
2526                   if(firstSpec && firstSpec.type == baseSpecifier && firstSpec.specifier == VOID && !firstParam.declarator)
2527                   {
2528                      TypeName param = funcDecl.function.parameters->first;
2529                      funcDecl.function.parameters->Remove(param);
2530                      FreeTypeName(param);
2531                   }
2532
2533                   if(!funcDecl.function.parameters)
2534                      funcDecl.function.parameters = MkList();
2535                   funcDecl.function.parameters->Insert(null, thisParam);
2536                }
2537             }
2538          }
2539          ProcessDeclarator(d, true);
2540
2541          ListAdd(declarators, MkInitDeclarator(d, null));
2542
2543          decl = MkDeclaration(specifiers, declarators);
2544
2545          ReplaceThisClassSpecifiers(specifiers, method._class);
2546
2547          external = MkExternalDeclaration(decl);
2548          external.symbol = symbol;
2549          symbol.pointerExternal = external;
2550          ast->Add(external);
2551          DeclareStruct(external, method._class.fullName, true, true);
2552          if(method.dataType)
2553             DeclareType(external, method.dataType, true, true);
2554       }
2555    }
2556    if(inCompiler && neededFor)
2557    {
2558       External external = symbol.pointerExternal ? symbol.pointerExternal : symbol.methodCodeExternal;
2559       neededFor.CreateUniqueEdge(external, external.type == functionExternal);
2560    }
2561 }
2562
2563 char * ReplaceThisClass(Class _class)
2564 {
2565    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2566    {
2567       bool first = true;
2568       int p = 0;
2569       ClassTemplateParameter param;
2570       int lastParam = -1;
2571
2572       char className[1024];
2573       strcpy(className, _class.fullName);
2574       for(param = _class.templateParams.first; param; param = param.next)
2575       {
2576          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2577          {
2578             if(first) strcat(className, "<");
2579             if(!first) strcat(className, ", ");
2580             if(lastParam + 1 != p)
2581             {
2582                strcat(className, param.name);
2583                strcat(className, " = ");
2584             }
2585             strcat(className, param.name);
2586             first = false;
2587             lastParam = p;
2588          }
2589          p++;
2590       }
2591       if(!first)
2592       {
2593          int len = strlen(className);
2594          if(className[len-1] == '>') className[len++] = ' ';
2595          className[len++] = '>';
2596          className[len++] = '\0';
2597       }
2598       return CopyString(className);
2599    }
2600    else
2601       return CopyString(_class.fullName);
2602 }
2603
2604 Type ReplaceThisClassType(Class _class)
2605 {
2606    Type type;
2607    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2608    {
2609       bool first = true;
2610       int p = 0;
2611       ClassTemplateParameter param;
2612       int lastParam = -1;
2613       char className[1024];
2614       strcpy(className, _class.fullName);
2615
2616       for(param = _class.templateParams.first; param; param = param.next)
2617       {
2618          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2619          {
2620             if(first) strcat(className, "<");
2621             if(!first) strcat(className, ", ");
2622             if(lastParam + 1 != p)
2623             {
2624                strcat(className, param.name);
2625                strcat(className, " = ");
2626             }
2627             strcat(className, param.name);
2628             first = false;
2629             lastParam = p;
2630          }
2631          p++;
2632       }
2633       if(!first)
2634       {
2635          int len = strlen(className);
2636          if(className[len-1] == '>') className[len++] = ' ';
2637          className[len++] = '>';
2638          className[len++] = '\0';
2639       }
2640       type = MkClassType(className);
2641       //type = ProcessTypeString(className, false);
2642    }
2643    else
2644    {
2645       type = MkClassType(_class.fullName);
2646       //type = ProcessTypeString(_class.fullName, false);
2647    }
2648    //type.wasThisClass = true;
2649    return type;
2650 }
2651
2652 void ReplaceThisClassSpecifiers(OldList specs, Class _class)
2653 {
2654    if(specs != null && _class)
2655    {
2656       Specifier spec;
2657       for(spec = specs.first; spec; spec = spec.next)
2658       {
2659          if(spec.type == baseSpecifier && spec.specifier == THISCLASS)
2660          {
2661             spec.type = nameSpecifier;
2662             spec.name = ReplaceThisClass(_class);
2663             spec.symbol = FindClass(spec.name); //_class.symbol;
2664          }
2665       }
2666    }
2667 }
2668
2669 // Returns imported or not
2670 bool DeclareFunction(External neededFor, GlobalFunction function, char * name)
2671 {
2672    Symbol symbol = function.symbol;
2673    // TOCHECK: Might get rid of the pointerExternal check in favor of marking the edge as breakable
2674    if(!symbol || !symbol.pointerExternal)
2675    {
2676       bool imported = false;
2677       bool dllImport = false;
2678
2679       if(!function.dataType)
2680       {
2681          function.dataType = ProcessTypeString(function.dataTypeString, false);
2682          if(!function.dataType.thisClass)
2683             function.dataType.staticMethod = true;
2684       }
2685
2686       if(inCompiler)
2687       {
2688          if(!symbol)
2689          {
2690             ModuleImport module = FindModule(function.module);
2691             // WARNING: This is not added anywhere...
2692             symbol = function.symbol = Symbol {  };
2693
2694             if(module.name)
2695             {
2696                if(!function.dataType.dllExport)
2697                {
2698                   symbol._import = (ClassImport)FunctionImport { name = CopyString(function.name) };
2699                   module.functions.Add(symbol._import);
2700                }
2701             }
2702             // Set the symbol type
2703             {
2704                symbol.type = ProcessTypeString(function.dataTypeString, false);
2705                if(!symbol.type.thisClass)
2706                   symbol.type.staticMethod = true;
2707             }
2708          }
2709          imported = symbol._import ? true : false;
2710          if(imported && function.module != privateModule && function.module.importType != staticImport)
2711             dllImport = true;
2712       }
2713
2714       if(inCompiler)
2715       {
2716          // TOCHECK: What's with the functionExternal check here? Is it Edge breaking / forward declaration?
2717          //if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2718          {
2719             // We need a declaration here :)
2720             Declaration decl;
2721             OldList * specifiers, * declarators;
2722             Declarator d;
2723             Declarator funcDecl;
2724             External external;
2725
2726             specifiers = MkList();
2727             declarators = MkList();
2728
2729             ListAdd(specifiers, MkSpecifier(EXTERN));
2730
2731             d = MkDeclaratorIdentifier(MkIdentifier(imported ? name : function.name));
2732             if(dllImport)
2733                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2734
2735             d = SpecDeclFromString(function.dataTypeString, specifiers, d);
2736             // TAKE OUT THE DLL EXPORT IF STATICALLY IMPORTED:
2737             if(function.module.importType == staticImport)
2738             {
2739                Specifier spec;
2740                for(spec = specifiers->first; spec; spec = spec.next)
2741                   if(spec.type == extendedSpecifier && spec.extDecl && spec.extDecl.type == extDeclString && !strcmp(spec.extDecl.s, "dllexport"))
2742                   {
2743                      specifiers->Remove(spec);
2744                      FreeSpecifier(spec);
2745                      break;
2746                   }
2747             }
2748
2749             funcDecl = GetFuncDecl(d);
2750
2751             // Make sure we don't have empty parameter declarations for static methods...
2752             if(funcDecl && !funcDecl.function.parameters)
2753             {
2754                funcDecl.function.parameters = MkList();
2755                funcDecl.function.parameters->Insert(null,
2756                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2757             }
2758
2759             ListAdd(declarators, MkInitDeclarator(d, null));
2760
2761             {
2762                Context oldCtx = curContext;
2763                curContext = globalContext;
2764                decl = MkDeclaration(specifiers, declarators);
2765                curContext = oldCtx;
2766             }
2767
2768             // Keep a different symbol for the function definition than the declaration...
2769             /* Note: This should be handled by the edge breaking...
2770             if(symbol.pointerExternal && symbol.pointerExternal.type == functionExternal)
2771             {
2772                Symbol functionSymbol { };
2773                // Copy symbol
2774                {
2775                   *functionSymbol = *symbol;
2776                   functionSymbol.string = CopyString(symbol.string);
2777                   if(functionSymbol.type)
2778                      functionSymbol.type.refCount++;
2779                }
2780
2781                excludedSymbols->Add(functionSymbol);
2782
2783                symbol.pointerExternal.symbol = functionSymbol;
2784             }
2785             */
2786             external = MkExternalDeclaration(decl);
2787             ast->Add(external);
2788             external.symbol = symbol;
2789             symbol.pointerExternal = external;
2790
2791             DeclareType(external, function.dataType, true, true);
2792          }
2793       }
2794    }
2795    if(inCompiler && neededFor && symbol && symbol.pointerExternal)
2796       neededFor.CreateUniqueEdge(symbol.pointerExternal, symbol.pointerExternal.type == functionExternal);
2797    return (symbol && symbol._import && function.module != privateModule && function.module.importType != staticImport) ? true : false;
2798 }
2799
2800 void DeclareGlobalData(External neededFor, GlobalData data)
2801 {
2802    Symbol symbol = data.symbol;
2803    // TOCHECK: Might get rid of the pointerExternal check in favor of marking the edge as breakable
2804    if(!symbol || !symbol.pointerExternal)
2805    {
2806       if(inCompiler)
2807       {
2808          if(!symbol)
2809             symbol = data.symbol = Symbol { };
2810       }
2811       if(!data.dataType)
2812          data.dataType = ProcessTypeString(data.dataTypeString, false);
2813
2814       if(inCompiler)
2815       {
2816          // We need a declaration here :)
2817          Declaration decl;
2818          OldList * specifiers, * declarators;
2819          Declarator d;
2820          External external;
2821
2822          specifiers = MkList();
2823          declarators = MkList();
2824
2825          ListAdd(specifiers, MkSpecifier(EXTERN));
2826          d = MkDeclaratorIdentifier(MkIdentifier(data.fullName));
2827          d = SpecDeclFromString(data.dataTypeString, specifiers, d);
2828
2829          ListAdd(declarators, MkInitDeclarator(d, null));
2830
2831          decl = MkDeclaration(specifiers, declarators);
2832          external = MkExternalDeclaration(decl);
2833          if(curExternal)
2834             ast->Insert(curExternal.prev, external);
2835          external.symbol = symbol;
2836          symbol.pointerExternal = external;
2837
2838          DeclareType(external, data.dataType, true, true);
2839       }
2840    }
2841    if(inCompiler && neededFor && symbol && symbol.pointerExternal)
2842       neededFor.CreateUniqueEdge(symbol.pointerExternal, false);
2843 }
2844
2845 class Conversion : struct
2846 {
2847    Conversion prev, next;
2848    Property convert;
2849    bool isGet;
2850    Type resultType;
2851 };
2852
2853 static bool CheckConstCompatibility(Type source, Type dest, bool warn)
2854 {
2855    bool status = true;
2856    if(((source.kind == classType && source._class && source._class.registered) || source.kind == arrayType || source.kind == pointerType) &&
2857       ((dest.kind == classType && dest._class && dest._class.registered) || /*dest.kind == arrayType || */dest.kind == pointerType))
2858    {
2859       Class sourceClass = source.kind == classType ? source._class.registered : null;
2860       Class destClass = dest.kind == classType ? dest._class.registered : null;
2861       if((!sourceClass || (sourceClass && sourceClass.type == normalClass && !sourceClass.structSize)) &&
2862          (!destClass || (destClass && destClass.type == normalClass && !destClass.structSize)))
2863       {
2864          Type sourceType = source, destType = dest;
2865          while((sourceType.kind == pointerType || sourceType.kind == arrayType) && sourceType.type) sourceType = sourceType.type;
2866          while((destType.kind == pointerType || destType.kind == arrayType) && destType.type) destType = destType.type;
2867          if(!destType.constant && sourceType.constant)
2868          {
2869             status = false;
2870             if(warn)
2871                Compiler_Warning($"discarding const qualifier\n");
2872          }
2873       }
2874    }
2875    return status;
2876 }
2877
2878 public bool MatchTypes(Type source, Type dest, OldList conversions, Class owningClassSource, Class owningClassDest, bool doConversion, bool enumBaseType, bool acceptReversedParams,
2879                        bool isConversionExploration, bool warnConst)
2880 {
2881    if(source && dest)
2882    {
2883       if(warnConst)
2884          CheckConstCompatibility(source, dest, true);
2885       // Property convert;
2886
2887       if(source.kind == templateType && dest.kind != templateType)
2888       {
2889          Type type = ProcessTemplateParameterType(source.templateParameter);
2890          if(type) source = type;
2891       }
2892
2893       if(dest.kind == templateType && source.kind != templateType)
2894       {
2895          Type type = ProcessTemplateParameterType(dest.templateParameter);
2896          if(type) dest = type;
2897       }
2898
2899       if(dest.classObjectType == typedObject && dest.kind != functionType)
2900       {
2901          if(source.classObjectType != anyObject)
2902             return true;
2903          else
2904          {
2905             // If either the source or the destination defines the class, accepts any_object as compatible for a typed_object
2906             if((dest._class && strcmp(dest._class.string, "class")) || (source._class && strcmp(source._class.string, "class")))
2907             {
2908                return true;
2909             }
2910          }
2911       }
2912       else
2913       {
2914          if(source.kind != functionType && source.classObjectType == anyObject)
2915             return true;
2916          if(dest.kind != functionType && dest.classObjectType == anyObject && source.classObjectType != typedObject)
2917             return true;
2918       }
2919
2920       if((dest.kind == structType && source.kind == structType) ||
2921          (dest.kind == unionType && source.kind == unionType))
2922       {
2923          if((dest.enumName && source.enumName && !strcmp(dest.enumName, source.enumName)) ||
2924              (source.members.first && source.members.first == dest.members.first))
2925             return true;
2926       }
2927
2928       if(dest.kind == ellipsisType && source.kind != voidType)
2929          return true;
2930
2931       if(dest.kind == pointerType && dest.type.kind == voidType &&
2932          ((source.kind == classType && (!source._class || !source._class.registered || source._class.registered.type == structClass || source._class.registered.type == normalClass || source._class.registered.type == noHeadClass || source._class.registered.type == systemClass))
2933          || source.kind == subClassType || source.kind == pointerType || source.kind == arrayType || source.kind == functionType || source.kind == thisClassType)
2934
2935          /*source.kind != voidType && source.kind != structType && source.kind != unionType  */
2936
2937          /*&& (source.kind != classType /-*|| source._class.registered.type != structClass)*/)
2938          return true;
2939       if(!isConversionExploration && source.kind == pointerType && source.type.kind == voidType &&
2940          ((dest.kind == classType && (!dest._class || !dest._class.registered || dest._class.registered.type == structClass || dest._class.registered.type == normalClass || dest._class.registered.type == noHeadClass || dest._class.registered.type == systemClass))
2941          || dest.kind == subClassType || dest.kind == pointerType || dest.kind == arrayType || dest.kind == functionType || dest.kind == thisClassType)
2942          /* dest.kind != voidType && dest.kind != structType && dest.kind != unionType  */
2943
2944          /*&& (dest.kind != classType || dest._class.registered.type != structClass)*/)
2945          return true;
2946
2947       if(((source.kind == classType && dest.kind == classType) || (source.kind == subClassType && dest.kind == subClassType)) && source._class)
2948       {
2949          if(source._class.registered && source._class.registered.type == unitClass)
2950          {
2951             if(conversions != null)
2952             {
2953                if(source._class.registered == dest._class.registered)
2954                   return true;
2955             }
2956             else
2957             {
2958                Class sourceBase, destBase;
2959                for(sourceBase = source._class.registered; sourceBase && sourceBase.base.type != systemClass; sourceBase = sourceBase.base);
2960                for(destBase = dest._class.registered; destBase && destBase.base.type != systemClass; destBase = destBase.base);
2961                if(sourceBase == destBase)
2962                   return true;
2963             }
2964          }
2965          // Don't match enum inheriting from other enum if resolving enumeration values
2966          // TESTING: !dest.classObjectType
2967          else if(source._class && dest._class && (dest.classObjectType == source.classObjectType || !dest.classObjectType) &&
2968             (enumBaseType ||
2969                (!source._class.registered || source._class.registered.type != enumClass) ||
2970                (!dest._class.registered || dest._class.registered.type != enumClass)) && eClass_IsDerived(source._class.registered, dest._class.registered))
2971             return true;
2972          else
2973          {
2974             // Added this so that DefinedColor = Color doesn't go through ColorRGB property
2975             if(dest._class && dest._class.registered && source._class && source._class.registered &&
2976                (dest.casted || (enumBaseType && dest._class.registered.type == enumClass &&
2977                   (source.kind == classType ||  // Added this here for a base enum to be acceptable for a derived enum (#139)
2978                    source._class.registered.type != enumClass)
2979                 ) ) )
2980             {
2981                if(eClass_IsDerived(dest._class.registered, source._class.registered))
2982                {
2983                   return true;
2984                }
2985             }
2986          }
2987       }
2988
2989       // JUST ADDED THIS...
2990       if(source.kind == subClassType && dest.kind == classType && dest._class && !strcmp(dest._class.string, "ecere::com::Class"))
2991          return true;
2992
2993       if(doConversion)
2994       {
2995          // Just added this for Straight conversion of ColorAlpha => Color
2996          if(source.kind == classType)
2997          {
2998             Class _class;
2999             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3000             {
3001                Property convert;
3002                for(convert = _class.conversions.first; convert; convert = convert.next)
3003                {
3004                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3005                   {
3006                      Conversion after = (conversions != null) ? conversions.last : null;
3007
3008                      if(!convert.dataType)
3009                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3010                      // Only go ahead with this conversion flow while processing an existing conversion if the conversion data type is a class
3011                      if((!isConversionExploration || convert.dataType.kind == classType || !strcmp(_class.name, "String")) &&
3012                         MatchTypes(convert.dataType, dest, conversions, null, null,
3013                            (convert.dataType.kind == classType && !strcmp(convert.dataTypeString, "String")) ? true : false,
3014                               convert.dataType.kind == classType, false, true, warnConst))
3015                      {
3016                         if(!conversions && !convert.Get)
3017                            return true;
3018                         else if(conversions != null)
3019                         {
3020                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3021                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3022                               (dest.kind != classType || dest._class.registered != _class.base))
3023                               return true;
3024                            else
3025                            {
3026                               Conversion conv { convert = convert, isGet = true };
3027                               // conversions.Add(conv);
3028                               conversions.Insert(after, conv);
3029
3030                               return true;
3031                            }
3032                         }
3033                      }
3034                   }
3035                }
3036             }
3037          }
3038
3039          // MOVING THIS??
3040
3041          if(dest.kind == classType)
3042          {
3043             Class _class;
3044             for(_class = dest._class ? dest._class.registered : null; _class; _class = _class.base)
3045             {
3046                Property convert;
3047                for(convert = _class.conversions.first; convert; convert = convert.next)
3048                {
3049                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3050                   {
3051                      Type constType = null;
3052                      bool success = false;
3053                      // Conversion after = (conversions != null) ? conversions.last : null;
3054
3055                      if(!convert.dataType)
3056                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3057
3058                      if(warnConst && convert.dataType.kind == pointerType && convert.dataType.type && dest.constant)
3059                      {
3060                         Type ptrType { };
3061                         constType = { kind = pointerType, refCount = 1, type = ptrType };
3062                         CopyTypeInto(ptrType, convert.dataType.type);
3063                         ptrType.constant = true;
3064                      }
3065
3066                      // Just added this equality check to prevent recursion.... Make it safer?
3067                      // Changed enumBaseType to false here to prevent all int-compatible enums to show up in AnchorValues
3068                      if((constType || convert.dataType != dest) && MatchTypes(source, constType ? constType : convert.dataType, conversions, null, null, true, false /*true*/, false, true, warnConst))
3069                      {
3070                         if(!conversions && !convert.Set)
3071                            success = true;
3072                         else if(conversions != null)
3073                         {
3074                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3075                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3076                               (source.kind != classType || source._class.registered != _class.base))
3077                               success = true;
3078                            else
3079                            {
3080                               // *** Testing this! ***
3081                               Conversion conv { convert = convert };
3082                               conversions.Add(conv);
3083                               //conversions.Insert(after, conv);
3084                               success = true;
3085                            }
3086                         }
3087                      }
3088                      if(constType)
3089                         FreeType(constType);
3090                      if(success)
3091                         return true;
3092                   }
3093                }
3094             }
3095             /*if(dest._class.registered && !strcmp(dest._class.registered.name, "bool"))
3096             {
3097                if(source.kind != voidType && source.kind != structType && source.kind != unionType &&
3098                   (source.kind != classType || source._class.registered.type != structClass))
3099                   return true;
3100             }*/
3101
3102             // TESTING THIS... IS THIS OK??
3103             if(enumBaseType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3104             {
3105                if(!dest._class.registered.dataType)
3106                   dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3107                // Only support this for classes...
3108                if(dest._class.registered.dataType.kind == classType || source.truth || dest.truth/* ||
3109                   !strcmp(dest._class.registered.name, "bool") || (source.kind == classType && !strcmp(source._class.string, "bool"))*/)
3110                {
3111                   if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, dest._class.registered.dataType.kind == classType, false, false, warnConst))
3112                   {
3113                      return true;
3114                   }
3115                }
3116             }
3117          }
3118
3119          // Moved this lower
3120          if(source.kind == classType)
3121          {
3122             Class _class;
3123             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3124             {
3125                Property convert;
3126                for(convert = _class.conversions.first; convert; convert = convert.next)
3127                {
3128                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3129                   {
3130                      Conversion after = (conversions != null) ? conversions.last : null;
3131
3132                      if(!convert.dataType)
3133                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3134                      if(convert.dataType != source &&
3135                         (!isConversionExploration || convert.dataType.kind == classType || !strcmp(_class.name, "String")) &&
3136                         MatchTypes(convert.dataType, dest, conversions, null, null, convert.dataType.kind == classType, convert.dataType.kind == classType, false, true, warnConst))
3137                      {
3138                         if(!conversions && !convert.Get)
3139                            return true;
3140                         else if(conversions != null)
3141                         {
3142                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3143                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3144                               (dest.kind != classType || dest._class.registered != _class.base))
3145                               return true;
3146                            else
3147                            {
3148                               Conversion conv { convert = convert, isGet = true };
3149
3150                               // conversions.Add(conv);
3151                               conversions.Insert(after, conv);
3152                               return true;
3153                            }
3154                         }
3155                      }
3156                   }
3157                }
3158             }
3159
3160             // TESTING THIS... IS THIS OK??
3161             if(enumBaseType && source._class && source._class.registered && source._class.registered.type == enumClass)
3162             {
3163                if(!source._class.registered.dataType)
3164                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3165                if(!isConversionExploration || source._class.registered.dataType.kind == classType || !strcmp(source._class.registered.name, "String"))
3166                {
3167                   if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, source._class.registered.dataType.kind == classType, source._class.registered.dataType.kind == classType, false, false, warnConst))
3168                      return true;
3169                   // For bool to be accepted by byte, short, etc.
3170                   else if(MatchTypes(dest, source._class.registered.dataType, null, null, null, false, false, false, false, warnConst))
3171                      return true;
3172                }
3173             }
3174          }
3175       }
3176
3177       if(source.kind == classType || source.kind == subClassType)
3178          ;
3179       else if(dest.kind == source.kind &&
3180          (dest.kind != structType && dest.kind != unionType &&
3181           dest.kind != functionType && dest.kind != arrayType && dest.kind != pointerType && dest.kind != methodType))
3182           return true;
3183       // RECENTLY ADDED THESE
3184       else if(dest.kind == doubleType && source.kind == floatType)
3185          return true;
3186       else if(dest.kind == shortType && (source.kind == charType || source.kind == _BoolType))
3187          return true;
3188       else if(dest.kind == intType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intSizeType /* Exception here for size_t */))
3189          return true;
3190       else if(dest.kind == int64Type && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intPtrType || source.kind == intSizeType))
3191          return true;
3192       else if(dest.kind == intPtrType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intSizeType || source.kind == int64Type))
3193          return true;
3194       else if(dest.kind == intSizeType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == int64Type || source.kind == intPtrType))
3195          return true;
3196       else if(source.kind == enumType &&
3197          (dest.kind == intType || dest.kind == shortType || dest.kind == charType || source.kind == _BoolType || dest.kind == longType || dest.kind == int64Type || dest.kind == intPtrType || dest.kind == intSizeType))
3198           return true;
3199       else if(dest.kind == enumType && !isConversionExploration &&
3200          (source.kind == intType || source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == longType || source.kind == int64Type || source.kind == intPtrType || source.kind == intSizeType))
3201           return true;
3202       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) &&
3203               ((source.kind == functionType || (source.kind == pointerType && source.type.kind == functionType) || source.kind == methodType)))
3204       {
3205          Type paramSource, paramDest;
3206
3207          if(dest.kind == methodType)
3208             owningClassDest = dest.methodClass ? dest.methodClass : dest.method._class;
3209          if(source.kind == methodType)
3210             owningClassSource = source.methodClass ? source.methodClass : source.method._class;
3211
3212          if(dest.kind == pointerType && dest.type.kind == functionType) dest = dest.type;
3213          if(source.kind == pointerType && source.type.kind == functionType) source = source.type;
3214          if(dest.kind == methodType)
3215             dest = dest.method.dataType;
3216          if(source.kind == methodType)
3217             source = source.method.dataType;
3218
3219          paramSource = source.params.first;
3220          if(paramSource && paramSource.kind == voidType) paramSource = null;
3221          paramDest = dest.params.first;
3222          if(paramDest && paramDest.kind == voidType) paramDest = null;
3223
3224
3225          if((dest.staticMethod || (!dest.thisClass && !owningClassDest)) &&
3226             !(source.staticMethod || (!source.thisClass && !owningClassSource)))
3227          {
3228             // Source thisClass must be derived from destination thisClass
3229             if(!paramDest || (!(paramDest.kind == pointerType && paramDest.type && paramDest.type.kind == voidType) && (paramDest.kind != classType ||
3230                !eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource,paramDest._class.registered))))
3231             {
3232                if(paramDest && paramDest.kind == classType)
3233                   Compiler_Error($"method class must be derived from %s\n", paramDest._class.string);
3234                else
3235                   Compiler_Error($"method class should not take an object\n");
3236                return false;
3237             }
3238             paramDest = paramDest.next;
3239          }
3240          else if(!dest.staticMethod && (dest.thisClass || owningClassDest))
3241          {
3242             if((source.staticMethod || (!source.thisClass && !owningClassSource)))
3243             {
3244                if(dest.thisClass)
3245                {
3246                   if(!paramSource || paramSource.kind != classType || !eClass_IsDerived(paramSource._class.registered,dest.thisClass.registered))
3247                   {
3248                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3249                      return false;
3250                   }
3251                }
3252                else
3253                {
3254                   // THIS WAS BACKWARDS:
3255                   // if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(owningClassDest, paramSource._class.registered)))
3256                   if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(paramSource._class.registered, owningClassDest)))
3257                   {
3258                      if(owningClassDest)
3259                        Compiler_Error($"%s expected to be derived from method class\n", owningClassDest.fullName);
3260                      else
3261                         Compiler_Error($"overriding class expected to be derived from method class\n");
3262                      return false;
3263                   }
3264                }
3265                paramSource = paramSource.next;
3266             }
3267             else
3268             {
3269                if(dest.thisClass)
3270                {
3271                   // Source thisClass must be derived from destination thisClass
3272                   if(!eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource, dest.thisClass.registered))
3273                   {
3274                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3275                      return false;
3276                   }
3277                }
3278                else
3279                {
3280                   // THIS WAS BACKWARDS TOO??
3281                   // if(source.thisClass && owningClassDest && !eClass_IsDerived(owningClassDest, source.thisClass.registered))
3282                   if(source.thisClass && source.thisClass.registered && owningClassDest && !eClass_IsDerived(source.thisClass.registered, owningClassDest))
3283                   {
3284                      //if(owningClass)
3285                         Compiler_Error($"%s expected to be derived from method class\n", /*owningClass.name*/ source.thisClass.registered.fullName);
3286                      //else
3287                         //Compiler_Error($"overriding class expected to be derived from method class\n");
3288                      return false;
3289                   }
3290                }
3291             }
3292          }
3293
3294
3295          // Source return type must be derived from destination return type
3296          if(!MatchTypes(source.returnType, dest.returnType, null, null, null, true, true, false, false, warnConst))
3297          {
3298             Compiler_Warning($"incompatible return type for function\n");
3299             return false;
3300          }
3301          // The const check is backwards from the MatchTypes above (for derivative classes checks)
3302          else
3303             CheckConstCompatibility(dest.returnType, source.returnType, true);
3304
3305          // Check parameters
3306
3307          for(; paramDest; paramDest = paramDest.next)
3308          {
3309             if(!paramSource)
3310             {
3311                //Compiler_Warning($"not enough parameters\n");
3312                Compiler_Error($"not enough parameters\n");
3313                return false;
3314             }
3315             {
3316                Type paramDestType = paramDest;
3317                Type paramSourceType = paramSource;
3318                Type type = paramDestType;
3319
3320                // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
3321                if(paramDest.kind == templateType && paramDest.templateParameter.type == TemplateParameterType::type && owningClassSource &&
3322                   paramSource.kind != templateType)
3323                {
3324                   int id = 0;
3325                   ClassTemplateParameter curParam = null;
3326                   Class sClass;
3327                   for(sClass = owningClassSource; sClass; sClass = sClass.base)
3328                   {
3329                      id = 0;
3330                      if(sClass.templateClass) sClass = sClass.templateClass;
3331                      for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
3332                      {
3333                         if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
3334                         {
3335                            for(sClass = sClass.base; sClass; sClass = sClass.base)
3336                            {
3337                               if(sClass.templateClass) sClass = sClass.templateClass;
3338                               id += sClass.templateParams.count;
3339                            }
3340                            break;
3341                         }
3342                         id++;
3343                      }
3344                      if(curParam) break;
3345                   }
3346
3347                   if(curParam)
3348                   {
3349                      ClassTemplateArgument arg = owningClassSource.templateArgs[id];
3350                      paramDestType = type = ProcessTypeString(arg.dataTypeString, false);
3351                   }
3352                }
3353
3354                // paramDest must be derived from paramSource
3355                if(!MatchTypes(paramDestType, paramSourceType, null, null, null, true, true, false, false, warnConst) &&
3356                   (!acceptReversedParams || !MatchTypes(paramSourceType, paramDestType, null, null, null, true, true, false, false, warnConst)))
3357                {
3358                   char type[1024];
3359                   type[0] = 0;
3360                   PrintType(paramDest, type, false, true);
3361                   Compiler_Warning($"incompatible parameter %s (expected %s)\n", paramSource.name, type);
3362
3363                   if(paramDestType != paramDest)
3364                      FreeType(paramDestType);
3365                   return false;
3366                }
3367                if(paramDestType != paramDest)
3368                   FreeType(paramDestType);
3369             }
3370
3371             paramSource = paramSource.next;
3372          }
3373          if(paramSource)
3374          {
3375             Compiler_Error($"too many parameters\n");
3376             return false;
3377          }
3378          return true;
3379       }
3380       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) && (source.kind == pointerType && source.type.kind == voidType))
3381       {
3382          return true;
3383       }
3384       else if((dest.kind == pointerType || dest.kind == arrayType) &&
3385          (source.kind == arrayType || source.kind == pointerType))
3386       {
3387          // Pointers to pointer is incompatible with non normal/nohead classes
3388          if(!(dest.type && dest.type.kind == pointerType && source.type.kind == classType && source.type._class &&
3389             source.type._class.registered && (source.type._class.registered.type != normalClass && source.type._class.registered.type != noHeadClass) && !source.type.byReference))
3390          {
3391             ComputeTypeSize(source.type);
3392             ComputeTypeSize(dest.type);
3393             if(source.type.size == dest.type.size && MatchTypes(source.type, dest.type, null, null, null, true, true, false, false, warnConst))
3394                return true;
3395          }
3396       }
3397    }
3398    return false;
3399 }
3400
3401 static void FreeConvert(Conversion convert)
3402 {
3403    if(convert.resultType)
3404       FreeType(convert.resultType);
3405 }
3406
3407 bool MatchWithEnums_NameSpace(NameSpace nameSpace, Expression sourceExp, Type dest,
3408                               char * string, OldList conversions)
3409 {
3410    BTNamedLink link;
3411
3412    for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
3413    {
3414       Class _class = link.data;
3415       if(_class.type == enumClass)
3416       {
3417          OldList converts { };
3418          Type type { };
3419          type.kind = classType;
3420
3421          if(!_class.symbol)
3422             _class.symbol = FindClass(_class.fullName);
3423          type._class = _class.symbol;
3424
3425          if(MatchTypes(type, dest, &converts, null, null, dest.kind != classType || !dest._class || strcmp(dest._class.string, "bool"),
3426                false, false, false, false))
3427          {
3428             NamedLink64 value;
3429             Class enumClass = eSystem_FindClass(privateModule, "enum");
3430             if(enumClass)
3431             {
3432                Class baseClass;
3433                for(baseClass = _class ; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
3434                {
3435                   EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
3436                   for(value = e.values.first; value; value = value.next)
3437                   {
3438                      if(!strcmp(value.name, string))
3439                         break;
3440                   }
3441                   if(value)
3442                   {
3443                      FreeType(sourceExp.expType);
3444
3445                      sourceExp.isConstant = true;
3446                      sourceExp.expType = MkClassType(baseClass.fullName);
3447                      if(inCompiler || inPreCompiler || inDebugger)
3448                      {
3449                         char constant[256];
3450                         FreeExpContents(sourceExp);
3451
3452                         sourceExp.type = constantExp;
3453                         if(!strcmp(baseClass.dataTypeString, "int") || !strcmp(baseClass.dataTypeString, "int64") || !strcmp(baseClass.dataTypeString, "short") || !strcmp(baseClass.dataTypeString, "char"))
3454                            sprintf(constant, FORMAT64D, value.data);
3455                         else
3456                            sprintf(constant, FORMAT64HEXLL, value.data);
3457                         sourceExp.constant = CopyString(constant);
3458                         //for(;baseClass.base && baseClass.base.type != systemClass; baseClass = baseClass.base);
3459                      }
3460
3461                      while(converts.first)
3462                      {
3463                         Conversion convert = converts.first;
3464                         converts.Remove(convert);
3465                         conversions.Add(convert);
3466                      }
3467                      delete type;
3468                      return true;
3469                   }
3470                }
3471             }
3472          }
3473          if(converts.first)
3474             converts.Free(FreeConvert);
3475          delete type;
3476       }
3477    }
3478    for(nameSpace = (NameSpace *)nameSpace.nameSpaces.first; nameSpace != null; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
3479       if(MatchWithEnums_NameSpace(nameSpace, sourceExp, dest, string, conversions))
3480          return true;
3481    return false;
3482 }
3483
3484 public bool ModuleVisibility(Module searchIn, Module searchFor)
3485 {
3486    SubModule subModule;
3487
3488    if(searchFor == searchIn)
3489       return true;
3490
3491    for(subModule = searchIn.modules.first; subModule; subModule = subModule.next)
3492    {
3493       if(subModule.importMode == publicAccess || searchIn == searchIn.application)
3494       {
3495          if(ModuleVisibility(subModule.module, searchFor))
3496             return true;
3497       }
3498    }
3499    return false;
3500 }
3501
3502 bool MatchWithEnums_Module(Module mainModule, Expression sourceExp, Type dest, char * string, OldList conversions)
3503 {
3504    Module module;
3505
3506    if(MatchWithEnums_NameSpace(mainModule.application.systemNameSpace, sourceExp, dest, string, conversions))
3507       return true;
3508    if(MatchWithEnums_NameSpace(mainModule.application.privateNameSpace, sourceExp, dest, string, conversions))
3509       return true;
3510    if(MatchWithEnums_NameSpace(mainModule.application.publicNameSpace, sourceExp, dest, string, conversions))
3511       return true;
3512
3513    for(module = mainModule.application.allModules.first; module; module = module.next)
3514    {
3515       if(ModuleVisibility(mainModule, module) && MatchWithEnums_NameSpace(module.publicNameSpace, sourceExp, dest, string, conversions))
3516          return true;
3517    }
3518    return false;
3519 }
3520
3521 bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, bool skipUnitBla, bool warnConst)
3522 {
3523    Type source;
3524    Type realDest = dest;
3525    Type backupSourceExpType = null;
3526    Expression nbExp = GetNonBracketsExp(sourceExp);
3527    Expression computedExp = nbExp;
3528    dest.refCount++;
3529
3530    if(sourceExp.isConstant && sourceExp.type != constantExp && sourceExp.type != identifierExp && sourceExp.type != castExp &&
3531       dest.kind == classType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3532    {
3533       computedExp = CopyExpression(nbExp);        // Keep the original expression, but compute for checking enum ranges
3534       ComputeExpression(computedExp /*sourceExp*/);
3535    }
3536
3537    source = sourceExp.expType;
3538
3539    if(dest.kind == pointerType && sourceExp.type == constantExp && !strtoul(sourceExp.constant, null, 0))
3540    {
3541       if(computedExp != nbExp)
3542       {
3543          FreeExpression(computedExp);
3544          computedExp = nbExp;
3545       }
3546       FreeType(dest);
3547       return true;
3548    }
3549
3550    if(!skipUnitBla && source && dest && source.kind == classType && dest.kind == classType)
3551    {
3552        if(source._class && source._class.registered && source._class.registered.type == unitClass)
3553        {
3554           Class sourceBase, destBase;
3555           for(sourceBase = source._class.registered;
3556               sourceBase && sourceBase.base && sourceBase.base.type != systemClass;
3557               sourceBase = sourceBase.base);
3558           for(destBase = dest._class.registered;
3559               destBase && destBase.base && destBase.base.type != systemClass;
3560               destBase = destBase.base);
3561           //if(source._class.registered == dest._class.registered)
3562           if(sourceBase == destBase)
3563           {
3564             if(computedExp != nbExp)
3565             {
3566                FreeExpression(computedExp);
3567                computedExp = nbExp;
3568             }
3569             FreeType(dest);
3570             return true;
3571          }
3572       }
3573    }
3574
3575    if(source)
3576    {
3577       OldList * specs;
3578       bool flag = false;
3579       int64 value = MAXINT;
3580
3581       source.refCount++;
3582
3583       if(computedExp.type == constantExp)
3584       {
3585          if(source.isSigned)
3586             value = strtoll(computedExp.constant, null, 0);
3587          else
3588             value = strtoull(computedExp.constant, null, 0);
3589       }
3590       else if(computedExp.type == opExp && computedExp.op.op == '-' && !computedExp.op.exp1 && computedExp.op.exp2 && computedExp.op.exp2.type == constantExp)
3591       {
3592          if(source.isSigned)
3593             value = -strtoll(computedExp.op.exp2.constant, null, 0);
3594          else
3595             value = -strtoull(computedExp.op.exp2.constant, null, 0);
3596       }
3597       if(computedExp != nbExp)
3598       {
3599          FreeExpression(computedExp);
3600          computedExp = nbExp;
3601       }
3602
3603       if(dest.kind != classType && source.kind == classType && source._class && source._class.registered &&
3604          !strcmp(source._class.registered.fullName, "unichar" /*"ecere::com::unichar"*/))
3605       {
3606          FreeType(source);
3607          source = Type { kind = intType, isSigned = false, refCount = 1 };
3608       }
3609
3610       if(dest.kind == classType)
3611       {
3612          Class _class = dest._class ? dest._class.registered : null;
3613
3614          if(_class && _class.type == unitClass)
3615          {
3616             if(source.kind != classType)
3617             {
3618                Type tempType { };
3619                Type tempDest, tempSource;
3620
3621                for(; _class.base.type != systemClass; _class = _class.base);
3622                tempSource = dest;
3623                tempDest = tempType;
3624
3625                tempType.kind = classType;
3626                if(!_class.symbol)
3627                   _class.symbol = FindClass(_class.fullName);
3628
3629                tempType._class = _class.symbol;
3630                tempType.truth = dest.truth;
3631                if(tempType._class)
3632                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false, warnConst);
3633
3634                // NOTE: To handle bad warnings on int64 vs 32 bit eda::Id incompatibilities
3635                backupSourceExpType = sourceExp.expType;
3636                if(dest.passAsTemplate)
3637                {
3638                   // Don't carry passAsTemplate
3639                   sourceExp.expType = { };
3640                   CopyTypeInto(sourceExp.expType, dest);
3641                   sourceExp.expType.passAsTemplate = false;
3642                }
3643                else
3644                {
3645                   sourceExp.expType = dest;
3646                   dest.refCount++;
3647                }
3648                //sourceExp.expType = MkClassType(_class.fullName);
3649                flag = true;
3650
3651                delete tempType;
3652             }
3653          }
3654
3655
3656          // Why wasn't there something like this?
3657          if(_class && _class.type == bitClass && source.kind != classType)
3658          {
3659             if(!dest._class.registered.dataType)
3660                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3661             if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false, warnConst))
3662             {
3663                FreeType(source);
3664                FreeType(sourceExp.expType);
3665                source = sourceExp.expType = MkClassType(dest._class.string);
3666                source.refCount++;
3667
3668                //source.kind = classType;
3669                //source._class = dest._class;
3670             }
3671          }
3672
3673          // Adding two enumerations
3674          /*
3675          if(_class && _class.type == enumClass && source.kind == classType && source._class && source._class.registered && source._class.registered.type == enumClass)
3676          {
3677             if(!source._class.registered.dataType)
3678                source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3679             if(!dest._class.registered.dataType)
3680                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3681
3682             if(MatchTypes(source._class.registered.dataType, dest._class.registered.dataType, conversions, null, null, true, false, false))
3683             {
3684                FreeType(source);
3685                source = sourceExp.expType = MkClassType(dest._class.string);
3686                source.refCount++;
3687
3688                //source.kind = classType;
3689                //source._class = dest._class;
3690             }
3691          }*/
3692
3693          if(_class && !strcmp(_class.fullName, "ecere::com::Class") && source.kind == pointerType && source.type && source.type.kind == charType && sourceExp.type == stringExp)
3694          {
3695             OldList * specs = MkList();
3696             Declarator decl;
3697             char string[1024];
3698
3699             ReadString(string, sourceExp.string);
3700             decl = SpecDeclFromString(string, specs, null);
3701
3702             FreeExpContents(sourceExp);
3703             FreeType(sourceExp.expType);
3704
3705             sourceExp.type = classExp;
3706             sourceExp._classExp.specifiers = specs;
3707             sourceExp._classExp.decl = decl;
3708             sourceExp.expType = dest;
3709             dest.refCount++;
3710
3711             FreeType(source);
3712             FreeType(dest);
3713             if(backupSourceExpType) FreeType(backupSourceExpType);
3714             return true;
3715          }
3716       }
3717       else if(source.kind == classType)
3718       {
3719          Class _class = source._class ? source._class.registered : null;
3720
3721          if(_class && (_class.type == unitClass || /*!strcmp(_class.fullName, "bool") || _class.type == enumClass || */_class.type == bitClass ))  // TOCHECK: enumClass, bitClass is new here...
3722          {
3723             /*
3724             if(dest.kind != classType)
3725             {
3726                // Testing this simpler piece of code... (Broke Units Conversion to no unit Logic)
3727                if(!source._class.registered.dataType)
3728                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3729
3730                FreeType(dest);
3731                dest = MkClassType(source._class.string);
3732                //if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, false, false))
3733                //   dest = MkClassType(source._class.string);
3734             }
3735             */
3736
3737             if(dest.kind != classType)
3738             {
3739                Type tempType { };
3740                Type tempDest, tempSource;
3741
3742                if(!source._class.registered.dataType)
3743                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3744
3745                for(; _class.base.type != systemClass; _class = _class.base);
3746                tempDest = source;
3747                tempSource = tempType;
3748                tempType.kind = classType;
3749                tempType._class = FindClass(_class.fullName);
3750                tempType.truth = source.truth;
3751                tempType.classObjectType = source.classObjectType;
3752
3753                if(tempType._class)
3754                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false, warnConst);
3755
3756                // PUT THIS BACK TESTING UNITS?
3757                if(conversions && conversions.last)
3758                {
3759                   ((Conversion)(conversions.last)).resultType = dest;
3760                   dest.refCount++;
3761
3762                   // This fixes passing unit as template to a double
3763                   modifyPassAsTemplate(&((Conversion)(conversions.last)).resultType, false);
3764                }
3765
3766                FreeType(sourceExp.expType);
3767                sourceExp.expType = MkClassType(_class.fullName);
3768                sourceExp.expType.truth = source.truth;
3769                sourceExp.expType.classObjectType = source.classObjectType;
3770
3771                // *** This if was commented out, put it back because "int a =^ Destroy()" shows up bool enum values in autocomplete ***
3772
3773                if(!sourceExp.destType)
3774                {
3775                   FreeType(sourceExp.destType);
3776                   sourceExp.destType = sourceExp.expType;
3777                   if(sourceExp.expType)
3778                      sourceExp.expType.refCount++;
3779                }
3780                //flag = true;
3781                //source = _class.dataType;
3782
3783
3784                // TOCHECK: TESTING THIS NEW CODE
3785                if(!_class.dataType)
3786                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3787                FreeType(dest);
3788                dest = MkClassType(source._class.string);
3789                dest.truth = source.truth;
3790                dest.classObjectType = source.classObjectType;
3791
3792                FreeType(source);
3793                source = _class.dataType;
3794                source.refCount++;
3795
3796                delete tempType;
3797             }
3798          }
3799       }
3800
3801       if(!flag)
3802       {
3803          if(MatchTypes(source, dest, conversions, null, null, true, true, false, false, warnConst))
3804          {
3805             FreeType(source);
3806             FreeType(dest);
3807             return true;
3808          }
3809       }
3810
3811       // Implicit Casts
3812       /*
3813       if(source.kind == classType)
3814       {
3815          Class _class = source._class.registered;
3816          if(_class.type == unitClass)
3817          {
3818             if(!_class.dataType)
3819                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3820             source = _class.dataType;
3821          }
3822       }*/
3823
3824       if(dest.kind == classType)
3825       {
3826          Class _class = dest._class ? dest._class.registered : null;
3827          bool fittingValue = false;
3828          if(_class && _class.type == enumClass)
3829          {
3830             Class enumClass = eSystem_FindClass(privateModule, "enum");
3831             EnumClassData c = ACCESS_CLASSDATA(_class, enumClass);
3832             if(c && value >= 0 && value <= c.largest)
3833                fittingValue = true;
3834          }
3835
3836          if(_class && !dest.truth && (_class.type == unitClass || fittingValue ||
3837             (/*_class.type == enumClass*/_class.type != structClass && !value && source.kind == intType) || _class.type == bitClass))   // TOCHECK: enumClass, bitClass is new here...
3838          {
3839             if(_class.type == normalClass || _class.type == noHeadClass)
3840             {
3841                Expression newExp { };
3842                *newExp = *sourceExp;
3843                if(sourceExp.destType) sourceExp.destType.refCount++;
3844                if(sourceExp.expType)  sourceExp.expType.refCount++;
3845                sourceExp.type = castExp;
3846                sourceExp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
3847                sourceExp.cast.exp = newExp;
3848                FreeType(sourceExp.expType);
3849                sourceExp.expType = null;
3850                ProcessExpressionType(sourceExp);
3851
3852                // In Debugger, this helps with addresses (e.g. null pointers) that end up casted to a void *: keeps a classType instead of a pointerType
3853                if(!inCompiler)
3854                {
3855                   FreeType(sourceExp.expType);
3856                   sourceExp.expType = dest;
3857                }
3858
3859                FreeType(source);
3860                if(inCompiler) FreeType(dest);
3861
3862                if(backupSourceExpType) FreeType(backupSourceExpType);
3863                return true;
3864             }
3865
3866             if(!_class.dataType)
3867                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3868             FreeType(dest);
3869             dest = _class.dataType;
3870             dest.refCount++;
3871          }
3872
3873          // Accept lower precision types for units, since we want to keep the unit type
3874          if(dest.kind == doubleType &&
3875             (source.kind == doubleType || source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType ||
3876              source.kind == charType || source.kind == _BoolType))
3877          {
3878             specs = MkListOne(MkSpecifier(DOUBLE));
3879          }
3880          else if(dest.kind == floatType &&
3881             (source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3882             source.kind == _BoolType || source.kind == doubleType))
3883          {
3884             specs = MkListOne(MkSpecifier(FLOAT));
3885          }
3886          else if(dest.kind == int64Type && (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3887             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3888          {
3889             specs = MkList();
3890             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3891             ListAdd(specs, MkSpecifier(INT64));
3892          }
3893          else if(dest.kind == intType && (source.kind == intType || source.kind == shortType || source.kind == charType ||
3894             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3895          {
3896             specs = MkList();
3897             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3898             ListAdd(specs, MkSpecifier(INT));
3899          }
3900          else if(dest.kind == shortType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType ||
3901             source.kind == floatType || source.kind == doubleType))
3902          {
3903             specs = MkList();
3904             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3905             ListAdd(specs, MkSpecifier(SHORT));
3906          }
3907          else if(dest.kind == charType && (source.kind == charType || source.kind == _BoolType || source.kind == shortType || source.kind == intType ||
3908             source.kind == floatType || source.kind == doubleType))
3909          {
3910             specs = MkList();
3911             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3912             ListAdd(specs, MkSpecifier(CHAR));
3913          }
3914          else
3915          {
3916             FreeType(source);
3917             FreeType(dest);
3918             if(backupSourceExpType)
3919             {
3920                // Failed to convert: revert previous exp type
3921                if(sourceExp.expType) FreeType(sourceExp.expType);
3922                sourceExp.expType = backupSourceExpType;
3923             }
3924             return false;
3925          }
3926       }
3927       else if(dest.kind == doubleType &&
3928          (source.kind == doubleType || source.kind == floatType || source.kind == int64Type || source.kind == intType || source.kind == enumType || source.kind == shortType ||
3929           source.kind == _BoolType || source.kind == charType))
3930       {
3931          specs = MkListOne(MkSpecifier(DOUBLE));
3932       }
3933       else if(dest.kind == floatType &&
3934          (source.kind == floatType || source.kind == enumType || source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3935       {
3936          specs = MkListOne(MkSpecifier(FLOAT));
3937       }
3938       else if(dest.kind == _BoolType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3939          (value == 1 || value == 0))
3940       {
3941          specs = MkList();
3942          ListAdd(specs, MkSpecifier(BOOL));
3943       }
3944       else if(dest.kind == charType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3945          (dest.isSigned ? (value >= -128 && value <= 127) : (value >= 0 && value <= 255)))
3946       {
3947          if(source.kind == intType)
3948          {
3949             FreeType(dest);
3950             FreeType(source);
3951             if(backupSourceExpType) FreeType(backupSourceExpType);
3952             return true;
3953          }
3954          else
3955          {
3956             specs = MkList();
3957             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3958             ListAdd(specs, MkSpecifier(CHAR));
3959          }
3960       }
3961       else if(dest.kind == shortType && (source.kind == enumType || source.kind == _BoolType || source.kind == charType || source.kind == shortType ||
3962          (source.kind == intType && (dest.isSigned ? (value >= -32768 && value <= 32767) : (value >= 0 && value <= 65535)))))
3963       {
3964          if(source.kind == intType)
3965          {
3966             FreeType(dest);
3967             FreeType(source);
3968             if(backupSourceExpType) FreeType(backupSourceExpType);
3969             return true;
3970          }
3971          else
3972          {
3973             specs = MkList();
3974             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3975             ListAdd(specs, MkSpecifier(SHORT));
3976          }
3977       }
3978       else if(dest.kind == intType && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType))
3979       {
3980          specs = MkList();
3981          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3982          ListAdd(specs, MkSpecifier(INT));
3983       }
3984       else if(dest.kind == int64Type && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType || source.kind == int64Type))
3985       {
3986          specs = MkList();
3987          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3988          ListAdd(specs, MkSpecifier(INT64));
3989       }
3990       else if(dest.kind == enumType &&
3991          (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3992       {
3993          specs = MkListOne(MkEnum(MkIdentifier(dest.enumName), null));
3994       }
3995       else
3996       {
3997          FreeType(source);
3998          FreeType(dest);
3999          if(backupSourceExpType)
4000          {
4001             // Failed to convert: revert previous exp type
4002             if(sourceExp.expType) FreeType(sourceExp.expType);
4003             sourceExp.expType = backupSourceExpType;
4004          }
4005          return false;
4006       }
4007
4008       if(!flag && !sourceExp.opDestType)
4009       {
4010          Expression newExp { };
4011          *newExp = *sourceExp;
4012          newExp.prev = null;
4013          newExp.next = null;
4014          if(sourceExp.destType) sourceExp.destType.refCount++;
4015          if(sourceExp.expType)  sourceExp.expType.refCount++;
4016
4017          sourceExp.type = castExp;
4018          if(realDest.kind == classType)
4019          {
4020             sourceExp.cast.typeName = QMkClass(realDest._class.string, null);
4021             FreeList(specs, FreeSpecifier);
4022          }
4023          else
4024             sourceExp.cast.typeName = MkTypeName(specs, null);
4025          if(newExp.type == opExp)
4026          {
4027             sourceExp.cast.exp = MkExpBrackets(MkListOne(newExp));
4028          }
4029          else
4030             sourceExp.cast.exp = newExp;
4031
4032          FreeType(sourceExp.expType);
4033          sourceExp.expType = null;
4034          ProcessExpressionType(sourceExp);
4035       }
4036       else
4037          FreeList(specs, FreeSpecifier);
4038
4039       FreeType(dest);
4040       FreeType(source);
4041       if(backupSourceExpType) FreeType(backupSourceExpType);
4042
4043       return true;
4044    }
4045    else
4046    {
4047       if(computedExp != nbExp)
4048       {
4049          FreeExpression(computedExp);
4050          computedExp = nbExp;
4051       }
4052
4053       while((sourceExp.type == bracketsExp || sourceExp.type == extensionExpressionExp) && sourceExp.list) sourceExp = sourceExp.list->last;
4054       if(sourceExp.type == identifierExp)
4055       {
4056          Identifier id = sourceExp.identifier;
4057          if(dest.kind == classType)
4058          {
4059             if(dest._class && dest._class.registered && dest._class.registered.type == enumClass)
4060             {
4061                Class _class = dest._class.registered;
4062                Class enumClass = eSystem_FindClass(privateModule, "enum");
4063                if(enumClass)
4064                {
4065                   for( ; _class && _class.type == ClassType::enumClass; _class = _class.base)
4066                   {
4067                      NamedLink64 value;
4068                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4069                      for(value = e.values.first; value; value = value.next)
4070                      {
4071                         if(!strcmp(value.name, id.string))
4072                            break;
4073                      }
4074                      if(value)
4075                      {
4076                         FreeType(sourceExp.expType);
4077
4078                         sourceExp.isConstant = true;
4079                         sourceExp.expType = MkClassType(_class.fullName);
4080                         if(inCompiler || inPreCompiler || inDebugger)
4081                         {
4082                            FreeExpContents(sourceExp);
4083
4084                            sourceExp.type = constantExp;
4085                            if(_class.dataTypeString && (!strcmp(_class.dataTypeString, "int") || !strcmp(_class.dataTypeString, "int64") || !strcmp(_class.dataTypeString, "short") || !strcmp(_class.dataTypeString, "char"))) // _class cannot be null here!
4086                               sourceExp.constant = PrintInt64(value.data);
4087                            else
4088                               sourceExp.constant = PrintUInt64(value.data);
4089                            //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
4090                         }
4091                         FreeType(dest);
4092                         return true;
4093                      }
4094                   }
4095                }
4096             }
4097          }
4098
4099          // Loop through all enum classes
4100          if(dest.classObjectType != typedObject && dest.kind == classType /*!= ellipsisType */&& MatchWithEnums_Module(privateModule, sourceExp, dest, id.string, conversions))
4101          {
4102             FreeType(dest);
4103             return true;
4104          }
4105       }
4106       FreeType(dest);
4107    }
4108    return false;
4109 }
4110
4111 #define TERTIARY(o, name, m, t, p) \
4112    static bool name(Expression exp, Operand op1, Operand op2, Operand op3)   \
4113    {                                                              \
4114       exp.type = constantExp;                                    \
4115       exp.string = p(op1.m ? op2.m : op3.m);                     \
4116       if(!exp.expType) \
4117          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4118       return true;                                                \
4119    }
4120
4121 #define BINARY(o, name, m, t, p) \
4122    static bool name(Expression exp, Operand op1, Operand op2)   \
4123    {                                                              \
4124       t value2 = op2.m;                                           \
4125       exp.type = constantExp;                                    \
4126       exp.string = p((t)(op1.m o value2));                     \
4127       if(!exp.expType) \
4128          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4129       return true;                                                \
4130    }
4131
4132 #define BINARY_DIVIDEINT(o, name, m, t, p) \
4133    static bool name(Expression exp, Operand op1, Operand op2)   \
4134    {                                                              \
4135       t value2 = op2.m;                                           \
4136       exp.type = constantExp;                                    \
4137       exp.string = p(value2 ? ((t)(op1.m o value2)) : 0);             \
4138       if(!exp.expType) \
4139          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4140       return true;                                                \
4141    }
4142
4143 #define BINARY_DIVIDEREAL(o, name, m, t, p) \
4144    static bool name(Expression exp, Operand op1, Operand op2)   \
4145    {                                                              \
4146       t value2 = op2.m;                                           \
4147       exp.type = constantExp;                                    \
4148       exp.string = p((t)(op1.m o value2));             \
4149       if(!exp.expType) \
4150          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4151       return true;                                                \
4152    }
4153
4154 #define UNARY(o, name, m, t, p) \
4155    static bool name(Expression exp, Operand op1)                \
4156    {                                                              \
4157       exp.type = constantExp;                                    \
4158       exp.string = p((t)(o op1.m));                                   \
4159       if(!exp.expType) \
4160          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4161       return true;                                                \
4162    }
4163
4164 #define OPERATOR_ALL(macro, o, name) \
4165    macro(o, Int##name, i, int, PrintInt) \
4166    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4167    macro(o, Int64##name, i64, int64, PrintInt64) \
4168    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4169    macro(o, Short##name, s, short, PrintShort) \
4170    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4171    macro(o, Char##name, c, char, PrintChar) \
4172    macro(o, UChar##name, uc, unsigned char, PrintUChar) \
4173    macro(o, Float##name, f, float, PrintFloat) \
4174    macro(o, Double##name, d, double, PrintDouble)
4175
4176 #define OPERATOR_INTTYPES(macro, o, name) \
4177    macro(o, Int##name, i, int, PrintInt) \
4178    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4179    macro(o, Int64##name, i64, int64, PrintInt64) \
4180    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4181    macro(o, Short##name, s, short, PrintShort) \
4182    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4183    macro(o, Char##name, c, char, PrintChar) \
4184    macro(o, UChar##name, uc, unsigned char, PrintUChar)
4185
4186 #define OPERATOR_REALTYPES(macro, o, name) \
4187    macro(o, Float##name, f, float, PrintFloat) \
4188    macro(o, Double##name, d, double, PrintDouble)
4189
4190 // binary arithmetic
4191 OPERATOR_ALL(BINARY, +, Add)
4192 OPERATOR_ALL(BINARY, -, Sub)
4193 OPERATOR_ALL(BINARY, *, Mul)
4194 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /, Div)
4195 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /, Div)
4196 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %, Mod)
4197
4198 // unary arithmetic
4199 OPERATOR_ALL(UNARY, -, Neg)
4200
4201 // unary arithmetic increment and decrement
4202 OPERATOR_ALL(UNARY, ++, Inc)
4203 OPERATOR_ALL(UNARY, --, Dec)
4204
4205 // binary arithmetic assignment
4206 OPERATOR_ALL(BINARY, =, Asign)
4207 OPERATOR_ALL(BINARY, +=, AddAsign)
4208 OPERATOR_ALL(BINARY, -=, SubAsign)
4209 OPERATOR_ALL(BINARY, *=, MulAsign)
4210 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /=, DivAsign)
4211 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /=, DivAsign)
4212 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %=, ModAsign)
4213
4214 // binary bitwise
4215 OPERATOR_INTTYPES(BINARY, &, BitAnd)
4216 OPERATOR_INTTYPES(BINARY, |, BitOr)
4217 OPERATOR_INTTYPES(BINARY, ^, BitXor)
4218 OPERATOR_INTTYPES(BINARY, <<, LShift)
4219 OPERATOR_INTTYPES(BINARY, >>, RShift)
4220
4221 // unary bitwise
4222 OPERATOR_INTTYPES(UNARY, ~, BitNot)
4223
4224 // binary bitwise assignment
4225 OPERATOR_INTTYPES(BINARY, &=, AndAsign)
4226 OPERATOR_INTTYPES(BINARY, |=, OrAsign)
4227 OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
4228 OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
4229 OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
4230
4231 // unary logical negation
4232 OPERATOR_INTTYPES(UNARY, !, Not)
4233
4234 // binary logical equality
4235 OPERATOR_ALL(BINARY, ==, Equ)
4236 OPERATOR_ALL(BINARY, !=, Nqu)
4237
4238 // binary logical
4239 OPERATOR_ALL(BINARY, &&, And)
4240 OPERATOR_ALL(BINARY, ||, Or)
4241
4242 // binary logical relational
4243 OPERATOR_ALL(BINARY, >, Grt)
4244 OPERATOR_ALL(BINARY, <, Sma)
4245 OPERATOR_ALL(BINARY, >=, GrtEqu)
4246 OPERATOR_ALL(BINARY, <=, SmaEqu)
4247
4248 // tertiary condition operator
4249 OPERATOR_INTTYPES(TERTIARY, ?, Cond)
4250
4251 //Add, Sub, Mul, Div, Mod,     , Neg,     Inc, Dec,    Asign, AddAsign, SubAsign, MulAsign, DivAsign, ModAsign,     BitAnd, BitOr, BitXor, LShift, RShift, BitNot,     AndAsign, OrAsign, XorAsign, LShiftAsign, RShiftAsign,     Not,     Equ, Nqu,     And, Or,     Grt, Sma, GrtEqu, SmaEqu
4252 #define OPERATOR_TABLE_ALL(name, type) \
4253     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, type##Mod, \
4254                           type##Neg, \
4255                           type##Inc, type##Dec, \
4256                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, type##ModAsign, \
4257                           type##BitAnd, type##BitOr, type##BitXor, type##LShift, type##RShift, \
4258                           type##BitNot, \
4259                           type##AndAsign, type##OrAsign, type##XorAsign, type##LShiftAsign, type##RShiftAsign, \
4260                           type##Not, \
4261                           type##Equ, type##Nqu, \
4262                           type##And, type##Or, \
4263                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu, type##Cond \
4264                         }; \
4265
4266 #define OPERATOR_TABLE_INTTYPES(name, type) \
4267     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, null, \
4268                           type##Neg, \
4269                           type##Inc, type##Dec, \
4270                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, null, \
4271                           null, null, null, null, null, \
4272                           null, \
4273                           null, null, null, null, null, \
4274                           null, \
4275                           type##Equ, type##Nqu, \
4276                           type##And, type##Or, \
4277                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu \
4278                         }; \
4279
4280 OPERATOR_TABLE_ALL(int, Int)
4281 OPERATOR_TABLE_ALL(uint, UInt)
4282 OPERATOR_TABLE_ALL(int64, Int64)
4283 OPERATOR_TABLE_ALL(uint64, UInt64)
4284 OPERATOR_TABLE_ALL(short, Short)
4285 OPERATOR_TABLE_ALL(ushort, UShort)
4286 OPERATOR_TABLE_INTTYPES(float, Float)
4287 OPERATOR_TABLE_INTTYPES(double, Double)
4288 OPERATOR_TABLE_ALL(char, Char)
4289 OPERATOR_TABLE_ALL(uchar, UChar)
4290
4291 //OpTable intOps =    {    IntAdd,    IntSub,    IntMul,    IntDiv,    IntMod,    IntExp,    IntNot,    IntBwn,    IntOr,    IntAnd,    IntEqu,    IntNqu,    IntGrt,    IntSma,    IntGrtEqu,    IntSmaEqu,    IntNeg,    IntLBitSft,    IntRBitSft };
4292 //OpTable uintOps =   {   UIntAdd,   UIntSub,   UIntMul,   UIntDiv,   UIntMod,   UIntExp,   UIntNot,   UIntBwn,   UIntOr,   UIntAnd,   UIntEqu,   UIntNqu,   UIntGrt,   UIntSma,   UIntGrtEqu,   UIntSmaEqu,   UIntNeg,   UIntLBitSft,   UIntRBitSft };
4293 //OpTable shortOps =  {  ShortAdd,  ShortSub,  ShortMul,  ShortDiv,  ShortMod,  ShortExp,  ShortNot,  ShortBwn,  ShortOr,  ShortAnd,  ShortEqu,  ShortNqu,  ShortGrt,  ShortSma,  ShortGrtEqu,  ShortSmaEqu,  ShortNeg,  ShortLBitSft,  ShortRBitSft };
4294 //OpTable ushortOps = { UShortAdd, UShortSub, UShortMul, UShortDiv, UShortMod, UShortExp, UShortNot, UShortBwn, UShortOr, UShortAnd, UShortEqu, UShortNqu, UShortGrt, UShortSma, UShortGrtEqu, UShortSmaEqu, UShortNeg, UShortLBitSft, UShortRBitSft };
4295 //OpTable floatOps =  {  FloatAdd,  FloatSub,  FloatMul,  FloatDiv,      null,      null,      null,      null,     null,      null,  FloatEqu,  FloatNqu,  FloatGrt,  FloatSma,  FloatGrtEqu,  FloatSmaEqu,  FloatNeg,          null,          null };
4296 //OpTable doubleOps = { DoubleAdd, DoubleSub, DoubleMul, DoubleDiv,      null,      null,      null,      null,     null,      null, DoubleEqu, DoubleNqu, DoubleGrt, DoubleSma, DoubleGrtEqu, DoubleSmaEqu, DoubleNeg,          null,          null };
4297 //OpTable charOps =   {   CharAdd,   CharSub,   CharMul,   CharDiv,   CharMod,   CharExp,   CharNot,   CharBwn,   CharOr,   CharAnd,   CharEqu,   CharNqu,   CharGrt,   CharSma,   CharGrtEqu,   CharSmaEqu,   CharNeg,   CharLBitSft,   CharRBitSft };
4298 //OpTable ucharOps =  {  UCharAdd,  UCharSub,  UCharMul,  UCharDiv,  UCharMod,  UCharExp,  UCharNot,  UCharBwn,  UCharOr,  UCharAnd,  UCharEqu,  UCharNqu,  UCharGrt,  UCharSma,  UCharGrtEqu,  UCharSmaEqu,  UCharNeg,  UCharLBitSft,  UCharRBitSft };
4299
4300 public void ReadString(char * output,  char * string)
4301 {
4302    int len = strlen(string);
4303    int c,d = 0;
4304    bool quoted = false, escaped = false;
4305    for(c = 0; c<len; c++)
4306    {
4307       char ch = string[c];
4308       if(escaped)
4309       {
4310          switch(ch)
4311          {
4312             case 'n': output[d] = '\n'; break;
4313             case 't': output[d] = '\t'; break;
4314             case 'a': output[d] = '\a'; break;
4315             case 'b': output[d] = '\b'; break;
4316             case 'f': output[d] = '\f'; break;
4317             case 'r': output[d] = '\r'; break;
4318             case 'v': output[d] = '\v'; break;
4319             case '\\': output[d] = '\\'; break;
4320             case '\"': output[d] = '\"'; break;
4321             case '\'': output[d] = '\''; break;
4322             default: output[d] = ch;
4323          }
4324          d++;
4325          escaped = false;
4326       }
4327       else
4328       {
4329          if(ch == '\"')
4330             quoted ^= true;
4331          else if(quoted)
4332          {
4333             if(ch == '\\')
4334                escaped = true;
4335             else
4336                output[d++] = ch;
4337          }
4338       }
4339    }
4340    output[d] = '\0';
4341 }
4342
4343 // String Unescape Copy
4344
4345 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
4346 // This is the same as ReadString above (which also misses numeric escape codes) except it doesn't handle external quotes
4347 public int UnescapeString(char * d, char * s, int len)
4348 {
4349    int j = 0, k = 0;
4350    char ch;
4351    while(j < len && (ch = s[j]))
4352    {
4353       switch(ch)
4354       {
4355          case '\\':
4356             switch((ch = s[++j]))
4357             {
4358                case 'n': d[k] = '\n'; break;
4359                case 't': d[k] = '\t'; break;
4360                case 'a': d[k] = '\a'; break;
4361                case 'b': d[k] = '\b'; break;
4362                case 'f': d[k] = '\f'; break;
4363                case 'r': d[k] = '\r'; break;
4364                case 'v': d[k] = '\v'; break;
4365                case '\\': d[k] = '\\'; break;
4366                case '\"': d[k] = '\"'; break;
4367                case '\'': d[k] = '\''; break;
4368                default: d[k] = '\\'; d[k] = ch;
4369             }
4370             break;
4371          default:
4372             d[k] = ch;
4373       }
4374       j++, k++;
4375    }
4376    d[k] = '\0';
4377    return k;
4378 }
4379
4380 public char * OffsetEscapedString(char * s, int len, int offset)
4381 {
4382    char ch;
4383    int j = 0, k = 0;
4384    while(j < len && k < offset && (ch = s[j]))
4385    {
4386       if(ch == '\\') ++j;
4387       j++, k++;
4388    }
4389    return (k == offset) ? s + j : null;
4390 }
4391
4392 public Operand GetOperand(Expression exp)
4393 {
4394    Operand op { };
4395    Type type = exp.expType;
4396    if(type)
4397    {
4398       while(type.kind == classType && type._class &&
4399          type._class.registered && (type._class.registered.type == bitClass || type._class.registered.type == unitClass || type._class.registered.type == enumClass))
4400       {
4401          if(!type._class.registered.dataType)
4402             type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
4403          type = type._class.registered.dataType;
4404
4405       }
4406       if(exp.type == stringExp && op.kind == pointerType)
4407       {
4408          op.ui64 = (uint64)(uintptr)exp.string;
4409          op.kind = pointerType;
4410          op.ops = uint64Ops;
4411       }
4412       else if(exp.isConstant && exp.type == constantExp)
4413       {
4414          op.kind = type.kind;
4415          op.type = type;
4416
4417          switch(op.kind)
4418          {
4419             case _BoolType:
4420             case charType:
4421             {
4422                if(exp.constant[0] == '\'')
4423                {
4424                   op.c = exp.constant[1];
4425                   op.ops = charOps;
4426                }
4427                else if(type.isSigned)
4428                {
4429                   op.c = (char)strtol(exp.constant, null, 0);
4430                   op.ops = charOps;
4431                }
4432                else
4433                {
4434                   op.uc = (unsigned char)strtoul(exp.constant, null, 0);
4435                   op.ops = ucharOps;
4436                }
4437                break;
4438             }
4439             case shortType:
4440                if(exp.constant[0] == '\'')
4441                {
4442                   op.s = exp.constant[1];
4443                   op.ops = shortOps;
4444                }
4445                else if(type.isSigned)
4446                {
4447                   op.s = (short)strtol(exp.constant, null, 0);
4448                   op.ops = shortOps;
4449                }
4450                else
4451                {
4452                   op.us = (unsigned short)strtoul(exp.constant, null, 0);
4453                   op.ops = ushortOps;
4454                }
4455                break;
4456             case intType:
4457             case longType:
4458                if(exp.constant[0] == '\'')
4459                {
4460                   op.i = exp.constant[1];
4461                   op.ops = intOps;
4462                }
4463                else if(type.isSigned)
4464                {
4465                   op.i = (int)strtol(exp.constant, null, 0);
4466                   op.ops = intOps;
4467                }
4468                else
4469                {
4470                   op.ui = (unsigned int)strtoul(exp.constant, null, 0);
4471                   op.ops = uintOps;
4472                }
4473                op.kind = intType;
4474                break;
4475             case int64Type:
4476                if(type.isSigned)
4477                {
4478                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4479                   op.ops = int64Ops;
4480                }
4481                else
4482                {
4483                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4484                   op.ops = uint64Ops;
4485                }
4486                op.kind = int64Type;
4487                break;
4488             case intPtrType:
4489                if(type.isSigned)
4490                {
4491                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4492                   op.ops = int64Ops;
4493                }
4494                else
4495                {
4496                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4497                   op.ops = uint64Ops;
4498                }
4499                op.kind = int64Type;
4500                break;
4501             case intSizeType:
4502                if(type.isSigned)
4503                {
4504                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4505                   op.ops = int64Ops;
4506                }
4507                else
4508                {
4509                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4510                   op.ops = uint64Ops;
4511                }
4512                op.kind = int64Type;
4513                break;
4514             case floatType:
4515                if(!strcmp(exp.constant, "inf")) op.f = float::inf();
4516                else if(!strcmp(exp.constant, "-inf")) op.f = -float::inf();
4517                else if(!strcmp(exp.constant, "nan")) op.f = float::nan();
4518                else if(!strcmp(exp.constant, "-nan")) op.f = -float::nan();
4519                else
4520                   op.f = (float)strtod(exp.constant, null);
4521                op.ops = floatOps;
4522                break;
4523             case doubleType:
4524                if(!strcmp(exp.constant, "inf")) op.d = double::inf();
4525                else if(!strcmp(exp.constant, "-inf")) op.d = -double::inf();
4526                else if(!strcmp(exp.constant, "nan")) op.d = double::nan();
4527                else if(!strcmp(exp.constant, "-nan")) op.d = -double::nan();
4528                else
4529                   op.d = (double)strtod(exp.constant, null);
4530                op.ops = doubleOps;
4531                break;
4532             //case classType:    For when we have operator overloading...
4533             // Pointer additions
4534             //case functionType:
4535             case arrayType:
4536             case pointerType:
4537             case classType:
4538                op.ui64 = _strtoui64(exp.constant, null, 0);
4539                op.kind = pointerType;
4540                op.ops = uint64Ops;
4541                // op.ptrSize =
4542                break;
4543          }
4544       }
4545    }
4546    return op;
4547 }
4548
4549 static int64 GetEnumValue(Class _class, void * ptr)
4550 {
4551    int64 v = 0;
4552    switch(_class.typeSize)
4553    {
4554       case 8:
4555          if(!strcmp(_class.dataTypeString, "uint64"))
4556             v = (int64)*(uint64 *)ptr;
4557          else
4558             v = (int64)*(int64 *)ptr;
4559          break;
4560       case 4:
4561          if(!strcmp(_class.dataTypeString, "uint"))
4562             v = (int64)*(uint *)ptr;
4563          else
4564             v = (int64)*(int *)ptr;
4565          break;
4566       case 2:
4567          if(!strcmp(_class.dataTypeString, "uint16"))
4568             v = (int64)*(uint16 *)ptr;
4569          else
4570             v = (int64)*(short *)ptr;
4571          break;
4572       case 1:
4573          if(!strcmp(_class.dataTypeString, "byte"))
4574             v = (int64)*(byte *)ptr;
4575          else
4576             v = (int64)*(char *)ptr;
4577          break;
4578    }
4579    return v;
4580 }
4581
4582 static __attribute__((unused)) void UnusedFunction()
4583 {
4584    int a;
4585    a.OnGetString(0,0,0);
4586 }
4587 default:
4588 extern int __ecereVMethodID_class_OnGetString;
4589 public:
4590
4591 static void PopulateInstanceProcessMember(Instantiation inst, OldList * memberList, DataMember parentDataMember, uint offset)
4592 {
4593    DataMember dataMember;
4594    for(dataMember = parentDataMember.members.first; dataMember; dataMember = dataMember.next)
4595    {
4596       if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4597          PopulateInstanceProcessMember(inst, memberList, dataMember, offset + dataMember.offset);
4598       else
4599       {
4600          Expression exp { };
4601          MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4602          Type type;
4603          void * ptr = inst.data + dataMember.offset + offset;
4604          char * result = null;
4605          exp.loc = member.loc = inst.loc;
4606          ((Identifier)member.identifiers->first).loc = inst.loc;
4607
4608          if(!dataMember.dataType)
4609             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4610          type = dataMember.dataType;
4611          if(type.kind == classType)
4612          {
4613             Class _class = type._class.registered;
4614             if(_class.type == enumClass)
4615             {
4616                Class enumClass = eSystem_FindClass(privateModule, "enum");
4617                if(enumClass)
4618                {
4619                   EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4620                   NamedLink64 item;
4621                   for(item = e.values.first; item; item = item.next)
4622                   {
4623                      if(item.data == GetEnumValue(_class, ptr))
4624                      {
4625                         result = item.name;
4626                         break;
4627                      }
4628                   }
4629                   if(result)
4630                   {
4631                      exp.identifier = MkIdentifier(result);
4632                      exp.type = identifierExp;
4633                      exp.destType = MkClassType(_class.fullName);
4634                      ProcessExpressionType(exp);
4635                   }
4636                }
4637             }
4638             if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4639             {
4640                if(!_class.dataType)
4641                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4642                type = _class.dataType;
4643             }
4644          }
4645          if(!result)
4646          {
4647             switch(type.kind)
4648             {
4649                case floatType:
4650                {
4651                   FreeExpContents(exp);
4652
4653                   exp.constant = PrintFloat(*(float*)ptr);
4654                   exp.type = constantExp;
4655                   break;
4656                }
4657                case doubleType:
4658                {
4659                   FreeExpContents(exp);
4660
4661                   exp.constant = PrintDouble(*(double*)ptr);
4662                   exp.type = constantExp;
4663                   break;
4664                }
4665                case intType:
4666                {
4667                   FreeExpContents(exp);
4668
4669                   exp.constant = PrintInt(*(int*)ptr);
4670                   exp.type = constantExp;
4671                   break;
4672                }
4673                case int64Type:
4674                {
4675                   FreeExpContents(exp);
4676
4677                   exp.constant = PrintInt64(*(int64*)ptr);
4678                   exp.type = constantExp;
4679                   break;
4680                }
4681                case intPtrType:
4682                {
4683                   FreeExpContents(exp);
4684                   // TODO: This should probably use proper type
4685                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4686                   exp.type = constantExp;
4687                   break;
4688                }
4689                case intSizeType:
4690                {
4691                   FreeExpContents(exp);
4692                   // TODO: This should probably use proper type
4693                   exp.constant = PrintInt64((int64)*(intsize*)ptr);
4694                   exp.type = constantExp;
4695                   break;
4696                }
4697                default:
4698                   Compiler_Error($"Unhandled type populating instance\n");
4699             }
4700          }
4701          ListAdd(memberList, member);
4702       }
4703
4704       if(parentDataMember.type == unionMember)
4705          break;
4706    }
4707 }
4708
4709 void PopulateInstance(Instantiation inst)
4710 {
4711    Symbol classSym = inst._class.symbol; // FindClass(inst._class.name);
4712    Class _class = classSym.registered;
4713    DataMember dataMember;
4714    OldList * memberList = MkList();
4715    // Added this check and ->Add to prevent memory leaks on bad code
4716    if(!inst.members)
4717       inst.members = MkListOne(MkMembersInitList(memberList));
4718    else
4719       inst.members->Add(MkMembersInitList(memberList));
4720    for(dataMember = _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
4721    {
4722       if(!dataMember.isProperty)
4723       {
4724          if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4725             PopulateInstanceProcessMember(inst, memberList, dataMember, dataMember.offset);
4726          else
4727          {
4728             Expression exp { };
4729             MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4730             Type type;
4731             void * ptr = inst.data + dataMember.offset;
4732             char * result = null;
4733
4734             exp.loc = member.loc = inst.loc;
4735             ((Identifier)member.identifiers->first).loc = inst.loc;
4736
4737             if(!dataMember.dataType)
4738                dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4739             type = dataMember.dataType;
4740             if(type.kind == classType)
4741             {
4742                Class _class = type._class.registered;
4743                if(_class.type == enumClass)
4744                {
4745                   Class enumClass = eSystem_FindClass(privateModule, "enum");
4746                   if(enumClass)
4747                   {
4748                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4749                      NamedLink64 item;
4750                      for(item = e.values.first; item; item = item.next)
4751                      {
4752                         if(item.data == GetEnumValue(_class, ptr))
4753                         {
4754                            result = item.name;
4755                            break;
4756                         }
4757                      }
4758                   }
4759                   if(result)
4760                   {
4761                      exp.identifier = MkIdentifier(result);
4762                      exp.type = identifierExp;
4763                      exp.destType = MkClassType(_class.fullName);
4764                      ProcessExpressionType(exp);
4765                   }
4766                }
4767                if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4768                {
4769                   if(!_class.dataType)
4770                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4771                   type = _class.dataType;
4772                }
4773             }
4774             if(!result)
4775             {
4776                switch(type.kind)
4777                {
4778                   case floatType:
4779                   {
4780                      exp.constant = PrintFloat(*(float*)ptr);
4781                      exp.type = constantExp;
4782                      break;
4783                   }
4784                   case doubleType:
4785                   {
4786                      exp.constant = PrintDouble(*(double*)ptr);
4787                      exp.type = constantExp;
4788                      break;
4789                   }
4790                   case intType:
4791                   {
4792                      exp.constant = PrintInt(*(int*)ptr);
4793                      exp.type = constantExp;
4794                      break;
4795                   }
4796                   case int64Type:
4797                   {
4798                      exp.constant = PrintInt64(*(int64*)ptr);
4799                      exp.type = constantExp;
4800                      break;
4801                   }
4802                   case intPtrType:
4803                   {
4804                      exp.constant = PrintInt64((int64)*(intptr*)ptr);
4805                      exp.type = constantExp;
4806                      break;
4807                   }
4808                   default:
4809                      Compiler_Error($"Unhandled type populating instance\n");
4810                }
4811             }
4812             ListAdd(memberList, member);
4813          }
4814       }
4815    }
4816 }
4817
4818 void ComputeInstantiation(Expression exp)
4819 {
4820    Instantiation inst = exp.instance;
4821    MembersInit members;
4822    Symbol classSym = inst._class ? inst._class.symbol : null; // FindClass(inst._class.name);
4823    Class _class = classSym ? classSym.registered : null;
4824    DataMember curMember = null;
4825    Class curClass = null;
4826    DataMember subMemberStack[256];
4827    int subMemberStackPos = 0;
4828    uint64 bits = 0;
4829
4830    if(_class && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass ))
4831    {
4832       // Don't recompute the instantiation...
4833       // Non Simple classes will have become constants by now
4834       if(inst.data)
4835          return;
4836
4837       if(_class.type == normalClass || _class.type == noHeadClass)
4838       {
4839          inst.data = (byte *)eInstance_New(_class);
4840          if(_class.type == normalClass)
4841             ((Instance)inst.data)._refCount++;
4842       }
4843       else
4844          inst.data = new0 byte[_class.structSize];
4845    }
4846
4847    if(inst.members)
4848    {
4849       for(members = inst.members->first; members; members = members.next)
4850       {
4851          switch(members.type)
4852          {
4853             case dataMembersInit:
4854             {
4855                if(members.dataMembers)
4856                {
4857                   MemberInit member;
4858                   for(member = members.dataMembers->first; member; member = member.next)
4859                   {
4860                      Identifier ident = member.identifiers ? member.identifiers->first : null;
4861                      bool found = false;
4862
4863                      Property prop = null;
4864                      DataMember dataMember = null;
4865                      uint dataMemberOffset;
4866
4867                      if(!ident)
4868                      {
4869                         eClass_FindNextMember(_class, &curClass, &curMember, subMemberStack, &subMemberStackPos);
4870                         if(curMember)
4871                         {
4872                            if(curMember.isProperty)
4873                               prop = (Property)curMember;
4874                            else
4875                            {
4876                               dataMember = curMember;
4877
4878                               // CHANGED THIS HERE
4879                               eClass_FindDataMemberAndOffset(_class, dataMember.name, &dataMemberOffset, privateModule, null, null);
4880
4881                               // 2013/17/29 -- It seems that this was missing here!
4882                               if(_class.type == normalClass)
4883                                  dataMemberOffset += _class.base.structSize;
4884                               // dataMemberOffset = dataMember.offset;
4885                            }
4886                            found = true;
4887                         }
4888                      }
4889                      else
4890                      {
4891                         prop = eClass_FindProperty(_class, ident.string, privateModule);
4892                         if(prop)
4893                         {
4894                            found = true;
4895                            if(prop.memberAccess == publicAccess)
4896                            {
4897                               curMember = (DataMember)prop;
4898                               curClass = prop._class;
4899                            }
4900                         }
4901                         else
4902                         {
4903                            DataMember _subMemberStack[256];
4904                            int _subMemberStackPos = 0;
4905
4906                            // FILL MEMBER STACK
4907                            dataMember = eClass_FindDataMemberAndOffset(_class, ident.string, &dataMemberOffset, privateModule, _subMemberStack, &_subMemberStackPos);
4908
4909                            if(dataMember)
4910                            {
4911                               found = true;
4912                               if(dataMember.memberAccess == publicAccess)
4913                               {
4914                                  curMember = dataMember;
4915                                  curClass = dataMember._class;
4916                                  memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
4917                                  subMemberStackPos = _subMemberStackPos;
4918                               }
4919                            }
4920                         }
4921                      }
4922
4923                      if(found && member.initializer && member.initializer.type == expInitializer)
4924                      {
4925                         Expression value = member.initializer.exp;
4926                         Type type = null;
4927                         bool deepMember = false;
4928                         if(prop)
4929                         {
4930                            type = prop.dataType;
4931                         }
4932                         else if(dataMember)
4933                         {
4934                            if(!dataMember.dataType)
4935                               dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4936
4937                            type = dataMember.dataType;
4938                         }
4939
4940                         if(ident && ident.next)
4941                         {
4942                            deepMember = true;
4943
4944                            // for(; ident && type; ident = ident.next)
4945                            for(ident = ident.next; ident && type; ident = ident.next)
4946                            {
4947                               if(type.kind == classType)
4948                               {
4949                                  prop = eClass_FindProperty(type._class.registered,
4950                                     ident.string, privateModule);
4951                                  if(prop)
4952                                     type = prop.dataType;
4953                                  else
4954                                  {
4955                                     dataMember = eClass_FindDataMemberAndOffset(type._class.registered,
4956                                        ident.string, &dataMemberOffset, privateModule, null, null);
4957                                     if(dataMember)
4958                                        type = dataMember.dataType;
4959                                  }
4960                               }
4961                               else if(type.kind == structType || type.kind == unionType)
4962                               {
4963                                  Type memberType;
4964                                  for(memberType = type.members.first; memberType; memberType = memberType.next)
4965                                  {
4966                                     if(!strcmp(memberType.name, ident.string))
4967                                     {
4968                                        type = memberType;
4969                                        break;
4970                                     }
4971                                  }
4972                               }
4973                            }
4974                         }
4975                         if(value)
4976                         {
4977                            FreeType(value.destType);
4978                            value.destType = type;
4979                            if(type) type.refCount++;
4980                            ComputeExpression(value);
4981                         }
4982                         if(!deepMember && type && value && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass /*&& value.expType.kind == type.kind*/))
4983                         {
4984                            if(type.kind == classType)
4985                            {
4986                               Class _class = type._class.registered;
4987                               if(_class && (_class.type == bitClass || _class.type == unitClass || _class.type == enumClass))
4988                               {
4989                                  if(!_class.dataType)
4990                                     _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4991                                  type = _class.dataType;
4992                               }
4993                            }
4994
4995                            if(dataMember)
4996                            {
4997                               void * ptr = inst.data + dataMemberOffset;
4998
4999                               if(value.type == constantExp)
5000                               {
5001                                  switch(type.kind)
5002                                  {
5003                                     case intType:
5004                                     {
5005                                        GetInt(value, (int*)ptr);
5006                                        break;
5007                                     }
5008                                     case int64Type:
5009                                     {
5010                                        GetInt64(value, (int64*)ptr);
5011                                        break;
5012                                     }
5013                                     case intPtrType:
5014                                     {
5015                                        GetIntPtr(value, (intptr*)ptr);
5016                                        break;
5017                                     }
5018                                     case intSizeType:
5019                                     {
5020                                        GetIntSize(value, (intsize*)ptr);
5021                                        break;
5022                                     }
5023                                     case floatType:
5024                                     {
5025                                        GetFloat(value, (float*)ptr);
5026                                        break;
5027                                     }
5028                                     case doubleType:
5029                                     {
5030                                        GetDouble(value, (double *)ptr);
5031                                        break;
5032                                     }
5033                                  }
5034                               }
5035                               else if(value.type == instanceExp)
5036                               {
5037                                  if(type.kind == classType)
5038                                  {
5039                                     Class _class = type._class.registered;
5040                                     if(_class.type == structClass)
5041                                     {
5042                                        ComputeTypeSize(type);
5043                                        if(value.instance.data)
5044                                           memcpy(ptr, value.instance.data, type.size);
5045                                     }
5046                                  }
5047                               }
5048                            }
5049                            else if(prop && prop.Set != (void *)(intptr)1)
5050                            {
5051                               if(value.type == instanceExp && value.instance.data)
5052                               {
5053                                  if(type.kind == classType)
5054                                  {
5055                                     Class _class = type._class.registered;
5056                                     if(_class && (_class.type != normalClass || eClass_IsDerived(((Instance)value.instance.data)._class, _class)))
5057                                     {
5058                                        void (*Set)(void *, void *) = (void *)prop.Set;
5059                                        Set(inst.data, value.instance.data);
5060                                        PopulateInstance(inst);
5061                                     }
5062                                  }
5063                               }
5064                               else if(value.type == constantExp)
5065                               {
5066                                  switch(type.kind)
5067                                  {
5068                                     case doubleType:
5069                                     {
5070                                        void (*Set)(void *, double) = (void *)prop.Set;
5071                                        Set(inst.data, strtod(value.constant, null) );
5072                                        break;
5073                                     }
5074                                     case floatType:
5075                                     {
5076                                        void (*Set)(void *, float) = (void *)prop.Set;
5077                                        Set(inst.data, (float)(strtod(value.constant, null)));
5078                                        break;
5079                                     }
5080                                     case intType:
5081                                     {
5082                                        void (*Set)(void *, int) = (void *)prop.Set;
5083                                        Set(inst.data, (int)strtol(value.constant, null, 0));
5084                                        break;
5085                                     }
5086                                     case int64Type:
5087                                     {
5088                                        void (*Set)(void *, int64) = (void *)prop.Set;
5089                                        Set(inst.data, _strtoi64(value.constant, null, 0));
5090                                        break;
5091                                     }
5092                                     case intPtrType:
5093                                     {
5094                                        void (*Set)(void *, intptr) = (void *)prop.Set;
5095                                        Set(inst.data, (intptr)_strtoi64(value.constant, null, 0));
5096                                        break;
5097                                     }
5098                                     case intSizeType:
5099                                     {
5100                                        void (*Set)(void *, intsize) = (void *)prop.Set;
5101                                        Set(inst.data, (intsize)_strtoi64(value.constant, null, 0));
5102                                        break;
5103                                     }
5104                                  }
5105                               }
5106                               else if(value.type == stringExp)
5107                               {
5108                                  char temp[1024];
5109                                  ReadString(temp, value.string);
5110                                  ((void (*)(void *, void *))(void *)prop.Set)(inst.data, temp);
5111                               }
5112                            }
5113                         }
5114                         else if(!deepMember && type && _class.type == unitClass)
5115                         {
5116                            if(prop)
5117                            {
5118                               // Only support converting units to units for now...
5119                               if(value.type == constantExp)
5120                               {
5121                                  if(type.kind == classType)
5122                                  {
5123                                     Class _class = type._class.registered;
5124                                     if(_class.type == unitClass)
5125                                     {
5126                                        if(!_class.dataType)
5127                                           _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5128                                        type = _class.dataType;
5129                                     }
5130                                  }
5131                                  // TODO: Assuming same base type for units...
5132                                  switch(type.kind)
5133                                  {
5134                                     case floatType:
5135                                     {
5136                                        float fValue;
5137                                        float (*Set)(float) = (void *)prop.Set;
5138                                        GetFloat(member.initializer.exp, &fValue);
5139                                        exp.constant = PrintFloat(Set(fValue));
5140                                        exp.type = constantExp;
5141                                        break;
5142                                     }
5143                                     case doubleType:
5144                                     {
5145                                        double dValue;
5146                                        double (*Set)(double) = (void *)prop.Set;
5147                                        GetDouble(member.initializer.exp, &dValue);
5148                                        exp.constant = PrintDouble(Set(dValue));
5149                                        exp.type = constantExp;
5150                                        break;
5151                                     }
5152                                  }
5153                               }
5154                            }
5155                         }
5156                         else if(!deepMember && type && _class.type == bitClass)
5157                         {
5158                            if(prop)
5159                            {
5160                               if(value.type == instanceExp && value.instance.data)
5161                               {
5162                                  unsigned int (*Set)(void *) = (void *)prop.Set;
5163                                  bits = Set(value.instance.data);
5164                               }
5165                               else if(value.type == constantExp)
5166                               {
5167                               }
5168                            }
5169                            else if(dataMember)
5170                            {
5171                               BitMember bitMember = (BitMember) dataMember;
5172                               Type type;
5173                               uint64 part = 0;
5174                               bits = (bits & ~bitMember.mask);
5175                               if(!bitMember.dataType)
5176                                  bitMember.dataType = ProcessTypeString(bitMember.dataTypeString, false);
5177                               type = bitMember.dataType;
5178                               if(type.kind == classType && type._class && type._class.registered)
5179                               {
5180                                  if(!type._class.registered.dataType)
5181                                     type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
5182                                  type = type._class.registered.dataType;
5183                               }
5184                               switch(type.kind)
5185                               {
5186                                  case _BoolType:
5187                                  case charType:       { byte v; type.isSigned ? GetChar(value, (char *)&v) : GetUChar(value, &v); part = (uint64)v; break; }
5188                                  case shortType:      { uint16 v; type.isSigned ? GetShort(value, (short *)&v) : GetUShort(value, &v); part = (uint64)v; break; }
5189                                  case intType:
5190                                  case longType:       { uint v; type.isSigned ? GetInt(value, (int *)&v) : GetUInt(value, &v); part = (uint64)v; break; }
5191                                  case int64Type:      { uint64 v; type.isSigned ? GetInt64(value, (int64 *)&v) : GetUInt64(value, &v); part = (uint64)v; break; }
5192                                  case intPtrType:     { uintptr v; type.isSigned ? GetIntPtr(value, (intptr *)&v) : GetUIntPtr(value, &v); part = (uint64)v; break; }
5193                                  case intSizeType:    { uintsize v; type.isSigned ? GetIntSize(value, (intsize *)&v) : GetUIntSize(value, &v); part = (uint64)v; break; }
5194                               }
5195                               bits |= part << bitMember.pos;
5196                            }
5197                         }
5198                      }
5199                      else
5200                      {
5201                         if(_class && _class.type == unitClass)
5202                         {
5203                            ComputeExpression(member.initializer.exp);
5204                            exp.constant = member.initializer.exp.constant;
5205                            exp.type = constantExp;
5206
5207                            member.initializer.exp.constant = null;
5208                         }
5209                      }
5210                   }
5211                }
5212                break;
5213             }
5214          }
5215       }
5216    }
5217    if(_class && _class.type == bitClass)
5218    {
5219       exp.constant = PrintHexUInt(bits);
5220       exp.type = constantExp;
5221    }
5222    if(exp.type != instanceExp)
5223    {
5224       FreeInstance(inst);
5225    }
5226 }
5227
5228 static bool Promote(Operand op, TypeKind kind, bool isSigned)
5229 {
5230    bool result = false;
5231    switch(kind)
5232    {
5233       case shortType:
5234          if(op.kind == charType || op.kind == enumType || op.kind == _BoolType)
5235             result = isSigned ? GetOpShort(op, &op.s) : GetOpUShort(op, &op.us);
5236          break;
5237       case intType:
5238       case longType:
5239          if(op.kind == charType || op.kind == shortType || op.kind == enumType || op.kind == _BoolType)
5240             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5241          break;
5242       case int64Type:
5243          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5244             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5245             result = isSigned ? GetOpInt64(op, &op.i64) : GetOpUInt64(op, &op.ui64);
5246          break;
5247       case floatType:
5248          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType ||
5249             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5250             result = GetOpFloat(op, &op.f);
5251          break;
5252       case doubleType:
5253          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType ||
5254             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5255             result = GetOpDouble(op, &op.d);
5256          break;
5257       case pointerType:
5258          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5259             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5260             result = GetOpUInt64 /*GetOpUIntPtr*/(op, &op.ui64);
5261          break;
5262       case enumType:
5263          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5264             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5265             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5266          break;
5267       case intPtrType:
5268          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5269             result = isSigned ? GetOpInt64 /*GetOpIntPtr*/(op, &op.i64) : GetOpUInt64 /*GetOpUIntPtr*/(op, &op.ui64);
5270          break;
5271       case intSizeType:
5272          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5273             result = isSigned ? GetOpInt64 /*GetOpIntSize*/(op, &op.i64) : GetOpUInt64 /*GetOpUIntSize*/(op, &op.ui64);
5274          break;
5275    }
5276    return result;
5277 }
5278
5279 void CallOperator(Expression exp, Expression exp1, Expression exp2, Operand op1, Operand op2)
5280 {
5281    if(exp.op.op == SIZEOF)
5282    {
5283       FreeExpContents(exp);
5284       exp.type = constantExp;
5285       exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5286    }
5287    else
5288    {
5289       if(!exp.op.exp1)
5290       {
5291          switch(exp.op.op)
5292          {
5293             // unary arithmetic
5294             case '+':
5295             {
5296                // Provide default unary +
5297                Expression exp2 = exp.op.exp2;
5298                exp.op.exp2 = null;
5299                FreeExpContents(exp);
5300                FreeType(exp.expType);
5301                FreeType(exp.destType);
5302                *exp = *exp2;
5303                delete exp2;
5304                break;
5305             }
5306             case '-':
5307                if(op1.ops.Neg) { FreeExpContents(exp); op1.ops.Neg(exp, op1); }
5308                break;
5309             // unary arithmetic increment and decrement
5310                   //OPERATOR_ALL(UNARY, ++, Inc)
5311                   //OPERATOR_ALL(UNARY, --, Dec)
5312             // unary bitwise
5313             case '~':
5314                if(op1.ops.BitNot) { FreeExpContents(exp); op1.ops.BitNot(exp, op1); }
5315                break;
5316             // unary logical negation
5317             case '!':
5318                if(op1.ops.Not) { FreeExpContents(exp); op1.ops.Not(exp, op1); }
5319                break;
5320          }
5321       }
5322       else
5323       {
5324          if(op1 && op2 && op1.type && op2.type && op1.kind != op2.kind)
5325          {
5326             if(Promote(op2, op1.kind, op1.type.isSigned))
5327                op2.kind = op1.kind, op2.ops = op1.ops;
5328             else if(Promote(op1, op2.kind, op2.type.isSigned))
5329                op1.kind = op2.kind, op1.ops = op2.ops;
5330          }
5331          switch(exp.op.op)
5332          {
5333             // binary arithmetic
5334             case '+':
5335                if(op1.ops.Add) { FreeExpContents(exp); op1.ops.Add(exp, op1, op2); }
5336                break;
5337             case '-':
5338                if(op1.ops.Sub) { FreeExpContents(exp); op1.ops.Sub(exp, op1, op2); }
5339                break;
5340             case '*':
5341                if(op1.ops.Mul) { FreeExpContents(exp); op1.ops.Mul(exp, op1, op2); }
5342                break;
5343             case '/':
5344                if(op1.ops.Div) { FreeExpContents(exp); op1.ops.Div(exp, op1, op2); }
5345                break;
5346             case '%':
5347                if(op1.ops.Mod) { FreeExpContents(exp); op1.ops.Mod(exp, op1, op2); }
5348                break;
5349             // binary arithmetic assignment
5350                   //OPERATOR_ALL(BINARY, =, Asign)
5351                   //OPERATOR_ALL(BINARY, +=, AddAsign)
5352                   //OPERATOR_ALL(BINARY, -=, SubAsign)
5353                   //OPERATOR_ALL(BINARY, *=, MulAsign)
5354                   //OPERATOR_ALL(BINARY, /=, DivAsign)
5355                   //OPERATOR_ALL(BINARY, %=, ModAsign)
5356             // binary bitwise
5357             case '&':
5358                if(exp.op.exp2)
5359                {
5360                   if(op1.ops.BitAnd) { FreeExpContents(exp); op1.ops.BitAnd(exp, op1, op2); }
5361                }
5362                break;
5363             case '|':
5364                if(op1.ops.BitOr) { FreeExpContents(exp); op1.ops.BitOr(exp, op1, op2); }
5365                break;
5366             case '^':
5367                if(op1.ops.BitXor) { FreeExpContents(exp); op1.ops.BitXor(exp, op1, op2); }
5368                break;
5369             case LEFT_OP:
5370                if(op1.ops.LShift) { FreeExpContents(exp); op1.ops.LShift(exp, op1, op2); }
5371                break;
5372             case RIGHT_OP:
5373                if(op1.ops.RShift) { FreeExpContents(exp); op1.ops.RShift(exp, op1, op2); }
5374                break;
5375             // binary bitwise assignment
5376                   //OPERATOR_INTTYPES(BINARY, &=, AndAsign)
5377                   //OPERATOR_INTTYPES(BINARY, |=, OrAsign)
5378                   //OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
5379                   //OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
5380                   //OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
5381             // binary logical equality
5382             case EQ_OP:
5383                if(op1.ops.Equ) { FreeExpContents(exp); op1.ops.Equ(exp, op1, op2); }
5384                break;
5385             case NE_OP:
5386                if(op1.ops.Nqu) { FreeExpContents(exp); op1.ops.Nqu(exp, op1, op2); }
5387                break;
5388             // binary logical
5389             case AND_OP:
5390                if(op1.ops.And) { FreeExpContents(exp); op1.ops.And(exp, op1, op2); }
5391                break;
5392             case OR_OP:
5393                if(op1.ops.Or) { FreeExpContents(exp); op1.ops.Or(exp, op1, op2); }
5394                break;
5395             // binary logical relational
5396             case '>':
5397                if(op1.ops.Grt) { FreeExpContents(exp); op1.ops.Grt(exp, op1, op2); }
5398                break;
5399             case '<':
5400                if(op1.ops.Sma) { FreeExpContents(exp); op1.ops.Sma(exp, op1, op2); }
5401                break;
5402             case GE_OP:
5403                if(op1.ops.GrtEqu) { FreeExpContents(exp); op1.ops.GrtEqu(exp, op1, op2); }
5404                break;
5405             case LE_OP:
5406                if(op1.ops.SmaEqu) { FreeExpContents(exp); op1.ops.SmaEqu(exp, op1, op2); }
5407                break;
5408          }
5409       }
5410    }
5411 }
5412
5413 void ComputeExpression(Expression exp)
5414 {
5415 #ifdef _DEBUG
5416    char expString[10240];
5417    expString[0] = '\0';
5418    PrintExpression(exp, expString);
5419 #endif
5420
5421    switch(exp.type)
5422    {
5423       case identifierExp:
5424       {
5425          Identifier id = exp.identifier;
5426          if(id && exp.isConstant && !inCompiler && !inPreCompiler && !inDebugger)
5427          {
5428             Class c = (exp.expType && exp.expType.kind == classType && exp.expType._class) ? exp.expType._class.registered : null;
5429             if(c && c.type == enumClass)
5430             {
5431                Class enumClass = eSystem_FindClass(privateModule, "enum");
5432                if(enumClass)
5433                {
5434                   NamedLink64 value;
5435                   EnumClassData e = ACCESS_CLASSDATA(c, enumClass);
5436                   for(value = e.values.first; value; value = value.next)
5437                   {
5438                      if(!strcmp(value.name, id.string))
5439                         break;
5440                   }
5441                   if(value)
5442                   {
5443                      const String dts = c.dataTypeString;
5444                      FreeExpContents(exp);
5445                      exp.type = constantExp;
5446                      exp.constant = (dts && (!strcmp(dts, "int") || !strcmp(dts, "int64") || !strcmp(dts, "short") || !strcmp(dts, "char"))) ? PrintInt64(value.data) : PrintUInt64(value.data);
5447                   }
5448                }
5449             }
5450          }
5451          break;
5452       }
5453       case instanceExp:
5454       {
5455          ComputeInstantiation(exp);
5456          break;
5457       }
5458       /*
5459       case constantExp:
5460          break;
5461       */
5462       case opExp:
5463       {
5464          Expression exp1, exp2 = null;
5465          Operand op1 { };
5466          Operand op2 { };
5467
5468          // We don't care about operations with only exp2 (INC_OP, DEC_OP...)
5469          if(exp.op.exp2)
5470          {
5471             Expression e = exp.op.exp2;
5472
5473             while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
5474             {
5475                if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
5476                {
5477                   if(e.type == extensionCompoundExp)
5478                      e = ((Statement)e.compound.compound.statements->last).expressions->last;
5479                   else
5480                      e = e.list->last;
5481                }
5482             }
5483             if(exp.op.op == TokenType::sizeOf && e && e.expType)
5484             {
5485                if(e.type == stringExp && e.string)
5486                {
5487                   char * string = e.string;
5488                   int len = strlen(string);
5489                   char * tmp = new char[len-2+1];
5490                   len = UnescapeString(tmp, string + 1, len - 2);
5491                   delete tmp;
5492                   FreeExpContents(exp);
5493                   exp.type = constantExp;
5494                   exp.constant = PrintUInt(len + 1);
5495                }
5496                else
5497                {
5498                   Type type = e.expType;
5499                   type.refCount++;
5500                   FreeExpContents(exp);
5501                   exp.type = constantExp;
5502                   exp.constant = PrintUInt(ComputeTypeSize(type));
5503                   FreeType(type);
5504                }
5505                break;
5506             }
5507             else
5508                ComputeExpression(exp.op.exp2);
5509          }
5510          if(exp.op.exp1)
5511          {
5512             ComputeExpression(exp.op.exp1);
5513             exp1 = exp.op.exp1;
5514             exp2 = exp.op.exp2;
5515             op1 = GetOperand(exp1);
5516             if(op1.type) op1.type.refCount++;
5517             if(exp2)
5518             {
5519                op2 = GetOperand(exp2);
5520                if(op2.type) op2.type.refCount++;
5521             }
5522          }
5523          else
5524          {
5525             exp1 = exp.op.exp2;
5526             op1 = GetOperand(exp1);
5527             if(op1.type) op1.type.refCount++;
5528          }
5529
5530          CallOperator(exp, exp1, exp2, op1, op2);
5531          /*
5532          switch(exp.op.op)
5533          {
5534             // Unary operators
5535             case '&':
5536                // Also binary
5537                if(exp.op.exp1 && exp.op.exp2)
5538                {
5539                   // Binary And
5540                   if(op1.ops.BitAnd)
5541                   {
5542                      FreeExpContents(exp);
5543                      op1.ops.BitAnd(exp, op1, op2);
5544                   }
5545                }
5546                break;
5547             case '*':
5548                if(exp.op.exp1)
5549                {
5550                   if(op1.ops.Mul)
5551                   {
5552                      FreeExpContents(exp);
5553                      op1.ops.Mul(exp, op1, op2);
5554                   }
5555                }
5556                break;
5557             case '+':
5558                if(exp.op.exp1)
5559                {
5560                   if(op1.ops.Add)
5561                   {
5562                      FreeExpContents(exp);
5563                      op1.ops.Add(exp, op1, op2);
5564                   }
5565                }
5566                else
5567                {
5568                   // Provide default unary +
5569                   Expression exp2 = exp.op.exp2;
5570                   exp.op.exp2 = null;
5571                   FreeExpContents(exp);
5572                   FreeType(exp.expType);
5573                   FreeType(exp.destType);
5574
5575                   *exp = *exp2;
5576                   delete exp2;
5577                }
5578                break;
5579             case '-':
5580                if(exp.op.exp1)
5581                {
5582                   if(op1.ops.Sub)
5583                   {
5584                      FreeExpContents(exp);
5585                      op1.ops.Sub(exp, op1, op2);
5586                   }
5587                }
5588                else
5589                {
5590                   if(op1.ops.Neg)
5591                   {
5592                      FreeExpContents(exp);
5593                      op1.ops.Neg(exp, op1);
5594                   }
5595                }
5596                break;
5597             case '~':
5598                if(op1.ops.BitNot)
5599                {
5600                   FreeExpContents(exp);
5601                   op1.ops.BitNot(exp, op1);
5602                }
5603                break;
5604             case '!':
5605                if(op1.ops.Not)
5606                {
5607                   FreeExpContents(exp);
5608                   op1.ops.Not(exp, op1);
5609                }
5610                break;
5611             // Binary only operators
5612             case '/':
5613                if(op1.ops.Div)
5614                {
5615                   FreeExpContents(exp);
5616                   op1.ops.Div(exp, op1, op2);
5617                }
5618                break;
5619             case '%':
5620                if(op1.ops.Mod)
5621                {
5622                   FreeExpContents(exp);
5623                   op1.ops.Mod(exp, op1, op2);
5624                }
5625                break;
5626             case LEFT_OP:
5627                break;
5628             case RIGHT_OP:
5629                break;
5630             case '<':
5631                if(exp.op.exp1)
5632                {
5633                   if(op1.ops.Sma)
5634                   {
5635                      FreeExpContents(exp);
5636                      op1.ops.Sma(exp, op1, op2);
5637                   }
5638                }
5639                break;
5640             case '>':
5641                if(exp.op.exp1)
5642                {
5643                   if(op1.ops.Grt)
5644                   {
5645                      FreeExpContents(exp);
5646                      op1.ops.Grt(exp, op1, op2);
5647                   }
5648                }
5649                break;
5650             case LE_OP:
5651                if(exp.op.exp1)
5652                {
5653                   if(op1.ops.SmaEqu)
5654                   {
5655                      FreeExpContents(exp);
5656                      op1.ops.SmaEqu(exp, op1, op2);
5657                   }
5658                }
5659                break;
5660             case GE_OP:
5661                if(exp.op.exp1)
5662                {
5663                   if(op1.ops.GrtEqu)
5664                   {
5665                      FreeExpContents(exp);
5666                      op1.ops.GrtEqu(exp, op1, op2);
5667                   }
5668                }
5669                break;
5670             case EQ_OP:
5671                if(exp.op.exp1)
5672                {
5673                   if(op1.ops.Equ)
5674                   {
5675                      FreeExpContents(exp);
5676                      op1.ops.Equ(exp, op1, op2);
5677                   }
5678                }
5679                break;
5680             case NE_OP:
5681                if(exp.op.exp1)
5682                {
5683                   if(op1.ops.Nqu)
5684                   {
5685                      FreeExpContents(exp);
5686                      op1.ops.Nqu(exp, op1, op2);
5687                   }
5688                }
5689                break;
5690             case '|':
5691                if(op1.ops.BitOr)
5692                {
5693                   FreeExpContents(exp);
5694                   op1.ops.BitOr(exp, op1, op2);
5695                }
5696                break;
5697             case '^':
5698                if(op1.ops.BitXor)
5699                {
5700                   FreeExpContents(exp);
5701                   op1.ops.BitXor(exp, op1, op2);
5702                }
5703                break;
5704             case AND_OP:
5705                break;
5706             case OR_OP:
5707                break;
5708             case SIZEOF:
5709                FreeExpContents(exp);
5710                exp.type = constantExp;
5711                exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5712                break;
5713          }
5714          */
5715          if(op1.type) FreeType(op1.type);
5716          if(op2.type) FreeType(op2.type);
5717          break;
5718       }
5719       case bracketsExp:
5720       case extensionExpressionExp:
5721       {
5722          Expression e, n;
5723          for(e = exp.list->first; e; e = n)
5724          {
5725             n = e.next;
5726             if(!n)
5727             {
5728                OldList * list = exp.list;
5729                Expression prev = exp.prev;
5730                Expression next = exp.next;
5731
5732                // For operations which set the exp type on brackets exp after the inner exp was processed...
5733                if(exp.expType && exp.expType.kind == classType && (!e.expType || e.expType.kind != classType))
5734                {
5735                   FreeType(e.expType);
5736                   e.expType = exp.expType;
5737                   e.expType.refCount++;
5738                }
5739                ComputeExpression(e);
5740                //FreeExpContents(exp);
5741                FreeType(exp.expType);
5742                FreeType(exp.destType);
5743                *exp = *e;
5744                exp.prev = prev;
5745                exp.next = next;
5746                delete e;
5747                delete list;
5748             }
5749             else
5750             {
5751                FreeExpression(e);
5752             }
5753          }
5754          break;
5755       }
5756       /*
5757
5758       case ExpIndex:
5759       {
5760          Expression e;
5761          exp.isConstant = true;
5762
5763          ComputeExpression(exp.index.exp);
5764          if(!exp.index.exp.isConstant)
5765             exp.isConstant = false;
5766
5767          for(e = exp.index.index->first; e; e = e.next)
5768          {
5769             ComputeExpression(e);
5770             if(!e.next)
5771             {
5772                // Check if this type is int
5773             }
5774             if(!e.isConstant)
5775                exp.isConstant = false;
5776          }
5777          exp.expType = Dereference(exp.index.exp.expType);
5778          break;
5779       }
5780       */
5781       case memberExp:
5782       {
5783          Expression memberExp = exp.member.exp;
5784          Identifier memberID = exp.member.member;
5785
5786          Type type;
5787          ComputeExpression(exp.member.exp);
5788          type = exp.member.exp.expType;
5789          if(type)
5790          {
5791             Class _class = (exp.member.member && exp.member.member.classSym) ? exp.member.member.classSym.registered : (((type.kind == classType || type.kind == subClassType) && type._class) ? type._class.registered : null);
5792             Property prop = null;
5793             DataMember member = null;
5794             Class convertTo = null;
5795             if(type.kind == subClassType && exp.member.exp.type == classExp)
5796                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
5797
5798             if(!_class)
5799             {
5800                char string[256];
5801                Symbol classSym;
5802                string[0] = '\0';
5803                PrintTypeNoConst(type, string, false, true);
5804                classSym = FindClass(string);
5805                _class = classSym ? classSym.registered : null;
5806             }
5807
5808             if(exp.member.member)
5809             {
5810                prop = eClass_FindProperty(_class, exp.member.member.string, privateModule);
5811                if(!prop)
5812                   member = eClass_FindDataMember(_class, exp.member.member.string, privateModule, null, null);
5813             }
5814             if(!prop && !member && _class && exp.member.member)
5815             {
5816                Symbol classSym = FindClass(exp.member.member.string);
5817                convertTo = _class;
5818                _class = classSym ? classSym.registered : null;
5819                prop = eClass_FindProperty(_class, convertTo.fullName, privateModule);
5820             }
5821
5822             if(prop)
5823             {
5824                if(prop.compiled)
5825                {
5826                   Type type = prop.dataType;
5827                   // TODO: Assuming same base type for units...
5828                   if(_class.type == unitClass)
5829                   {
5830                      if(type.kind == classType)
5831                      {
5832                         Class _class = type._class.registered;
5833                         if(_class.type == unitClass)
5834                         {
5835                            if(!_class.dataType)
5836                               _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5837                            type = _class.dataType;
5838                         }
5839                      }
5840                      switch(type.kind)
5841                      {
5842                         case floatType:
5843                         {
5844                            float value;
5845                            float (*Get)(float) = (void *)prop.Get;
5846                            GetFloat(exp.member.exp, &value);
5847                            exp.constant = PrintFloat(Get ? Get(value) : value);
5848                            exp.type = constantExp;
5849                            break;
5850                         }
5851                         case doubleType:
5852                         {
5853                            double value;
5854                            double (*Get)(double);
5855                            GetDouble(exp.member.exp, &value);
5856
5857                            if(convertTo)
5858                               Get = (void *)prop.Set;
5859                            else
5860                               Get = (void *)prop.Get;
5861                            exp.constant = PrintDouble(Get ? Get(value) : value);
5862                            exp.type = constantExp;
5863                            break;
5864                         }
5865                      }
5866                   }
5867                   else
5868                   {
5869                      if(convertTo)
5870                      {
5871                         Expression value = exp.member.exp;
5872                         Type type;
5873                         if(!prop.dataType)
5874                            ProcessPropertyType(prop);
5875
5876                         type = prop.dataType;
5877                         if(!type)
5878                         {
5879                             // printf("Investigate this\n");
5880                         }
5881                         else if(_class.type == structClass)
5882                         {
5883                            switch(type.kind)
5884                            {
5885                               case classType:
5886                               {
5887                                  Class propertyClass = type._class.registered;
5888                                  if(propertyClass.type == structClass && value.type == instanceExp)
5889                                  {
5890                                     void (*Set)(void *, void *) = (void *)prop.Set;
5891                                     exp.instance = Instantiation { };
5892                                     exp.instance.data = new0 byte[_class.structSize];
5893                                     exp.instance._class = MkSpecifierName(_class.fullName);
5894                                     exp.instance.loc = exp.loc;
5895                                     exp.type = instanceExp;
5896                                     Set(exp.instance.data, value.instance.data);
5897                                     PopulateInstance(exp.instance);
5898                                  }
5899                                  break;
5900                               }
5901                               case intType:
5902                               {
5903                                  int intValue;
5904                                  void (*Set)(void *, int) = (void *)prop.Set;
5905
5906                                  exp.instance = Instantiation { };
5907                                  exp.instance.data = new0 byte[_class.structSize];
5908                                  exp.instance._class = MkSpecifierName(_class.fullName);
5909                                  exp.instance.loc = exp.loc;
5910                                  exp.type = instanceExp;
5911
5912                                  GetInt(value, &intValue);
5913
5914                                  Set(exp.instance.data, intValue);
5915                                  PopulateInstance(exp.instance);
5916                                  break;
5917                               }
5918                               case int64Type:
5919                               {
5920                                  int64 intValue;
5921                                  void (*Set)(void *, int64) = (void *)prop.Set;
5922
5923                                  exp.instance = Instantiation { };
5924                                  exp.instance.data = new0 byte[_class.structSize];
5925                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5926                                  exp.instance.loc = exp.loc;
5927                                  exp.type = instanceExp;
5928
5929                                  GetInt64(value, &intValue);
5930
5931                                  Set(exp.instance.data, intValue);
5932                                  PopulateInstance(exp.instance);
5933                                  break;
5934                               }
5935                               case intPtrType:
5936                               {
5937                                  // TOFIX:
5938                                  intptr intValue;
5939                                  void (*Set)(void *, intptr) = (void *)prop.Set;
5940
5941                                  exp.instance = Instantiation { };
5942                                  exp.instance.data = new0 byte[_class.structSize];
5943                                  exp.instance._class = MkSpecifierName(_class.fullName);
5944                                  exp.instance.loc = exp.loc;
5945                                  exp.type = instanceExp;
5946
5947                                  GetIntPtr(value, &intValue);
5948
5949                                  Set(exp.instance.data, intValue);
5950                                  PopulateInstance(exp.instance);
5951                                  break;
5952                               }
5953                               case intSizeType:
5954                               {
5955                                  // TOFIX:
5956                                  intsize intValue;
5957                                  void (*Set)(void *, intsize) = (void *)prop.Set;
5958
5959                                  exp.instance = Instantiation { };
5960                                  exp.instance.data = new0 byte[_class.structSize];
5961                                  exp.instance._class = MkSpecifierName(_class.fullName);
5962                                  exp.instance.loc = exp.loc;
5963                                  exp.type = instanceExp;
5964
5965                                  GetIntSize(value, &intValue);
5966
5967                                  Set(exp.instance.data, intValue);
5968                                  PopulateInstance(exp.instance);
5969                                  break;
5970                               }
5971                               case floatType:
5972                               {
5973                                  float floatValue;
5974                                  void (*Set)(void *, float) = (void *)prop.Set;
5975
5976                                  exp.instance = Instantiation { };
5977                                  exp.instance.data = new0 byte[_class.structSize];
5978                                  exp.instance._class = MkSpecifierName(_class.fullName);
5979                                  exp.instance.loc = exp.loc;
5980                                  exp.type = instanceExp;
5981
5982                                  GetFloat(value, &floatValue);
5983
5984                                  Set(exp.instance.data, floatValue);
5985                                  PopulateInstance(exp.instance);
5986                                  break;
5987                               }
5988                               case doubleType:
5989                               {
5990                                  double doubleValue;
5991                                  void (*Set)(void *, double) = (void *)prop.Set;
5992
5993                                  exp.instance = Instantiation { };
5994                                  exp.instance.data = new0 byte[_class.structSize];
5995                                  exp.instance._class = MkSpecifierName(_class.fullName);
5996                                  exp.instance.loc = exp.loc;
5997                                  exp.type = instanceExp;
5998
5999                                  GetDouble(value, &doubleValue);
6000
6001                                  Set(exp.instance.data, doubleValue);
6002                                  PopulateInstance(exp.instance);
6003                                  break;
6004                               }
6005                            }
6006                         }
6007                         else if(_class.type == bitClass)
6008                         {
6009                            switch(type.kind)
6010                            {
6011                               case classType:
6012                               {
6013                                  Class propertyClass = type._class.registered;
6014                                  if(propertyClass.type == structClass && value.instance.data)
6015                                  {
6016                                     unsigned int (*Set)(void *) = (void *)prop.Set;
6017                                     unsigned int bits = Set(value.instance.data);
6018                                     exp.constant = PrintHexUInt(bits);
6019                                     exp.type = constantExp;
6020                                     break;
6021                                  }
6022                                  else if(_class.type == bitClass)
6023                                  {
6024                                     unsigned int value;
6025                                     unsigned int (*Set)(unsigned int) = (void *)prop.Set;
6026                                     unsigned int bits;
6027
6028                                     GetUInt(exp.member.exp, &value);
6029                                     bits = Set(value);
6030                                     exp.constant = PrintHexUInt(bits);
6031                                     exp.type = constantExp;
6032                                  }
6033                               }
6034                            }
6035                         }
6036                      }
6037                      else
6038                      {
6039                         if(_class.type == bitClass)
6040                         {
6041                            unsigned int value;
6042                            GetUInt(exp.member.exp, &value);
6043
6044                            switch(type.kind)
6045                            {
6046                               case classType:
6047                               {
6048                                  Class _class = type._class.registered;
6049                                  if(_class.type == structClass)
6050                                  {
6051                                     void (*Get)(unsigned int, void *) = (void *)prop.Get;
6052
6053                                     exp.instance = Instantiation { };
6054                                     exp.instance.data = new0 byte[_class.structSize];
6055                                     exp.instance._class = MkSpecifierName(_class.fullName);
6056                                     exp.instance.loc = exp.loc;
6057                                     //exp.instance.fullSet = true;
6058                                     exp.type = instanceExp;
6059                                     Get(value, exp.instance.data);
6060                                     PopulateInstance(exp.instance);
6061                                  }
6062                                  else if(_class.type == bitClass)
6063                                  {
6064                                     unsigned int (*Get)(unsigned int) = (void *)prop.Get;
6065                                     uint64 bits = Get(value);
6066                                     exp.constant = PrintHexUInt64(bits);
6067                                     exp.type = constantExp;
6068                                  }
6069                                  break;
6070                               }
6071                            }
6072                         }
6073                         else if(_class.type == structClass)
6074                         {
6075                            byte * value = (exp.member.exp.type == instanceExp ) ? exp.member.exp.instance.data : null;
6076                            switch(type.kind)
6077                            {
6078                               case classType:
6079                               {
6080                                  Class _class = type._class.registered;
6081                                  if(_class.type == structClass && value)
6082                                  {
6083                                     void (*Get)(void *, void *) = (void *)prop.Get;
6084
6085                                     exp.instance = Instantiation { };
6086                                     exp.instance.data = new0 byte[_class.structSize];
6087                                     exp.instance._class = MkSpecifierName(_class.fullName);
6088                                     exp.instance.loc = exp.loc;
6089                                     //exp.instance.fullSet = true;
6090                                     exp.type = instanceExp;
6091                                     Get(value, exp.instance.data);
6092                                     PopulateInstance(exp.instance);
6093                                  }
6094                                  break;
6095                               }
6096                            }
6097                         }
6098                         /*else
6099                         {
6100                            char * value = exp.member.exp.instance.data;
6101                            switch(type.kind)
6102                            {
6103                               case classType:
6104                               {
6105                                  Class _class = type._class.registered;
6106                                  if(_class.type == normalClass)
6107                                  {
6108                                     void *(*Get)(void *) = (void *)prop.Get;
6109
6110                                     exp.instance = Instantiation { };
6111                                     exp.instance._class = MkSpecifierName(_class.fullName); //MkClassName(_class.fullName);
6112                                     exp.type = instanceExp;
6113                                     exp.instance.data = Get(value, exp.instance.data);
6114                                  }
6115                                  break;
6116                               }
6117                            }
6118                         }
6119                         */
6120                      }
6121                   }
6122                }
6123                else
6124                {
6125                   exp.isConstant = false;
6126                }
6127             }
6128             else if(member)
6129             {
6130             }
6131          }
6132
6133          if(exp.type != ExpressionType::memberExp)
6134          {
6135             FreeExpression(memberExp);
6136             FreeIdentifier(memberID);
6137          }
6138          break;
6139       }
6140       case typeSizeExp:
6141       {
6142          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
6143          FreeExpContents(exp);
6144          exp.constant = PrintUInt(ComputeTypeSize(type));
6145          exp.type = constantExp;
6146          FreeType(type);
6147          break;
6148       }
6149       case classSizeExp:
6150       {
6151          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
6152          if(classSym && classSym.registered)
6153          {
6154             if(classSym.registered.fixed)
6155             {
6156                FreeSpecifier(exp._class);
6157                exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
6158                exp.type = constantExp;
6159             }
6160             else
6161             {
6162                char className[1024];
6163                strcpy(className, "__ecereClass_");
6164                FullClassNameCat(className, classSym.string, true);
6165
6166                DeclareClass(curExternal, classSym, className);
6167
6168                FreeExpContents(exp);
6169                exp.type = pointerExp;
6170                exp.member.exp = MkExpIdentifier(MkIdentifier(className));
6171                exp.member.member = MkIdentifier("structSize");
6172             }
6173          }
6174          break;
6175       }
6176       case castExp:
6177       //case constantExp:
6178       {
6179          Type type;
6180          Expression e = exp;
6181          if(exp.type == castExp)
6182          {
6183             if(exp.cast.exp)
6184                ComputeExpression(exp.cast.exp);
6185             e = exp.cast.exp;
6186          }
6187          if(e && exp.expType)
6188          {
6189             /*if(exp.destType)
6190                type = exp.destType;
6191             else*/
6192                type = exp.expType;
6193             if(type.kind == classType)
6194             {
6195                Class _class = type._class.registered;
6196                if(_class && (_class.type == unitClass || _class.type == bitClass))
6197                {
6198                   if(!_class.dataType)
6199                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
6200                   type = _class.dataType;
6201                }
6202             }
6203
6204             switch(type.kind)
6205             {
6206                case _BoolType:
6207                case charType:
6208                   if(type.isSigned)
6209                   {
6210                      char value = 0;
6211                      if(GetChar(e, &value))
6212                      {
6213                         FreeExpContents(exp);
6214                         exp.constant = PrintChar(value);
6215                         exp.type = constantExp;
6216                      }
6217                   }
6218                   else
6219                   {
6220                      unsigned char value = 0;
6221                      if(GetUChar(e, &value))
6222                      {
6223                         FreeExpContents(exp);
6224                         exp.constant = PrintUChar(value);
6225                         exp.type = constantExp;
6226                      }
6227                   }
6228                   break;
6229                case shortType:
6230                   if(type.isSigned)
6231                   {
6232                      short value = 0;
6233                      if(GetShort(e, &value))
6234                      {
6235                         FreeExpContents(exp);
6236                         exp.constant = PrintShort(value);
6237                         exp.type = constantExp;
6238                      }
6239                   }
6240                   else
6241                   {
6242                      unsigned short value = 0;
6243                      if(GetUShort(e, &value))
6244                      {
6245                         FreeExpContents(exp);
6246                         exp.constant = PrintUShort(value);
6247                         exp.type = constantExp;
6248                      }
6249                   }
6250                   break;
6251                case intType:
6252                   if(type.isSigned)
6253                   {
6254                      int value = 0;
6255                      if(GetInt(e, &value))
6256                      {
6257                         FreeExpContents(exp);
6258                         exp.constant = PrintInt(value);
6259                         exp.type = constantExp;
6260                      }
6261                   }
6262                   else
6263                   {
6264                      unsigned int value = 0;
6265                      if(GetUInt(e, &value))
6266                      {
6267                         FreeExpContents(exp);
6268                         exp.constant = PrintUInt(value);
6269                         exp.type = constantExp;
6270                      }
6271                   }
6272                   break;
6273                case int64Type:
6274                   if(type.isSigned)
6275                   {
6276                      int64 value = 0;
6277                      if(GetInt64(e, &value))
6278                      {
6279                         FreeExpContents(exp);
6280                         exp.constant = PrintInt64(value);
6281                         exp.type = constantExp;
6282                      }
6283                   }
6284                   else
6285                   {
6286                      uint64 value = 0;
6287                      if(GetUInt64(e, &value))
6288                      {
6289                         FreeExpContents(exp);
6290                         exp.constant = PrintUInt64(value);
6291                         exp.type = constantExp;
6292                      }
6293                   }
6294                   break;
6295                case intPtrType:
6296                   if(type.isSigned)
6297                   {
6298                      intptr value = 0;
6299                      if(GetIntPtr(e, &value))
6300                      {
6301                         FreeExpContents(exp);
6302                         exp.constant = PrintInt64((int64)value);
6303                         exp.type = constantExp;
6304                      }
6305                   }
6306                   else
6307                   {
6308                      uintptr value = 0;
6309                      if(GetUIntPtr(e, &value))
6310                      {
6311                         FreeExpContents(exp);
6312                         exp.constant = PrintUInt64((uint64)value);
6313                         exp.type = constantExp;
6314                      }
6315                   }
6316                   break;
6317                case intSizeType:
6318                   if(type.isSigned)
6319                   {
6320                      intsize value = 0;
6321                      if(GetIntSize(e, &value))
6322                      {
6323                         FreeExpContents(exp);
6324                         exp.constant = PrintInt64((int64)value);
6325                         exp.type = constantExp;
6326                      }
6327                   }
6328                   else
6329                   {
6330                      uintsize value = 0;
6331                      if(GetUIntSize(e, &value))
6332                      {
6333                         FreeExpContents(exp);
6334                         exp.constant = PrintUInt64((uint64)value);
6335                         exp.type = constantExp;
6336                      }
6337                   }
6338                   break;
6339                case floatType:
6340                {
6341                   float value = 0;
6342                   if(GetFloat(e, &value))
6343                   {
6344                      FreeExpContents(exp);
6345                      exp.constant = PrintFloat(value);
6346                      exp.type = constantExp;
6347                   }
6348                   break;
6349                }
6350                case doubleType:
6351                {
6352                   double value = 0;
6353                   if(GetDouble(e, &value))
6354                   {
6355                      FreeExpContents(exp);
6356                      exp.constant = PrintDouble(value);
6357                      exp.type = constantExp;
6358                   }
6359                   break;
6360                }
6361             }
6362          }
6363          break;
6364       }
6365       case conditionExp:
6366       {
6367          Operand op1 { };
6368          Operand op2 { };
6369          Operand op3 { };
6370
6371          if(exp.cond.exp)
6372             // Caring only about last expression for now...
6373             ComputeExpression(exp.cond.exp->last);
6374          if(exp.cond.elseExp)
6375             ComputeExpression(exp.cond.elseExp);
6376          if(exp.cond.cond)
6377             ComputeExpression(exp.cond.cond);
6378
6379          op1 = GetOperand(exp.cond.cond);
6380          if(op1.type) op1.type.refCount++;
6381          op2 = GetOperand(exp.cond.exp->last);
6382          if(op2.type) op2.type.refCount++;
6383          op3 = GetOperand(exp.cond.elseExp);
6384          if(op3.type) op3.type.refCount++;
6385
6386          if(op1.ops.Cond) { FreeExpContents(exp); op1.ops.Cond(exp, op1, op2, op3); }
6387          if(op1.type) FreeType(op1.type);
6388          if(op2.type) FreeType(op2.type);
6389          if(op3.type) FreeType(op3.type);
6390          break;
6391       }
6392    }
6393 }
6394
6395 static bool CheckExpressionType(Expression exp, Type destType, bool skipUnitBla, bool warnConst)
6396 {
6397    bool result = true;
6398    if(destType)
6399    {
6400       OldList converts { };
6401       Conversion convert;
6402
6403       if(destType.kind == voidType)
6404          return false;
6405
6406       if(!MatchTypeExpression(exp, destType, &converts, skipUnitBla, warnConst))
6407          result = false;
6408       if(converts.count)
6409       {
6410          // for(convert = converts.last; convert; convert = convert.prev)
6411          for(convert = converts.first; convert; convert = convert.next)
6412          {
6413             bool empty = !(convert.isGet ? (void *)convert.convert.Get : (void *)convert.convert.Set);
6414             if(!empty)
6415             {
6416                Expression newExp { };
6417                ClassObjectType objectType = exp.expType ? exp.expType.classObjectType : none;
6418
6419                // TODO: Check this...
6420                *newExp = *exp;
6421                newExp.prev = null;
6422                newExp.next = null;
6423                newExp.destType = null;
6424
6425                if(convert.isGet)
6426                {
6427                   // [exp].ColorRGB
6428                   exp.type = memberExp;
6429                   exp.addedThis = true;
6430                   exp.member.exp = newExp;
6431                   FreeType(exp.member.exp.expType);
6432
6433                   exp.member.exp.expType = MkClassType(convert.convert._class.fullName);
6434                   exp.member.exp.expType.classObjectType = objectType;
6435                   exp.member.member = MkIdentifier(convert.convert.dataTypeString);
6436                   exp.member.memberType = propertyMember;
6437                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6438                   // TESTING THIS... for (int)degrees
6439                   exp.needCast = true;
6440                   if(exp.expType) exp.expType.refCount++;
6441                   ApplyAnyObjectLogic(exp.member.exp);
6442                }
6443                else
6444                {
6445
6446                   /*if(exp.isConstant)
6447                   {
6448                      // Color { ColorRGB = [exp] };
6449                      exp.type = instanceExp;
6450                      exp.instance = MkInstantiation(MkSpecifierName((convert.convert._class.fullName), //MkClassName(convert.convert._class.fullName),
6451                         null, MkListOne(MkMembersInitList(MkListOne(MkMemberInit(
6452                         MkListOne(MkIdentifier(convert.convert.dataTypeString)), newExp)))));
6453                   }
6454                   else*/
6455                   {
6456                      // If not constant, don't turn it yet into an instantiation
6457                      // (Go through the deep members system first)
6458                      exp.type = memberExp;
6459                      exp.addedThis = true;
6460                      exp.member.exp = newExp;
6461
6462                      // ADDED THIS HERE TO SOLVE PROPERTY ISSUES WITH NOHEAD CLASSES
6463                      if(/*!notByReference && */newExp.expType && newExp.expType.kind == classType && newExp.expType._class && newExp.expType._class.registered &&
6464                         newExp.expType._class.registered.type == noHeadClass)
6465                      {
6466                         newExp.byReference = true;
6467                      }
6468
6469                      FreeType(exp.member.exp.expType);
6470                      /*exp.member.exp.expType = convert.convert.dataType;
6471                      if(convert.convert.dataType) convert.convert.dataType.refCount++;*/
6472                      exp.member.exp.expType = null;
6473                      if(convert.convert.dataType)
6474                      {
6475                         exp.member.exp.expType = { };
6476                         CopyTypeInto(exp.member.exp.expType, convert.convert.dataType);
6477                         exp.member.exp.expType.refCount = 1;
6478                         exp.member.exp.expType.classObjectType = objectType;
6479                         ApplyAnyObjectLogic(exp.member.exp);
6480                      }
6481
6482                      exp.member.member = MkIdentifier(convert.convert._class.fullName);
6483                      exp.member.memberType = reverseConversionMember;
6484                      exp.expType = convert.resultType ? convert.resultType :
6485                         MkClassType(convert.convert._class.fullName);
6486                      exp.needCast = true;
6487                      if(convert.resultType) convert.resultType.refCount++;
6488                   }
6489                }
6490             }
6491             else
6492             {
6493                FreeType(exp.expType);
6494                if(convert.isGet)
6495                {
6496                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6497                   if(exp.destType.casted)
6498                      exp.needCast = true;
6499                   if(exp.expType) exp.expType.refCount++;
6500                }
6501                else
6502                {
6503                   exp.expType = convert.resultType ? convert.resultType : MkClassType(convert.convert._class.fullName);
6504                   if(exp.destType.casted)
6505                      exp.needCast = true;
6506                   if(convert.resultType)
6507                      convert.resultType.refCount++;
6508                }
6509             }
6510          }
6511          if(exp.isConstant && inCompiler)
6512             ComputeExpression(exp);
6513
6514          converts.Free(FreeConvert);
6515       }
6516
6517       if(!result && exp.expType && converts.count)      // TO TEST: Added converts.count here to avoid a double warning with function type
6518       {
6519          result = MatchTypes(exp.expType, exp.destType, null, null, null, true, true, false, false, warnConst);
6520       }
6521       if(!result && exp.expType && exp.destType)
6522       {
6523          if((exp.destType.kind == classType && exp.expType.kind == pointerType &&
6524              exp.expType.type.kind == classType && exp.expType.type._class == exp.destType._class && exp.destType._class.registered && exp.destType._class.registered.type == structClass) ||
6525             (exp.expType.kind == classType && exp.destType.kind == pointerType &&
6526             exp.destType.type.kind == classType && exp.destType.type._class == exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass))
6527             result = true;
6528       }
6529    }
6530    // if(result) CheckTemplateTypes(exp);
6531    return result;
6532 }
6533
6534 void modifyPassAsTemplate(Type * typePtr, bool value)
6535 {
6536    if(*typePtr && typePtr->passAsTemplate != value)
6537    {
6538       Type type { refCount = 1 };
6539       CopyTypeInto(type, *typePtr);
6540       type.passAsTemplate = value;
6541       FreeType(*typePtr);
6542       *typePtr = type;
6543    }
6544 }
6545
6546 void CheckTemplateTypes(Expression exp)
6547 {
6548    /*
6549    bool et = exp.expType ? exp.expType.passAsTemplate : false;
6550    bool dt = exp.destType ? exp.destType.passAsTemplate : false;
6551    */
6552    Expression nbExp = GetNonBracketsExp(exp);
6553    if(exp.destType && exp.destType.passAsTemplate && exp.expType && exp.expType.kind != templateType && !exp.expType.passAsTemplate &&
6554       (nbExp == exp || nbExp.type != castExp))
6555    {
6556       Expression newExp { };
6557       Context context;
6558       TypeKind kind = exp.expType.kind;
6559       *newExp = *exp;
6560       if(exp.destType) exp.destType.refCount++;
6561       if(exp.expType)  exp.expType.refCount++;
6562       newExp.prev = null;
6563       newExp.next = null;
6564
6565       if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered)
6566       {
6567          Class c = exp.expType._class.registered;
6568          if(c.type == bitClass || c.type == enumClass || c.type == unitClass)
6569          {
6570             if(!c.dataType)
6571                c.dataType = ProcessTypeString(c.dataTypeString, false);
6572             kind = c.dataType.kind;
6573          }
6574       }
6575
6576       switch(kind)
6577       {
6578          case doubleType:
6579             if(exp.destType.classObjectType)
6580             {
6581                // We need to pass the address, just pass it along (Undo what was done above)
6582                if(exp.destType) exp.destType.refCount--;
6583                if(exp.expType)  exp.expType.refCount--;
6584                delete newExp;
6585             }
6586             else
6587             {
6588                // We want to pass as a template argument
6589                // ({ union { double d; uint64 i; } u; u.d = [newExp]; u.i; })
6590                OldList * specs;
6591                OldList * unionDefs = MkList();
6592                OldList * statements = MkList();
6593                context = PushContext();
6594                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6595                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6596                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6597                exp.type = extensionCompoundExp;
6598
6599                modifyPassAsTemplate(&exp.expType, true);
6600                modifyPassAsTemplate(&newExp.destType, false);
6601                modifyPassAsTemplate(&newExp.expType, false);
6602
6603                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6604                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")), '=', newExp))));
6605                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
6606                exp.compound.compound.context = context;
6607                PopContext(context);
6608             }
6609             break;
6610          case floatType:
6611             if(exp.destType.classObjectType)
6612             {
6613                // We need to pass the address, just pass it along (Undo what was done above)
6614                if(exp.destType) exp.destType.refCount--;
6615                if(exp.expType)  exp.expType.refCount--;
6616                delete newExp;
6617             }
6618             else
6619             {
6620                // We want to pass as a template argument
6621                // ({ union { float f; uint64 i; } u; u.f = [newExp]; u.i; })
6622                OldList * specs;
6623                OldList * unionDefs = MkList();
6624                OldList * statements = MkList();
6625                context = PushContext();
6626                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(FLOAT)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("f"))), null)));
6627                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6628                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6629                exp.type = extensionCompoundExp;
6630                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6631
6632                modifyPassAsTemplate(&exp.expType, true);
6633                modifyPassAsTemplate(&newExp.destType, false);
6634                modifyPassAsTemplate(&newExp.expType, false);
6635
6636                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("f")), '=', newExp))));
6637                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
6638                exp.compound.compound.context = context;
6639                PopContext(context);
6640             }
6641             break;
6642          case voidType:
6643             // Generated code already processed...
6644             break;
6645          default:
6646             exp.type = castExp;
6647             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6648             if((exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass) || exp.expType.isPointerType)
6649                exp.cast.exp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), MkExpBrackets(MkListOne(newExp)));
6650             else
6651                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6652             exp.needCast = true;
6653             break;
6654       }
6655    }
6656    else if(exp.expType && exp.expType.passAsTemplate && exp.destType && exp.usage.usageGet && exp.destType.kind != templateType && !exp.destType.passAsTemplate)
6657    {
6658       Expression newExp { };
6659       Context context;
6660       TypeKind kind = exp.expType.kind;
6661       *newExp = *exp;
6662       if(exp.destType) exp.destType.refCount++;
6663       if(exp.expType)  exp.expType.refCount++;
6664       newExp.prev = null;
6665       newExp.next = null;
6666
6667       if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered)
6668       {
6669          Class c = exp.expType._class.registered;
6670          if(c.type == bitClass || c.type == enumClass || c.type == unitClass)
6671          {
6672             if(!c.dataType)
6673                c.dataType = ProcessTypeString(c.dataTypeString, false);
6674             kind = c.dataType.kind;
6675          }
6676       }
6677
6678       switch(kind)
6679       {
6680          case doubleType:
6681             if(exp.destType.classObjectType)
6682             {
6683                // We need to pass the address, just pass it along (Undo what was done above)
6684                if(exp.destType) exp.destType.refCount--;
6685                if(exp.expType)  exp.expType.refCount--;
6686                delete newExp;
6687             }
6688             else
6689             {
6690                // If we're looking for value:
6691                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6692                OldList * specs;
6693                OldList * unionDefs = MkList();
6694                OldList * statements = MkList();
6695                context = PushContext();
6696                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6697                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6698                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6699                exp.type = extensionCompoundExp;
6700                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6701
6702                modifyPassAsTemplate(&exp.expType, false);
6703                modifyPassAsTemplate(&newExp.destType, true);
6704                modifyPassAsTemplate(&newExp.expType, true);
6705
6706                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
6707                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")))));
6708                exp.compound.compound.context = context;
6709                PopContext(context);
6710             }
6711             break;
6712          case floatType:
6713             if(exp.destType.classObjectType)
6714             {
6715                // We need to pass the address, just pass it along (Undo what was done above)
6716                if(exp.destType) exp.destType.refCount--;
6717                if(exp.expType)  exp.expType.refCount--;
6718                delete newExp;
6719             }
6720             else
6721             {
6722                // If we're looking for value:
6723                // ({ union { float f; uint64 i; } u; u.i = [newExp]; u.f; })
6724                OldList * specs;
6725                OldList * unionDefs = MkList();
6726                OldList * statements = MkList();
6727                context = PushContext();
6728                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(FLOAT)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("f"))), null)));
6729                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6730                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6731                exp.type = extensionCompoundExp;
6732                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6733
6734                modifyPassAsTemplate(&exp.expType, false);
6735                modifyPassAsTemplate(&newExp.destType, true);
6736                modifyPassAsTemplate(&newExp.expType, true);
6737
6738                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
6739                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("f")))));
6740                exp.compound.compound.context = context;
6741                PopContext(context);
6742             }
6743             break;
6744          case classType:
6745          {
6746             if(exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass)
6747             {
6748                exp.type = bracketsExp;
6749
6750                newExp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), newExp);
6751                exp.list = MkListOne(MkExpOp(null, '*', MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)),
6752                   MkDeclaratorPointer(MkPointer(null, null), null)), newExp)));
6753                ProcessExpressionType(exp.list->first);
6754                break;
6755             }
6756             else
6757             {
6758                exp.type = bracketsExp;
6759                if(exp.expType.isPointerType)
6760                {
6761                   exp.needTemplateCast = 2;
6762                   newExp.needCast = true;
6763                   newExp.needTemplateCast = 2;
6764                   newExp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), newExp);
6765                }
6766
6767                exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)), null), newExp));
6768                exp.needTemplateCast = 2;
6769                newExp.needCast = true;
6770                newExp.needTemplateCast = 2;
6771                ProcessExpressionType(exp.list->first);
6772                break;
6773             }
6774          }
6775          default:
6776          {
6777             if(exp.expType.kind == templateType)
6778             {
6779                Type type = ProcessTemplateParameterType(exp.expType.templateParameter);
6780                if(type)
6781                {
6782                   FreeType(exp.destType);
6783                   FreeType(exp.expType);
6784                   delete newExp;
6785                   break;
6786                }
6787             }
6788             /*if(newExp.type == memberExp && newExp.member.memberType == dataMember)
6789             {
6790                // When was this required?    Removed to address using templated values to pass to printf()
6791                exp.type = opExp;
6792                exp.op.op = '*';
6793                exp.op.exp1 = null;
6794                exp.op.exp2 = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uint64")), MkDeclaratorPointer(MkPointer(null, null), null)),
6795                   MkExpBrackets(MkListOne(MkExpOp(null, '&', newExp))));
6796             }
6797             else*/
6798             {
6799                char typeString[1024];
6800                Declarator decl;
6801                OldList * specs = MkList();
6802                typeString[0] = '\0';
6803                PrintType(exp.expType, typeString, false, false);
6804                decl = SpecDeclFromString(typeString, specs, null);
6805
6806                exp.type = castExp;
6807                //exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6808                exp.cast.typeName = MkTypeName(specs, decl);
6809                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6810                exp.cast.exp.needCast = true;
6811                exp.needTemplateCast = 2;
6812                newExp.needTemplateCast = 2;
6813             }
6814             break;
6815          }
6816       }
6817    }
6818 }
6819 // TODO: The Symbol tree should be reorganized by namespaces
6820 // Name Space:
6821 //    - Tree of all symbols within (stored without namespace)
6822 //    - Tree of sub-namespaces
6823
6824 static Symbol ScanWithNameSpace(BinaryTree tree, const char * nameSpace, const char * name)
6825 {
6826    int nsLen = strlen(nameSpace);
6827    Symbol symbol;
6828    // Start at the name space prefix
6829    for(symbol = (Symbol)tree.FindPrefix(nameSpace); symbol; symbol = (Symbol)((BTNode)symbol).next)
6830    {
6831       char * s = symbol.string;
6832       if(!strncmp(s, nameSpace, nsLen))
6833       {
6834          // This supports e.g. matching ecere::Socket to ecere::net::Socket
6835          int c;
6836          char * namePart;
6837          for(c = strlen(s)-1; c >= 0; c--)
6838             if(s[c] == ':')
6839                break;
6840
6841          namePart = s+c+1;
6842          if(!strcmp(namePart, name))
6843          {
6844             // TODO: Error on ambiguity
6845             return symbol;
6846          }
6847       }
6848       else
6849          break;
6850    }
6851    return null;
6852 }
6853
6854 static Symbol FindWithNameSpace(BinaryTree tree, const char * name)
6855 {
6856    int c;
6857    char nameSpace[1024];
6858    const char * namePart;
6859    bool gotColon = false;
6860
6861    nameSpace[0] = '\0';
6862    for(c = strlen(name)-1; c >= 0; c--)
6863       if(name[c] == ':')
6864       {
6865          gotColon = true;
6866          break;
6867       }
6868
6869    namePart = name+c+1;
6870    while(c >= 0 && name[c] == ':') c--;
6871    if(c >= 0)
6872    {
6873       // Try an exact match first
6874       Symbol symbol = (Symbol)tree.FindString(name);
6875       if(symbol)
6876          return symbol;
6877
6878       // Namespace specified
6879       memcpy(nameSpace, name, c + 1);
6880       nameSpace[c+1] = 0;
6881
6882       return ScanWithNameSpace(tree, nameSpace, namePart);
6883    }
6884    else if(gotColon)
6885    {
6886       // Looking for a global symbol, e.g. ::Sleep()
6887       Symbol symbol = (Symbol)tree.FindString(namePart);
6888       return symbol;
6889    }
6890    else
6891    {
6892       // Name only (no namespace specified)
6893       Symbol symbol = (Symbol)tree.FindString(namePart);
6894       if(symbol)
6895          return symbol;
6896       return ScanWithNameSpace(tree, "", namePart);
6897    }
6898    return null;
6899 }
6900
6901 /*static */Symbol FindSymbol(const char * name, Context startContext, Context endContext, bool isStruct, bool globalNameSpace)
6902 {
6903 #ifdef _DEBUG
6904    //Time startTime = GetTime();
6905 #endif
6906    // Optimize this later? Do this before/less?
6907    Context ctx;
6908    Symbol symbol = null;
6909
6910    // First, check if the identifier is declared inside the function
6911    //for(ctx = curContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6912
6913    for(ctx = startContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6914    {
6915       if(ctx == globalContext && !globalNameSpace && ctx.hasNameSpace)
6916       {
6917          symbol = null;
6918          if(thisNameSpace)
6919          {
6920             char curName[1024];
6921             strcpy(curName, thisNameSpace);
6922             strcat(curName, "::");
6923             strcat(curName, name);
6924             // Try to resolve in current namespace first
6925             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, curName);
6926          }
6927          if(!symbol)
6928             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, name);
6929       }
6930       else
6931          symbol = (Symbol)(isStruct ? ctx.structSymbols : ctx.symbols).FindString(name);
6932
6933       if(symbol || ctx == endContext) break;
6934    }
6935    if(inCompiler && symbol && ctx == globalContext && symbol.pointerExternal && curExternal && symbol.pointerExternal != curExternal)
6936       curExternal.CreateUniqueEdge(symbol.pointerExternal, symbol.pointerExternal.type == functionExternal);
6937 #ifdef _DEBUG
6938    //findSymbolTotalTime += GetTime() - startTime;
6939 #endif
6940    return symbol;
6941 }
6942
6943 static void GetTypeSpecs(Type type, OldList * specs)
6944 {
6945    if(!type.isSigned && type.kind != intPtrType && type.kind != intSizeType) ListAdd(specs, MkSpecifier(UNSIGNED));
6946    switch(type.kind)
6947    {
6948       case classType:
6949       {
6950          if(type._class.registered)
6951          {
6952             if(!type._class.registered.dataType)
6953                type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
6954             GetTypeSpecs(type._class.registered.dataType, specs);
6955          }
6956          break;
6957       }
6958       case doubleType: ListAdd(specs, MkSpecifier(DOUBLE)); break;
6959       case floatType: ListAdd(specs, MkSpecifier(FLOAT)); break;
6960       case charType: ListAdd(specs, MkSpecifier(CHAR)); break;
6961       case _BoolType: ListAdd(specs, MkSpecifier(_BOOL)); break;
6962       case shortType: ListAdd(specs, MkSpecifier(SHORT)); break;
6963       case int64Type: ListAdd(specs, MkSpecifier(INT64)); break;
6964       case intPtrType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intptr" : "uintptr")); break;
6965       case intSizeType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intsize" : "uintsize")); break;
6966       case intType:
6967       default:
6968          ListAdd(specs, MkSpecifier(INT)); break;
6969    }
6970 }
6971
6972 static void PrintArraySize(Type arrayType, char * string)
6973 {
6974    char size[256];
6975    size[0] = '\0';
6976    strcat(size, "[");
6977    if(arrayType.enumClass)
6978       strcat(size, arrayType.enumClass.string);
6979    else if(arrayType.arraySizeExp)
6980       PrintExpression(arrayType.arraySizeExp, size);
6981    strcat(size, "]");
6982    strcat(string, size);
6983 }
6984
6985 // WARNING : This function expects a null terminated string since it recursively concatenate...
6986 static void PrintTypeSpecs(Type type, char * string, bool fullName, bool printConst)
6987 {
6988    if(type)
6989    {
6990       if(printConst && type.constant)
6991          strcat(string, "const ");
6992       switch(type.kind)
6993       {
6994          case classType:
6995          {
6996             Symbol c = type._class;
6997             bool isObjectBaseClass = !c || !c.string || !strcmp(c.string, "class");
6998             // TODO: typed_object does not fully qualify the type, as it may have taken up an actual class (Stored in _class) from overriding
6999             //       look into merging with thisclass ?
7000             if(type.classObjectType == typedObject && isObjectBaseClass)
7001                strcat(string, "typed_object");
7002             else if(type.classObjectType == anyObject && isObjectBaseClass)
7003                strcat(string, "any_object");
7004             else
7005             {
7006                if(c && c.string)
7007                   strcat(string, (fullName || !c.registered) ? c.string : c.registered.name);
7008             }
7009             if(type.byReference)
7010                strcat(string, " &");
7011             break;
7012          }
7013          case voidType: strcat(string, "void"); break;
7014          case intType:  strcat(string, type.isSigned ? "int" : "uint"); break;
7015          case int64Type:  strcat(string, type.isSigned ? "int64" : "uint64"); break;
7016          case intPtrType:  strcat(string, type.isSigned ? "intptr" : "uintptr"); break;
7017          case intSizeType:  strcat(string, type.isSigned ? "intsize" : "uintsize"); break;
7018          case charType: strcat(string, type.isSigned ? "char" : "byte"); break;
7019          case _BoolType: strcat(string, "_Bool"); break;
7020          case shortType: strcat(string, type.isSigned ? "short" : "uint16"); break;
7021          case floatType: strcat(string, "float"); break;
7022          case doubleType: strcat(string, "double"); break;
7023          case structType:
7024             if(type.enumName)
7025             {
7026                strcat(string, "struct ");
7027                strcat(string, type.enumName);
7028             }
7029             else if(type.typeName)
7030                strcat(string, type.typeName);
7031             else
7032             {
7033                Type member;
7034                strcat(string, "struct { ");
7035                for(member = type.members.first; member; member = member.next)
7036                {
7037                   PrintType(member, string, true, fullName);
7038                   strcat(string,"; ");
7039                }
7040                strcat(string,"}");
7041             }
7042             break;
7043          case unionType:
7044             if(type.enumName)
7045             {
7046                strcat(string, "union ");
7047                strcat(string, type.enumName);
7048             }
7049             else if(type.typeName)
7050                strcat(string, type.typeName);
7051             else
7052             {
7053                strcat(string, "union ");
7054                strcat(string,"(unnamed)");
7055             }
7056             break;
7057          case enumType:
7058             if(type.enumName)
7059             {
7060                strcat(string, "enum ");
7061                strcat(string, type.enumName);
7062             }
7063             else if(type.typeName)
7064                strcat(string, type.typeName);
7065             else
7066                strcat(string, "int"); // "enum");
7067             break;
7068          case ellipsisType:
7069             strcat(string, "...");
7070             break;
7071          case subClassType:
7072             strcat(string, "subclass(");
7073             strcat(string, type._class ? type._class.string : "int");
7074             strcat(string, ")");
7075             break;
7076          case templateType:
7077             strcat(string, type.templateParameter.identifier.string);
7078             break;
7079          case thisClassType:
7080             strcat(string, "thisclass");
7081             break;
7082          case vaListType:
7083             strcat(string, "__builtin_va_list");
7084             break;
7085       }
7086    }
7087 }
7088
7089 static void PrintName(Type type, char * string, bool fullName)
7090 {
7091    if(type.name && type.name[0])
7092    {
7093       if(fullName)
7094          strcat(string, type.name);
7095       else
7096       {
7097          char * name = RSearchString(type.name, "::", strlen(type.name), true, false);
7098          if(name) name += 2; else name = type.name;
7099          strcat(string, name);
7100       }
7101    }
7102 }
7103
7104 static void PrintAttribs(Type type, char * string)
7105 {
7106    if(type)
7107    {
7108       if(type.dllExport)   strcat(string, "dllexport ");
7109       if(type.attrStdcall) strcat(string, "stdcall ");
7110    }
7111 }
7112
7113 static void PrePrintType(Type type, char * string, bool fullName, Type parentType, bool printConst)
7114 {
7115    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
7116    {
7117       if((type.kind == functionType || type.kind == methodType) && (!parentType || parentType.kind != pointerType))
7118          PrintAttribs(type, string);
7119       if(printConst && type.constant && (type.kind == functionType || type.kind == methodType))
7120          strcat(string, " const");
7121       PrePrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName, type, printConst);
7122       if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
7123          strcat(string, " (");
7124       if(type.kind == pointerType)
7125       {
7126          if(type.type.kind == functionType || type.type.kind == methodType)
7127             PrintAttribs(type.type, string);
7128       }
7129       if(type.kind == pointerType)
7130       {
7131          if(type.type.kind == functionType || type.type.kind == methodType || type.type.kind == arrayType)
7132             strcat(string, "*");
7133          else
7134             strcat(string, " *");
7135       }
7136       if(printConst && type.constant && type.kind == pointerType)
7137          strcat(string, " const");
7138    }
7139    else
7140       PrintTypeSpecs(type, string, fullName, printConst);
7141 }
7142
7143 static void PostPrintType(Type type, char * string, bool fullName)
7144 {
7145    if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
7146       strcat(string, ")");
7147    if(type.kind == arrayType)
7148       PrintArraySize(type, string);
7149    else if(type.kind == functionType)
7150    {
7151       Type param;
7152       strcat(string, "(");
7153       for(param = type.params.first; param; param = param.next)
7154       {
7155          PrintType(param, string, true, fullName);
7156          if(param.next) strcat(string, ", ");
7157       }
7158       strcat(string, ")");
7159    }
7160    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
7161       PostPrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName);
7162 }
7163
7164 // *****
7165 // TODO: Add a max buffer size to avoid overflows. This function is used with static size char arrays.
7166 // *****
7167 static void _PrintType(Type type, char * string, bool printName, bool fullName, bool printConst)
7168 {
7169    PrePrintType(type, string, fullName, null, printConst);
7170
7171    if(type.thisClass || (printName && type.name && type.name[0]))
7172       strcat(string, " ");
7173    if(/*(type.kind == methodType || type.kind == functionType) && */(type.thisClass || type.staticMethod))
7174    {
7175       Symbol _class = type.thisClass;
7176       if((type.classObjectType == typedObject || type.classObjectType == classPointer) || (_class && !strcmp(_class.string, "class")))
7177       {
7178          if(type.classObjectType == classPointer)
7179             strcat(string, "class");
7180          else
7181             strcat(string, type.byReference ? "typed_object&" : "typed_object");
7182       }
7183       else if(_class && _class.string)
7184       {
7185          String s = _class.string;
7186          if(fullName)
7187             strcat(string, s);
7188          else
7189          {
7190             char * name = RSearchString(s, "::", strlen(s), true, false);
7191             if(name) name += 2; else name = s;
7192             strcat(string, name);
7193          }
7194       }
7195       strcat(string, "::");
7196    }
7197
7198    if(printName && type.name)
7199       PrintName(type, string, fullName);
7200    PostPrintType(type, string, fullName);
7201    if(type.bitFieldCount)
7202    {
7203       char count[100];
7204       sprintf(count, ":%d", type.bitFieldCount);
7205       strcat(string, count);
7206    }
7207 }
7208
7209 void PrintType(Type type, char * string, bool printName, bool fullName)
7210 {
7211    _PrintType(type, string, printName, fullName, true);
7212 }
7213
7214 void PrintTypeNoConst(Type type, char * string, bool printName, bool fullName)
7215 {
7216    _PrintType(type, string, printName, fullName, false);
7217 }
7218
7219 static Type FindMember(Type type, char * string)
7220 {
7221    Type memberType;
7222    for(memberType = type.members.first; memberType; memberType = memberType.next)
7223    {
7224       if(!memberType.name)
7225       {
7226          Type subType = FindMember(memberType, string);
7227          if(subType)
7228             return subType;
7229       }
7230       else if(!strcmp(memberType.name, string))
7231          return memberType;
7232    }
7233    return null;
7234 }
7235
7236 Type FindMemberAndOffset(Type type, char * string, uint * offset)
7237 {
7238    Type memberType;
7239    for(memberType = type.members.first; memberType; memberType = memberType.next)
7240    {
7241       if(!memberType.name)
7242       {
7243          Type subType = FindMember(memberType, string);
7244          if(subType)
7245          {
7246             *offset += memberType.offset;
7247             return subType;
7248          }
7249       }
7250       else if(!strcmp(memberType.name, string))
7251       {
7252          *offset += memberType.offset;
7253          return memberType;
7254       }
7255    }
7256    return null;
7257 }
7258
7259 public bool GetParseError() { return parseError; }
7260
7261 Expression ParseExpressionString(char * expression)
7262 {
7263    parseError = false;
7264
7265    fileInput = TempFile { };
7266    fileInput.Write(expression, 1, strlen(expression));
7267    fileInput.Seek(0, start);
7268
7269    echoOn = false;
7270    parsedExpression = null;
7271    resetScanner();
7272    expression_yyparse();
7273    delete fileInput;
7274
7275    return parsedExpression;
7276 }
7277
7278 static bool ResolveIdWithClass(Expression exp, Class _class, bool skipIDClassCheck)
7279 {
7280    Identifier id = exp.identifier;
7281    Method method = null;
7282    Property prop = null;
7283    DataMember member = null;
7284    ClassProperty classProp = null;
7285
7286    if(_class && _class.type == enumClass)
7287    {
7288       NamedLink64 value = null;
7289       Class enumClass = eSystem_FindClass(privateModule, "enum");
7290       if(enumClass)
7291       {
7292          Class baseClass;
7293          for(baseClass = _class; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
7294          {
7295             EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
7296             for(value = e.values.first; value; value = value.next)
7297             {
7298                if(!strcmp(value.name, id.string))
7299                   break;
7300             }
7301             if(value)
7302             {
7303                exp.isConstant = true;
7304                if(inCompiler || inPreCompiler || inDebugger)
7305                {
7306                   char constant[256];
7307                   FreeExpContents(exp);
7308
7309                   exp.type = constantExp;
7310                   if(!strcmp(baseClass.dataTypeString, "int") || !strcmp(baseClass.dataTypeString, "int64") || !strcmp(baseClass.dataTypeString, "char") || !strcmp(baseClass.dataTypeString, "short"))
7311                      sprintf(constant, FORMAT64D, value.data);
7312                   else
7313                      sprintf(constant, FORMAT64HEX, value.data);
7314                   exp.constant = CopyString(constant);
7315                }
7316                //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
7317                exp.expType = MkClassType(baseClass.fullName);
7318                break;
7319             }
7320          }
7321       }
7322       if(value)
7323          return true;
7324    }
7325    if((method = eClass_FindMethod(_class, id.string, privateModule)))
7326    {
7327       ProcessMethodType(method);
7328       exp.expType = Type
7329       {
7330          refCount = 1;
7331          kind = methodType;
7332          method = method;
7333          // Crash here?
7334          // TOCHECK: Put it back to what it was...
7335          // methodClass = _class;
7336          methodClass = (skipIDClassCheck || (id && id._class)) ? _class : null;
7337       };
7338       //id._class = null;
7339       return true;
7340    }
7341    else if((prop = eClass_FindProperty(_class, id.string, privateModule)))
7342    {
7343       if(!prop.dataType)
7344          ProcessPropertyType(prop);
7345       exp.expType = prop.dataType;
7346       if(prop.dataType) prop.dataType.refCount++;
7347       return true;
7348    }
7349    else if((member = eClass_FindDataMember(_class, id.string, privateModule, null, null)))
7350    {
7351       if(!member.dataType)
7352          member.dataType = ProcessTypeString(member.dataTypeString, false);
7353       exp.expType = member.dataType;
7354       if(member.dataType) member.dataType.refCount++;
7355       return true;
7356    }
7357    else if((classProp = eClass_FindClassProperty(_class, id.string)))
7358    {
7359       if(!classProp.dataType)
7360          classProp.dataType = ProcessTypeString(classProp.dataTypeString, false);
7361
7362       if(classProp.constant)
7363       {
7364          FreeExpContents(exp);
7365
7366          exp.isConstant = true;
7367          if(classProp.dataType.kind == pointerType && classProp.dataType.type.kind == charType)
7368          {
7369             //char constant[256];
7370             exp.type = stringExp;
7371             exp.constant = QMkString((char *)(uintptr)classProp.Get(_class));
7372          }
7373          else
7374          {
7375             char constant[256];
7376             exp.type = constantExp;
7377             sprintf(constant, "%d", (int)classProp.Get(_class));
7378             exp.constant = CopyString(constant);
7379          }
7380       }
7381       else
7382       {
7383          // TO IMPLEMENT...
7384       }
7385
7386       exp.expType = classProp.dataType;
7387       if(classProp.dataType) classProp.dataType.refCount++;
7388       return true;
7389    }
7390    return false;
7391 }
7392
7393 static GlobalData ScanGlobalData(NameSpace nameSpace, char * name)
7394 {
7395    BinaryTree * tree = &nameSpace.functions;
7396    GlobalData data = (GlobalData)tree->FindString(name);
7397    NameSpace * child;
7398    if(!data)
7399    {
7400       for(child = (NameSpace *)nameSpace.nameSpaces.first; child; child = (NameSpace *)((BTNode)child).next)
7401       {
7402          data = ScanGlobalData(child, name);
7403          if(data)
7404             break;
7405       }
7406    }
7407    return data;
7408 }
7409
7410 static GlobalData FindGlobalData(char * name)
7411 {
7412    int start = 0, c;
7413    NameSpace * nameSpace;
7414    nameSpace = globalData;
7415    for(c = 0; name[c]; c++)
7416    {
7417       if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
7418       {
7419          NameSpace * newSpace;
7420          char * spaceName = new char[c - start + 1];
7421          strncpy(spaceName, name + start, c - start);
7422          spaceName[c-start] = '\0';
7423          newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
7424          delete spaceName;
7425          if(!newSpace)
7426             return null;
7427          nameSpace = newSpace;
7428          if(name[c] == ':') c++;
7429          start = c+1;
7430       }
7431    }
7432    if(c - start)
7433    {
7434       return ScanGlobalData(nameSpace, name + start);
7435    }
7436    return null;
7437 }
7438
7439 static int definedExpStackPos;
7440 static void * definedExpStack[512];
7441
7442 // This function makes checkedExp equivalent to newExp, ending up freeing newExp
7443 void ReplaceExpContents(Expression checkedExp, Expression newExp)
7444 {
7445    Expression prev = checkedExp.prev, next = checkedExp.next;
7446
7447    FreeExpContents(checkedExp);
7448    FreeType(checkedExp.expType);
7449    FreeType(checkedExp.destType);
7450
7451    *checkedExp = *newExp;
7452
7453    delete newExp;
7454
7455    checkedExp.prev = prev;
7456    checkedExp.next = next;
7457 }
7458
7459 void ApplyAnyObjectLogic(Expression e)
7460 {
7461    Type destType = /*(e.destType && e.destType.kind == ellipsisType) ? ellipsisDestType : */e.destType;
7462 #ifdef _DEBUG
7463    char debugExpString[4096];
7464    debugExpString[0] = '\0';
7465    PrintExpression(e, debugExpString);
7466 #endif
7467
7468    if(destType && (/*destType.classObjectType == ClassObjectType::typedObject || */destType.classObjectType == anyObject))
7469    {
7470       //if(e.destType && e.destType.kind == ellipsisType) usedEllipsis = true;
7471       //ellipsisDestType = destType;
7472       if(e && e.expType)
7473       {
7474          Type type = e.expType;
7475          Class _class = null;
7476          //Type destType = e.destType;
7477
7478          if(type.kind == classType && type._class && type._class.registered)
7479          {
7480             _class = type._class.registered;
7481          }
7482          else if(type.kind == subClassType)
7483          {
7484             _class = FindClass("ecere::com::Class").registered;
7485          }
7486          else
7487          {
7488             char string[1024] = "";
7489             Symbol classSym;
7490
7491             PrintTypeNoConst(type, string, false, true);
7492             classSym = FindClass(string);
7493             if(classSym) _class = classSym.registered;
7494          }
7495
7496          if((_class && (_class.type == enumClass || _class.type == unitClass || _class.type == bitClass || _class.type == systemClass) && strcmp(_class.fullName, "class") && strcmp(_class.fullName, "uintptr") && strcmp(_class.fullName, "intptr")) || // Patched so that class isn't considered SYSTEM...
7497             (!e.expType.classObjectType && (((type.kind != pointerType && type.kind != intPtrType && type.kind != subClassType && (type.kind != classType || !type._class || !type._class.registered || type._class.registered.type == structClass))) ||
7498             destType.byReference)))
7499          {
7500             if(!_class || strcmp(_class.fullName, "char *"))     // TESTING THIS WITH NEW String class...
7501             {
7502                Expression checkedExp = e, newExp;
7503
7504                while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7505                {
7506                   if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7507                   {
7508                      if(checkedExp.type == extensionCompoundExp)
7509                      {
7510                         checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7511                      }
7512                      else
7513                         checkedExp = checkedExp.list->last;
7514                   }
7515                   else if(checkedExp.type == castExp)
7516                      checkedExp = checkedExp.cast.exp;
7517                }
7518
7519                if(checkedExp && checkedExp.type == opExp && checkedExp.op.op == '*' && !checkedExp.op.exp1)
7520                {
7521                   newExp = checkedExp.op.exp2;
7522                   checkedExp.op.exp2 = null;
7523                   FreeExpContents(checkedExp);
7524
7525                   if(e.expType && e.expType.passAsTemplate)
7526                   {
7527                      char size[100];
7528                      ComputeTypeSize(e.expType);
7529                      sprintf(size, "%d", e.expType.size);   // Potential 32/64 Bootstrap issue
7530                      newExp = MkExpBrackets(MkListOne(MkExpOp(MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)),
7531                         MkDeclaratorPointer(MkPointer(null, null), null)), newExp), '+',
7532                            MkExpCall(MkExpIdentifier(MkIdentifier("__ENDIAN_PAD")), MkListOne(MkExpConstant(size))))));
7533                   }
7534
7535                   ReplaceExpContents(checkedExp, newExp);
7536                   e.byReference = true;
7537                }
7538                else if(!e.byReference || (_class && _class.type == noHeadClass))     // TESTING THIS HERE...
7539                {
7540                   Expression checkedExp; //, newExp;
7541
7542                   {
7543                      // TODO: Move code from debugTools.ec for hasAddress flag, this is just temporary
7544                      bool hasAddress =
7545                         e.type == identifierExp ||
7546                         (e.type == ExpressionType::memberExp && e.member.memberType == dataMember) ||
7547                         (e.type == ExpressionType::pointerExp && e.member.memberType == dataMember) ||
7548                         (e.type == opExp && !e.op.exp1 && e.op.op == '*') ||
7549                         e.type == indexExp;
7550
7551                      if(_class && _class.type != noHeadClass && _class.type != normalClass && _class.type != structClass && !hasAddress)
7552                      {
7553                         Context context = PushContext();
7554                         Declarator decl;
7555                         OldList * specs = MkList();
7556                         char typeString[1024];
7557                         Expression newExp { };
7558
7559                         typeString[0] = '\0';
7560                         *newExp = *e;
7561
7562                         //if(e.destType) e.destType.refCount++;
7563                         // if(exp.expType) exp.expType.refCount++;
7564                         newExp.prev = null;
7565                         newExp.next = null;
7566                         newExp.expType = null;
7567
7568                         PrintTypeNoConst(e.expType, typeString, false, true);
7569                         decl = SpecDeclFromString(typeString, specs, null);
7570                         newExp.destType = ProcessType(specs, decl);
7571
7572                         curContext = context;
7573
7574                         // We need a current compound for this
7575                         if(curCompound)
7576                         {
7577                            char name[100];
7578                            OldList * stmts = MkList();
7579                            e.type = extensionCompoundExp;
7580                            sprintf(name, "__internalValue%03X", internalValueCounter++);
7581                            if(!curCompound.compound.declarations)
7582                               curCompound.compound.declarations = MkList();
7583                            curCompound.compound.declarations->Insert(null, MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(name)), null))));
7584                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(name)), '=', newExp))));
7585                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier(name)))));
7586                            e.compound = MkCompoundStmt(null, stmts);
7587                         }
7588                         else
7589                            printf("libec: compiler error, curCompound is null in ApplyAnyObjectLogic\n");
7590
7591                         /*
7592                         e.compound = MkCompoundStmt(
7593                            MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(
7594                               MkDeclaratorIdentifier(MkIdentifier("__internalValue")), MkInitializerAssignment(newExp))))),
7595
7596                            MkListOne(MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier("__internalValue"))))));
7597                         */
7598
7599                         {
7600                            Type type = e.destType;
7601                            e.destType = { };
7602                            CopyTypeInto(e.destType, type);
7603                            e.destType.refCount = 1;
7604                            e.destType.classObjectType = none;
7605                            FreeType(type);
7606                         }
7607
7608                         e.compound.compound.context = context;
7609                         PopContext(context);
7610                         curContext = context.parent;
7611                      }
7612                   }
7613
7614                   // TODO: INTEGRATE THIS WITH VERSION ABOVE WHICH WAS ADDED TO ENCOMPASS OTHER CASE (*pointer)
7615                   checkedExp = e;
7616                   while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7617                   {
7618                      if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7619                      {
7620                         if(checkedExp.type == extensionCompoundExp)
7621                         {
7622                            checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7623                         }
7624                         else
7625                            checkedExp = checkedExp.list->last;
7626                      }
7627                      else if(checkedExp.type == castExp)
7628                         checkedExp = checkedExp.cast.exp;
7629                   }
7630                   {
7631                      Expression operand { };
7632                      operand = *checkedExp;
7633                      checkedExp.Clear();
7634                      checkedExp.destType = ProcessTypeString("void *", false);
7635                      checkedExp.expType = checkedExp.destType;
7636                      checkedExp.destType.refCount++;
7637
7638                      checkedExp.type = opExp;
7639                      checkedExp.op.op = '&';
7640                      checkedExp.op.exp1 = null;
7641                      checkedExp.op.exp2 = operand;
7642
7643                      //newExp = MkExpOp(null, '&', checkedExp);
7644                   }
7645                   //ReplaceExpContents(checkedExp, newExp);
7646                }
7647             }
7648          }
7649       }
7650    }
7651    {
7652       // If expression type is a simple class, make it an address
7653       // FixReference(e, true);
7654    }
7655 //#if 0
7656    if((!destType || destType.kind == ellipsisType || destType.kind == voidType) && e.expType && (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7657       (e.expType.byReference || (e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7658          (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass ) )))
7659    {
7660       if(e.expType.classObjectType && destType && destType.classObjectType) //e.expType.kind == classType && e.expType._class && e.expType._class.registered && !strcmp(e.expType._class.registered.name, "class"))
7661       {
7662          return;  // LEAVE THIS CASE (typed_object & :: methods 's this) TO PASS 2 FOR NOW
7663       }
7664       else
7665       {
7666          Expression thisExp { };
7667
7668          *thisExp = *e;
7669          thisExp.prev = null;
7670          thisExp.next = null;
7671          e.Clear();
7672
7673          e.type = bracketsExp;
7674          e.list = MkListOne(MkExpOp(null, '*', thisExp.type == identifierExp ? thisExp : MkExpBrackets(MkListOne(thisExp))));
7675          if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && thisExp.expType._class.registered.type == noHeadClass)
7676             ((Expression)e.list->first).byReference = true;
7677
7678          /*if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && !strcmp(thisExp.expType._class.registered.name, "class"))
7679          {
7680             e.expType = thisExp.expType;
7681             e.expType.refCount++;
7682          }
7683          else*/
7684          {
7685             e.expType = { };
7686             CopyTypeInto(e.expType, thisExp.expType);
7687             e.expType.byReference = false;
7688             e.expType.refCount = 1;
7689
7690             if(e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7691                (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass))
7692             {
7693                e.expType.classObjectType = none;
7694             }
7695          }
7696       }
7697    }
7698 // TOFIX: Try this for a nice IDE crash!
7699 //#endif
7700    // The other way around
7701    else
7702 //#endif
7703    if(destType && e.expType &&
7704          //e.expType.kind == classType && e.expType._class && e.expType._class.registered && !strcmp(e.expType._class.registered.name, "class") &&
7705          (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7706          !destType.classObjectType && /*(destType.kind != pointerType || !destType.type || destType.type.kind != voidType) &&*/ destType.kind != voidType)
7707    {
7708       if(destType.kind == ellipsisType)
7709       {
7710          Compiler_Error($"Unspecified type\n");
7711       }
7712       else if(!(destType.truth && e.expType.kind == classType && e.expType._class && e.expType._class.registered && e.expType._class.registered.type == structClass))
7713       {
7714          bool byReference = e.expType.byReference;
7715          Expression thisExp { };
7716          Declarator decl;
7717          OldList * specs = MkList();
7718          char typeString[1024]; // Watch buffer overruns
7719          Type type;
7720          ClassObjectType backupClassObjectType;
7721          bool backupByReference;
7722
7723          if(e.expType.kind == classType && e.expType._class && e.expType._class.registered && strcmp(e.expType._class.registered.name, "class"))
7724             type = e.expType;
7725          else
7726             type = destType;
7727
7728          backupClassObjectType = type.classObjectType;
7729          backupByReference = type.byReference;
7730
7731          type.classObjectType = none;
7732          type.byReference = false;
7733
7734          typeString[0] = '\0';
7735          PrintType(type, typeString, false, true);
7736          decl = SpecDeclFromString(typeString, specs, null);
7737
7738          type.classObjectType = backupClassObjectType;
7739          type.byReference = backupByReference;
7740
7741          *thisExp = *e;
7742          thisExp.prev = null;
7743          thisExp.next = null;
7744          e.Clear();
7745
7746          if( ( type.kind == classType && type._class && type._class.registered &&
7747                    (type._class.registered.type == systemClass || type._class.registered.type == bitClass ||
7748                     type._class.registered.type == enumClass || type._class.registered.type == unitClass) ) ||
7749              (type.kind != pointerType && type.kind != intPtrType && type.kind != arrayType && type.kind != classType) ||
7750              (!destType.byReference && byReference && (destType.kind != pointerType || type.kind != pointerType)))
7751          {
7752             bool passAsTemplate = thisExp.destType.passAsTemplate;
7753             Type t;
7754
7755             destType.refCount++;
7756
7757             e.type = opExp;
7758             e.op.op = '*';
7759             e.op.exp1 = null;
7760             e.op.exp2 = MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), thisExp);
7761
7762             t = { };
7763             CopyTypeInto(t, thisExp.destType);
7764             t.passAsTemplate = false;
7765             FreeType(thisExp.destType);
7766             thisExp.destType = t;
7767
7768             t = { };
7769             CopyTypeInto(t, destType);
7770             t.passAsTemplate = passAsTemplate;
7771             FreeType(destType);
7772             destType = t;
7773             destType.refCount = 0;
7774
7775             e.expType = { };
7776             CopyTypeInto(e.expType, type);
7777             if(type.passAsTemplate)
7778             {
7779                e.expType.classObjectType = none;
7780                e.expType.passAsTemplate = false;
7781             }
7782             e.expType.byReference = false;
7783             e.expType.refCount = 1;
7784          }
7785          else
7786          {
7787             e.type = castExp;
7788             e.cast.typeName = MkTypeName(specs, decl);
7789             e.cast.exp = thisExp;
7790             e.byReference = true;
7791             e.expType = type;
7792             type.refCount++;
7793          }
7794
7795          if(e.destType)
7796             FreeType(e.destType);
7797
7798          e.destType = destType;
7799          destType.refCount++;
7800       }
7801    }
7802 }
7803
7804 void ApplyLocation(Expression exp, Location loc)
7805 {
7806    exp.loc = loc;
7807    switch(exp.type)
7808    {
7809       case opExp:
7810          if(exp.op.exp1) ApplyLocation(exp.op.exp1, loc);
7811          if(exp.op.exp2) ApplyLocation(exp.op.exp2, loc);
7812          break;
7813       case bracketsExp:
7814          if(exp.list)
7815          {
7816             Expression e;
7817             for(e = exp.list->first; e; e = e.next)
7818                ApplyLocation(e, loc);
7819          }
7820          break;
7821       case indexExp:
7822          if(exp.index.index)
7823          {
7824             Expression e;
7825             for(e = exp.index.index->first; e; e = e.next)
7826                ApplyLocation(e, loc);
7827          }
7828          if(exp.index.exp)
7829             ApplyLocation(exp.index.exp, loc);
7830          break;
7831       case callExp:
7832          if(exp.call.arguments)
7833          {
7834             Expression arg;
7835             for(arg = exp.call.arguments->first; arg; arg = arg.next)
7836                ApplyLocation(arg, loc);
7837          }
7838          if(exp.call.exp)
7839             ApplyLocation(exp.call.exp, loc);
7840          break;
7841       case memberExp:
7842       case pointerExp:
7843          if(exp.member.exp)
7844             ApplyLocation(exp.member.exp, loc);
7845          break;
7846       case castExp:
7847          if(exp.cast.exp)
7848             ApplyLocation(exp.cast.exp, loc);
7849          break;
7850       case conditionExp:
7851          if(exp.cond.exp)
7852          {
7853             Expression e;
7854             for(e = exp.cond.exp->first; e; e = e.next)
7855                ApplyLocation(e, loc);
7856          }
7857          if(exp.cond.cond)
7858             ApplyLocation(exp.cond.cond, loc);
7859          if(exp.cond.elseExp)
7860             ApplyLocation(exp.cond.elseExp, loc);
7861          break;
7862       case vaArgExp:
7863          if(exp.vaArg.exp)
7864             ApplyLocation(exp.vaArg.exp, loc);
7865          break;
7866       default:
7867          break;
7868    }
7869 }
7870
7871 bool RelatedUnits(Class c1, Class c2)
7872 {
7873    if(c1.base.type == unitClass) c1 = c1.base;
7874    if(c2.base.type == unitClass) c2 = c2.base;
7875    return c1 == c2;
7876 }
7877
7878 void ProcessExpressionType(Expression exp)
7879 {
7880    bool unresolved = false;
7881    Location oldyylloc = yylloc;
7882    bool notByReference = false;
7883 #ifdef _DEBUG
7884    char debugExpString[4096];
7885    debugExpString[0] = '\0';
7886    PrintExpression(exp, debugExpString);
7887 #endif
7888    if(!exp || exp.expType)
7889       return;
7890
7891    //eSystem_Logf("%s\n", expString);
7892
7893    // Testing this here
7894    yylloc = exp.loc;
7895    switch(exp.type)
7896    {
7897       case identifierExp:
7898       {
7899          Identifier id = exp.identifier;
7900          if(!id || !topContext) return;
7901
7902          // DOING THIS LATER NOW...
7903          if(id._class && id._class.name)
7904          {
7905             id.classSym = id._class.symbol; // FindClass(id._class.name);
7906             /* TODO: Name Space Fix ups
7907             if(!id.classSym)
7908                id.nameSpace = eSystem_FindNameSpace(privateModule, id._class.name);
7909             */
7910          }
7911
7912          /* WHY WAS THIS COMMENTED OUT? if(!strcmp(id.string, "__thisModule"))
7913          {
7914             exp.expType = ProcessTypeString("Module", true);
7915             break;
7916          }
7917          else */
7918          if(!strcmp(id.string, "__runtimePlatform"))
7919          {
7920             exp.expType = ProcessTypeString("ecere::com::Platform", true);
7921             break;
7922          }
7923          else if(strstr(id.string, "__ecereClass") == id.string)
7924          {
7925             exp.expType = ProcessTypeString("ecere::com::Class", true);
7926             break;
7927          }
7928          else if(id._class && (id.classSym || (id._class.name && !strcmp(id._class.name, "property"))))
7929          {
7930             // Added this here as well
7931             ReplaceClassMembers(exp, thisClass);
7932             if(exp.type != identifierExp)
7933             {
7934                ProcessExpressionType(exp);
7935                break;
7936             }
7937
7938             if(id.classSym && ResolveIdWithClass(exp, id.classSym.registered, false))
7939                break;
7940          }
7941          else
7942          {
7943             Symbol symbol = null;
7944             bool findInGlobal = false;
7945             if(!topContext.parent && exp.destType && exp.destType.kind == classType && exp.destType._class && exp.destType._class.registered && exp.destType._class.registered.type == enumClass)
7946                findInGlobal = true;  // In global context, look at enum values first
7947             else
7948                symbol = FindSymbol(id.string, curContext, topContext /*exp.destType ? topContext : globalContext*/, false, id._class && id._class.name == null);
7949
7950             // Enums should be resolved here (Special pass in opExp to fix identifiers not seen as enum on the first pass)
7951             if(!symbol/* && exp.destType*/)
7952             {
7953                if(exp.destType && CheckExpressionType(exp, exp.destType, false, false))
7954                   break;
7955                else
7956                {
7957                   if(thisClass && strcmp(id.string, "this"))
7958                   {
7959                      ReplaceClassMembers(exp, thisClass ? thisClass : currentClass);
7960                      if(exp.type != identifierExp)
7961                      {
7962                         ProcessExpressionType(exp);
7963                         break;
7964                      }
7965                   }
7966                   // Static methods called from inside the _class
7967                   else if(currentClass && !id._class)
7968                   {
7969                      if(ResolveIdWithClass(exp, currentClass, true))
7970                         break;
7971                   }
7972                   symbol = FindSymbol(id.string, topContext.parent, globalContext, false, id._class && id._class.name == null);
7973                }
7974             }
7975             if(findInGlobal)
7976                symbol = FindSymbol(id.string, curContext, topContext, false, id._class && id._class.name == null);
7977
7978             // If we manage to resolve this symbol
7979             if(symbol)
7980             {
7981                Type type = symbol.type;
7982                Class _class = (type && type.kind == classType && type._class) ? type._class.registered : null;
7983
7984                if(_class && !strcmp(id.string, "this") && !type.classObjectType)
7985                {
7986                   Context context = SetupTemplatesContext(_class);
7987                   type = ReplaceThisClassType(_class);
7988                   FinishTemplatesContext(context);
7989                   if(type) type.refCount = 0;   // We'll be incrementing it right below...
7990                }
7991
7992                FreeSpecifier(id._class);
7993                id._class = null;
7994                delete id.string;
7995                id.string = CopyString(symbol.string);
7996
7997                id.classSym = null;
7998                exp.expType = type;
7999                if(type)
8000                   type.refCount++;
8001
8002                                                 // Commented this out, it was making non-constant enum parameters seen as constant
8003                                                 // enums should have been resolved by ResolveIdWithClass, changed to constantExp and marked as constant
8004                if(type && (type.kind == enumType /*|| (_class && _class.type == enumClass)*/))
8005                   // Add missing cases here... enum Classes...
8006                   exp.isConstant = true;
8007
8008                // TOCHECK: Why was !strcmp(id.string, "this") commented out?
8009                if(symbol.isParam || !strcmp(id.string, "this"))
8010                {
8011                   if(_class && _class.type == structClass && !type.declaredWithStruct)
8012                      exp.byReference = true;
8013
8014                   //TESTING COMMENTING THIS OUT IN FAVOR OF ApplyAnyObjectLogic
8015                   /*if(type && _class && (type.classObjectType == typedObject || type.classObjectType == anyObject) &&
8016                      ((_class.type == unitClass || _class.type == enumClass || _class.type == bitClass) ||
8017                      (type.byReference && (_class.type == normalClass || _class.type == noHeadClass))))
8018                   {
8019                      Identifier id = exp.identifier;
8020                      exp.type = bracketsExp;
8021                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(id)));
8022                   }*/
8023                }
8024
8025                if(symbol.isIterator)
8026                {
8027                   if(symbol.isIterator == 3)
8028                   {
8029                      exp.type = bracketsExp;
8030                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(exp.identifier)));
8031                      ((Expression)exp.list->first).op.exp2.expType = exp.expType;
8032                      exp.expType = null;
8033                      ProcessExpressionType(exp);
8034                   }
8035                   else if(symbol.isIterator != 4)
8036                   {
8037                      exp.type = memberExp;
8038                      exp.member.exp = MkExpIdentifier(exp.identifier);
8039                      exp.member.exp.expType = exp.expType;
8040                      /*if(symbol.isIterator == 6)
8041                         exp.member.member = MkIdentifier("key");
8042                      else*/
8043                         exp.member.member = MkIdentifier("data");
8044                      exp.expType = null;
8045                      ProcessExpressionType(exp);
8046                   }
8047                }
8048                break;
8049             }
8050             else
8051             {
8052                DefinedExpression definedExp = null;
8053                if(thisNameSpace && !(id._class && !id._class.name))
8054                {
8055                   char name[1024];
8056                   strcpy(name, thisNameSpace);
8057                   strcat(name, "::");
8058                   strcat(name, id.string);
8059                   definedExp = eSystem_FindDefine(privateModule, name);
8060                }
8061                if(!definedExp)
8062                   definedExp = eSystem_FindDefine(privateModule, id.string);
8063                if(definedExp)
8064                {
8065                   int c;
8066                   for(c = 0; c<definedExpStackPos; c++)
8067                      if(definedExpStack[c] == definedExp)
8068                         break;
8069                   if(c == definedExpStackPos && c < sizeof(definedExpStack) / sizeof(void *))
8070                   {
8071                      Location backupYylloc = yylloc;
8072                      File backInput = fileInput;
8073                      definedExpStack[definedExpStackPos++] = definedExp;
8074
8075                      fileInput = TempFile { };
8076                      fileInput.Write(definedExp.value, 1, strlen(definedExp.value));
8077                      fileInput.Seek(0, start);
8078
8079                      echoOn = false;
8080                      parsedExpression = null;
8081                      resetScanner();
8082                      expression_yyparse();
8083                      delete fileInput;
8084                      if(backInput)
8085                         fileInput = backInput;
8086
8087                      yylloc = backupYylloc;
8088
8089                      if(parsedExpression)
8090                      {
8091                         FreeIdentifier(id);
8092                         exp.type = bracketsExp;
8093                         exp.list = MkListOne(parsedExpression);
8094                         ApplyLocation(parsedExpression, yylloc);
8095                         ProcessExpressionType(exp);
8096                         definedExpStackPos--;
8097                         return;
8098                      }
8099                      definedExpStackPos--;
8100                   }
8101                   else
8102                   {
8103                      if(inCompiler)
8104                      {
8105                         Compiler_Error($"Recursion in defined expression %s\n", id.string);
8106                      }
8107                   }
8108                }
8109                else
8110                {
8111                   GlobalData data = null;
8112                   if(thisNameSpace && !(id._class && !id._class.name))
8113                   {
8114                      char name[1024];
8115                      strcpy(name, thisNameSpace);
8116                      strcat(name, "::");
8117                      strcat(name, id.string);
8118                      data = FindGlobalData(name);
8119                   }
8120                   if(!data)
8121                      data = FindGlobalData(id.string);
8122                   if(data)
8123                   {
8124                      DeclareGlobalData(curExternal, data);
8125                      exp.expType = data.dataType;
8126                      if(data.dataType) data.dataType.refCount++;
8127
8128                      delete id.string;
8129                      id.string = CopyString(data.fullName);
8130                      FreeSpecifier(id._class);
8131                      id._class = null;
8132
8133                      break;
8134                   }
8135                   else
8136                   {
8137                      GlobalFunction function = null;
8138                      if(thisNameSpace && !(id._class && !id._class.name))
8139                      {
8140                         char name[1024];
8141                         strcpy(name, thisNameSpace);
8142                         strcat(name, "::");
8143                         strcat(name, id.string);
8144                         function = eSystem_FindFunction(privateModule, name);
8145                      }
8146                      if(!function)
8147                         function = eSystem_FindFunction(privateModule, id.string);
8148                      if(function)
8149                      {
8150                         char name[1024];
8151                         delete id.string;
8152                         id.string = CopyString(function.name);
8153                         name[0] = 0;
8154
8155                         if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
8156                            strcpy(name, "__ecereFunction_");
8157                         FullClassNameCat(name, id.string, false); // Why is this using FullClassNameCat ?
8158                         if(DeclareFunction(curExternal, function, name))
8159                         {
8160                            delete id.string;
8161                            id.string = CopyString(name);
8162                         }
8163                         exp.expType = function.dataType;
8164                         if(function.dataType) function.dataType.refCount++;
8165
8166                         FreeSpecifier(id._class);
8167                         id._class = null;
8168
8169                         break;
8170                      }
8171                   }
8172                }
8173             }
8174          }
8175          unresolved = true;
8176          break;
8177       }
8178       case instanceExp:
8179       {
8180          // Class _class;
8181          // Symbol classSym;
8182
8183          if(!exp.instance._class)
8184          {
8185             if(exp.destType && exp.destType.kind == classType && exp.destType._class)
8186             {
8187                exp.instance._class = MkSpecifierName(exp.destType._class.string);
8188             }
8189          }
8190
8191          //classSym = FindClass(exp.instance._class.fullName);
8192          //_class = classSym ? classSym.registered : null;
8193
8194          ProcessInstantiationType(exp.instance);
8195
8196          exp.isConstant = exp.instance.isConstant;
8197
8198          /*
8199          if(_class.type == unitClass && _class.base.type != systemClass)
8200          {
8201             {
8202                Type destType = exp.destType;
8203
8204                exp.destType = MkClassType(_class.base.fullName);
8205                exp.expType = MkClassType(_class.fullName);
8206                CheckExpressionType(exp, exp.destType, true);
8207
8208                exp.destType = destType;
8209             }
8210             exp.expType = MkClassType(_class.fullName);
8211          }
8212          else*/
8213          if(exp.instance._class)
8214          {
8215             exp.expType = MkClassType(exp.instance._class.name);
8216             /*if(exp.expType._class && exp.expType._class.registered &&
8217                (exp.expType._class.registered.type == normalClass || exp.expType._class.registered.type == noHeadClass))
8218                exp.expType.byReference = true;*/
8219          }
8220          break;
8221       }
8222       case constantExp:
8223       {
8224          if(!exp.expType)
8225          {
8226             char * constant = exp.constant;
8227             Type type
8228             {
8229                refCount = 1;
8230                constant = true;
8231             };
8232             exp.expType = type;
8233
8234             if(constant[0] == '\'')
8235             {
8236                if((int)((byte *)constant)[1] > 127)
8237                {
8238                   int nb;
8239                   unichar ch = UTF8GetChar(constant + 1, &nb);
8240                   if(nb < 2) ch = constant[1];
8241                   delete constant;
8242                   exp.constant = PrintUInt(ch);
8243                   // type.kind = (ch > 0xFFFF) ? intType : shortType;
8244                   type.kind = classType; //(ch > 0xFFFF) ? intType : shortType;
8245                   type._class = FindClass("unichar");
8246
8247                   type.isSigned = false;
8248                }
8249                else
8250                {
8251                   type.kind = charType;
8252                   type.isSigned = true;
8253                }
8254             }
8255             else
8256             {
8257                char * dot = strchr(constant, '.');
8258                bool isHex = (constant[0] == '0' && (constant[1] == 'x' || constant[1] == 'X'));
8259                char * exponent;
8260                if(isHex)
8261                {
8262                   exponent = strchr(constant, 'p');
8263                   if(!exponent) exponent = strchr(constant, 'P');
8264                }
8265                else
8266                {
8267                   exponent = strchr(constant, 'e');
8268                   if(!exponent) exponent = strchr(constant, 'E');
8269                }
8270
8271                if(dot || exponent)
8272                {
8273                   if(strchr(constant, 'f') || strchr(constant, 'F'))
8274                      type.kind = floatType;
8275                   else
8276                      type.kind = doubleType;
8277                   type.isSigned = true;
8278                }
8279                else
8280                {
8281                   bool isSigned = constant[0] == '-';
8282                   char * endP = null;
8283                   int64 i64 = strtoll(constant, &endP, 0);
8284                   uint64 ui64 = strtoull(constant, &endP, 0);
8285                   bool is64Bit = endP && (!strcmp(endP, "LL") || !strcmp(endP, "ll") || !strcmp(endP, "LLU") || !strcmp(endP, "llu") || !strcmp(endP, "ull") || !strcmp(endP, "ULL"));
8286                   bool forceUnsigned = endP && (!strcmp(endP, "U") || !strcmp(endP, "u") || !strcmp(endP, "LLU") || !strcmp(endP, "llu") || !strcmp(endP, "ull") || !strcmp(endP, "ULL"));
8287                   if(isSigned)
8288                   {
8289                      if(i64 < MININT)
8290                         is64Bit = true;
8291                   }
8292                   else
8293                   {
8294                      if(ui64 > MAXINT)
8295                      {
8296                         if(ui64 > MAXDWORD)
8297                         {
8298                            is64Bit = true;
8299                            if(ui64 <= MAXINT64 && (constant[0] != '0' || !constant[1]))
8300                               isSigned = true;
8301                         }
8302                      }
8303                      else if(constant[0] != '0' || !constant[1])
8304                         isSigned = true;
8305                   }
8306                   if(forceUnsigned)
8307                      isSigned = false;
8308                   type.kind = is64Bit ? int64Type : intType;
8309                   type.isSigned = isSigned;
8310                }
8311             }
8312             exp.isConstant = true;
8313             if(exp.destType && exp.destType.kind == doubleType)
8314                type.kind = doubleType;
8315             else if(exp.destType && exp.destType.kind == floatType)
8316                type.kind = floatType;
8317             else if(exp.destType && exp.destType.kind == int64Type)
8318                type.kind = int64Type;
8319          }
8320          break;
8321       }
8322       case stringExp:
8323       {
8324          exp.isConstant = true;      // Why wasn't this constant?
8325          exp.expType = Type
8326          {
8327             refCount = 1;
8328             kind = pointerType;
8329             type = Type
8330             {
8331                refCount = 1;
8332                kind = exp.wideString ? shortType : charType;
8333                constant = true;
8334                isSigned = exp.wideString ? false : true;
8335             }
8336          };
8337          break;
8338       }
8339       case newExp:
8340       case new0Exp:
8341          ProcessExpressionType(exp._new.size);
8342          exp.expType = Type
8343          {
8344             refCount = 1;
8345             kind = pointerType;
8346             type = ProcessType(exp._new.typeName.qualifiers, exp._new.typeName.declarator);
8347          };
8348          DeclareType(curExternal, exp.expType.type, true, false);
8349          break;
8350       case renewExp:
8351       case renew0Exp:
8352          ProcessExpressionType(exp._renew.size);
8353          ProcessExpressionType(exp._renew.exp);
8354          exp.expType = Type
8355          {
8356             refCount = 1;
8357             kind = pointerType;
8358             type = ProcessType(exp._renew.typeName.qualifiers, exp._renew.typeName.declarator);
8359          };
8360          DeclareType(curExternal, exp.expType.type, true, false);
8361          break;
8362       case opExp:
8363       {
8364          bool assign = false, boolResult = false, boolOps = false;
8365          Type type1 = null, type2 = null;
8366          bool useDestType = false, useSideType = false;
8367          Location oldyylloc = yylloc;
8368          bool useSideUnit = false;
8369          Class destClass = (exp.destType && exp.destType.kind == classType && exp.destType._class) ? exp.destType._class.registered : null;
8370          bool powerOp = false, relationOp = false;
8371          Class c1 = null, c2 = null;
8372
8373          // Dummy type to prevent ProcessExpression of operands to say unresolved identifiers yet
8374          Type dummy
8375          {
8376             count = 1;
8377             refCount = 1;
8378          };
8379
8380          switch(exp.op.op)
8381          {
8382             // Assignment Operators
8383             case '=':
8384             case MUL_ASSIGN:
8385             case DIV_ASSIGN:
8386             case MOD_ASSIGN:
8387             case ADD_ASSIGN:
8388             case SUB_ASSIGN:
8389             case LEFT_ASSIGN:
8390             case RIGHT_ASSIGN:
8391             case AND_ASSIGN:
8392             case XOR_ASSIGN:
8393             case OR_ASSIGN:
8394                assign = true;
8395                break;
8396             // boolean Operators
8397             case '!':
8398                // Expect boolean operators
8399                //boolOps = true;
8400                //boolResult = true;
8401                break;
8402             case AND_OP:
8403             case OR_OP:
8404                // Expect boolean operands
8405                boolOps = true;
8406                boolResult = true;
8407                break;
8408             // Comparisons
8409             case EQ_OP:
8410             case '<':
8411             case '>':
8412             case LE_OP:
8413             case GE_OP:
8414             case NE_OP:
8415                // Gives boolean result
8416                boolResult = true;
8417                useSideType = true;
8418                relationOp = true;
8419                break;
8420             case '+':
8421             case '-':
8422                useSideUnit = true;
8423                useSideType = true;
8424                useDestType = true;
8425                break;
8426
8427             case LEFT_OP:
8428             case RIGHT_OP:
8429                // useSideType = true;
8430                // useDestType = true;
8431                break;
8432
8433             case '|':
8434             case '^':
8435                useSideType = true;
8436                useDestType = true;
8437                break;
8438
8439             case '/':
8440             case '%':
8441                useSideType = true;
8442                useDestType = true;
8443                if(exp.op.op == '/') powerOp = true;
8444                break;
8445             case '&':
8446             case '*':
8447                if(exp.op.exp1)
8448                {
8449                   // For & operator, useDestType nicely ensures the result will fit in a bool (TODO: Fix for generic enum)
8450                   useSideType = true;
8451                   useDestType = true;
8452                   if(exp.op.op == '*') powerOp = true;
8453                }
8454                break;
8455
8456             /*// Implement speed etc.
8457             case '*':
8458             case '/':
8459                break;
8460             */
8461          }
8462          if(exp.op.op == '&')
8463          {
8464             // Added this here earlier for Iterator address as key
8465             if(!exp.op.exp1 && exp.op.exp2 && exp.op.exp2.type == identifierExp && exp.op.exp2.identifier)
8466             {
8467                Identifier id = exp.op.exp2.identifier;
8468                Symbol symbol = FindSymbol(id.string, curContext, topContext, false, id._class && id._class.name == null);
8469                if(symbol && symbol.isIterator == 2)
8470                {
8471                   exp.type = memberExp;
8472                   exp.member.exp = exp.op.exp2;
8473                   exp.member.member = MkIdentifier("key");
8474                   exp.expType = null;
8475                   exp.op.exp2.expType = symbol.type;
8476                   symbol.type.refCount++;
8477                   ProcessExpressionType(exp);
8478                   FreeType(dummy);
8479                   break;
8480                }
8481                // exp.op.exp2.usage.usageRef = true;
8482             }
8483          }
8484
8485          //dummy.kind = TypeDummy;
8486          if(exp.op.exp1)
8487          {
8488             // Added this check here to use the dest type only for units derived from the base unit
8489             // So that untyped units will use the side unit as opposed to the untyped destination unit
8490             // This fixes (#771) sin(Degrees { 5 } + 5) to be equivalent to sin(Degrees { 10 }), since sin expects a generic Angle
8491             if(exp.op.exp2 && useSideUnit && useDestType && destClass && destClass.type == unitClass && destClass.base.type != unitClass)
8492                useDestType = false;
8493
8494             if(destClass && useDestType &&
8495               ((destClass.type == unitClass && useSideUnit) || destClass.type == enumClass || destClass.type == bitClass))
8496
8497               //(exp.destType._class.registered.type == unitClass || exp.destType._class.registered.type == enumClass) && useDestType)
8498             {
8499                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8500                exp.op.exp1.destType = exp.destType;
8501                exp.op.exp1.opDestType = true;
8502                if(exp.destType)
8503                   exp.destType.refCount++;
8504             }
8505             else if(!assign)
8506             {
8507                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8508                exp.op.exp1.destType = dummy;
8509                dummy.refCount++;
8510                if(powerOp)
8511                   exp.op.exp1.opDestType = true;
8512                if(relationOp)
8513                   exp.op.exp1.usedInComparison = true;
8514             }
8515             if(exp.op.op == '+' || exp.op.op == '-')
8516             {
8517                if(exp.opDestType)
8518                   exp.op.exp1.parentOpDestType = true;
8519                if(exp.usedInComparison)
8520                   exp.op.exp1.usedInComparison = true;
8521             }
8522
8523             // TESTING THIS HERE...
8524             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count++;
8525                ProcessExpressionType(exp.op.exp1);
8526             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count--;
8527
8528             exp.op.exp1.opDestType = false;
8529             exp.op.exp1.usedInComparison = false;
8530
8531             // Fix for unit and ++ / --
8532             if(!exp.op.exp2 && (exp.op.op == INC_OP || exp.op.op == DEC_OP) && exp.op.exp1.expType && exp.op.exp1.expType.kind == classType &&
8533                exp.op.exp1.expType._class && exp.op.exp1.expType._class.registered && exp.op.exp1.expType._class.registered.type == unitClass)
8534             {
8535                exp.op.exp2 = MkExpConstant("1");
8536                exp.op.op = exp.op.op == INC_OP ? ADD_ASSIGN : SUB_ASSIGN;
8537                assign = true;
8538             }
8539
8540             if(exp.op.exp1.destType == dummy)
8541             {
8542                FreeType(dummy);
8543                exp.op.exp1.destType = null;
8544             }
8545
8546             if(exp.op.exp2)
8547             {
8548                if(!assign && exp.op.exp1.expType && (exp.op.exp1.expType.kind == charType || exp.op.exp1.expType.kind == shortType))
8549                {
8550                   Type type { kind = intType, isSigned = true, refCount = 1, signedBeforePromotion = exp.op.exp1.expType.isSigned, bitMemberSize = exp.op.exp1.expType.bitMemberSize, promotedFrom = exp.op.exp1.expType.kind };
8551                   FreeType(exp.op.exp1.expType);
8552                   exp.op.exp1.expType = type;
8553                }
8554             }
8555
8556             type1 = exp.op.exp1.expType;
8557          }
8558
8559          if(exp.op.exp2)
8560          {
8561             char expString[10240];
8562             expString[0] = '\0';
8563             if(exp.op.exp2.type == instanceExp && !exp.op.exp2.instance._class)
8564             {
8565                if(exp.op.exp1)
8566                {
8567                   exp.op.exp2.destType = exp.op.exp1.expType;
8568                   if(exp.op.exp1.expType)
8569                      exp.op.exp1.expType.refCount++;
8570                }
8571                else
8572                {
8573                   exp.op.exp2.destType = exp.destType;
8574                   if(!exp.op.exp1 || (exp.op.op != '&' && exp.op.op != '^'))
8575                      exp.op.exp2.opDestType = true;
8576                   if(exp.destType)
8577                      exp.destType.refCount++;
8578                }
8579
8580                if(type1) type1.refCount++;
8581                exp.expType = type1;
8582             }
8583             else if(assign)
8584             {
8585                if(inCompiler)
8586                   PrintExpression(exp.op.exp2, expString);
8587
8588                if(type1 && type1.kind == pointerType)
8589                {
8590                   if(exp.op.op == MUL_ASSIGN || exp.op.op == DIV_ASSIGN ||exp.op.op == MOD_ASSIGN ||exp.op.op == LEFT_ASSIGN ||exp.op.op == RIGHT_ASSIGN ||
8591                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN)
8592                      Compiler_Error($"operator %s illegal on pointer\n", exp.op.op);
8593                   else if(exp.op.op == '=')
8594                   {
8595                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8596                      exp.op.exp2.destType = type1;
8597                      if(type1)
8598                         type1.refCount++;
8599                   }
8600                }
8601                else
8602                {
8603                   // Don't convert to the type for those... (e.g.: Degrees a; a /= 2;)
8604                   if(exp.op.op == MUL_ASSIGN || exp.op.op == DIV_ASSIGN ||exp.op.op == MOD_ASSIGN ||exp.op.op == LEFT_ASSIGN ||exp.op.op == RIGHT_ASSIGN/* ||
8605                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN*/);
8606                   else
8607                   {
8608                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8609                      exp.op.exp2.destType = type1;
8610                      if(type1)
8611                         type1.refCount++;
8612                   }
8613                }
8614                if(type1) type1.refCount++;
8615                exp.expType = type1;
8616             }
8617             else if(destClass &&
8618                   ((destClass.type == unitClass && useDestType && useSideUnit) ||
8619                   (destClass.type == enumClass && useDestType)))
8620             {
8621                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8622                exp.op.exp2.destType = exp.destType;
8623                if(exp.op.op != '&' && exp.op.op != '^')
8624                   exp.op.exp2.opDestType = true;
8625                if(exp.destType)
8626                   exp.destType.refCount++;
8627             }
8628             else
8629             {
8630                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8631                exp.op.exp2.destType = dummy;
8632                dummy.refCount++;
8633                if(powerOp)
8634                   exp.op.exp2.opDestType = true;
8635                if(relationOp)
8636                   exp.op.exp2.usedInComparison = true;
8637             }
8638
8639             // TESTING THIS HERE... (DANGEROUS)
8640             if(type1 && boolResult && useSideType && type1.kind == classType && type1._class && type1._class.registered &&
8641                (type1._class.registered.type == bitClass || type1._class.registered.type == enumClass))
8642             {
8643                FreeType(exp.op.exp2.destType);
8644                exp.op.exp2.destType = type1;
8645                type1.refCount++;
8646             }
8647             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count++;
8648             // Cannot lose the cast on a sizeof
8649             if(exp.op.op == SIZEOF)
8650             {
8651                Expression e = exp.op.exp2;
8652                while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
8653                {
8654                   if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
8655                   {
8656                      if(e.type == extensionCompoundExp)
8657                         e = ((Statement)e.compound.compound.statements->last).expressions->last;
8658                      else
8659                         e = e.list->last;
8660                   }
8661                }
8662                if(e.type == castExp && e.cast.exp)
8663                   e.cast.exp.needCast = true;
8664             }
8665             if(exp.op.op == '+' || exp.op.op == '-')
8666             {
8667                if(exp.opDestType)
8668                   exp.op.exp2.parentOpDestType = true;
8669                if(exp.usedInComparison)
8670                   exp.op.exp2.usedInComparison = true;
8671             }
8672             ProcessExpressionType(exp.op.exp2);
8673             exp.op.exp2.opDestType = false;
8674             exp.op.exp2.usedInComparison = false;
8675             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count--;
8676
8677             if(!assign && (exp.op.exp1 || exp.op.op == '~'))
8678             {
8679                if(exp.op.exp2.expType && (exp.op.exp2.expType.kind == charType || exp.op.exp2.expType.kind == shortType))
8680                {
8681                   Type type { kind = intType, isSigned = true, refCount = 1, signedBeforePromotion = exp.op.exp2.expType.isSigned, bitMemberSize = exp.op.exp2.expType.bitMemberSize, promotedFrom = exp.op.exp2.expType.kind };
8682                   FreeType(exp.op.exp2.expType);
8683                   exp.op.exp2.expType = type;
8684                }
8685             }
8686
8687             if(assign && type1 && type1.kind == pointerType && exp.op.exp2.expType)
8688             {
8689                if(exp.op.exp2.expType.kind == intSizeType || exp.op.exp2.expType.kind == intPtrType || exp.op.exp2.expType.kind == int64Type || exp.op.exp2.expType.kind == intType || exp.op.exp2.expType.kind == shortType || exp.op.exp2.expType.kind == charType)
8690                {
8691                   if(exp.op.op != '=' && type1.type.kind == voidType)
8692                      Compiler_Error($"void *: unknown size\n");
8693                }
8694                else if(exp.op.exp2.expType.kind == pointerType || exp.op.exp2.expType.kind == arrayType || exp.op.exp2.expType.kind == functionType || exp.op.exp2.expType.kind == methodType||
8695                            (type1.type.kind == voidType && exp.op.exp2.expType.kind == classType && exp.op.exp2.expType._class.registered &&
8696                               (exp.op.exp2.expType._class.registered.type == normalClass ||
8697                               exp.op.exp2.expType._class.registered.type == structClass ||
8698                               exp.op.exp2.expType._class.registered.type == noHeadClass)))
8699                {
8700                   if(exp.op.op == ADD_ASSIGN)
8701                      Compiler_Error($"cannot add two pointers\n");
8702                }
8703                else if((exp.op.exp2.expType.kind == classType && type1.kind == pointerType && type1.type.kind == classType &&
8704                   type1.type._class == exp.op.exp2.expType._class && exp.op.exp2.expType._class.registered && exp.op.exp2.expType._class.registered.type == structClass))
8705                {
8706                   if(exp.op.op == ADD_ASSIGN)
8707                      Compiler_Error($"cannot add two pointers\n");
8708                }
8709                else if(inCompiler)
8710                {
8711                   char type1String[1024];
8712                   char type2String[1024];
8713                   type1String[0] = '\0';
8714                   type2String[0] = '\0';
8715
8716                   PrintType(exp.op.exp2.expType, type1String, false, true);
8717                   PrintType(type1, type2String, false, true);
8718                   ChangeCh(expString, '\n', ' ');
8719                   Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1String, type2String);
8720                }
8721             }
8722
8723             if(exp.op.exp2.destType == dummy)
8724             {
8725                FreeType(dummy);
8726                exp.op.exp2.destType = null;
8727             }
8728
8729             if(exp.op.op == '-' && !exp.op.exp1 && exp.op.exp2.expType && !exp.op.exp2.expType.isSigned)
8730             {
8731                type2 = { };
8732                type2.refCount = 1;
8733                CopyTypeInto(type2, exp.op.exp2.expType);
8734                type2.isSigned = true;
8735             }
8736             else if(exp.op.op == '~' && !exp.op.exp1 && exp.op.exp2.expType && (!exp.op.exp2.expType.isSigned || exp.op.exp2.expType.kind != intType))
8737             {
8738                type2 = { kind = intType };
8739                type2.refCount = 1;
8740                type2.isSigned = true;
8741             }
8742             else
8743             {
8744                type2 = exp.op.exp2.expType;
8745                if(type2) type2.refCount++;
8746             }
8747          }
8748          c1 = type1 && type1.kind == classType && type1._class ? type1._class.registered : null;
8749          c2 = type2 && type2.kind == classType && type2._class ? type2._class.registered : null;
8750
8751          if(relationOp &&
8752             ( (exp.op.exp1 && exp.op.exp1.ambiguousUnits && (!c2 || c2.type != unitClass)) ||
8753                (exp.op.exp2 && exp.op.exp2.ambiguousUnits && (!c1 || c1.type != unitClass))) )
8754             Compiler_Warning($"ambiguous units in relational operation\n");
8755
8756          if(!relationOp &&
8757             ((exp.op.exp1 && exp.op.exp1.ambiguousUnits) ||
8758              (exp.op.exp2 && exp.op.exp2.ambiguousUnits)) &&
8759              (!powerOp || !c1 || c1.type != unitClass || !c2 || c2.type != unitClass || !RelatedUnits(c1, c2)))
8760          {
8761             if(exp.opDestType || exp.usedInComparison)
8762                exp.ambiguousUnits = true;
8763             else
8764                Compiler_Warning($"ambiguous units\n");
8765          }
8766
8767          dummy.kind = voidType;
8768
8769          if(exp.op.op == SIZEOF)
8770          {
8771             exp.expType = Type
8772             {
8773                refCount = 1;
8774                kind = intSizeType;
8775             };
8776             exp.isConstant = true;
8777          }
8778          // Get type of dereferenced pointer
8779          else if(exp.op.op == '*' && !exp.op.exp1)
8780          {
8781             exp.expType = Dereference(type2);
8782             if(type2 && type2.kind == classType)
8783                notByReference = true;
8784          }
8785          else if(exp.op.op == '&' && !exp.op.exp1)
8786             exp.expType = Reference(type2);
8787          else if(exp.op.op == LEFT_OP || exp.op.op == RIGHT_OP)
8788          {
8789             if(exp.op.exp1.expType)
8790             {
8791                exp.expType = exp.op.exp1.expType;
8792                exp.expType.refCount++;
8793             }
8794          }
8795          else if(!assign)
8796          {
8797             if(c1 && !c1.dataType)
8798                c1.dataType = ProcessTypeString(c1.dataTypeString, false);
8799             if(c2 && !c2.dataType)
8800                c2.dataType = ProcessTypeString(c2.dataTypeString, false);
8801
8802             if(boolOps)
8803             {
8804                if(exp.op.exp1)
8805                {
8806                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8807                   exp.op.exp1.destType = MkClassType("bool");
8808                   exp.op.exp1.destType.truth = true;
8809                   if(!exp.op.exp1.expType)
8810                      ProcessExpressionType(exp.op.exp1);
8811                   else
8812                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8813                   FreeType(exp.op.exp1.expType);
8814                   exp.op.exp1.expType = MkClassType("bool");
8815                   exp.op.exp1.expType.truth = true;
8816                }
8817                if(exp.op.exp2)
8818                {
8819                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8820                   exp.op.exp2.destType = MkClassType("bool");
8821                   exp.op.exp2.destType.truth = true;
8822                   if(!exp.op.exp2.expType)
8823                      ProcessExpressionType(exp.op.exp2);
8824                   else
8825                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8826                   FreeType(exp.op.exp2.expType);
8827                   exp.op.exp2.expType = MkClassType("bool");
8828                   exp.op.exp2.expType.truth = true;
8829                }
8830             }
8831             else if(powerOp && exp.op.exp1 && exp.op.exp2 && ((c1 && c1.type == unitClass) || (c2 && c2.type == unitClass)))
8832             {
8833                // * or / with at least one unit operand
8834                if(c1 && c1.type == unitClass && c2 && c2.type == unitClass)
8835                {
8836                   // This is where we'd handle unit powers e.g. square meters or meters/seconds
8837                   // For now using base types
8838                   if(c1.dataType.kind == doubleType)        exp.expType = c1.dataType;
8839                   else if(c2.dataType.kind == doubleType)   exp.expType = c2.dataType;
8840                   else if(c1.dataType.kind == floatType)    exp.expType = c1.dataType;
8841                   else if(c2.dataType.kind == floatType)    exp.expType = c2.dataType;
8842                   else
8843                      exp.expType = c1.dataType;
8844                }
8845                else if((c1 && c1.type == unitClass) || exp.op.op == '/')   // 1/units should not be typed with unit
8846                   exp.expType = type1;
8847                else
8848                   exp.expType = type2;
8849
8850                if(exp.expType)
8851                   exp.expType.refCount++;
8852             }
8853             else if(exp.op.exp1 && exp.op.exp2 &&
8854                ((useSideType /*&&
8855                      (useSideUnit ||
8856                         ((!c1 || c1.type != unitClass) &&
8857                          (!c2 || c2.type != unitClass)))*/) ||
8858                   ((!type1 || type1.kind != classType || !strcmp(type1._class.string, "String")) &&
8859                   (!type2 || type2.kind != classType || !strcmp(type2._class.string, "String")))))
8860             {
8861                if(type1 && type2 &&
8862                   // If either both are class or both are not class
8863                   ((type1.kind == classType && type1._class && strcmp(type1._class.string, "String")) == (type2.kind == classType && type2._class && strcmp(type2._class.string, "String"))))
8864                {
8865                   // Added this check for enum subtraction to result in an int type:
8866                   if(exp.op.op == '-' && ((c1 && c1.type == enumClass) || (c2 && c2.type == enumClass)) )
8867                   {
8868                      Type intType = ProcessTypeString((c1 && c1.dataType.kind == int64Type) || (c2 && c2.dataType.kind == int64Type) ? "int64" : "int", false);
8869
8870                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8871                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8872                      exp.op.exp1.destType = intType;
8873                      exp.op.exp2.destType = intType;
8874                      intType.refCount++;
8875                   }
8876                   else
8877                   {
8878                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8879                      exp.op.exp2.destType = type1;
8880                      type1.refCount++;
8881                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8882                      exp.op.exp1.destType = type2;
8883                      type2.refCount++;
8884                   }
8885
8886                   // Warning here for adding Radians + Degrees with no destination type
8887                   if(!boolResult && !exp.opDestType && (!exp.destType || exp.destType.kind != classType) &&
8888                      c1 && c1.type == unitClass &&
8889                      c2 && c2.type == unitClass &&
8890                      c1 != c2)
8891                   {
8892                      if(exp.usedInComparison || exp.parentOpDestType)
8893                         exp.ambiguousUnits = true;
8894                      else
8895                         Compiler_Warning($"operating on %s and %s with an untyped result, assuming %s\n",
8896                            type1._class.string, type2._class.string, type1._class.string);
8897                   }
8898
8899                   if(type1.kind == pointerType && type1.type.kind == templateType && type2.kind != pointerType)
8900                   {
8901                      Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8902                      if(argExp)
8903                      {
8904                         Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8905
8906                         exp.op.exp1 = MkExpBrackets(MkListOne(MkExpCast(
8907                            MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
8908                            exp.op.exp1)));
8909
8910                         ProcessExpressionType(exp.op.exp1);
8911
8912                         if(type2.kind != pointerType)
8913                         {
8914                            ProcessExpressionType(classExp);
8915
8916                            exp.op.exp2 = MkExpBrackets(MkListOne(MkExpOp(exp.op.exp2, '*', MkExpMember(classExp, MkIdentifier("typeSize")) )));
8917
8918                            if(!exp.op.exp2.expType)
8919                            {
8920                               if(type2)
8921                                  FreeType(type2);
8922                               type2 = exp.op.exp2.expType = ProcessTypeString("int", false); c2 = null;
8923                               type2.refCount++;
8924                            }
8925
8926                            ProcessExpressionType(exp.op.exp2);
8927                         }
8928                      }
8929                   }
8930
8931                   if(!boolResult && ((type1.kind == pointerType || type1.kind == arrayType || (type1.kind == classType && !strcmp(type1._class.string, "String"))) && (type2.kind == intSizeType || type2.kind == intPtrType || type2.kind == int64Type || type2.kind == intType || type2.kind == shortType || type2.kind == charType)))
8932                   {
8933                      if(type1.kind != classType && type1.type.kind == voidType)
8934                         Compiler_Error($"void *: unknown size\n");
8935                      exp.expType = type1;
8936                      if(type1) type1.refCount++;
8937                   }
8938                   else if(!boolResult && ((type2.kind == pointerType || type2.kind == arrayType || (type2.kind == classType && !strcmp(type2._class.string, "String"))) && (type1.kind == intSizeType || type1.kind == intPtrType || type1.kind == int64Type || type1.kind == intType || type1.kind == shortType || type1.kind == charType)))
8939                   {
8940                      if(type2.kind != classType && type2.type.kind == voidType)
8941                         Compiler_Error($"void *: unknown size\n");
8942                      exp.expType = type2;
8943                      if(type2) type2.refCount++;
8944                   }
8945                   else if((type1.kind == pointerType && type2.kind != pointerType && type2.kind != arrayType && type2.kind != functionType && type2.kind != methodType && type2.kind != classType && type2.kind != subClassType) ||
8946                           (type2.kind == pointerType && type1.kind != pointerType && type1.kind != arrayType && type1.kind != functionType && type1.kind != methodType && type1.kind != classType && type1.kind != subClassType))
8947                   {
8948                      Compiler_Warning($"different levels of indirection\n");
8949                   }
8950                   else
8951                   {
8952                      bool success = false;
8953                      if(type1.kind == pointerType && type2.kind == pointerType)
8954                      {
8955                         if(exp.op.op == '+')
8956                            Compiler_Error($"cannot add two pointers\n");
8957                         else if(exp.op.op == '-')
8958                         {
8959                            // Pointer Subtraction gives integer
8960                            if(MatchTypes(type1.type, type2.type, null, null, null, false, false, false, false, false))
8961                            {
8962                               exp.expType = Type
8963                               {
8964                                  kind = intType;
8965                                  refCount = 1;
8966                               };
8967                               success = true;
8968
8969                               if(type1.type.kind == templateType)
8970                               {
8971                                  Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8972                                  if(argExp)
8973                                  {
8974                                     Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8975
8976                                     ProcessExpressionType(classExp);
8977
8978                                     exp.type = bracketsExp;
8979                                     exp.list = MkListOne(MkExpOp(
8980                                        MkExpBrackets(MkListOne(MkExpOp(
8981                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp1)))
8982                                              , exp.op.op,
8983                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp2)))))), '/',
8984                                              MkExpMember(classExp, MkIdentifier("typeSize"))));
8985
8986                                     ProcessExpressionType(((Expression)exp.list->first).op.exp2);
8987                                     FreeType(dummy);
8988                                     return;
8989                                  }
8990                               }
8991                            }
8992                         }
8993                      }
8994
8995                      if(!success && exp.op.exp1.type == constantExp)
8996                      {
8997                         // If first expression is constant, try to match that first
8998                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8999                         {
9000                            if(exp.expType) FreeType(exp.expType);
9001                            exp.expType = exp.op.exp1.destType;
9002                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
9003                            success = true;
9004                         }
9005                         else if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
9006                         {
9007                            if(exp.expType) FreeType(exp.expType);
9008                            exp.expType = exp.op.exp2.destType;
9009                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
9010                            success = true;
9011                         }
9012                      }
9013                      else if(!success)
9014                      {
9015                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
9016                         {
9017                            if(exp.expType) FreeType(exp.expType);
9018                            exp.expType = exp.op.exp2.destType;
9019                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
9020                            success = true;
9021                         }
9022                         else if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
9023                         {
9024                            if(exp.expType) FreeType(exp.expType);
9025                            exp.expType = exp.op.exp1.destType;
9026                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
9027                            success = true;
9028                         }
9029                      }
9030                      if(!success)
9031                      {
9032                         char expString1[10240];
9033                         char expString2[10240];
9034                         char type1[1024];
9035                         char type2[1024];
9036                         expString1[0] = '\0';
9037                         expString2[0] = '\0';
9038                         type1[0] = '\0';
9039                         type2[0] = '\0';
9040                         if(inCompiler)
9041                         {
9042                            PrintExpression(exp.op.exp1, expString1);
9043                            ChangeCh(expString1, '\n', ' ');
9044                            PrintExpression(exp.op.exp2, expString2);
9045                            ChangeCh(expString2, '\n', ' ');
9046                            PrintType(exp.op.exp1.expType, type1, false, true);
9047                            PrintType(exp.op.exp2.expType, type2, false, true);
9048                         }
9049
9050                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1, expString2, type2);
9051                      }
9052                   }
9053                }
9054                // ADDED THESE TWO FROM OUTSIDE useSideType CHECK
9055                else if(!boolResult && !useSideUnit && c2 && c2.type == unitClass && type1 && type1.kind != classType)
9056                {
9057                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9058                   // Convert e.g. / 4 into / 4.0
9059                   exp.op.exp1.destType = type2._class.registered.dataType;
9060                   if(type2._class.registered.dataType)
9061                      type2._class.registered.dataType.refCount++;
9062                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
9063                   exp.expType = type2;
9064                   if(type2) type2.refCount++;
9065                }
9066                else if(!boolResult && !useSideUnit && c1 && c1.type == unitClass && type2 && type2.kind != classType)
9067                {
9068                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9069                   // Convert e.g. / 4 into / 4.0
9070                   exp.op.exp2.destType = type1._class.registered.dataType;
9071                   if(type1._class.registered.dataType)
9072                      type1._class.registered.dataType.refCount++;
9073                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
9074                   exp.expType = type1;
9075                   if(type1) type1.refCount++;
9076                }
9077                else if(type1)
9078                {
9079                   bool valid = false;
9080
9081                   if(!boolResult && useSideUnit && c1 && c1.type == unitClass && type2 && type2.kind != classType)
9082                   {
9083                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9084
9085                      exp.op.exp2.destType = c1.dataType;
9086                      exp.op.exp2.destType.refCount++;
9087
9088                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
9089                      if(type2)
9090                         FreeType(type2);
9091                      type2 = exp.op.exp2.destType;
9092                      c2 = type2 && type2.kind == classType && type2._class ? type2._class.registered : null;
9093                      if(type2) type2.refCount++;
9094
9095                      exp.expType = type2;
9096                      type2.refCount++;
9097                   }
9098
9099                   if(!boolResult && useSideUnit && c2 && c2.type == unitClass && type1 && type1.kind != classType)
9100                   {
9101                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9102
9103                      exp.op.exp1.destType = c2.dataType;
9104                      exp.op.exp1.destType.refCount++;
9105
9106                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
9107                      type1 = exp.op.exp1.destType;
9108                      c1 = type1 && type1.kind == classType && type1._class ? type1._class.registered : null;
9109                      exp.expType = type1;
9110                      type1.refCount++;
9111                   }
9112
9113                   // TESTING THIS NEW CODE
9114                   if(!boolResult || exp.op.op == '>' || exp.op.op == '<' || exp.op.op == GE_OP || exp.op.op == LE_OP)
9115                   {
9116                      bool op1IsEnum = c1 && c1.type == enumClass;
9117                      bool op2IsEnum = c2 && c2.type == enumClass;
9118                      if(exp.op.op == '*' || exp.op.op == '/' || exp.op.op == '-' || exp.op.op == '|' || exp.op.op == '^')
9119                      {
9120                         // Convert the enum to an int instead for these operators
9121                         if(op1IsEnum && exp.op.exp2.expType)
9122                         {
9123                            if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false, false))
9124                            {
9125                               if(exp.expType) FreeType(exp.expType);
9126                               exp.expType = exp.op.exp2.expType;
9127                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
9128                               valid = true;
9129                            }
9130                         }
9131                         else if(op2IsEnum && exp.op.exp1.expType)
9132                         {
9133                            if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false, false))
9134                            {
9135                               if(exp.expType) FreeType(exp.expType);
9136                               exp.expType = exp.op.exp1.expType;
9137                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
9138                               valid = true;
9139                            }
9140                         }
9141                      }
9142                      else
9143                      {
9144                         if(op1IsEnum && exp.op.exp2.expType)
9145                         {
9146                            if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false, false))
9147                            {
9148                               if(exp.expType) FreeType(exp.expType);
9149                               exp.expType = exp.op.exp1.expType;
9150                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
9151                               valid = true;
9152                            }
9153                         }
9154                         else if(op2IsEnum && exp.op.exp1.expType)
9155                         {
9156                            if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false, false))
9157                            {
9158                               if(exp.expType) FreeType(exp.expType);
9159                               exp.expType = exp.op.exp2.expType;
9160                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
9161                               valid = true;
9162                            }
9163                         }
9164                      }
9165                   }
9166
9167                   if(!valid)
9168                   {
9169                      // Added this first part of the if here to handle  5 + Degrees { 5 } with either a base unit dest or not a unit dest type
9170                      if(c2 && c2.type == unitClass && (!c1 || c1.type != unitClass))
9171                      {
9172                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9173                         exp.op.exp1.destType = type2;
9174                         type2.refCount++;
9175
9176                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
9177                         {
9178                            if(exp.expType) FreeType(exp.expType);
9179                            exp.expType = exp.op.exp1.destType;
9180                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
9181                         }
9182                      }
9183                      else
9184                      {
9185                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9186                         exp.op.exp2.destType = type1;
9187                         type1.refCount++;
9188
9189                      /*
9190                      // Maybe this was meant to be an enum...
9191                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
9192                      {
9193                         Type oldType = exp.op.exp2.expType;
9194                         exp.op.exp2.expType = null;
9195                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
9196                            FreeType(oldType);
9197                         else
9198                            exp.op.exp2.expType = oldType;
9199                      }
9200                      */
9201
9202                      /*
9203                      // TESTING THIS HERE... LATEST ADDITION
9204                      if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
9205                      {
9206                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9207                         exp.op.exp2.destType = type2._class.registered.dataType;
9208                         if(type2._class.registered.dataType)
9209                            type2._class.registered.dataType.refCount++;
9210                         CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
9211
9212                         //exp.expType = type2._class.registered.dataType; //type2;
9213                         //if(type2) type2.refCount++;
9214                      }
9215
9216                      // TESTING THIS HERE... LATEST ADDITION
9217                      if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
9218                      {
9219                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9220                         exp.op.exp1.destType = type1._class.registered.dataType;
9221                         if(type1._class.registered.dataType)
9222                            type1._class.registered.dataType.refCount++;
9223                         CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
9224                         exp.expType = type1._class.registered.dataType; //type1;
9225                         if(type1) type1.refCount++;
9226                      }
9227                      */
9228
9229                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
9230                         {
9231                            if(exp.expType) FreeType(exp.expType);
9232                            exp.expType = exp.op.exp2.destType;
9233                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
9234                         }
9235                         else if(type1 && type2)
9236                         {
9237                            char expString1[10240];
9238                            char expString2[10240];
9239                            char type1String[1024];
9240                            char type2String[1024];
9241                            expString1[0] = '\0';
9242                            expString2[0] = '\0';
9243                            type1String[0] = '\0';
9244                            type2String[0] = '\0';
9245                            if(inCompiler)
9246                            {
9247                               PrintExpression(exp.op.exp1, expString1);
9248                               ChangeCh(expString1, '\n', ' ');
9249                               PrintExpression(exp.op.exp2, expString2);
9250                               ChangeCh(expString2, '\n', ' ');
9251                               PrintType(exp.op.exp1.expType, type1String, false, true);
9252                               PrintType(exp.op.exp2.expType, type2String, false, true);
9253                            }
9254
9255                            Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1String, expString2, type2String);
9256
9257                            if(c1 && c1.type == enumClass)
9258                            {
9259                               exp.expType = exp.op.exp1.expType;
9260                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
9261                            }
9262                            else if(c2 && c2.type == enumClass)
9263                            {
9264                               exp.expType = exp.op.exp2.expType;
9265                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
9266                            }
9267                         }
9268                      }
9269                   }
9270                }
9271                else if(type2)
9272                {
9273                   // Maybe this was meant to be an enum...
9274                   if(c2 && c2.type == enumClass)
9275                   {
9276                      Type oldType = exp.op.exp1.expType;
9277                      exp.op.exp1.expType = null;
9278                      if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
9279                         FreeType(oldType);
9280                      else
9281                         exp.op.exp1.expType = oldType;
9282                   }
9283
9284                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9285                   exp.op.exp1.destType = type2;
9286                   type2.refCount++;
9287                   /*
9288                   // TESTING THIS HERE... LATEST ADDITION
9289                   if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
9290                   {
9291                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9292                      exp.op.exp1.destType = type1._class.registered.dataType;
9293                      if(type1._class.registered.dataType)
9294                         type1._class.registered.dataType.refCount++;
9295                   }
9296
9297                   // TESTING THIS HERE... LATEST ADDITION
9298                   if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
9299                   {
9300                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9301                      exp.op.exp2.destType = type2._class.registered.dataType;
9302                      if(type2._class.registered.dataType)
9303                         type2._class.registered.dataType.refCount++;
9304                   }
9305                   */
9306
9307                   if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
9308                   {
9309                      if(exp.expType) FreeType(exp.expType);
9310                      exp.expType = exp.op.exp1.destType;
9311                      if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
9312                   }
9313                }
9314             }
9315             else if(type2 && (!type1 || (type2.kind == classType && type1.kind != classType)))
9316             {
9317                if(type1 && c2 && c2.type == unitClass)
9318                {
9319                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9320                   // Convert e.g. / 4 into / 4.0
9321                   exp.op.exp1.destType = type2._class.registered.dataType;
9322                   if(type2._class.registered.dataType)
9323                      type2._class.registered.dataType.refCount++;
9324                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
9325                }
9326                if(exp.op.op == '!')
9327                {
9328                   exp.expType = MkClassType("bool");
9329                   exp.expType.truth = true;
9330                }
9331                else
9332                {
9333                   exp.expType = type2;
9334                   if(type2) type2.refCount++;
9335                }
9336             }
9337             else if(type1 && (!type2 || (type1.kind == classType && type2.kind != classType)))
9338             {
9339                if(c2 && c2.type == unitClass)
9340                {
9341                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9342                   // Convert e.g. / 4 into / 4.0
9343                   exp.op.exp2.destType = type1._class.registered.dataType;
9344                   if(type1._class.registered.dataType)
9345                      type1._class.registered.dataType.refCount++;
9346                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
9347                }
9348                exp.expType = type1;
9349                if(type1) type1.refCount++;
9350             }
9351          }
9352
9353          yylloc = exp.loc;
9354          if(exp.op.exp1 && !exp.op.exp1.expType)
9355          {
9356             char expString[10000];
9357             expString[0] = '\0';
9358             if(inCompiler)
9359             {
9360                PrintExpression(exp.op.exp1, expString);
9361                ChangeCh(expString, '\n', ' ');
9362             }
9363             if(expString[0])
9364                Compiler_Error($"couldn't determine type of %s\n", expString);
9365          }
9366          if(exp.op.exp2 && !exp.op.exp2.expType)
9367          {
9368             char expString[10240];
9369             expString[0] = '\0';
9370             if(inCompiler)
9371             {
9372                PrintExpression(exp.op.exp2, expString);
9373                ChangeCh(expString, '\n', ' ');
9374             }
9375             if(expString[0])
9376                Compiler_Error($"couldn't determine type of %s\n", expString);
9377          }
9378
9379          if(boolResult)
9380          {
9381             FreeType(exp.expType);
9382             exp.expType = MkClassType("bool");
9383             exp.expType.truth = true;
9384          }
9385
9386          if(exp.op.op != SIZEOF)
9387             exp.isConstant = (!exp.op.exp1 || exp.op.exp1.isConstant) &&
9388                (!exp.op.exp2 || exp.op.exp2.isConstant);
9389
9390          if(exp.op.op == SIZEOF && exp.op.exp2.expType)
9391          {
9392             DeclareType(curExternal, exp.op.exp2.expType, true, false);
9393          }
9394
9395          if(exp.op.op == DELETE && exp.op.exp2 && exp.op.exp2.expType && exp.op.exp2.expType.specConst)
9396             Compiler_Warning($"deleting const qualified object\n");
9397
9398          yylloc = oldyylloc;
9399
9400          FreeType(dummy);
9401          if(type2)
9402             FreeType(type2);
9403          break;
9404       }
9405       case bracketsExp:
9406       case extensionExpressionExp:
9407       {
9408          Expression e;
9409          exp.isConstant = true;
9410          for(e = exp.list->first; e; e = e.next)
9411          {
9412             //bool inced = false;
9413             if(!e.next)
9414             {
9415                FreeType(e.destType);
9416                e.opDestType = exp.opDestType;
9417                e.usedInComparison = exp.usedInComparison;
9418                e.parentOpDestType = exp.parentOpDestType;
9419                e.destType = exp.destType;
9420                if(e.destType) { exp.destType.refCount++; /*e.destType.count++; inced = true;*/ }
9421             }
9422             ProcessExpressionType(e);
9423             if(e.ambiguousUnits)
9424                exp.ambiguousUnits = true;
9425             /*if(inced)
9426                exp.destType.count--;*/
9427             if(!exp.expType && !e.next)
9428             {
9429                exp.expType = e.expType;
9430                if(e.expType) e.expType.refCount++;
9431                exp.needCast = e.needCast;
9432             }
9433             if(!e.isConstant)
9434                exp.isConstant = false;
9435          }
9436
9437          // In case a cast became a member...
9438          e = exp.list->first;
9439          if(!e.next && e.type == memberExp)
9440          {
9441             // Preserve prev, next
9442             Expression next = exp.next, prev = exp.prev;
9443
9444
9445             FreeType(exp.expType);
9446             FreeType(exp.destType);
9447             delete exp.list;
9448
9449             *exp = *e;
9450
9451             exp.prev = prev;
9452             exp.next = next;
9453
9454             delete e;
9455
9456             ProcessExpressionType(exp);
9457          }
9458          break;
9459       }
9460       case indexExp:
9461       {
9462          Expression e;
9463          exp.isConstant = true;
9464
9465          ProcessExpressionType(exp.index.exp);
9466          if(!exp.index.exp.isConstant)
9467             exp.isConstant = false;
9468
9469          if(exp.index.exp.expType)
9470          {
9471             Type source = exp.index.exp.expType;
9472             if(source.kind == classType && source._class && source._class.registered)
9473             {
9474                Class _class = source._class.registered;
9475                Class c = _class.templateClass ? _class.templateClass : _class;
9476                if(_class != containerClass && eClass_IsDerived(c, containerClass) && _class.templateArgs)
9477                {
9478                   exp.expType = ProcessTypeString(_class.templateArgs[2].dataTypeString, false);
9479
9480                   if(exp.index.index && exp.index.index->last)
9481                   {
9482                      Type type = ProcessTypeString(_class.templateArgs[1].dataTypeString, false);
9483
9484                      if(type.kind == classType) type.constant = true;
9485                      else if(type.kind == pointerType)
9486                      {
9487                         Type t = type;
9488                         while(t.kind == pointerType) t = t.type;
9489                         t.constant = true;
9490                      }
9491
9492                      ((Expression)exp.index.index->last).destType = type;
9493                   }
9494                }
9495             }
9496          }
9497
9498          for(e = exp.index.index->first; e; e = e.next)
9499          {
9500             if(!e.next && exp.index.exp.expType && exp.index.exp.expType.kind == arrayType && exp.index.exp.expType.enumClass)
9501             {
9502                if(e.destType) FreeType(e.destType);
9503                e.destType = MkClassType(exp.index.exp.expType.enumClass.string);
9504             }
9505             ProcessExpressionType(e);
9506             if(!e.next)
9507             {
9508                // Check if this type is int
9509             }
9510             if(!e.isConstant)
9511                exp.isConstant = false;
9512          }
9513
9514          if(!exp.expType)
9515             exp.expType = Dereference(exp.index.exp.expType);
9516          if(exp.expType)
9517             DeclareType(curExternal, exp.expType, true, false);
9518          break;
9519       }
9520       case callExp:
9521       {
9522          Expression e;
9523          Type functionType;
9524          Type methodType = null;
9525          char name[1024];
9526          name[0] = '\0';
9527
9528          if(inCompiler)
9529          {
9530             PrintExpression(exp.call.exp,  name);
9531             if(exp.call.exp.expType && !exp.call.exp.expType.returnType)
9532             {
9533                //exp.call.exp.expType = null;
9534                PrintExpression(exp.call.exp,  name);
9535             }
9536          }
9537          if(exp.call.exp.type == identifierExp)
9538          {
9539             Expression idExp = exp.call.exp;
9540             Identifier id = idExp.identifier;
9541             if(!strcmp(id.string, "__builtin_frame_address"))
9542             {
9543                exp.expType = ProcessTypeString("void *", true);
9544                if(exp.call.arguments && exp.call.arguments->first)
9545                   ProcessExpressionType(exp.call.arguments->first);
9546                break;
9547             }
9548             else if(!strcmp(id.string, "__ENDIAN_PAD"))
9549             {
9550                exp.expType = ProcessTypeString("int", true);
9551                if(exp.call.arguments && exp.call.arguments->first)
9552                   ProcessExpressionType(exp.call.arguments->first);
9553                break;
9554             }
9555             else if(!strcmp(id.string, "Max") ||
9556                !strcmp(id.string, "Min") ||
9557                !strcmp(id.string, "Sgn") ||
9558                !strcmp(id.string, "Abs"))
9559             {
9560                Expression a = null;
9561                Expression b = null;
9562                Expression tempExp1 = null, tempExp2 = null;
9563                if((!strcmp(id.string, "Max") ||
9564                   !strcmp(id.string, "Min")) && exp.call.arguments->count == 2)
9565                {
9566                   a = exp.call.arguments->first;
9567                   b = exp.call.arguments->last;
9568                   tempExp1 = a;
9569                   tempExp2 = b;
9570                }
9571                else if(exp.call.arguments->count == 1)
9572                {
9573                   a = exp.call.arguments->first;
9574                   tempExp1 = a;
9575                }
9576
9577                if(a)
9578                {
9579                   exp.call.arguments->Clear();
9580                   idExp.identifier = null;
9581
9582                   FreeExpContents(exp);
9583
9584                   ProcessExpressionType(a);
9585                   if(b)
9586                      ProcessExpressionType(b);
9587
9588                   exp.type = bracketsExp;
9589                   exp.list = MkList();
9590
9591                   if(a.expType && (!b || b.expType))
9592                   {
9593                      if((!a.isConstant && a.type != identifierExp) || (b && !b.isConstant && b.type != identifierExp))
9594                      {
9595                         // Use the simpleStruct name/ids for now...
9596                         if(inCompiler)
9597                         {
9598                            OldList * specs = MkList();
9599                            OldList * decls = MkList();
9600                            Declaration decl;
9601                            char temp1[1024], temp2[1024];
9602
9603                            GetTypeSpecs(a.expType, specs);
9604
9605                            if(a && !a.isConstant && a.type != identifierExp)
9606                            {
9607                               sprintf(temp1, "__simpleStruct%d", curContext.simpleID++);
9608                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp1)), null));
9609                               tempExp1 = QMkExpId(temp1);
9610                               tempExp1.expType = a.expType;
9611                               if(a.expType)
9612                                  a.expType.refCount++;
9613                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp1), '=', a));
9614                            }
9615                            if(b && !b.isConstant && b.type != identifierExp)
9616                            {
9617                               sprintf(temp2, "__simpleStruct%d", curContext.simpleID++);
9618                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp2)), null));
9619                               tempExp2 = QMkExpId(temp2);
9620                               tempExp2.expType = b.expType;
9621                               if(b.expType)
9622                                  b.expType.refCount++;
9623                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp2), '=', b));
9624                            }
9625
9626                            decl = MkDeclaration(specs, decls);
9627                            if(!curCompound.compound.declarations)
9628                               curCompound.compound.declarations = MkList();
9629                            curCompound.compound.declarations->Insert(null, decl);
9630                         }
9631                      }
9632                   }
9633
9634                   if(!strcmp(id.string, "Max") || !strcmp(id.string, "Min"))
9635                   {
9636                      int op = (!strcmp(id.string, "Max")) ? '>' : '<';
9637                      ListAdd(exp.list,
9638                         MkExpCondition(MkExpBrackets(MkListOne(
9639                            MkExpOp(CopyExpression(tempExp1), op, CopyExpression(tempExp2)))),
9640                            MkListOne(CopyExpression(tempExp1)), CopyExpression(tempExp2)));
9641                      exp.expType = a.expType;
9642                      if(a.expType)
9643                         a.expType.refCount++;
9644                   }
9645                   else if(!strcmp(id.string, "Abs"))
9646                   {
9647                      ListAdd(exp.list,
9648                         MkExpCondition(MkExpBrackets(MkListOne(
9649                            MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9650                            MkListOne(MkExpOp(null, '-', CopyExpression(tempExp1))), CopyExpression(tempExp1)));
9651                      exp.expType = a.expType;
9652                      if(a.expType)
9653                         a.expType.refCount++;
9654                   }
9655                   else if(!strcmp(id.string, "Sgn"))
9656                   {
9657                      // ((!(a))?(0):(((a)<0)?(-1):(1)))
9658                      ListAdd(exp.list,
9659                         MkExpCondition(MkExpBrackets(MkListOne(
9660                            MkExpOp(null, '!', CopyExpression(tempExp1)))), MkListOne(MkExpConstant("0")),
9661                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(
9662                                  MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9663                                  MkListOne(MkExpConstant("-1")), MkExpConstant("1"))))));
9664                      exp.expType = ProcessTypeString("int", false);
9665                   }
9666
9667                   FreeExpression(tempExp1);
9668                   if(tempExp2) FreeExpression(tempExp2);
9669
9670                   FreeIdentifier(id);
9671                   break;
9672                }
9673             }
9674          }
9675
9676          {
9677             Type dummy
9678             {
9679                count = 1;
9680                refCount = 1;
9681             };
9682             if(!exp.call.exp.destType)
9683             {
9684                exp.call.exp.destType = dummy;
9685                dummy.refCount++;
9686             }
9687             ProcessExpressionType(exp.call.exp);
9688             if(exp.call.exp.destType == dummy)
9689             {
9690                FreeType(dummy);
9691                exp.call.exp.destType = null;
9692             }
9693             FreeType(dummy);
9694          }
9695
9696          // Check argument types against parameter types
9697          functionType = exp.call.exp.expType;
9698
9699          if(functionType && functionType.kind == TypeKind::methodType)
9700          {
9701             methodType = functionType;
9702             functionType = methodType.method.dataType;
9703
9704             //if(functionType.returnType && functionType.returnType.kind == thisClassType)
9705             // TOCHECK: Instead of doing this here could this be done per param?
9706             if(exp.call.exp.expType.usedClass)
9707             {
9708                char typeString[1024];
9709                typeString[0] = '\0';
9710                {
9711                   Symbol back = functionType.thisClass;
9712                   // Do not output class specifier here (thisclass was added to this)
9713                   functionType.thisClass = null;
9714                   PrintType(functionType, typeString, true, true);
9715                   functionType.thisClass = back;
9716                }
9717                if(strstr(typeString, "thisclass"))
9718                {
9719                   OldList * specs = MkList();
9720                   Declarator decl;
9721                   {
9722                      Context context = SetupTemplatesContext(exp.call.exp.expType.usedClass);
9723
9724                      decl = SpecDeclFromString(typeString, specs, null);
9725
9726                      // SET THIS TO FALSE WHEN PROCESSING THISCLASS OUTSIDE THE CLASS
9727                      if(thisClass != (exp.call.exp.expType.usedClass.templateClass ? exp.call.exp.expType.usedClass.templateClass :
9728                         exp.call.exp.expType.usedClass))
9729                         thisClassParams = false;
9730
9731                      ReplaceThisClassSpecifiers(specs, exp.call.exp.expType.usedClass);
9732                      {
9733                         Class backupThisClass = thisClass;
9734                         thisClass = exp.call.exp.expType.usedClass;
9735                         ProcessDeclarator(decl, true);
9736                         thisClass = backupThisClass;
9737                      }
9738
9739                      thisClassParams = true;
9740
9741                      functionType = ProcessType(specs, decl);
9742                      functionType.refCount = 0;
9743                      FinishTemplatesContext(context);
9744
9745                      // Mark parameters that were 'thisclass'
9746                      {
9747                         Type p, op;
9748                         for(p = functionType.params.first, op = methodType.method.dataType.params.first; p && op; p = p.next, op = op.next)
9749                         {
9750                            //p.wasThisClass = op.kind == thisClassType;
9751                            if(op.kind == thisClassType)
9752                               p.thisClassFrom = methodType.method._class;
9753                         }
9754                      }
9755                      if(methodType.method.dataType.returnType.kind == thisClassType)
9756                      {
9757                         // functionType.returnType.wasThisClass = true;
9758                         functionType.returnType.thisClassFrom = methodType.method._class;
9759                      }
9760                   }
9761
9762                   FreeList(specs, FreeSpecifier);
9763                   FreeDeclarator(decl);
9764                 }
9765             }
9766          }
9767          if(functionType && functionType.kind == pointerType && functionType.type && functionType.type.kind == TypeKind::functionType)
9768          {
9769             Type type = functionType.type;
9770             if(!functionType.refCount)
9771             {
9772                functionType.type = null;
9773                FreeType(functionType);
9774             }
9775             //methodType = functionType;
9776             functionType = type;
9777          }
9778          if(functionType && functionType.kind != TypeKind::functionType)
9779          {
9780             Compiler_Error($"called object %s is not a function\n", name);
9781          }
9782          else if(functionType)
9783          {
9784             bool emptyParams = false, noParams = false;
9785             Expression e = exp.call.arguments ? exp.call.arguments->first : null;
9786             Type type = functionType.params.first;
9787             Expression memberExp = (exp.call.exp.type == ExpressionType::memberExp) ? exp.call.exp : null;
9788             int extra = 0;
9789             Location oldyylloc = yylloc;
9790
9791             if(!type) emptyParams = true;
9792
9793             // WORKING ON THIS:
9794             if(functionType.extraParam && e && functionType.thisClass)
9795             {
9796                e.destType = MkClassType(functionType.thisClass.string);
9797                e = e.next;
9798             }
9799
9800             // WHY WAS THIS COMMENTED OUT ? Broke DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
9801             // Fixed #141 by adding '&& !functionType.extraParam'
9802             if(!functionType.staticMethod && !functionType.extraParam)
9803             {
9804                if(memberExp && memberExp.member.exp && memberExp.member.exp.expType && memberExp.member.exp.expType.kind == subClassType &&
9805                   memberExp.member.exp.expType._class)
9806                {
9807                   type = MkClassType(memberExp.member.exp.expType._class.string);
9808                   if(e)
9809                   {
9810                      e.destType = type;
9811                      e = e.next;
9812                      type = functionType.params.first;
9813                   }
9814                   else
9815                      type.refCount = 0;
9816                }
9817                else if(!memberExp && (functionType.thisClass || (methodType && methodType.methodClass)))
9818                {
9819                   type = MkClassType(functionType.thisClass ? functionType.thisClass.string : (methodType ? methodType.methodClass.fullName : null));
9820                   type.byReference = functionType.byReference;
9821                   type.typedByReference = functionType.typedByReference;
9822                   if(e)
9823                   {
9824                      // Allow manually passing a class for typed object
9825                      if(e.next && type.kind == classType && (functionType && functionType.thisClass) && functionType.classObjectType == typedObject)
9826                         e = e.next;
9827                      e.destType = type;
9828                      e = e.next;
9829                      type = functionType.params.first;
9830                   }
9831                   else
9832                      type.refCount = 0;
9833                   //extra = 1;
9834                }
9835             }
9836
9837             if(type && type.kind == voidType)
9838             {
9839                noParams = true;
9840                if(!type.refCount) FreeType(type);
9841                type = null;
9842             }
9843
9844             for( ; e; e = e.next)
9845             {
9846                if(!type && !emptyParams)
9847                {
9848                   yylloc = e.loc;
9849                   if(methodType && methodType.methodClass)
9850                      Compiler_Error($"too many arguments for method %s::%s (%d given, expected %d)\n",
9851                         methodType.methodClass.fullName, methodType.method.name, exp.call.arguments->count,
9852                         noParams ? 0 : functionType.params.count);
9853                   else
9854                      Compiler_Error($"too many arguments for function %s (%d given, expected %d)\n",
9855                         name /*exp.call.exp.identifier.string*/, exp.call.arguments->count,
9856                         noParams ? 0 : functionType.params.count);
9857                   break;
9858                }
9859
9860                if(methodType && type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type)
9861                {
9862                   Type templatedType = null;
9863                   Class _class = methodType.usedClass;
9864                   ClassTemplateParameter curParam = null;
9865                   int id = 0;
9866                   if(_class && _class.templateArgs /*&& _class.templateClass*/)
9867                   {
9868                      Class sClass;
9869                      for(sClass = _class; sClass; sClass = sClass.base)
9870                      {
9871                         if(sClass.templateClass) sClass = sClass.templateClass;
9872                         id = 0;
9873                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9874                         {
9875                            if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
9876                            {
9877                               Class nextClass;
9878                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
9879                               {
9880                                  if(nextClass.templateClass) nextClass = nextClass.templateClass;
9881                                  id += nextClass.templateParams.count;
9882                               }
9883                               break;
9884                            }
9885                            id++;
9886                         }
9887                         if(curParam) break;
9888                      }
9889                   }
9890                   if(curParam && _class.templateArgs[id].dataTypeString)
9891                   {
9892                      bool constant = type.constant;
9893                      ClassTemplateArgument arg = _class.templateArgs[id];
9894                      {
9895                         Context context = SetupTemplatesContext(_class);
9896
9897                         /*if(!arg.dataType)
9898                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9899                         templatedType = ProcessTypeString(arg.dataTypeString, false);
9900                         FinishTemplatesContext(context);
9901                      }
9902
9903                      if(templatedType.kind == classType && constant) templatedType.constant = true;
9904                      else if(templatedType.kind == pointerType)
9905                      {
9906                         Type t = templatedType.type;
9907                         while(t.kind == pointerType) t = t.type;
9908                         if(constant) t.constant = constant;
9909                      }
9910
9911                      e.destType = templatedType;
9912                      if(templatedType)
9913                      {
9914                         templatedType.passAsTemplate = true;
9915                         // templatedType.refCount++;
9916                      }
9917                   }
9918                   else
9919                   {
9920                      e.destType = type;
9921                      if(type) type.refCount++;
9922                   }
9923                }
9924                else
9925                {
9926                   if(type && type.kind == ellipsisType && type.prev && type.prev.kind == classType && type.prev.classObjectType)
9927                   {
9928                      e.destType = type.prev;
9929                      e.destType.refCount++;
9930                   }
9931                   else
9932                   {
9933                      e.destType = type;
9934                      if(type) type.refCount++;
9935                   }
9936                }
9937                // Don't reach the end for the ellipsis
9938                if(type && type.kind != ellipsisType)
9939                {
9940                   Type next = type.next;
9941                   if(!type.refCount) FreeType(type);
9942                   type = next;
9943                }
9944             }
9945
9946             if(type && type.kind != ellipsisType)
9947             {
9948                if(methodType && methodType.methodClass)
9949                   Compiler_Warning($"not enough arguments for method %s::%s (%d given, expected %d)\n",
9950                      methodType.methodClass.fullName, methodType.method.name, exp.call.arguments ? exp.call.arguments->count : 0,
9951                      functionType.params.count + extra);
9952                else
9953                   Compiler_Warning($"not enough arguments for function %s (%d given, expected %d)\n",
9954                      name /*exp.call.exp.identifier.string*/, exp.call.arguments ? exp.call.arguments->count : 0,
9955                      functionType.params.count + extra);
9956             }
9957             yylloc = oldyylloc;
9958             if(type && !type.refCount) FreeType(type);
9959          }
9960          else
9961          {
9962             functionType = Type
9963             {
9964                refCount = 0;
9965                kind = TypeKind::functionType;
9966             };
9967
9968             if(exp.call.exp.type == identifierExp)
9969             {
9970                char * string = exp.call.exp.identifier.string;
9971                if(inCompiler)
9972                {
9973                   Symbol symbol;
9974                   Location oldyylloc = yylloc;
9975
9976                   yylloc = exp.call.exp.identifier.loc;
9977                   if(strstr(string, "__builtin_") == string)
9978                   {
9979                      if(exp.destType)
9980                      {
9981                         functionType.returnType = exp.destType;
9982                         exp.destType.refCount++;
9983                      }
9984                   }
9985                   else
9986                      Compiler_Warning($"%s undefined; assuming extern returning int\n", string);
9987                   symbol = Symbol { string = CopyString(string), type = ProcessTypeString("int()", true) };
9988                   globalContext.symbols.Add((BTNode)symbol);
9989                   if(strstr(symbol.string, "::"))
9990                      globalContext.hasNameSpace = true;
9991
9992                   yylloc = oldyylloc;
9993                }
9994             }
9995             else if(exp.call.exp.type == memberExp)
9996             {
9997                /*Compiler_Warning($"%s undefined; assuming returning int\n",
9998                   exp.call.exp.member.member.string);*/
9999             }
10000             else
10001                Compiler_Warning($"callable object undefined; extern assuming returning int\n");
10002
10003             if(!functionType.returnType)
10004             {
10005                functionType.returnType = Type
10006                {
10007                   refCount = 1;
10008                   kind = intType;
10009                };
10010             }
10011          }
10012          if(functionType && functionType.kind == TypeKind::functionType)
10013          {
10014             exp.expType = functionType.returnType;
10015
10016             if(functionType.returnType)
10017                functionType.returnType.refCount++;
10018
10019             if(!functionType.refCount)
10020                FreeType(functionType);
10021          }
10022
10023          if(exp.call.arguments)
10024          {
10025             for(e = exp.call.arguments->first; e; e = e.next)
10026                ProcessExpressionType(e);
10027          }
10028          break;
10029       }
10030       case memberExp:
10031       {
10032          Type type;
10033          Location oldyylloc = yylloc;
10034          bool thisPtr;
10035          Expression checkExp = exp.member.exp;
10036          while(checkExp)
10037          {
10038             if(checkExp.type == castExp)
10039                checkExp = checkExp.cast.exp;
10040             else if(checkExp.type == bracketsExp)
10041                checkExp = checkExp.list ? checkExp.list->first : null;
10042             else
10043                break;
10044          }
10045
10046          thisPtr = (checkExp && checkExp.type == identifierExp && !strcmp(checkExp.identifier.string, "this"));
10047          exp.thisPtr = thisPtr;
10048
10049          // DOING THIS LATER NOW...
10050          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
10051          {
10052             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
10053             /* TODO: Name Space Fix ups
10054             if(!exp.member.member.classSym)
10055                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.fullName);
10056             */
10057          }
10058
10059          ProcessExpressionType(exp.member.exp);
10060          if(exp.member.exp.expType && exp.member.exp.expType.kind == classType && exp.member.exp.expType._class &&
10061             exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == normalClass)
10062          {
10063             exp.isConstant = false;
10064          }
10065          else
10066             exp.isConstant = exp.member.exp.isConstant;
10067          type = exp.member.exp.expType;
10068
10069          yylloc = exp.loc;
10070
10071          if(type && (type.kind == templateType))
10072          {
10073             Class _class = thisClass ? thisClass : currentClass;
10074             ClassTemplateParameter param = null;
10075             if(_class)
10076             {
10077                for(param = _class.templateParams.first; param; param = param.next)
10078                {
10079                   if(param.type == identifier && exp.member.member && exp.member.member.string && !strcmp(param.name, exp.member.member.string))
10080                      break;
10081                }
10082             }
10083             if(param && param.defaultArg.member)
10084             {
10085                Expression argExp = GetTemplateArgExpByName(param.name, thisClass, TemplateParameterType::identifier);
10086                if(argExp)
10087                {
10088                   Expression expMember = exp.member.exp;
10089                   Declarator decl;
10090                   OldList * specs = MkList();
10091                   char thisClassTypeString[1024];
10092
10093                   FreeIdentifier(exp.member.member);
10094
10095                   ProcessExpressionType(argExp);
10096
10097                   {
10098                      char * colon = strstr(param.defaultArg.memberString, "::");
10099                      if(colon)
10100                      {
10101                         memcpy(thisClassTypeString, param.defaultArg.memberString, colon - param.defaultArg.memberString);
10102                         thisClassTypeString[colon - param.defaultArg.memberString] = '\0';
10103                      }
10104                      else
10105                         strcpy(thisClassTypeString, _class.fullName);
10106                   }
10107
10108                   decl = SpecDeclFromString(param.defaultArg.member.dataTypeString, specs, null);
10109
10110                   exp.expType = ProcessType(specs, decl);
10111                   if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.templateClass)
10112                   {
10113                      Class expClass = exp.expType._class.registered;
10114                      Class cClass = null;
10115                      int paramCount = 0;
10116                      int lastParam = -1;
10117
10118                      char templateString[1024];
10119                      ClassTemplateParameter param;
10120                      sprintf(templateString, "%s<", expClass.templateClass.fullName);
10121                      for(cClass = expClass; cClass; cClass = cClass.base)
10122                      {
10123                         int p = 0;
10124                         for(param = cClass.templateParams.first; param; param = param.next)
10125                         {
10126                            int id = p;
10127                            Class sClass;
10128                            ClassTemplateArgument arg;
10129                            for(sClass = cClass.base; sClass; sClass = sClass.base) id += sClass.templateParams.count;
10130                            arg = expClass.templateArgs[id];
10131
10132                            for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
10133                            {
10134                               ClassTemplateParameter cParam;
10135                               //int p = numParams - sClass.templateParams.count;
10136                               int p = 0;
10137                               Class nextClass;
10138                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) p += nextClass.templateParams.count;
10139
10140                               for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
10141                               {
10142                                  if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
10143                                  {
10144                                     if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10145                                     {
10146                                        arg.dataTypeString = _class.templateArgs[p].dataTypeString;
10147                                        arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
10148                                        break;
10149                                     }
10150                                  }
10151                               }
10152                            }
10153
10154                            {
10155                               char argument[256];
10156                               argument[0] = '\0';
10157                               /*if(arg.name)
10158                               {
10159                                  strcat(argument, arg.name.string);
10160                                  strcat(argument, " = ");
10161                               }*/
10162                               switch(param.type)
10163                               {
10164                                  case expression:
10165                                  {
10166                                     // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
10167                                     char expString[1024];
10168                                     OldList * specs = MkList();
10169                                     Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
10170                                     Expression exp;
10171                                     char * string = PrintHexUInt64(arg.expression.ui64);
10172                                     exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
10173                                     delete string;
10174
10175                                     ProcessExpressionType(exp);
10176                                     ComputeExpression(exp);
10177                                     expString[0] = '\0';
10178                                     PrintExpression(exp, expString);
10179                                     strcat(argument, expString);
10180                                     // delete exp;
10181                                     FreeExpression(exp);
10182                                     break;
10183                                  }
10184                                  case identifier:
10185                                  {
10186                                     strcat(argument, arg.member.name);
10187                                     break;
10188                                  }
10189                                  case TemplateParameterType::type:
10190                                  {
10191                                     if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10192                                     {
10193                                        if(!strcmp(arg.dataTypeString, "thisclass"))
10194                                           strcat(argument, thisClassTypeString);
10195                                        else
10196                                           strcat(argument, arg.dataTypeString);
10197                                     }
10198                                     break;
10199                                  }
10200                               }
10201                               if(argument[0])
10202                               {
10203                                  if(paramCount) strcat(templateString, ", ");
10204                                  if(lastParam != p - 1)
10205                                  {
10206                                     strcat(templateString, param.name);
10207                                     strcat(templateString, " = ");
10208                                  }
10209                                  strcat(templateString, argument);
10210                                  paramCount++;
10211                                  lastParam = p;
10212                               }
10213                               p++;
10214                            }
10215                         }
10216                      }
10217                      {
10218                         int len = strlen(templateString);
10219                         if(templateString[len-1] == '>') templateString[len++] = ' ';
10220                         templateString[len++] = '>';
10221                         templateString[len++] = '\0';
10222                      }
10223                      {
10224                         Context context = SetupTemplatesContext(_class);
10225                         FreeType(exp.expType);
10226                         exp.expType = ProcessTypeString(templateString, false);
10227                         FinishTemplatesContext(context);
10228                      }
10229                   }
10230
10231                   if(!expMember.expType.isPointerType)
10232                      expMember = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), expMember);
10233                   // *([expType] *)(((byte *)(uintptr)[exp.member.exp]) + [argExp].member.offset)
10234                   exp.type = bracketsExp;
10235                   exp.list = MkListOne(MkExpOp(null, '*',
10236                   /*opExp;
10237                   exp.op.op = '*';
10238                   exp.op.exp1 = null;
10239                   exp.op.exp2 = */
10240                   MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpBrackets(MkListOne(MkExpOp(
10241                      MkExpBrackets(MkListOne(
10242                         MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
10243                            expMember))),
10244                               '+',
10245                               MkExpOp(MkExpMember(MkExpMember(argExp, MkIdentifier("member")), MkIdentifier("offset")),
10246                               '+',
10247                               MkExpMember(MkExpMember(MkExpMember(CopyExpression(argExp), MkIdentifier("member")), MkIdentifier("_class")), MkIdentifier("offset")))))))
10248
10249                            ));
10250                }
10251             }
10252             else if(type.templateParameter && type.templateParameter.type == TemplateParameterType::type &&
10253                (type.templateParameter.dataType || type.templateParameter.dataTypeString))
10254             {
10255                type = ProcessTemplateParameterType(type.templateParameter);
10256             }
10257          }
10258          // TODO: *** This seems to be where we should add method support for all basic types ***
10259          if(type && (type.kind == templateType));
10260          else if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType ||
10261                           type.kind == int64Type || type.kind == shortType || type.kind == longType || type.kind == charType || type.kind == _BoolType ||
10262                           type.kind == intPtrType || type.kind == intSizeType || type.kind == floatType || type.kind == doubleType ||
10263                           (type.kind == pointerType && type.type.kind == charType)))
10264          {
10265             Identifier id = exp.member.member;
10266             TypeKind typeKind = type.kind;
10267             Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10268             if(typeKind == subClassType && exp.member.exp.type == classExp)
10269             {
10270                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
10271                typeKind = classType;
10272             }
10273
10274             if(id)
10275             {
10276                if(typeKind == intType || typeKind == enumType)
10277                   _class = eSystem_FindClass(privateModule, "int");
10278                else if(!_class)
10279                {
10280                   if(type.kind == classType && type._class && type._class.registered)
10281                   {
10282                      _class = type._class.registered;
10283                   }
10284                   else if((type.kind == arrayType || type.kind == pointerType) && type.type && type.type.kind == charType)
10285                   {
10286                      _class = FindClass("char *").registered;
10287                   }
10288                   else if(type.kind == pointerType)
10289                   {
10290                      _class = eSystem_FindClass(privateModule, "uintptr");
10291                      FreeType(exp.expType);
10292                      exp.expType = ProcessTypeString("uintptr", false);
10293                      exp.byReference = true;
10294                   }
10295                   else
10296                   {
10297                      char string[1024] = "";
10298                      Symbol classSym;
10299                      PrintTypeNoConst(type, string, false, true);
10300                      classSym = FindClass(string);
10301                      if(classSym) _class = classSym.registered;
10302                   }
10303                }
10304             }
10305
10306             if(_class && id)
10307             {
10308                /*bool thisPtr =
10309                   (exp.member.exp.type == identifierExp &&
10310                   !strcmp(exp.member.exp.identifier.string, "this"));*/
10311                Property prop = null;
10312                Method method = null;
10313                DataMember member = null;
10314                Property revConvert = null;
10315                ClassProperty classProp = null;
10316
10317                if(id && id._class && id._class.name && !strcmp(id._class.name, "property"))
10318                   exp.member.memberType = propertyMember;
10319
10320                if(id && id._class && type._class && !eClass_IsDerived(type._class.registered, _class))
10321                   Compiler_Error($"invalid class specifier %s for object of class %s\n", _class.fullName, type._class.string);
10322
10323                if(typeKind != subClassType)
10324                {
10325                   // Prioritize data members over properties for "this"
10326                   if((exp.member.memberType == unresolvedMember && thisPtr) || exp.member.memberType == dataMember)
10327                   {
10328                      member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
10329                      if(member && member._class != (_class.templateClass ? _class.templateClass : _class) && exp.member.memberType != dataMember)
10330                      {
10331                         prop = eClass_FindProperty(_class, id.string, privateModule);
10332                         if(prop)
10333                            member = null;
10334                      }
10335                      if(!member && !prop)
10336                         prop = eClass_FindProperty(_class, id.string, privateModule);
10337                      if((member && member._class == (_class.templateClass ? _class.templateClass : _class)) ||
10338                         (prop && prop._class == (_class.templateClass ? _class.templateClass : _class)))
10339                         exp.member.thisPtr = true;
10340                   }
10341                   // Prioritize properties over data members otherwise
10342                   else
10343                   {
10344                      bool useMemberForNonConst = false;
10345                      // First look for Public Members (Unless class specifier is provided, which skips public priority)
10346                      if(!id.classSym)
10347                      {
10348                         prop = eClass_FindProperty(_class, id.string, null);
10349
10350                         useMemberForNonConst = prop && exp.destType &&
10351                            ( (exp.destType.kind == classType && !exp.destType.constant) || ((exp.destType.kind == pointerType || exp.destType.kind == arrayType) && exp.destType.type && !exp.destType.type.constant) ) &&
10352                               !strncmp(prop.dataTypeString, "const ", 6);
10353
10354                         if(useMemberForNonConst || !id._class || !id._class.name || strcmp(id._class.name, "property"))
10355                            member = eClass_FindDataMember(_class, id.string, null, null, null);
10356                      }
10357
10358                      if((!prop || useMemberForNonConst) && !member)
10359                      {
10360                         method = useMemberForNonConst ? null : eClass_FindMethod(_class, id.string, null);
10361                         if(!method)
10362                         {
10363                            prop = eClass_FindProperty(_class, id.string, privateModule);
10364
10365                            useMemberForNonConst |= prop && exp.destType &&
10366                               ( (exp.destType.kind == classType && !exp.destType.constant) || ((exp.destType.kind == pointerType || exp.destType.kind == arrayType) && exp.destType.type && !exp.destType.type.constant) ) &&
10367                                  !strncmp(prop.dataTypeString, "const ", 6);
10368
10369                            if(useMemberForNonConst || !id._class || !id._class.name || strcmp(id._class.name, "property"))
10370                               member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
10371                         }
10372                      }
10373
10374                      if(member && prop)
10375                      {
10376                         if(useMemberForNonConst || (member._class != prop._class && !id._class && eClass_IsDerived(member._class, prop._class)))
10377                            prop = null;
10378                         else
10379                            member = null;
10380                      }
10381                   }
10382                }
10383                if(!prop && !member && !method)     // NOTE: Recently added the !method here, causes private methods to unprioritized
10384                   method = eClass_FindMethod(_class, id.string, privateModule);
10385                if(!prop && !member && !method)
10386                {
10387                   if(typeKind == subClassType)
10388                   {
10389                      classProp = eClass_FindClassProperty(type._class.registered, exp.member.member.string);
10390                      if(classProp)
10391                      {
10392                         exp.member.memberType = classPropertyMember;
10393                         exp.expType = ProcessTypeString(classProp.dataTypeString, false);
10394                      }
10395                      else
10396                      {
10397                         // Assume this is a class_data member
10398                         char structName[1024];
10399                         Identifier id = exp.member.member;
10400                         Expression classExp = exp.member.exp;
10401                         type.refCount++;
10402
10403                         FreeType(classExp.expType);
10404                         classExp.expType = ProcessTypeString("ecere::com::Class", false);
10405
10406                         strcpy(structName, "__ecereClassData_");
10407                         FullClassNameCat(structName, type._class.string, false);
10408                         exp.type = pointerExp;
10409                         exp.member.member = id;
10410
10411                         exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10412                            MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10413                               MkExpBrackets(MkListOne(MkExpOp(
10414                                  MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10415                                     MkExpMember(classExp, MkIdentifier("data"))), '+',
10416                                        MkExpMember(MkExpClass(MkListOne(MkSpecifierName(type._class.string)), null), MkIdentifier("offsetClass")))))
10417                                  )));
10418
10419                         FreeType(type);
10420
10421                         ProcessExpressionType(exp);
10422                         return;
10423                      }
10424                   }
10425                   else
10426                   {
10427                      // Check for reverse conversion
10428                      // (Convert in an instantiation later, so that we can use
10429                      //  deep properties system)
10430                      Symbol classSym = FindClass(id.string);
10431                      if(classSym)
10432                      {
10433                         Class convertClass = classSym.registered;
10434                         if(convertClass)
10435                            revConvert = eClass_FindProperty(convertClass, _class.fullName, privateModule);
10436                      }
10437                   }
10438                }
10439
10440                //if(!exp.member.exp.destType)
10441                if(exp.member.exp.destType)
10442                   FreeType(exp.member.exp.destType);
10443                {
10444                   if(method && !method._class.symbol)
10445                      method._class.symbol = FindClass(method._class.fullName);
10446                   if(prop && !prop._class.symbol)
10447                      prop._class.symbol = FindClass(prop._class.fullName);
10448
10449                   exp.member.exp.destType = Type
10450                   {
10451                      refCount = 1;
10452                      kind = classType;
10453                      _class = prop ? prop._class.symbol : method ? method._class.symbol : _class.symbol;
10454                      // wasThisClass = type ? type.wasThisClass : false;
10455                      thisClassFrom = type ? type.thisClassFrom : null;
10456                   };
10457                }
10458
10459                if(prop)
10460                {
10461                   exp.member.memberType = propertyMember;
10462                   if(!prop.dataType)
10463                      ProcessPropertyType(prop);
10464                   exp.expType = prop.dataType;
10465                   if(!strcmp(_class.base.fullName, "eda::Row") && !exp.expType.constant && !exp.destType)
10466                   {
10467                      Type type { };
10468                      CopyTypeInto(type, exp.expType);
10469                      type.refCount = 1;
10470                      type.constant = true;
10471                      exp.expType = type;
10472                   }
10473                   else if(prop.dataType)
10474                      prop.dataType.refCount++;
10475                }
10476                else if(member)
10477                {
10478                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
10479                   {
10480                      FreeExpContents(exp);
10481                      exp.type = identifierExp;
10482                      exp.identifier = MkIdentifier("class");
10483                      ProcessExpressionType(exp);
10484                      return;
10485                   }
10486
10487                   exp.member.memberType = dataMember;
10488                   DeclareStruct(curExternal, _class.fullName, false, true);
10489                   if(member._class != _class)
10490                      DeclareStruct(curExternal, member._class.fullName, false, true);
10491
10492                   if(!member.dataType)
10493                   {
10494                      Context context = SetupTemplatesContext(_class);
10495                      member.dataType = ProcessTypeString(member.dataTypeString, false);
10496                      FinishTemplatesContext(context);
10497                   }
10498                   if(exp.member.exp.expType.kind == classType && exp.member.exp.expType._class && exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == bitClass)
10499                      member.dataType.bitMemberSize = ((BitMember)member).size;
10500                   exp.expType = member.dataType;
10501                   if(member.dataType) member.dataType.refCount++;
10502                }
10503                else if(revConvert)
10504                {
10505                   exp.member.memberType = reverseConversionMember;
10506                   exp.expType = MkClassType(revConvert._class.fullName);
10507                }
10508                else if(method)
10509                {
10510                   //if(inCompiler)
10511                   {
10512                      /*if(id._class)
10513                      {
10514                         exp.type = identifierExp;
10515                         exp.identifier = exp.member.member;
10516                      }
10517                      else*/
10518                         exp.member.memberType = methodMember;
10519                   }
10520                   if(!method.dataType)
10521                      ProcessMethodType(method);
10522                   exp.expType = Type
10523                   {
10524                      refCount = 1;
10525                      kind = methodType;
10526                      method = method;
10527                   };
10528
10529                   // Tricky spot here... To use instance versus class virtual table
10530                   // Put it back to what it was... What did we break?
10531
10532                   // Had to put it back for overriding Main of Thread global instance
10533
10534                   //exp.expType.methodClass = _class;
10535                   exp.expType.methodClass = (id && id._class) ? _class : null;
10536
10537                   // Need the actual class used for templated classes
10538                   exp.expType.usedClass = _class;
10539                }
10540                else if(!classProp)
10541                {
10542                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
10543                   {
10544                      FreeExpContents(exp);
10545                      exp.type = identifierExp;
10546                      exp.identifier = MkIdentifier("class");
10547                      FreeType(exp.expType);
10548                      exp.expType = MkClassType("ecere::com::Class");
10549                      return;
10550                   }
10551                   yylloc = exp.member.member.loc;
10552                   Compiler_Error($"couldn't find member %s in class %s\n", id.string, _class.fullName);
10553                   if(inCompiler)
10554                      eClass_AddDataMember(_class, id.string, "int", 0, 0, publicAccess);
10555                }
10556
10557                if(_class && /*(_class.templateClass || _class.templateArgs) && */exp.expType)
10558                {
10559                   Class tClass;
10560
10561                   tClass = type._class && type._class.registered ? type._class.registered : _class;
10562                   while(tClass && !tClass.templateClass) tClass = tClass.base;
10563
10564                   if(tClass && exp.expType.kind == templateType && exp.expType.templateParameter.type == TemplateParameterType::type)
10565                   {
10566                      int id = 0;
10567                      ClassTemplateParameter curParam = null;
10568                      Class sClass;
10569
10570                      for(sClass = tClass; sClass; sClass = sClass.base)
10571                      {
10572                         id = 0;
10573                         if(sClass.templateClass) sClass = sClass.templateClass;
10574                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
10575                         {
10576                            if(curParam.type == TemplateParameterType::type && !strcmp(exp.expType.templateParameter.identifier.string, curParam.name))
10577                            {
10578                               for(sClass = sClass.base; sClass; sClass = sClass.base)
10579                                  id += sClass.templateParams.count;
10580                               break;
10581                            }
10582                            id++;
10583                         }
10584                         if(curParam) break;
10585                      }
10586
10587                      if(curParam && tClass.templateArgs[id].dataTypeString)
10588                      {
10589                         ClassTemplateArgument arg = tClass.templateArgs[id];
10590                         Context context = SetupTemplatesContext(tClass);
10591                         bool constant = exp.expType.constant;
10592                         bool passAsTemplate = false;
10593                         Class thisClassFrom = null;
10594                         Type t = ProcessTypeString(exp.expType.templateParameter.dataTypeString, false);
10595                         if(t && t.kind == classType && t._class)
10596                            thisClassFrom = t._class.registered;
10597                         else
10598                            // Mark that 'thisClassFrom' was set to something
10599                            thisClassFrom = eSystem_FindClass(GetPrivateModule(), "class");
10600
10601                         FreeType(t);
10602
10603                         passAsTemplate = tClass.templateClass && (exp.expType.kind != templateType ||
10604                            (!exp.expType.templateParameter || (!exp.expType.templateParameter.dataTypeString && !exp.expType.templateParameter.dataType)));
10605
10606                         /*if(!arg.dataType)
10607                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
10608                         FreeType(exp.expType);
10609
10610                         exp.expType = ProcessTypeString(arg.dataTypeString, false);
10611                         exp.expType.thisClassFrom = thisClassFrom;
10612                         if(exp.expType.kind == classType && constant) exp.expType.constant = true;
10613                         else if(exp.expType.kind == pointerType)
10614                         {
10615                            Type t = exp.expType.type;
10616                            while(t.kind == pointerType) t = t.type;
10617                            if(constant) t.constant = constant;
10618                         }
10619                         if(exp.expType)
10620                         {
10621                            if(exp.expType.kind == thisClassType)
10622                            {
10623                               FreeType(exp.expType);
10624                               exp.expType = ReplaceThisClassType(_class);
10625                            }
10626
10627                            if(passAsTemplate)
10628                               exp.expType.passAsTemplate = true;
10629                            //exp.expType.refCount++;
10630                            if(!exp.destType)
10631                            {
10632                               exp.destType = ProcessTypeString(arg.dataTypeString, false);
10633                               if(exp.destType.kind == classType && constant) exp.destType.constant = true;
10634                               else if(exp.destType.kind == pointerType)
10635                               {
10636                                  Type t = exp.destType.type;
10637                                  while(t.kind == pointerType) t = t.type;
10638                                  if(constant) t.constant = constant;
10639                               }
10640
10641                               //exp.destType.refCount++;
10642
10643                               if(exp.destType.kind == thisClassType)
10644                               {
10645                                  FreeType(exp.destType);
10646                                  exp.destType = ReplaceThisClassType(_class);
10647                               }
10648                            }
10649                         }
10650                         FinishTemplatesContext(context);
10651                      }
10652                   }
10653                   // TODO: MORE GENERIC SUPPORT FOR DEEPER TYPES
10654                   else if(tClass && exp.expType.kind == pointerType && exp.expType.type && exp.expType.type.kind == templateType && exp.expType.type.templateParameter.type == TemplateParameterType::type)
10655                   {
10656                      int id = 0;
10657                      ClassTemplateParameter curParam = null;
10658                      Class sClass;
10659
10660                      for(sClass = tClass; sClass; sClass = sClass.base)
10661                      {
10662                         id = 0;
10663                         if(sClass.templateClass) sClass = sClass.templateClass;
10664                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
10665                         {
10666                            if(curParam.type == TemplateParameterType::type &&
10667                               !strcmp(exp.expType.type.templateParameter.identifier.string, curParam.name))
10668                            {
10669                               for(sClass = sClass.base; sClass; sClass = sClass.base)
10670                                  id += sClass.templateParams.count;
10671                               break;
10672                            }
10673                            id++;
10674                         }
10675                         if(curParam) break;
10676                      }
10677
10678                      if(curParam)
10679                      {
10680                         ClassTemplateArgument arg = tClass.templateArgs[id];
10681                         Context context = SetupTemplatesContext(tClass);
10682                         Type basicType;
10683                         /*if(!arg.dataType)
10684                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
10685
10686                         basicType = ProcessTypeString(arg.dataTypeString, false);
10687                         if(basicType)
10688                         {
10689                            if(basicType.kind == thisClassType)
10690                            {
10691                               FreeType(basicType);
10692                               basicType = ReplaceThisClassType(_class);
10693                            }
10694
10695                            /*    DO WE REALLY WANT THIS HERE? IT SEEMS TO BE ONLY USED WITH Array::array which was causing bug 135
10696                            if(tClass.templateClass)
10697                               basicType.passAsTemplate = true;
10698                            */
10699
10700                            FreeType(exp.expType);
10701
10702                            exp.expType = Type { refCount = 1, kind = pointerType, type = basicType };
10703                            //exp.expType.refCount++;
10704                            if(!exp.destType)
10705                            {
10706                               exp.destType = exp.expType;
10707                               exp.destType.refCount++;
10708                            }
10709
10710                            {
10711                               Expression newExp { };
10712                               OldList * specs = MkList();
10713                               Declarator decl;
10714                               decl = SpecDeclFromString(arg.dataTypeString, specs, null);
10715                               *newExp = *exp;
10716                               if(exp.destType) exp.destType.refCount++;
10717                               if(exp.expType)  exp.expType.refCount++;
10718                               exp.type = bracketsExp;
10719                               exp.list = MkListOne(MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), newExp));
10720                               //FreeType(exp.expType);
10721                               //exp.expType = null;
10722                               //ProcessExpressionType(sourceExp);
10723                            }
10724                         }
10725                         FinishTemplatesContext(context);
10726                      }
10727                   }
10728                   else if(tClass && exp.expType.kind == classType && exp.expType._class && strchr(exp.expType._class.string, '<'))
10729                   {
10730                      Class expClass = exp.expType._class.registered;
10731                      if(expClass)
10732                      {
10733                         Class cClass = null;
10734                         int p = 0;
10735                         int paramCount = 0;
10736                         int lastParam = -1;
10737                         char templateString[1024];
10738                         ClassTemplateParameter param;
10739                         sprintf(templateString, "%s<", expClass.templateClass.fullName);
10740                         while(cClass != expClass)
10741                         {
10742                            Class sClass;
10743                            for(sClass = expClass; sClass && sClass.base != cClass; sClass = sClass.base);
10744                            cClass = sClass;
10745
10746                            for(param = cClass.templateParams.first; param; param = param.next)
10747                            {
10748                               Class cClassCur = null;
10749                               int cp = 0;
10750                               ClassTemplateParameter paramCur = null;
10751                               ClassTemplateArgument arg;
10752                               while(cClassCur != tClass && !paramCur)
10753                               {
10754                                  Class sClassCur;
10755                                  for(sClassCur = tClass; sClassCur && sClassCur.base != cClassCur; sClassCur = sClassCur.base);
10756                                  cClassCur = sClassCur;
10757
10758                                  for(paramCur = cClassCur.templateParams.first; paramCur; paramCur = paramCur.next)
10759                                  {
10760                                     if(!strcmp(paramCur.name, param.name))
10761                                     {
10762
10763                                        break;
10764                                     }
10765                                     cp++;
10766                                  }
10767                               }
10768                               if(paramCur && paramCur.type == TemplateParameterType::type)
10769                                  arg = tClass.templateArgs[cp];
10770                               else
10771                                  arg = expClass.templateArgs[p];
10772
10773                               {
10774                                  char argument[256];
10775                                  argument[0] = '\0';
10776                                  /*if(arg.name)
10777                                  {
10778                                     strcat(argument, arg.name.string);
10779                                     strcat(argument, " = ");
10780                                  }*/
10781                                  switch(param.type)
10782                                  {
10783                                     case expression:
10784                                     {
10785                                        // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
10786                                        char expString[1024];
10787                                        OldList * specs = MkList();
10788                                        Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
10789                                        Expression exp;
10790                                        char * string = PrintHexUInt64(arg.expression.ui64);
10791                                        exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
10792                                        delete string;
10793
10794                                        ProcessExpressionType(exp);
10795                                        ComputeExpression(exp);
10796                                        expString[0] = '\0';
10797                                        PrintExpression(exp, expString);
10798                                        strcat(argument, expString);
10799                                        // delete exp;
10800                                        FreeExpression(exp);
10801                                        break;
10802                                     }
10803                                     case identifier:
10804                                     {
10805                                        strcat(argument, arg.member.name);
10806                                        break;
10807                                     }
10808                                     case TemplateParameterType::type:
10809                                     {
10810                                        if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10811                                           strcat(argument, arg.dataTypeString);
10812                                        break;
10813                                     }
10814                                  }
10815                                  if(argument[0])
10816                                  {
10817                                     if(paramCount) strcat(templateString, ", ");
10818                                     if(lastParam != p - 1)
10819                                     {
10820                                        strcat(templateString, param.name);
10821                                        strcat(templateString, " = ");
10822                                     }
10823                                     strcat(templateString, argument);
10824                                     paramCount++;
10825                                     lastParam = p;
10826                                  }
10827                               }
10828                               p++;
10829                            }
10830                         }
10831                         {
10832                            int len = strlen(templateString);
10833                            if(templateString[len-1] == '>') templateString[len++] = ' ';
10834                            templateString[len++] = '>';
10835                            templateString[len++] = '\0';
10836                         }
10837
10838                         FreeType(exp.expType);
10839                         {
10840                            Context context = SetupTemplatesContext(tClass);
10841                            exp.expType = ProcessTypeString(templateString, false);
10842                            FinishTemplatesContext(context);
10843                         }
10844                      }
10845                   }
10846                }
10847             }
10848             else
10849                Compiler_Error($"undefined class %s\n", (id && (!id._class || id._class.name))? (id.classSym ? id.classSym.string : (type._class ? type._class.string : null)) : "(null)");
10850          }
10851          else if(type && (type.kind == structType || type.kind == unionType))
10852          {
10853             Type memberType = exp.member.member ? FindMember(type, exp.member.member.string) : null;
10854             if(memberType)
10855             {
10856                exp.expType = memberType;
10857                if(memberType)
10858                   memberType.refCount++;
10859             }
10860          }
10861          else
10862          {
10863             char expString[10240];
10864             expString[0] = '\0';
10865             if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10866             Compiler_Error($"member operator on non-structure type expression %s\n", expString);
10867          }
10868
10869          if(exp.expType && exp.expType.kind == thisClassType && (!exp.destType || exp.destType.kind != thisClassType))
10870          {
10871             if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType))
10872             {
10873                Identifier id = exp.member.member;
10874                Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10875                if(_class)
10876                {
10877                   FreeType(exp.expType);
10878                   exp.expType = ReplaceThisClassType(_class);
10879                }
10880             }
10881          }
10882          yylloc = oldyylloc;
10883          break;
10884       }
10885       // Convert x->y into (*x).y
10886       case pointerExp:
10887       {
10888          Type destType = exp.destType;
10889
10890          // DOING THIS LATER NOW...
10891          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
10892          {
10893             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
10894             /* TODO: Name Space Fix ups
10895             if(!exp.member.member.classSym)
10896                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.name);
10897             */
10898          }
10899
10900          exp.member.exp = MkExpBrackets(MkListOne(MkExpOp(null, '*', exp.member.exp)));
10901          exp.type = memberExp;
10902          if(destType)
10903             destType.count++;
10904          ProcessExpressionType(exp);
10905          if(destType)
10906             destType.count--;
10907          break;
10908       }
10909       case classSizeExp:
10910       {
10911          //ComputeExpression(exp);
10912
10913          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
10914          if(classSym && classSym.registered)
10915          {
10916             if(classSym.registered.type == noHeadClass || (classSym.registered.fixed && classSym.registered.structSize))
10917             {
10918                char name[1024];
10919                Class b = classSym.registered;
10920                name[0] = '\0';
10921                DeclareStruct(curExternal, classSym.string, false, true);
10922                FreeSpecifier(exp._class);
10923                FullClassNameCat(name, classSym.string, false);
10924
10925                if(b.offset == 0)
10926                {
10927                   exp.type = typeSizeExp;
10928                   exp.typeName = MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null);
10929                }
10930                else
10931                {
10932                   Expression e;
10933                   exp.type = opExp;
10934                   if(b.structSize == b.offset)
10935                      exp.op.exp1 = MkExpConstant("0");
10936                   else
10937                      exp.op.exp1 = MkExpTypeSize(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null));
10938                   exp.op.op = '+';
10939                   e = exp;
10940                   while(b.offset != 0)
10941                   {
10942                      Symbol sym;
10943                      Expression typeSize;
10944
10945                      b = b.base;
10946                      sym = FindClass(b.fullName);
10947
10948                      name[0] = '\0';
10949                      DeclareStruct(curExternal, sym.string, false, true);
10950                      FullClassNameCat(name, sym.string, false);
10951
10952                      if(b.structSize == b.offset)
10953                         typeSize = MkExpConstant("0");
10954                      else
10955                         typeSize = MkExpTypeSize(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null));
10956                      e.op.exp2 = b.offset ? MkExpOp(typeSize, '+', null) : typeSize;
10957                      e = e.op.exp2;
10958                   }
10959                }
10960             }
10961             else
10962             {
10963                if(classSym.registered.fixed && !classSym.registered.structSize)
10964                {
10965                   FreeSpecifier(exp._class);
10966                   exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
10967                   exp.type = constantExp;
10968                }
10969                else
10970                {
10971                   char className[1024];
10972                   strcpy(className, "__ecereClass_");
10973                   FullClassNameCat(className, classSym.string, true);
10974
10975                   DeclareClass(curExternal, classSym, className);
10976
10977                   FreeExpContents(exp);
10978                   exp.type = pointerExp;
10979                   exp.member.exp = MkExpIdentifier(MkIdentifier(className));
10980                   exp.member.member = MkIdentifier("structSize");
10981                }
10982             }
10983          }
10984
10985          exp.expType = Type
10986          {
10987             refCount = 1;
10988             kind = intSizeType;
10989          };
10990          // exp.isConstant = true;
10991          break;
10992       }
10993       case typeSizeExp:
10994       {
10995          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
10996
10997          exp.expType = Type
10998          {
10999             refCount = 1;
11000             kind = intSizeType;
11001          };
11002          exp.isConstant = true;
11003
11004          DeclareType(curExternal, type, true, false);
11005          FreeType(type);
11006          break;
11007       }
11008       case castExp:
11009       {
11010          Type type = ProcessType(exp.cast.typeName.qualifiers, exp.cast.typeName.declarator);
11011          type.count = 1;
11012          FreeType(exp.cast.exp.destType);
11013          exp.cast.exp.destType = type;
11014          type.refCount++;
11015          type.casted = true;
11016          ProcessExpressionType(exp.cast.exp);
11017          type.casted = false;
11018          type.count = 0;
11019          exp.expType = type;
11020          //type.refCount++;
11021
11022          // if(!NeedCast(exp.cast.exp.expType, exp.cast.exp.destType))
11023          if(!exp.cast.exp.needCast && !NeedCast(exp.cast.exp.expType, type))
11024          {
11025             void * prev = exp.prev, * next = exp.next;
11026             Type expType = exp.cast.exp.destType;
11027             Expression castExp = exp.cast.exp;
11028             Type destType = exp.destType;
11029
11030             if(expType) expType.refCount++;
11031
11032             //FreeType(exp.destType);
11033             FreeType(exp.expType);
11034             FreeTypeName(exp.cast.typeName);
11035
11036             *exp = *castExp;
11037             FreeType(exp.expType);
11038             FreeType(exp.destType);
11039
11040             exp.expType = expType;
11041             exp.destType = destType;
11042
11043             delete castExp;
11044
11045             exp.prev = prev;
11046             exp.next = next;
11047
11048          }
11049          else
11050          {
11051             exp.isConstant = exp.cast.exp.isConstant;
11052          }
11053          //FreeType(type);
11054          break;
11055       }
11056       case extensionInitializerExp:
11057       {
11058          Type type = ProcessType(exp.initializer.typeName.qualifiers, exp.initializer.typeName.declarator);
11059          // We have yet to support this... ( { } initializers are currently processed inside ProcessDeclaration()'s initDeclaration case statement
11060          // ProcessInitializer(exp.initializer.initializer, type);
11061          exp.expType = type;
11062          break;
11063       }
11064       case vaArgExp:
11065       {
11066          Type type = ProcessType(exp.vaArg.typeName.qualifiers, exp.vaArg.typeName.declarator);
11067          ProcessExpressionType(exp.vaArg.exp);
11068          exp.expType = type;
11069          break;
11070       }
11071       case conditionExp:
11072       {
11073          Expression e;
11074          Type t = exp.destType;
11075          if(t && !exp.destType.casted)
11076          {
11077             t = { };
11078             CopyTypeInto(t, exp.destType);
11079             t.count = 0;
11080          }
11081          else if(t)
11082             t.refCount++;
11083
11084          exp.isConstant = true;
11085
11086          FreeType(exp.cond.cond.destType);
11087          exp.cond.cond.destType = MkClassType("bool");
11088          exp.cond.cond.destType.truth = true;
11089          ProcessExpressionType(exp.cond.cond);
11090          if(!exp.cond.cond.isConstant)
11091             exp.isConstant = false;
11092          for(e = exp.cond.exp->first; e; e = e.next)
11093          {
11094             if(!e.next)
11095             {
11096                FreeType(e.destType);
11097                e.destType = t;
11098                if(e.destType) e.destType.refCount++;
11099             }
11100             ProcessExpressionType(e);
11101             if(!e.next)
11102             {
11103                exp.expType = e.expType;
11104                if(e.expType) e.expType.refCount++;
11105             }
11106             if(!e.isConstant)
11107                exp.isConstant = false;
11108          }
11109
11110          FreeType(exp.cond.elseExp.destType);
11111          // Added this check if we failed to find an expType
11112          // exp.cond.elseExp.destType = exp.expType ? exp.expType : exp.destType;
11113
11114          // Reversed it...
11115          exp.cond.elseExp.destType = t ? t : exp.expType;
11116
11117          if(exp.cond.elseExp.destType)
11118             exp.cond.elseExp.destType.refCount++;
11119          ProcessExpressionType(exp.cond.elseExp);
11120
11121          // FIXED THIS: Was done before calling process on elseExp
11122          if(!exp.cond.elseExp.isConstant)
11123             exp.isConstant = false;
11124
11125          FreeType(t);
11126          break;
11127       }
11128       case extensionCompoundExp:
11129       {
11130          if(exp.compound && exp.compound.compound.statements && exp.compound.compound.statements->last)
11131          {
11132             Statement last = exp.compound.compound.statements->last;
11133             if(last.type == expressionStmt && last.expressions && last.expressions->last)
11134             {
11135                ((Expression)last.expressions->last).destType = exp.destType;
11136                if(exp.destType)
11137                   exp.destType.refCount++;
11138             }
11139             ProcessStatement(exp.compound);
11140             exp.expType = (last.expressions && last.expressions->last) ? ((Expression)last.expressions->last).expType : null;
11141             if(exp.expType)
11142                exp.expType.refCount++;
11143          }
11144          break;
11145       }
11146       case classExp:
11147       {
11148          Specifier spec = exp._classExp.specifiers->first;
11149          if(spec && spec.type == nameSpecifier)
11150          {
11151             exp.expType = MkClassType(spec.name);
11152             exp.expType.kind = subClassType;
11153             exp.byReference = true;
11154          }
11155          else
11156          {
11157             exp.expType = MkClassType("ecere::com::Class");
11158             exp.byReference = true;
11159          }
11160          break;
11161       }
11162       case classDataExp:
11163       {
11164          Class _class = thisClass ? thisClass : currentClass;
11165          if(_class)
11166          {
11167             Identifier id = exp.classData.id;
11168             char structName[1024];
11169             Expression classExp;
11170             strcpy(structName, "__ecereClassData_");
11171             FullClassNameCat(structName, _class.fullName, false);
11172             exp.type = pointerExp;
11173             exp.member.member = id;
11174             if(curCompound && FindSymbol("this", curContext, curCompound.compound.context, false, false))
11175                classExp = MkExpMember(MkExpIdentifier(MkIdentifier("this")), MkIdentifier("_class"));
11176             else
11177                classExp = MkExpIdentifier(MkIdentifier("class"));
11178
11179             exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
11180                MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
11181                   MkExpBrackets(MkListOne(MkExpOp(
11182                      MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
11183                         MkExpMember(classExp, MkIdentifier("data"))), '+',
11184                            MkExpMember(MkExpClass(MkListOne(MkSpecifierName(_class.fullName)), null), MkIdentifier("offsetClass")))))
11185                      )));
11186
11187             ProcessExpressionType(exp);
11188             return;
11189          }
11190          break;
11191       }
11192       case arrayExp:
11193       {
11194          Type type = null;
11195          const char * typeString = null;
11196          char typeStringBuf[1024];
11197          if(exp.destType && exp.destType.kind == classType && exp.destType._class && exp.destType._class.registered &&
11198             exp.destType._class.registered != containerClass && eClass_IsDerived(exp.destType._class.registered, containerClass))
11199          {
11200             Class templateClass = exp.destType._class.registered;
11201             typeString = templateClass.templateArgs[2].dataTypeString;
11202          }
11203          else if(exp.list)
11204          {
11205             // Guess type from expressions in the array
11206             Expression e;
11207             for(e = exp.list->first; e; e = e.next)
11208             {
11209                ProcessExpressionType(e);
11210                if(e.expType)
11211                {
11212                   if(!type) { type = e.expType; type.refCount++; }
11213                   else
11214                   {
11215                      // if(!MatchType(e.expType, type, null, null, null, false, false, false))
11216                      if(!MatchTypeExpression(e, type, null, false, true))
11217                      {
11218                         FreeType(type);
11219                         type = e.expType;
11220                         e.expType = null;
11221
11222                         e = exp.list->first;
11223                         ProcessExpressionType(e);
11224                         if(e.expType)
11225                         {
11226                            //if(!MatchTypes(e.expType, type, null, null, null, false, false, false))
11227                            if(!MatchTypeExpression(e, type, null, false, true))
11228                            {
11229                               FreeType(e.expType);
11230                               e.expType = null;
11231                               FreeType(type);
11232                               type = null;
11233                               break;
11234                            }
11235                         }
11236                      }
11237                   }
11238                   if(e.expType)
11239                   {
11240                      FreeType(e.expType);
11241                      e.expType = null;
11242                   }
11243                }
11244             }
11245             if(type)
11246             {
11247                typeStringBuf[0] = '\0';
11248                PrintTypeNoConst(type, typeStringBuf, false, true);
11249                typeString = typeStringBuf;
11250                FreeType(type);
11251                type = null;
11252             }
11253          }
11254          if(typeString)
11255          {
11256             /*
11257             (Container)& (struct BuiltInContainer)
11258             {
11259                ._vTbl = class(BuiltInContainer)._vTbl,
11260                ._class = class(BuiltInContainer),
11261                .refCount = 0,
11262                .data = (int[]){ 1, 7, 3, 4, 5 },
11263                .count = 5,
11264                .type = class(int),
11265             }
11266             */
11267             char templateString[1024];
11268             OldList * initializers = MkList();
11269             OldList * structInitializers = MkList();
11270             OldList * specs = MkList();
11271             Expression expExt;
11272             Declarator decl = SpecDeclFromString(typeString, specs, null);
11273             sprintf(templateString, "Container<%s>", typeString);
11274
11275             if(exp.list)
11276             {
11277                Expression e;
11278                type = ProcessTypeString(typeString, false);
11279                while((e = exp.list->first))
11280                {
11281                   exp.list->Remove(e);
11282                   e.destType = type;
11283                   type.refCount++;
11284                   ProcessExpressionType(e);
11285                   ListAdd(initializers, MkInitializerAssignment(e));
11286                }
11287                FreeType(type);
11288                delete exp.list;
11289             }
11290
11291             DeclareStruct(curExternal, "ecere::com::BuiltInContainer", false, true);
11292
11293             ListAdd(structInitializers, /*MkIdentifier("_vTbl")*/    MkInitializerAssignment(MkExpMember(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null), MkIdentifier("_vTbl"))));
11294                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11295             ListAdd(structInitializers, /*MkIdentifier("_class")*/   MkInitializerAssignment(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null)));
11296                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11297             ListAdd(structInitializers, /*MkIdentifier("_refCount")*/MkInitializerAssignment(MkExpConstant("0")));
11298                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11299             ListAdd(structInitializers, /*MkIdentifier("data")*/     MkInitializerAssignment(MkExpExtensionInitializer(
11300                MkTypeName(specs, MkDeclaratorArray(decl, null)),
11301                MkInitializerList(initializers))));
11302                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11303             ListAdd(structInitializers, /*MkIdentifier("count")*/    MkInitializerAssignment({ type = constantExp, constant = PrintString(initializers->count) }));
11304                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11305             ListAdd(structInitializers, /*MkIdentifier("type")*/     MkInitializerAssignment(MkExpClass(CopyList(specs, CopySpecifier), CopyDeclarator(decl))));
11306                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11307             exp.expType = ProcessTypeString(templateString, false);
11308             exp.type = bracketsExp;
11309             exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(templateString)), null),
11310                MkExpOp(null, '&',
11311                expExt = MkExpExtensionInitializer(MkTypeName(MkListOne(MkSpecifierName("BuiltInContainer")), null),
11312                   MkInitializerList(structInitializers)))));
11313             ProcessExpressionType(expExt);
11314          }
11315          else
11316          {
11317             exp.expType = ProcessTypeString("Container", false);
11318             Compiler_Error($"Couldn't determine type of array elements\n");
11319          }
11320          break;
11321       }
11322    }
11323
11324    if(exp.expType && exp.expType.kind == thisClassType && thisClass && (!exp.destType || exp.destType.kind != thisClassType))
11325    {
11326       FreeType(exp.expType);
11327       exp.expType = ReplaceThisClassType(thisClass);
11328    }
11329
11330    // Resolve structures here
11331    if(exp.expType && (exp.expType.kind == structType || exp.expType.kind == unionType || exp.expType.kind == enumType) && !exp.expType.members.first && exp.expType.enumName)
11332    {
11333       Symbol symbol = FindSymbol(exp.expType.enumName, curContext, globalContext, true, false);
11334       // TODO: Fix members reference...
11335       if(symbol)
11336       {
11337          if(exp.expType.kind != enumType)
11338          {
11339             Type member;
11340             String enumName = CopyString(exp.expType.enumName);
11341
11342             // Fixed a memory leak on self-referencing C structs typedefs
11343             // by instantiating a new type rather than simply copying members
11344             // into exp.expType
11345             FreeType(exp.expType);
11346             exp.expType = Type { };
11347             exp.expType.kind = symbol.type.kind;
11348             exp.expType.refCount++;
11349             exp.expType.enumName = enumName;
11350
11351             exp.expType.members = symbol.type.members;
11352             for(member = symbol.type.members.first; member; member = member.next)
11353                member.refCount++;
11354          }
11355          else
11356          {
11357             NamedLink64 member;
11358             for(member = symbol.type.members.first; member; member = member.next)
11359             {
11360                NamedLink64 value { name = CopyString(member.name) };
11361                exp.expType.members.Add(value);
11362             }
11363          }
11364       }
11365    }
11366
11367    // Trying to do this here before conversion properties kick in and this becomes a new expression... (Fixing Class c; const char * a = c;)
11368    // Mark nohead classes as by reference, unless we're casting them to an integral type
11369    if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
11370       exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
11371          (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
11372           exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
11373    {
11374       exp.byReference = true;
11375    }
11376
11377    yylloc = exp.loc;
11378    if(exp.destType && (/*exp.destType.kind == voidType || */exp.destType.kind == dummyType) );
11379    else if(exp.destType && !exp.destType.keepCast)
11380    {
11381       if(!exp.needTemplateCast && exp.expType && (exp.expType.kind == templateType || exp.expType.passAsTemplate)) // && exp.destType && !exp.destType.passAsTemplate)
11382          exp.needTemplateCast = 1;
11383
11384       if(exp.destType.kind == voidType);
11385       else if(!CheckExpressionType(exp, exp.destType, false, !exp.destType.casted))
11386       {
11387          // Warn for casting unrelated types to/from struct classes
11388          bool invalidCast = false;
11389          if(inCompiler && exp.destType.count && exp.expType)
11390          {
11391             Class c1 = (exp.expType.kind == classType && exp.expType._class) ? exp.expType._class.registered : null;
11392             Class c2 = (exp.destType.kind == classType && exp.destType._class) ? exp.destType._class.registered : null;
11393             if(c1 && c1.type != structClass) c1 = null;
11394             if(c2 && c2.type != structClass) c2 = null;
11395             if((c1 && !exp.expType.byReference && !c2 && !exp.destType.isPointerType) || (c2 && !exp.destType.byReference && !c1 && !exp.expType.isPointerType))
11396                invalidCast = true;
11397          }
11398          if(!exp.destType.count || unresolved || invalidCast)
11399          {
11400             if(!exp.expType)
11401             {
11402                yylloc = exp.loc;
11403                if(exp.destType.kind != ellipsisType)
11404                {
11405                   char type2[1024];
11406                   type2[0] = '\0';
11407                   if(inCompiler)
11408                   {
11409                      char expString[10240];
11410                      expString[0] = '\0';
11411
11412                      PrintType(exp.destType, type2, false, true);
11413
11414                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11415                      if(unresolved)
11416                         Compiler_Error($"unresolved identifier %s; expected %s\n", expString, type2);
11417                      else if(exp.type != dummyExp)
11418                         Compiler_Error($"couldn't determine type of %s; expected %s\n", expString, type2);
11419                   }
11420                }
11421                else
11422                {
11423                   char expString[10240] ;
11424                   expString[0] = '\0';
11425                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11426
11427                   if(unresolved)
11428                      Compiler_Error($"unresolved identifier %s\n", expString);
11429                   else if(exp.type != dummyExp)
11430                      Compiler_Error($"couldn't determine type of %s\n", expString);
11431                }
11432             }
11433             else
11434             {
11435                char type1[1024];
11436                char type2[1024];
11437                type1[0] = '\0';
11438                type2[0] = '\0';
11439                if(inCompiler)
11440                {
11441                   PrintType(exp.expType, type1, false, true);
11442                   PrintType(exp.destType, type2, false, true);
11443                }
11444
11445                //CheckExpressionType(exp, exp.destType, false);
11446
11447                if(exp.destType.truth && exp.destType._class && exp.destType._class.registered && !strcmp(exp.destType._class.registered.name, "bool") &&
11448                   exp.expType.kind != voidType && exp.expType.kind != structType && exp.expType.kind != unionType &&
11449                   (exp.expType.kind != classType || exp.expType.classObjectType || (exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type != structClass)));
11450                else
11451                {
11452                   Expression nbExp = GetNonBracketsExp(exp);
11453                   bool skipWarning = false;
11454                   TypeKind kind = exp.destType.kind;
11455                   if(nbExp.type == conditionExp && nbExp.destType && !nbExp.destType.casted && nbExp.destType.kind == exp.destType.kind)
11456                      // The if/else operands have already been checked / warned about
11457                      skipWarning = true;
11458                   if((kind == charType || kind == shortType) && exp.destType.isSigned == exp.expType.signedBeforePromotion && nbExp.type == opExp && nbExp.op.exp1 && nbExp.op.exp2)
11459                   {
11460                      int op = nbExp.op.op;
11461                      Expression nbExp1, nbExp2;
11462                      TypeKind from;
11463
11464                      switch(op)
11465                      {
11466                         case '%': case '/':
11467                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11468                            from = nbExp1.expType.promotedFrom;
11469                            // Division and Modulo will not take more room than type before promotion
11470                            if(from == charType || (kind == shortType && from == shortType))
11471                               skipWarning = true;
11472                            break;
11473                         // Left shift
11474                         case LEFT_OP: case RIGHT_OP:
11475                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11476                            nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11477                            from = nbExp1.expType.promotedFrom;
11478                            // Right shift will not take more room than type before promotion
11479                            if(op == RIGHT_OP && (from == charType || (kind == shortType && from == shortType)))
11480                               skipWarning = true;
11481                            else if(nbExp2.isConstant && nbExp2.type == constantExp && (nbExp.op.op == RIGHT_OP || nbExp1.expType.bitMemberSize))
11482                            {
11483                               int n = (int)strtol(nbExp2.constant, null, 0);
11484                               int s = from == charType ? 8 : 16;
11485                               // Left shifting a bit member constrained in size may still fit in type before promotion
11486                               if(nbExp1.expType.bitMemberSize && nbExp1.expType.bitMemberSize < s)
11487                                  s = nbExp1.expType.bitMemberSize;
11488
11489                               // If right shifted enough things will fit in smaller type
11490                               if(nbExp.op.op == RIGHT_OP)
11491                                  s -= n;
11492                               else
11493                                  s += n;
11494                               if(s <= (kind == charType ? 8 : 16))
11495                                  skipWarning = true;
11496                            }
11497                            break;
11498                         case '-':
11499                            if(!exp.destType.isSigned)
11500                            {
11501                               nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11502                               nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11503                               from = nbExp2.expType.promotedFrom;
11504                               // Max value of unsigned type before promotion minus the same will always fit
11505                               if((from == charType || from == shortType) && nbExp1.isConstant && nbExp1.type == constantExp)
11506                               {
11507                                  int n = (int)strtol(nbExp1.constant, null, 0);
11508                                  if(n == (from == charType ? 255 : 65535))
11509                                     skipWarning = true;
11510                               }
11511                            }
11512                            break;
11513                         case '|':
11514                         {
11515                            TypeKind kind1, kind2;
11516                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11517                            nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11518                            kind1 = nbExp1.expType.promotedFrom ? nbExp1.expType.promotedFrom : nbExp1.expType.kind;
11519                            kind2 = nbExp2.expType.promotedFrom ? nbExp2.expType.promotedFrom : nbExp2.expType.kind;
11520                            if(((kind1 == charType || (kind1 == shortType && kind == shortType)) || MatchTypeExpression(nbExp1, exp.destType, null, false, false)) &&
11521                               ((kind2 == charType || (kind2 == shortType && kind == shortType)) || MatchTypeExpression(nbExp2, exp.destType, null, false, false)))
11522                               skipWarning = true;
11523                            break;
11524                         }
11525                         case '&':
11526                         {
11527                            TypeKind kind1, kind2;
11528                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11529                            nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11530                            kind1 = nbExp1.expType.promotedFrom ? nbExp1.expType.promotedFrom : nbExp1.expType.kind;
11531                            kind2 = nbExp2.expType.promotedFrom ? nbExp2.expType.promotedFrom : nbExp2.expType.kind;
11532                            if(((kind1 == charType || (kind1 == shortType && kind == shortType)) || MatchTypeExpression(nbExp1, exp.destType, null, false, false)) ||
11533                               ((kind2 == charType || (kind2 == shortType && kind == shortType)) || MatchTypeExpression(nbExp2, exp.destType, null, false, false)))
11534                               skipWarning = true;
11535                            break;
11536                         }
11537                      }
11538                   }
11539
11540                   if(!skipWarning)
11541                   {
11542                      char expString[10240];
11543                      expString[0] = '\0';
11544                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11545
11546 #ifdef _DEBUG
11547                      CheckExpressionType(exp, exp.destType, false, true);
11548 #endif
11549
11550                      // Flex & Bison generate code that triggers this, so we ignore it for a quiet sdk build:
11551                      if(!sourceFile || (!strstr(sourceFile, "src\\lexer.ec") && !strstr(sourceFile, "src/lexer.ec") &&
11552                                         !strstr(sourceFile, "src\\grammar.ec") && !strstr(sourceFile, "src/grammar.ec") &&
11553                                         !strstr(sourceFile, "src\\type.ec") && !strstr(sourceFile, "src/type.ec") &&
11554                                         !strstr(sourceFile, "src\\expression.ec") && !strstr(sourceFile, "src/expression.ec")))
11555                      {
11556                         if(invalidCast)
11557                            Compiler_Error($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
11558                         else
11559                            Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
11560                      }
11561                   }
11562
11563                   // TO CHECK: FORCING HERE TO HELP DEBUGGER
11564                   if(!inCompiler)
11565                   {
11566                      FreeType(exp.expType);
11567                      exp.destType.refCount++;
11568                      exp.expType = exp.destType;
11569                   }
11570                }
11571             }
11572          }
11573       }
11574       // Cast function pointers to void * as eC already checked compatibility
11575       else if(exp.destType && exp.destType.kind == pointerType && exp.destType.type && exp.destType.type.kind == functionType &&
11576               exp.expType && (exp.expType.kind == functionType || exp.expType.kind == methodType))
11577       {
11578          Expression nbExp = GetNonBracketsExp(exp);
11579          if(nbExp.type != castExp || !IsVoidPtrCast(nbExp.cast.typeName))
11580          {
11581             Expression e = MoveExpContents(exp);
11582             exp.cast.exp = MkExpBrackets(MkListOne(e));
11583             exp.type = castExp;
11584             exp.cast.exp.destType = exp.destType;
11585             if(exp.destType) exp.destType.refCount++;
11586             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
11587          }
11588       }
11589    }
11590    else if(unresolved)
11591    {
11592       if(exp.identifier._class && exp.identifier._class.name)
11593          Compiler_Error($"unresolved identifier %s::%s\n", exp.identifier._class.name, exp.identifier.string);
11594       else if(exp.identifier.string && exp.identifier.string[0])
11595          Compiler_Error($"unresolved identifier %s\n", exp.identifier.string);
11596    }
11597    else if(!exp.expType && exp.type != dummyExp)
11598    {
11599       char expString[10240];
11600       expString[0] = '\0';
11601       if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11602       Compiler_Error($"couldn't determine type of %s\n", expString);
11603    }
11604
11605    // Let's try to support any_object & typed_object here:
11606    if(inCompiler)
11607       ApplyAnyObjectLogic(exp);
11608
11609    // Mark nohead classes as by reference, unless we're casting them to an integral type
11610    if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
11611       exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
11612          (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
11613           exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
11614    {
11615       exp.byReference = true;
11616    }
11617    yylloc = oldyylloc;
11618 }
11619
11620 static void FindNextDataMember(Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
11621 {
11622    // THIS CODE WILL FIND NEXT MEMBER...
11623    if(*curMember)
11624    {
11625       *curMember = (*curMember).next;
11626
11627       if(subMemberStackPos && *subMemberStackPos > 0 && subMemberStack[*subMemberStackPos-1].type == unionMember)
11628       {
11629          *curMember = subMemberStack[--(*subMemberStackPos)];
11630          *curMember = (*curMember).next;
11631       }
11632
11633       // SKIP ALL PROPERTIES HERE...
11634       while((*curMember) && (*curMember).isProperty)
11635          *curMember = (*curMember).next;
11636
11637       if(subMemberStackPos)
11638       {
11639          while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
11640          {
11641             subMemberStack[(*subMemberStackPos)++] = *curMember;
11642
11643             *curMember = (*curMember).members.first;
11644             while(*curMember && (*curMember).isProperty)
11645                *curMember = (*curMember).next;
11646          }
11647       }
11648    }
11649    while(!*curMember)
11650    {
11651       if(!*curMember)
11652       {
11653          if(subMemberStackPos && *subMemberStackPos)
11654          {
11655             *curMember = subMemberStack[--(*subMemberStackPos)];
11656             *curMember = (*curMember).next;
11657          }
11658          else
11659          {
11660             Class lastCurClass = *curClass;
11661
11662             if(*curClass == _class) break;     // REACHED THE END
11663
11664             for(*curClass = _class; (*curClass).base != lastCurClass && (*curClass).base.type != systemClass; *curClass = (*curClass).base);
11665             *curMember = (*curClass).membersAndProperties.first;
11666          }
11667
11668          while((*curMember) && (*curMember).isProperty)
11669             *curMember = (*curMember).next;
11670          if(subMemberStackPos)
11671          {
11672             while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
11673             {
11674                subMemberStack[(*subMemberStackPos)++] = *curMember;
11675
11676                *curMember = (*curMember).members.first;
11677                while(*curMember && (*curMember).isProperty)
11678                   *curMember = (*curMember).next;
11679             }
11680          }
11681       }
11682    }
11683 }
11684
11685
11686 static void ProcessInitializer(Initializer init, Type type)
11687 {
11688    switch(init.type)
11689    {
11690       case expInitializer:
11691          if(!init.exp || init.exp.type != instanceExp || !init.exp.instance || init.exp.instance._class || !type || type.kind == classType)
11692          {
11693             // TESTING THIS FOR SHUTTING = 0 WARNING
11694             if(init.exp && !init.exp.destType)
11695             {
11696                FreeType(init.exp.destType);
11697                init.exp.destType = type;
11698                if(type) type.refCount++;
11699             }
11700             if(init.exp)
11701             {
11702                ProcessExpressionType(init.exp);
11703                init.isConstant = init.exp.isConstant;
11704             }
11705             break;
11706          }
11707          else
11708          {
11709             Expression exp = init.exp;
11710             Instantiation inst = exp.instance;
11711             MembersInit members;
11712
11713             init.type = listInitializer;
11714             init.list = MkList();
11715
11716             if(inst.members)
11717             {
11718                for(members = inst.members->first; members; members = members.next)
11719                {
11720                   if(members.type == dataMembersInit)
11721                   {
11722                      MemberInit member;
11723                      for(member = members.dataMembers->first; member; member = member.next)
11724                      {
11725                         ListAdd(init.list, member.initializer);
11726                         member.initializer = null;
11727                      }
11728                   }
11729                   // Discard all MembersInitMethod
11730                }
11731             }
11732             FreeExpression(exp);
11733          }
11734       case listInitializer:
11735       {
11736          Initializer i;
11737          Type initializerType = null;
11738          Class curClass = null;
11739          DataMember curMember = null;
11740          DataMember subMemberStack[256];
11741          int subMemberStackPos = 0;
11742
11743          if(type && type.kind == arrayType)
11744             initializerType = Dereference(type);
11745          else if(type && (type.kind == structType || type.kind == unionType))
11746             initializerType = type.members.first;
11747
11748          for(i = init.list->first; i; i = i.next)
11749          {
11750             if(type && type.kind == classType && type._class && type._class.registered)
11751             {
11752                // THIS IS FOR A C STYLE INSTANTIATION OF STRUCT CLASSES ONLY... WE ONLY CARE ABOUT DATA MEMBERS, AND ACTUAL MEMORY ORDER (PRIVATE MEMBERS ARE INCLUDED)
11753                FindNextDataMember(type._class.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
11754                // TODO: Generate error on initializing a private data member this way from another module...
11755                if(curMember)
11756                {
11757                   if(!curMember.dataType)
11758                      curMember.dataType = ProcessTypeString(curMember.dataTypeString, false);
11759                   initializerType = curMember.dataType;
11760                }
11761             }
11762             ProcessInitializer(i, initializerType);
11763             if(initializerType && type && (type.kind == structType || type.kind == unionType))
11764                initializerType = initializerType.next;
11765             if(!i.isConstant)
11766                init.isConstant = false;
11767          }
11768
11769          if(type && type.kind == arrayType)
11770             FreeType(initializerType);
11771
11772          if(type && type.kind != arrayType && type.kind != structType && type.kind != unionType && (type.kind != classType || !type._class.registered || type._class.registered.type != structClass))
11773          {
11774             Compiler_Error($"Assigning list initializer to non list\n");
11775          }
11776          break;
11777       }
11778    }
11779 }
11780
11781 static void ProcessSpecifier(Specifier spec, bool declareStruct, bool warnClasses)
11782 {
11783    switch(spec.type)
11784    {
11785       case baseSpecifier:
11786       {
11787          if(spec.specifier == THISCLASS)
11788          {
11789             if(thisClass)
11790             {
11791                spec.type = nameSpecifier;
11792                spec.name = ReplaceThisClass(thisClass);
11793                spec.symbol = FindClass(spec.name);
11794                ProcessSpecifier(spec, declareStruct, false);
11795             }
11796          }
11797          break;
11798       }
11799       case nameSpecifier:
11800       {
11801          Symbol symbol = FindType(curContext, spec.name);
11802          if(symbol)
11803             DeclareType(curExternal, symbol.type, true, true);
11804          else if(spec.symbol /*&& declareStruct*/)
11805          {
11806             Class c = spec.symbol.registered;
11807             if(warnClasses && !c)
11808                Compiler_Warning("Undeclared class %s\n", spec.name);
11809             DeclareStruct(curExternal, spec.name, c && c.type == noHeadClass, declareStruct && c && c.type == structClass);
11810          }
11811          break;
11812       }
11813       case enumSpecifier:
11814       {
11815          Enumerator e;
11816          if(spec.list)
11817          {
11818             for(e = spec.list->first; e; e = e.next)
11819             {
11820                if(e.exp)
11821                   ProcessExpressionType(e.exp);
11822             }
11823          }
11824          // Fall through for IDE type processing
11825          if(inCompiler)
11826             break;
11827       }
11828       case structSpecifier:
11829       case unionSpecifier:
11830       {
11831          if(spec.definitions)
11832          {
11833             //ClassDef def;
11834             Symbol symbol = spec.id ? FindClass(spec.id.string) : null;
11835             //if(symbol)
11836                ProcessClass(spec.definitions, symbol);
11837             /*else
11838             {
11839                for(def = spec.definitions->first; def; def = def.next)
11840                {
11841                   //if(def.type == declarationClassDef && def.decl && def.decl.type == DeclarationStruct)
11842                      ProcessDeclaration(def.decl);
11843                }
11844             }*/
11845          }
11846          break;
11847       }
11848       /*
11849       case classSpecifier:
11850       {
11851          Symbol classSym = FindClass(spec.name);
11852          if(classSym && classSym.registered && classSym.registered.type == structClass)
11853             DeclareStruct(spec.name, false, true);
11854          break;
11855       }
11856       */
11857    }
11858 }
11859
11860
11861 static void ProcessDeclarator(Declarator decl, bool isFunction)
11862 {
11863    switch(decl.type)
11864    {
11865       case identifierDeclarator:
11866          if(decl.identifier.classSym /* TODO: Name Space Fix ups  || decl.identifier.nameSpace*/)
11867          {
11868             FreeSpecifier(decl.identifier._class);
11869             decl.identifier._class = null;
11870          }
11871          break;
11872       case arrayDeclarator:
11873          if(decl.array.exp)
11874             ProcessExpressionType(decl.array.exp);
11875       case structDeclarator:
11876       case bracketsDeclarator:
11877       case functionDeclarator:
11878       case pointerDeclarator:
11879       case extendedDeclarator:
11880       case extendedDeclaratorEnd:
11881       {
11882          Identifier id = null;
11883          Specifier classSpec = null;
11884          if(decl.type == functionDeclarator)
11885          {
11886             id = GetDeclId(decl);
11887             if(id && id._class)
11888             {
11889                classSpec = id._class;
11890                id._class = null;
11891             }
11892          }
11893          if(decl.declarator)
11894             ProcessDeclarator(decl.declarator, isFunction);
11895          if(decl.type == functionDeclarator)
11896          {
11897             if(classSpec)
11898             {
11899                TypeName param
11900                {
11901                   qualifiers = MkListOne(classSpec);
11902                   declarator = null;
11903                };
11904                if(!decl.function.parameters)
11905                   decl.function.parameters = MkList();
11906                decl.function.parameters->Insert(null, param);
11907             }
11908             if(decl.function.parameters)
11909             {
11910                TypeName param;
11911
11912                for(param = decl.function.parameters->first; param; param = param.next)
11913                {
11914                   if(param.qualifiers)
11915                   {
11916                      Specifier spec;
11917                      for(spec = param.qualifiers->first; spec; spec = spec.next)
11918                      {
11919                         if(spec.type == baseSpecifier)
11920                         {
11921                            if(spec.specifier == TYPED_OBJECT)
11922                            {
11923                               Declarator d = param.declarator;
11924                               TypeName newParam
11925                               {
11926                                  qualifiers = MkListOne(MkSpecifier(VOID));
11927                                  declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11928                               };
11929                               if(!d || d.type != pointerDeclarator)
11930                                  newParam.qualifiers->Insert(null, MkSpecifier(CONST));
11931
11932                               FreeList(param.qualifiers, FreeSpecifier);
11933
11934                               param.qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
11935                               param.declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
11936
11937                               DeclareStruct(curExternal, "ecere::com::Class", false, true);
11938
11939                               decl.function.parameters->Insert(param, newParam);
11940                               param = newParam;
11941                               break;
11942                            }
11943                            else if(spec.specifier == ANY_OBJECT)
11944                            {
11945                               Declarator d = param.declarator;
11946
11947                               FreeList(param.qualifiers, FreeSpecifier);
11948
11949                               param.qualifiers = MkListOne(MkSpecifier(VOID));
11950                               if(!d || d.type != pointerDeclarator)
11951                                  param.qualifiers->Insert(null, MkSpecifier(CONST));
11952                               param.declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11953                               break;
11954                            }
11955                            else if(spec.specifier == THISCLASS)
11956                            {
11957                               if(thisClass)
11958                               {
11959                                  spec.type = nameSpecifier;
11960                                  spec.name = ReplaceThisClass(thisClass);
11961                                  spec.symbol = FindClass(spec.name);
11962                                  ProcessSpecifier(spec, false, false);
11963                               }
11964                               break;
11965                            }
11966                         }
11967                         else if(spec.type == nameSpecifier)
11968                         {
11969                            ProcessSpecifier(spec, isFunction, true);
11970                         }
11971                         else if((spec.type == structSpecifier || spec.type == unionSpecifier) && !spec.definitions && spec.id && spec.id.string)
11972                         {
11973                            Declarator d = param.declarator;
11974                            if(!d || d.type != pointerDeclarator)
11975                               DeclareStruct(curExternal, spec.id.string, false, true);
11976                         }
11977                      }
11978                   }
11979
11980                   if(param.declarator)
11981                      ProcessDeclarator(param.declarator, false);
11982                }
11983             }
11984          }
11985          break;
11986       }
11987    }
11988 }
11989
11990 static void ProcessDeclaration(Declaration decl, bool warnClasses)
11991 {
11992    yylloc = decl.loc;
11993    switch(decl.type)
11994    {
11995       case initDeclaration:
11996       {
11997          bool declareStruct = false;
11998          /*
11999          lineNum = decl.pos.line;
12000          column = decl.pos.col;
12001          */
12002
12003          if(decl.declarators)
12004          {
12005             InitDeclarator d;
12006
12007             for(d = decl.declarators->first; d; d = d.next)
12008             {
12009                Type type, subType;
12010                ProcessDeclarator(d.declarator, false);
12011
12012                type = ProcessType(decl.specifiers, d.declarator);
12013
12014                if(d.initializer)
12015                {
12016                   ProcessInitializer(d.initializer, type);
12017
12018                   // Change "ColorRGB a = ColorRGB { 1,2,3 } => ColorRGB a { 1,2,3 }
12019
12020                   if(decl.declarators->count == 1 && d.initializer.type == expInitializer &&
12021                      d.initializer.exp.type == instanceExp)
12022                   {
12023                      if(type.kind == classType && type._class ==
12024                         d.initializer.exp.expType._class)
12025                      {
12026                         Instantiation inst = d.initializer.exp.instance;
12027                         inst.exp = MkExpIdentifier(CopyIdentifier(GetDeclId(d.declarator)));
12028
12029                         d.initializer.exp.instance = null;
12030                         if(decl.specifiers)
12031                            FreeList(decl.specifiers, FreeSpecifier);
12032                         FreeList(decl.declarators, FreeInitDeclarator);
12033
12034                         d = null;
12035
12036                         decl.type = instDeclaration;
12037                         decl.inst = inst;
12038                      }
12039                   }
12040                }
12041                for(subType = type; subType;)
12042                {
12043                   if(subType.kind == classType)
12044                   {
12045                      declareStruct = true;
12046                      break;
12047                   }
12048                   else if(subType.kind == pointerType)
12049                      break;
12050                   else if(subType.kind == arrayType)
12051                      subType = subType.arrayType;
12052                   else
12053                      break;
12054                }
12055
12056                FreeType(type);
12057                if(!d) break;
12058             }
12059          }
12060
12061          if(decl.specifiers)
12062          {
12063             Specifier s;
12064             for(s = decl.specifiers->first; s; s = s.next)
12065             {
12066                ProcessSpecifier(s, declareStruct, true);
12067             }
12068          }
12069          break;
12070       }
12071       case instDeclaration:
12072       {
12073          ProcessInstantiationType(decl.inst);
12074          break;
12075       }
12076       case structDeclaration:
12077       {
12078          Specifier spec;
12079          Declarator d;
12080          bool declareStruct = false;
12081
12082          if(decl.declarators)
12083          {
12084             for(d = decl.declarators->first; d; d = d.next)
12085             {
12086                Type type = ProcessType(decl.specifiers, d.declarator);
12087                Type subType;
12088                ProcessDeclarator(d, false);
12089                for(subType = type; subType;)
12090                {
12091                   if(subType.kind == classType)
12092                   {
12093                      declareStruct = true;
12094                      break;
12095                   }
12096                   else if(subType.kind == pointerType)
12097                      break;
12098                   else if(subType.kind == arrayType)
12099                      subType = subType.arrayType;
12100                   else
12101                      break;
12102                }
12103                FreeType(type);
12104             }
12105          }
12106          if(decl.specifiers)
12107          {
12108             for(spec = decl.specifiers->first; spec; spec = spec.next)
12109                ProcessSpecifier(spec, declareStruct, warnClasses);
12110          }
12111          break;
12112       }
12113    }
12114 }
12115
12116 static FunctionDefinition curFunction;
12117
12118 static void CreateFireWatcher(Property prop, Expression object, Statement stmt)
12119 {
12120    char propName[1024], propNameM[1024];
12121    char getName[1024], setName[1024];
12122    OldList * args;
12123
12124    DeclareProperty(curExternal, prop, setName, getName);
12125
12126    // eInstance_FireWatchers(object, prop);
12127    strcpy(propName, "__ecereProp_");
12128    FullClassNameCat(propName, prop._class.fullName, false);
12129    strcat(propName, "_");
12130    FullClassNameCat(propName, prop.name, true);
12131
12132    strcpy(propNameM, "__ecerePropM_");
12133    FullClassNameCat(propNameM, prop._class.fullName, false);
12134    strcat(propNameM, "_");
12135    FullClassNameCat(propNameM, prop.name, true);
12136
12137    if(prop.isWatchable)
12138    {
12139       args = MkList();
12140       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
12141       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12142       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
12143
12144       args = MkList();
12145       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
12146       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
12147       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
12148
12149       DeclareFunctionUtil(curExternal, "eInstance_FireWatchers");
12150    }
12151
12152    {
12153       args = MkList();
12154       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
12155       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12156       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
12157
12158       args = MkList();
12159       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
12160       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
12161       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
12162
12163       DeclareFunctionUtil(curExternal, "eInstance_FireSelfWatchers");
12164    }
12165
12166    if(curFunction.propSet && !strcmp(curFunction.propSet.string, prop.name) &&
12167       (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
12168       curFunction.propSet.fireWatchersDone = true;
12169 }
12170
12171 static void ProcessStatement(Statement stmt)
12172 {
12173    yylloc = stmt.loc;
12174    /*
12175    lineNum = stmt.pos.line;
12176    column = stmt.pos.col;
12177    */
12178    switch(stmt.type)
12179    {
12180       case labeledStmt:
12181          ProcessStatement(stmt.labeled.stmt);
12182          break;
12183       case caseStmt:
12184          // This expression should be constant...
12185          if(stmt.caseStmt.exp)
12186          {
12187             FreeType(stmt.caseStmt.exp.destType);
12188             stmt.caseStmt.exp.destType = curSwitchType;
12189             if(curSwitchType) curSwitchType.refCount++;
12190             ProcessExpressionType(stmt.caseStmt.exp);
12191             ComputeExpression(stmt.caseStmt.exp);
12192          }
12193          if(stmt.caseStmt.stmt)
12194             ProcessStatement(stmt.caseStmt.stmt);
12195          break;
12196       case compoundStmt:
12197       {
12198          if(stmt.compound.context)
12199          {
12200             Declaration decl;
12201             Statement s;
12202
12203             Statement prevCompound = curCompound;
12204             Context prevContext = curContext;
12205
12206             if(!stmt.compound.isSwitch)
12207                curCompound = stmt;
12208             curContext = stmt.compound.context;
12209
12210             if(stmt.compound.declarations)
12211             {
12212                for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
12213                   ProcessDeclaration(decl, true);
12214             }
12215             if(stmt.compound.statements)
12216             {
12217                for(s = stmt.compound.statements->first; s; s = s.next)
12218                   ProcessStatement(s);
12219             }
12220
12221             curContext = prevContext;
12222             curCompound = prevCompound;
12223          }
12224          break;
12225       }
12226       case expressionStmt:
12227       {
12228          Expression exp;
12229          if(stmt.expressions)
12230          {
12231             for(exp = stmt.expressions->first; exp; exp = exp.next)
12232                ProcessExpressionType(exp);
12233          }
12234          break;
12235       }
12236       case ifStmt:
12237       {
12238          Expression exp;
12239
12240          FreeType(((Expression)stmt.ifStmt.exp->last).destType);
12241          ((Expression)stmt.ifStmt.exp->last).destType = MkClassType("bool");
12242          ((Expression)stmt.ifStmt.exp->last).destType.truth = true;
12243          for(exp = stmt.ifStmt.exp->first; exp; exp = exp.next)
12244          {
12245             ProcessExpressionType(exp);
12246          }
12247          if(stmt.ifStmt.stmt)
12248             ProcessStatement(stmt.ifStmt.stmt);
12249          if(stmt.ifStmt.elseStmt)
12250             ProcessStatement(stmt.ifStmt.elseStmt);
12251          break;
12252       }
12253       case switchStmt:
12254       {
12255          Type oldSwitchType = curSwitchType;
12256          if(stmt.switchStmt.exp)
12257          {
12258             Expression exp;
12259             for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
12260             {
12261                if(!exp.next)
12262                {
12263                   /*
12264                   Type destType
12265                   {
12266                      kind = intType;
12267                      refCount = 1;
12268                   };
12269                   e.exp.destType = destType;
12270                   */
12271
12272                   ProcessExpressionType(exp);
12273                }
12274                if(!exp.next)
12275                   curSwitchType = exp.expType;
12276             }
12277          }
12278          ProcessStatement(stmt.switchStmt.stmt);
12279          curSwitchType = oldSwitchType;
12280          break;
12281       }
12282       case whileStmt:
12283       {
12284          if(stmt.whileStmt.exp)
12285          {
12286             Expression exp;
12287
12288             FreeType(((Expression)stmt.whileStmt.exp->last).destType);
12289             ((Expression)stmt.whileStmt.exp->last).destType = MkClassType("bool");
12290             ((Expression)stmt.whileStmt.exp->last).destType.truth = true;
12291             for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
12292             {
12293                ProcessExpressionType(exp);
12294             }
12295          }
12296          if(stmt.whileStmt.stmt)
12297             ProcessStatement(stmt.whileStmt.stmt);
12298          break;
12299       }
12300       case doWhileStmt:
12301       {
12302          if(stmt.doWhile.exp)
12303          {
12304             Expression exp;
12305
12306             if(stmt.doWhile.exp->last)
12307             {
12308                FreeType(((Expression)stmt.doWhile.exp->last).destType);
12309                ((Expression)stmt.doWhile.exp->last).destType = MkClassType("bool");
12310                ((Expression)stmt.doWhile.exp->last).destType.truth = true;
12311             }
12312             for(exp = stmt.doWhile.exp->first; exp; exp = exp.next)
12313             {
12314                ProcessExpressionType(exp);
12315             }
12316          }
12317          if(stmt.doWhile.stmt)
12318             ProcessStatement(stmt.doWhile.stmt);
12319          break;
12320       }
12321       case forStmt:
12322       {
12323          Expression exp;
12324          if(stmt.forStmt.init)
12325             ProcessStatement(stmt.forStmt.init);
12326
12327          if(stmt.forStmt.check && stmt.forStmt.check.expressions)
12328          {
12329             FreeType(((Expression)stmt.forStmt.check.expressions->last).destType);
12330             ((Expression)stmt.forStmt.check.expressions->last).destType = MkClassType("bool");
12331             ((Expression)stmt.forStmt.check.expressions->last).destType.truth = true;
12332          }
12333
12334          if(stmt.forStmt.check)
12335             ProcessStatement(stmt.forStmt.check);
12336          if(stmt.forStmt.increment)
12337          {
12338             for(exp = stmt.forStmt.increment->first; exp; exp = exp.next)
12339                ProcessExpressionType(exp);
12340          }
12341
12342          if(stmt.forStmt.stmt)
12343             ProcessStatement(stmt.forStmt.stmt);
12344          break;
12345       }
12346       case forEachStmt:
12347       {
12348          Identifier id = stmt.forEachStmt.id;
12349          OldList * exp = stmt.forEachStmt.exp;
12350          OldList * filter = stmt.forEachStmt.filter;
12351          Statement block = stmt.forEachStmt.stmt;
12352          char iteratorType[1024];
12353          Type source;
12354          Expression e;
12355          bool isBuiltin = exp && exp->last &&
12356             (((Expression)exp->last).type == ExpressionType::arrayExp ||
12357               (((Expression)exp->last).type == castExp && ((Expression)exp->last).cast.exp.type == ExpressionType::arrayExp));
12358          Expression arrayExp;
12359          const char * typeString = null;
12360          int builtinCount = 0;
12361
12362          for(e = exp ? exp->first : null; e; e = e.next)
12363          {
12364             if(!e.next)
12365             {
12366                FreeType(e.destType);
12367                e.destType = ProcessTypeString("Container", false);
12368             }
12369             if(!isBuiltin || e.next)
12370                ProcessExpressionType(e);
12371          }
12372
12373          source = (exp && exp->last) ? ((Expression)exp->last).expType : null;
12374          if(isBuiltin || (source && source.kind == classType && source._class && source._class.registered && source._class.registered != containerClass &&
12375             eClass_IsDerived(source._class.registered, containerClass)))
12376          {
12377             Class _class = source ? source._class.registered : null;
12378             Symbol symbol;
12379             Expression expIt = null;
12380             bool isMap = false, isArray = false, isLinkList = false, isList = false, isCustomAVLTree = false; //, isAVLTree = false;
12381             Class arrayClass = eSystem_FindClass(privateModule, "Array");
12382             Class linkListClass = eSystem_FindClass(privateModule, "LinkList");
12383             Class customAVLTreeClass = eSystem_FindClass(privateModule, "CustomAVLTree");
12384
12385             if(inCompiler)
12386             {
12387                stmt.type = compoundStmt;
12388
12389                stmt.compound.context = Context { };
12390                stmt.compound.context.parent = curContext;
12391                curContext = stmt.compound.context;
12392             }
12393
12394             if(source && eClass_IsDerived(source._class.registered, customAVLTreeClass))
12395             {
12396                Class mapClass = eSystem_FindClass(privateModule, "Map");
12397                //Class avlTreeClass = eSystem_FindClass(privateModule, "AVLTree");
12398                isCustomAVLTree = true;
12399                /*if(eClass_IsDerived(source._class.registered, avlTreeClass))
12400                   isAVLTree = true;
12401                else */if(eClass_IsDerived(source._class.registered, mapClass))
12402                   isMap = true;
12403             }
12404             else if(source && eClass_IsDerived(source._class.registered, arrayClass)) isArray = true;
12405             else if(source && eClass_IsDerived(source._class.registered, linkListClass))
12406             {
12407                Class listClass = eSystem_FindClass(privateModule, "List");
12408                isLinkList = true;
12409                isList = eClass_IsDerived(source._class.registered, listClass);
12410             }
12411
12412             if(inCompiler && isArray)
12413             {
12414                Declarator decl;
12415                OldList * specs = MkList();
12416                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
12417                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
12418                stmt.compound.declarations = MkListOne(
12419                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12420                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12421                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalArray")),
12422                      MkInitializerAssignment(MkExpBrackets(exp))))));
12423             }
12424             else if(isBuiltin)
12425             {
12426                Type type = null;
12427                char typeStringBuf[1024];
12428
12429                // TODO: Merge this code?
12430                arrayExp = (((Expression)exp->last).type == ExpressionType::arrayExp) ? (Expression)exp->last : ((Expression)exp->last).cast.exp;
12431                if(((Expression)exp->last).type == castExp)
12432                {
12433                   TypeName typeName = ((Expression)exp->last).cast.typeName;
12434                   if(typeName)
12435                      arrayExp.destType = ProcessType(typeName.qualifiers, typeName.declarator);
12436                }
12437
12438                if(arrayExp.destType && arrayExp.destType.kind == classType && arrayExp.destType._class && arrayExp.destType._class.registered &&
12439                   arrayExp.destType._class.registered != containerClass && eClass_IsDerived(arrayExp.destType._class.registered, containerClass) &&
12440                   arrayExp.destType._class.registered.templateArgs)
12441                {
12442                   Class templateClass = arrayExp.destType._class.registered;
12443                   typeString = templateClass.templateArgs[2].dataTypeString;
12444                }
12445                else if(arrayExp.list)
12446                {
12447                   // Guess type from expressions in the array
12448                   Expression e;
12449                   for(e = arrayExp.list->first; e; e = e.next)
12450                   {
12451                      ProcessExpressionType(e);
12452                      if(e.expType)
12453                      {
12454                         if(!type) { type = e.expType; type.refCount++; }
12455                         else
12456                         {
12457                            // if(!MatchType(e.expType, type, null, null, null, false, false, false))
12458                            if(!MatchTypeExpression(e, type, null, false, true))
12459                            {
12460                               FreeType(type);
12461                               type = e.expType;
12462                               e.expType = null;
12463
12464                               e = arrayExp.list->first;
12465                               ProcessExpressionType(e);
12466                               if(e.expType)
12467                               {
12468                                  //if(!MatchTypes(e.expType, type, null, null, null, false, false, false, false))
12469                                  if(!MatchTypeExpression(e, type, null, false, true))
12470                                  {
12471                                     FreeType(e.expType);
12472                                     e.expType = null;
12473                                     FreeType(type);
12474                                     type = null;
12475                                     break;
12476                                  }
12477                               }
12478                            }
12479                         }
12480                         if(e.expType)
12481                         {
12482                            FreeType(e.expType);
12483                            e.expType = null;
12484                         }
12485                      }
12486                   }
12487                   if(type)
12488                   {
12489                      typeStringBuf[0] = '\0';
12490                      PrintType(type, typeStringBuf, false, true);
12491                      typeString = typeStringBuf;
12492                      FreeType(type);
12493                   }
12494                }
12495                if(typeString)
12496                {
12497                   if(inCompiler)
12498                   {
12499                      OldList * initializers = MkList();
12500                      Declarator decl;
12501                      OldList * specs = MkList();
12502                      if(arrayExp.list)
12503                      {
12504                         Expression e;
12505
12506                         builtinCount = arrayExp.list->count;
12507                         type = ProcessTypeString(typeString, false);
12508                         while((e = arrayExp.list->first))
12509                         {
12510                            arrayExp.list->Remove(e);
12511                            e.destType = type;
12512                            type.refCount++;
12513                            ProcessExpressionType(e);
12514                            if(inCompiler)
12515                               ListAdd(initializers, MkInitializerAssignment(e));
12516                         }
12517                         FreeType(type);
12518                         delete arrayExp.list;
12519                      }
12520                      decl = SpecDeclFromString(typeString, specs, MkDeclaratorIdentifier(id));
12521
12522                      stmt.compound.declarations = MkListOne(MkDeclaration(CopyList(specs, CopySpecifier),
12523                         MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), /*CopyDeclarator(*/decl/*)*/), null))));
12524
12525                      ListAdd(stmt.compound.declarations, MkDeclaration(specs, MkListOne(MkInitDeclarator(
12526                         PlugDeclarator(
12527                            /*CopyDeclarator(*/decl/*)*/, MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__internalArray")), null)
12528                            ), MkInitializerList(initializers)))));
12529                      FreeList(exp, FreeExpression);
12530                   }
12531                   else if(arrayExp.list)
12532                   {
12533                      Expression e;
12534                      type = ProcessTypeString(typeString, false);
12535                      for(e = arrayExp.list->first; e; e = e.next)
12536                      {
12537                         e.destType = type;
12538                         type.refCount++;
12539                         ProcessExpressionType(e);
12540                      }
12541                      FreeType(type);
12542                   }
12543                }
12544                else
12545                {
12546                   arrayExp.expType = ProcessTypeString("Container", false);
12547                   Compiler_Error($"Couldn't determine type of array elements\n");
12548                }
12549
12550                /*
12551                Declarator decl;
12552                OldList * specs = MkList();
12553
12554                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
12555                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
12556                stmt.compound.declarations = MkListOne(
12557                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12558                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName("BuiltInContainer")),
12559                   MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(MkIdentifier("__internalArray"))),
12560                      MkInitializerAssignment(MkExpBrackets(exp))))));
12561                */
12562             }
12563             else if(inCompiler && isLinkList && !isList)
12564             {
12565                Declarator decl;
12566                OldList * specs = MkList();
12567                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
12568                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12569                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12570                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalLinkList")),
12571                      MkInitializerAssignment(MkExpBrackets(exp))))));
12572             }
12573             /*else if(isCustomAVLTree)
12574             {
12575                Declarator decl;
12576                OldList * specs = MkList();
12577                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
12578                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12579                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12580                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalTree")),
12581                      MkInitializerAssignment(MkExpBrackets(exp))))));
12582             }*/
12583             else if(inCompiler && _class.templateArgs)
12584             {
12585                if(isMap)
12586                   sprintf(iteratorType, "MapIterator<%s, %s >", _class.templateArgs[5].dataTypeString, _class.templateArgs[6].dataTypeString);
12587                else
12588                   sprintf(iteratorType, "Iterator<%s, %s >", _class.templateArgs[2].dataTypeString, _class.templateArgs[1].dataTypeString);
12589
12590                stmt.compound.declarations = MkListOne(
12591                   MkDeclarationInst(MkInstantiationNamed(MkListOne(MkSpecifierName(iteratorType)),
12592                   MkExpIdentifier(id), MkListOne(MkMembersInitList(MkListOne(MkMemberInit(isMap ? MkListOne(MkIdentifier("map")) : null,
12593                   MkInitializerAssignment(MkExpBrackets(exp)))))))));
12594             }
12595             if(inCompiler)
12596             {
12597                symbol = FindSymbol(id.string, curContext, curContext, false, false);
12598
12599                if(block)
12600                {
12601                   // Reparent sub-contexts in this statement
12602                   switch(block.type)
12603                   {
12604                      case compoundStmt:
12605                         if(block.compound.context)
12606                            block.compound.context.parent = stmt.compound.context;
12607                         break;
12608                      case ifStmt:
12609                         if(block.ifStmt.stmt && block.ifStmt.stmt.type == compoundStmt && block.ifStmt.stmt.compound.context)
12610                            block.ifStmt.stmt.compound.context.parent = stmt.compound.context;
12611                         if(block.ifStmt.elseStmt && block.ifStmt.elseStmt.type == compoundStmt && block.ifStmt.elseStmt.compound.context)
12612                            block.ifStmt.elseStmt.compound.context.parent = stmt.compound.context;
12613                         break;
12614                      case switchStmt:
12615                         if(block.switchStmt.stmt && block.switchStmt.stmt.type == compoundStmt && block.switchStmt.stmt.compound.context)
12616                            block.switchStmt.stmt.compound.context.parent = stmt.compound.context;
12617                         break;
12618                      case whileStmt:
12619                         if(block.whileStmt.stmt && block.whileStmt.stmt.type == compoundStmt && block.whileStmt.stmt.compound.context)
12620                            block.whileStmt.stmt.compound.context.parent = stmt.compound.context;
12621                         break;
12622                      case doWhileStmt:
12623                         if(block.doWhile.stmt && block.doWhile.stmt.type == compoundStmt && block.doWhile.stmt.compound.context)
12624                            block.doWhile.stmt.compound.context.parent = stmt.compound.context;
12625                         break;
12626                      case forStmt:
12627                         if(block.forStmt.stmt && block.forStmt.stmt.type == compoundStmt && block.forStmt.stmt.compound.context)
12628                            block.forStmt.stmt.compound.context.parent = stmt.compound.context;
12629                         break;
12630                      case forEachStmt:
12631                         if(block.forEachStmt.stmt && block.forEachStmt.stmt.type == compoundStmt && block.forEachStmt.stmt.compound.context)
12632                            block.forEachStmt.stmt.compound.context.parent = stmt.compound.context;
12633                         break;
12634                      /* Only handle those with compound blocks for now... (Potential limitation on compound statements within expressions)
12635                      case labeledStmt:
12636                      case caseStmt
12637                      case expressionStmt:
12638                      case gotoStmt:
12639                      case continueStmt:
12640                      case breakStmt
12641                      case returnStmt:
12642                      case asmStmt:
12643                      case badDeclarationStmt:
12644                      case fireWatchersStmt:
12645                      case stopWatchingStmt:
12646                      case watchStmt:
12647                      */
12648                   }
12649                }
12650
12651                if(filter)
12652                {
12653                   block = MkIfStmt(filter, block, null);
12654                }
12655                if(isArray)
12656                {
12657                   stmt.compound.statements = MkListOne(MkForStmt(
12658                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array"))))),
12659                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12660                         MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array")), '+', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
12661                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12662                      block));
12663                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12664                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12665                  ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12666                }
12667                else if(isBuiltin)
12668                {
12669                   char count[128];
12670                   //OldList * specs = MkList();
12671                   // Declarator decl = SpecDeclFromString(typeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
12672
12673                   sprintf(count, "%d", builtinCount);
12674
12675                   stmt.compound.statements = MkListOne(MkForStmt(
12676                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpIdentifier(MkIdentifier("__internalArray"))))),
12677                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12678                         MkExpOp(MkExpIdentifier(MkIdentifier("__internalArray")), '+', MkExpConstant(count))))),
12679                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12680                      block));
12681
12682                   /*
12683                   Declarator decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
12684                   stmt.compound.statements = MkListOne(MkForStmt(
12685                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))))),
12686                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12687                         MkExpOp(MkExpCast(MkTypeName(specs, decl), MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))), '+', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
12688                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12689                      block));
12690                  */
12691                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12692                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12693                  ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12694                }
12695                else if(isLinkList && !isList)
12696                {
12697                   Class typeClass = eSystem_FindClass(_class.module, _class.templateArgs[3].dataTypeString);
12698                   Class listItemClass = eSystem_FindClass(_class.module, "ListItem");
12699                   if(typeClass && eClass_IsDerived(typeClass, listItemClass) && _class.templateArgs[5].dataTypeString &&
12700                      !strcmp(_class.templateArgs[5].dataTypeString, "LT::link"))
12701                   {
12702                      stmt.compound.statements = MkListOne(MkForStmt(
12703                         MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
12704                         MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12705                         MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
12706                         block));
12707                   }
12708                   else
12709                   {
12710                      OldList * specs = MkList();
12711                      Declarator decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, null);
12712                      stmt.compound.statements = MkListOne(MkForStmt(
12713                         MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
12714                         MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12715                         MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpCast(MkTypeName(specs, decl), MkExpCall(
12716                            MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("GetNext")),
12717                               MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName("IteratorPointer")), null), MkExpIdentifier(CopyIdentifier(id)))))))),
12718                         block));
12719                   }
12720                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12721                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12722                   ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12723                }
12724                /*else if(isCustomAVLTree)
12725                {
12726                   stmt.compound.statements = MkListOne(MkForStmt(
12727                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpMember(MkExpIdentifier(
12728                         MkIdentifier("__internalTree")), MkIdentifier("root")), MkIdentifier("minimum"))))),
12729                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12730                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
12731                      block));
12732
12733                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12734                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12735                   ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12736                }*/
12737                else
12738                {
12739                   stmt.compound.statements = MkListOne(MkWhileStmt(MkListOne(MkExpCall(MkExpMember(expIt = MkExpIdentifier(CopyIdentifier(id)),
12740                      MkIdentifier("Next")), null)), block));
12741                }
12742                ProcessExpressionType(expIt);
12743                if(stmt.compound.declarations->first)
12744                   ProcessDeclaration(stmt.compound.declarations->first, true);
12745
12746                if(symbol)
12747                   symbol.isIterator = isMap ? 2 : ((isArray || isBuiltin) ? 3 : (isLinkList ? (isList ? 5 : 4) : (isCustomAVLTree ? 6 : 1)));
12748
12749                ProcessStatement(stmt);
12750             }
12751             else
12752                ProcessStatement(stmt.forEachStmt.stmt);
12753             if(inCompiler)
12754                curContext = stmt.compound.context.parent;
12755             break;
12756          }
12757          else
12758          {
12759             Compiler_Error($"Expression is not a container\n");
12760          }
12761          break;
12762       }
12763       case gotoStmt:
12764          break;
12765       case continueStmt:
12766          break;
12767       case breakStmt:
12768          break;
12769       case returnStmt:
12770       {
12771          Expression exp;
12772          if(stmt.expressions)
12773          {
12774             for(exp = stmt.expressions->first; exp; exp = exp.next)
12775             {
12776                if(!exp.next)
12777                {
12778                   if(curFunction && !curFunction.type)
12779                      curFunction.type = ProcessType(
12780                         curFunction.specifiers, curFunction.declarator);
12781                   FreeType(exp.destType);
12782                   // TODO: current property if not compiling
12783                   exp.destType = (curFunction && curFunction.type && curFunction.type.kind == functionType) ? curFunction.type.returnType : null;
12784                   if(exp.destType) exp.destType.refCount++;
12785                }
12786                ProcessExpressionType(exp);
12787             }
12788          }
12789          break;
12790       }
12791       case badDeclarationStmt:
12792       {
12793          ProcessDeclaration(stmt.decl, true);
12794          break;
12795       }
12796       case asmStmt:
12797       {
12798          AsmField field;
12799          if(stmt.asmStmt.inputFields)
12800          {
12801             for(field = stmt.asmStmt.inputFields->first; field; field = field.next)
12802                if(field.expression)
12803                   ProcessExpressionType(field.expression);
12804          }
12805          if(stmt.asmStmt.outputFields)
12806          {
12807             for(field = stmt.asmStmt.outputFields->first; field; field = field.next)
12808                if(field.expression)
12809                   ProcessExpressionType(field.expression);
12810          }
12811          if(stmt.asmStmt.clobberedFields)
12812          {
12813             for(field = stmt.asmStmt.clobberedFields->first; field; field = field.next)
12814             {
12815                if(field.expression)
12816                   ProcessExpressionType(field.expression);
12817             }
12818          }
12819          break;
12820       }
12821       case watchStmt:
12822       {
12823          PropertyWatch propWatch;
12824          OldList * watches = stmt._watch.watches;
12825          Expression object = stmt._watch.object;
12826          Expression watcher = stmt._watch.watcher;
12827          if(watcher)
12828             ProcessExpressionType(watcher);
12829          if(object)
12830             ProcessExpressionType(object);
12831
12832          if(inCompiler)
12833          {
12834             if(watcher || thisClass)
12835             {
12836                External external = curExternal;
12837                Context context = curContext;
12838
12839                stmt.type = expressionStmt;
12840                stmt.expressions = MkList();
12841
12842                for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12843                {
12844                   ClassFunction func;
12845                   char watcherName[1024];
12846                   Class watcherClass = watcher ?
12847                      ((watcher.expType && watcher.expType.kind == classType && watcher.expType._class) ? watcher.expType._class.registered : null) : thisClass;
12848                   External createdExternal;
12849
12850                   sprintf(watcherName,"__ecerePropertyWatcher_%d", propWatcherID++);
12851                   if(propWatch.deleteWatch)
12852                      strcat(watcherName, "_delete");
12853                   else
12854                   {
12855                      Identifier propID;
12856                      for(propID = propWatch.properties->first; propID; propID = propID.next)
12857                      {
12858                         strcat(watcherName, "_");
12859                         strcat(watcherName, propID.string);
12860                      }
12861                   }
12862
12863                   if(object && object.expType && object.expType.kind == classType && object.expType._class && object.expType._class.registered)
12864                   {
12865                      func = MkClassFunction(MkListOne(MkSpecifier(VOID)), null, MkDeclaratorFunction(MkDeclaratorIdentifier(MkIdentifier(watcherName)),
12866                         MkListOne(MkTypeName(MkListOne(MkSpecifierName(object.expType._class.string)), MkDeclaratorIdentifier(MkIdentifier("value"))))), null);
12867                      ProcessClassFunctionBody(func, propWatch.compound);
12868                      propWatch.compound = null;
12869
12870                      createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal, true);
12871
12872                      FreeClassFunction(func);
12873
12874                      curExternal = createdExternal;
12875                      ProcessFunction(createdExternal.function);
12876
12877                      if(propWatch.deleteWatch)
12878                      {
12879                         OldList * args = MkList();
12880                         ListAdd(args, CopyExpression(object));
12881                         ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12882                         ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
12883                         ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_WatchDestruction")), args));
12884                      }
12885                      else
12886                      {
12887                         Class _class = object.expType._class.registered;
12888                         Identifier propID;
12889
12890                         for(propID = propWatch.properties->first; propID; propID = propID.next)
12891                         {
12892                            char propName[1024];
12893                            Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12894                            if(prop)
12895                            {
12896                               char getName[1024], setName[1024];
12897                               OldList * args = MkList();
12898
12899                               DeclareProperty(createdExternal, prop, setName, getName);
12900
12901                               // eInstance_Watch(stmt.watch.object, prop, stmt.watch.watcher, callback);
12902                               strcpy(propName, "__ecereProp_");
12903                               FullClassNameCat(propName, prop._class.fullName, false);
12904                               strcat(propName, "_");
12905                               FullClassNameCat(propName, prop.name, true);
12906
12907                               ListAdd(args, CopyExpression(object));
12908                               ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12909                               ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12910                               ListAdd(args, MkExpCast(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpIdentifier(MkIdentifier(watcherName))));
12911
12912                               ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_Watch")), args));
12913
12914                               external.CreateUniqueEdge(createdExternal, true);
12915                            }
12916                            else
12917                               Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12918                         }
12919                      }
12920                   }
12921                   else
12922                      Compiler_Error($"Invalid watched object\n");
12923                }
12924
12925                curExternal = external;
12926                curContext = context;
12927
12928                if(watcher)
12929                   FreeExpression(watcher);
12930                if(object)
12931                   FreeExpression(object);
12932                FreeList(watches, FreePropertyWatch);
12933             }
12934             else
12935                Compiler_Error($"No observer specified and not inside a class\n");
12936          }
12937          else
12938          {
12939             for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12940             {
12941                ProcessStatement(propWatch.compound);
12942             }
12943
12944          }
12945          break;
12946       }
12947       case fireWatchersStmt:
12948       {
12949          OldList * watches = stmt._watch.watches;
12950          Expression object = stmt._watch.object;
12951          Class _class;
12952          // DEBUGGER BUG: Why doesn't watches evaluate to null??
12953          // printf("%X\n", watches);
12954          // printf("%X\n", stmt._watch.watches);
12955          if(object)
12956             ProcessExpressionType(object);
12957
12958          if(inCompiler)
12959          {
12960             _class = object ?
12961                   ((object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null) : thisClass;
12962
12963             if(_class)
12964             {
12965                Identifier propID;
12966
12967                stmt.type = expressionStmt;
12968                stmt.expressions = MkList();
12969
12970                // Check if we're inside a property set
12971                if(!watches && curFunction.propSet && (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
12972                {
12973                   watches = MkListOne(MkIdentifier(curFunction.propSet.string));
12974                }
12975                else if(!watches)
12976                {
12977                   //Compiler_Error($"No property specified and not inside a property set\n");
12978                }
12979                if(watches)
12980                {
12981                   for(propID = watches->first; propID; propID = propID.next)
12982                   {
12983                      Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12984                      if(prop)
12985                      {
12986                         CreateFireWatcher(prop, object, stmt);
12987                      }
12988                      else
12989                         Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12990                   }
12991                }
12992                else
12993                {
12994                   // Fire all properties!
12995                   Property prop;
12996                   Class base;
12997                   for(base = _class; base; base = base.base)
12998                   {
12999                      for(prop = base.membersAndProperties.first; prop; prop = prop.next)
13000                      {
13001                         if(prop.isProperty && prop.isWatchable)
13002                         {
13003                            CreateFireWatcher(prop, object, stmt);
13004                         }
13005                      }
13006                   }
13007                }
13008
13009                if(object)
13010                   FreeExpression(object);
13011                FreeList(watches, FreeIdentifier);
13012             }
13013             else
13014                Compiler_Error($"Invalid object specified and not inside a class\n");
13015          }
13016          break;
13017       }
13018       case stopWatchingStmt:
13019       {
13020          OldList * watches = stmt._watch.watches;
13021          Expression object = stmt._watch.object;
13022          Expression watcher = stmt._watch.watcher;
13023          Class _class;
13024          if(object)
13025             ProcessExpressionType(object);
13026          if(watcher)
13027             ProcessExpressionType(watcher);
13028          if(inCompiler)
13029          {
13030             _class = (object && object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null;
13031
13032             if(watcher || thisClass)
13033             {
13034                if(_class)
13035                {
13036                   Identifier propID;
13037
13038                   stmt.type = expressionStmt;
13039                   stmt.expressions = MkList();
13040
13041                   if(!watches)
13042                   {
13043                      OldList * args;
13044                      // eInstance_StopWatching(object, null, watcher);
13045                      args = MkList();
13046                      ListAdd(args, CopyExpression(object));
13047                      ListAdd(args, MkExpConstant("0"));
13048                      ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
13049                      ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
13050                   }
13051                   else
13052                   {
13053                      for(propID = watches->first; propID; propID = propID.next)
13054                      {
13055                         char propName[1024];
13056                         Property prop = eClass_FindProperty(_class, propID.string, privateModule);
13057                         if(prop)
13058                         {
13059                            char getName[1024], setName[1024];
13060                            OldList * args = MkList();
13061
13062                            DeclareProperty(curExternal, prop, setName, getName);
13063
13064                            // eInstance_StopWatching(object, prop, watcher);
13065                            strcpy(propName, "__ecereProp_");
13066                            FullClassNameCat(propName, prop._class.fullName, false);
13067                            strcat(propName, "_");
13068                            FullClassNameCat(propName, prop.name, true);
13069
13070                            ListAdd(args, CopyExpression(object));
13071                            ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
13072                            ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
13073                            ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
13074                         }
13075                         else
13076                            Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
13077                      }
13078                   }
13079
13080                   if(object)
13081                      FreeExpression(object);
13082                   if(watcher)
13083                      FreeExpression(watcher);
13084                   FreeList(watches, FreeIdentifier);
13085                }
13086                else
13087                   Compiler_Error($"Invalid object specified and not inside a class\n");
13088             }
13089             else
13090                Compiler_Error($"No observer specified and not inside a class\n");
13091          }
13092          break;
13093       }
13094    }
13095 }
13096
13097 static void ProcessFunction(FunctionDefinition function)
13098 {
13099    Identifier id = GetDeclId(function.declarator);
13100    Symbol symbol = function.declarator ? function.declarator.symbol : null;
13101    Type type = symbol ? symbol.type : null;
13102    Class oldThisClass = thisClass;
13103    Context oldTopContext = topContext;
13104
13105    yylloc = function.loc;
13106    // Process thisClass
13107
13108    if(type && type.thisClass)
13109    {
13110       Symbol classSym = type.thisClass;
13111       Class _class = type.thisClass.registered;
13112       char className[1024];
13113       char structName[1024];
13114       Declarator funcDecl;
13115       Symbol thisSymbol;
13116
13117       bool typedObject = false;
13118
13119       if(_class && !_class.base)
13120       {
13121          _class = currentClass;
13122          if(_class && !_class.symbol)
13123             _class.symbol = FindClass(_class.fullName);
13124          classSym = _class ? _class.symbol : null;
13125          typedObject = true;
13126       }
13127
13128       thisClass = _class;
13129
13130       if(inCompiler && _class)
13131       {
13132          if(type.kind == functionType)
13133          {
13134             if(symbol.type.params.count == 1 && ((Type)symbol.type.params.first).kind == voidType)
13135             {
13136                //TypeName param = symbol.type.params.first;
13137                Type param = symbol.type.params.first;
13138                symbol.type.params.Remove(param);
13139                //FreeTypeName(param);
13140                FreeType(param);
13141             }
13142             if(type.classObjectType != classPointer)
13143             {
13144                symbol.type.params.Insert(null, MkClassType(_class.fullName));
13145                symbol.type.staticMethod = true;
13146                symbol.type.thisClass = null;
13147
13148                // HIGH DANGER: VERIFYING THIS...
13149                symbol.type.extraParam = false;
13150             }
13151          }
13152
13153          strcpy(className, "__ecereClass_");
13154          FullClassNameCat(className, _class.fullName, true);
13155
13156          structName[0] = 0;
13157          FullClassNameCat(structName, _class.fullName, false);
13158
13159          // [class] this
13160          funcDecl = GetFuncDecl(function.declarator);
13161          if(funcDecl)
13162          {
13163             if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
13164             {
13165                TypeName param = funcDecl.function.parameters->first;
13166                if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
13167                {
13168                   funcDecl.function.parameters->Remove(param);
13169                   FreeTypeName(param);
13170                }
13171             }
13172
13173             if(!function.propertyNoThis)
13174             {
13175                TypeName thisParam = null;
13176
13177                if(type.classObjectType != classPointer)
13178                {
13179                   thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
13180                   if(!funcDecl.function.parameters)
13181                      funcDecl.function.parameters = MkList();
13182                   funcDecl.function.parameters->Insert(null, thisParam);
13183                }
13184
13185                if(typedObject)
13186                {
13187                   if(type.classObjectType != classPointer)
13188                   {
13189                      if(type.byReference || _class.type == unitClass || _class.type == systemClass || _class.type == enumClass || _class.type == bitClass)
13190                         thisParam.declarator = MkDeclaratorPointer(MkPointer(null,null), thisParam.declarator);
13191                   }
13192
13193                   thisParam = TypeName
13194                   {
13195                      declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
13196                      qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
13197                   };
13198                   DeclareStruct(curExternal, "ecere::com::Class", false, true);
13199                   funcDecl.function.parameters->Insert(null, thisParam);
13200                }
13201             }
13202          }
13203
13204          if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
13205          {
13206             InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
13207             funcDecl = GetFuncDecl(initDecl.declarator);
13208             if(funcDecl)
13209             {
13210                if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
13211                {
13212                   TypeName param = funcDecl.function.parameters->first;
13213                   if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
13214                   {
13215                      funcDecl.function.parameters->Remove(param);
13216                      FreeTypeName(param);
13217                   }
13218                }
13219
13220                if(type.classObjectType != classPointer)
13221                {
13222                   if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
13223                   {
13224                      TypeName thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
13225
13226                      if(!funcDecl.function.parameters)
13227                         funcDecl.function.parameters = MkList();
13228                      funcDecl.function.parameters->Insert(null, thisParam);
13229                   }
13230                }
13231             }
13232          }
13233       }
13234
13235       // Add this to the context
13236       if(function.body)
13237       {
13238          if(type.classObjectType != classPointer)
13239          {
13240             thisSymbol = Symbol
13241             {
13242                string = CopyString("this");
13243                type = classSym ? MkClassType(classSym.string) : null;
13244             };
13245             function.body.compound.context.symbols.Add((BTNode)thisSymbol);
13246
13247             if(typedObject && thisSymbol.type)
13248             {
13249                thisSymbol.type.classObjectType = ClassObjectType::typedObject;
13250                thisSymbol.type.byReference = type.byReference;
13251                thisSymbol.type.typedByReference = type.byReference;
13252             }
13253          }
13254       }
13255
13256       // Pointer to class data
13257       if(inCompiler && _class && _class.type == normalClass && type.classObjectType != classPointer)
13258       {
13259          DataMember member = null;
13260          {
13261             Class base;
13262             for(base = _class; base && base.type != systemClass; base = base.next)
13263             {
13264                for(member = base.membersAndProperties.first; member; member = member.next)
13265                   if(!member.isProperty)
13266                      break;
13267                if(member)
13268                   break;
13269             }
13270          }
13271          for(member = _class.membersAndProperties.first; member; member = member.next)
13272             if(!member.isProperty)
13273                break;
13274          if(member)
13275          {
13276             char pointerName[1024];
13277
13278             Declaration decl;
13279             Initializer initializer;
13280             Expression exp, bytePtr;
13281
13282             strcpy(pointerName, "__ecerePointer_");
13283             FullClassNameCat(pointerName, _class.fullName, false);
13284             {
13285                char className[1024];
13286                strcpy(className, "__ecereClass_");
13287                FullClassNameCat(className, classSym.string, true);
13288
13289                DeclareClass(curExternal, classSym, className);
13290             }
13291
13292             // ((byte *) this)
13293             bytePtr = QBrackets(MkExpCast(QMkType("char", QMkPtrDecl(null)), QMkExpId("this")));
13294
13295             if(_class.fixed)
13296             {
13297                Expression e;
13298                if(_class.offset && _class.offset == (_class.base.type == noHeadClass ? _class.base.memberOffset : _class.base.structSize))
13299                {
13300                   e = MkExpClassSize(MkSpecifierName(_class.base.fullName));
13301                   ProcessExpressionType(e);
13302                }
13303                else
13304                {
13305                   char string[256];
13306                   sprintf(string, "%d", _class.offset);  // Need Bootstrap Fix
13307                   e = MkExpConstant(string);
13308                }
13309                exp = QBrackets(MkExpOp(bytePtr, '+', e));
13310             }
13311             else
13312             {
13313                // ([bytePtr] + [className]->offset)
13314                exp = QBrackets(MkExpOp(bytePtr, '+',
13315                   MkExpPointer(QMkExpId(className), MkIdentifier("offset"))));
13316             }
13317
13318             // (this ? [exp] : 0)
13319             exp = QBrackets(QMkExpCond(QMkExpId("this"), exp, MkExpConstant("0")));
13320             exp.expType = Type
13321             {
13322                refCount = 1;
13323                kind = pointerType;
13324                type = Type { refCount = 1, kind = voidType };
13325             };
13326
13327             if(function.body)
13328             {
13329                yylloc = function.body.loc;
13330                // ([structName] *) [exp]
13331                // initializer = MkInitializerAssignment(MkExpCast(QMkType(structName, QMkPtrDecl(null)), exp));
13332                initializer = MkInitializerAssignment(
13333                   MkExpCast(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)), exp));
13334
13335                // [structName] * [pointerName] = [initializer];
13336                // decl = QMkDeclaration(structName, MkInitDeclarator(QMkPtrDecl(pointerName), initializer));
13337
13338                {
13339                   Context prevContext = curContext;
13340                   OldList * list;
13341                   curContext = function.body.compound.context;
13342
13343                   decl = MkDeclaration((list = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null))),
13344                      MkListOne(MkInitDeclarator(QMkPtrDecl(pointerName), initializer)));
13345                   list->Insert(null, MkSpecifierExtended(MkExtDeclAttrib(MkAttrib(ATTRIB, MkListOne(MkAttribute(CopyString("unused"), null))))));
13346
13347                   curContext = prevContext;
13348                }
13349
13350                // WHY?
13351                decl.symbol = null;
13352
13353                if(!function.body.compound.declarations)
13354                   function.body.compound.declarations = MkList();
13355                function.body.compound.declarations->Insert(null, decl);
13356             }
13357          }
13358       }
13359
13360
13361       // Loop through the function and replace undeclared identifiers
13362       // which are a member of the class (methods, properties or data)
13363       // by "this.[member]"
13364    }
13365    else
13366       thisClass = null;
13367
13368    if(id)
13369    {
13370       FreeSpecifier(id._class);
13371       id._class = null;
13372
13373       if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
13374       {
13375          InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
13376          id = GetDeclId(initDecl.declarator);
13377
13378          FreeSpecifier(id._class);
13379          id._class = null;
13380       }
13381    }
13382    if(function.body)
13383       topContext = function.body.compound.context;
13384    {
13385       FunctionDefinition oldFunction = curFunction;
13386       curFunction = function;
13387       if(function.body)
13388          ProcessStatement(function.body);
13389
13390       // If this is a property set and no firewatchers has been done yet, add one here
13391       if(inCompiler && function.propSet && !function.propSet.fireWatchersDone)
13392       {
13393          Statement prevCompound = curCompound;
13394          Context prevContext = curContext;
13395
13396          Statement fireWatchers = MkFireWatchersStmt(null, null);
13397          if(!function.body.compound.statements) function.body.compound.statements = MkList();
13398          ListAdd(function.body.compound.statements, fireWatchers);
13399
13400          curCompound = function.body;
13401          curContext = function.body.compound.context;
13402
13403          ProcessStatement(fireWatchers);
13404
13405          curContext = prevContext;
13406          curCompound = prevCompound;
13407
13408       }
13409
13410       curFunction = oldFunction;
13411    }
13412
13413    if(function.declarator)
13414    {
13415       ProcessDeclarator(function.declarator, true);
13416    }
13417
13418    topContext = oldTopContext;
13419    thisClass = oldThisClass;
13420 }
13421
13422 /////////// INSTANTIATIONS / DATA TYPES PASS /////////////////////////////////////////////
13423 static void ProcessClass(OldList definitions, Symbol symbol)
13424 {
13425    ClassDef def;
13426    External external = curExternal;
13427    Class regClass = symbol ? symbol.registered : null;
13428
13429    // Process all functions
13430    for(def = definitions.first; def; def = def.next)
13431    {
13432       if(def.type == functionClassDef)
13433       {
13434          if(def.function.declarator)
13435             curExternal = def.function.declarator.symbol.pointerExternal;
13436          else
13437             curExternal = external;
13438
13439          ProcessFunction((FunctionDefinition)def.function);
13440       }
13441       else if(def.type == declarationClassDef)
13442       {
13443          if(def.decl.type == instDeclaration)
13444          {
13445             thisClass = regClass;
13446             ProcessInstantiationType(def.decl.inst);
13447             thisClass = null;
13448          }
13449          // Testing this
13450          else
13451          {
13452             Class backThisClass = thisClass;
13453             if(regClass) thisClass = regClass;
13454             ProcessDeclaration(def.decl, symbol ? true : false);
13455             thisClass = backThisClass;
13456          }
13457       }
13458       else if(def.type == defaultPropertiesClassDef && def.defProperties)
13459       {
13460          MemberInit defProperty;
13461
13462          // Add this to the context
13463          Symbol thisSymbol = Symbol
13464          {
13465             string = CopyString("this");
13466             type = regClass ? MkClassType(regClass.fullName) : null;
13467          };
13468          globalContext.symbols.Add((BTNode)thisSymbol);
13469
13470          for(defProperty = def.defProperties->first; defProperty; defProperty = defProperty.next)
13471          {
13472             thisClass = regClass;
13473             ProcessMemberInitData(defProperty, regClass, null, null, null, null);
13474             thisClass = null;
13475          }
13476
13477          globalContext.symbols.Remove((BTNode)thisSymbol);
13478          FreeSymbol(thisSymbol);
13479       }
13480       else if(def.type == propertyClassDef && def.propertyDef)
13481       {
13482          PropertyDef prop = def.propertyDef;
13483
13484          // Add this to the context
13485          thisClass = regClass;
13486          if(prop.setStmt)
13487          {
13488             if(regClass)
13489             {
13490                Symbol thisSymbol
13491                {
13492                   string = CopyString("this");
13493                   type = MkClassType(regClass.fullName);
13494                };
13495                prop.setStmt.compound.context.symbols.Add((BTNode)thisSymbol);
13496             }
13497
13498             curExternal = prop.symbol ? prop.symbol.externalSet : null;
13499             ProcessStatement(prop.setStmt);
13500          }
13501          if(prop.getStmt)
13502          {
13503             if(regClass)
13504             {
13505                Symbol thisSymbol
13506                {
13507                   string = CopyString("this");
13508                   type = MkClassType(regClass.fullName);
13509                };
13510                prop.getStmt.compound.context.symbols.Add((BTNode)thisSymbol);
13511             }
13512
13513             curExternal = prop.symbol ? prop.symbol.externalGet : null;
13514             ProcessStatement(prop.getStmt);
13515          }
13516          if(prop.issetStmt)
13517          {
13518             if(regClass)
13519             {
13520                Symbol thisSymbol
13521                {
13522                   string = CopyString("this");
13523                   type = MkClassType(regClass.fullName);
13524                };
13525                prop.issetStmt.compound.context.symbols.Add((BTNode)thisSymbol);
13526             }
13527
13528             curExternal = prop.symbol ? prop.symbol.externalIsSet : null;
13529             ProcessStatement(prop.issetStmt);
13530          }
13531
13532          thisClass = null;
13533       }
13534       else if(def.type == propertyWatchClassDef && def.propertyWatch)
13535       {
13536          PropertyWatch propertyWatch = def.propertyWatch;
13537
13538          thisClass = regClass;
13539          if(propertyWatch.compound)
13540          {
13541             Symbol thisSymbol
13542             {
13543                string = CopyString("this");
13544                type = regClass ? MkClassType(regClass.fullName) : null;
13545             };
13546
13547             propertyWatch.compound.compound.context.symbols.Add((BTNode)thisSymbol);
13548
13549             curExternal = null;
13550             ProcessStatement(propertyWatch.compound);
13551          }
13552          thisClass = null;
13553       }
13554    }
13555 }
13556
13557 void DeclareFunctionUtil(External neededBy, const String s)
13558 {
13559    GlobalFunction function = eSystem_FindFunction(privateModule, s);
13560    if(function)
13561    {
13562       char name[1024];
13563       name[0] = 0;
13564       if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
13565          strcpy(name, "__ecereFunction_");
13566       FullClassNameCat(name, s, false); // Why is this using FullClassNameCat ?
13567       DeclareFunction(neededBy, function, name);
13568    }
13569    else if(neededBy)
13570       FindSymbol(s, globalContext, globalContext, false, false);
13571 }
13572
13573 bool reachedPass15;
13574
13575 void ComputeDataTypes()
13576 {
13577    External external;
13578
13579    currentClass = null;
13580
13581    containerClass = eSystem_FindClass(GetPrivateModule(), "Container");
13582
13583    DeclareStruct(null, "ecere::com::Class", false, true);
13584    DeclareStruct(null, "ecere::com::Instance", false, true);
13585    DeclareStruct(null, "ecere::com::Property", false, true);
13586    DeclareStruct(null, "ecere::com::DataMember", false, true);
13587    DeclareStruct(null, "ecere::com::Method", false, true);
13588    DeclareStruct(null, "ecere::com::SerialBuffer", false, true);
13589    DeclareStruct(null, "ecere::com::ClassTemplateArgument", false, true);
13590
13591    DeclareFunctionUtil(null, "eSystem_New");
13592    DeclareFunctionUtil(null, "eSystem_New0");
13593    DeclareFunctionUtil(null, "eSystem_Renew");
13594    DeclareFunctionUtil(null, "eSystem_Renew0");
13595    DeclareFunctionUtil(null, "eSystem_Delete");
13596    DeclareFunctionUtil(null, "eClass_GetProperty");
13597    DeclareFunctionUtil(null, "eClass_SetProperty");
13598    DeclareFunctionUtil(null, "eInstance_FireSelfWatchers");
13599    DeclareFunctionUtil(null, "eInstance_SetMethod");
13600    DeclareFunctionUtil(null, "eInstance_IncRef");
13601    DeclareFunctionUtil(null, "eInstance_StopWatching");
13602    DeclareFunctionUtil(null, "eInstance_Watch");
13603    DeclareFunctionUtil(null, "eInstance_FireWatchers");
13604    reachedPass15 = true;
13605
13606    for(external = ast->first; external; external = external.next)
13607    {
13608       afterExternal = curExternal = external;
13609       if(external.type == functionExternal)
13610       {
13611          if(memoryGuard)
13612          {
13613             DeclareFunctionUtil(external, "MemoryGuard_PushLoc");
13614             DeclareFunctionUtil(external, "MemoryGuard_PopLoc");
13615          }
13616
13617          currentClass = external.function._class;
13618          ProcessFunction(external.function);
13619       }
13620       // There shouldn't be any _class member access here anyways...
13621       else if(external.type == declarationExternal)
13622       {
13623          if(memoryGuard && external.declaration && external.declaration.type == instDeclaration)
13624          {
13625             DeclareFunctionUtil(external, "MemoryGuard_PushLoc");
13626             DeclareFunctionUtil(external, "MemoryGuard_PopLoc");
13627          }
13628
13629          currentClass = null;
13630          if(external.declaration)
13631             ProcessDeclaration(external.declaration, true);
13632       }
13633       else if(external.type == classExternal)
13634       {
13635          ClassDefinition _class = external._class;
13636          currentClass = external.symbol.registered;
13637          if(memoryGuard)
13638          {
13639             DeclareFunctionUtil(external, "MemoryGuard_PushLoc");
13640             DeclareFunctionUtil(external, "MemoryGuard_PopLoc");
13641          }
13642          if(_class.definitions)
13643          {
13644             ProcessClass(_class.definitions, _class.symbol);
13645          }
13646          if(inCompiler)
13647          {
13648             // Free class data...
13649             ast->Remove(external);
13650             delete external;
13651          }
13652       }
13653       else if(external.type == nameSpaceExternal)
13654       {
13655          thisNameSpace = external.id.string;
13656       }
13657    }
13658    currentClass = null;
13659    thisNameSpace = null;
13660    curExternal = null;
13661 }