compiler/libec; ide/debugger: Division by 0: Error message for integers; nan or inf...
[sdk] / compiler / libec / src / pass15.ec
1 import "ecdefs"
2
3 #define uint _uint
4 #include <stdlib.h>  // For strtoll
5 #undef uint
6
7 // UNTIL IMPLEMENTED IN GRAMMAR
8 #define ACCESS_CLASSDATA(_class, baseClass) \
9    (_class ? ((void *)(((char *)_class.data) + baseClass.offsetClass)) : null)
10
11 #define YYLTYPE Location
12 #include "grammar.h"
13
14 extern OldList * ast;
15 extern int returnCode;
16 extern Expression parsedExpression;
17 extern bool yydebug;
18 public void SetYydebug(bool b) { yydebug = b; }
19 extern bool echoOn;
20
21 void resetScanner();
22
23 // TODO: Reset this to 0 on reinitialization
24 int propWatcherID;
25
26 int expression_yyparse();
27 static Statement curCompound;
28 External curExternal, afterExternal;
29 static Type curSwitchType;
30 static Class currentClass;
31 Class thisClass;
32 public void SetThisClass(Class c) { thisClass = c; } public Class GetThisClass() { return thisClass; }
33 static char * thisNameSpace;
34 /*static */Class containerClass;
35 bool thisClassParams = true;
36
37 uint internalValueCounter;
38
39 #ifdef _DEBUG
40 Time findSymbolTotalTime;
41 #endif
42
43 // WARNING: PrintExpression CONCATENATES to string. Please initialize.
44 /*static */public void PrintExpression(Expression exp, char * string)
45 {
46    //if(inCompiler)
47    {
48       TempFile f { };
49       int count;
50
51       if(exp)
52          OutputExpression(exp, f);
53       f.Seek(0, start);
54       count = strlen(string);
55       count += f.Read(string + count, 1, 1023);
56       string[count] = '\0';
57       delete f;
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)
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 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             symbol = (Symbol)ctx.symbols.FindString(id.string);
125             if(symbol) break;
126          }
127       }
128
129       // If it is not, check if it is a member of the _class
130       if(!symbol && ((!id._class || (id._class.name && !strcmp(id._class.name, "property"))) || (id.classSym && eClass_IsDerived(_class, id.classSym.registered))))
131       {
132          Property prop = eClass_FindProperty(_class, id.string, privateModule);
133          Method method = null;
134          DataMember member = null;
135          ClassProperty classProp = null;
136          if(!prop)
137          {
138             method = eClass_FindMethod(_class, id.string, privateModule);
139          }
140          if(!prop && !method)
141             member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
142          if(!prop && !method && !member)
143          {
144             classProp = eClass_FindClassProperty(_class, id.string);
145          }
146          if(prop || method || member || classProp)
147          {
148             // Replace by this.[member]
149             exp.type = memberExp;
150             exp.member.member = id;
151             exp.member.memberType = unresolvedMember;
152             exp.member.exp = QMkExpId("this");
153             //exp.member.exp.loc = exp.loc;
154             exp.addedThis = true;
155          }
156          else if(_class && _class.templateParams.first)
157          {
158             Class sClass;
159             for(sClass = _class; sClass; sClass = sClass.base)
160             {
161                if(sClass.templateParams.first)
162                {
163                   ClassTemplateParameter param;
164                   for(param = sClass.templateParams.first; param; param = param.next)
165                   {
166                      if(param.type == expression && !strcmp(param.name, id.string))
167                      {
168                         Expression argExp = GetTemplateArgExpByName(param.name, _class, TemplateParameterType::expression);
169
170                         if(argExp)
171                         {
172                            Declarator decl;
173                            OldList * specs = MkList();
174
175                            FreeIdentifier(exp.member.member);
176
177                            ProcessExpressionType(argExp);
178
179                            decl = SpecDeclFromString(param.dataTypeString, specs, null);
180
181                            exp.expType = ProcessType(specs, decl);
182
183                            // *[expType] *[argExp]
184                            exp.type = bracketsExp;
185                            exp.list = MkListOne(MkExpOp(null, '*',
186                               MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpOp(null, '&', argExp))));
187                         }
188                      }
189                   }
190                }
191             }
192          }
193       }
194    }
195 }
196
197 ////////////////////////////////////////////////////////////////////////
198 // PRINTING ////////////////////////////////////////////////////////////
199 ////////////////////////////////////////////////////////////////////////
200
201 public char * PrintInt(int64 result)
202 {
203    char temp[100];
204    if(result > MAXINT64)
205       sprintf(temp, FORMAT64HEXLL /*"0x%I64XLL"*/, result);
206    else
207       sprintf(temp, FORMAT64DLL /*"%I64d"*/, result);
208    return CopyString(temp);
209 }
210
211 public char * PrintUInt(uint64 result)
212 {
213    char temp[100];
214    if(result > MAXDWORD)
215       sprintf(temp, FORMAT64HEXLL /*"0x%I64XLL"*/, result);
216    else if(result > MAXINT)
217       sprintf(temp, FORMAT64HEX /*"0x%I64X"*/, result);
218    else
219       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
220    return CopyString(temp);
221 }
222
223 public char * PrintInt64(int64 result)
224 {
225    char temp[100];
226    sprintf(temp, FORMAT64DLL /*"%I64d"*/, result);
227    return CopyString(temp);
228 }
229
230 public char * PrintUInt64(uint64 result)
231 {
232    char temp[100];
233    if(result > MAXINT64)
234       sprintf(temp, FORMAT64HEXLL /*"0x%I64XLL"*/, result);
235    else
236       sprintf(temp, FORMAT64DLL /*"%I64d"*/, result);
237    return CopyString(temp);
238 }
239
240 public char * PrintHexUInt(uint64 result)
241 {
242    char temp[100];
243    if(result > MAXDWORD)
244       sprintf(temp, FORMAT64HEXLL /*"0x%I64xLL"*/, result);
245    else
246       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
247    return CopyString(temp);
248 }
249
250 public char * PrintHexUInt64(uint64 result)
251 {
252    char temp[100];
253    if(result > MAXDWORD)
254       sprintf(temp, FORMAT64HEXLL /*"0x%I64xLL"*/, result);
255    else
256       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
257    return CopyString(temp);
258 }
259
260 public char * PrintShort(short result)
261 {
262    char temp[100];
263    sprintf(temp, "%d", (unsigned short)result);
264    return CopyString(temp);
265 }
266
267 public char * PrintUShort(unsigned short result)
268 {
269    char temp[100];
270    if(result > 32767)
271       sprintf(temp, "0x%X", (int)result);
272    else
273       sprintf(temp, "%d", (int)result);
274    return CopyString(temp);
275 }
276
277 public char * PrintChar(char result)
278 {
279    char temp[100];
280    if(result > 0 && isprint(result))
281       sprintf(temp, "'%c'", result);
282    else if(result < 0)
283       sprintf(temp, "%d", (int)result);
284    else
285       //sprintf(temp, "%#X", result);
286       sprintf(temp, "0x%X", (unsigned char)result);
287    return CopyString(temp);
288 }
289
290 public char * PrintUChar(unsigned char result)
291 {
292    char temp[100];
293    sprintf(temp, "0x%X", result);
294    return CopyString(temp);
295 }
296
297 public char * PrintFloat(float result)
298 {
299    char temp[350];
300    if(result.isInf)
301    {
302       if(result.signBit)
303          strcpy(temp, "-inf");
304       else
305          strcpy(temp, "inf");
306    }
307    else if(result.isNan)
308    {
309       if(result.signBit)
310          strcpy(temp, "-nan");
311       else
312          strcpy(temp, "nan");
313    }
314    else
315       sprintf(temp, "%.16ff", result);
316    return CopyString(temp);
317 }
318
319 public char * PrintDouble(double result)
320 {
321    char temp[350];
322    if(result.isInf)
323    {
324       if(result.signBit)
325          strcpy(temp, "-inf");
326       else
327          strcpy(temp, "inf");
328    }
329    else if(result.isNan)
330    {
331       if(result.signBit)
332          strcpy(temp, "-nan");
333       else
334          strcpy(temp, "nan");
335    }
336    else
337       sprintf(temp, "%.16f", result);
338    return CopyString(temp);
339 }
340
341 ////////////////////////////////////////////////////////////////////////
342 ////////////////////////////////////////////////////////////////////////
343
344 //public Operand GetOperand(Expression exp);
345
346 #define GETVALUE(name, t) \
347    public bool GetOp##name(Operand op2, t * value2) \
348    {                                                        \
349       if(op2.kind == intType && op2.type.isSigned) *value2 = (t) op2.i; \
350       else if(op2.kind == intType) *value2 = (t) op2.ui;                 \
351       else if(op2.kind == int64Type && op2.type.isSigned) *value2 = (t) op2.i64; \
352       else if(op2.kind == int64Type) *value2 = (t) op2.ui64;                 \
353       else if(op2.kind == intSizeType && op2.type.isSigned) *value2 = (t) op2.i64; \
354       else if(op2.kind == intSizeType) *value2 = (t) op2.ui64; \
355       else if(op2.kind == intPtrType && op2.type.isSigned) *value2 = (t) op2.i64; \
356       else if(op2.kind == intPtrType) *value2 = (t) op2.ui64;                 \
357       else if(op2.kind == shortType && op2.type.isSigned) *value2 = (t) op2.s;   \
358       else if(op2.kind == shortType) *value2 = (t) op2.us;                        \
359       else if(op2.kind == charType && op2.type.isSigned) *value2 = (t) op2.c;    \
360       else if(op2.kind == _BoolType || op2.kind == charType) *value2 = (t) op2.uc; \
361       else if(op2.kind == floatType) *value2 = (t) op2.f;                         \
362       else if(op2.kind == doubleType) *value2 = (t) op2.d;                        \
363       else if(op2.kind == pointerType) *value2 = (t) op2.ui64;                    \
364       else                                                                          \
365          return false;                                                              \
366       return true;                                                                  \
367    } \
368    public bool Get##name(Expression exp, t * value2) \
369    {                                                        \
370       Operand op2 = GetOperand(exp);                        \
371       return GetOp##name(op2, value2); \
372    }
373
374 // To help the deubugger currently not preprocessing...
375 #define HELP(x) x
376
377 GETVALUE(Int, HELP(int));
378 GETVALUE(UInt, HELP(unsigned int));
379 GETVALUE(Int64, HELP(int64));
380 GETVALUE(UInt64, HELP(uint64));
381 GETVALUE(IntPtr, HELP(intptr));
382 GETVALUE(UIntPtr, HELP(uintptr));
383 GETVALUE(IntSize, HELP(intsize));
384 GETVALUE(UIntSize, HELP(uintsize));
385 GETVALUE(Short, HELP(short));
386 GETVALUE(UShort, HELP(unsigned short));
387 GETVALUE(Char, HELP(char));
388 GETVALUE(UChar, HELP(unsigned char));
389 GETVALUE(Float, HELP(float));
390 GETVALUE(Double, HELP(double));
391
392 void ComputeExpression(Expression exp);
393
394 void ComputeClassMembers(Class _class, bool isMember)
395 {
396    DataMember member = isMember ? (DataMember) _class : null;
397    Context context = isMember ? null : SetupTemplatesContext(_class);
398    if(member || ((_class.type == bitClass || _class.type == normalClass || _class.type == structClass || _class.type == noHeadClass) &&
399                  (_class.type == bitClass || (!_class.structSize || _class.structSize == _class.offset)) && _class.computeSize))
400    {
401       int c;
402       int unionMemberOffset = 0;
403       int bitFields = 0;
404
405       /*
406       if(!member && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass) && _class.memberOffset && _class.memberOffset > _class.base.structSize)
407          _class.memberOffset = (_class.base && _class.base.type != systemClass) ? _class.base.structSize : 0;
408       */
409
410       if(member)
411       {
412          member.memberOffset = 0;
413          if(targetBits < sizeof(void *) * 8)
414             member.structAlignment = 0;
415       }
416       else if(targetBits < sizeof(void *) * 8)
417          _class.structAlignment = 0;
418
419       // Confusion here: non struct classes seem to have their memberOffset restart at 0 at each hierarchy level
420       if(!member && ((_class.type == normalClass || _class.type == noHeadClass) || (_class.type == structClass && _class.memberOffset && _class.memberOffset > _class.base.structSize)))
421          _class.memberOffset = (_class.base && _class.type == structClass) ? _class.base.structSize : 0;
422
423       if(!member && _class.destructionWatchOffset)
424          _class.memberOffset += sizeof(OldList);
425
426       // To avoid reentrancy...
427       //_class.structSize = -1;
428
429       {
430          DataMember dataMember;
431          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
432          {
433             if(!dataMember.isProperty)
434             {
435                if(dataMember.type == normalMember && dataMember.dataTypeString && !dataMember.dataType)
436                {
437                   dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
438                   /*if(!dataMember.dataType)
439                      dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
440                      */
441                }
442             }
443          }
444       }
445
446       {
447          DataMember dataMember;
448          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
449          {
450             if(!dataMember.isProperty && (dataMember.type != normalMember || dataMember.dataTypeString))
451             {
452                if(!isMember && _class.type == bitClass && dataMember.dataType)
453                {
454                   BitMember bitMember = (BitMember) dataMember;
455                   uint64 mask = 0;
456                   int d;
457
458                   ComputeTypeSize(dataMember.dataType);
459
460                   if(bitMember.pos == -1) bitMember.pos = _class.memberOffset;
461                   if(!bitMember.size) bitMember.size = dataMember.dataType.size * 8;
462
463                   _class.memberOffset = bitMember.pos + bitMember.size;
464                   for(d = 0; d<bitMember.size; d++)
465                   {
466                      if(d)
467                         mask <<= 1;
468                      mask |= 1;
469                   }
470                   bitMember.mask = mask << bitMember.pos;
471                }
472                else if(dataMember.type == normalMember && dataMember.dataType)
473                {
474                   int size;
475                   int alignment = 0;
476
477                   // Prevent infinite recursion
478                   if(dataMember.dataType.kind != classType ||
479                      ((!dataMember.dataType._class || !dataMember.dataType._class.registered || dataMember.dataType._class.registered != _class ||
480                      _class.type != structClass)))
481                      ComputeTypeSize(dataMember.dataType);
482
483                   if(dataMember.dataType.bitFieldCount)
484                   {
485                      bitFields += dataMember.dataType.bitFieldCount;
486                      size = 0;
487                   }
488                   else
489                   {
490                      if(bitFields)
491                      {
492                         int size = (bitFields + 7) / 8;
493
494                         if(isMember)
495                         {
496                            // TESTING THIS PADDING CODE
497                            if(alignment)
498                            {
499                               member.structAlignment = Max(member.structAlignment, alignment);
500
501                               if(member.memberOffset % alignment)
502                                  member.memberOffset += alignment - (member.memberOffset % alignment);
503                            }
504
505                            dataMember.offset = member.memberOffset;
506                            if(member.type == unionMember)
507                               unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
508                            else
509                            {
510                               member.memberOffset += size;
511                            }
512                         }
513                         else
514                         {
515                            // TESTING THIS PADDING CODE
516                            if(alignment)
517                            {
518                               _class.structAlignment = Max(_class.structAlignment, alignment);
519
520                               if(_class.memberOffset % alignment)
521                                  _class.memberOffset += alignment - (_class.memberOffset % alignment);
522                            }
523
524                            dataMember.offset = _class.memberOffset;
525                            _class.memberOffset += size;
526                         }
527                         bitFields = 0;
528                      }
529                      size = dataMember.dataType.size;
530                      alignment = dataMember.dataType.alignment;
531                   }
532
533                   if(isMember)
534                   {
535                      // TESTING THIS PADDING CODE
536                      if(alignment)
537                      {
538                         member.structAlignment = Max(member.structAlignment, alignment);
539
540                         if(member.memberOffset % alignment)
541                            member.memberOffset += alignment - (member.memberOffset % alignment);
542                      }
543
544                      dataMember.offset = member.memberOffset;
545                      if(member.type == unionMember)
546                         unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
547                      else
548                      {
549                         member.memberOffset += size;
550                      }
551                   }
552                   else
553                   {
554                      // TESTING THIS PADDING CODE
555                      if(alignment)
556                      {
557                         _class.structAlignment = Max(_class.structAlignment, alignment);
558
559                         if(_class.memberOffset % alignment)
560                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
561                      }
562
563                      dataMember.offset = _class.memberOffset;
564                      _class.memberOffset += size;
565                   }
566                }
567                else
568                {
569                   int alignment;
570
571                   ComputeClassMembers((Class)dataMember, true);
572                   alignment = dataMember.structAlignment;
573
574                   if(isMember)
575                   {
576                      if(alignment)
577                      {
578                         if(member.memberOffset % alignment)
579                            member.memberOffset += alignment - (member.memberOffset % alignment);
580
581                         member.structAlignment = Max(member.structAlignment, alignment);
582                      }
583                      dataMember.offset = member.memberOffset;
584                      if(member.type == unionMember)
585                         unionMemberOffset = Max(unionMemberOffset, dataMember.memberOffset);
586                      else
587                         member.memberOffset += dataMember.memberOffset;
588                   }
589                   else
590                   {
591                      if(alignment)
592                      {
593                         if(_class.memberOffset % alignment)
594                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
595                         _class.structAlignment = Max(_class.structAlignment, alignment);
596                      }
597                      dataMember.offset = _class.memberOffset;
598                      _class.memberOffset += dataMember.memberOffset;
599                   }
600                }
601             }
602          }
603          if(bitFields)
604          {
605             int alignment = 0;
606             int size = (bitFields + 7) / 8;
607
608             if(isMember)
609             {
610                // TESTING THIS PADDING CODE
611                if(alignment)
612                {
613                   member.structAlignment = Max(member.structAlignment, alignment);
614
615                   if(member.memberOffset % alignment)
616                      member.memberOffset += alignment - (member.memberOffset % alignment);
617                }
618
619                if(member.type == unionMember)
620                   unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
621                else
622                {
623                   member.memberOffset += size;
624                }
625             }
626             else
627             {
628                // TESTING THIS PADDING CODE
629                if(alignment)
630                {
631                   _class.structAlignment = Max(_class.structAlignment, alignment);
632
633                   if(_class.memberOffset % alignment)
634                      _class.memberOffset += alignment - (_class.memberOffset % alignment);
635                }
636                _class.memberOffset += size;
637             }
638             bitFields = 0;
639          }
640       }
641       if(member && member.type == unionMember)
642       {
643          member.memberOffset = unionMemberOffset;
644       }
645
646       if(!isMember)
647       {
648          /*if(_class.type == structClass)
649             _class.size = _class.memberOffset;
650          else
651          */
652
653          if(_class.type != bitClass)
654          {
655             int extra = 0;
656             if(_class.structAlignment)
657             {
658                if(_class.memberOffset % _class.structAlignment)
659                   extra += _class.structAlignment - (_class.memberOffset % _class.structAlignment);
660             }
661             _class.structSize = (_class.base ? (_class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize) : 0) + _class.memberOffset + extra;
662             if(!member)
663             {
664                Property prop;
665                for(prop = _class.membersAndProperties.first; prop; prop = prop.next)
666                {
667                   if(prop.isProperty && prop.isWatchable)
668                   {
669                      prop.watcherOffset = _class.structSize;
670                      _class.structSize += sizeof(OldList);
671                   }
672                }
673             }
674
675             // Fix Derivatives
676             {
677                OldLink derivative;
678                for(derivative = _class.derivatives.first; derivative; derivative = derivative.next)
679                {
680                   Class deriv = derivative.data;
681
682                   if(deriv.computeSize)
683                   {
684                      // TESTING THIS NEW CODE HERE... TRYING TO FIX ScrollBar MEMBERS DEBUGGING
685                      deriv.offset = /*_class.offset + */_class.structSize;
686                      deriv.memberOffset = 0;
687                      // ----------------------
688
689                      deriv.structSize = deriv.offset;
690
691                      ComputeClassMembers(deriv, false);
692                   }
693                }
694             }
695          }
696       }
697    }
698    if(context)
699       FinishTemplatesContext(context);
700 }
701
702 public void ComputeModuleClasses(Module module)
703 {
704    Class _class;
705    OldLink subModule;
706
707    for(subModule = module.modules.first; subModule; subModule = subModule.next)
708       ComputeModuleClasses(subModule.data);
709    for(_class = module.classes.first; _class; _class = _class.next)
710       ComputeClassMembers(_class, false);
711 }
712
713
714 public int ComputeTypeSize(Type type)
715 {
716    uint size = type ? type.size : 0;
717    if(!size && type && !type.computing)
718    {
719       type.computing = true;
720       switch(type.kind)
721       {
722          case _BoolType: type.alignment = size = sizeof(char); break;   // Assuming 1 byte _Bool
723          case charType: type.alignment = size = sizeof(char); break;
724          case intType: type.alignment = size = sizeof(int); break;
725          case int64Type: type.alignment = size = sizeof(int64); break;
726          case intPtrType: type.alignment = size = targetBits / 8; break;
727          case intSizeType: type.alignment = size = targetBits / 8; break;
728          case longType: type.alignment = size = sizeof(long); break;
729          case shortType: type.alignment = size = sizeof(short); break;
730          case floatType: type.alignment = size = sizeof(float); break;
731          case doubleType: type.alignment = size = sizeof(double); break;
732          case classType:
733          {
734             Class _class = type._class ? type._class.registered : null;
735
736             if(_class && _class.type == structClass)
737             {
738                // Ensure all members are properly registered
739                ComputeClassMembers(_class, false);
740                type.alignment = _class.structAlignment;
741                size = _class.structSize;
742                if(type.alignment && size % type.alignment)
743                   size += type.alignment - (size % type.alignment);
744
745             }
746             else if(_class && (_class.type == unitClass ||
747                    _class.type == enumClass ||
748                    _class.type == bitClass))
749             {
750                if(!_class.dataType)
751                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
752                size = type.alignment = ComputeTypeSize(_class.dataType);
753             }
754             else
755                size = type.alignment = targetBits / 8; // sizeof(Instance *);
756             break;
757          }
758          case pointerType: case subClassType: size = type.alignment = targetBits / 8; /*sizeof(void *); */break;
759          case arrayType:
760             if(type.arraySizeExp)
761             {
762                ProcessExpressionType(type.arraySizeExp);
763                ComputeExpression(type.arraySizeExp);
764                if(!type.arraySizeExp.isConstant || (type.arraySizeExp.expType.kind != intType && type.arraySizeExp.expType.kind != enumType &&
765                   (type.arraySizeExp.expType.kind != classType || !type.arraySizeExp.expType._class.registered || type.arraySizeExp.expType._class.registered.type != enumClass)))
766                {
767                   Location oldLoc = yylloc;
768                   // bool isConstant = type.arraySizeExp.isConstant;
769                   char expression[10240];
770                   expression[0] = '\0';
771                   type.arraySizeExp.expType = null;
772                   yylloc = type.arraySizeExp.loc;
773                   if(inCompiler)
774                      PrintExpression(type.arraySizeExp, expression);
775                   Compiler_Error($"Array size not constant int (%s)\n", expression);
776                   yylloc = oldLoc;
777                }
778                GetInt(type.arraySizeExp, &type.arraySize);
779             }
780             else if(type.enumClass)
781             {
782                if(type.enumClass && type.enumClass.registered && type.enumClass.registered.type == enumClass)
783                {
784                   type.arraySize = (int)eClass_GetProperty(type.enumClass.registered, "enumSize");
785                }
786                else
787                   type.arraySize = 0;
788             }
789             else
790             {
791                // Unimplemented auto size
792                type.arraySize = 0;
793             }
794
795             size = ComputeTypeSize(type.type) * type.arraySize;
796             if(type.type)
797                type.alignment = type.type.alignment;
798
799             break;
800          case structType:
801          {
802             Type member;
803             for(member = type.members.first; member; member = member.next)
804             {
805                uint addSize = ComputeTypeSize(member);
806
807                member.offset = size;
808                if(member.alignment && size % member.alignment)
809                   member.offset += member.alignment - (size % member.alignment);
810                size = member.offset;
811
812                type.alignment = Max(type.alignment, member.alignment);
813                size += addSize;
814             }
815             if(type.alignment && size % type.alignment)
816                size += type.alignment - (size % type.alignment);
817             break;
818          }
819          case unionType:
820          {
821             Type member;
822             for(member = type.members.first; member; member = member.next)
823             {
824                uint addSize = ComputeTypeSize(member);
825
826                member.offset = size;
827                if(member.alignment && size % member.alignment)
828                   member.offset += member.alignment - (size % member.alignment);
829                size = member.offset;
830
831                type.alignment = Max(type.alignment, member.alignment);
832                size = Max(size, addSize);
833             }
834             if(type.alignment && size % type.alignment)
835                size += type.alignment - (size % type.alignment);
836             break;
837          }
838          case templateType:
839          {
840             TemplateParameter param = type.templateParameter;
841             Type baseType = ProcessTemplateParameterType(param);
842             if(baseType)
843             {
844                size = ComputeTypeSize(baseType);
845                type.alignment = baseType.alignment;
846             }
847             else
848                type.alignment = size = sizeof(uint64);
849             break;
850          }
851          case enumType:
852          {
853             type.alignment = size = sizeof(enum { test });
854             break;
855          }
856          case thisClassType:
857          {
858             type.alignment = size = targetBits / 8; //sizeof(void *);
859             break;
860          }
861       }
862       type.size = size;
863       type.computing = false;
864    }
865    return size;
866 }
867
868
869 /*static */int AddMembers(OldList * declarations, Class _class, bool isMember, uint * retSize, Class topClass, bool *addedPadding)
870 {
871    // This function is in need of a major review when implementing private members etc.
872    DataMember topMember = isMember ? (DataMember) _class : null;
873    uint totalSize = 0;
874    uint maxSize = 0;
875    int alignment, size;
876    DataMember member;
877    Context context = isMember ? null : SetupTemplatesContext(_class);
878    if(addedPadding)
879       *addedPadding = false;
880
881    if(!isMember && _class.base)
882    {
883       maxSize = _class.structSize;
884       //if(_class.base.type != systemClass) // Commented out with new Instance _class
885       {
886          // DANGER: Testing this noHeadClass here...
887          if(_class.type == structClass || _class.type == noHeadClass)
888             /*totalSize = */AddMembers(declarations, _class.base, false, &totalSize, topClass, null);
889          else
890          {
891             uint baseSize = _class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize;
892             if(maxSize > baseSize)
893                maxSize -= baseSize;
894             else
895                maxSize = 0;
896          }
897       }
898    }
899
900    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
901    {
902       if(!member.isProperty)
903       {
904          switch(member.type)
905          {
906             case normalMember:
907             {
908                if(member.dataTypeString)
909                {
910                   OldList * specs = MkList(), * decls = MkList();
911                   Declarator decl;
912
913                   decl = SpecDeclFromString(member.dataTypeString, specs,
914                      MkDeclaratorIdentifier(MkIdentifier(member.name)));
915                   ListAdd(decls, MkStructDeclarator(decl, null));
916                   ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, decls, null)));
917
918                   if(!member.dataType)
919                      member.dataType = ProcessType(specs, decl);
920
921                   ReplaceThisClassSpecifiers(specs, topClass /*member._class*/);
922
923                   {
924                      Type type = ProcessType(specs, decl);
925                      DeclareType(member.dataType, false, false);
926                      FreeType(type);
927                   }
928                   /*
929                   if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
930                      member.dataType._class.registered && member.dataType._class.registered.type == structClass)
931                      DeclareStruct(member.dataType._class.string, false);
932                   */
933
934                   ComputeTypeSize(member.dataType);
935                   size = member.dataType.size;
936                   alignment = member.dataType.alignment;
937
938                   if(alignment)
939                   {
940                      if(totalSize % alignment)
941                         totalSize += alignment - (totalSize % alignment);
942                   }
943                   totalSize += size;
944                }
945                break;
946             }
947             case unionMember:
948             case structMember:
949             {
950                OldList * specs = MkList(), * list = MkList();
951
952                size = 0;
953                AddMembers(list, (Class)member, true, &size, topClass, null);
954                ListAdd(specs,
955                   MkStructOrUnion((member.type == unionMember)?unionSpecifier:structSpecifier, null, list));
956                ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, null, null)));
957                alignment = member.structAlignment;
958
959                if(alignment)
960                {
961                   if(totalSize % alignment)
962                      totalSize += alignment - (totalSize % alignment);
963                }
964                totalSize += size;
965                break;
966             }
967          }
968       }
969    }
970    if(retSize)
971    {
972       if(topMember && topMember.type == unionMember)
973          *retSize = Max(*retSize, totalSize);
974       else
975          *retSize += totalSize;
976    }
977    else if(totalSize < maxSize && _class.type != systemClass)
978    {
979       int autoPadding = 0;
980       if(!isMember && _class.structAlignment && totalSize % _class.structAlignment)
981          autoPadding = _class.structAlignment - (totalSize % _class.structAlignment);
982       if(totalSize + autoPadding < maxSize)
983       {
984          char sizeString[50];
985          sprintf(sizeString, "%d", maxSize - totalSize);
986          ListAdd(declarations,
987             MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(CHAR)),
988             MkListOne(MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__ecere_padding")), MkExpConstant(sizeString))), null)));
989          if(addedPadding)
990             *addedPadding = true;
991       }
992    }
993    if(context)
994       FinishTemplatesContext(context);
995    return topMember ? topMember.memberID : _class.memberID;
996 }
997
998 static int DeclareMembers(Class _class, bool isMember)
999 {
1000    DataMember topMember = isMember ? (DataMember) _class : null;
1001    uint totalSize = 0;
1002    DataMember member;
1003    Context context = isMember ? null : SetupTemplatesContext(_class);
1004
1005    if(!isMember && (_class.type == structClass || _class.type == noHeadClass) && _class.base.type != systemClass)
1006       DeclareMembers(_class.base, false);
1007
1008    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
1009    {
1010       if(!member.isProperty)
1011       {
1012          switch(member.type)
1013          {
1014             case normalMember:
1015             {
1016                /*
1017                if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
1018                   member.dataType._class.registered && member.dataType._class.registered.type == structClass)
1019                   DeclareStruct(member.dataType._class.string, false);
1020                   */
1021                if(!member.dataType && member.dataTypeString)
1022                   member.dataType = ProcessTypeString(member.dataTypeString, false);
1023                if(member.dataType)
1024                   DeclareType(member.dataType, false, false);
1025                break;
1026             }
1027             case unionMember:
1028             case structMember:
1029             {
1030                DeclareMembers((Class)member, true);
1031                break;
1032             }
1033          }
1034       }
1035    }
1036    if(context)
1037       FinishTemplatesContext(context);
1038
1039    return topMember ? topMember.memberID : _class.memberID;
1040 }
1041
1042 void DeclareStruct(char * name, bool skipNoHead)
1043 {
1044    External external = null;
1045    Symbol classSym = FindClass(name);
1046
1047    if(!inCompiler || !classSym) return;
1048
1049    // We don't need any declaration for bit classes...
1050    if(classSym.registered &&
1051       (classSym.registered.type == bitClass || classSym.registered.type == unitClass || classSym.registered.type == enumClass))
1052       return;
1053
1054    /*if(classSym.registered.templateClass)
1055       return DeclareStruct(classSym.registered.templateClass.fullName, skipNoHead);
1056    */
1057
1058    if(classSym.registered && classSym.imported && !classSym.declaredStructSym)
1059    {
1060       // Add typedef struct
1061       Declaration decl;
1062       OldList * specifiers, * declarators;
1063       OldList * declarations = null;
1064       char structName[1024];
1065       external = (classSym.registered && classSym.registered.type == structClass) ?
1066          classSym.pointerExternal : classSym.structExternal;
1067
1068       // TEMPORARY HACK: Pass 3 will move up struct declarations without moving members
1069       // Moved this one up because DeclareClass done later will need it
1070
1071       classSym.declaring++;
1072
1073       if(strchr(classSym.string, '<'))
1074       {
1075          if(classSym.registered.templateClass)
1076          {
1077             DeclareStruct(classSym.registered.templateClass.fullName, skipNoHead);
1078             classSym.declaring--;
1079          }
1080          return;
1081       }
1082
1083       //if(!skipNoHead)
1084          DeclareMembers(classSym.registered, false);
1085
1086       structName[0] = 0;
1087       FullClassNameCat(structName, name, false);
1088
1089       /*if(!external)
1090          external = MkExternalDeclaration(null);*/
1091
1092       if(!skipNoHead)
1093       {
1094          bool addedPadding = false;
1095          classSym.declaredStructSym = true;
1096
1097          declarations = MkList();
1098
1099          AddMembers(declarations, classSym.registered, false, null, classSym.registered, &addedPadding);
1100
1101          //ListAdd(specifiers, MkSpecifier(TYPEDEF));
1102          //ListAdd(specifiers, MkStructOrUnion(structSpecifier, null, declarations));
1103
1104          if(!declarations->count || (declarations->count == 1 && addedPadding))
1105          {
1106             FreeList(declarations, FreeClassDef);
1107             declarations = null;
1108          }
1109       }
1110       if(skipNoHead || declarations)
1111       {
1112          if(external && external.declaration)
1113          {
1114             ((Specifier)external.declaration.specifiers->first).definitions = declarations;
1115
1116             if(curExternal && curExternal.symbol && curExternal.symbol.idCode < classSym.id)
1117             {
1118                // TODO: Fix this
1119                //ast->Move(classSym.structExternal ? classSym.structExternal : classSym.pointerExternal, curExternal.prev);
1120
1121                // DANGER
1122                if(classSym.structExternal)
1123                   ast->Move(classSym.structExternal, curExternal.prev);
1124                ast->Move(classSym.pointerExternal, curExternal.prev);
1125
1126                classSym.id = curExternal.symbol.idCode;
1127                classSym.idCode = curExternal.symbol.idCode;
1128                // external = classSym.pointerExternal;
1129                //external = classSym.structExternal ? classSym.structExternal : classSym.pointerExternal;
1130             }
1131          }
1132          else
1133          {
1134             if(!external)
1135                external = MkExternalDeclaration(null);
1136
1137             specifiers = MkList();
1138             declarators = MkList();
1139             ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), declarations));
1140
1141             /*
1142             d = MkDeclaratorIdentifier(MkIdentifier(structName));
1143             ListAdd(declarators, MkInitDeclarator(d, null));
1144             */
1145             external.declaration = decl = MkDeclaration(specifiers, declarators);
1146             if(decl.symbol && !decl.symbol.pointerExternal)
1147                decl.symbol.pointerExternal = external;
1148
1149             // For simple classes, keep the declaration as the external to move around
1150             if(classSym.registered && classSym.registered.type == structClass)
1151             {
1152                char className[1024];
1153                strcpy(className, "__ecereClass_");
1154                FullClassNameCat(className, classSym.string, true);
1155                MangleClassName(className);
1156
1157                // Testing This
1158                DeclareClass(classSym, className);
1159
1160                external.symbol = classSym;
1161                classSym.pointerExternal = external;
1162                classSym.id = (curExternal && curExternal.symbol) ? curExternal.symbol.idCode : 0;
1163                classSym.idCode = (curExternal && curExternal.symbol) ? curExternal.symbol.idCode : 0;
1164             }
1165             else
1166             {
1167                char className[1024];
1168                strcpy(className, "__ecereClass_");
1169                FullClassNameCat(className, classSym.string, true);
1170                MangleClassName(className);
1171
1172                // TOFIX: TESTING THIS...
1173                classSym.structExternal = external;
1174                DeclareClass(classSym, className);
1175                external.symbol = classSym;
1176             }
1177
1178             //if(curExternal)
1179                ast->Insert(curExternal ? curExternal.prev : null, external);
1180          }
1181       }
1182
1183       classSym.declaring--;
1184    }
1185    else if(curExternal && curExternal.symbol && curExternal.symbol.idCode < classSym.id)
1186    {
1187       // TEMPORARY HACK: Pass 3 will move up struct declarations without moving members
1188       // Moved this one up because DeclareClass done later will need it
1189
1190       // TESTING THIS:
1191       classSym.declaring++;
1192
1193       //if(!skipNoHead)
1194       {
1195          if(classSym.registered)
1196             DeclareMembers(classSym.registered, false);
1197       }
1198
1199       if(classSym.registered && (classSym.registered.type == structClass || classSym.registered.type == noHeadClass))
1200       {
1201          // TODO: Fix this
1202          //ast->Move(classSym.structExternal ? classSym.structExternal : classSym.pointerExternal, curExternal.prev);
1203
1204          // DANGER
1205          if(classSym.structExternal)
1206             ast->Move(classSym.structExternal, curExternal.prev);
1207          ast->Move(classSym.pointerExternal, curExternal.prev);
1208
1209          classSym.id = curExternal.symbol.idCode;
1210          classSym.idCode = curExternal.symbol.idCode;
1211          // external = classSym.pointerExternal;
1212          // external = classSym.structExternal ? classSym.structExternal : classSym.pointerExternal;
1213       }
1214
1215       classSym.declaring--;
1216    }
1217    //return external;
1218 }
1219
1220 void DeclareProperty(Property prop, char * setName, char * getName)
1221 {
1222    Symbol symbol = prop.symbol;
1223    char propName[1024];
1224
1225    strcpy(setName, "__ecereProp_");
1226    FullClassNameCat(setName, prop._class.fullName, false);
1227    strcat(setName, "_Set_");
1228    // strcat(setName, prop.name);
1229    FullClassNameCat(setName, prop.name, true);
1230
1231    strcpy(getName, "__ecereProp_");
1232    FullClassNameCat(getName, prop._class.fullName, false);
1233    strcat(getName, "_Get_");
1234    FullClassNameCat(getName, prop.name, true);
1235    // strcat(getName, prop.name);
1236
1237    strcpy(propName, "__ecereProp_");
1238    FullClassNameCat(propName, prop._class.fullName, false);
1239    strcat(propName, "_");
1240    FullClassNameCat(propName, prop.name, true);
1241    // strcat(propName, prop.name);
1242
1243    // To support "char *" property
1244    MangleClassName(getName);
1245    MangleClassName(setName);
1246    MangleClassName(propName);
1247
1248    if(prop._class.type == structClass)
1249       DeclareStruct(prop._class.fullName, false);
1250
1251    if(!symbol || curExternal.symbol.idCode < symbol.id)
1252    {
1253       bool imported = false;
1254       bool dllImport = false;
1255       if(!symbol || symbol._import)
1256       {
1257          if(!symbol)
1258          {
1259             Symbol classSym;
1260             if(!prop._class.symbol)
1261                prop._class.symbol = FindClass(prop._class.fullName);
1262             classSym = prop._class.symbol;
1263             if(classSym && !classSym._import)
1264             {
1265                ModuleImport module;
1266
1267                if(prop._class.module)
1268                   module = FindModule(prop._class.module);
1269                else
1270                   module = mainModule;
1271
1272                classSym._import = ClassImport
1273                {
1274                   name = CopyString(prop._class.fullName);
1275                   isRemote = prop._class.isRemote;
1276                };
1277                module.classes.Add(classSym._import);
1278             }
1279             symbol = prop.symbol = Symbol { };
1280             symbol._import = (ClassImport)PropertyImport
1281             {
1282                name = CopyString(prop.name);
1283                isVirtual = false; //prop.isVirtual;
1284                hasSet = prop.Set ? true : false;
1285                hasGet = prop.Get ? true : false;
1286             };
1287             if(classSym)
1288                classSym._import.properties.Add(symbol._import);
1289          }
1290          imported = true;
1291          // Ugly work around for isNan properties declared within float/double classes which are initialized with ecereCOM
1292          if((prop._class.module != privateModule || !strcmp(prop._class.name, "float") || !strcmp(prop._class.name, "double")) &&
1293             prop._class.module.importType != staticImport)
1294             dllImport = true;
1295       }
1296
1297       if(!symbol.type)
1298       {
1299          Context context = SetupTemplatesContext(prop._class);
1300          symbol.type = ProcessTypeString(prop.dataTypeString, false);
1301          FinishTemplatesContext(context);
1302       }
1303
1304       // Get
1305       if(prop.Get)
1306       {
1307          if(!symbol.externalGet || symbol.externalGet.type == functionExternal)
1308          {
1309             Declaration decl;
1310             OldList * specifiers, * declarators;
1311             Declarator d;
1312             OldList * params;
1313             Specifier spec;
1314             External external;
1315             Declarator typeDecl;
1316             bool simple = false;
1317
1318             specifiers = MkList();
1319             declarators = MkList();
1320             params = MkList();
1321
1322             ListAdd(params, MkTypeName(MkListOne(MkSpecifierName /*MkClassName*/(prop._class.fullName)),
1323                MkDeclaratorIdentifier(MkIdentifier("this"))));
1324
1325             d = MkDeclaratorIdentifier(MkIdentifier(getName));
1326             //if(imported)
1327             if(dllImport)
1328                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1329
1330             {
1331                Context context = SetupTemplatesContext(prop._class);
1332                typeDecl = SpecDeclFromString(prop.dataTypeString, specifiers, null);
1333                FinishTemplatesContext(context);
1334             }
1335
1336             // Make sure the simple _class's type is declared
1337             for(spec = specifiers->first; spec; spec = spec.next)
1338             {
1339                if(spec.type == nameSpecifier /*SpecifierClass*/)
1340                {
1341                   if((!typeDecl || typeDecl.type == identifierDeclarator))
1342                   {
1343                      Symbol classSym = spec.symbol; // FindClass(spec.name);
1344                      symbol._class = classSym.registered;
1345                      if(classSym.registered && classSym.registered.type == structClass)
1346                      {
1347                         DeclareStruct(spec.name, false);
1348                         simple = true;
1349                      }
1350                   }
1351                }
1352             }
1353
1354             if(!simple)
1355                d = PlugDeclarator(typeDecl, d);
1356             else
1357             {
1358                ListAdd(params, MkTypeName(specifiers,
1359                   PlugDeclarator(typeDecl, MkDeclaratorIdentifier(MkIdentifier("value")))));
1360                specifiers = MkList();
1361             }
1362
1363             d = MkDeclaratorFunction(d, params);
1364
1365             //if(imported)
1366             if(dllImport)
1367                specifiers->Insert(null, MkSpecifier(EXTERN));
1368             else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1369                specifiers->Insert(null, MkSpecifier(STATIC));
1370             if(simple)
1371                ListAdd(specifiers, MkSpecifier(VOID));
1372
1373             ListAdd(declarators, MkInitDeclarator(d, null));
1374
1375             decl = MkDeclaration(specifiers, declarators);
1376
1377             external = MkExternalDeclaration(decl);
1378             ast->Insert(curExternal.prev, external);
1379             external.symbol = symbol;
1380             symbol.externalGet = external;
1381
1382             ReplaceThisClassSpecifiers(specifiers, prop._class);
1383
1384             if(typeDecl)
1385                FreeDeclarator(typeDecl);
1386          }
1387          else
1388          {
1389             // Move declaration higher...
1390             ast->Move(symbol.externalGet, curExternal.prev);
1391          }
1392       }
1393
1394       // Set
1395       if(prop.Set)
1396       {
1397          if(!symbol.externalSet || symbol.externalSet.type == functionExternal)
1398          {
1399             Declaration decl;
1400             OldList * specifiers, * declarators;
1401             Declarator d;
1402             OldList * params;
1403             Specifier spec;
1404             External external;
1405             Declarator typeDecl;
1406
1407             declarators = MkList();
1408             params = MkList();
1409
1410             // TESTING COMMENTING THIS FIRST LINE OUT, what was the problem? Trying to add noHeadClass here ...
1411             if(!prop.conversion || prop._class.type == structClass)
1412             {
1413                ListAdd(params, MkTypeName(MkListOne(MkSpecifierName/*MkClassName*/(prop._class.fullName)),
1414                   MkDeclaratorIdentifier(MkIdentifier("this"))));
1415             }
1416
1417             specifiers = MkList();
1418
1419             {
1420                Context context = SetupTemplatesContext(prop._class);
1421                typeDecl = d = SpecDeclFromString(prop.dataTypeString, specifiers,
1422                   MkDeclaratorIdentifier(MkIdentifier("value")));
1423                FinishTemplatesContext(context);
1424             }
1425             ListAdd(params, MkTypeName(specifiers, d));
1426
1427             d = MkDeclaratorIdentifier(MkIdentifier(setName));
1428             //if(imported)
1429             if(dllImport)
1430                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1431             d = MkDeclaratorFunction(d, params);
1432
1433             // Make sure the simple _class's type is declared
1434             for(spec = specifiers->first; spec; spec = spec.next)
1435             {
1436                if(spec.type == nameSpecifier /*SpecifierClass*/)
1437                {
1438                   if((!typeDecl || typeDecl.type == identifierDeclarator))
1439                   {
1440                      Symbol classSym = spec.symbol; // FindClass(spec.name);
1441                      symbol._class = classSym.registered;
1442                      if(classSym.registered && classSym.registered.type == structClass)
1443                         DeclareStruct(spec.name, false);
1444                   }
1445                }
1446             }
1447
1448             ListAdd(declarators, MkInitDeclarator(d, null));
1449
1450             specifiers = MkList();
1451             //if(imported)
1452             if(dllImport)
1453                specifiers->Insert(null, MkSpecifier(EXTERN));
1454             else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1455                specifiers->Insert(null, MkSpecifier(STATIC));
1456
1457             // TESTING COMMENTING THIS FIRST LINE OUT, what was the problem? Trying to add noHeadClass here ...
1458             if(!prop.conversion || prop._class.type == structClass)
1459                ListAdd(specifiers, MkSpecifier(VOID));
1460             else
1461                ListAdd(specifiers, MkSpecifierName/*MkClassName*/(prop._class.fullName));
1462
1463             decl = MkDeclaration(specifiers, declarators);
1464
1465             external = MkExternalDeclaration(decl);
1466             ast->Insert(curExternal.prev, external);
1467             external.symbol = symbol;
1468             symbol.externalSet = external;
1469
1470             ReplaceThisClassSpecifiers(specifiers, prop._class);
1471          }
1472          else
1473          {
1474             // Move declaration higher...
1475             ast->Move(symbol.externalSet, curExternal.prev);
1476          }
1477       }
1478
1479       // Property (for Watchers)
1480       if(!symbol.externalPtr)
1481       {
1482          Declaration decl;
1483          External external;
1484          OldList * specifiers = MkList();
1485
1486          if(imported)
1487             specifiers->Insert(null, MkSpecifier(EXTERN));
1488          else
1489             specifiers->Insert(null, MkSpecifier(STATIC));
1490
1491          ListAdd(specifiers, MkSpecifierName("Property"));
1492
1493          {
1494             OldList * list = MkList();
1495             ListAdd(list, MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null),
1496                   MkDeclaratorIdentifier(MkIdentifier(propName))), null));
1497
1498             if(!imported)
1499             {
1500                strcpy(propName, "__ecerePropM_");
1501                FullClassNameCat(propName, prop._class.fullName, false);
1502                strcat(propName, "_");
1503                // strcat(propName, prop.name);
1504                FullClassNameCat(propName, prop.name, true);
1505
1506                MangleClassName(propName);
1507
1508                ListAdd(list, MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null),
1509                      MkDeclaratorIdentifier(MkIdentifier(propName))), null));
1510             }
1511             decl = MkDeclaration(specifiers, list);
1512          }
1513
1514          external = MkExternalDeclaration(decl);
1515          ast->Insert(curExternal.prev, external);
1516          external.symbol = symbol;
1517          symbol.externalPtr = external;
1518       }
1519       else
1520       {
1521          // Move declaration higher...
1522          ast->Move(symbol.externalPtr, curExternal.prev);
1523       }
1524
1525       symbol.id = curExternal.symbol.idCode;
1526    }
1527 }
1528
1529 // ***************** EXPRESSION PROCESSING ***************************
1530 public Type Dereference(Type source)
1531 {
1532    Type type = null;
1533    if(source)
1534    {
1535       if(source.kind == pointerType || source.kind == arrayType)
1536       {
1537          type = source.type;
1538          source.type.refCount++;
1539       }
1540       else if(source.kind == classType && !strcmp(source._class.string, "String"))
1541       {
1542          type = Type
1543          {
1544             kind = charType;
1545             refCount = 1;
1546          };
1547       }
1548       // Support dereferencing of no head classes for now...
1549       else if(source.kind == classType && source._class && source._class.registered && source._class.registered.type == noHeadClass)
1550       {
1551          type = source;
1552          source.refCount++;
1553       }
1554       else
1555          Compiler_Error($"cannot dereference type\n");
1556    }
1557    return type;
1558 }
1559
1560 static Type Reference(Type source)
1561 {
1562    Type type = null;
1563    if(source)
1564    {
1565       type = Type
1566       {
1567          kind = pointerType;
1568          type = source;
1569          refCount = 1;
1570       };
1571       source.refCount++;
1572    }
1573    return type;
1574 }
1575
1576 void ProcessMemberInitData(MemberInit member, Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
1577 {
1578    Identifier ident = member.identifiers ? member.identifiers->first : null;
1579    bool found = false;
1580    DataMember dataMember = null;
1581    Method method = null;
1582    bool freeType = false;
1583
1584    yylloc = member.loc;
1585
1586    if(!ident)
1587    {
1588       if(curMember)
1589       {
1590          eClass_FindNextMember(_class, curClass, curMember, subMemberStack, subMemberStackPos);
1591          if(*curMember)
1592          {
1593             found = true;
1594             dataMember = *curMember;
1595          }
1596       }
1597    }
1598    else
1599    {
1600       DataMember thisMember = (DataMember)eClass_FindProperty(_class, ident.string, privateModule);
1601       DataMember _subMemberStack[256];
1602       int _subMemberStackPos = 0;
1603
1604       // FILL MEMBER STACK
1605       if(!thisMember)
1606          thisMember = eClass_FindDataMember(_class, ident.string, privateModule, _subMemberStack, &_subMemberStackPos);
1607       if(thisMember)
1608       {
1609          dataMember = thisMember;
1610          if(curMember && thisMember.memberAccess == publicAccess)
1611          {
1612             *curMember = thisMember;
1613             *curClass = thisMember._class;
1614             memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
1615             *subMemberStackPos = _subMemberStackPos;
1616          }
1617          found = true;
1618       }
1619       else
1620       {
1621          // Setting a method
1622          method = eClass_FindMethod(_class, ident.string, privateModule);
1623          if(method && method.type == virtualMethod)
1624             found = true;
1625          else
1626             method = null;
1627       }
1628    }
1629
1630    if(found)
1631    {
1632       Type type = null;
1633       if(dataMember)
1634       {
1635          if(!dataMember.dataType && dataMember.dataTypeString)
1636          {
1637             //Context context = SetupTemplatesContext(dataMember._class);
1638             Context context = SetupTemplatesContext(_class);
1639             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
1640             FinishTemplatesContext(context);
1641          }
1642          type = dataMember.dataType;
1643       }
1644       else if(method)
1645       {
1646          // This is for destination type...
1647          if(!method.dataType)
1648             ProcessMethodType(method);
1649          //DeclareMethod(method);
1650          // method.dataType = ((Symbol)method.symbol)->type;
1651          type = method.dataType;
1652       }
1653
1654       if(ident && ident.next)
1655       {
1656          for(ident = ident.next; ident && type; ident = ident.next)
1657          {
1658             if(type.kind == classType)
1659             {
1660                dataMember = (DataMember)eClass_FindProperty(type._class.registered, ident.string, privateModule);
1661                if(!dataMember)
1662                   dataMember = eClass_FindDataMember(type._class.registered, ident.string, privateModule, null, null);
1663                if(dataMember)
1664                   type = dataMember.dataType;
1665             }
1666             else if(type.kind == structType || type.kind == unionType)
1667             {
1668                Type memberType;
1669                for(memberType = type.members.first; memberType; memberType = memberType.next)
1670                {
1671                   if(!strcmp(memberType.name, ident.string))
1672                   {
1673                      type = memberType;
1674                      break;
1675                   }
1676                }
1677             }
1678          }
1679       }
1680
1681       // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
1682       if(type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type && _class.templateArgs /* TODO: Watch out for these _class.templateClass*/)
1683       {
1684          int id = 0;
1685          ClassTemplateParameter curParam = null;
1686          Class sClass;
1687          for(sClass = _class; sClass; sClass = sClass.base)
1688          {
1689             id = 0;
1690             if(sClass.templateClass) sClass = sClass.templateClass;
1691             for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
1692             {
1693                if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
1694                {
1695                   for(sClass = sClass.base; sClass; sClass = sClass.base)
1696                   {
1697                      if(sClass.templateClass) sClass = sClass.templateClass;
1698                      id += sClass.templateParams.count;
1699                   }
1700                   break;
1701                }
1702                id++;
1703             }
1704             if(curParam) break;
1705          }
1706
1707          if(curParam)
1708          {
1709             ClassTemplateArgument arg = _class.templateArgs[id];
1710             if(arg.dataTypeString)
1711             {
1712                // FreeType(type);
1713                type = ProcessTypeString(arg.dataTypeString, false);
1714                freeType = true;
1715                if(type && _class.templateClass)
1716                   type.passAsTemplate = true;
1717                if(type)
1718                {
1719                   // type.refCount++;
1720                   /*if(!exp.destType)
1721                   {
1722                      exp.destType = ProcessTypeString(arg.dataTypeString, false);
1723                      exp.destType.refCount++;
1724                   }*/
1725                }
1726             }
1727          }
1728       }
1729       if(type && type.kind == classType && type._class && type._class.registered && strchr(type._class.registered.fullName, '<'))
1730       {
1731          Class expClass = type._class.registered;
1732          Class cClass = null;
1733          int c;
1734          int paramCount = 0;
1735          int lastParam = -1;
1736
1737          char templateString[1024];
1738          ClassTemplateParameter param;
1739          sprintf(templateString, "%s<", expClass.templateClass.fullName);
1740          for(cClass = expClass; cClass; cClass = cClass.base)
1741          {
1742             int p = 0;
1743             if(cClass.templateClass) cClass = cClass.templateClass;
1744             for(param = cClass.templateParams.first; param; param = param.next)
1745             {
1746                int id = p;
1747                Class sClass;
1748                ClassTemplateArgument arg;
1749                for(sClass = cClass.base; sClass; sClass = sClass.base)
1750                {
1751                   if(sClass.templateClass) sClass = sClass.templateClass;
1752                   id += sClass.templateParams.count;
1753                }
1754                arg = expClass.templateArgs[id];
1755
1756                for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
1757                {
1758                   ClassTemplateParameter cParam;
1759                   //int p = numParams - sClass.templateParams.count;
1760                   int p = 0;
1761                   Class nextClass;
1762                   if(sClass.templateClass) sClass = sClass.templateClass;
1763
1764                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
1765                   {
1766                      if(nextClass.templateClass) nextClass = nextClass.templateClass;
1767                      p += nextClass.templateParams.count;
1768                   }
1769
1770                   for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
1771                   {
1772                      if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
1773                      {
1774                         if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1775                         {
1776                            arg.dataTypeString = _class.templateArgs[p].dataTypeString;
1777                            arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
1778                            break;
1779                         }
1780                      }
1781                   }
1782                }
1783
1784                {
1785                   char argument[256];
1786                   argument[0] = '\0';
1787                   /*if(arg.name)
1788                   {
1789                      strcat(argument, arg.name.string);
1790                      strcat(argument, " = ");
1791                   }*/
1792                   switch(param.type)
1793                   {
1794                      case expression:
1795                      {
1796                         // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
1797                         char expString[1024];
1798                         OldList * specs = MkList();
1799                         Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
1800                         Expression exp;
1801                         char * string = PrintHexUInt64(arg.expression.ui64);
1802                         exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
1803                         delete string;
1804
1805                         ProcessExpressionType(exp);
1806                         ComputeExpression(exp);
1807                         expString[0] = '\0';
1808                         PrintExpression(exp, expString);
1809                         strcat(argument, expString);
1810                         //delete exp;
1811                         FreeExpression(exp);
1812                         break;
1813                      }
1814                      case identifier:
1815                      {
1816                         strcat(argument, arg.member.name);
1817                         break;
1818                      }
1819                      case TemplateParameterType::type:
1820                      {
1821                         if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1822                            strcat(argument, arg.dataTypeString);
1823                         break;
1824                      }
1825                   }
1826                   if(argument[0])
1827                   {
1828                      if(paramCount) strcat(templateString, ", ");
1829                      if(lastParam != p - 1)
1830                      {
1831                         strcat(templateString, param.name);
1832                         strcat(templateString, " = ");
1833                      }
1834                      strcat(templateString, argument);
1835                      paramCount++;
1836                      lastParam = p;
1837                   }
1838                   p++;
1839                }
1840             }
1841          }
1842          {
1843             int len = strlen(templateString);
1844             if(templateString[len-1] == '<')
1845                len--;
1846             else
1847             {
1848                if(templateString[len-1] == '>')
1849                   templateString[len++] = ' ';
1850                templateString[len++] = '>';
1851             }
1852             templateString[len++] = '\0';
1853          }
1854          {
1855             Context context = SetupTemplatesContext(_class);
1856             if(freeType) FreeType(type);
1857             type = ProcessTypeString(templateString, false);
1858             freeType = true;
1859             FinishTemplatesContext(context);
1860          }
1861       }
1862
1863       if(method && member.initializer && member.initializer.type == expInitializer && member.initializer.exp)
1864       {
1865          ProcessExpressionType(member.initializer.exp);
1866          if(!member.initializer.exp.expType)
1867          {
1868             if(inCompiler)
1869             {
1870                char expString[10240];
1871                expString[0] = '\0';
1872                PrintExpression(member.initializer.exp, expString);
1873                ChangeCh(expString, '\n', ' ');
1874                Compiler_Error($"unresolved symbol used as an instance method %s\n", expString);
1875             }
1876          }
1877          //else if(!MatchTypes(member.exp.expType, type, null, _class, null, true, true, false, false))
1878          else if(!MatchTypes(member.initializer.exp.expType, type, null, null, _class, true, true, false, false))
1879          {
1880             Compiler_Error($"incompatible instance method %s\n", ident.string);
1881          }
1882       }
1883       else if(member.initializer)
1884       {
1885          /*
1886          FreeType(member.exp.destType);
1887          member.exp.destType = type;
1888          if(member.exp.destType)
1889             member.exp.destType.refCount++;
1890          ProcessExpressionType(member.exp);
1891          */
1892
1893          ProcessInitializer(member.initializer, type);
1894       }
1895       if(freeType) FreeType(type);
1896    }
1897    else
1898    {
1899       if(_class && _class.type == unitClass)
1900       {
1901          if(member.initializer)
1902          {
1903             /*
1904             FreeType(member.exp.destType);
1905             member.exp.destType = MkClassType(_class.fullName);
1906             ProcessExpressionType(member.initializer, type);
1907             */
1908             Type type = MkClassType(_class.fullName);
1909             ProcessInitializer(member.initializer, type);
1910             FreeType(type);
1911          }
1912       }
1913       else
1914       {
1915          if(member.initializer)
1916          {
1917             //ProcessExpressionType(member.exp);
1918             ProcessInitializer(member.initializer, null);
1919          }
1920          if(ident)
1921          {
1922             if(method)
1923             {
1924                Compiler_Error($"couldn't find virtual method %s in class %s\n", ident.string, _class.fullName);
1925             }
1926             else if(_class)
1927             {
1928                Compiler_Error($"couldn't find member %s in class %s\n", ident.string, _class.fullName);
1929                if(inCompiler)
1930                   eClass_AddDataMember(_class, ident.string, "int", 0, 0, publicAccess);
1931             }
1932          }
1933          else if(_class)
1934             Compiler_Error($"too many initializers for instantiation of class %s\n", _class.fullName);
1935       }
1936    }
1937 }
1938
1939 void ProcessInstantiationType(Instantiation inst)
1940 {
1941    yylloc = inst.loc;
1942    if(inst._class)
1943    {
1944       MembersInit members;
1945       Symbol classSym; // = inst._class.symbol; // FindClass(inst._class.name);
1946       Class _class;
1947
1948       /*if(!inst._class.symbol)
1949          inst._class.symbol = FindClass(inst._class.name);*/
1950       classSym = inst._class.symbol;
1951       _class = classSym ? classSym.registered : null;
1952
1953       // DANGER: Patch for mutex not declaring its struct when not needed
1954       if(!_class || _class.type != noHeadClass)
1955          DeclareStruct(inst._class.name, false); //_class && _class.type == noHeadClass);
1956
1957       afterExternal = afterExternal ? afterExternal : curExternal;
1958
1959       if(inst.exp)
1960          ProcessExpressionType(inst.exp);
1961
1962       inst.isConstant = true;
1963       if(inst.members)
1964       {
1965          DataMember curMember = null;
1966          Class curClass = null;
1967          DataMember subMemberStack[256];
1968          int subMemberStackPos = 0;
1969
1970          for(members = inst.members->first; members; members = members.next)
1971          {
1972             switch(members.type)
1973             {
1974                case methodMembersInit:
1975                {
1976                   char name[1024];
1977                   static uint instMethodID = 0;
1978                   External external = curExternal;
1979                   Context context = curContext;
1980                   Declarator declarator = members.function.declarator;
1981                   Identifier nameID = GetDeclId(declarator);
1982                   char * unmangled = nameID ? nameID.string : null;
1983                   Expression exp;
1984                   External createdExternal = null;
1985
1986                   if(inCompiler)
1987                   {
1988                      char number[16];
1989                      //members.function.dontMangle = true;
1990                      strcpy(name, "__ecereInstMeth_");
1991                      FullClassNameCat(name, _class ? _class.fullName : "_UNKNOWNCLASS", false);
1992                      strcat(name, "_");
1993                      strcat(name, nameID.string);
1994                      strcat(name, "_");
1995                      sprintf(number, "_%08d", instMethodID++);
1996                      strcat(name, number);
1997                      nameID.string = CopyString(name);
1998                   }
1999
2000                   // Do modifications here...
2001                   if(declarator)
2002                   {
2003                      Symbol symbol = declarator.symbol;
2004                      Method method = eClass_FindMethod(_class, unmangled, privateModule);
2005
2006                      if(method && method.type == virtualMethod)
2007                      {
2008                         symbol.method = method;
2009                         ProcessMethodType(method);
2010
2011                         if(!symbol.type.thisClass)
2012                         {
2013                            if(method.dataType.thisClass && currentClass &&
2014                               eClass_IsDerived(currentClass, method.dataType.thisClass.registered))
2015                            {
2016                               if(!currentClass.symbol)
2017                                  currentClass.symbol = FindClass(currentClass.fullName);
2018                               symbol.type.thisClass = currentClass.symbol;
2019                            }
2020                            else
2021                            {
2022                               if(!_class.symbol)
2023                                  _class.symbol = FindClass(_class.fullName);
2024                               symbol.type.thisClass = _class.symbol;
2025                            }
2026                         }
2027                         // TESTING THIS HERE:
2028                         DeclareType(symbol.type, true, true);
2029
2030                      }
2031                      else if(classSym)
2032                      {
2033                         Compiler_Error($"couldn't find virtual method %s in class %s\n",
2034                            unmangled, classSym.string);
2035                      }
2036                   }
2037
2038                   //declarator.symbol.id = declarator.symbol.idCode = curExternal.symbol.idCode;
2039                   createdExternal = ProcessClassFunction(classSym ? classSym.registered : null, members.function, ast, afterExternal, true);
2040
2041                   if(nameID)
2042                   {
2043                      FreeSpecifier(nameID._class);
2044                      nameID._class = null;
2045                   }
2046
2047                   if(inCompiler)
2048                   {
2049
2050                      Type type = declarator.symbol.type;
2051                      External oldExternal = curExternal;
2052
2053                      // *** Commented this out... Any negative impact? Yes: makes double prototypes declarations... Why was it commented out?
2054                      // *** It was commented out for problems such as
2055                      /*
2056                            class VirtualDesktop : Window
2057                            {
2058                               clientSize = Size { };
2059                               Timer timer
2060                               {
2061                                  bool DelayExpired()
2062                                  {
2063                                     clientSize.w;
2064                                     return true;
2065                                  }
2066                               };
2067                            }
2068                      */
2069                      // Commented Out: Good for bet.ec in Poker (Otherwise: obj\bet.c:187: error: `currentBet' undeclared (first use in this function))
2070
2071                      declarator.symbol.id = declarator.symbol.idCode = curExternal.symbol.idCode;
2072
2073                      /*
2074                      if(strcmp(declarator.symbol.string, name))
2075                      {
2076                         printf("TOCHECK: Look out for this\n");
2077                         delete declarator.symbol.string;
2078                         declarator.symbol.string = CopyString(name);
2079                      }
2080
2081                      if(!declarator.symbol.parent && globalContext.symbols.root != (BTNode)declarator.symbol)
2082                      {
2083                         printf("TOCHECK: Will this ever be in a list? Yes.\n");
2084                         excludedSymbols->Remove(declarator.symbol);
2085                         globalContext.symbols.Add((BTNode)declarator.symbol);
2086                         if(strstr(declarator.symbol.string), "::")
2087                            globalContext.hasNameSpace = true;
2088
2089                      }
2090                      */
2091
2092                      //curExternal = curExternal.prev;
2093                      //afterExternal = afterExternal->next;
2094
2095                      //ProcessFunction(afterExternal->function);
2096
2097                      //curExternal = afterExternal;
2098                      {
2099                         External externalDecl;
2100                         externalDecl = MkExternalDeclaration(null);
2101                         ast->Insert(oldExternal.prev, externalDecl);
2102
2103                         // Which function does this process?
2104                         if(createdExternal.function)
2105                         {
2106                            ProcessFunction(createdExternal.function);
2107
2108                            //curExternal = oldExternal;
2109
2110                            {
2111                               //Declaration decl = MkDeclaration(members.function.specifiers, MkListOne(MkInitDeclarator(CopyDeclarator(declarator), null)));
2112
2113                               Declaration decl = MkDeclaration(CopyList(createdExternal.function.specifiers, CopySpecifier),
2114                                  MkListOne(MkInitDeclarator(CopyDeclarator(declarator), null)));
2115
2116                               //externalDecl = MkExternalDeclaration(decl);
2117
2118                               //***** ast->Insert(external.prev, externalDecl);
2119                               //ast->Insert(curExternal.prev, externalDecl);
2120                               externalDecl.declaration = decl;
2121                               if(decl.symbol && !decl.symbol.pointerExternal)
2122                                  decl.symbol.pointerExternal = externalDecl;
2123
2124                               // Trying this out...
2125                               declarator.symbol.pointerExternal = externalDecl;
2126                            }
2127                         }
2128                      }
2129                   }
2130                   else if(declarator)
2131                   {
2132                      curExternal = declarator.symbol.pointerExternal;
2133                      ProcessFunction((FunctionDefinition)members.function);
2134                   }
2135                   curExternal = external;
2136                   curContext = context;
2137
2138                   if(inCompiler)
2139                   {
2140                      FreeClassFunction(members.function);
2141
2142                      // In this pass, turn this into a MemberInitData
2143                      exp = QMkExpId(name);
2144                      members.type = dataMembersInit;
2145                      members.dataMembers = MkListOne(MkMemberInit(MkListOne(MkIdentifier(unmangled)), MkInitializerAssignment(exp)));
2146
2147                      delete unmangled;
2148                   }
2149                   break;
2150                }
2151                case dataMembersInit:
2152                {
2153                   if(members.dataMembers && classSym)
2154                   {
2155                      MemberInit member;
2156                      Location oldyyloc = yylloc;
2157                      for(member = members.dataMembers->first; member; member = member.next)
2158                      {
2159                         ProcessMemberInitData(member, classSym.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
2160                         if(member.initializer && !member.initializer.isConstant)
2161                            inst.isConstant = false;
2162                      }
2163                      yylloc = oldyyloc;
2164                   }
2165                   break;
2166                }
2167             }
2168          }
2169       }
2170    }
2171 }
2172
2173 static void DeclareType(Type type, bool declarePointers, bool declareParams)
2174 {
2175    // OPTIMIZATIONS: TESTING THIS...
2176    if(inCompiler)
2177    {
2178       if(type.kind == functionType)
2179       {
2180          Type param;
2181          if(declareParams)
2182          {
2183             for(param = type.params.first; param; param = param.next)
2184                DeclareType(param, declarePointers, true);
2185          }
2186          DeclareType(type.returnType, declarePointers, true);
2187       }
2188       else if(type.kind == pointerType && declarePointers)
2189          DeclareType(type.type, declarePointers, false);
2190       else if(type.kind == classType)
2191       {
2192          if(type._class.registered && (type._class.registered.type == structClass || type._class.registered.type == noHeadClass) && !type._class.declaring)
2193             DeclareStruct(type._class.registered.fullName, type._class.registered.type == noHeadClass);
2194       }
2195       else if(type.kind == structType || type.kind == unionType)
2196       {
2197          Type member;
2198          for(member = type.members.first; member; member = member.next)
2199             DeclareType(member, false, false);
2200       }
2201       else if(type.kind == arrayType)
2202          DeclareType(type.arrayType, declarePointers, false);
2203    }
2204 }
2205
2206 ClassTemplateArgument * FindTemplateArg(Class _class, TemplateParameter param)
2207 {
2208    ClassTemplateArgument * arg = null;
2209    int id = 0;
2210    ClassTemplateParameter curParam = null;
2211    Class sClass;
2212    for(sClass = _class; sClass; sClass = sClass.base)
2213    {
2214       id = 0;
2215       if(sClass.templateClass) sClass = sClass.templateClass;
2216       for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
2217       {
2218          if(curParam.type == TemplateParameterType::type && !strcmp(param.identifier.string, curParam.name))
2219          {
2220             for(sClass = sClass.base; sClass; sClass = sClass.base)
2221             {
2222                if(sClass.templateClass) sClass = sClass.templateClass;
2223                id += sClass.templateParams.count;
2224             }
2225             break;
2226          }
2227          id++;
2228       }
2229       if(curParam) break;
2230    }
2231    if(curParam)
2232    {
2233       arg = &_class.templateArgs[id];
2234       if(arg && param.type == type)
2235          arg->dataTypeClass = eSystem_FindClass(_class.module, arg->dataTypeString);
2236    }
2237    return arg;
2238 }
2239
2240 public Context SetupTemplatesContext(Class _class)
2241 {
2242    Context context = PushContext();
2243    context.templateTypesOnly = true;
2244    if(_class.symbol && ((Symbol)_class.symbol).templateParams)
2245    {
2246       TemplateParameter param = ((Symbol)_class.symbol).templateParams->first;
2247       for(; param; param = param.next)
2248       {
2249          if(param.type == type && param.identifier)
2250          {
2251             TemplatedType type { key = (uintptr)param.identifier.string, param = param };
2252             curContext.templateTypes.Add((BTNode)type);
2253          }
2254       }
2255    }
2256    else if(_class)
2257    {
2258       Class sClass;
2259       for(sClass = _class; sClass; sClass = sClass.base)
2260       {
2261          ClassTemplateParameter p;
2262          for(p = sClass.templateParams.first; p; p = p.next)
2263          {
2264             //OldList * specs = MkList();
2265             //Declarator decl = null;
2266             //decl = SpecDeclFromString(p.dataTypeString, specs, null);
2267             if(p.type == type)
2268             {
2269                TemplateParameter param = p.param;
2270                TemplatedType type;
2271                if(!param)
2272                {
2273                   // ADD DATA TYPE HERE...
2274                   p.param = param = TemplateParameter
2275                   {
2276                      identifier = MkIdentifier(p.name), type = p.type,
2277                      dataTypeString = p.dataTypeString /*, dataType = { specs, decl }*/
2278                   };
2279                }
2280                type = TemplatedType { key = (uintptr)p.name, param = param };
2281                curContext.templateTypes.Add((BTNode)type);
2282             }
2283          }
2284       }
2285    }
2286    return context;
2287 }
2288
2289 public void FinishTemplatesContext(Context context)
2290 {
2291    PopContext(context);
2292    FreeContext(context);
2293    delete context;
2294 }
2295
2296 public void ProcessMethodType(Method method)
2297 {
2298    if(!method.dataType)
2299    {
2300       Context context = SetupTemplatesContext(method._class);
2301
2302       method.dataType = ProcessTypeString(method.dataTypeString, false);
2303
2304       FinishTemplatesContext(context);
2305
2306       if(method.type != virtualMethod && method.dataType)
2307       {
2308          if(!method.dataType.thisClass && !method.dataType.staticMethod)
2309          {
2310             if(!method._class.symbol)
2311                method._class.symbol = FindClass(method._class.fullName);
2312             method.dataType.thisClass = method._class.symbol;
2313          }
2314       }
2315
2316       // Why was this commented out? Working fine without now...
2317
2318       /*
2319       if(method.dataType.kind == functionType && !method.dataType.staticMethod && !method.dataType.thisClass)
2320          method.dataType.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2321          */
2322    }
2323
2324    /*
2325    if(type)
2326    {
2327       char * par = strstr(type, "(");
2328       char * classOp = null;
2329       int classOpLen = 0;
2330       if(par)
2331       {
2332          int c;
2333          for(c = par-type-1; c >= 0; c++)
2334          {
2335             if(type[c] == ':' && type[c+1] == ':')
2336             {
2337                classOp = type + c - 1;
2338                for(c = c-1; c >=0 && !isspace(type[c]); c--)
2339                {
2340                   classOp--;
2341                   classOpLen++;
2342                }
2343                break;
2344             }
2345             else if(!isspace(type[c]))
2346                break;
2347          }
2348       }
2349       if(classOp)
2350       {
2351          char temp[1024];
2352          int typeLen = strlen(type);
2353          memcpy(temp, classOp, classOpLen);
2354          temp[classOpLen] = '\0';
2355          if(temp[0])
2356             _class = eSystem_FindClass(module, temp);
2357          else
2358             _class = null;
2359          method.dataTypeString = new char[typeLen - classOpLen + 1];
2360          memcpy(method.dataTypeString, type, classOp - type);
2361          memcpy(method.dataTypeString + (classOp - type), classOp + classOpLen, typeLen - (classOp - type + classOpLen));
2362       }
2363       else
2364          method.dataTypeString = type;
2365    }
2366    */
2367 }
2368
2369
2370 public void ProcessPropertyType(Property prop)
2371 {
2372    if(!prop.dataType)
2373    {
2374       Context context = SetupTemplatesContext(prop._class);
2375       prop.dataType = ProcessTypeString(prop.dataTypeString, false);
2376       FinishTemplatesContext(context);
2377    }
2378 }
2379
2380 public void DeclareMethod(Method method, char * name)
2381 {
2382    Symbol symbol = method.symbol;
2383    if(!symbol || (!symbol.pointerExternal && method.type == virtualMethod) || symbol.id > (curExternal ? curExternal.symbol.idCode : -1))
2384    {
2385       bool imported = false;
2386       bool dllImport = false;
2387
2388       if(!method.dataType)
2389          method.dataType = ProcessTypeString(method.dataTypeString, false);
2390
2391       if(!symbol || symbol._import || method.type == virtualMethod)
2392       {
2393          if(!symbol || method.type == virtualMethod)
2394          {
2395             Symbol classSym;
2396             if(!method._class.symbol)
2397                method._class.symbol = FindClass(method._class.fullName);
2398             classSym = method._class.symbol;
2399             if(!classSym._import)
2400             {
2401                ModuleImport module;
2402
2403                if(method._class.module && method._class.module.name)
2404                   module = FindModule(method._class.module);
2405                else
2406                   module = mainModule;
2407                classSym._import = ClassImport
2408                {
2409                   name = CopyString(method._class.fullName);
2410                   isRemote = method._class.isRemote;
2411                };
2412                module.classes.Add(classSym._import);
2413             }
2414             if(!symbol)
2415             {
2416                symbol = method.symbol = Symbol { };
2417             }
2418             if(!symbol._import)
2419             {
2420                symbol._import = (ClassImport)MethodImport
2421                {
2422                   name = CopyString(method.name);
2423                   isVirtual = method.type == virtualMethod;
2424                };
2425                classSym._import.methods.Add(symbol._import);
2426             }
2427             if(!symbol)
2428             {
2429                // Set the symbol type
2430                /*
2431                if(!type.thisClass)
2432                {
2433                   type.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2434                }
2435                else if(type.thisClass == (void *)-1)
2436                {
2437                   type.thisClass = null;
2438                }
2439                */
2440                // symbol.type = ProcessTypeString(method.dataTypeString, false);
2441                symbol.type = method.dataType;
2442                if(symbol.type) symbol.type.refCount++;
2443             }
2444             /*
2445             if(!method.thisClass || strcmp(method.thisClass, "void"))
2446                symbol.type.params.Insert(null,
2447                   MkClassType(method.thisClass ? method.thisClass : method._class.fullName));
2448             */
2449          }
2450          if(!method.dataType.dllExport)
2451          {
2452             imported = true;
2453             if((method._class.module != privateModule || !strcmp(method._class.name, "float") || !strcmp(method._class.name, "double")) && method._class.module.importType != staticImport)
2454                dllImport = true;
2455          }
2456       }
2457
2458       /* MOVING THIS UP
2459       if(!method.dataType)
2460          method.dataType = ((Symbol)method.symbol).type;
2461          //ProcessMethodType(method);
2462       */
2463
2464       if(method.type != virtualMethod && method.dataType)
2465          DeclareType(method.dataType, true, true);
2466
2467       if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2468       {
2469          // We need a declaration here :)
2470          Declaration decl;
2471          OldList * specifiers, * declarators;
2472          Declarator d;
2473          Declarator funcDecl;
2474          External external;
2475
2476          specifiers = MkList();
2477          declarators = MkList();
2478
2479          //if(imported)
2480          if(dllImport)
2481             ListAdd(specifiers, MkSpecifier(EXTERN));
2482          else if(method._class.symbol && ((Symbol)method._class.symbol).isStatic)
2483             ListAdd(specifiers, MkSpecifier(STATIC));
2484
2485          if(method.type == virtualMethod)
2486          {
2487             ListAdd(specifiers, MkSpecifier(INT));
2488             d = MkDeclaratorIdentifier(MkIdentifier(name));
2489          }
2490          else
2491          {
2492             d = MkDeclaratorIdentifier(MkIdentifier(name));
2493             //if(imported)
2494             if(dllImport)
2495                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2496             {
2497                Context context = SetupTemplatesContext(method._class);
2498                d = SpecDeclFromString(method.dataTypeString, specifiers, d);
2499                FinishTemplatesContext(context);
2500             }
2501             funcDecl = GetFuncDecl(d);
2502
2503             if(dllImport)
2504             {
2505                Specifier spec, next;
2506                for(spec = specifiers->first; spec; spec = next)
2507                {
2508                   next = spec.next;
2509                   if(spec.type == extendedSpecifier)
2510                   {
2511                      specifiers->Remove(spec);
2512                      FreeSpecifier(spec);
2513                   }
2514                }
2515             }
2516
2517             // Add this parameter if not a static method
2518             if(method.dataType && !method.dataType.staticMethod)
2519             {
2520                if(funcDecl && funcDecl.function.parameters && funcDecl.function.parameters->count)
2521                {
2522                   Class _class = method.dataType.thisClass ? method.dataType.thisClass.registered : method._class;
2523                   TypeName thisParam = MkTypeName(MkListOne(
2524                      MkSpecifierName/*MkClassName*/(method.dataType.thisClass ? method.dataType.thisClass.string : method._class.fullName)),
2525                      (_class && _class.type == systemClass) ? MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("this"))) : MkDeclaratorIdentifier(MkIdentifier("this")));
2526                   TypeName firstParam = ((TypeName)funcDecl.function.parameters->first);
2527                   Specifier firstSpec = firstParam.qualifiers ? firstParam.qualifiers->first : null;
2528
2529                   if(firstSpec && firstSpec.type == baseSpecifier && firstSpec.specifier == VOID && !firstParam.declarator)
2530                   {
2531                      TypeName param = funcDecl.function.parameters->first;
2532                      funcDecl.function.parameters->Remove(param);
2533                      FreeTypeName(param);
2534                   }
2535
2536                   if(!funcDecl.function.parameters)
2537                      funcDecl.function.parameters = MkList();
2538                   funcDecl.function.parameters->Insert(null, thisParam);
2539                }
2540             }
2541             // Make sure we don't have empty parameter declarations for static methods...
2542             /*
2543             else if(!funcDecl.function.parameters)
2544             {
2545                funcDecl.function.parameters = MkList();
2546                funcDecl.function.parameters->Insert(null,
2547                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2548             }*/
2549          }
2550          // TESTING THIS:
2551          ProcessDeclarator(d);
2552
2553          ListAdd(declarators, MkInitDeclarator(d, null));
2554
2555          decl = MkDeclaration(specifiers, declarators);
2556
2557          ReplaceThisClassSpecifiers(specifiers, method._class);
2558
2559          // Keep a different symbol for the function definition than the declaration...
2560          if(symbol.pointerExternal)
2561          {
2562             Symbol functionSymbol { };
2563
2564             // Copy symbol
2565             {
2566                *functionSymbol = *symbol;
2567                functionSymbol.string = CopyString(symbol.string);
2568                if(functionSymbol.type)
2569                   functionSymbol.type.refCount++;
2570             }
2571
2572             excludedSymbols->Add(functionSymbol);
2573             symbol.pointerExternal.symbol = functionSymbol;
2574          }
2575          external = MkExternalDeclaration(decl);
2576          if(curExternal)
2577             ast->Insert(curExternal ? curExternal.prev : null, external);
2578          external.symbol = symbol;
2579          symbol.pointerExternal = external;
2580       }
2581       else if(ast)
2582       {
2583          // Move declaration higher...
2584          ast->Move(symbol.pointerExternal, curExternal.prev);
2585       }
2586
2587       symbol.id = curExternal ? curExternal.symbol.idCode : MAXINT;
2588    }
2589 }
2590
2591 char * ReplaceThisClass(Class _class)
2592 {
2593    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2594    {
2595       bool first = true;
2596       int p = 0;
2597       ClassTemplateParameter param;
2598       int lastParam = -1;
2599
2600       char className[1024];
2601       strcpy(className, _class.fullName);
2602       for(param = _class.templateParams.first; param; param = param.next)
2603       {
2604          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2605          {
2606             if(first) strcat(className, "<");
2607             if(!first) strcat(className, ", ");
2608             if(lastParam + 1 != p)
2609             {
2610                strcat(className, param.name);
2611                strcat(className, " = ");
2612             }
2613             strcat(className, param.name);
2614             first = false;
2615             lastParam = p;
2616          }
2617          p++;
2618       }
2619       if(!first)
2620       {
2621          int len = strlen(className);
2622          if(className[len-1] == '>') className[len++] = ' ';
2623          className[len++] = '>';
2624          className[len++] = '\0';
2625       }
2626       return CopyString(className);
2627    }
2628    else
2629       return CopyString(_class.fullName);
2630 }
2631
2632 Type ReplaceThisClassType(Class _class)
2633 {
2634    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2635    {
2636       bool first = true;
2637       int p = 0;
2638       ClassTemplateParameter param;
2639       int lastParam = -1;
2640       char className[1024];
2641       strcpy(className, _class.fullName);
2642
2643       for(param = _class.templateParams.first; param; param = param.next)
2644       {
2645          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2646          {
2647             if(first) strcat(className, "<");
2648             if(!first) strcat(className, ", ");
2649             if(lastParam + 1 != p)
2650             {
2651                strcat(className, param.name);
2652                strcat(className, " = ");
2653             }
2654             strcat(className, param.name);
2655             first = false;
2656             lastParam = p;
2657          }
2658          p++;
2659       }
2660       if(!first)
2661       {
2662          int len = strlen(className);
2663          if(className[len-1] == '>') className[len++] = ' ';
2664          className[len++] = '>';
2665          className[len++] = '\0';
2666       }
2667       return MkClassType(className);
2668       //return ProcessTypeString(className, false);
2669    }
2670    else
2671    {
2672       return MkClassType(_class.fullName);
2673       //return ProcessTypeString(_class.fullName, false);
2674    }
2675 }
2676
2677 void ReplaceThisClassSpecifiers(OldList specs, Class _class)
2678 {
2679    if(specs != null && _class)
2680    {
2681       Specifier spec;
2682       for(spec = specs.first; spec; spec = spec.next)
2683       {
2684          if(spec.type == baseSpecifier && spec.specifier == THISCLASS)
2685          {
2686             spec.type = nameSpecifier;
2687             spec.name = ReplaceThisClass(_class);
2688             spec.symbol = FindClass(spec.name); //_class.symbol;
2689          }
2690       }
2691    }
2692 }
2693
2694 // Returns imported or not
2695 bool DeclareFunction(GlobalFunction function, char * name)
2696 {
2697    Symbol symbol = function.symbol;
2698    if(curExternal && (!symbol || symbol.id > curExternal.symbol.idCode))
2699    {
2700       bool imported = false;
2701       bool dllImport = false;
2702
2703       if(!function.dataType)
2704       {
2705          function.dataType = ProcessTypeString(function.dataTypeString, false);
2706          if(!function.dataType.thisClass)
2707             function.dataType.staticMethod = true;
2708       }
2709
2710       if(inCompiler)
2711       {
2712          if(!symbol)
2713          {
2714             ModuleImport module = FindModule(function.module);
2715             // WARNING: This is not added anywhere...
2716             symbol = function.symbol = Symbol {  };
2717
2718             if(module.name)
2719             {
2720                if(!function.dataType.dllExport)
2721                {
2722                   symbol._import = (ClassImport)FunctionImport { name = CopyString(function.name) };
2723                   module.functions.Add(symbol._import);
2724                }
2725             }
2726             // Set the symbol type
2727             {
2728                symbol.type = ProcessTypeString(function.dataTypeString, false);
2729                if(!symbol.type.thisClass)
2730                   symbol.type.staticMethod = true;
2731             }
2732          }
2733          imported = symbol._import ? true : false;
2734          if(imported && function.module != privateModule && function.module.importType != staticImport)
2735             dllImport = true;
2736       }
2737
2738       DeclareType(function.dataType, true, true);
2739
2740       if(inCompiler)
2741       {
2742          if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2743          {
2744             // We need a declaration here :)
2745             Declaration decl;
2746             OldList * specifiers, * declarators;
2747             Declarator d;
2748             Declarator funcDecl;
2749             External external;
2750
2751             specifiers = MkList();
2752             declarators = MkList();
2753
2754             //if(imported)
2755                ListAdd(specifiers, MkSpecifier(EXTERN));
2756             /*
2757             else
2758                ListAdd(specifiers, MkSpecifier(STATIC));
2759             */
2760
2761             d = MkDeclaratorIdentifier(MkIdentifier(imported ? name : function.name));
2762             //if(imported)
2763             if(dllImport)
2764                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2765
2766             d = SpecDeclFromString(function.dataTypeString, specifiers, d);
2767             // TAKE OUT THE DLL EXPORT IF STATICALLY IMPORTED:
2768             if(function.module.importType == staticImport)
2769             {
2770                Specifier spec;
2771                for(spec = specifiers->first; spec; spec = spec.next)
2772                   if(spec.type == extendedSpecifier && spec.extDecl && spec.extDecl.type == extDeclString && !strcmp(spec.extDecl.s, "dllexport"))
2773                   {
2774                      specifiers->Remove(spec);
2775                      FreeSpecifier(spec);
2776                      break;
2777                   }
2778             }
2779
2780             funcDecl = GetFuncDecl(d);
2781
2782             // Make sure we don't have empty parameter declarations for static methods...
2783             if(funcDecl && !funcDecl.function.parameters)
2784             {
2785                funcDecl.function.parameters = MkList();
2786                funcDecl.function.parameters->Insert(null,
2787                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2788             }
2789
2790             ListAdd(declarators, MkInitDeclarator(d, null));
2791
2792             {
2793                Context oldCtx = curContext;
2794                curContext = globalContext;
2795                decl = MkDeclaration(specifiers, declarators);
2796                curContext = oldCtx;
2797             }
2798
2799             // Keep a different symbol for the function definition than the declaration...
2800             if(symbol.pointerExternal)
2801             {
2802                Symbol functionSymbol { };
2803                // Copy symbol
2804                {
2805                   *functionSymbol = *symbol;
2806                   functionSymbol.string = CopyString(symbol.string);
2807                   if(functionSymbol.type)
2808                      functionSymbol.type.refCount++;
2809                }
2810
2811                excludedSymbols->Add(functionSymbol);
2812
2813                symbol.pointerExternal.symbol = functionSymbol;
2814             }
2815             external = MkExternalDeclaration(decl);
2816             if(curExternal)
2817                ast->Insert(curExternal.prev, external);
2818             external.symbol = symbol;
2819             symbol.pointerExternal = external;
2820          }
2821          else
2822          {
2823             // Move declaration higher...
2824             ast->Move(symbol.pointerExternal, curExternal.prev);
2825          }
2826
2827          if(curExternal)
2828             symbol.id = curExternal.symbol.idCode;
2829       }
2830    }
2831    return (symbol && symbol._import && function.module != privateModule && function.module.importType != staticImport) ? true : false;
2832 }
2833
2834 void DeclareGlobalData(GlobalData data)
2835 {
2836    Symbol symbol = data.symbol;
2837    if(curExternal && (!symbol || symbol.id > curExternal.symbol.idCode))
2838    {
2839       if(inCompiler)
2840       {
2841          if(!symbol)
2842             symbol = data.symbol = Symbol { };
2843       }
2844       if(!data.dataType)
2845          data.dataType = ProcessTypeString(data.dataTypeString, false);
2846       DeclareType(data.dataType, true, true);
2847       if(inCompiler)
2848       {
2849          if(!symbol.pointerExternal)
2850          {
2851             // We need a declaration here :)
2852             Declaration decl;
2853             OldList * specifiers, * declarators;
2854             Declarator d;
2855             External external;
2856
2857             specifiers = MkList();
2858             declarators = MkList();
2859
2860             ListAdd(specifiers, MkSpecifier(EXTERN));
2861             d = MkDeclaratorIdentifier(MkIdentifier(data.fullName));
2862             d = SpecDeclFromString(data.dataTypeString, specifiers, d);
2863
2864             ListAdd(declarators, MkInitDeclarator(d, null));
2865
2866             decl = MkDeclaration(specifiers, declarators);
2867             external = MkExternalDeclaration(decl);
2868             if(curExternal)
2869                ast->Insert(curExternal.prev, external);
2870             external.symbol = symbol;
2871             symbol.pointerExternal = external;
2872          }
2873          else
2874          {
2875             // Move declaration higher...
2876             ast->Move(symbol.pointerExternal, curExternal.prev);
2877          }
2878
2879          if(curExternal)
2880             symbol.id = curExternal.symbol.idCode;
2881       }
2882    }
2883 }
2884
2885 class Conversion : struct
2886 {
2887    Conversion prev, next;
2888    Property convert;
2889    bool isGet;
2890    Type resultType;
2891 };
2892
2893 public bool MatchTypes(Type source, Type dest, OldList conversions, Class owningClassSource, Class owningClassDest, bool doConversion, bool enumBaseType, bool acceptReversedParams, bool isConversionExploration)
2894 {
2895    if(source && dest)
2896    {
2897       // Property convert;
2898
2899       if(source.kind == templateType && dest.kind != templateType)
2900       {
2901          Type type = ProcessTemplateParameterType(source.templateParameter);
2902          if(type) source = type;
2903       }
2904
2905       if(dest.kind == templateType && source.kind != templateType)
2906       {
2907          Type type = ProcessTemplateParameterType(dest.templateParameter);
2908          if(type) dest = type;
2909       }
2910
2911       if(dest.classObjectType == typedObject)
2912       {
2913          if(source.classObjectType != anyObject)
2914             return true;
2915          else
2916          {
2917             // If either the source or the destination defines the class, accepts any_object as compatible for a typed_object
2918             if((dest._class && strcmp(dest._class.string, "class")) || (source._class && strcmp(source._class.string, "class")))
2919             {
2920                return true;
2921             }
2922          }
2923       }
2924       else
2925       {
2926          if(source.classObjectType == anyObject)
2927             return true;
2928          if(dest.classObjectType == anyObject && source.classObjectType != typedObject)
2929             return true;
2930       }
2931
2932       if((dest.kind == structType && source.kind == structType) ||
2933          (dest.kind == unionType && source.kind == unionType))
2934       {
2935          if((dest.enumName && source.enumName && !strcmp(dest.enumName, source.enumName)) ||
2936              (source.members.first && source.members.first == dest.members.first))
2937             return true;
2938       }
2939
2940       if(dest.kind == ellipsisType && source.kind != voidType)
2941          return true;
2942
2943       if(dest.kind == pointerType && dest.type.kind == voidType &&
2944          ((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))
2945          || source.kind == subClassType || source.kind == pointerType || source.kind == arrayType || source.kind == functionType || source.kind == thisClassType)
2946
2947          /*source.kind != voidType && source.kind != structType && source.kind != unionType  */
2948
2949          /*&& (source.kind != classType /-*|| source._class.registered.type != structClass)*/)
2950          return true;
2951       if(!isConversionExploration && source.kind == pointerType && source.type.kind == voidType &&
2952          ((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))
2953          || dest.kind == subClassType || dest.kind == pointerType || dest.kind == arrayType || dest.kind == functionType || dest.kind == thisClassType)
2954
2955          /* dest.kind != voidType && dest.kind != structType && dest.kind != unionType  */
2956
2957          /*&& (dest.kind != classType || dest._class.registered.type != structClass)*/)
2958          return true;
2959
2960       if(((source.kind == classType && dest.kind == classType) || (source.kind == subClassType && dest.kind == subClassType)) && source._class)
2961       {
2962          if(source._class.registered && source._class.registered.type == unitClass)
2963          {
2964             if(conversions != null)
2965             {
2966                if(source._class.registered == dest._class.registered)
2967                   return true;
2968             }
2969             else
2970             {
2971                Class sourceBase, destBase;
2972                for(sourceBase = source._class.registered; sourceBase && sourceBase.base.type != systemClass; sourceBase = sourceBase.base);
2973                for(destBase = dest._class.registered; destBase && destBase.base.type != systemClass; destBase = destBase.base);
2974                if(sourceBase == destBase)
2975                   return true;
2976             }
2977          }
2978          // Don't match enum inheriting from other enum if resolving enumeration values
2979          // TESTING: !dest.classObjectType
2980          else if(source._class && dest._class && (dest.classObjectType == source.classObjectType || !dest.classObjectType) &&
2981             (enumBaseType ||
2982                (!source._class.registered || source._class.registered.type != enumClass) ||
2983                (!dest._class.registered || dest._class.registered.type != enumClass)) && eClass_IsDerived(source._class.registered, dest._class.registered))
2984             return true;
2985          else
2986          {
2987             // Added this so that DefinedColor = Color doesn't go through ColorRGB property
2988             if(enumBaseType &&
2989                dest._class && dest._class.registered && dest._class.registered.type == enumClass &&
2990                ((source._class && source._class.registered && source._class.registered.type != enumClass) || source.kind == classType)) // Added this here for a base enum to be acceptable for a derived enum (#139)
2991             {
2992                if(eClass_IsDerived(dest._class.registered, source._class.registered))
2993                {
2994                   return true;
2995                }
2996             }
2997          }
2998       }
2999
3000       // JUST ADDED THIS...
3001       if(source.kind == subClassType && dest.kind == classType && dest._class && !strcmp(dest._class.string, "ecere::com::Class"))
3002          return true;
3003
3004       if(doConversion)
3005       {
3006          // Just added this for Straight conversion of ColorAlpha => Color
3007          if(source.kind == classType)
3008          {
3009             Class _class;
3010             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3011             {
3012                Property convert;
3013                for(convert = _class.conversions.first; convert; convert = convert.next)
3014                {
3015                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3016                   {
3017                      Conversion after = (conversions != null) ? conversions.last : null;
3018
3019                      if(!convert.dataType)
3020                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3021                      if(MatchTypes(convert.dataType, dest, conversions, null, null, false, true, false, true))
3022                      {
3023                         if(!conversions && !convert.Get)
3024                            return true;
3025                         else if(conversions != null)
3026                         {
3027                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3028                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3029                               (dest.kind != classType || dest._class.registered != _class.base))
3030                               return true;
3031                            else
3032                            {
3033                               Conversion conv { convert = convert, isGet = true };
3034                               // conversions.Add(conv);
3035                               conversions.Insert(after, conv);
3036                               return true;
3037                            }
3038                         }
3039                      }
3040                   }
3041                }
3042             }
3043          }
3044
3045          // MOVING THIS??
3046
3047          if(dest.kind == classType)
3048          {
3049             Class _class;
3050             for(_class = dest._class ? dest._class.registered : null; _class; _class = _class.base)
3051             {
3052                Property convert;
3053                for(convert = _class.conversions.first; convert; convert = convert.next)
3054                {
3055                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3056                   {
3057                      // Conversion after = (conversions != null) ? conversions.last : null;
3058
3059                      if(!convert.dataType)
3060                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3061                      // Just added this equality check to prevent recursion.... Make it safer?
3062                      // Changed enumBaseType to false here to prevent all int-compatible enums to show up in AnchorValues
3063                      if(convert.dataType != dest && MatchTypes(source, convert.dataType, conversions, null, null, true, false /*true*/, false, true))
3064                      {
3065                         if(!conversions && !convert.Set)
3066                            return true;
3067                         else if(conversions != null)
3068                         {
3069                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3070                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3071                               (source.kind != classType || source._class.registered != _class.base))
3072                               return true;
3073                            else
3074                            {
3075                               // *** Testing this! ***
3076                               Conversion conv { convert = convert };
3077                               conversions.Add(conv);
3078                               //conversions.Insert(after, conv);
3079                               return true;
3080                            }
3081                         }
3082                      }
3083                   }
3084                }
3085             }
3086             /*if(dest._class.registered && !strcmp(dest._class.registered.name, "bool"))
3087             {
3088                if(source.kind != voidType && source.kind != structType && source.kind != unionType &&
3089                   (source.kind != classType || source._class.registered.type != structClass))
3090                   return true;
3091             }*/
3092
3093             // TESTING THIS... IS THIS OK??
3094             if(enumBaseType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3095             {
3096                if(!dest._class.registered.dataType)
3097                   dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3098                // Only support this for classes...
3099                if(dest._class.registered.dataType.kind == classType || source.truth || dest.truth/* ||
3100                   !strcmp(dest._class.registered.name, "bool") || (source.kind == classType && !strcmp(source._class.string, "bool"))*/)
3101                {
3102                   if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false))
3103                   {
3104                      return true;
3105                   }
3106                }
3107             }
3108          }
3109
3110          // Moved this lower
3111          if(source.kind == classType)
3112          {
3113             Class _class;
3114             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3115             {
3116                Property convert;
3117                for(convert = _class.conversions.first; convert; convert = convert.next)
3118                {
3119                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3120                   {
3121                      Conversion after = (conversions != null) ? conversions.last : null;
3122
3123                      if(!convert.dataType)
3124                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3125                      if(convert.dataType != source && MatchTypes(convert.dataType, dest, conversions, null, null, true, true, false, true))
3126                      {
3127                         if(!conversions && !convert.Get)
3128                            return true;
3129                         else if(conversions != null)
3130                         {
3131                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3132                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3133                               (dest.kind != classType || dest._class.registered != _class.base))
3134                               return true;
3135                            else
3136                            {
3137                               Conversion conv { convert = convert, isGet = true };
3138
3139                               // conversions.Add(conv);
3140                               conversions.Insert(after, conv);
3141                               return true;
3142                            }
3143                         }
3144                      }
3145                   }
3146                }
3147             }
3148
3149             // TESTING THIS... IS THIS OK??
3150             if(enumBaseType && source._class && source._class.registered && source._class.registered.type == enumClass)
3151             {
3152                if(!source._class.registered.dataType)
3153                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3154                if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, true, false, false))
3155                {
3156                   return true;
3157                }
3158             }
3159          }
3160       }
3161
3162       if(source.kind == classType || source.kind == subClassType)
3163          ;
3164       else if(dest.kind == source.kind &&
3165          (dest.kind != structType && dest.kind != unionType &&
3166           dest.kind != functionType && dest.kind != arrayType && dest.kind != pointerType && dest.kind != methodType))
3167           return true;
3168       // RECENTLY ADDED THESE
3169       else if(dest.kind == doubleType && source.kind == floatType)
3170          return true;
3171       else if(dest.kind == shortType && (source.kind == charType || source.kind == _BoolType))
3172          return true;
3173       else if(dest.kind == intType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intSizeType /* Exception here for size_t */))
3174          return true;
3175       else if(dest.kind == int64Type && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intPtrType || source.kind == intSizeType))
3176          return true;
3177       else if(dest.kind == intPtrType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intSizeType || source.kind == int64Type))
3178          return true;
3179       else if(dest.kind == intSizeType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == int64Type || source.kind == intPtrType))
3180          return true;
3181       else if(source.kind == enumType &&
3182          (dest.kind == intType || dest.kind == shortType || dest.kind == charType || source.kind == _BoolType || dest.kind == longType || dest.kind == int64Type || dest.kind == intPtrType || dest.kind == intSizeType))
3183           return true;
3184       else if(dest.kind == enumType &&
3185          (source.kind == intType || source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == longType || source.kind == int64Type || source.kind == intPtrType || source.kind == intSizeType))
3186           return true;
3187       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) &&
3188               ((source.kind == functionType || (source.kind == pointerType && source.type.kind == functionType) || source.kind == methodType)))
3189       {
3190          Type paramSource, paramDest;
3191
3192          if(dest.kind == methodType)
3193             owningClassDest = dest.methodClass ? dest.methodClass : dest.method._class;
3194          if(source.kind == methodType)
3195             owningClassSource = source.methodClass ? source.methodClass : source.method._class;
3196
3197          if(dest.kind == pointerType && dest.type.kind == functionType) dest = dest.type;
3198          if(source.kind == pointerType && source.type.kind == functionType) source = source.type;
3199          if(dest.kind == methodType)
3200             dest = dest.method.dataType;
3201          if(source.kind == methodType)
3202             source = source.method.dataType;
3203
3204          paramSource = source.params.first;
3205          if(paramSource && paramSource.kind == voidType) paramSource = null;
3206          paramDest = dest.params.first;
3207          if(paramDest && paramDest.kind == voidType) paramDest = null;
3208
3209
3210          if((dest.staticMethod || (!dest.thisClass && !owningClassDest)) &&
3211             !(source.staticMethod || (!source.thisClass && !owningClassSource)))
3212          {
3213             // Source thisClass must be derived from destination thisClass
3214             if(!paramDest || (!(paramDest.kind == pointerType && paramDest.type && paramDest.type.kind == voidType) && (paramDest.kind != classType ||
3215                !eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource,paramDest._class.registered))))
3216             {
3217                if(paramDest && paramDest.kind == classType)
3218                   Compiler_Error($"method class must be derived from %s\n", paramDest._class.string);
3219                else
3220                   Compiler_Error($"method class should not take an object\n");
3221                return false;
3222             }
3223             paramDest = paramDest.next;
3224          }
3225          else if(!dest.staticMethod && (dest.thisClass || owningClassDest))
3226          {
3227             if((source.staticMethod || (!source.thisClass && !owningClassSource)))
3228             {
3229                if(dest.thisClass)
3230                {
3231                   if(!paramSource || paramSource.kind != classType || !eClass_IsDerived(paramSource._class.registered,dest.thisClass.registered))
3232                   {
3233                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3234                      return false;
3235                   }
3236                }
3237                else
3238                {
3239                   // THIS WAS BACKWARDS:
3240                   // if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(owningClassDest, paramSource._class.registered)))
3241                   if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(paramSource._class.registered, owningClassDest)))
3242                   {
3243                      if(owningClassDest)
3244                        Compiler_Error($"%s expected to be derived from method class\n", owningClassDest.fullName);
3245                      else
3246                         Compiler_Error($"overriding class expected to be derived from method class\n");
3247                      return false;
3248                   }
3249                }
3250                paramSource = paramSource.next;
3251             }
3252             else
3253             {
3254                if(dest.thisClass)
3255                {
3256                   // Source thisClass must be derived from destination thisClass
3257                   if(!eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource, dest.thisClass.registered))
3258                   {
3259                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3260                      return false;
3261                   }
3262                }
3263                else
3264                {
3265                   // THIS WAS BACKWARDS TOO??
3266                   // if(source.thisClass && owningClassDest && !eClass_IsDerived(owningClassDest, source.thisClass.registered))
3267                   if(source.thisClass && source.thisClass.registered && owningClassDest && !eClass_IsDerived(source.thisClass.registered, owningClassDest))
3268                   {
3269                      //if(owningClass)
3270                         Compiler_Error($"%s expected to be derived from method class\n", /*owningClass.name*/ source.thisClass.registered.fullName);
3271                      //else
3272                         //Compiler_Error($"overriding class expected to be derived from method class\n");
3273                      return false;
3274                   }
3275                }
3276             }
3277          }
3278
3279
3280          // Source return type must be derived from destination return type
3281          if(!MatchTypes(source.returnType, dest.returnType, null, null, null, true, true, false, false))
3282          {
3283             Compiler_Warning($"incompatible return type for function\n");
3284             return false;
3285          }
3286
3287          // Check parameters
3288
3289          for(; paramDest; paramDest = paramDest.next)
3290          {
3291             if(!paramSource)
3292             {
3293                //Compiler_Warning($"not enough parameters\n");
3294                Compiler_Error($"not enough parameters\n");
3295                return false;
3296             }
3297             {
3298                Type paramDestType = paramDest;
3299                Type paramSourceType = paramSource;
3300                Type type = paramDestType;
3301
3302                // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
3303                if(paramDest.kind == templateType && paramDest.templateParameter.type == TemplateParameterType::type && owningClassSource &&
3304                   paramSource.kind != templateType)
3305                {
3306                   int id = 0;
3307                   ClassTemplateParameter curParam = null;
3308                   Class sClass;
3309                   for(sClass = owningClassSource; sClass; sClass = sClass.base)
3310                   {
3311                      id = 0;
3312                      if(sClass.templateClass) sClass = sClass.templateClass;
3313                      for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
3314                      {
3315                         if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
3316                         {
3317                            for(sClass = sClass.base; sClass; sClass = sClass.base)
3318                            {
3319                               if(sClass.templateClass) sClass = sClass.templateClass;
3320                               id += sClass.templateParams.count;
3321                            }
3322                            break;
3323                         }
3324                         id++;
3325                      }
3326                      if(curParam) break;
3327                   }
3328
3329                   if(curParam)
3330                   {
3331                      ClassTemplateArgument arg = owningClassSource.templateArgs[id];
3332                      paramDestType = type = ProcessTypeString(arg.dataTypeString, false);
3333                   }
3334                }
3335
3336                // paramDest must be derived from paramSource
3337                if(!MatchTypes(paramDestType, paramSourceType, null, null, null, true, true, false, false) &&
3338                   (!acceptReversedParams || !MatchTypes(paramSourceType, paramDestType, null, null, null, true, true, false, false)))
3339                {
3340                   char type[1024];
3341                   type[0] = 0;
3342                   PrintType(paramDest, type, false, true);
3343                   Compiler_Warning($"incompatible parameter %s (expected %s)\n", paramSource.name, type);
3344
3345                   if(paramDestType != paramDest)
3346                      FreeType(paramDestType);
3347                   return false;
3348                }
3349                if(paramDestType != paramDest)
3350                   FreeType(paramDestType);
3351             }
3352
3353             paramSource = paramSource.next;
3354          }
3355          if(paramSource)
3356          {
3357             Compiler_Error($"too many parameters\n");
3358             return false;
3359          }
3360          return true;
3361       }
3362       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) && (source.kind == pointerType && source.type.kind == voidType))
3363       {
3364          return true;
3365       }
3366       else if((dest.kind == pointerType || dest.kind == arrayType) &&
3367          (source.kind == arrayType || source.kind == pointerType))
3368       {
3369          if(MatchTypes(source.type, dest.type, null, null, null, true, true, false, false))
3370             return true;
3371       }
3372    }
3373    return false;
3374 }
3375
3376 static void FreeConvert(Conversion convert)
3377 {
3378    if(convert.resultType)
3379       FreeType(convert.resultType);
3380 }
3381
3382 bool MatchWithEnums_NameSpace(NameSpace nameSpace, Expression sourceExp, Type dest,
3383                               char * string, OldList conversions)
3384 {
3385    BTNamedLink link;
3386
3387    for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
3388    {
3389       Class _class = link.data;
3390       if(_class.type == enumClass)
3391       {
3392          OldList converts { };
3393          Type type { };
3394          type.kind = classType;
3395
3396          if(!_class.symbol)
3397             _class.symbol = FindClass(_class.fullName);
3398          type._class = _class.symbol;
3399
3400          if(MatchTypes(type, dest, &converts, null, null, true, false, false, false))
3401          {
3402             NamedLink value;
3403             Class enumClass = eSystem_FindClass(privateModule, "enum");
3404             if(enumClass)
3405             {
3406                Class baseClass;
3407                for(baseClass = _class ; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
3408                {
3409                   EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
3410                   for(value = e.values.first; value; value = value.next)
3411                   {
3412                      if(!strcmp(value.name, string))
3413                         break;
3414                   }
3415                   if(value)
3416                   {
3417                      FreeExpContents(sourceExp);
3418                      FreeType(sourceExp.expType);
3419
3420                      sourceExp.isConstant = true;
3421                      sourceExp.expType = MkClassType(baseClass.fullName);
3422                      //if(inCompiler)
3423                      {
3424                         char constant[256];
3425                         sourceExp.type = constantExp;
3426                         if(!strcmp(baseClass.dataTypeString, "int"))
3427                            sprintf(constant, "%d",(int)value.data);
3428                         else
3429                            sprintf(constant, "0x%X",(int)value.data);
3430                         sourceExp.constant = CopyString(constant);
3431                         //for(;baseClass.base && baseClass.base.type != systemClass; baseClass = baseClass.base);
3432                      }
3433
3434                      while(converts.first)
3435                      {
3436                         Conversion convert = converts.first;
3437                         converts.Remove(convert);
3438                         conversions.Add(convert);
3439                      }
3440                      delete type;
3441                      return true;
3442                   }
3443                }
3444             }
3445          }
3446          if(converts.first)
3447             converts.Free(FreeConvert);
3448          delete type;
3449       }
3450    }
3451    for(nameSpace = (NameSpace *)nameSpace.nameSpaces.first; nameSpace != null; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
3452       if(MatchWithEnums_NameSpace(nameSpace, sourceExp, dest, string, conversions))
3453          return true;
3454    return false;
3455 }
3456
3457 public bool ModuleVisibility(Module searchIn, Module searchFor)
3458 {
3459    SubModule subModule;
3460
3461    if(searchFor == searchIn)
3462       return true;
3463
3464    for(subModule = searchIn.modules.first; subModule; subModule = subModule.next)
3465    {
3466       if(subModule.importMode == publicAccess || searchIn == searchIn.application)
3467       {
3468          if(ModuleVisibility(subModule.module, searchFor))
3469             return true;
3470       }
3471    }
3472    return false;
3473 }
3474
3475 bool MatchWithEnums_Module(Module mainModule, Expression sourceExp, Type dest, char * string, OldList conversions)
3476 {
3477    Module module;
3478
3479    if(MatchWithEnums_NameSpace(mainModule.application.systemNameSpace, sourceExp, dest, string, conversions))
3480       return true;
3481    if(MatchWithEnums_NameSpace(mainModule.application.privateNameSpace, sourceExp, dest, string, conversions))
3482       return true;
3483    if(MatchWithEnums_NameSpace(mainModule.application.publicNameSpace, sourceExp, dest, string, conversions))
3484       return true;
3485
3486    for(module = mainModule.application.allModules.first; module; module = module.next)
3487    {
3488       if(ModuleVisibility(mainModule, module) && MatchWithEnums_NameSpace(module.publicNameSpace, sourceExp, dest, string, conversions))
3489          return true;
3490    }
3491    return false;
3492 }
3493
3494 bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, bool skipUnitBla)
3495 {
3496    Type source = sourceExp.expType;
3497    Type realDest = dest;
3498    Type backupSourceExpType = null;
3499
3500    if(dest.kind == pointerType && sourceExp.type == constantExp && !strtoul(sourceExp.constant, null, 0))
3501       return true;
3502
3503    if(!skipUnitBla && source && dest && source.kind == classType && dest.kind == classType)
3504    {
3505        if(source._class && source._class.registered && source._class.registered.type == unitClass)
3506        {
3507           Class sourceBase, destBase;
3508           for(sourceBase = source._class.registered;
3509               sourceBase && sourceBase.base && sourceBase.base.type != systemClass;
3510               sourceBase = sourceBase.base);
3511           for(destBase = dest._class.registered;
3512               destBase && destBase.base && destBase.base.type != systemClass;
3513               destBase = destBase.base);
3514           //if(source._class.registered == dest._class.registered)
3515           if(sourceBase == destBase)
3516              return true;
3517        }
3518    }
3519
3520    if(source)
3521    {
3522       OldList * specs;
3523       bool flag = false;
3524       int64 value = MAXINT;
3525
3526       source.refCount++;
3527       dest.refCount++;
3528
3529       if(sourceExp.type == constantExp)
3530       {
3531          if(source.isSigned)
3532             value = strtoll(sourceExp.constant, null, 0);
3533          else
3534             value = strtoull(sourceExp.constant, null, 0);
3535       }
3536       else if(sourceExp.type == opExp && sourceExp.op.op == '-' && !sourceExp.op.exp1 && sourceExp.op.exp2 && sourceExp.op.exp2.type == constantExp)
3537       {
3538          if(source.isSigned)
3539             value = -strtoll(sourceExp.op.exp2.constant, null, 0);
3540          else
3541             value = -strtoull(sourceExp.op.exp2.constant, null, 0);
3542       }
3543
3544       if(dest.kind != classType && source.kind == classType && source._class && source._class.registered &&
3545          !strcmp(source._class.registered.fullName, "ecere::com::unichar"))
3546       {
3547          FreeType(source);
3548          source = Type { kind = intType, isSigned = false, refCount = 1 };
3549       }
3550
3551       if(dest.kind == classType)
3552       {
3553          Class _class = dest._class ? dest._class.registered : null;
3554
3555          if(_class && _class.type == unitClass)
3556          {
3557             if(source.kind != classType)
3558             {
3559                Type tempType { };
3560                Type tempDest, tempSource;
3561
3562                for(; _class.base.type != systemClass; _class = _class.base);
3563                tempSource = dest;
3564                tempDest = tempType;
3565
3566                tempType.kind = classType;
3567                if(!_class.symbol)
3568                   _class.symbol = FindClass(_class.fullName);
3569
3570                tempType._class = _class.symbol;
3571                tempType.truth = dest.truth;
3572                if(tempType._class)
3573                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false);
3574
3575                // NOTE: To handle bad warnings on int64 vs 32 bit eda::Id incompatibilities
3576                backupSourceExpType = sourceExp.expType;
3577                sourceExp.expType = dest; dest.refCount++;
3578                //sourceExp.expType = MkClassType(_class.fullName);
3579                flag = true;
3580
3581                delete tempType;
3582             }
3583          }
3584
3585
3586          // Why wasn't there something like this?
3587          if(_class && _class.type == bitClass && source.kind != classType)
3588          {
3589             if(!dest._class.registered.dataType)
3590                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3591             if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false))
3592             {
3593                FreeType(source);
3594                FreeType(sourceExp.expType);
3595                source = sourceExp.expType = MkClassType(dest._class.string);
3596                source.refCount++;
3597
3598                //source.kind = classType;
3599                //source._class = dest._class;
3600             }
3601          }
3602
3603          // Adding two enumerations
3604          /*
3605          if(_class && _class.type == enumClass && source.kind == classType && source._class && source._class.registered && source._class.registered.type == enumClass)
3606          {
3607             if(!source._class.registered.dataType)
3608                source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3609             if(!dest._class.registered.dataType)
3610                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3611
3612             if(MatchTypes(source._class.registered.dataType, dest._class.registered.dataType, conversions, null, null, true, false, false))
3613             {
3614                FreeType(source);
3615                source = sourceExp.expType = MkClassType(dest._class.string);
3616                source.refCount++;
3617
3618                //source.kind = classType;
3619                //source._class = dest._class;
3620             }
3621          }*/
3622
3623          if(_class && !strcmp(_class.fullName, "ecere::com::Class") && source.kind == pointerType && source.type && source.type.kind == charType && sourceExp.type == stringExp)
3624          {
3625             OldList * specs = MkList();
3626             Declarator decl;
3627             char string[1024];
3628
3629             ReadString(string, sourceExp.string);
3630             decl = SpecDeclFromString(string, specs, null);
3631
3632             FreeExpContents(sourceExp);
3633             FreeType(sourceExp.expType);
3634
3635             sourceExp.type = classExp;
3636             sourceExp._classExp.specifiers = specs;
3637             sourceExp._classExp.decl = decl;
3638             sourceExp.expType = dest;
3639             dest.refCount++;
3640
3641             FreeType(source);
3642             FreeType(dest);
3643             if(backupSourceExpType) FreeType(backupSourceExpType);
3644             return true;
3645          }
3646       }
3647       else if(source.kind == classType)
3648       {
3649          Class _class = source._class ? source._class.registered : null;
3650
3651          if(_class && (_class.type == unitClass || !strcmp(_class.fullName, "bool") || /*_class.type == enumClass || */_class.type == bitClass ))  // TOCHECK: enumClass, bitClass is new here...
3652          {
3653             /*
3654             if(dest.kind != classType)
3655             {
3656                // Testing this simpler piece of code... (Broke Units Conversion to no unit Logic)
3657                if(!source._class.registered.dataType)
3658                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3659
3660                FreeType(dest);
3661                dest = MkClassType(source._class.string);
3662                //if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, false, false))
3663                //   dest = MkClassType(source._class.string);
3664             }
3665             */
3666
3667             if(dest.kind != classType)
3668             {
3669                Type tempType { };
3670                Type tempDest, tempSource;
3671
3672                if(!source._class.registered.dataType)
3673                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3674
3675                for(; _class.base.type != systemClass; _class = _class.base);
3676                tempDest = source;
3677                tempSource = tempType;
3678                tempType.kind = classType;
3679                tempType._class = FindClass(_class.fullName);
3680                tempType.truth = source.truth;
3681                tempType.classObjectType = source.classObjectType;
3682
3683                if(tempType._class)
3684                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false);
3685
3686                // PUT THIS BACK TESTING UNITS?
3687                if(conversions.last)
3688                {
3689                   ((Conversion)(conversions.last)).resultType = dest;
3690                   dest.refCount++;
3691                }
3692
3693                FreeType(sourceExp.expType);
3694                sourceExp.expType = MkClassType(_class.fullName);
3695                sourceExp.expType.truth = source.truth;
3696                sourceExp.expType.classObjectType = source.classObjectType;
3697
3698                // *** This if was commented out, put it back because "int a =^ Destroy()" shows up bool enum values in autocomplete ***
3699
3700                if(!sourceExp.destType)
3701                {
3702                   FreeType(sourceExp.destType);
3703                   sourceExp.destType = sourceExp.expType;
3704                   if(sourceExp.expType)
3705                      sourceExp.expType.refCount++;
3706                }
3707                //flag = true;
3708                //source = _class.dataType;
3709
3710
3711                // TOCHECK: TESTING THIS NEW CODE
3712                if(!_class.dataType)
3713                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3714                FreeType(dest);
3715                dest = MkClassType(source._class.string);
3716                dest.truth = source.truth;
3717                dest.classObjectType = source.classObjectType;
3718
3719                FreeType(source);
3720                source = _class.dataType;
3721                source.refCount++;
3722
3723                delete tempType;
3724             }
3725          }
3726       }
3727
3728       if(!flag)
3729       {
3730          if(MatchTypes(source, dest, conversions, null, null, true, true, false, false))
3731          {
3732             FreeType(source);
3733             FreeType(dest);
3734             return true;
3735          }
3736       }
3737
3738       // Implicit Casts
3739       /*
3740       if(source.kind == classType)
3741       {
3742          Class _class = source._class.registered;
3743          if(_class.type == unitClass)
3744          {
3745             if(!_class.dataType)
3746                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3747             source = _class.dataType;
3748          }
3749       }*/
3750
3751       if(dest.kind == classType)
3752       {
3753          Class _class = dest._class ? dest._class.registered : null;
3754          if(_class && !dest.truth && (_class.type == unitClass || !strcmp(_class.fullName, "bool") ||
3755             (/*_class.type == enumClass*/_class.type != structClass && !value && source.kind == intType) || _class.type == bitClass))   // TOCHECK: enumClass, bitClass is new here...
3756          {
3757             if(_class.type == normalClass || _class.type == noHeadClass)
3758             {
3759                Expression newExp { };
3760                *newExp = *sourceExp;
3761                if(sourceExp.destType) sourceExp.destType.refCount++;
3762                if(sourceExp.expType)  sourceExp.expType.refCount++;
3763                sourceExp.type = castExp;
3764                sourceExp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
3765                sourceExp.cast.exp = newExp;
3766                FreeType(sourceExp.expType);
3767                sourceExp.expType = null;
3768                ProcessExpressionType(sourceExp);
3769
3770                // In Debugger, this helps with addresses (e.g. null pointers) that end up casted to a void *: keeps a classType instead of a pointerType
3771                if(!inCompiler)
3772                {
3773                   FreeType(sourceExp.expType);
3774                   sourceExp.expType = dest;
3775                }
3776
3777                FreeType(source);
3778                if(inCompiler) FreeType(dest);
3779
3780                if(backupSourceExpType) FreeType(backupSourceExpType);
3781                return true;
3782             }
3783
3784             if(!_class.dataType)
3785                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3786             FreeType(dest);
3787             dest = _class.dataType;
3788             dest.refCount++;
3789          }
3790
3791          // Accept lower precision types for units, since we want to keep the unit type
3792          if(dest.kind == doubleType &&
3793             (source.kind == doubleType || source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType ||
3794              source.kind == charType || source.kind == _BoolType))
3795          {
3796             specs = MkListOne(MkSpecifier(DOUBLE));
3797          }
3798          else if(dest.kind == floatType &&
3799             (source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3800             source.kind == _BoolType || source.kind == doubleType))
3801          {
3802             specs = MkListOne(MkSpecifier(FLOAT));
3803          }
3804          else if(dest.kind == int64Type && (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3805             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3806          {
3807             specs = MkList();
3808             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3809             ListAdd(specs, MkSpecifier(INT64));
3810          }
3811          else if(dest.kind == intType && (source.kind == intType || source.kind == shortType || source.kind == charType ||
3812             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3813          {
3814             specs = MkList();
3815             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3816             ListAdd(specs, MkSpecifier(INT));
3817          }
3818          else if(dest.kind == shortType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType ||
3819             source.kind == floatType || source.kind == doubleType))
3820          {
3821             specs = MkList();
3822             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3823             ListAdd(specs, MkSpecifier(SHORT));
3824          }
3825          else if(dest.kind == charType && (source.kind == charType || source.kind == _BoolType || source.kind == shortType || source.kind == intType ||
3826             source.kind == floatType || source.kind == doubleType))
3827          {
3828             specs = MkList();
3829             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3830             ListAdd(specs, MkSpecifier(CHAR));
3831          }
3832          else
3833          {
3834             FreeType(source);
3835             FreeType(dest);
3836             if(backupSourceExpType)
3837             {
3838                // Failed to convert: revert previous exp type
3839                if(sourceExp.expType) FreeType(sourceExp.expType);
3840                sourceExp.expType = backupSourceExpType;
3841             }
3842             return false;
3843          }
3844       }
3845       else if(dest.kind == doubleType &&
3846          (source.kind == doubleType || source.kind == floatType || source.kind == int64Type || source.kind == intType || source.kind == enumType || source.kind == shortType ||
3847           source.kind == _BoolType || source.kind == charType))
3848       {
3849          specs = MkListOne(MkSpecifier(DOUBLE));
3850       }
3851       else if(dest.kind == floatType &&
3852          (source.kind == floatType || source.kind == enumType || source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3853       {
3854          specs = MkListOne(MkSpecifier(FLOAT));
3855       }
3856       else if(dest.kind == _BoolType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3857          (value == 1 || value == 0))
3858       {
3859          specs = MkList();
3860          ListAdd(specs, MkSpecifier(BOOL));
3861       }
3862       else if(dest.kind == charType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3863          (dest.isSigned ? (value >= -128 && value <= 127) : (value >= 0 && value <= 255)))
3864       {
3865          specs = MkList();
3866          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3867          ListAdd(specs, MkSpecifier(CHAR));
3868       }
3869       else if(dest.kind == shortType && (source.kind == enumType || source.kind == _BoolType || source.kind == charType || source.kind == shortType ||
3870          (source.kind == intType && (dest.isSigned ? (value >= -32768 && value <= 32767) : (value >= 0 && value <= 65535)))))
3871       {
3872          specs = MkList();
3873          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3874          ListAdd(specs, MkSpecifier(SHORT));
3875       }
3876       else if(dest.kind == intType && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType))
3877       {
3878          specs = MkList();
3879          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3880          ListAdd(specs, MkSpecifier(INT));
3881       }
3882       else if(dest.kind == int64Type && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType || source.kind == int64Type))
3883       {
3884          specs = MkList();
3885          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3886          ListAdd(specs, MkSpecifier(INT64));
3887       }
3888       else if(dest.kind == enumType &&
3889          (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3890       {
3891          specs = MkListOne(MkEnum(MkIdentifier(dest.enumName), null));
3892       }
3893       else
3894       {
3895          FreeType(source);
3896          FreeType(dest);
3897          if(backupSourceExpType)
3898          {
3899             // Failed to convert: revert previous exp type
3900             if(sourceExp.expType) FreeType(sourceExp.expType);
3901             sourceExp.expType = backupSourceExpType;
3902          }
3903          return false;
3904       }
3905
3906       if(!flag)
3907       {
3908          Expression newExp { };
3909          *newExp = *sourceExp;
3910          newExp.prev = null;
3911          newExp.next = null;
3912          if(sourceExp.destType) sourceExp.destType.refCount++;
3913          if(sourceExp.expType)  sourceExp.expType.refCount++;
3914
3915          sourceExp.type = castExp;
3916          if(realDest.kind == classType)
3917          {
3918             sourceExp.cast.typeName = QMkClass(realDest._class.string, null);
3919             FreeList(specs, FreeSpecifier);
3920          }
3921          else
3922             sourceExp.cast.typeName = MkTypeName(specs, null);
3923          if(newExp.type == opExp)
3924          {
3925             sourceExp.cast.exp = MkExpBrackets(MkListOne(newExp));
3926          }
3927          else
3928             sourceExp.cast.exp = newExp;
3929
3930          FreeType(sourceExp.expType);
3931          sourceExp.expType = null;
3932          ProcessExpressionType(sourceExp);
3933       }
3934       else
3935          FreeList(specs, FreeSpecifier);
3936
3937       FreeType(dest);
3938       FreeType(source);
3939       if(backupSourceExpType) FreeType(backupSourceExpType);
3940
3941       return true;
3942    }
3943    else
3944    {
3945       while((sourceExp.type == bracketsExp || sourceExp.type == extensionExpressionExp) && sourceExp.list) sourceExp = sourceExp.list->last;
3946       if(sourceExp.type == identifierExp)
3947       {
3948          Identifier id = sourceExp.identifier;
3949          if(dest.kind == classType)
3950          {
3951             if(dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3952             {
3953                Class _class = dest._class.registered;
3954                Class enumClass = eSystem_FindClass(privateModule, "enum");
3955                if(enumClass)
3956                {
3957                   for( ; _class && _class.type == ClassType::enumClass; _class = _class.base)
3958                   {
3959                      NamedLink value;
3960                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
3961                      for(value = e.values.first; value; value = value.next)
3962                      {
3963                         if(!strcmp(value.name, id.string))
3964                            break;
3965                      }
3966                      if(value)
3967                      {
3968                         FreeExpContents(sourceExp);
3969                         FreeType(sourceExp.expType);
3970
3971                         sourceExp.isConstant = true;
3972                         sourceExp.expType = MkClassType(_class.fullName);
3973                         //if(inCompiler)
3974                         {
3975                            char constant[256];
3976                            sourceExp.type = constantExp;
3977                            if(/*_class && */_class.dataTypeString && !strcmp(_class.dataTypeString, "int")) // _class cannot be null here!
3978                               sprintf(constant, "%d", (int) value.data);
3979                            else
3980                               sprintf(constant, "0x%X", (int) value.data);
3981                            sourceExp.constant = CopyString(constant);
3982                            //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
3983                         }
3984                         return true;
3985                      }
3986                   }
3987                }
3988             }
3989          }
3990
3991          // Loop through all enum classes
3992          if(dest.classObjectType != typedObject && dest.kind == classType /*!= ellipsisType */&& MatchWithEnums_Module(privateModule, sourceExp, dest, id.string, conversions))
3993             return true;
3994       }
3995    }
3996    return false;
3997 }
3998
3999 #define TERTIARY(o, name, m, t, p) \
4000    static bool name(Expression exp, Operand op1, Operand op2, Operand op3)   \
4001    {                                                              \
4002       exp.type = constantExp;                                    \
4003       exp.string = p(op1.m ? op2.m : op3.m);                     \
4004       if(!exp.expType) \
4005          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4006       return true;                                                \
4007    }
4008
4009 #define BINARY(o, name, m, t, p) \
4010    static bool name(Expression exp, Operand op1, Operand op2)   \
4011    {                                                              \
4012       t value2 = op2.m;                                           \
4013       exp.type = constantExp;                                    \
4014       exp.string = p(op1.m o value2);                     \
4015       if(!exp.expType) \
4016          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4017       return true;                                                \
4018    }
4019
4020 #define BINARY_DIVIDEINT(o, name, m, t, p) \
4021    static bool name(Expression exp, Operand op1, Operand op2)   \
4022    {                                                              \
4023       t value2 = op2.m;                                           \
4024       exp.type = constantExp;                                    \
4025       exp.string = p(value2 ? (op1.m o value2) : 0);             \
4026       if(!exp.expType) \
4027          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4028       return true;                                                \
4029    }
4030
4031 #define BINARY_DIVIDEREAL(o, name, m, t, p) \
4032    static bool name(Expression exp, Operand op1, Operand op2)   \
4033    {                                                              \
4034       t value2 = op2.m;                                           \
4035       exp.type = constantExp;                                    \
4036       exp.string = p(op1.m o value2);             \
4037       if(!exp.expType) \
4038          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4039       return true;                                                \
4040    }
4041
4042 #define UNARY(o, name, m, t, p) \
4043    static bool name(Expression exp, Operand op1)                \
4044    {                                                              \
4045       exp.type = constantExp;                                    \
4046       exp.string = p((t)(o op1.m));                                   \
4047       if(!exp.expType) \
4048          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4049       return true;                                                \
4050    }
4051
4052 #define OPERATOR_ALL(macro, o, name) \
4053    macro(o, Int##name, i, int, PrintInt) \
4054    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4055    macro(o, Int64##name, i64, int64, PrintInt64) \
4056    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4057    macro(o, Short##name, s, short, PrintShort) \
4058    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4059    macro(o, Char##name, c, char, PrintChar) \
4060    macro(o, UChar##name, uc, unsigned char, PrintUChar) \
4061    macro(o, Float##name, f, float, PrintFloat) \
4062    macro(o, Double##name, d, double, PrintDouble)
4063
4064 #define OPERATOR_INTTYPES(macro, o, name) \
4065    macro(o, Int##name, i, int, PrintInt) \
4066    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4067    macro(o, Int64##name, i64, int64, PrintInt64) \
4068    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4069    macro(o, Short##name, s, short, PrintShort) \
4070    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4071    macro(o, Char##name, c, char, PrintChar) \
4072    macro(o, UChar##name, uc, unsigned char, PrintUChar)
4073
4074 #define OPERATOR_REALTYPES(macro, o, name) \
4075    macro(o, Float##name, f, float, PrintFloat) \
4076    macro(o, Double##name, d, double, PrintDouble)
4077
4078 // binary arithmetic
4079 OPERATOR_ALL(BINARY, +, Add)
4080 OPERATOR_ALL(BINARY, -, Sub)
4081 OPERATOR_ALL(BINARY, *, Mul)
4082 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /, Div)
4083 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /, Div)
4084 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %, Mod)
4085
4086 // unary arithmetic
4087 OPERATOR_ALL(UNARY, -, Neg)
4088
4089 // unary arithmetic increment and decrement
4090 OPERATOR_ALL(UNARY, ++, Inc)
4091 OPERATOR_ALL(UNARY, --, Dec)
4092
4093 // binary arithmetic assignment
4094 OPERATOR_ALL(BINARY, =, Asign)
4095 OPERATOR_ALL(BINARY, +=, AddAsign)
4096 OPERATOR_ALL(BINARY, -=, SubAsign)
4097 OPERATOR_ALL(BINARY, *=, MulAsign)
4098 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /=, DivAsign)
4099 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /=, DivAsign)
4100 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %=, ModAsign)
4101
4102 // binary bitwise
4103 OPERATOR_INTTYPES(BINARY, &, BitAnd)
4104 OPERATOR_INTTYPES(BINARY, |, BitOr)
4105 OPERATOR_INTTYPES(BINARY, ^, BitXor)
4106 OPERATOR_INTTYPES(BINARY, <<, LShift)
4107 OPERATOR_INTTYPES(BINARY, >>, RShift)
4108
4109 // unary bitwise
4110 OPERATOR_INTTYPES(UNARY, ~, BitNot)
4111
4112 // binary bitwise assignment
4113 OPERATOR_INTTYPES(BINARY, &=, AndAsign)
4114 OPERATOR_INTTYPES(BINARY, |=, OrAsign)
4115 OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
4116 OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
4117 OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
4118
4119 // unary logical negation
4120 OPERATOR_INTTYPES(UNARY, !, Not)
4121
4122 // binary logical equality
4123 OPERATOR_ALL(BINARY, ==, Equ)
4124 OPERATOR_ALL(BINARY, !=, Nqu)
4125
4126 // binary logical
4127 OPERATOR_ALL(BINARY, &&, And)
4128 OPERATOR_ALL(BINARY, ||, Or)
4129
4130 // binary logical relational
4131 OPERATOR_ALL(BINARY, >, Grt)
4132 OPERATOR_ALL(BINARY, <, Sma)
4133 OPERATOR_ALL(BINARY, >=, GrtEqu)
4134 OPERATOR_ALL(BINARY, <=, SmaEqu)
4135
4136 // tertiary condition operator
4137 OPERATOR_ALL(TERTIARY, ?, Cond)
4138
4139 //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
4140 #define OPERATOR_TABLE_ALL(name, type) \
4141     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, type##Mod, \
4142                           type##Neg, \
4143                           type##Inc, type##Dec, \
4144                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, type##ModAsign, \
4145                           type##BitAnd, type##BitOr, type##BitXor, type##LShift, type##RShift, \
4146                           type##BitNot, \
4147                           type##AndAsign, type##OrAsign, type##XorAsign, type##LShiftAsign, type##RShiftAsign, \
4148                           type##Not, \
4149                           type##Equ, type##Nqu, \
4150                           type##And, type##Or, \
4151                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu, type##Cond \
4152                         }; \
4153
4154 #define OPERATOR_TABLE_INTTYPES(name, type) \
4155     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, null, \
4156                           type##Neg, \
4157                           type##Inc, type##Dec, \
4158                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, null, \
4159                           null, null, null, null, null, \
4160                           null, \
4161                           null, null, null, null, null, \
4162                           null, \
4163                           type##Equ, type##Nqu, \
4164                           type##And, type##Or, \
4165                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu \
4166                         }; \
4167
4168 OPERATOR_TABLE_ALL(int, Int)
4169 OPERATOR_TABLE_ALL(uint, UInt)
4170 OPERATOR_TABLE_ALL(int64, Int64)
4171 OPERATOR_TABLE_ALL(uint64, UInt64)
4172 OPERATOR_TABLE_ALL(short, Short)
4173 OPERATOR_TABLE_ALL(ushort, UShort)
4174 OPERATOR_TABLE_INTTYPES(float, Float)
4175 OPERATOR_TABLE_INTTYPES(double, Double)
4176 OPERATOR_TABLE_ALL(char, Char)
4177 OPERATOR_TABLE_ALL(uchar, UChar)
4178
4179 //OpTable intOps =    {    IntAdd,    IntSub,    IntMul,    IntDiv,    IntMod,    IntExp,    IntNot,    IntBwn,    IntOr,    IntAnd,    IntEqu,    IntNqu,    IntGrt,    IntSma,    IntGrtEqu,    IntSmaEqu,    IntNeg,    IntLBitSft,    IntRBitSft };
4180 //OpTable uintOps =   {   UIntAdd,   UIntSub,   UIntMul,   UIntDiv,   UIntMod,   UIntExp,   UIntNot,   UIntBwn,   UIntOr,   UIntAnd,   UIntEqu,   UIntNqu,   UIntGrt,   UIntSma,   UIntGrtEqu,   UIntSmaEqu,   UIntNeg,   UIntLBitSft,   UIntRBitSft };
4181 //OpTable shortOps =  {  ShortAdd,  ShortSub,  ShortMul,  ShortDiv,  ShortMod,  ShortExp,  ShortNot,  ShortBwn,  ShortOr,  ShortAnd,  ShortEqu,  ShortNqu,  ShortGrt,  ShortSma,  ShortGrtEqu,  ShortSmaEqu,  ShortNeg,  ShortLBitSft,  ShortRBitSft };
4182 //OpTable ushortOps = { UShortAdd, UShortSub, UShortMul, UShortDiv, UShortMod, UShortExp, UShortNot, UShortBwn, UShortOr, UShortAnd, UShortEqu, UShortNqu, UShortGrt, UShortSma, UShortGrtEqu, UShortSmaEqu, UShortNeg, UShortLBitSft, UShortRBitSft };
4183 //OpTable floatOps =  {  FloatAdd,  FloatSub,  FloatMul,  FloatDiv,      null,      null,      null,      null,     null,      null,  FloatEqu,  FloatNqu,  FloatGrt,  FloatSma,  FloatGrtEqu,  FloatSmaEqu,  FloatNeg,          null,          null };
4184 //OpTable doubleOps = { DoubleAdd, DoubleSub, DoubleMul, DoubleDiv,      null,      null,      null,      null,     null,      null, DoubleEqu, DoubleNqu, DoubleGrt, DoubleSma, DoubleGrtEqu, DoubleSmaEqu, DoubleNeg,          null,          null };
4185 //OpTable charOps =   {   CharAdd,   CharSub,   CharMul,   CharDiv,   CharMod,   CharExp,   CharNot,   CharBwn,   CharOr,   CharAnd,   CharEqu,   CharNqu,   CharGrt,   CharSma,   CharGrtEqu,   CharSmaEqu,   CharNeg,   CharLBitSft,   CharRBitSft };
4186 //OpTable ucharOps =  {  UCharAdd,  UCharSub,  UCharMul,  UCharDiv,  UCharMod,  UCharExp,  UCharNot,  UCharBwn,  UCharOr,  UCharAnd,  UCharEqu,  UCharNqu,  UCharGrt,  UCharSma,  UCharGrtEqu,  UCharSmaEqu,  UCharNeg,  UCharLBitSft,  UCharRBitSft };
4187
4188 public void ReadString(char * output,  char * string)
4189 {
4190    int len = strlen(string);
4191    int c,d = 0;
4192    bool quoted = false, escaped = false;
4193    for(c = 0; c<len; c++)
4194    {
4195       char ch = string[c];
4196       if(escaped)
4197       {
4198          switch(ch)
4199          {
4200             case 'n': output[d] = '\n'; break;
4201             case 't': output[d] = '\t'; break;
4202             case 'a': output[d] = '\a'; break;
4203             case 'b': output[d] = '\b'; break;
4204             case 'f': output[d] = '\f'; break;
4205             case 'r': output[d] = '\r'; break;
4206             case 'v': output[d] = '\v'; break;
4207             case '\\': output[d] = '\\'; break;
4208             case '\"': output[d] = '\"'; break;
4209             case '\'': output[d] = '\''; break;
4210             default: output[d] = ch;
4211          }
4212          d++;
4213          escaped = false;
4214       }
4215       else
4216       {
4217          if(ch == '\"')
4218             quoted ^= true;
4219          else if(quoted)
4220          {
4221             if(ch == '\\')
4222                escaped = true;
4223             else
4224                output[d++] = ch;
4225          }
4226       }
4227    }
4228    output[d] = '\0';
4229 }
4230
4231 // String Unescape Copy
4232
4233 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
4234 // This is the same as ReadString above (which also misses numeric escape codes) except it doesn't handle external quotes
4235 public int UnescapeString(char * d, char * s, int len)
4236 {
4237    int j = 0, k = 0;
4238    char ch;
4239    while(j < len && (ch = s[j]))
4240    {
4241       switch(ch)
4242       {
4243          case '\\':
4244             switch((ch = s[++j]))
4245             {
4246                case 'n': d[k] = '\n'; break;
4247                case 't': d[k] = '\t'; break;
4248                case 'a': d[k] = '\a'; break;
4249                case 'b': d[k] = '\b'; break;
4250                case 'f': d[k] = '\f'; break;
4251                case 'r': d[k] = '\r'; break;
4252                case 'v': d[k] = '\v'; break;
4253                case '\\': d[k] = '\\'; break;
4254                case '\"': d[k] = '\"'; break;
4255                case '\'': d[k] = '\''; break;
4256                default: d[k] = '\\'; d[k] = ch;
4257             }
4258             break;
4259          default:
4260             d[k] = ch;
4261       }
4262       j++, k++;
4263    }
4264    d[k] = '\0';
4265    return k;
4266 }
4267
4268 public char * OffsetEscapedString(char * s, int len, int offset)
4269 {
4270    char ch;
4271    int j = 0, k = 0;
4272    while(j < len && k < offset && (ch = s[j]))
4273    {
4274       if(ch == '\\') ++j;
4275       j++, k++;
4276    }
4277    return (k == offset) ? s + j : null;
4278 }
4279
4280 public Operand GetOperand(Expression exp)
4281 {
4282    Operand op { };
4283    Type type = exp.expType;
4284    if(type)
4285    {
4286       while(type.kind == classType &&
4287          type._class.registered && (type._class.registered.type == bitClass || type._class.registered.type == unitClass || type._class.registered.type == enumClass))
4288       {
4289          if(!type._class.registered.dataType)
4290             type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
4291          type = type._class.registered.dataType;
4292
4293       }
4294       if(exp.type == stringExp && op.kind == pointerType)
4295       {
4296          op.ui64 = (uint64)exp.string;
4297          op.kind = pointerType;
4298          op.ops = uint64Ops;
4299       }
4300       else if(exp.isConstant && exp.type == constantExp)
4301       {
4302          op.kind = type.kind;
4303          op.type = exp.expType;
4304
4305          switch(op.kind)
4306          {
4307             case _BoolType:
4308             case charType:
4309             {
4310                if(exp.constant[0] == '\'')
4311                {
4312                   op.c = exp.constant[1];
4313                   op.ops = charOps;
4314                }
4315                else if(type.isSigned)
4316                {
4317                   op.c = (char)strtol(exp.constant, null, 0);
4318                   op.ops = charOps;
4319                }
4320                else
4321                {
4322                   op.uc = (unsigned char)strtoul(exp.constant, null, 0);
4323                   op.ops = ucharOps;
4324                }
4325                break;
4326             }
4327             case shortType:
4328                if(type.isSigned)
4329                {
4330                   op.s = (short)strtol(exp.constant, null, 0);
4331                   op.ops = shortOps;
4332                }
4333                else
4334                {
4335                   op.us = (unsigned short)strtoul(exp.constant, null, 0);
4336                   op.ops = ushortOps;
4337                }
4338                break;
4339             case intType:
4340             case longType:
4341                if(type.isSigned)
4342                {
4343                   op.i = (int)strtol(exp.constant, null, 0);
4344                   op.ops = intOps;
4345                }
4346                else
4347                {
4348                   op.ui = (unsigned int)strtoul(exp.constant, null, 0);
4349                   op.ops = uintOps;
4350                }
4351                op.kind = intType;
4352                break;
4353             case int64Type:
4354                if(type.isSigned)
4355                {
4356                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4357                   op.ops = intOps;
4358                }
4359                else
4360                {
4361                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4362                   op.ops = uintOps;
4363                }
4364                op.kind = int64Type;
4365                break;
4366             case intPtrType:
4367                if(type.isSigned)
4368                {
4369                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4370                   op.ops = int64Ops;
4371                }
4372                else
4373                {
4374                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4375                   op.ops = uint64Ops;
4376                }
4377                op.kind = int64Type;
4378                break;
4379             case intSizeType:
4380                if(type.isSigned)
4381                {
4382                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4383                   op.ops = int64Ops;
4384                }
4385                else
4386                {
4387                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4388                   op.ops = uint64Ops;
4389                }
4390                op.kind = int64Type;
4391                break;
4392             case floatType:
4393                if(!strcmp(exp.constant, "inf")) op.f = float::inf();
4394                else if(!strcmp(exp.constant, "-inf")) op.f = -float::inf();
4395                else if(!strcmp(exp.constant, "nan")) op.f = float::nan();
4396                else if(!strcmp(exp.constant, "-nan")) op.f = -float::nan();
4397                else
4398                   op.f = (float)strtod(exp.constant, null);
4399                op.ops = floatOps;
4400                break;
4401             case doubleType:
4402                if(!strcmp(exp.constant, "inf")) op.d = double::inf();
4403                else if(!strcmp(exp.constant, "-inf")) op.d = -double::inf();
4404                else if(!strcmp(exp.constant, "nan")) op.d = double::nan();
4405                else if(!strcmp(exp.constant, "-nan")) op.d = -double::nan();
4406                else
4407                   op.d = (double)strtod(exp.constant, null);
4408                op.ops = doubleOps;
4409                break;
4410             //case classType:    For when we have operator overloading...
4411             // Pointer additions
4412             //case functionType:
4413             case arrayType:
4414             case pointerType:
4415             case classType:
4416                op.ui64 = _strtoui64(exp.constant, null, 0);
4417                op.kind = pointerType;
4418                op.ops = uint64Ops;
4419                // op.ptrSize =
4420                break;
4421          }
4422       }
4423    }
4424    return op;
4425 }
4426
4427 static void UnusedFunction()
4428 {
4429    int a;
4430    a.OnGetString(0,0,0);
4431 }
4432 default:
4433 extern int __ecereVMethodID_class_OnGetString;
4434 public:
4435
4436 static void PopulateInstanceProcessMember(Instantiation inst, OldList * memberList, DataMember parentDataMember, uint offset)
4437 {
4438    DataMember dataMember;
4439    for(dataMember = parentDataMember.members.first; dataMember; dataMember = dataMember.next)
4440    {
4441       if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4442          PopulateInstanceProcessMember(inst, memberList, dataMember, offset + dataMember.offset);
4443       else
4444       {
4445          Expression exp { };
4446          MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4447          Type type;
4448          void * ptr = inst.data + dataMember.offset + offset;
4449          char * result = null;
4450          exp.loc = member.loc = inst.loc;
4451          ((Identifier)member.identifiers->first).loc = inst.loc;
4452
4453          if(!dataMember.dataType)
4454             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4455          type = dataMember.dataType;
4456          if(type.kind == classType)
4457          {
4458             Class _class = type._class.registered;
4459             if(_class.type == enumClass)
4460             {
4461                Class enumClass = eSystem_FindClass(privateModule, "enum");
4462                if(enumClass)
4463                {
4464                   EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4465                   NamedLink item;
4466                   for(item = e.values.first; item; item = item.next)
4467                   {
4468                      if((int)item.data == *(int *)ptr)
4469                      {
4470                         result = item.name;
4471                         break;
4472                      }
4473                   }
4474                   if(result)
4475                   {
4476                      exp.identifier = MkIdentifier(result);
4477                      exp.type = identifierExp;
4478                      exp.destType = MkClassType(_class.fullName);
4479                      ProcessExpressionType(exp);
4480                   }
4481                }
4482             }
4483             if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4484             {
4485                if(!_class.dataType)
4486                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4487                type = _class.dataType;
4488             }
4489          }
4490          if(!result)
4491          {
4492             switch(type.kind)
4493             {
4494                case floatType:
4495                {
4496                   FreeExpContents(exp);
4497
4498                   exp.constant = PrintFloat(*(float*)ptr);
4499                   exp.type = constantExp;
4500                   break;
4501                }
4502                case doubleType:
4503                {
4504                   FreeExpContents(exp);
4505
4506                   exp.constant = PrintDouble(*(double*)ptr);
4507                   exp.type = constantExp;
4508                   break;
4509                }
4510                case intType:
4511                {
4512                   FreeExpContents(exp);
4513
4514                   exp.constant = PrintInt(*(int*)ptr);
4515                   exp.type = constantExp;
4516                   break;
4517                }
4518                case int64Type:
4519                {
4520                   FreeExpContents(exp);
4521
4522                   exp.constant = PrintInt64(*(int64*)ptr);
4523                   exp.type = constantExp;
4524                   break;
4525                }
4526                case intPtrType:
4527                {
4528                   FreeExpContents(exp);
4529                   // TODO: This should probably use proper type
4530                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4531                   exp.type = constantExp;
4532                   break;
4533                }
4534                case intSizeType:
4535                {
4536                   FreeExpContents(exp);
4537                   // TODO: This should probably use proper type
4538                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4539                   exp.type = constantExp;
4540                   break;
4541                }
4542                default:
4543                   Compiler_Error($"Unhandled type populating instance\n");
4544             }
4545          }
4546          ListAdd(memberList, member);
4547       }
4548
4549       if(parentDataMember.type == unionMember)
4550          break;
4551    }
4552 }
4553
4554 void PopulateInstance(Instantiation inst)
4555 {
4556    Symbol classSym = inst._class.symbol; // FindClass(inst._class.name);
4557    Class _class = classSym.registered;
4558    DataMember dataMember;
4559    OldList * memberList = MkList();
4560    // Added this check and ->Add to prevent memory leaks on bad code
4561    if(!inst.members)
4562       inst.members = MkListOne(MkMembersInitList(memberList));
4563    else
4564       inst.members->Add(MkMembersInitList(memberList));
4565    for(dataMember = _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
4566    {
4567       if(!dataMember.isProperty)
4568       {
4569          if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4570             PopulateInstanceProcessMember(inst, memberList, dataMember, dataMember.offset);
4571          else
4572          {
4573             Expression exp { };
4574             MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4575             Type type;
4576             void * ptr = inst.data + dataMember.offset;
4577             char * result = null;
4578
4579             exp.loc = member.loc = inst.loc;
4580             ((Identifier)member.identifiers->first).loc = inst.loc;
4581
4582             if(!dataMember.dataType)
4583                dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4584             type = dataMember.dataType;
4585             if(type.kind == classType)
4586             {
4587                Class _class = type._class.registered;
4588                if(_class.type == enumClass)
4589                {
4590                   Class enumClass = eSystem_FindClass(privateModule, "enum");
4591                   if(enumClass)
4592                   {
4593                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4594                      NamedLink item;
4595                      for(item = e.values.first; item; item = item.next)
4596                      {
4597                         if((int)item.data == *(int *)ptr)
4598                         {
4599                            result = item.name;
4600                            break;
4601                         }
4602                      }
4603                   }
4604                   if(result)
4605                   {
4606                      exp.identifier = MkIdentifier(result);
4607                      exp.type = identifierExp;
4608                      exp.destType = MkClassType(_class.fullName);
4609                      ProcessExpressionType(exp);
4610                   }
4611                }
4612                if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4613                {
4614                   if(!_class.dataType)
4615                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4616                   type = _class.dataType;
4617                }
4618             }
4619             if(!result)
4620             {
4621                switch(type.kind)
4622                {
4623                   case floatType:
4624                   {
4625                      exp.constant = PrintFloat(*(float*)ptr);
4626                      exp.type = constantExp;
4627                      break;
4628                   }
4629                   case doubleType:
4630                   {
4631                      exp.constant = PrintDouble(*(double*)ptr);
4632                      exp.type = constantExp;
4633                      break;
4634                   }
4635                   case intType:
4636                   {
4637                      exp.constant = PrintInt(*(int*)ptr);
4638                      exp.type = constantExp;
4639                      break;
4640                   }
4641                   case int64Type:
4642                   {
4643                      exp.constant = PrintInt64(*(int64*)ptr);
4644                      exp.type = constantExp;
4645                      break;
4646                   }
4647                   case intPtrType:
4648                   {
4649                      exp.constant = PrintInt64((int64)*(intptr*)ptr);
4650                      exp.type = constantExp;
4651                      break;
4652                   }
4653                   default:
4654                      Compiler_Error($"Unhandled type populating instance\n");
4655                }
4656             }
4657             ListAdd(memberList, member);
4658          }
4659       }
4660    }
4661 }
4662
4663 void ComputeInstantiation(Expression exp)
4664 {
4665    Instantiation inst = exp.instance;
4666    MembersInit members;
4667    Symbol classSym = inst._class ? inst._class.symbol : null; // FindClass(inst._class.name);
4668    Class _class = classSym ? classSym.registered : null;
4669    DataMember curMember = null;
4670    Class curClass = null;
4671    DataMember subMemberStack[256];
4672    int subMemberStackPos = 0;
4673    uint64 bits = 0;
4674
4675    if(_class && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass ))
4676    {
4677       // Don't recompute the instantiation...
4678       // Non Simple classes will have become constants by now
4679       if(inst.data)
4680          return;
4681
4682       if(_class.type == normalClass || _class.type == noHeadClass)
4683       {
4684          inst.data = (byte *)eInstance_New(_class);
4685          if(_class.type == normalClass)
4686             ((Instance)inst.data)._refCount++;
4687       }
4688       else
4689          inst.data = new0 byte[_class.structSize];
4690    }
4691
4692    if(inst.members)
4693    {
4694       for(members = inst.members->first; members; members = members.next)
4695       {
4696          switch(members.type)
4697          {
4698             case dataMembersInit:
4699             {
4700                if(members.dataMembers)
4701                {
4702                   MemberInit member;
4703                   for(member = members.dataMembers->first; member; member = member.next)
4704                   {
4705                      Identifier ident = member.identifiers ? member.identifiers->first : null;
4706                      bool found = false;
4707
4708                      Property prop = null;
4709                      DataMember dataMember = null;
4710                      Method method = null;
4711                      uint dataMemberOffset;
4712
4713                      if(!ident)
4714                      {
4715                         eClass_FindNextMember(_class, &curClass, &curMember, subMemberStack, &subMemberStackPos);
4716                         if(curMember)
4717                         {
4718                            if(curMember.isProperty)
4719                               prop = (Property)curMember;
4720                            else
4721                            {
4722                               dataMember = curMember;
4723
4724                               // CHANGED THIS HERE
4725                               eClass_FindDataMemberAndOffset(_class, dataMember.name, &dataMemberOffset, privateModule, null, null);
4726
4727                               // 2013/17/29 -- It seems that this was missing here!
4728                               if(_class.type == normalClass)
4729                                  dataMemberOffset += _class.base.structSize;
4730                               // dataMemberOffset = dataMember.offset;
4731                            }
4732                            found = true;
4733                         }
4734                      }
4735                      else
4736                      {
4737                         prop = eClass_FindProperty(_class, ident.string, privateModule);
4738                         if(prop)
4739                         {
4740                            found = true;
4741                            if(prop.memberAccess == publicAccess)
4742                            {
4743                               curMember = (DataMember)prop;
4744                               curClass = prop._class;
4745                            }
4746                         }
4747                         else
4748                         {
4749                            DataMember _subMemberStack[256];
4750                            int _subMemberStackPos = 0;
4751
4752                            // FILL MEMBER STACK
4753                            dataMember = eClass_FindDataMemberAndOffset(_class, ident.string, &dataMemberOffset, privateModule, _subMemberStack, &_subMemberStackPos);
4754
4755                            if(dataMember)
4756                            {
4757                               found = true;
4758                               if(dataMember.memberAccess == publicAccess)
4759                               {
4760                                  curMember = dataMember;
4761                                  curClass = dataMember._class;
4762                                  memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
4763                                  subMemberStackPos = _subMemberStackPos;
4764                               }
4765                            }
4766                         }
4767                      }
4768
4769                      if(found && member.initializer && member.initializer.type == expInitializer)
4770                      {
4771                         Expression value = member.initializer.exp;
4772                         Type type = null;
4773                         bool deepMember = false;
4774                         if(prop)
4775                         {
4776                            type = prop.dataType;
4777                         }
4778                         else if(dataMember)
4779                         {
4780                            if(!dataMember.dataType)
4781                               dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4782
4783                            type = dataMember.dataType;
4784                         }
4785
4786                         if(ident && ident.next)
4787                         {
4788                            deepMember = true;
4789
4790                            // for(; ident && type; ident = ident.next)
4791                            for(ident = ident.next; ident && type; ident = ident.next)
4792                            {
4793                               if(type.kind == classType)
4794                               {
4795                                  prop = eClass_FindProperty(type._class.registered,
4796                                     ident.string, privateModule);
4797                                  if(prop)
4798                                     type = prop.dataType;
4799                                  else
4800                                  {
4801                                     dataMember = eClass_FindDataMemberAndOffset(type._class.registered,
4802                                        ident.string, &dataMemberOffset, privateModule, null, null);
4803                                     if(dataMember)
4804                                        type = dataMember.dataType;
4805                                  }
4806                               }
4807                               else if(type.kind == structType || type.kind == unionType)
4808                               {
4809                                  Type memberType;
4810                                  for(memberType = type.members.first; memberType; memberType = memberType.next)
4811                                  {
4812                                     if(!strcmp(memberType.name, ident.string))
4813                                     {
4814                                        type = memberType;
4815                                        break;
4816                                     }
4817                                  }
4818                               }
4819                            }
4820                         }
4821                         if(value)
4822                         {
4823                            FreeType(value.destType);
4824                            value.destType = type;
4825                            if(type) type.refCount++;
4826                            ComputeExpression(value);
4827                         }
4828                         if(!deepMember && type && value && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass /*&& value.expType.kind == type.kind*/))
4829                         {
4830                            if(type.kind == classType)
4831                            {
4832                               Class _class = type._class.registered;
4833                               if(_class.type == bitClass || _class.type == unitClass ||
4834                                  _class.type == enumClass)
4835                               {
4836                                  if(!_class.dataType)
4837                                     _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4838                                  type = _class.dataType;
4839                               }
4840                            }
4841
4842                            if(dataMember)
4843                            {
4844                               void * ptr = inst.data + dataMemberOffset;
4845
4846                               if(value.type == constantExp)
4847                               {
4848                                  switch(type.kind)
4849                                  {
4850                                     case intType:
4851                                     {
4852                                        GetInt(value, (int*)ptr);
4853                                        break;
4854                                     }
4855                                     case int64Type:
4856                                     {
4857                                        GetInt64(value, (int64*)ptr);
4858                                        break;
4859                                     }
4860                                     case intPtrType:
4861                                     {
4862                                        GetIntPtr(value, (intptr*)ptr);
4863                                        break;
4864                                     }
4865                                     case intSizeType:
4866                                     {
4867                                        GetIntSize(value, (intsize*)ptr);
4868                                        break;
4869                                     }
4870                                     case floatType:
4871                                     {
4872                                        GetFloat(value, (float*)ptr);
4873                                        break;
4874                                     }
4875                                     case doubleType:
4876                                     {
4877                                        GetDouble(value, (double *)ptr);
4878                                        break;
4879                                     }
4880                                  }
4881                               }
4882                               else if(value.type == instanceExp)
4883                               {
4884                                  if(type.kind == classType)
4885                                  {
4886                                     Class _class = type._class.registered;
4887                                     if(_class.type == structClass)
4888                                     {
4889                                        ComputeTypeSize(type);
4890                                        if(value.instance.data)
4891                                           memcpy(ptr, value.instance.data, type.size);
4892                                     }
4893                                  }
4894                               }
4895                            }
4896                            else if(prop)
4897                            {
4898                               if(value.type == instanceExp && value.instance.data)
4899                               {
4900                                  if(type.kind == classType)
4901                                  {
4902                                     Class _class = type._class.registered;
4903                                     if(_class && (_class.type != normalClass || eClass_IsDerived(((Instance)value.instance.data)._class, _class)))
4904                                     {
4905                                        void (*Set)(void *, void *) = (void *)prop.Set;
4906                                        Set(inst.data, value.instance.data);
4907                                        PopulateInstance(inst);
4908                                     }
4909                                  }
4910                               }
4911                               else if(value.type == constantExp)
4912                               {
4913                                  switch(type.kind)
4914                                  {
4915                                     case doubleType:
4916                                     {
4917                                        void (*Set)(void *, double) = (void *)prop.Set;
4918                                        Set(inst.data, strtod(value.constant, null) );
4919                                        break;
4920                                     }
4921                                     case floatType:
4922                                     {
4923                                        void (*Set)(void *, float) = (void *)prop.Set;
4924                                        Set(inst.data, (float)(strtod(value.constant, null)));
4925                                        break;
4926                                     }
4927                                     case intType:
4928                                     {
4929                                        void (*Set)(void *, int) = (void *)prop.Set;
4930                                        Set(inst.data, (int)strtol(value.constant, null, 0));
4931                                        break;
4932                                     }
4933                                     case int64Type:
4934                                     {
4935                                        void (*Set)(void *, int64) = (void *)prop.Set;
4936                                        Set(inst.data, _strtoi64(value.constant, null, 0));
4937                                        break;
4938                                     }
4939                                     case intPtrType:
4940                                     {
4941                                        void (*Set)(void *, intptr) = (void *)prop.Set;
4942                                        Set(inst.data, (intptr)_strtoi64(value.constant, null, 0));
4943                                        break;
4944                                     }
4945                                     case intSizeType:
4946                                     {
4947                                        void (*Set)(void *, intsize) = (void *)prop.Set;
4948                                        Set(inst.data, (intsize)_strtoi64(value.constant, null, 0));
4949                                        break;
4950                                     }
4951                                  }
4952                               }
4953                               else if(value.type == stringExp)
4954                               {
4955                                  char temp[1024];
4956                                  ReadString(temp, value.string);
4957                                  ((void (*)(void *, void *))(void *)prop.Set)(inst.data, temp);
4958                               }
4959                            }
4960                         }
4961                         else if(!deepMember && type && _class.type == unitClass)
4962                         {
4963                            if(prop)
4964                            {
4965                               // Only support converting units to units for now...
4966                               if(value.type == constantExp)
4967                               {
4968                                  if(type.kind == classType)
4969                                  {
4970                                     Class _class = type._class.registered;
4971                                     if(_class.type == unitClass)
4972                                     {
4973                                        if(!_class.dataType)
4974                                           _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4975                                        type = _class.dataType;
4976                                     }
4977                                  }
4978                                  // TODO: Assuming same base type for units...
4979                                  switch(type.kind)
4980                                  {
4981                                     case floatType:
4982                                     {
4983                                        float fValue;
4984                                        float (*Set)(float) = (void *)prop.Set;
4985                                        GetFloat(member.initializer.exp, &fValue);
4986                                        exp.constant = PrintFloat(Set(fValue));
4987                                        exp.type = constantExp;
4988                                        break;
4989                                     }
4990                                     case doubleType:
4991                                     {
4992                                        double dValue;
4993                                        double (*Set)(double) = (void *)prop.Set;
4994                                        GetDouble(member.initializer.exp, &dValue);
4995                                        exp.constant = PrintDouble(Set(dValue));
4996                                        exp.type = constantExp;
4997                                        break;
4998                                     }
4999                                  }
5000                               }
5001                            }
5002                         }
5003                         else if(!deepMember && type && _class.type == bitClass)
5004                         {
5005                            if(prop)
5006                            {
5007                               if(value.type == instanceExp && value.instance.data)
5008                               {
5009                                  unsigned int (*Set)(void *) = (void *)prop.Set;
5010                                  bits = Set(value.instance.data);
5011                               }
5012                               else if(value.type == constantExp)
5013                               {
5014                               }
5015                            }
5016                            else if(dataMember)
5017                            {
5018                               BitMember bitMember = (BitMember) dataMember;
5019                               Type type;
5020                               int part = 0;
5021                               GetInt(value, &part);
5022                               bits = (bits & ~bitMember.mask);
5023                               if(!bitMember.dataType)
5024                                  bitMember.dataType = ProcessTypeString(bitMember.dataTypeString, false);
5025
5026                               type = bitMember.dataType;
5027
5028                               if(type.kind == classType && type._class && type._class.registered)
5029                               {
5030                                  if(!type._class.registered.dataType)
5031                                     type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
5032                                  type = type._class.registered.dataType;
5033                               }
5034
5035                               switch(type.kind)
5036                               {
5037                                  case _BoolType:
5038                                  case charType:
5039                                     if(type.isSigned)
5040                                        bits |= ((char)part << bitMember.pos);
5041                                     else
5042                                        bits |= ((unsigned char)part << bitMember.pos);
5043                                     break;
5044                                  case shortType:
5045                                     if(type.isSigned)
5046                                        bits |= ((short)part << bitMember.pos);
5047                                     else
5048                                        bits |= ((unsigned short)part << bitMember.pos);
5049                                     break;
5050                                  case intType:
5051                                  case longType:
5052                                     if(type.isSigned)
5053                                        bits |= ((int)part << bitMember.pos);
5054                                     else
5055                                        bits |= ((unsigned int)part << bitMember.pos);
5056                                     break;
5057                                  case int64Type:
5058                                     if(type.isSigned)
5059                                        bits |= ((int64)part << bitMember.pos);
5060                                     else
5061                                        bits |= ((uint64)part << bitMember.pos);
5062                                     break;
5063                                  case intPtrType:
5064                                     if(type.isSigned)
5065                                     {
5066                                        bits |= ((intptr)part << bitMember.pos);
5067                                     }
5068                                     else
5069                                     {
5070                                        bits |= ((uintptr)part << bitMember.pos);
5071                                     }
5072                                     break;
5073                                  case intSizeType:
5074                                     if(type.isSigned)
5075                                     {
5076                                        bits |= ((ssize_t)(intsize)part << bitMember.pos);
5077                                     }
5078                                     else
5079                                     {
5080                                        bits |= ((size_t) (uintsize)part << bitMember.pos);
5081                                     }
5082                                     break;
5083                               }
5084                            }
5085                         }
5086                      }
5087                      else
5088                      {
5089                         if(_class && _class.type == unitClass)
5090                         {
5091                            ComputeExpression(member.initializer.exp);
5092                            exp.constant = member.initializer.exp.constant;
5093                            exp.type = constantExp;
5094
5095                            member.initializer.exp.constant = null;
5096                         }
5097                      }
5098                   }
5099                }
5100                break;
5101             }
5102          }
5103       }
5104    }
5105    if(_class && _class.type == bitClass)
5106    {
5107       exp.constant = PrintHexUInt(bits);
5108       exp.type = constantExp;
5109    }
5110    if(exp.type != instanceExp)
5111    {
5112       FreeInstance(inst);
5113    }
5114 }
5115
5116 static bool Promote(Operand op, TypeKind kind, bool isSigned)
5117 {
5118    bool result = false;
5119    switch(kind)
5120    {
5121       case shortType:
5122          if(op.kind == charType || op.kind == enumType || op.kind == _BoolType)
5123             result = isSigned ? GetOpShort(op, &op.s) : GetOpUShort(op, &op.us);
5124          break;
5125       case intType:
5126       case longType:
5127          if(op.kind == charType || op.kind == shortType || op.kind == enumType || op.kind == _BoolType)
5128             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5129          break;
5130       case int64Type:
5131          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5132             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5133          result = isSigned ? GetOpInt64(op, &op.i64) : GetOpUInt64(op, &op.ui64);
5134          break;
5135       case floatType:
5136          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType ||
5137             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5138          result = GetOpFloat(op, &op.f);
5139          break;
5140       case doubleType:
5141          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType ||
5142             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5143          result = GetOpDouble(op, &op.d);
5144          break;
5145       case pointerType:
5146          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5147             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5148             result = GetOpUIntPtr(op, &op.ui64);
5149          break;
5150       case enumType:
5151          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5152             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5153             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5154          break;
5155       case intPtrType:
5156          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5157             result = isSigned ? GetOpIntPtr(op, &op.i64) : GetOpUIntPtr(op, &op.i64);
5158          break;
5159       case intSizeType:
5160          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5161             result = isSigned ? GetOpIntSize(op, &op.ui64) : GetOpUIntSize(op, &op.ui64);
5162          break;
5163    }
5164    return result;
5165 }
5166
5167 void CallOperator(Expression exp, Expression exp1, Expression exp2, Operand op1, Operand op2)
5168 {
5169    if(exp.op.op == SIZEOF)
5170    {
5171       FreeExpContents(exp);
5172       exp.type = constantExp;
5173       exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5174    }
5175    else
5176    {
5177       if(!exp.op.exp1)
5178       {
5179          switch(exp.op.op)
5180          {
5181             // unary arithmetic
5182             case '+':
5183             {
5184                // Provide default unary +
5185                Expression exp2 = exp.op.exp2;
5186                exp.op.exp2 = null;
5187                FreeExpContents(exp);
5188                FreeType(exp.expType);
5189                FreeType(exp.destType);
5190                *exp = *exp2;
5191                delete exp2;
5192                break;
5193             }
5194             case '-':
5195                if(op1.ops.Neg) { FreeExpContents(exp); op1.ops.Neg(exp, op1); }
5196                break;
5197             // unary arithmetic increment and decrement
5198                   //OPERATOR_ALL(UNARY, ++, Inc)
5199                   //OPERATOR_ALL(UNARY, --, Dec)
5200             // unary bitwise
5201             case '~':
5202                if(op1.ops.BitNot) { FreeExpContents(exp); op1.ops.BitNot(exp, op1); }
5203                break;
5204             // unary logical negation
5205             case '!':
5206                if(op1.ops.Not) { FreeExpContents(exp); op1.ops.Not(exp, op1); }
5207                break;
5208          }
5209       }
5210       else
5211       {
5212          if(op1 && op2 && op1.type && op2.type && op1.kind != op2.kind)
5213          {
5214             if(Promote(op2, op1.kind, op1.type.isSigned))
5215                op2.kind = op1.kind, op2.ops = op1.ops;
5216             else if(Promote(op1, op2.kind, op2.type.isSigned))
5217                op1.kind = op2.kind, op1.ops = op2.ops;
5218          }
5219          switch(exp.op.op)
5220          {
5221             // binary arithmetic
5222             case '+':
5223                if(op1.ops.Add) { FreeExpContents(exp); op1.ops.Add(exp, op1, op2); }
5224                break;
5225             case '-':
5226                if(op1.ops.Sub) { FreeExpContents(exp); op1.ops.Sub(exp, op1, op2); }
5227                break;
5228             case '*':
5229                if(op1.ops.Mul) { FreeExpContents(exp); op1.ops.Mul(exp, op1, op2); }
5230                break;
5231             case '/':
5232                if(op1.ops.Div) { FreeExpContents(exp); op1.ops.Div(exp, op1, op2); }
5233                break;
5234             case '%':
5235                if(op1.ops.Mod) { FreeExpContents(exp); op1.ops.Mod(exp, op1, op2); }
5236                break;
5237             // binary arithmetic assignment
5238                   //OPERATOR_ALL(BINARY, =, Asign)
5239                   //OPERATOR_ALL(BINARY, +=, AddAsign)
5240                   //OPERATOR_ALL(BINARY, -=, SubAsign)
5241                   //OPERATOR_ALL(BINARY, *=, MulAsign)
5242                   //OPERATOR_ALL(BINARY, /=, DivAsign)
5243                   //OPERATOR_ALL(BINARY, %=, ModAsign)
5244             // binary bitwise
5245             case '&':
5246                if(exp.op.exp2)
5247                {
5248                   if(op1.ops.BitAnd) { FreeExpContents(exp); op1.ops.BitAnd(exp, op1, op2); }
5249                }
5250                break;
5251             case '|':
5252                if(op1.ops.BitOr) { FreeExpContents(exp); op1.ops.BitOr(exp, op1, op2); }
5253                break;
5254             case '^':
5255                if(op1.ops.BitXor) { FreeExpContents(exp); op1.ops.BitXor(exp, op1, op2); }
5256                break;
5257             case LEFT_OP:
5258                if(op1.ops.LShift) { FreeExpContents(exp); op1.ops.LShift(exp, op1, op2); }
5259                break;
5260             case RIGHT_OP:
5261                if(op1.ops.RShift) { FreeExpContents(exp); op1.ops.RShift(exp, op1, op2); }
5262                break;
5263             // binary bitwise assignment
5264                   //OPERATOR_INTTYPES(BINARY, &=, AndAsign)
5265                   //OPERATOR_INTTYPES(BINARY, |=, OrAsign)
5266                   //OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
5267                   //OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
5268                   //OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
5269             // binary logical equality
5270             case EQ_OP:
5271                if(op1.ops.Equ) { FreeExpContents(exp); op1.ops.Equ(exp, op1, op2); }
5272                break;
5273             case NE_OP:
5274                if(op1.ops.Nqu) { FreeExpContents(exp); op1.ops.Nqu(exp, op1, op2); }
5275                break;
5276             // binary logical
5277             case AND_OP:
5278                if(op1.ops.And) { FreeExpContents(exp); op1.ops.And(exp, op1, op2); }
5279                break;
5280             case OR_OP:
5281                if(op1.ops.Or) { FreeExpContents(exp); op1.ops.Or(exp, op1, op2); }
5282                break;
5283             // binary logical relational
5284             case '>':
5285                if(op1.ops.Grt) { FreeExpContents(exp); op1.ops.Grt(exp, op1, op2); }
5286                break;
5287             case '<':
5288                if(op1.ops.Sma) { FreeExpContents(exp); op1.ops.Sma(exp, op1, op2); }
5289                break;
5290             case GE_OP:
5291                if(op1.ops.GrtEqu) { FreeExpContents(exp); op1.ops.GrtEqu(exp, op1, op2); }
5292                break;
5293             case LE_OP:
5294                if(op1.ops.SmaEqu) { FreeExpContents(exp); op1.ops.SmaEqu(exp, op1, op2); }
5295                break;
5296          }
5297       }
5298    }
5299 }
5300
5301 void ComputeExpression(Expression exp)
5302 {
5303    char expString[10240];
5304    expString[0] = '\0';
5305 #ifdef _DEBUG
5306    PrintExpression(exp, expString);
5307 #endif
5308
5309    switch(exp.type)
5310    {
5311       case instanceExp:
5312       {
5313          ComputeInstantiation(exp);
5314          break;
5315       }
5316       /*
5317       case constantExp:
5318          break;
5319       */
5320       case opExp:
5321       {
5322          Expression exp1, exp2 = null;
5323          Operand op1 { };
5324          Operand op2 { };
5325
5326          // We don't care about operations with only exp2 (INC_OP, DEC_OP...)
5327          if(exp.op.exp2)
5328          {
5329             Expression e = exp.op.exp2;
5330
5331             while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
5332             {
5333                if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
5334                {
5335                   if(e.type == extensionCompoundExp)
5336                      e = ((Statement)e.compound.compound.statements->last).expressions->last;
5337                   else
5338                      e = e.list->last;
5339                }
5340             }
5341             if(exp.op.op == TokenType::sizeOf && e && e.expType)
5342             {
5343                if(e.type == stringExp && e.string)
5344                {
5345                   char * string = e.string;
5346                   int len = strlen(string);
5347                   char * tmp = new char[len-2+1];
5348                   len = UnescapeString(tmp, string + 1, len - 2);
5349                   delete tmp;
5350                   FreeExpContents(exp);
5351                   exp.type = constantExp;
5352                   exp.constant = PrintUInt(len + 1);
5353                }
5354                else
5355                {
5356                   Type type = e.expType;
5357                   type.refCount++;
5358                   FreeExpContents(exp);
5359                   exp.type = constantExp;
5360                   exp.constant = PrintUInt(ComputeTypeSize(type));
5361                   FreeType(type);
5362                }
5363                break;
5364             }
5365             else
5366                ComputeExpression(exp.op.exp2);
5367          }
5368          if(exp.op.exp1)
5369          {
5370             ComputeExpression(exp.op.exp1);
5371             exp1 = exp.op.exp1;
5372             exp2 = exp.op.exp2;
5373             op1 = GetOperand(exp1);
5374             if(op1.type) op1.type.refCount++;
5375             if(exp2)
5376             {
5377                op2 = GetOperand(exp2);
5378                if(op2.type) op2.type.refCount++;
5379             }
5380          }
5381          else
5382          {
5383             exp1 = exp.op.exp2;
5384             op1 = GetOperand(exp1);
5385             if(op1.type) op1.type.refCount++;
5386          }
5387
5388          CallOperator(exp, exp1, exp2, op1, op2);
5389          /*
5390          switch(exp.op.op)
5391          {
5392             // Unary operators
5393             case '&':
5394                // Also binary
5395                if(exp.op.exp1 && exp.op.exp2)
5396                {
5397                   // Binary And
5398                   if(op1.ops.BitAnd)
5399                   {
5400                      FreeExpContents(exp);
5401                      op1.ops.BitAnd(exp, op1, op2);
5402                   }
5403                }
5404                break;
5405             case '*':
5406                if(exp.op.exp1)
5407                {
5408                   if(op1.ops.Mul)
5409                   {
5410                      FreeExpContents(exp);
5411                      op1.ops.Mul(exp, op1, op2);
5412                   }
5413                }
5414                break;
5415             case '+':
5416                if(exp.op.exp1)
5417                {
5418                   if(op1.ops.Add)
5419                   {
5420                      FreeExpContents(exp);
5421                      op1.ops.Add(exp, op1, op2);
5422                   }
5423                }
5424                else
5425                {
5426                   // Provide default unary +
5427                   Expression exp2 = exp.op.exp2;
5428                   exp.op.exp2 = null;
5429                   FreeExpContents(exp);
5430                   FreeType(exp.expType);
5431                   FreeType(exp.destType);
5432
5433                   *exp = *exp2;
5434                   delete exp2;
5435                }
5436                break;
5437             case '-':
5438                if(exp.op.exp1)
5439                {
5440                   if(op1.ops.Sub)
5441                   {
5442                      FreeExpContents(exp);
5443                      op1.ops.Sub(exp, op1, op2);
5444                   }
5445                }
5446                else
5447                {
5448                   if(op1.ops.Neg)
5449                   {
5450                      FreeExpContents(exp);
5451                      op1.ops.Neg(exp, op1);
5452                   }
5453                }
5454                break;
5455             case '~':
5456                if(op1.ops.BitNot)
5457                {
5458                   FreeExpContents(exp);
5459                   op1.ops.BitNot(exp, op1);
5460                }
5461                break;
5462             case '!':
5463                if(op1.ops.Not)
5464                {
5465                   FreeExpContents(exp);
5466                   op1.ops.Not(exp, op1);
5467                }
5468                break;
5469             // Binary only operators
5470             case '/':
5471                if(op1.ops.Div)
5472                {
5473                   FreeExpContents(exp);
5474                   op1.ops.Div(exp, op1, op2);
5475                }
5476                break;
5477             case '%':
5478                if(op1.ops.Mod)
5479                {
5480                   FreeExpContents(exp);
5481                   op1.ops.Mod(exp, op1, op2);
5482                }
5483                break;
5484             case LEFT_OP:
5485                break;
5486             case RIGHT_OP:
5487                break;
5488             case '<':
5489                if(exp.op.exp1)
5490                {
5491                   if(op1.ops.Sma)
5492                   {
5493                      FreeExpContents(exp);
5494                      op1.ops.Sma(exp, op1, op2);
5495                   }
5496                }
5497                break;
5498             case '>':
5499                if(exp.op.exp1)
5500                {
5501                   if(op1.ops.Grt)
5502                   {
5503                      FreeExpContents(exp);
5504                      op1.ops.Grt(exp, op1, op2);
5505                   }
5506                }
5507                break;
5508             case LE_OP:
5509                if(exp.op.exp1)
5510                {
5511                   if(op1.ops.SmaEqu)
5512                   {
5513                      FreeExpContents(exp);
5514                      op1.ops.SmaEqu(exp, op1, op2);
5515                   }
5516                }
5517                break;
5518             case GE_OP:
5519                if(exp.op.exp1)
5520                {
5521                   if(op1.ops.GrtEqu)
5522                   {
5523                      FreeExpContents(exp);
5524                      op1.ops.GrtEqu(exp, op1, op2);
5525                   }
5526                }
5527                break;
5528             case EQ_OP:
5529                if(exp.op.exp1)
5530                {
5531                   if(op1.ops.Equ)
5532                   {
5533                      FreeExpContents(exp);
5534                      op1.ops.Equ(exp, op1, op2);
5535                   }
5536                }
5537                break;
5538             case NE_OP:
5539                if(exp.op.exp1)
5540                {
5541                   if(op1.ops.Nqu)
5542                   {
5543                      FreeExpContents(exp);
5544                      op1.ops.Nqu(exp, op1, op2);
5545                   }
5546                }
5547                break;
5548             case '|':
5549                if(op1.ops.BitOr)
5550                {
5551                   FreeExpContents(exp);
5552                   op1.ops.BitOr(exp, op1, op2);
5553                }
5554                break;
5555             case '^':
5556                if(op1.ops.BitXor)
5557                {
5558                   FreeExpContents(exp);
5559                   op1.ops.BitXor(exp, op1, op2);
5560                }
5561                break;
5562             case AND_OP:
5563                break;
5564             case OR_OP:
5565                break;
5566             case SIZEOF:
5567                FreeExpContents(exp);
5568                exp.type = constantExp;
5569                exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5570                break;
5571          }
5572          */
5573          if(op1.type) FreeType(op1.type);
5574          if(op2.type) FreeType(op2.type);
5575          break;
5576       }
5577       case bracketsExp:
5578       case extensionExpressionExp:
5579       {
5580          Expression e, n;
5581          for(e = exp.list->first; e; e = n)
5582          {
5583             n = e.next;
5584             if(!n)
5585             {
5586                OldList * list = exp.list;
5587                ComputeExpression(e);
5588                //FreeExpContents(exp);
5589                FreeType(exp.expType);
5590                FreeType(exp.destType);
5591                *exp = *e;
5592                delete e;
5593                delete list;
5594             }
5595             else
5596             {
5597                FreeExpression(e);
5598             }
5599          }
5600          break;
5601       }
5602       /*
5603
5604       case ExpIndex:
5605       {
5606          Expression e;
5607          exp.isConstant = true;
5608
5609          ComputeExpression(exp.index.exp);
5610          if(!exp.index.exp.isConstant)
5611             exp.isConstant = false;
5612
5613          for(e = exp.index.index->first; e; e = e.next)
5614          {
5615             ComputeExpression(e);
5616             if(!e.next)
5617             {
5618                // Check if this type is int
5619             }
5620             if(!e.isConstant)
5621                exp.isConstant = false;
5622          }
5623          exp.expType = Dereference(exp.index.exp.expType);
5624          break;
5625       }
5626       */
5627       case memberExp:
5628       {
5629          Expression memberExp = exp.member.exp;
5630          Identifier memberID = exp.member.member;
5631
5632          Type type;
5633          ComputeExpression(exp.member.exp);
5634          type = exp.member.exp.expType;
5635          if(type)
5636          {
5637             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);
5638             Property prop = null;
5639             DataMember member = null;
5640             Class convertTo = null;
5641             if(type.kind == subClassType && exp.member.exp.type == classExp)
5642                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
5643
5644             if(!_class)
5645             {
5646                char string[256];
5647                Symbol classSym;
5648                string[0] = '\0';
5649                PrintTypeNoConst(type, string, false, true);
5650                classSym = FindClass(string);
5651                _class = classSym ? classSym.registered : null;
5652             }
5653
5654             if(exp.member.member)
5655             {
5656                prop = eClass_FindProperty(_class, exp.member.member.string, privateModule);
5657                if(!prop)
5658                   member = eClass_FindDataMember(_class, exp.member.member.string, privateModule, null, null);
5659             }
5660             if(!prop && !member && _class && exp.member.member)
5661             {
5662                Symbol classSym = FindClass(exp.member.member.string);
5663                convertTo = _class;
5664                _class = classSym ? classSym.registered : null;
5665                prop = eClass_FindProperty(_class, convertTo.fullName, privateModule);
5666             }
5667
5668             if(prop)
5669             {
5670                if(prop.compiled)
5671                {
5672                   Type type = prop.dataType;
5673                   // TODO: Assuming same base type for units...
5674                   if(_class.type == unitClass)
5675                   {
5676                      if(type.kind == classType)
5677                      {
5678                         Class _class = type._class.registered;
5679                         if(_class.type == unitClass)
5680                         {
5681                            if(!_class.dataType)
5682                               _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5683                            type = _class.dataType;
5684                         }
5685                      }
5686                      switch(type.kind)
5687                      {
5688                         case floatType:
5689                         {
5690                            float value;
5691                            float (*Get)(float) = (void *)prop.Get;
5692                            GetFloat(exp.member.exp, &value);
5693                            exp.constant = PrintFloat(Get ? Get(value) : value);
5694                            exp.type = constantExp;
5695                            break;
5696                         }
5697                         case doubleType:
5698                         {
5699                            double value;
5700                            double (*Get)(double);
5701                            GetDouble(exp.member.exp, &value);
5702
5703                            if(convertTo)
5704                               Get = (void *)prop.Set;
5705                            else
5706                               Get = (void *)prop.Get;
5707                            exp.constant = PrintDouble(Get ? Get(value) : value);
5708                            exp.type = constantExp;
5709                            break;
5710                         }
5711                      }
5712                   }
5713                   else
5714                   {
5715                      if(convertTo)
5716                      {
5717                         Expression value = exp.member.exp;
5718                         Type type;
5719                         if(!prop.dataType)
5720                            ProcessPropertyType(prop);
5721
5722                         type = prop.dataType;
5723                         if(!type)
5724                         {
5725                             // printf("Investigate this\n");
5726                         }
5727                         else if(_class.type == structClass)
5728                         {
5729                            switch(type.kind)
5730                            {
5731                               case classType:
5732                               {
5733                                  Class propertyClass = type._class.registered;
5734                                  if(propertyClass.type == structClass && value.type == instanceExp)
5735                                  {
5736                                     void (*Set)(void *, void *) = (void *)prop.Set;
5737                                     exp.instance = Instantiation { };
5738                                     exp.instance.data = new0 byte[_class.structSize];
5739                                     exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5740                                     exp.instance.loc = exp.loc;
5741                                     exp.type = instanceExp;
5742                                     Set(exp.instance.data, value.instance.data);
5743                                     PopulateInstance(exp.instance);
5744                                  }
5745                                  break;
5746                               }
5747                               case intType:
5748                               {
5749                                  int intValue;
5750                                  void (*Set)(void *, int) = (void *)prop.Set;
5751
5752                                  exp.instance = Instantiation { };
5753                                  exp.instance.data = new0 byte[_class.structSize];
5754                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5755                                  exp.instance.loc = exp.loc;
5756                                  exp.type = instanceExp;
5757
5758                                  GetInt(value, &intValue);
5759
5760                                  Set(exp.instance.data, intValue);
5761                                  PopulateInstance(exp.instance);
5762                                  break;
5763                               }
5764                               case int64Type:
5765                               {
5766                                  int64 intValue;
5767                                  void (*Set)(void *, int64) = (void *)prop.Set;
5768
5769                                  exp.instance = Instantiation { };
5770                                  exp.instance.data = new0 byte[_class.structSize];
5771                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5772                                  exp.instance.loc = exp.loc;
5773                                  exp.type = instanceExp;
5774
5775                                  GetInt64(value, &intValue);
5776
5777                                  Set(exp.instance.data, intValue);
5778                                  PopulateInstance(exp.instance);
5779                                  break;
5780                               }
5781                               case intPtrType:
5782                               {
5783                                  // TOFIX:
5784                                  intptr intValue;
5785                                  void (*Set)(void *, intptr) = (void *)prop.Set;
5786
5787                                  exp.instance = Instantiation { };
5788                                  exp.instance.data = new0 byte[_class.structSize];
5789                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5790                                  exp.instance.loc = exp.loc;
5791                                  exp.type = instanceExp;
5792
5793                                  GetIntPtr(value, &intValue);
5794
5795                                  Set(exp.instance.data, intValue);
5796                                  PopulateInstance(exp.instance);
5797                                  break;
5798                               }
5799                               case intSizeType:
5800                               {
5801                                  // TOFIX:
5802                                  intsize intValue;
5803                                  void (*Set)(void *, intsize) = (void *)prop.Set;
5804
5805                                  exp.instance = Instantiation { };
5806                                  exp.instance.data = new0 byte[_class.structSize];
5807                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5808                                  exp.instance.loc = exp.loc;
5809                                  exp.type = instanceExp;
5810
5811                                  GetIntSize(value, &intValue);
5812
5813                                  Set(exp.instance.data, intValue);
5814                                  PopulateInstance(exp.instance);
5815                                  break;
5816                               }
5817                               case doubleType:
5818                               {
5819                                  double doubleValue;
5820                                  void (*Set)(void *, double) = (void *)prop.Set;
5821
5822                                  exp.instance = Instantiation { };
5823                                  exp.instance.data = new0 byte[_class.structSize];
5824                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5825                                  exp.instance.loc = exp.loc;
5826                                  exp.type = instanceExp;
5827
5828                                  GetDouble(value, &doubleValue);
5829
5830                                  Set(exp.instance.data, doubleValue);
5831                                  PopulateInstance(exp.instance);
5832                                  break;
5833                               }
5834                            }
5835                         }
5836                         else if(_class.type == bitClass)
5837                         {
5838                            switch(type.kind)
5839                            {
5840                               case classType:
5841                               {
5842                                  Class propertyClass = type._class.registered;
5843                                  if(propertyClass.type == structClass && value.instance.data)
5844                                  {
5845                                     unsigned int (*Set)(void *) = (void *)prop.Set;
5846                                     unsigned int bits = Set(value.instance.data);
5847                                     exp.constant = PrintHexUInt(bits);
5848                                     exp.type = constantExp;
5849                                     break;
5850                                  }
5851                                  else if(_class.type == bitClass)
5852                                  {
5853                                     unsigned int value;
5854                                     unsigned int (*Set)(unsigned int) = (void *)prop.Set;
5855                                     unsigned int bits;
5856
5857                                     GetUInt(exp.member.exp, &value);
5858                                     bits = Set(value);
5859                                     exp.constant = PrintHexUInt(bits);
5860                                     exp.type = constantExp;
5861                                  }
5862                               }
5863                            }
5864                         }
5865                      }
5866                      else
5867                      {
5868                         if(_class.type == bitClass)
5869                         {
5870                            unsigned int value;
5871                            GetUInt(exp.member.exp, &value);
5872
5873                            switch(type.kind)
5874                            {
5875                               case classType:
5876                               {
5877                                  Class _class = type._class.registered;
5878                                  if(_class.type == structClass)
5879                                  {
5880                                     void (*Get)(unsigned int, void *) = (void *)prop.Get;
5881
5882                                     exp.instance = Instantiation { };
5883                                     exp.instance.data = new0 byte[_class.structSize];
5884                                     exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5885                                     exp.instance.loc = exp.loc;
5886                                     //exp.instance.fullSet = true;
5887                                     exp.type = instanceExp;
5888                                     Get(value, exp.instance.data);
5889                                     PopulateInstance(exp.instance);
5890                                  }
5891                                  else if(_class.type == bitClass)
5892                                  {
5893                                     unsigned int (*Get)(unsigned int) = (void *)prop.Get;
5894                                     uint64 bits = Get(value);
5895                                     exp.constant = PrintHexUInt64(bits);
5896                                     exp.type = constantExp;
5897                                  }
5898                                  break;
5899                               }
5900                            }
5901                         }
5902                         else if(_class.type == structClass)
5903                         {
5904                            char * value = (exp.member.exp.type == instanceExp ) ? exp.member.exp.instance.data : null;
5905                            switch(type.kind)
5906                            {
5907                               case classType:
5908                               {
5909                                  Class _class = type._class.registered;
5910                                  if(_class.type == structClass && value)
5911                                  {
5912                                     void (*Get)(void *, void *) = (void *)prop.Get;
5913
5914                                     exp.instance = Instantiation { };
5915                                     exp.instance.data = new0 byte[_class.structSize];
5916                                     exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5917                                     exp.instance.loc = exp.loc;
5918                                     //exp.instance.fullSet = true;
5919                                     exp.type = instanceExp;
5920                                     Get(value, exp.instance.data);
5921                                     PopulateInstance(exp.instance);
5922                                  }
5923                                  break;
5924                               }
5925                            }
5926                         }
5927                         /*else
5928                         {
5929                            char * value = exp.member.exp.instance.data;
5930                            switch(type.kind)
5931                            {
5932                               case classType:
5933                               {
5934                                  Class _class = type._class.registered;
5935                                  if(_class.type == normalClass)
5936                                  {
5937                                     void *(*Get)(void *) = (void *)prop.Get;
5938
5939                                     exp.instance = Instantiation { };
5940                                     exp.instance._class = MkSpecifierName(_class.fullName); //MkClassName(_class.fullName);
5941                                     exp.type = instanceExp;
5942                                     exp.instance.data = Get(value, exp.instance.data);
5943                                  }
5944                                  break;
5945                               }
5946                            }
5947                         }
5948                         */
5949                      }
5950                   }
5951                }
5952                else
5953                {
5954                   exp.isConstant = false;
5955                }
5956             }
5957             else if(member)
5958             {
5959             }
5960          }
5961
5962          if(exp.type != ExpressionType::memberExp)
5963          {
5964             FreeExpression(memberExp);
5965             FreeIdentifier(memberID);
5966          }
5967          break;
5968       }
5969       case typeSizeExp:
5970       {
5971          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
5972          FreeExpContents(exp);
5973          exp.constant = PrintUInt(ComputeTypeSize(type));
5974          exp.type = constantExp;
5975          FreeType(type);
5976          break;
5977       }
5978       case classSizeExp:
5979       {
5980          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
5981          if(classSym && classSym.registered)
5982          {
5983             if(classSym.registered.fixed)
5984             {
5985                FreeSpecifier(exp._class);
5986                exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
5987                exp.type = constantExp;
5988             }
5989             else
5990             {
5991                char className[1024];
5992                strcpy(className, "__ecereClass_");
5993                FullClassNameCat(className, classSym.string, true);
5994                MangleClassName(className);
5995
5996                DeclareClass(classSym, className);
5997
5998                FreeExpContents(exp);
5999                exp.type = pointerExp;
6000                exp.member.exp = MkExpIdentifier(MkIdentifier(className));
6001                exp.member.member = MkIdentifier("structSize");
6002             }
6003          }
6004          break;
6005       }
6006       case castExp:
6007       //case constantExp:
6008       {
6009          Type type;
6010          Expression e = exp;
6011          if(exp.type == castExp)
6012          {
6013             if(exp.cast.exp)
6014                ComputeExpression(exp.cast.exp);
6015             e = exp.cast.exp;
6016          }
6017          if(e && exp.expType)
6018          {
6019             /*if(exp.destType)
6020                type = exp.destType;
6021             else*/
6022                type = exp.expType;
6023             if(type.kind == classType)
6024             {
6025                Class _class = type._class.registered;
6026                if(_class && (_class.type == unitClass || _class.type == bitClass))
6027                {
6028                   if(!_class.dataType)
6029                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
6030                   type = _class.dataType;
6031                }
6032             }
6033
6034             switch(type.kind)
6035             {
6036                case _BoolType:
6037                case charType:
6038                   if(type.isSigned)
6039                   {
6040                      char value = 0;
6041                      if(GetChar(e, &value))
6042                      {
6043                         FreeExpContents(exp);
6044                         exp.constant = PrintChar(value);
6045                         exp.type = constantExp;
6046                      }
6047                   }
6048                   else
6049                   {
6050                      unsigned char value = 0;
6051                      if(GetUChar(e, &value))
6052                      {
6053                         FreeExpContents(exp);
6054                         exp.constant = PrintUChar(value);
6055                         exp.type = constantExp;
6056                      }
6057                   }
6058                   break;
6059                case shortType:
6060                   if(type.isSigned)
6061                   {
6062                      short value = 0;
6063                      if(GetShort(e, &value))
6064                      {
6065                         FreeExpContents(exp);
6066                         exp.constant = PrintShort(value);
6067                         exp.type = constantExp;
6068                      }
6069                   }
6070                   else
6071                   {
6072                      unsigned short value = 0;
6073                      if(GetUShort(e, &value))
6074                      {
6075                         FreeExpContents(exp);
6076                         exp.constant = PrintUShort(value);
6077                         exp.type = constantExp;
6078                      }
6079                   }
6080                   break;
6081                case intType:
6082                   if(type.isSigned)
6083                   {
6084                      int value = 0;
6085                      if(GetInt(e, &value))
6086                      {
6087                         FreeExpContents(exp);
6088                         exp.constant = PrintInt(value);
6089                         exp.type = constantExp;
6090                      }
6091                   }
6092                   else
6093                   {
6094                      unsigned int value = 0;
6095                      if(GetUInt(e, &value))
6096                      {
6097                         FreeExpContents(exp);
6098                         exp.constant = PrintUInt(value);
6099                         exp.type = constantExp;
6100                      }
6101                   }
6102                   break;
6103                case int64Type:
6104                   if(type.isSigned)
6105                   {
6106                      int64 value = 0;
6107                      if(GetInt64(e, &value))
6108                      {
6109                         FreeExpContents(exp);
6110                         exp.constant = PrintInt64(value);
6111                         exp.type = constantExp;
6112                      }
6113                   }
6114                   else
6115                   {
6116                      uint64 value = 0;
6117                      if(GetUInt64(e, &value))
6118                      {
6119                         FreeExpContents(exp);
6120                         exp.constant = PrintUInt64(value);
6121                         exp.type = constantExp;
6122                      }
6123                   }
6124                   break;
6125                case intPtrType:
6126                   if(type.isSigned)
6127                   {
6128                      intptr value = 0;
6129                      if(GetIntPtr(e, &value))
6130                      {
6131                         FreeExpContents(exp);
6132                         exp.constant = PrintInt64((int64)value);
6133                         exp.type = constantExp;
6134                      }
6135                   }
6136                   else
6137                   {
6138                      uintptr value = 0;
6139                      if(GetUIntPtr(e, &value))
6140                      {
6141                         FreeExpContents(exp);
6142                         exp.constant = PrintUInt64((uint64)value);
6143                         exp.type = constantExp;
6144                      }
6145                   }
6146                   break;
6147                case intSizeType:
6148                   if(type.isSigned)
6149                   {
6150                      intsize value = 0;
6151                      if(GetIntSize(e, &value))
6152                      {
6153                         FreeExpContents(exp);
6154                         exp.constant = PrintInt64((int64)value);
6155                         exp.type = constantExp;
6156                      }
6157                   }
6158                   else
6159                   {
6160                      uintsize value = 0;
6161                      if(GetUIntSize(e, &value))
6162                      {
6163                         FreeExpContents(exp);
6164                         exp.constant = PrintUInt64((uint64)value);
6165                         exp.type = constantExp;
6166                      }
6167                   }
6168                   break;
6169                case floatType:
6170                {
6171                   float value = 0;
6172                   if(GetFloat(e, &value))
6173                   {
6174                      FreeExpContents(exp);
6175                      exp.constant = PrintFloat(value);
6176                      exp.type = constantExp;
6177                   }
6178                   break;
6179                }
6180                case doubleType:
6181                {
6182                   double value = 0;
6183                   if(GetDouble(e, &value))
6184                   {
6185                      FreeExpContents(exp);
6186                      exp.constant = PrintDouble(value);
6187                      exp.type = constantExp;
6188                   }
6189                   break;
6190                }
6191             }
6192          }
6193          break;
6194       }
6195       case conditionExp:
6196       {
6197          Operand op1 { };
6198          Operand op2 { };
6199          Operand op3 { };
6200
6201          if(exp.cond.exp)
6202             // Caring only about last expression for now...
6203             ComputeExpression(exp.cond.exp->last);
6204          if(exp.cond.elseExp)
6205             ComputeExpression(exp.cond.elseExp);
6206          if(exp.cond.cond)
6207             ComputeExpression(exp.cond.cond);
6208
6209          op1 = GetOperand(exp.cond.cond);
6210          if(op1.type) op1.type.refCount++;
6211          op2 = GetOperand(exp.cond.exp->last);
6212          if(op2.type) op2.type.refCount++;
6213          op3 = GetOperand(exp.cond.elseExp);
6214          if(op3.type) op3.type.refCount++;
6215
6216          if(op1.ops.Cond) { FreeExpContents(exp); op1.ops.Cond(exp, op1, op2, op3); }
6217          if(op1.type) FreeType(op1.type);
6218          if(op2.type) FreeType(op2.type);
6219          if(op3.type) FreeType(op3.type);
6220          break;
6221       }
6222    }
6223 }
6224
6225 static bool CheckExpressionType(Expression exp, Type destType, bool skipUnitBla)
6226 {
6227    bool result = true;
6228    if(destType)
6229    {
6230       OldList converts { };
6231       Conversion convert;
6232
6233       if(destType.kind == voidType)
6234          return false;
6235
6236       if(!MatchTypeExpression(exp, destType, &converts, skipUnitBla))
6237          result = false;
6238       if(converts.count)
6239       {
6240          // for(convert = converts.last; convert; convert = convert.prev)
6241          for(convert = converts.first; convert; convert = convert.next)
6242          {
6243             bool empty = !(convert.isGet ? (void *)convert.convert.Get : (void *)convert.convert.Set);
6244             if(!empty)
6245             {
6246                Expression newExp { };
6247                ClassObjectType objectType = exp.expType ? exp.expType.classObjectType : none;
6248
6249                // TODO: Check this...
6250                *newExp = *exp;
6251                newExp.destType = null;
6252
6253                if(convert.isGet)
6254                {
6255                   // [exp].ColorRGB
6256                   exp.type = memberExp;
6257                   exp.addedThis = true;
6258                   exp.member.exp = newExp;
6259                   FreeType(exp.member.exp.expType);
6260
6261                   exp.member.exp.expType = MkClassType(convert.convert._class.fullName);
6262                   exp.member.exp.expType.classObjectType = objectType;
6263                   exp.member.member = MkIdentifier(convert.convert.dataTypeString);
6264                   exp.member.memberType = propertyMember;
6265                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6266                   // TESTING THIS... for (int)degrees
6267                   exp.needCast = true;
6268                   if(exp.expType) exp.expType.refCount++;
6269                   ApplyAnyObjectLogic(exp.member.exp);
6270                }
6271                else
6272                {
6273
6274                   /*if(exp.isConstant)
6275                   {
6276                      // Color { ColorRGB = [exp] };
6277                      exp.type = instanceExp;
6278                      exp.instance = MkInstantiation(MkSpecifierName((convert.convert._class.fullName), //MkClassName(convert.convert._class.fullName),
6279                         null, MkListOne(MkMembersInitList(MkListOne(MkMemberInit(
6280                         MkListOne(MkIdentifier(convert.convert.dataTypeString)), newExp)))));
6281                   }
6282                   else*/
6283                   {
6284                      // If not constant, don't turn it yet into an instantiation
6285                      // (Go through the deep members system first)
6286                      exp.type = memberExp;
6287                      exp.addedThis = true;
6288                      exp.member.exp = newExp;
6289
6290                      // ADDED THIS HERE TO SOLVE PROPERTY ISSUES WITH NOHEAD CLASSES
6291                      if(/*!notByReference && */newExp.expType && newExp.expType.kind == classType && newExp.expType._class && newExp.expType._class.registered &&
6292                         newExp.expType._class.registered.type == noHeadClass)
6293                      {
6294                         newExp.byReference = true;
6295                      }
6296
6297                      FreeType(exp.member.exp.expType);
6298                      /*exp.member.exp.expType = convert.convert.dataType;
6299                      if(convert.convert.dataType) convert.convert.dataType.refCount++;*/
6300                      exp.member.exp.expType = null;
6301                      if(convert.convert.dataType)
6302                      {
6303                         exp.member.exp.expType = { };
6304                         CopyTypeInto(exp.member.exp.expType, convert.convert.dataType);
6305                         exp.member.exp.expType.refCount = 1;
6306                         exp.member.exp.expType.classObjectType = objectType;
6307                         ApplyAnyObjectLogic(exp.member.exp);
6308                      }
6309
6310                      exp.member.member = MkIdentifier(convert.convert._class.fullName);
6311                      exp.member.memberType = reverseConversionMember;
6312                      exp.expType = convert.resultType ? convert.resultType :
6313                         MkClassType(convert.convert._class.fullName);
6314                      exp.needCast = true;
6315                      if(convert.resultType) convert.resultType.refCount++;
6316                   }
6317                }
6318             }
6319             else
6320             {
6321                FreeType(exp.expType);
6322                if(convert.isGet)
6323                {
6324                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6325                   exp.needCast = true;
6326                   if(exp.expType) exp.expType.refCount++;
6327                }
6328                else
6329                {
6330                   exp.expType = convert.resultType ? convert.resultType : MkClassType(convert.convert._class.fullName);
6331                   exp.needCast = true;
6332                   if(convert.resultType)
6333                      convert.resultType.refCount++;
6334                }
6335             }
6336          }
6337          if(exp.isConstant && inCompiler)
6338             ComputeExpression(exp);
6339
6340          converts.Free(FreeConvert);
6341       }
6342
6343       if(!result && exp.expType && converts.count)      // TO TEST: Added converts.count here to avoid a double warning with function type
6344       {
6345          result = MatchTypes(exp.expType, exp.destType, null, null, null, true, true, false, false);
6346       }
6347       if(!result && exp.expType && exp.destType)
6348       {
6349          if((exp.destType.kind == classType && exp.expType.kind == pointerType &&
6350              exp.expType.type.kind == classType && exp.expType.type._class == exp.destType._class && exp.destType._class.registered && exp.destType._class.registered.type == structClass) ||
6351             (exp.expType.kind == classType && exp.destType.kind == pointerType &&
6352             exp.destType.type.kind == classType && exp.destType.type._class == exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass))
6353             result = true;
6354       }
6355    }
6356    // if(result) CheckTemplateTypes(exp);
6357    return result;
6358 }
6359
6360 void CheckTemplateTypes(Expression exp)
6361 {
6362    if(exp.destType && exp.destType.passAsTemplate && exp.expType && exp.expType.kind != templateType && !exp.expType.passAsTemplate)
6363    {
6364       Expression newExp { };
6365       Statement compound;
6366       Context context;
6367       *newExp = *exp;
6368       if(exp.destType) exp.destType.refCount++;
6369       if(exp.expType)  exp.expType.refCount++;
6370       newExp.prev = null;
6371       newExp.next = null;
6372
6373       switch(exp.expType.kind)
6374       {
6375          case doubleType:
6376             if(exp.destType.classObjectType)
6377             {
6378                // We need to pass the address, just pass it along (Undo what was done above)
6379                if(exp.destType) exp.destType.refCount--;
6380                if(exp.expType)  exp.expType.refCount--;
6381                delete newExp;
6382             }
6383             else
6384             {
6385                // If we're looking for value:
6386                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6387                OldList * specs;
6388                OldList * unionDefs = MkList();
6389                OldList * statements = MkList();
6390                context = PushContext();
6391                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6392                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6393                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6394                exp.type = extensionCompoundExp;
6395                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6396                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")), '=', newExp))));
6397                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
6398                exp.compound.compound.context = context;
6399                PopContext(context);
6400             }
6401             break;
6402          default:
6403             exp.type = castExp;
6404             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6405             exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6406             break;
6407       }
6408    }
6409    else if(exp.expType && exp.expType.passAsTemplate && exp.destType && exp.usage.usageGet && exp.destType.kind != templateType && !exp.destType.passAsTemplate)
6410    {
6411       Expression newExp { };
6412       Statement compound;
6413       Context context;
6414       *newExp = *exp;
6415       if(exp.destType) exp.destType.refCount++;
6416       if(exp.expType)  exp.expType.refCount++;
6417       newExp.prev = null;
6418       newExp.next = null;
6419
6420       switch(exp.expType.kind)
6421       {
6422          case doubleType:
6423             if(exp.destType.classObjectType)
6424             {
6425                // We need to pass the address, just pass it along (Undo what was done above)
6426                if(exp.destType) exp.destType.refCount--;
6427                if(exp.expType)  exp.expType.refCount--;
6428                delete newExp;
6429             }
6430             else
6431             {
6432                // If we're looking for value:
6433                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6434                OldList * specs;
6435                OldList * unionDefs = MkList();
6436                OldList * statements = MkList();
6437                context = PushContext();
6438                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6439                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6440                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6441                exp.type = extensionCompoundExp;
6442                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6443                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
6444                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")))));
6445                exp.compound.compound.context = context;
6446                PopContext(context);
6447             }
6448             break;
6449          case classType:
6450          {
6451             if(exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass)
6452             {
6453                exp.type = bracketsExp;
6454                exp.list = MkListOne(MkExpOp(null, '*', MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)),
6455                   MkDeclaratorPointer(MkPointer(null, null), null)), newExp)));
6456                ProcessExpressionType(exp.list->first);
6457                break;
6458             }
6459             else
6460             {
6461                exp.type = bracketsExp;
6462                exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)), null), newExp));
6463                newExp.needCast = true;
6464                ProcessExpressionType(exp.list->first);
6465                break;
6466             }
6467          }
6468          default:
6469          {
6470             if(exp.expType.kind == templateType)
6471             {
6472                Type type = ProcessTemplateParameterType(exp.expType.templateParameter);
6473                if(type)
6474                {
6475                   FreeType(exp.destType);
6476                   FreeType(exp.expType);
6477                   delete newExp;
6478                   break;
6479                }
6480             }
6481             if(newExp.type == memberExp && newExp.member.memberType == dataMember)
6482             {
6483                exp.type = opExp;
6484                exp.op.op = '*';
6485                exp.op.exp1 = null;
6486                exp.op.exp2 = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uint64")), MkDeclaratorPointer(MkPointer(null, null), null)),
6487                   MkExpBrackets(MkListOne(MkExpOp(null, '&', newExp))));
6488             }
6489             else
6490             {
6491                char typeString[1024];
6492                Declarator decl;
6493                OldList * specs = MkList();
6494                typeString[0] = '\0';
6495                PrintType(exp.expType, typeString, false, false);
6496                decl = SpecDeclFromString(typeString, specs, null);
6497
6498                exp.type = castExp;
6499                //exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6500                exp.cast.typeName = MkTypeName(specs, decl);
6501                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6502                exp.cast.exp.needCast = true;
6503             }
6504             break;
6505          }
6506       }
6507    }
6508 }
6509 // TODO: The Symbol tree should be reorganized by namespaces
6510 // Name Space:
6511 //    - Tree of all symbols within (stored without namespace)
6512 //    - Tree of sub-namespaces
6513
6514 static Symbol ScanWithNameSpace(BinaryTree tree, char * nameSpace, char * name)
6515 {
6516    int nsLen = strlen(nameSpace);
6517    Symbol symbol;
6518    // Start at the name space prefix
6519    for(symbol = (Symbol)tree.FindPrefix(nameSpace); symbol; symbol = (Symbol)((BTNode)symbol).next)
6520    {
6521       char * s = symbol.string;
6522       if(!strncmp(s, nameSpace, nsLen))
6523       {
6524          // This supports e.g. matching ecere::Socket to ecere::net::Socket
6525          int c;
6526          char * namePart;
6527          for(c = strlen(s)-1; c >= 0; c--)
6528             if(s[c] == ':')
6529                break;
6530
6531          namePart = s+c+1;
6532          if(!strcmp(namePart, name))
6533          {
6534             // TODO: Error on ambiguity
6535             return symbol;
6536          }
6537       }
6538       else
6539          break;
6540    }
6541    return null;
6542 }
6543
6544 static Symbol FindWithNameSpace(BinaryTree tree, char * name)
6545 {
6546    int c;
6547    char nameSpace[1024];
6548    char * namePart;
6549    bool gotColon = false;
6550
6551    nameSpace[0] = '\0';
6552    for(c = strlen(name)-1; c >= 0; c--)
6553       if(name[c] == ':')
6554       {
6555          gotColon = true;
6556          break;
6557       }
6558
6559    namePart = name+c+1;
6560    while(c >= 0 && name[c] == ':') c--;
6561    if(c >= 0)
6562    {
6563       // Try an exact match first
6564       Symbol symbol = (Symbol)tree.FindString(name);
6565       if(symbol)
6566          return symbol;
6567
6568       // Namespace specified
6569       memcpy(nameSpace, name, c + 1);
6570       nameSpace[c+1] = 0;
6571
6572       return ScanWithNameSpace(tree, nameSpace, namePart);
6573    }
6574    else if(gotColon)
6575    {
6576       // Looking for a global symbol, e.g. ::Sleep()
6577       Symbol symbol = (Symbol)tree.FindString(namePart);
6578       return symbol;
6579    }
6580    else
6581    {
6582       // Name only (no namespace specified)
6583       Symbol symbol = (Symbol)tree.FindString(namePart);
6584       if(symbol)
6585          return symbol;
6586       return ScanWithNameSpace(tree, "", namePart);
6587    }
6588    return null;
6589 }
6590
6591 static void ProcessDeclaration(Declaration decl);
6592
6593 /*static */Symbol FindSymbol(char * name, Context startContext, Context endContext, bool isStruct, bool globalNameSpace)
6594 {
6595 #ifdef _DEBUG
6596    //Time startTime = GetTime();
6597 #endif
6598    // Optimize this later? Do this before/less?
6599    Context ctx;
6600    Symbol symbol = null;
6601    // First, check if the identifier is declared inside the function
6602    //for(ctx = curContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6603
6604    for(ctx = startContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6605    {
6606       if(ctx == globalContext && !globalNameSpace && ctx.hasNameSpace)
6607       {
6608          symbol = null;
6609          if(thisNameSpace)
6610          {
6611             char curName[1024];
6612             strcpy(curName, thisNameSpace);
6613             strcat(curName, "::");
6614             strcat(curName, name);
6615             // Try to resolve in current namespace first
6616             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, curName);
6617          }
6618          if(!symbol)
6619             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, name);
6620       }
6621       else
6622          symbol = (Symbol)(isStruct ? ctx.structSymbols : ctx.symbols).FindString(name);
6623
6624       if(symbol || ctx == endContext) break;
6625    }
6626    if(inCompiler && curExternal && symbol && ctx == globalContext && curExternal.symbol && symbol.id > curExternal.symbol.idCode && symbol.pointerExternal)
6627    {
6628       if(symbol.pointerExternal.type == functionExternal)
6629       {
6630          FunctionDefinition function = symbol.pointerExternal.function;
6631
6632          // Modified this recently...
6633          Context tmpContext = curContext;
6634          curContext = null;
6635          symbol.pointerExternal = MkExternalDeclaration(MkDeclaration(CopyList(function.specifiers, CopySpecifier), MkListOne(MkInitDeclarator(CopyDeclarator(function.declarator), null))));
6636          curContext = tmpContext;
6637
6638          symbol.pointerExternal.symbol = symbol;
6639
6640          // TESTING THIS:
6641          DeclareType(symbol.type, true, true);
6642
6643          ast->Insert(curExternal.prev, symbol.pointerExternal);
6644
6645          symbol.id = curExternal.symbol.idCode;
6646
6647       }
6648       else if(symbol.pointerExternal.type == declarationExternal && curExternal.symbol.idCode < symbol.pointerExternal.symbol.id) // Added id comparison because Global Function prototypes were broken
6649       {
6650          ast->Move(symbol.pointerExternal, curExternal.prev);
6651          symbol.id = curExternal.symbol.idCode;
6652       }
6653    }
6654 #ifdef _DEBUG
6655    //findSymbolTotalTime += GetTime() - startTime;
6656 #endif
6657    return symbol;
6658 }
6659
6660 static void GetTypeSpecs(Type type, OldList * specs)
6661 {
6662    if(!type.isSigned && type.kind != intPtrType && type.kind != intSizeType) ListAdd(specs, MkSpecifier(UNSIGNED));
6663    switch(type.kind)
6664    {
6665       case classType:
6666       {
6667          if(type._class.registered)
6668          {
6669             if(!type._class.registered.dataType)
6670                type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
6671             GetTypeSpecs(type._class.registered.dataType, specs);
6672          }
6673          break;
6674       }
6675       case doubleType: ListAdd(specs, MkSpecifier(DOUBLE)); break;
6676       case floatType: ListAdd(specs, MkSpecifier(FLOAT)); break;
6677       case charType: ListAdd(specs, MkSpecifier(CHAR)); break;
6678       case _BoolType: ListAdd(specs, MkSpecifier(_BOOL)); break;
6679       case shortType: ListAdd(specs, MkSpecifier(SHORT)); break;
6680       case int64Type: ListAdd(specs, MkSpecifier(INT64)); break;
6681       case intPtrType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intptr" : "uintptr")); break;
6682       case intSizeType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intsize" : "uintsize")); break;
6683       case intType:
6684       default:
6685          ListAdd(specs, MkSpecifier(INT)); break;
6686    }
6687 }
6688
6689 static void PrintArraySize(Type arrayType, char * string)
6690 {
6691    char size[256];
6692    size[0] = '\0';
6693    strcat(size, "[");
6694    if(arrayType.enumClass)
6695       strcat(size, arrayType.enumClass.string);
6696    else if(arrayType.arraySizeExp)
6697       PrintExpression(arrayType.arraySizeExp, size);
6698    strcat(size, "]");
6699    strcat(string, size);
6700 }
6701
6702 // WARNING : This function expects a null terminated string since it recursively concatenate...
6703 static void PrintTypeSpecs(Type type, char * string, bool fullName, bool printConst)
6704 {
6705    if(type)
6706    {
6707       if(printConst && type.constant)
6708          strcat(string, "const ");
6709       switch(type.kind)
6710       {
6711          case classType:
6712          {
6713             Symbol c = type._class;
6714             // TODO: typed_object does not fully qualify the type, as it may have taken up an actual class (Stored in _class) from overriding
6715             //       look into merging with thisclass ?
6716             if(type.classObjectType == typedObject)
6717                strcat(string, "typed_object");
6718             else if(type.classObjectType == anyObject)
6719                strcat(string, "any_object");
6720             else
6721             {
6722                if(c && c.string)
6723                   strcat(string, (fullName || !c.registered) ? c.string : c.registered.name);
6724             }
6725             if(type.byReference)
6726                strcat(string, " &");
6727             break;
6728          }
6729          case voidType: strcat(string, "void"); break;
6730          case intType:  strcat(string, type.isSigned ? "int" : "uint"); break;
6731          case int64Type:  strcat(string, type.isSigned ? "int64" : "uint64"); break;
6732          case intPtrType:  strcat(string, type.isSigned ? "intptr" : "uintptr"); break;
6733          case intSizeType:  strcat(string, type.isSigned ? "intsize" : "uintsize"); break;
6734          case charType: strcat(string, type.isSigned ? "char" : "byte"); break;
6735          case _BoolType: strcat(string, "_Bool"); break;
6736          case shortType: strcat(string, type.isSigned ? "short" : "uint16"); break;
6737          case floatType: strcat(string, "float"); break;
6738          case doubleType: strcat(string, "double"); break;
6739          case structType:
6740             if(type.enumName)
6741             {
6742                strcat(string, "struct ");
6743                strcat(string, type.enumName);
6744             }
6745             else if(type.typeName)
6746                strcat(string, type.typeName);
6747             else
6748             {
6749                Type member;
6750                strcat(string, "struct { ");
6751                for(member = type.members.first; member; member = member.next)
6752                {
6753                   PrintType(member, string, true, fullName);
6754                   strcat(string,"; ");
6755                }
6756                strcat(string,"}");
6757             }
6758             break;
6759          case unionType:
6760             if(type.enumName)
6761             {
6762                strcat(string, "union ");
6763                strcat(string, type.enumName);
6764             }
6765             else if(type.typeName)
6766                strcat(string, type.typeName);
6767             else
6768             {
6769                strcat(string, "union ");
6770                strcat(string,"(unnamed)");
6771             }
6772             break;
6773          case enumType:
6774             if(type.enumName)
6775             {
6776                strcat(string, "enum ");
6777                strcat(string, type.enumName);
6778             }
6779             else if(type.typeName)
6780                strcat(string, type.typeName);
6781             else
6782                strcat(string, "int"); // "enum");
6783             break;
6784          case ellipsisType:
6785             strcat(string, "...");
6786             break;
6787          case subClassType:
6788             strcat(string, "subclass(");
6789             strcat(string, type._class ? type._class.string : "int");
6790             strcat(string, ")");
6791             break;
6792          case templateType:
6793             strcat(string, type.templateParameter.identifier.string);
6794             break;
6795          case thisClassType:
6796             strcat(string, "thisclass");
6797             break;
6798          case vaListType:
6799             strcat(string, "__builtin_va_list");
6800             break;
6801       }
6802    }
6803 }
6804
6805 static void PrintName(Type type, char * string, bool fullName)
6806 {
6807    if(type.name && type.name[0])
6808    {
6809       if(fullName)
6810          strcat(string, type.name);
6811       else
6812       {
6813          char * name = RSearchString(type.name, "::", strlen(type.name), true, false);
6814          if(name) name += 2; else name = type.name;
6815          strcat(string, name);
6816       }
6817    }
6818 }
6819
6820 static void PrintAttribs(Type type, char * string)
6821 {
6822    if(type)
6823    {
6824       if(type.dllExport)   strcat(string, "dllexport ");
6825       if(type.attrStdcall) strcat(string, "stdcall ");
6826    }
6827 }
6828
6829 static void PrePrintType(Type type, char * string, bool fullName, Type parentType, bool printConst)
6830 {
6831    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
6832    {
6833       Type attrType = null;
6834       if((type.kind == functionType || type.kind == methodType) && (!parentType || parentType.kind != pointerType))
6835          PrintAttribs(type, string);
6836       if(printConst && type.constant && (type.kind == functionType || type.kind == methodType))
6837          strcat(string, " const");
6838       PrePrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName, type, printConst);
6839       if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
6840          strcat(string, " (");
6841       if(type.kind == pointerType)
6842       {
6843          if(type.type.kind == functionType || type.type.kind == methodType)
6844             PrintAttribs(type.type, string);
6845       }
6846       if(type.kind == pointerType)
6847       {
6848          if(type.type.kind == functionType || type.type.kind == methodType || type.type.kind == arrayType)
6849             strcat(string, "*");
6850          else
6851             strcat(string, " *");
6852       }
6853       if(printConst && type.constant && type.kind == pointerType)
6854          strcat(string, " const");
6855    }
6856    else
6857       PrintTypeSpecs(type, string, fullName, printConst);
6858 }
6859
6860 static void PostPrintType(Type type, char * string, bool fullName)
6861 {
6862    if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
6863       strcat(string, ")");
6864    if(type.kind == arrayType)
6865       PrintArraySize(type, string);
6866    else if(type.kind == functionType)
6867    {
6868       Type param;
6869       strcat(string, "(");
6870       for(param = type.params.first; param; param = param.next)
6871       {
6872          PrintType(param, string, true, fullName);
6873          if(param.next) strcat(string, ", ");
6874       }
6875       strcat(string, ")");
6876    }
6877    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
6878       PostPrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName);
6879 }
6880
6881 // *****
6882 // TODO: Add a max buffer size to avoid overflows. This function is used with static size char arrays.
6883 // *****
6884 static void _PrintType(Type type, char * string, bool printName, bool fullName, bool printConst)
6885 {
6886    PrePrintType(type, string, fullName, null, printConst);
6887
6888    if(type.thisClass || (printName && type.name && type.name[0]))
6889       strcat(string, " ");
6890    if(/*(type.kind == methodType || type.kind == functionType) && */(type.thisClass || type.staticMethod))
6891    {
6892       Symbol _class = type.thisClass;
6893       if((type.classObjectType == typedObject || type.classObjectType == classPointer) || (_class && !strcmp(_class.string, "class")))
6894       {
6895          if(type.classObjectType == classPointer)
6896             strcat(string, "class");
6897          else
6898             strcat(string, type.byReference ? "typed_object&" : "typed_object");
6899       }
6900       else if(_class && _class.string)
6901       {
6902          String s = _class.string;
6903          if(fullName)
6904             strcat(string, s);
6905          else
6906          {
6907             char * name = RSearchString(s, "::", strlen(s), true, false);
6908             if(name) name += 2; else name = s;
6909             strcat(string, name);
6910          }
6911       }
6912       strcat(string, "::");
6913    }
6914
6915    if(printName && type.name)
6916       PrintName(type, string, fullName);
6917    PostPrintType(type, string, fullName);
6918    if(type.bitFieldCount)
6919    {
6920       char count[100];
6921       sprintf(count, ":%d", type.bitFieldCount);
6922       strcat(string, count);
6923    }
6924 }
6925
6926 void PrintType(Type type, char * string, bool printName, bool fullName)
6927 {
6928    _PrintType(type, string, printName, fullName, true);
6929 }
6930
6931 void PrintTypeNoConst(Type type, char * string, bool printName, bool fullName)
6932 {
6933    _PrintType(type, string, printName, fullName, false);
6934 }
6935
6936 static Type FindMember(Type type, char * string)
6937 {
6938    Type memberType;
6939    for(memberType = type.members.first; memberType; memberType = memberType.next)
6940    {
6941       if(!memberType.name)
6942       {
6943          Type subType = FindMember(memberType, string);
6944          if(subType)
6945             return subType;
6946       }
6947       else if(!strcmp(memberType.name, string))
6948          return memberType;
6949    }
6950    return null;
6951 }
6952
6953 Type FindMemberAndOffset(Type type, char * string, uint * offset)
6954 {
6955    Type memberType;
6956    for(memberType = type.members.first; memberType; memberType = memberType.next)
6957    {
6958       if(!memberType.name)
6959       {
6960          Type subType = FindMember(memberType, string);
6961          if(subType)
6962          {
6963             *offset += memberType.offset;
6964             return subType;
6965          }
6966       }
6967       else if(!strcmp(memberType.name, string))
6968       {
6969          *offset += memberType.offset;
6970          return memberType;
6971       }
6972    }
6973    return null;
6974 }
6975
6976 public bool GetParseError() { return parseError; }
6977
6978 Expression ParseExpressionString(char * expression)
6979 {
6980    parseError = false;
6981
6982    fileInput = TempFile { };
6983    fileInput.Write(expression, 1, strlen(expression));
6984    fileInput.Seek(0, start);
6985
6986    echoOn = false;
6987    parsedExpression = null;
6988    resetScanner();
6989    expression_yyparse();
6990    delete fileInput;
6991
6992    return parsedExpression;
6993 }
6994
6995 static bool ResolveIdWithClass(Expression exp, Class _class, bool skipIDClassCheck)
6996 {
6997    Identifier id = exp.identifier;
6998    Method method = null;
6999    Property prop = null;
7000    DataMember member = null;
7001    ClassProperty classProp = null;
7002
7003    if(_class && _class.type == enumClass)
7004    {
7005       NamedLink value = null;
7006       Class enumClass = eSystem_FindClass(privateModule, "enum");
7007       if(enumClass)
7008       {
7009          Class baseClass;
7010          for(baseClass = _class; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
7011          {
7012             EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
7013             for(value = e.values.first; value; value = value.next)
7014             {
7015                if(!strcmp(value.name, id.string))
7016                   break;
7017             }
7018             if(value)
7019             {
7020                char constant[256];
7021
7022                FreeExpContents(exp);
7023
7024                exp.type = constantExp;
7025                exp.isConstant = true;
7026                if(!strcmp(baseClass.dataTypeString, "int"))
7027                   sprintf(constant, "%d",(int)value.data);
7028                else
7029                   sprintf(constant, "0x%X",(int)value.data);
7030                exp.constant = CopyString(constant);
7031                //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
7032                exp.expType = MkClassType(baseClass.fullName);
7033                break;
7034             }
7035          }
7036       }
7037       if(value)
7038          return true;
7039    }
7040    if((method = eClass_FindMethod(_class, id.string, privateModule)))
7041    {
7042       ProcessMethodType(method);
7043       exp.expType = Type
7044       {
7045          refCount = 1;
7046          kind = methodType;
7047          method = method;
7048          // Crash here?
7049          // TOCHECK: Put it back to what it was...
7050          // methodClass = _class;
7051          methodClass = (skipIDClassCheck || (id && id._class)) ? _class : null;
7052       };
7053       //id._class = null;
7054       return true;
7055    }
7056    else if((prop = eClass_FindProperty(_class, id.string, privateModule)))
7057    {
7058       if(!prop.dataType)
7059          ProcessPropertyType(prop);
7060       exp.expType = prop.dataType;
7061       if(prop.dataType) prop.dataType.refCount++;
7062       return true;
7063    }
7064    else if((member = eClass_FindDataMember(_class, id.string, privateModule, null, null)))
7065    {
7066       if(!member.dataType)
7067          member.dataType = ProcessTypeString(member.dataTypeString, false);
7068       exp.expType = member.dataType;
7069       if(member.dataType) member.dataType.refCount++;
7070       return true;
7071    }
7072    else if((classProp = eClass_FindClassProperty(_class, id.string)))
7073    {
7074       if(!classProp.dataType)
7075          classProp.dataType = ProcessTypeString(classProp.dataTypeString, false);
7076
7077       if(classProp.constant)
7078       {
7079          FreeExpContents(exp);
7080
7081          exp.isConstant = true;
7082          if(classProp.dataType.kind == pointerType && classProp.dataType.type.kind == charType)
7083          {
7084             //char constant[256];
7085             exp.type = stringExp;
7086             exp.constant = QMkString((char *)classProp.Get(_class));
7087          }
7088          else
7089          {
7090             char constant[256];
7091             exp.type = constantExp;
7092             sprintf(constant, "%d", (int)classProp.Get(_class));
7093             exp.constant = CopyString(constant);
7094          }
7095       }
7096       else
7097       {
7098          // TO IMPLEMENT...
7099       }
7100
7101       exp.expType = classProp.dataType;
7102       if(classProp.dataType) classProp.dataType.refCount++;
7103       return true;
7104    }
7105    return false;
7106 }
7107
7108 static GlobalData ScanGlobalData(NameSpace nameSpace, char * name)
7109 {
7110    BinaryTree * tree = &nameSpace.functions;
7111    GlobalData data = (GlobalData)tree->FindString(name);
7112    NameSpace * child;
7113    if(!data)
7114    {
7115       for(child = (NameSpace *)nameSpace.nameSpaces.first; child; child = (NameSpace *)((BTNode)child).next)
7116       {
7117          data = ScanGlobalData(child, name);
7118          if(data)
7119             break;
7120       }
7121    }
7122    return data;
7123 }
7124
7125 static GlobalData FindGlobalData(char * name)
7126 {
7127    int start = 0, c;
7128    NameSpace * nameSpace;
7129    nameSpace = globalData;
7130    for(c = 0; name[c]; c++)
7131    {
7132       if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
7133       {
7134          NameSpace * newSpace;
7135          char * spaceName = new char[c - start + 1];
7136          strncpy(spaceName, name + start, c - start);
7137          spaceName[c-start] = '\0';
7138          newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
7139          delete spaceName;
7140          if(!newSpace)
7141             return null;
7142          nameSpace = newSpace;
7143          if(name[c] == ':') c++;
7144          start = c+1;
7145       }
7146    }
7147    if(c - start)
7148    {
7149       return ScanGlobalData(nameSpace, name + start);
7150    }
7151    return null;
7152 }
7153
7154 static int definedExpStackPos;
7155 static void * definedExpStack[512];
7156
7157 // This function makes checkedExp equivalent to newExp, ending up freeing newExp
7158 void ReplaceExpContents(Expression checkedExp, Expression newExp)
7159 {
7160    Expression prev = checkedExp.prev, next = checkedExp.next;
7161
7162    FreeExpContents(checkedExp);
7163    FreeType(checkedExp.expType);
7164    FreeType(checkedExp.destType);
7165
7166    *checkedExp = *newExp;
7167
7168    delete newExp;
7169
7170    checkedExp.prev = prev;
7171    checkedExp.next = next;
7172 }
7173
7174 void ApplyAnyObjectLogic(Expression e)
7175 {
7176    Type destType = /*(e.destType && e.destType.kind == ellipsisType) ? ellipsisDestType : */e.destType;
7177 #ifdef _DEBUG
7178    char debugExpString[4096];
7179    debugExpString[0] = '\0';
7180    PrintExpression(e, debugExpString);
7181 #endif
7182
7183    if(destType && (/*destType.classObjectType == ClassObjectType::typedObject || */destType.classObjectType == anyObject))
7184    {
7185       //if(e.destType && e.destType.kind == ellipsisType) usedEllipsis = true;
7186       //ellipsisDestType = destType;
7187       if(e && e.expType)
7188       {
7189          Type type = e.expType;
7190          Class _class = null;
7191          //Type destType = e.destType;
7192
7193          if(type.kind == classType && type._class && type._class.registered)
7194          {
7195             _class = type._class.registered;
7196          }
7197          else if(type.kind == subClassType)
7198          {
7199             _class = FindClass("ecere::com::Class").registered;
7200          }
7201          else
7202          {
7203             char string[1024] = "";
7204             Symbol classSym;
7205
7206             PrintTypeNoConst(type, string, false, true);
7207             classSym = FindClass(string);
7208             if(classSym) _class = classSym.registered;
7209          }
7210
7211          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...
7212             (!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))) ||
7213             destType.byReference)))
7214          {
7215             if(!_class || strcmp(_class.fullName, "char *"))     // TESTING THIS WITH NEW String class...
7216             {
7217                Expression checkedExp = e, newExp;
7218
7219                while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7220                {
7221                   if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7222                   {
7223                      if(checkedExp.type == extensionCompoundExp)
7224                      {
7225                         checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7226                      }
7227                      else
7228                         checkedExp = checkedExp.list->last;
7229                   }
7230                   else if(checkedExp.type == castExp)
7231                      checkedExp = checkedExp.cast.exp;
7232                }
7233
7234                if(checkedExp && checkedExp.type == opExp && checkedExp.op.op == '*' && !checkedExp.op.exp1)
7235                {
7236                   newExp = checkedExp.op.exp2;
7237                   checkedExp.op.exp2 = null;
7238                   FreeExpContents(checkedExp);
7239
7240                   if(e.expType && e.expType.passAsTemplate)
7241                   {
7242                      char size[100];
7243                      ComputeTypeSize(e.expType);
7244                      sprintf(size, "%d", e.expType.size);
7245                      newExp = MkExpBrackets(MkListOne(MkExpOp(MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)),
7246                         MkDeclaratorPointer(MkPointer(null, null), null)), newExp), '+',
7247                            MkExpCall(MkExpIdentifier(MkIdentifier("__ENDIAN_PAD")), MkListOne(MkExpConstant(size))))));
7248                   }
7249
7250                   ReplaceExpContents(checkedExp, newExp);
7251                   e.byReference = true;
7252                }
7253                else if(!e.byReference || (_class && _class.type == noHeadClass))     // TESTING THIS HERE...
7254                {
7255                   Expression checkedExp, newExp;
7256
7257                   {
7258                      // TODO: Move code from debugTools.ec for hasAddress flag, this is just temporary
7259                      bool hasAddress =
7260                         e.type == identifierExp ||
7261                         (e.type == ExpressionType::memberExp && e.member.memberType == dataMember) ||
7262                         (e.type == ExpressionType::pointerExp && e.member.memberType == dataMember) ||
7263                         (e.type == opExp && !e.op.exp1 && e.op.op == '*') ||
7264                         e.type == indexExp;
7265
7266                      if(_class && _class.type != noHeadClass && _class.type != normalClass && _class.type != structClass && !hasAddress)
7267                      {
7268                         Context context = PushContext();
7269                         Declarator decl;
7270                         OldList * specs = MkList();
7271                         char typeString[1024];
7272                         Expression newExp { };
7273
7274                         typeString[0] = '\0';
7275                         *newExp = *e;
7276
7277                         //if(e.destType) e.destType.refCount++;
7278                         // if(exp.expType) exp.expType.refCount++;
7279                         newExp.prev = null;
7280                         newExp.next = null;
7281                         newExp.expType = null;
7282
7283                         PrintTypeNoConst(e.expType, typeString, false, true);
7284                         decl = SpecDeclFromString(typeString, specs, null);
7285                         newExp.destType = ProcessType(specs, decl);
7286
7287                         curContext = context;
7288
7289                         // We need a current compound for this
7290                         if(curCompound)
7291                         {
7292                            char name[100];
7293                            OldList * stmts = MkList();
7294                            e.type = extensionCompoundExp;
7295                            sprintf(name, "__internalValue%03X", internalValueCounter++);
7296                            if(!curCompound.compound.declarations)
7297                               curCompound.compound.declarations = MkList();
7298                            curCompound.compound.declarations->Insert(null, MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(name)), null))));
7299                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(name)), '=', newExp))));
7300                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier(name)))));
7301                            e.compound = MkCompoundStmt(null, stmts);
7302                         }
7303                         else
7304                            printf("libec: compiler error, curCompound is null in ApplyAnyObjectLogic\n");
7305
7306                         /*
7307                         e.compound = MkCompoundStmt(
7308                            MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(
7309                               MkDeclaratorIdentifier(MkIdentifier("__internalValue")), MkInitializerAssignment(newExp))))),
7310
7311                            MkListOne(MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier("__internalValue"))))));
7312                         */
7313
7314                         {
7315                            Type type = e.destType;
7316                            e.destType = { };
7317                            CopyTypeInto(e.destType, type);
7318                            e.destType.refCount = 1;
7319                            e.destType.classObjectType = none;
7320                            FreeType(type);
7321                         }
7322
7323                         e.compound.compound.context = context;
7324                         PopContext(context);
7325                         curContext = context.parent;
7326                      }
7327                   }
7328
7329                   // TODO: INTEGRATE THIS WITH VERSION ABOVE WHICH WAS ADDED TO ENCOMPASS OTHER CASE (*pointer)
7330                   checkedExp = e;
7331                   while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7332                   {
7333                      if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7334                      {
7335                         if(checkedExp.type == extensionCompoundExp)
7336                         {
7337                            checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7338                         }
7339                         else
7340                            checkedExp = checkedExp.list->last;
7341                      }
7342                      else if(checkedExp.type == castExp)
7343                         checkedExp = checkedExp.cast.exp;
7344                   }
7345                   {
7346                      Expression operand { };
7347                      operand = *checkedExp;
7348                      checkedExp.destType = null;
7349                      checkedExp.expType = null;
7350                      checkedExp.Clear();
7351                      checkedExp.type = opExp;
7352                      checkedExp.op.op = '&';
7353                      checkedExp.op.exp1 = null;
7354                      checkedExp.op.exp2 = operand;
7355
7356                      //newExp = MkExpOp(null, '&', checkedExp);
7357                   }
7358                   //ReplaceExpContents(checkedExp, newExp);
7359                }
7360             }
7361          }
7362       }
7363    }
7364    {
7365       // If expression type is a simple class, make it an address
7366       // FixReference(e, true);
7367    }
7368 //#if 0
7369    if((!destType || destType.kind == ellipsisType || destType.kind == voidType) && e.expType && (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7370       (e.expType.byReference || (e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7371          (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass ) )))
7372    {
7373       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"))
7374       {
7375          return;  // LEAVE THIS CASE (typed_object & :: methods 's this) TO PASS 2 FOR NOW
7376       }
7377       else
7378       {
7379          Expression thisExp { };
7380
7381          *thisExp = *e;
7382          thisExp.prev = null;
7383          thisExp.next = null;
7384          e.Clear();
7385
7386          e.type = bracketsExp;
7387          e.list = MkListOne(MkExpOp(null, '*', thisExp.type == identifierExp ? thisExp : MkExpBrackets(MkListOne(thisExp))));
7388          if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && thisExp.expType._class.registered.type == noHeadClass)
7389             ((Expression)e.list->first).byReference = true;
7390
7391          /*if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && !strcmp(thisExp.expType._class.registered.name, "class"))
7392          {
7393             e.expType = thisExp.expType;
7394             e.expType.refCount++;
7395          }
7396          else*/
7397          {
7398             e.expType = { };
7399             CopyTypeInto(e.expType, thisExp.expType);
7400             e.expType.byReference = false;
7401             e.expType.refCount = 1;
7402
7403             if(e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7404                (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass))
7405             {
7406                e.expType.classObjectType = none;
7407             }
7408          }
7409       }
7410    }
7411 // TOFIX: Try this for a nice IDE crash!
7412 //#endif
7413    // The other way around
7414    else
7415 //#endif
7416    if(destType && e.expType &&
7417          //e.expType.kind == classType && e.expType._class && e.expType._class.registered && !strcmp(e.expType._class.registered.name, "class") &&
7418          (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7419          !destType.classObjectType && /*(destType.kind != pointerType || !destType.type || destType.type.kind != voidType) &&*/ destType.kind != voidType)
7420    {
7421       if(destType.kind == ellipsisType)
7422       {
7423          Compiler_Error($"Unspecified type\n");
7424       }
7425       else if(!(destType.truth && e.expType.kind == classType && e.expType._class && e.expType._class.registered && e.expType._class.registered.type == structClass))
7426       {
7427          bool byReference = e.expType.byReference;
7428          Expression thisExp { };
7429          Declarator decl;
7430          OldList * specs = MkList();
7431          char typeString[1024]; // Watch buffer overruns
7432          Type type;
7433          ClassObjectType backupClassObjectType;
7434          bool backupByReference;
7435
7436          if(e.expType.kind == classType && e.expType._class && e.expType._class.registered && strcmp(e.expType._class.registered.name, "class"))
7437             type = e.expType;
7438          else
7439             type = destType;
7440
7441          backupClassObjectType = type.classObjectType;
7442          backupByReference = type.byReference;
7443
7444          type.classObjectType = none;
7445          type.byReference = false;
7446
7447          typeString[0] = '\0';
7448          PrintType(type, typeString, false, true);
7449          decl = SpecDeclFromString(typeString, specs, null);
7450
7451          type.classObjectType = backupClassObjectType;
7452          type.byReference = backupByReference;
7453
7454          *thisExp = *e;
7455          thisExp.prev = null;
7456          thisExp.next = null;
7457          e.Clear();
7458
7459          if( ( type.kind == classType && type._class && type._class.registered &&
7460                    (type._class.registered.type == systemClass || type._class.registered.type == bitClass ||
7461                     type._class.registered.type == enumClass || type._class.registered.type == unitClass) ) ||
7462              (type.kind != pointerType && type.kind != intPtrType && type.kind != arrayType && type.kind != classType) ||
7463              (!destType.byReference && byReference && (destType.kind != pointerType || type.kind != pointerType)))
7464          {
7465             e.type = opExp;
7466             e.op.op = '*';
7467             e.op.exp1 = null;
7468             e.op.exp2 = MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), thisExp);
7469
7470             e.expType = { };
7471             CopyTypeInto(e.expType, type);
7472             e.expType.byReference = false;
7473             e.expType.refCount = 1;
7474          }
7475          else
7476          {
7477             e.type = castExp;
7478             e.cast.typeName = MkTypeName(specs, decl);
7479             e.cast.exp = thisExp;
7480             e.byReference = true;
7481             e.expType = type;
7482             type.refCount++;
7483          }
7484          e.destType = destType;
7485          destType.refCount++;
7486       }
7487    }
7488 }
7489
7490 void ProcessExpressionType(Expression exp)
7491 {
7492    bool unresolved = false;
7493    Location oldyylloc = yylloc;
7494    bool notByReference = false;
7495 #ifdef _DEBUG
7496    char debugExpString[4096];
7497    debugExpString[0] = '\0';
7498    PrintExpression(exp, debugExpString);
7499 #endif
7500    if(!exp || exp.expType)
7501       return;
7502
7503    //eSystem_Logf("%s\n", expString);
7504
7505    // Testing this here
7506    yylloc = exp.loc;
7507    switch(exp.type)
7508    {
7509       case identifierExp:
7510       {
7511          Identifier id = exp.identifier;
7512          if(!id || !topContext) return;
7513
7514          // DOING THIS LATER NOW...
7515          if(id._class && id._class.name)
7516          {
7517             id.classSym = id._class.symbol; // FindClass(id._class.name);
7518             /* TODO: Name Space Fix ups
7519             if(!id.classSym)
7520                id.nameSpace = eSystem_FindNameSpace(privateModule, id._class.name);
7521             */
7522          }
7523
7524          /* WHY WAS THIS COMMENTED OUT? if(!strcmp(id.string, "__thisModule"))
7525          {
7526             exp.expType = ProcessTypeString("Module", true);
7527             break;
7528          }
7529          else */if(strstr(id.string, "__ecereClass") == id.string)
7530          {
7531             exp.expType = ProcessTypeString("ecere::com::Class", true);
7532             break;
7533          }
7534          else if(id._class && (id.classSym || (id._class.name && !strcmp(id._class.name, "property"))))
7535          {
7536             // Added this here as well
7537             ReplaceClassMembers(exp, thisClass);
7538             if(exp.type != identifierExp)
7539             {
7540                ProcessExpressionType(exp);
7541                break;
7542             }
7543
7544             if(id.classSym && ResolveIdWithClass(exp, id.classSym.registered, false))
7545                break;
7546          }
7547          else
7548          {
7549             Symbol symbol = FindSymbol(id.string, curContext, topContext /*exp.destType ? topContext : globalContext*/, false, id._class && id._class.name == null);
7550             // Enums should be resolved here (Special pass in opExp to fix identifiers not seen as enum on the first pass)
7551             if(!symbol/* && exp.destType*/)
7552             {
7553                if(exp.destType && CheckExpressionType(exp, exp.destType, false))
7554                   break;
7555                else
7556                {
7557                   if(thisClass)
7558                   {
7559                      ReplaceClassMembers(exp, thisClass ? thisClass : currentClass);
7560                      if(exp.type != identifierExp)
7561                      {
7562                         ProcessExpressionType(exp);
7563                         break;
7564                      }
7565                   }
7566                   // Static methods called from inside the _class
7567                   else if(currentClass && !id._class)
7568                   {
7569                      if(ResolveIdWithClass(exp, currentClass, true))
7570                         break;
7571                   }
7572                   symbol = FindSymbol(id.string, topContext.parent, globalContext, false, id._class && id._class.name == null);
7573                }
7574             }
7575
7576             // If we manage to resolve this symbol
7577             if(symbol)
7578             {
7579                Type type = symbol.type;
7580                Class _class = (type && type.kind == classType && type._class) ? type._class.registered : null;
7581
7582                if(_class && !strcmp(id.string, "this") && !type.classObjectType)
7583                {
7584                   Context context = SetupTemplatesContext(_class);
7585                   type = ReplaceThisClassType(_class);
7586                   FinishTemplatesContext(context);
7587                   if(type) type.refCount = 0;   // We'll be incrementing it right below...
7588                }
7589
7590                FreeSpecifier(id._class);
7591                id._class = null;
7592                delete id.string;
7593                id.string = CopyString(symbol.string);
7594
7595                id.classSym = null;
7596                exp.expType = type;
7597                if(type)
7598                   type.refCount++;
7599                if(type && (type.kind == enumType || (_class && _class.type == enumClass)))
7600                   // Add missing cases here... enum Classes...
7601                   exp.isConstant = true;
7602
7603                // TOCHECK: Why was !strcmp(id.string, "this") commented out?
7604                if(symbol.isParam || !strcmp(id.string, "this"))
7605                {
7606                   if(_class && _class.type == structClass && !type.declaredWithStruct)
7607                      exp.byReference = true;
7608
7609                   //TESTING COMMENTING THIS OUT IN FAVOR OF ApplyAnyObjectLogic
7610                   /*if(type && _class && (type.classObjectType == typedObject || type.classObjectType == anyObject) &&
7611                      ((_class.type == unitClass || _class.type == enumClass || _class.type == bitClass) ||
7612                      (type.byReference && (_class.type == normalClass || _class.type == noHeadClass))))
7613                   {
7614                      Identifier id = exp.identifier;
7615                      exp.type = bracketsExp;
7616                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(id)));
7617                   }*/
7618                }
7619
7620                if(symbol.isIterator)
7621                {
7622                   if(symbol.isIterator == 3)
7623                   {
7624                      exp.type = bracketsExp;
7625                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(exp.identifier)));
7626                      ((Expression)exp.list->first).op.exp2.expType = exp.expType;
7627                      exp.expType = null;
7628                      ProcessExpressionType(exp);
7629                   }
7630                   else if(symbol.isIterator != 4)
7631                   {
7632                      exp.type = memberExp;
7633                      exp.member.exp = MkExpIdentifier(exp.identifier);
7634                      exp.member.exp.expType = exp.expType;
7635                      /*if(symbol.isIterator == 6)
7636                         exp.member.member = MkIdentifier("key");
7637                      else*/
7638                         exp.member.member = MkIdentifier("data");
7639                      exp.expType = null;
7640                      ProcessExpressionType(exp);
7641                   }
7642                }
7643                break;
7644             }
7645             else
7646             {
7647                DefinedExpression definedExp = null;
7648                if(thisNameSpace && !(id._class && !id._class.name))
7649                {
7650                   char name[1024];
7651                   strcpy(name, thisNameSpace);
7652                   strcat(name, "::");
7653                   strcat(name, id.string);
7654                   definedExp = eSystem_FindDefine(privateModule, name);
7655                }
7656                if(!definedExp)
7657                   definedExp = eSystem_FindDefine(privateModule, id.string);
7658                if(definedExp)
7659                {
7660                   int c;
7661                   for(c = 0; c<definedExpStackPos; c++)
7662                      if(definedExpStack[c] == definedExp)
7663                         break;
7664                   if(c == definedExpStackPos && c < sizeof(definedExpStack) / sizeof(void *))
7665                   {
7666                      Location backupYylloc = yylloc;
7667                      File backInput = fileInput;
7668                      definedExpStack[definedExpStackPos++] = definedExp;
7669
7670                      fileInput = TempFile { };
7671                      fileInput.Write(definedExp.value, 1, strlen(definedExp.value));
7672                      fileInput.Seek(0, start);
7673
7674                      echoOn = false;
7675                      parsedExpression = null;
7676                      resetScanner();
7677                      expression_yyparse();
7678                      delete fileInput;
7679                      if(backInput)
7680                         fileInput = backInput;
7681
7682                      yylloc = backupYylloc;
7683
7684                      if(parsedExpression)
7685                      {
7686                         FreeIdentifier(id);
7687                         exp.type = bracketsExp;
7688                         exp.list = MkListOne(parsedExpression);
7689                         parsedExpression.loc = yylloc;
7690                         ProcessExpressionType(exp);
7691                         definedExpStackPos--;
7692                         return;
7693                      }
7694                      definedExpStackPos--;
7695                   }
7696                   else
7697                   {
7698                      if(inCompiler)
7699                      {
7700                         Compiler_Error($"Recursion in defined expression %s\n", id.string);
7701                      }
7702                   }
7703                }
7704                else
7705                {
7706                   GlobalData data = null;
7707                   if(thisNameSpace && !(id._class && !id._class.name))
7708                   {
7709                      char name[1024];
7710                      strcpy(name, thisNameSpace);
7711                      strcat(name, "::");
7712                      strcat(name, id.string);
7713                      data = FindGlobalData(name);
7714                   }
7715                   if(!data)
7716                      data = FindGlobalData(id.string);
7717                   if(data)
7718                   {
7719                      DeclareGlobalData(data);
7720                      exp.expType = data.dataType;
7721                      if(data.dataType) data.dataType.refCount++;
7722
7723                      delete id.string;
7724                      id.string = CopyString(data.fullName);
7725                      FreeSpecifier(id._class);
7726                      id._class = null;
7727
7728                      break;
7729                   }
7730                   else
7731                   {
7732                      GlobalFunction function = null;
7733                      if(thisNameSpace && !(id._class && !id._class.name))
7734                      {
7735                         char name[1024];
7736                         strcpy(name, thisNameSpace);
7737                         strcat(name, "::");
7738                         strcat(name, id.string);
7739                         function = eSystem_FindFunction(privateModule, name);
7740                      }
7741                      if(!function)
7742                         function = eSystem_FindFunction(privateModule, id.string);
7743                      if(function)
7744                      {
7745                         char name[1024];
7746                         delete id.string;
7747                         id.string = CopyString(function.name);
7748                         name[0] = 0;
7749
7750                         if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
7751                            strcpy(name, "__ecereFunction_");
7752                         FullClassNameCat(name, id.string, false); // Why is this using FullClassNameCat ?
7753                         if(DeclareFunction(function, name))
7754                         {
7755                            delete id.string;
7756                            id.string = CopyString(name);
7757                         }
7758                         exp.expType = function.dataType;
7759                         if(function.dataType) function.dataType.refCount++;
7760
7761                         FreeSpecifier(id._class);
7762                         id._class = null;
7763
7764                         break;
7765                      }
7766                   }
7767                }
7768             }
7769          }
7770          unresolved = true;
7771          break;
7772       }
7773       case instanceExp:
7774       {
7775          Class _class;
7776          // Symbol classSym;
7777
7778          if(!exp.instance._class)
7779          {
7780             if(exp.destType && exp.destType.kind == classType && exp.destType._class)
7781             {
7782                exp.instance._class = MkSpecifierName(exp.destType._class.string);
7783             }
7784          }
7785
7786          //classSym = FindClass(exp.instance._class.fullName);
7787          //_class = classSym ? classSym.registered : null;
7788
7789          ProcessInstantiationType(exp.instance);
7790          exp.isConstant = exp.instance.isConstant;
7791
7792          /*
7793          if(_class.type == unitClass && _class.base.type != systemClass)
7794          {
7795             {
7796                Type destType = exp.destType;
7797
7798                exp.destType = MkClassType(_class.base.fullName);
7799                exp.expType = MkClassType(_class.fullName);
7800                CheckExpressionType(exp, exp.destType, true);
7801
7802                exp.destType = destType;
7803             }
7804             exp.expType = MkClassType(_class.fullName);
7805          }
7806          else*/
7807          if(exp.instance._class)
7808          {
7809             exp.expType = MkClassType(exp.instance._class.name);
7810             /*if(exp.expType._class && exp.expType._class.registered &&
7811                (exp.expType._class.registered.type == normalClass || exp.expType._class.registered.type == noHeadClass))
7812                exp.expType.byReference = true;*/
7813          }
7814          break;
7815       }
7816       case constantExp:
7817       {
7818          if(!exp.expType)
7819          {
7820             char * constant = exp.constant;
7821             Type type
7822             {
7823                refCount = 1;
7824                constant = true;
7825             };
7826             exp.expType = type;
7827
7828             if(constant[0] == '\'')
7829             {
7830                if((int)((byte *)constant)[1] > 127)
7831                {
7832                   int nb;
7833                   unichar ch = UTF8GetChar(constant + 1, &nb);
7834                   if(nb < 2) ch = constant[1];
7835                   delete constant;
7836                   exp.constant = PrintUInt(ch);
7837                   // type.kind = (ch > 0xFFFF) ? intType : shortType;
7838                   type.kind = classType; //(ch > 0xFFFF) ? intType : shortType;
7839                   type._class = FindClass("unichar");
7840
7841                   type.isSigned = false;
7842                }
7843                else
7844                {
7845                   type.kind = charType;
7846                   type.isSigned = true;
7847                }
7848             }
7849             else
7850             {
7851                char * dot = strchr(constant, '.');
7852                bool isHex = (constant[0] == '0' && (constant[1] == 'x' || constant[1] == 'X'));
7853                char * exponent;
7854                if(isHex)
7855                {
7856                   exponent = strchr(constant, 'p');
7857                   if(!exponent) exponent = strchr(constant, 'P');
7858                }
7859                else
7860                {
7861                   exponent = strchr(constant, 'e');
7862                   if(!exponent) exponent = strchr(constant, 'E');
7863                }
7864
7865                if(dot || exponent)
7866                {
7867                   if(strchr(constant, 'f') || strchr(constant, 'F'))
7868                      type.kind = floatType;
7869                   else
7870                      type.kind = doubleType;
7871                   type.isSigned = true;
7872                }
7873                else
7874                {
7875                   bool isSigned = constant[0] == '-';
7876                   int64 i64 = strtoll(constant, null, 0);
7877                   uint64 ui64 = strtoull(constant, null, 0);
7878                   bool is64Bit = false;
7879                   if(isSigned)
7880                   {
7881                      if(i64 < MININT)
7882                         is64Bit = true;
7883                   }
7884                   else
7885                   {
7886                      if(ui64 > MAXINT)
7887                      {
7888                         if(ui64 > MAXDWORD)
7889                         {
7890                            is64Bit = true;
7891                            if(ui64 <= MAXINT64 && (constant[0] != '0' || !constant[1]))
7892                               isSigned = true;
7893                         }
7894                      }
7895                      else if(constant[0] != '0' || !constant[1])
7896                         isSigned = true;
7897                   }
7898                   type.kind = is64Bit ? int64Type : intType;
7899                   type.isSigned = isSigned;
7900                }
7901             }
7902             exp.isConstant = true;
7903             if(exp.destType && exp.destType.kind == doubleType)
7904                type.kind = doubleType;
7905             else if(exp.destType && exp.destType.kind == floatType)
7906                type.kind = floatType;
7907             else if(exp.destType && exp.destType.kind == int64Type)
7908                type.kind = int64Type;
7909          }
7910          break;
7911       }
7912       case stringExp:
7913       {
7914          exp.isConstant = true;      // Why wasn't this constant?
7915          exp.expType = Type
7916          {
7917             refCount = 1;
7918             kind = pointerType;
7919             type = Type
7920             {
7921                refCount = 1;
7922                kind = charType;
7923                constant = true;
7924                isSigned = true;
7925             }
7926          };
7927          break;
7928       }
7929       case newExp:
7930       case new0Exp:
7931          ProcessExpressionType(exp._new.size);
7932          exp.expType = Type
7933          {
7934             refCount = 1;
7935             kind = pointerType;
7936             type = ProcessType(exp._new.typeName.qualifiers, exp._new.typeName.declarator);
7937          };
7938          DeclareType(exp.expType.type, false, false);
7939          break;
7940       case renewExp:
7941       case renew0Exp:
7942          ProcessExpressionType(exp._renew.size);
7943          ProcessExpressionType(exp._renew.exp);
7944          exp.expType = Type
7945          {
7946             refCount = 1;
7947             kind = pointerType;
7948             type = ProcessType(exp._renew.typeName.qualifiers, exp._renew.typeName.declarator);
7949          };
7950          DeclareType(exp.expType.type, false, false);
7951          break;
7952       case opExp:
7953       {
7954          bool assign = false, boolResult = false, boolOps = false;
7955          Type type1 = null, type2 = null;
7956          bool useDestType = false, useSideType = false;
7957          Location oldyylloc = yylloc;
7958          bool useSideUnit = false;
7959
7960          // Dummy type to prevent ProcessExpression of operands to say unresolved identifiers yet
7961          Type dummy
7962          {
7963             count = 1;
7964             refCount = 1;
7965          };
7966
7967          switch(exp.op.op)
7968          {
7969             // Assignment Operators
7970             case '=':
7971             case MUL_ASSIGN:
7972             case DIV_ASSIGN:
7973             case MOD_ASSIGN:
7974             case ADD_ASSIGN:
7975             case SUB_ASSIGN:
7976             case LEFT_ASSIGN:
7977             case RIGHT_ASSIGN:
7978             case AND_ASSIGN:
7979             case XOR_ASSIGN:
7980             case OR_ASSIGN:
7981                assign = true;
7982                break;
7983             // boolean Operators
7984             case '!':
7985                // Expect boolean operators
7986                //boolOps = true;
7987                //boolResult = true;
7988                break;
7989             case AND_OP:
7990             case OR_OP:
7991                // Expect boolean operands
7992                boolOps = true;
7993                boolResult = true;
7994                break;
7995             // Comparisons
7996             case EQ_OP:
7997             case '<':
7998             case '>':
7999             case LE_OP:
8000             case GE_OP:
8001             case NE_OP:
8002                // Gives boolean result
8003                boolResult = true;
8004                useSideType = true;
8005                break;
8006             case '+':
8007             case '-':
8008                useSideUnit = true;
8009
8010                // Just added these... testing
8011             case '|':
8012             case '&':
8013             case '^':
8014
8015             // DANGER: Verify units
8016             case '/':
8017             case '%':
8018             case '*':
8019
8020                if(exp.op.op != '*' || exp.op.exp1)
8021                {
8022                   useSideType = true;
8023                   useDestType = true;
8024                }
8025                break;
8026
8027             /*// Implement speed etc.
8028             case '*':
8029             case '/':
8030                break;
8031             */
8032          }
8033          if(exp.op.op == '&')
8034          {
8035             // Added this here earlier for Iterator address as key
8036             if(!exp.op.exp1 && exp.op.exp2 && exp.op.exp2.type == identifierExp && exp.op.exp2.identifier)
8037             {
8038                Identifier id = exp.op.exp2.identifier;
8039                Symbol symbol = FindSymbol(id.string, curContext, topContext, false, id._class && id._class.name == null);
8040                if(symbol && symbol.isIterator == 2)
8041                {
8042                   exp.type = memberExp;
8043                   exp.member.exp = exp.op.exp2;
8044                   exp.member.member = MkIdentifier("key");
8045                   exp.expType = null;
8046                   exp.op.exp2.expType = symbol.type;
8047                   symbol.type.refCount++;
8048                   ProcessExpressionType(exp);
8049                   FreeType(dummy);
8050                   break;
8051                }
8052                // exp.op.exp2.usage.usageRef = true;
8053             }
8054          }
8055
8056          //dummy.kind = TypeDummy;
8057
8058          if(exp.op.exp1)
8059          {
8060             if(exp.destType && exp.destType.kind == classType &&
8061                exp.destType._class && exp.destType._class.registered && useDestType &&
8062
8063               ((exp.destType._class.registered.type == unitClass && useSideUnit) ||
8064                exp.destType._class.registered.type == enumClass ||
8065                exp.destType._class.registered.type == bitClass
8066                ))
8067
8068               //(exp.destType._class.registered.type == unitClass || exp.destType._class.registered.type == enumClass) && useDestType)
8069             {
8070                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8071                exp.op.exp1.destType = exp.destType;
8072                if(exp.destType)
8073                   exp.destType.refCount++;
8074             }
8075             else if(!assign)
8076             {
8077                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8078                exp.op.exp1.destType = dummy;
8079                dummy.refCount++;
8080             }
8081
8082             // TESTING THIS HERE...
8083             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count++;
8084             ProcessExpressionType(exp.op.exp1);
8085             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count--;
8086
8087             if(exp.op.exp1.destType == dummy)
8088             {
8089                FreeType(dummy);
8090                exp.op.exp1.destType = null;
8091             }
8092             type1 = exp.op.exp1.expType;
8093          }
8094
8095          if(exp.op.exp2)
8096          {
8097             char expString[10240];
8098             expString[0] = '\0';
8099             if(exp.op.exp2.type == instanceExp && !exp.op.exp2.instance._class)
8100             {
8101                if(exp.op.exp1)
8102                {
8103                   exp.op.exp2.destType = exp.op.exp1.expType;
8104                   if(exp.op.exp1.expType)
8105                      exp.op.exp1.expType.refCount++;
8106                }
8107                else
8108                {
8109                   exp.op.exp2.destType = exp.destType;
8110                   if(exp.destType)
8111                      exp.destType.refCount++;
8112                }
8113
8114                if(type1) type1.refCount++;
8115                exp.expType = type1;
8116             }
8117             else if(assign)
8118             {
8119                if(inCompiler)
8120                   PrintExpression(exp.op.exp2, expString);
8121
8122                if(type1 && type1.kind == pointerType)
8123                {
8124                   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 ||
8125                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN)
8126                      Compiler_Error($"operator %s illegal on pointer\n", exp.op.op);
8127                   else if(exp.op.op == '=')
8128                   {
8129                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8130                      exp.op.exp2.destType = type1;
8131                      if(type1)
8132                         type1.refCount++;
8133                   }
8134                }
8135                else
8136                {
8137                   // Don't convert to the type for those... (e.g.: Degrees a; a /= 2;)
8138                   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/* ||
8139                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN*/);
8140                   else
8141                   {
8142                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8143                      exp.op.exp2.destType = type1;
8144                      if(type1)
8145                         type1.refCount++;
8146                   }
8147                }
8148                if(type1) type1.refCount++;
8149                exp.expType = type1;
8150             }
8151             else if(exp.destType && exp.destType.kind == classType &&
8152                exp.destType._class && exp.destType._class.registered &&
8153
8154                   ((exp.destType._class.registered.type == unitClass && useDestType && useSideUnit) ||
8155                   (exp.destType._class.registered.type == enumClass && useDestType))
8156                   )
8157             {
8158                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8159                exp.op.exp2.destType = exp.destType;
8160                if(exp.destType)
8161                   exp.destType.refCount++;
8162             }
8163             else
8164             {
8165                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8166                exp.op.exp2.destType = dummy;
8167                dummy.refCount++;
8168             }
8169
8170             // TESTING THIS HERE... (DANGEROUS)
8171             if(type1 && boolResult && useSideType && type1.kind == classType && type1._class && type1._class.registered &&
8172                (type1._class.registered.type == bitClass || type1._class.registered.type == enumClass))
8173             {
8174                FreeType(exp.op.exp2.destType);
8175                exp.op.exp2.destType = type1;
8176                type1.refCount++;
8177             }
8178             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count++;
8179             // Cannot lose the cast on a sizeof
8180             if(exp.op.op == SIZEOF)
8181             {
8182                Expression e = exp.op.exp2;
8183                while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
8184                {
8185                   if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
8186                   {
8187                      if(e.type == extensionCompoundExp)
8188                         e = ((Statement)e.compound.compound.statements->last).expressions->last;
8189                      else
8190                         e = e.list->last;
8191                   }
8192                }
8193                if(e.type == castExp && e.cast.exp)
8194                   e.cast.exp.needCast = true;
8195             }
8196             ProcessExpressionType(exp.op.exp2);
8197             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count--;
8198
8199             if(assign && type1 && type1.kind == pointerType && exp.op.exp2.expType)
8200             {
8201                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)
8202                {
8203                   if(exp.op.op != '=' && type1.type.kind == voidType)
8204                      Compiler_Error($"void *: unknown size\n");
8205                }
8206                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||
8207                            (type1.type.kind == voidType && exp.op.exp2.expType.kind == classType && exp.op.exp2.expType._class.registered &&
8208                               (exp.op.exp2.expType._class.registered.type == normalClass ||
8209                               exp.op.exp2.expType._class.registered.type == structClass ||
8210                               exp.op.exp2.expType._class.registered.type == noHeadClass)))
8211                {
8212                   if(exp.op.op == ADD_ASSIGN)
8213                      Compiler_Error($"cannot add two pointers\n");
8214                }
8215                else if((exp.op.exp2.expType.kind == classType && type1.kind == pointerType && type1.type.kind == classType &&
8216                   type1.type._class == exp.op.exp2.expType._class && exp.op.exp2.expType._class.registered && exp.op.exp2.expType._class.registered.type == structClass))
8217                {
8218                   if(exp.op.op == ADD_ASSIGN)
8219                      Compiler_Error($"cannot add two pointers\n");
8220                }
8221                else if(inCompiler)
8222                {
8223                   char type1String[1024];
8224                   char type2String[1024];
8225                   type1String[0] = '\0';
8226                   type2String[0] = '\0';
8227
8228                   PrintType(exp.op.exp2.expType, type1String, false, true);
8229                   PrintType(type1, type2String, false, true);
8230                   ChangeCh(expString, '\n', ' ');
8231                   Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1String, type2String);
8232                }
8233             }
8234
8235             if(exp.op.exp2.destType == dummy)
8236             {
8237                FreeType(dummy);
8238                exp.op.exp2.destType = null;
8239             }
8240
8241             if(exp.op.op == '-' && !exp.op.exp1 && exp.op.exp2.expType && !exp.op.exp2.expType.isSigned)
8242             {
8243                type2 = { };
8244                type2.refCount = 1;
8245                CopyTypeInto(type2, exp.op.exp2.expType);
8246                type2.isSigned = true;
8247             }
8248             else if(exp.op.op == '~' && !exp.op.exp1 && exp.op.exp2.expType && (!exp.op.exp2.expType.isSigned || exp.op.exp2.expType.kind != intType))
8249             {
8250                type2 = { kind = intType };
8251                type2.refCount = 1;
8252                type2.isSigned = true;
8253             }
8254             else
8255             {
8256                type2 = exp.op.exp2.expType;
8257                if(type2) type2.refCount++;
8258             }
8259          }
8260
8261          dummy.kind = voidType;
8262
8263          if(exp.op.op == SIZEOF)
8264          {
8265             exp.expType = Type
8266             {
8267                refCount = 1;
8268                kind = intType;
8269             };
8270             exp.isConstant = true;
8271          }
8272          // Get type of dereferenced pointer
8273          else if(exp.op.op == '*' && !exp.op.exp1)
8274          {
8275             exp.expType = Dereference(type2);
8276             if(type2 && type2.kind == classType)
8277                notByReference = true;
8278          }
8279          else if(exp.op.op == '&' && !exp.op.exp1)
8280             exp.expType = Reference(type2);
8281          else if(!assign)
8282          {
8283             if(boolOps)
8284             {
8285                if(exp.op.exp1)
8286                {
8287                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8288                   exp.op.exp1.destType = MkClassType("bool");
8289                   exp.op.exp1.destType.truth = true;
8290                   if(!exp.op.exp1.expType)
8291                      ProcessExpressionType(exp.op.exp1);
8292                   else
8293                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8294                   FreeType(exp.op.exp1.expType);
8295                   exp.op.exp1.expType = MkClassType("bool");
8296                   exp.op.exp1.expType.truth = true;
8297                }
8298                if(exp.op.exp2)
8299                {
8300                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8301                   exp.op.exp2.destType = MkClassType("bool");
8302                   exp.op.exp2.destType.truth = true;
8303                   if(!exp.op.exp2.expType)
8304                      ProcessExpressionType(exp.op.exp2);
8305                   else
8306                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8307                   FreeType(exp.op.exp2.expType);
8308                   exp.op.exp2.expType = MkClassType("bool");
8309                   exp.op.exp2.expType.truth = true;
8310                }
8311             }
8312             else if(exp.op.exp1 && exp.op.exp2 &&
8313                ((useSideType /*&&
8314                      (useSideUnit ||
8315                         ((!type1 || type1.kind != classType || type1._class.registered.type != unitClass) &&
8316                          (!type2 || type2.kind != classType || type2._class.registered.type != unitClass)))*/) ||
8317                   ((!type1 || type1.kind != classType || !strcmp(type1._class.string, "String")) &&
8318                   (!type2 || type2.kind != classType || !strcmp(type2._class.string, "String")))))
8319             {
8320                if(type1 && type2 &&
8321                   // If either both are class or both are not class
8322                   ((type1.kind == classType && type1._class && strcmp(type1._class.string, "String")) == (type2.kind == classType && type2._class && strcmp(type2._class.string, "String"))))
8323                {
8324                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8325                   exp.op.exp2.destType = type1;
8326                   type1.refCount++;
8327                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8328                   exp.op.exp1.destType = type2;
8329                   type2.refCount++;
8330                   // Warning here for adding Radians + Degrees with no destination type
8331                   if(!boolResult && type1.kind == classType && (!exp.destType || exp.destType.kind != classType) &&
8332                      type1._class.registered && type1._class.registered.type == unitClass &&
8333                      type2._class.registered && type2._class.registered.type == unitClass &&
8334                      type1._class.registered != type2._class.registered)
8335                      Compiler_Warning($"operating on %s and %s with an untyped result, assuming %s\n",
8336                         type1._class.string, type2._class.string, type1._class.string);
8337
8338                   if(type1.kind == pointerType && type1.type.kind == templateType && type2.kind != pointerType)
8339                   {
8340                      Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8341                      if(argExp)
8342                      {
8343                         Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8344
8345                         exp.op.exp1 = MkExpBrackets(MkListOne(MkExpCast(
8346                            MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
8347                            exp.op.exp1)));
8348
8349                         ProcessExpressionType(exp.op.exp1);
8350
8351                         if(type2.kind != pointerType)
8352                         {
8353                            ProcessExpressionType(classExp);
8354
8355                            exp.op.exp2 = MkExpBrackets(MkListOne(MkExpOp(exp.op.exp2, '*',
8356                               // ((_class.type == noHeadClass || _class.type == normalClass) ? sizeof(void *) : type.size)
8357                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(MkExpOp(
8358                                  // noHeadClass
8359                                  MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpConstant("5")),
8360                                     OR_OP,
8361                                  // normalClass
8362                                  MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpConstant("0"))))),
8363                                     MkListOne(MkExpTypeSize(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(
8364                                        MkPointer(null, null), null)))),
8365                                        MkExpMember(classExp, MkIdentifier("typeSize"))))))));
8366
8367                            if(!exp.op.exp2.expType)
8368                            {
8369                               if(type2)
8370                                  FreeType(type2);
8371                               type2 = exp.op.exp2.expType = ProcessTypeString("int", false);
8372                               type2.refCount++;
8373                            }
8374
8375                            ProcessExpressionType(exp.op.exp2);
8376                         }
8377                      }
8378                   }
8379
8380                   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)))
8381                   {
8382                      if(type1.kind != classType && type1.type.kind == voidType)
8383                         Compiler_Error($"void *: unknown size\n");
8384                      exp.expType = type1;
8385                      if(type1) type1.refCount++;
8386                   }
8387                   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)))
8388                   {
8389                      if(type2.kind != classType && type2.type.kind == voidType)
8390                         Compiler_Error($"void *: unknown size\n");
8391                      exp.expType = type2;
8392                      if(type2) type2.refCount++;
8393                   }
8394                   else if((type1.kind == pointerType && type2.kind != pointerType && type2.kind != arrayType && type2.kind != functionType && type2.kind != methodType && type2.kind != classType && type2.kind != subClassType) ||
8395                           (type2.kind == pointerType && type1.kind != pointerType && type1.kind != arrayType && type1.kind != functionType && type1.kind != methodType && type1.kind != classType && type1.kind != subClassType))
8396                   {
8397                      Compiler_Warning($"different levels of indirection\n");
8398                   }
8399                   else
8400                   {
8401                      bool success = false;
8402                      if(type1.kind == pointerType && type2.kind == pointerType)
8403                      {
8404                         if(exp.op.op == '+')
8405                            Compiler_Error($"cannot add two pointers\n");
8406                         else if(exp.op.op == '-')
8407                         {
8408                            // Pointer Subtraction gives integer
8409                            if(MatchTypes(type1.type, type2.type, null, null, null, false, false, false, false))
8410                            {
8411                               exp.expType = Type
8412                               {
8413                                  kind = intType;
8414                                  refCount = 1;
8415                               };
8416                               success = true;
8417
8418                               if(type1.type.kind == templateType)
8419                               {
8420                                  Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8421                                  if(argExp)
8422                                  {
8423                                     Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8424
8425                                     ProcessExpressionType(classExp);
8426
8427                                     exp.type = bracketsExp;
8428                                     exp.list = MkListOne(MkExpOp(
8429                                        MkExpBrackets(MkListOne(MkExpOp(
8430                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp1)))
8431                                              , exp.op.op,
8432                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp2)))))), '/',
8433
8434                                              //MkExpMember(classExp, MkIdentifier("typeSize"))
8435
8436                                              // ((_class.type == noHeadClass || _class.type == normalClass) ? sizeof(void *) : type.size)
8437                                              MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(MkExpOp(
8438                                                 // noHeadClass
8439                                                 MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpIdentifier(MkIdentifier("noHeadClass"))),
8440                                                    OR_OP,
8441                                                 // normalClass
8442                                                 MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpIdentifier(MkIdentifier("normalClass")))))),
8443                                                    MkListOne(MkExpTypeSize(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(
8444                                                       MkPointer(null, null), null)))),
8445                                                       MkExpMember(classExp, MkIdentifier("typeSize")))))
8446
8447
8448                                              ));
8449
8450                                     ProcessExpressionType(((Expression)exp.list->first).op.exp2);
8451                                     FreeType(dummy);
8452                                     return;
8453                                  }
8454                               }
8455                            }
8456                         }
8457                      }
8458
8459                      if(!success && exp.op.exp1.type == constantExp)
8460                      {
8461                         // If first expression is constant, try to match that first
8462                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8463                         {
8464                            if(exp.expType) FreeType(exp.expType);
8465                            exp.expType = exp.op.exp1.destType;
8466                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8467                            success = true;
8468                         }
8469                         else if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8470                         {
8471                            if(exp.expType) FreeType(exp.expType);
8472                            exp.expType = exp.op.exp2.destType;
8473                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8474                            success = true;
8475                         }
8476                      }
8477                      else if(!success)
8478                      {
8479                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8480                         {
8481                            if(exp.expType) FreeType(exp.expType);
8482                            exp.expType = exp.op.exp2.destType;
8483                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8484                            success = true;
8485                         }
8486                         else if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8487                         {
8488                            if(exp.expType) FreeType(exp.expType);
8489                            exp.expType = exp.op.exp1.destType;
8490                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8491                            success = true;
8492                         }
8493                      }
8494                      if(!success)
8495                      {
8496                         char expString1[10240];
8497                         char expString2[10240];
8498                         char type1[1024];
8499                         char type2[1024];
8500                         expString1[0] = '\0';
8501                         expString2[0] = '\0';
8502                         type1[0] = '\0';
8503                         type2[0] = '\0';
8504                         if(inCompiler)
8505                         {
8506                            PrintExpression(exp.op.exp1, expString1);
8507                            ChangeCh(expString1, '\n', ' ');
8508                            PrintExpression(exp.op.exp2, expString2);
8509                            ChangeCh(expString2, '\n', ' ');
8510                            PrintType(exp.op.exp1.expType, type1, false, true);
8511                            PrintType(exp.op.exp2.expType, type2, false, true);
8512                         }
8513
8514                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1, expString2, type2);
8515                      }
8516                   }
8517                }
8518                // ADDED THESE TWO FROM OUTSIDE useSideType CHECK
8519                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type2 && type1 && type2.kind == classType && type1.kind != classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
8520                {
8521                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8522                   // Convert e.g. / 4 into / 4.0
8523                   exp.op.exp1.destType = type2._class.registered.dataType;
8524                   if(type2._class.registered.dataType)
8525                      type2._class.registered.dataType.refCount++;
8526                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8527                   exp.expType = type2;
8528                   if(type2) type2.refCount++;
8529                }
8530                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type1 && type2 && type1.kind == classType && type2.kind != classType && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
8531                {
8532                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8533                   // Convert e.g. / 4 into / 4.0
8534                   exp.op.exp2.destType = type1._class.registered.dataType;
8535                   if(type1._class.registered.dataType)
8536                      type1._class.registered.dataType.refCount++;
8537                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8538                   exp.expType = type1;
8539                   if(type1) type1.refCount++;
8540                }
8541                else if(type1)
8542                {
8543                   bool valid = false;
8544
8545                   if(!boolResult && useSideUnit && type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8546                   {
8547                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8548
8549                      if(!type1._class.registered.dataType)
8550                         type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
8551                      exp.op.exp2.destType = type1._class.registered.dataType;
8552                      exp.op.exp2.destType.refCount++;
8553
8554                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8555                      if(type2)
8556                         FreeType(type2);
8557                      type2 = exp.op.exp2.destType;
8558                      if(type2) type2.refCount++;
8559
8560                      exp.expType = type2;
8561                      type2.refCount++;
8562                   }
8563
8564                   if(!boolResult && useSideUnit && type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8565                   {
8566                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8567
8568                      if(!type2._class.registered.dataType)
8569                         type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
8570                      exp.op.exp1.destType = type2._class.registered.dataType;
8571                      exp.op.exp1.destType.refCount++;
8572
8573                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8574                      type1 = exp.op.exp1.destType;
8575                      exp.expType = type1;
8576                      type1.refCount++;
8577                   }
8578
8579                   // TESTING THIS NEW CODE
8580                   if(!boolResult || exp.op.op == '>' || exp.op.op == '<')
8581                   {
8582                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass && exp.op.exp2.expType)
8583                      {
8584                         if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false))
8585                         {
8586                            if(exp.expType) FreeType(exp.expType);
8587                            exp.expType = exp.op.exp1.expType;
8588                            if(exp.op.exp2.expType) exp.op.exp1.expType.refCount++;
8589                            valid = true;
8590                         }
8591                      }
8592
8593                      else if(type2 && (type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass && exp.op.exp1.expType))
8594                      {
8595                         if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false))
8596                         {
8597                            if(exp.expType) FreeType(exp.expType);
8598                            exp.expType = exp.op.exp2.expType;
8599                            if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8600                            valid = true;
8601                         }
8602                      }
8603                   }
8604
8605                   if(!valid)
8606                   {
8607                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8608                      exp.op.exp2.destType = type1;
8609                      type1.refCount++;
8610
8611                      /*
8612                      // Maybe this was meant to be an enum...
8613                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
8614                      {
8615                         Type oldType = exp.op.exp2.expType;
8616                         exp.op.exp2.expType = null;
8617                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8618                            FreeType(oldType);
8619                         else
8620                            exp.op.exp2.expType = oldType;
8621                      }
8622                      */
8623
8624                      /*
8625                      // TESTING THIS HERE... LATEST ADDITION
8626                      if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8627                      {
8628                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8629                         exp.op.exp2.destType = type2._class.registered.dataType;
8630                         if(type2._class.registered.dataType)
8631                            type2._class.registered.dataType.refCount++;
8632                         CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8633
8634                         //exp.expType = type2._class.registered.dataType; //type2;
8635                         //if(type2) type2.refCount++;
8636                      }
8637
8638                      // TESTING THIS HERE... LATEST ADDITION
8639                      if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8640                      {
8641                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8642                         exp.op.exp1.destType = type1._class.registered.dataType;
8643                         if(type1._class.registered.dataType)
8644                            type1._class.registered.dataType.refCount++;
8645                         CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8646                         exp.expType = type1._class.registered.dataType; //type1;
8647                         if(type1) type1.refCount++;
8648                      }
8649                      */
8650
8651                      if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8652                      {
8653                         if(exp.expType) FreeType(exp.expType);
8654                         exp.expType = exp.op.exp2.destType;
8655                         if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8656                      }
8657                      else if(type1 && type2)
8658                      {
8659                         char expString1[10240];
8660                         char expString2[10240];
8661                         char type1String[1024];
8662                         char type2String[1024];
8663                         expString1[0] = '\0';
8664                         expString2[0] = '\0';
8665                         type1String[0] = '\0';
8666                         type2String[0] = '\0';
8667                         if(inCompiler)
8668                         {
8669                            PrintExpression(exp.op.exp1, expString1);
8670                            ChangeCh(expString1, '\n', ' ');
8671                            PrintExpression(exp.op.exp2, expString2);
8672                            ChangeCh(expString2, '\n', ' ');
8673                            PrintType(exp.op.exp1.expType, type1String, false, true);
8674                            PrintType(exp.op.exp2.expType, type2String, false, true);
8675                         }
8676
8677                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1String, expString2, type2String);
8678
8679                         if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
8680                         {
8681                            exp.expType = exp.op.exp1.expType;
8682                            if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8683                         }
8684                         else if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
8685                         {
8686                            exp.expType = exp.op.exp2.expType;
8687                            if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8688                         }
8689                      }
8690                   }
8691                }
8692                else if(type2)
8693                {
8694                   // Maybe this was meant to be an enum...
8695                   if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
8696                   {
8697                      Type oldType = exp.op.exp1.expType;
8698                      exp.op.exp1.expType = null;
8699                      if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8700                         FreeType(oldType);
8701                      else
8702                         exp.op.exp1.expType = oldType;
8703                   }
8704
8705                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8706                   exp.op.exp1.destType = type2;
8707                   type2.refCount++;
8708                   /*
8709                   // TESTING THIS HERE... LATEST ADDITION
8710                   if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8711                   {
8712                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8713                      exp.op.exp1.destType = type1._class.registered.dataType;
8714                      if(type1._class.registered.dataType)
8715                         type1._class.registered.dataType.refCount++;
8716                   }
8717
8718                   // TESTING THIS HERE... LATEST ADDITION
8719                   if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8720                   {
8721                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8722                      exp.op.exp2.destType = type2._class.registered.dataType;
8723                      if(type2._class.registered.dataType)
8724                         type2._class.registered.dataType.refCount++;
8725                   }
8726                   */
8727
8728                   if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8729                   {
8730                      if(exp.expType) FreeType(exp.expType);
8731                      exp.expType = exp.op.exp1.destType;
8732                      if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8733                   }
8734                }
8735             }
8736             else if(type2 && (!type1 || (type2.kind == classType && type1.kind != classType)))
8737             {
8738                if(type1 && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
8739                {
8740                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8741                   // Convert e.g. / 4 into / 4.0
8742                   exp.op.exp1.destType = type2._class.registered.dataType;
8743                   if(type2._class.registered.dataType)
8744                      type2._class.registered.dataType.refCount++;
8745                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8746                }
8747                if(exp.op.op == '!')
8748                {
8749                   exp.expType = MkClassType("bool");
8750                   exp.expType.truth = true;
8751                }
8752                else
8753                {
8754                   exp.expType = type2;
8755                   if(type2) type2.refCount++;
8756                }
8757             }
8758             else if(type1 && (!type2 || (type1.kind == classType && type2.kind != classType)))
8759             {
8760                if(type2 && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
8761                {
8762                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8763                   // Convert e.g. / 4 into / 4.0
8764                   exp.op.exp2.destType = type1._class.registered.dataType;
8765                   if(type1._class.registered.dataType)
8766                      type1._class.registered.dataType.refCount++;
8767                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8768                }
8769                exp.expType = type1;
8770                if(type1) type1.refCount++;
8771             }
8772          }
8773
8774          yylloc = exp.loc;
8775          if(exp.op.exp1 && !exp.op.exp1.expType)
8776          {
8777             char expString[10000];
8778             expString[0] = '\0';
8779             if(inCompiler)
8780             {
8781                PrintExpression(exp.op.exp1, expString);
8782                ChangeCh(expString, '\n', ' ');
8783             }
8784             if(expString[0])
8785                Compiler_Error($"couldn't determine type of %s\n", expString);
8786          }
8787          if(exp.op.exp2 && !exp.op.exp2.expType)
8788          {
8789             char expString[10240];
8790             expString[0] = '\0';
8791             if(inCompiler)
8792             {
8793                PrintExpression(exp.op.exp2, expString);
8794                ChangeCh(expString, '\n', ' ');
8795             }
8796             if(expString[0])
8797                Compiler_Error($"couldn't determine type of %s\n", expString);
8798          }
8799
8800          if(boolResult)
8801          {
8802             FreeType(exp.expType);
8803             exp.expType = MkClassType("bool");
8804             exp.expType.truth = true;
8805          }
8806
8807          if(exp.op.op != SIZEOF)
8808             exp.isConstant = (!exp.op.exp1 || exp.op.exp1.isConstant) &&
8809                (!exp.op.exp2 || exp.op.exp2.isConstant);
8810
8811          if(exp.op.op == SIZEOF && exp.op.exp2.expType)
8812          {
8813             DeclareType(exp.op.exp2.expType, false, false);
8814          }
8815
8816          yylloc = oldyylloc;
8817
8818          FreeType(dummy);
8819          if(type2)
8820             FreeType(type2);
8821          break;
8822       }
8823       case bracketsExp:
8824       case extensionExpressionExp:
8825       {
8826          Expression e;
8827          exp.isConstant = true;
8828          for(e = exp.list->first; e; e = e.next)
8829          {
8830             bool inced = false;
8831             if(!e.next)
8832             {
8833                FreeType(e.destType);
8834                e.destType = exp.destType;
8835                if(e.destType) { exp.destType.refCount++; e.destType.count++; inced = true; }
8836             }
8837             ProcessExpressionType(e);
8838             if(inced)
8839                exp.destType.count--;
8840             if(!exp.expType && !e.next)
8841             {
8842                exp.expType = e.expType;
8843                if(e.expType) e.expType.refCount++;
8844             }
8845             if(!e.isConstant)
8846                exp.isConstant = false;
8847          }
8848
8849          // In case a cast became a member...
8850          e = exp.list->first;
8851          if(!e.next && e.type == memberExp)
8852          {
8853             // Preserve prev, next
8854             Expression next = exp.next, prev = exp.prev;
8855
8856
8857             FreeType(exp.expType);
8858             FreeType(exp.destType);
8859             delete exp.list;
8860
8861             *exp = *e;
8862
8863             exp.prev = prev;
8864             exp.next = next;
8865
8866             delete e;
8867
8868             ProcessExpressionType(exp);
8869          }
8870          break;
8871       }
8872       case indexExp:
8873       {
8874          Expression e;
8875          exp.isConstant = true;
8876
8877          ProcessExpressionType(exp.index.exp);
8878          if(!exp.index.exp.isConstant)
8879             exp.isConstant = false;
8880
8881          if(exp.index.exp.expType)
8882          {
8883             Type source = exp.index.exp.expType;
8884             if(source.kind == classType && source._class && source._class.registered)
8885             {
8886                Class _class = source._class.registered;
8887                Class c = _class.templateClass ? _class.templateClass : _class;
8888                if(_class != containerClass && eClass_IsDerived(c, containerClass) && _class.templateArgs)
8889                {
8890                   exp.expType = ProcessTypeString(_class.templateArgs[2].dataTypeString, false);
8891
8892                   if(exp.index.index && exp.index.index->last)
8893                   {
8894                      ((Expression)exp.index.index->last).destType = ProcessTypeString(_class.templateArgs[1].dataTypeString, false);
8895                   }
8896                }
8897             }
8898          }
8899
8900          for(e = exp.index.index->first; e; e = e.next)
8901          {
8902             if(!e.next && exp.index.exp.expType && exp.index.exp.expType.kind == arrayType && exp.index.exp.expType.enumClass)
8903             {
8904                if(e.destType) FreeType(e.destType);
8905                e.destType = MkClassType(exp.index.exp.expType.enumClass.string);
8906             }
8907             ProcessExpressionType(e);
8908             if(!e.next)
8909             {
8910                // Check if this type is int
8911             }
8912             if(!e.isConstant)
8913                exp.isConstant = false;
8914          }
8915
8916          if(!exp.expType)
8917             exp.expType = Dereference(exp.index.exp.expType);
8918          if(exp.expType)
8919             DeclareType(exp.expType, false, false);
8920          break;
8921       }
8922       case callExp:
8923       {
8924          Expression e;
8925          Type functionType;
8926          Type methodType = null;
8927          char name[1024];
8928          name[0] = '\0';
8929
8930          if(inCompiler)
8931          {
8932             PrintExpression(exp.call.exp,  name);
8933             if(exp.call.exp.expType && !exp.call.exp.expType.returnType)
8934             {
8935                //exp.call.exp.expType = null;
8936                PrintExpression(exp.call.exp,  name);
8937             }
8938          }
8939          if(exp.call.exp.type == identifierExp)
8940          {
8941             Expression idExp = exp.call.exp;
8942             Identifier id = idExp.identifier;
8943             if(!strcmp(id.string, "__builtin_frame_address"))
8944             {
8945                exp.expType = ProcessTypeString("void *", true);
8946                if(exp.call.arguments && exp.call.arguments->first)
8947                   ProcessExpressionType(exp.call.arguments->first);
8948                break;
8949             }
8950             else if(!strcmp(id.string, "__ENDIAN_PAD"))
8951             {
8952                exp.expType = ProcessTypeString("int", true);
8953                if(exp.call.arguments && exp.call.arguments->first)
8954                   ProcessExpressionType(exp.call.arguments->first);
8955                break;
8956             }
8957             else if(!strcmp(id.string, "Max") ||
8958                !strcmp(id.string, "Min") ||
8959                !strcmp(id.string, "Sgn") ||
8960                !strcmp(id.string, "Abs"))
8961             {
8962                Expression a = null;
8963                Expression b = null;
8964                Expression tempExp1 = null, tempExp2 = null;
8965                if((!strcmp(id.string, "Max") ||
8966                   !strcmp(id.string, "Min")) && exp.call.arguments->count == 2)
8967                {
8968                   a = exp.call.arguments->first;
8969                   b = exp.call.arguments->last;
8970                   tempExp1 = a;
8971                   tempExp2 = b;
8972                }
8973                else if(exp.call.arguments->count == 1)
8974                {
8975                   a = exp.call.arguments->first;
8976                   tempExp1 = a;
8977                }
8978
8979                if(a)
8980                {
8981                   exp.call.arguments->Clear();
8982                   idExp.identifier = null;
8983
8984                   FreeExpContents(exp);
8985
8986                   ProcessExpressionType(a);
8987                   if(b)
8988                      ProcessExpressionType(b);
8989
8990                   exp.type = bracketsExp;
8991                   exp.list = MkList();
8992
8993                   if(a.expType && (!b || b.expType))
8994                   {
8995                      if((!a.isConstant && a.type != identifierExp) || (b && !b.isConstant && b.type != identifierExp))
8996                      {
8997                         // Use the simpleStruct name/ids for now...
8998                         if(inCompiler)
8999                         {
9000                            OldList * specs = MkList();
9001                            OldList * decls = MkList();
9002                            Declaration decl;
9003                            char temp1[1024], temp2[1024];
9004
9005                            GetTypeSpecs(a.expType, specs);
9006
9007                            if(a && !a.isConstant && a.type != identifierExp)
9008                            {
9009                               sprintf(temp1, "__simpleStruct%d", curContext.simpleID++);
9010                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp1)), null));
9011                               tempExp1 = QMkExpId(temp1);
9012                               tempExp1.expType = a.expType;
9013                               if(a.expType)
9014                                  a.expType.refCount++;
9015                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp1), '=', a));
9016                            }
9017                            if(b && !b.isConstant && b.type != identifierExp)
9018                            {
9019                               sprintf(temp2, "__simpleStruct%d", curContext.simpleID++);
9020                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp2)), null));
9021                               tempExp2 = QMkExpId(temp2);
9022                               tempExp2.expType = b.expType;
9023                               if(b.expType)
9024                                  b.expType.refCount++;
9025                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp2), '=', b));
9026                            }
9027
9028                            decl = MkDeclaration(specs, decls);
9029                            if(!curCompound.compound.declarations)
9030                               curCompound.compound.declarations = MkList();
9031                            curCompound.compound.declarations->Insert(null, decl);
9032                         }
9033                      }
9034                   }
9035
9036                   if(!strcmp(id.string, "Max") || !strcmp(id.string, "Min"))
9037                   {
9038                      int op = (!strcmp(id.string, "Max")) ? '>' : '<';
9039                      ListAdd(exp.list,
9040                         MkExpCondition(MkExpBrackets(MkListOne(
9041                            MkExpOp(CopyExpression(tempExp1), op, CopyExpression(tempExp2)))),
9042                            MkListOne(CopyExpression(tempExp1)), CopyExpression(tempExp2)));
9043                      exp.expType = a.expType;
9044                      if(a.expType)
9045                         a.expType.refCount++;
9046                   }
9047                   else if(!strcmp(id.string, "Abs"))
9048                   {
9049                      ListAdd(exp.list,
9050                         MkExpCondition(MkExpBrackets(MkListOne(
9051                            MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9052                            MkListOne(MkExpOp(null, '-', CopyExpression(tempExp1))), CopyExpression(tempExp1)));
9053                      exp.expType = a.expType;
9054                      if(a.expType)
9055                         a.expType.refCount++;
9056                   }
9057                   else if(!strcmp(id.string, "Sgn"))
9058                   {
9059                      // ((!(a))?(0):(((a)<0)?(-1):(1)))
9060                      ListAdd(exp.list,
9061                         MkExpCondition(MkExpBrackets(MkListOne(
9062                            MkExpOp(null, '!', CopyExpression(tempExp1)))), MkListOne(MkExpConstant("0")),
9063                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(
9064                                  MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9065                                  MkListOne(MkExpConstant("-1")), MkExpConstant("1"))))));
9066                      exp.expType = ProcessTypeString("int", false);
9067                   }
9068
9069                   FreeExpression(tempExp1);
9070                   if(tempExp2) FreeExpression(tempExp2);
9071
9072                   FreeIdentifier(id);
9073                   break;
9074                }
9075             }
9076          }
9077
9078          {
9079             Type dummy
9080             {
9081                count = 1;
9082                refCount = 1;
9083             };
9084             if(!exp.call.exp.destType)
9085             {
9086                exp.call.exp.destType = dummy;
9087                dummy.refCount++;
9088             }
9089             ProcessExpressionType(exp.call.exp);
9090             if(exp.call.exp.destType == dummy)
9091             {
9092                FreeType(dummy);
9093                exp.call.exp.destType = null;
9094             }
9095             FreeType(dummy);
9096          }
9097
9098          // Check argument types against parameter types
9099          functionType = exp.call.exp.expType;
9100
9101          if(functionType && functionType.kind == TypeKind::methodType)
9102          {
9103             methodType = functionType;
9104             functionType = methodType.method.dataType;
9105
9106             //if(functionType.returnType && functionType.returnType.kind == thisClassType)
9107             // TOCHECK: Instead of doing this here could this be done per param?
9108             if(exp.call.exp.expType.usedClass)
9109             {
9110                char typeString[1024];
9111                typeString[0] = '\0';
9112                {
9113                   Symbol back = functionType.thisClass;
9114                   // Do not output class specifier here (thisclass was added to this)
9115                   functionType.thisClass = null;
9116                   PrintType(functionType, typeString, true, true);
9117                   functionType.thisClass = back;
9118                }
9119                if(strstr(typeString, "thisclass"))
9120                {
9121                   OldList * specs = MkList();
9122                   Declarator decl;
9123                   {
9124                      Context context = SetupTemplatesContext(exp.call.exp.expType.usedClass);
9125
9126                      decl = SpecDeclFromString(typeString, specs, null);
9127
9128                      // SET THIS TO FALSE WHEN PROCESSING THISCLASS OUTSIDE THE CLASS
9129                      if(thisClass != (exp.call.exp.expType.usedClass.templateClass ? exp.call.exp.expType.usedClass.templateClass :
9130                         exp.call.exp.expType.usedClass))
9131                         thisClassParams = false;
9132
9133                      ReplaceThisClassSpecifiers(specs, exp.call.exp.expType.usedClass);
9134                      {
9135                         Class backupThisClass = thisClass;
9136                         thisClass = exp.call.exp.expType.usedClass;
9137                         ProcessDeclarator(decl);
9138                         thisClass = backupThisClass;
9139                      }
9140
9141                      thisClassParams = true;
9142
9143                      functionType = ProcessType(specs, decl);
9144                      functionType.refCount = 0;
9145                      FinishTemplatesContext(context);
9146                   }
9147
9148                   FreeList(specs, FreeSpecifier);
9149                   FreeDeclarator(decl);
9150                 }
9151             }
9152          }
9153          if(functionType && functionType.kind == pointerType && functionType.type && functionType.type.kind == TypeKind::functionType)
9154          {
9155             Type type = functionType.type;
9156             if(!functionType.refCount)
9157             {
9158                functionType.type = null;
9159                FreeType(functionType);
9160             }
9161             //methodType = functionType;
9162             functionType = type;
9163          }
9164          if(functionType && functionType.kind != TypeKind::functionType)
9165          {
9166             Compiler_Error($"called object %s is not a function\n", name);
9167          }
9168          else if(functionType)
9169          {
9170             bool emptyParams = false, noParams = false;
9171             Expression e = exp.call.arguments ? exp.call.arguments->first : null;
9172             Type type = functionType.params.first;
9173             Expression memberExp = (exp.call.exp.type == ExpressionType::memberExp) ? exp.call.exp : null;
9174             int extra = 0;
9175             Location oldyylloc = yylloc;
9176
9177             if(!type) emptyParams = true;
9178
9179             // WORKING ON THIS:
9180             if(functionType.extraParam && e && functionType.thisClass)
9181             {
9182                e.destType = MkClassType(functionType.thisClass.string);
9183                e = e.next;
9184             }
9185
9186             // WHY WAS THIS COMMENTED OUT ? Broke DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
9187             // Fixed #141 by adding '&& !functionType.extraParam'
9188             if(!functionType.staticMethod && !functionType.extraParam)
9189             {
9190                if(memberExp && memberExp.member.exp && memberExp.member.exp.expType && memberExp.member.exp.expType.kind == subClassType &&
9191                   memberExp.member.exp.expType._class)
9192                {
9193                   type = MkClassType(memberExp.member.exp.expType._class.string);
9194                   if(e)
9195                   {
9196                      e.destType = type;
9197                      e = e.next;
9198                      type = functionType.params.first;
9199                   }
9200                   else
9201                      type.refCount = 0;
9202                }
9203                else if(!memberExp && (functionType.thisClass || (methodType && methodType.methodClass)))
9204                {
9205                   type = MkClassType(functionType.thisClass ? functionType.thisClass.string : (methodType ? methodType.methodClass.fullName : null));
9206                   type.byReference = functionType.byReference;
9207                   type.typedByReference = functionType.typedByReference;
9208                   if(e)
9209                   {
9210                      // Allow manually passing a class for typed object
9211                      if(e.next && type.kind == classType && (functionType && functionType.thisClass) && functionType.classObjectType == typedObject)
9212                         e = e.next;
9213                      e.destType = type;
9214                      e = e.next;
9215                      type = functionType.params.first;
9216                   }
9217                   else
9218                      type.refCount = 0;
9219                   //extra = 1;
9220                }
9221             }
9222
9223             if(type && type.kind == voidType)
9224             {
9225                noParams = true;
9226                if(!type.refCount) FreeType(type);
9227                type = null;
9228             }
9229
9230             for( ; e; e = e.next)
9231             {
9232                if(!type && !emptyParams)
9233                {
9234                   yylloc = e.loc;
9235                   if(methodType && methodType.methodClass)
9236                      Compiler_Error($"too many arguments for method %s::%s (%d given, expected %d)\n",
9237                         methodType.methodClass.fullName, methodType.method.name, exp.call.arguments->count,
9238                         noParams ? 0 : functionType.params.count);
9239                   else
9240                      Compiler_Error($"too many arguments for function %s (%d given, expected %d)\n",
9241                         name /*exp.call.exp.identifier.string*/, exp.call.arguments->count,
9242                         noParams ? 0 : functionType.params.count);
9243                   break;
9244                }
9245
9246                if(methodType && type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type)
9247                {
9248                   Type templatedType = null;
9249                   Class _class = methodType.usedClass;
9250                   ClassTemplateParameter curParam = null;
9251                   int id = 0;
9252                   if(_class && _class.templateArgs /*&& _class.templateClass*/)
9253                   {
9254                      Class sClass;
9255                      for(sClass = _class; sClass; sClass = sClass.base)
9256                      {
9257                         if(sClass.templateClass) sClass = sClass.templateClass;
9258                         id = 0;
9259                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9260                         {
9261                            if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
9262                            {
9263                               Class nextClass;
9264                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
9265                               {
9266                                  if(nextClass.templateClass) nextClass = nextClass.templateClass;
9267                                  id += nextClass.templateParams.count;
9268                               }
9269                               break;
9270                            }
9271                            id++;
9272                         }
9273                         if(curParam) break;
9274                      }
9275                   }
9276                   if(curParam && _class.templateArgs[id].dataTypeString)
9277                   {
9278                      ClassTemplateArgument arg = _class.templateArgs[id];
9279                      {
9280                         Context context = SetupTemplatesContext(_class);
9281
9282                         /*if(!arg.dataType)
9283                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9284                         templatedType = ProcessTypeString(arg.dataTypeString, false);
9285                         FinishTemplatesContext(context);
9286                      }
9287                      e.destType = templatedType;
9288                      if(templatedType)
9289                      {
9290                         templatedType.passAsTemplate = true;
9291                         // templatedType.refCount++;
9292                      }
9293                   }
9294                   else
9295                   {
9296                      e.destType = type;
9297                      if(type) type.refCount++;
9298                   }
9299                }
9300                else
9301                {
9302                   if(type && type.kind == ellipsisType && type.prev && type.prev.kind == classType && type.prev.classObjectType)
9303                   {
9304                      e.destType = type.prev;
9305                      e.destType.refCount++;
9306                   }
9307                   else
9308                   {
9309                      e.destType = type;
9310                      if(type) type.refCount++;
9311                   }
9312                }
9313                // Don't reach the end for the ellipsis
9314                if(type && type.kind != ellipsisType)
9315                {
9316                   Type next = type.next;
9317                   if(!type.refCount) FreeType(type);
9318                   type = next;
9319                }
9320             }
9321
9322             if(type && type.kind != ellipsisType)
9323             {
9324                if(methodType && methodType.methodClass)
9325                   Compiler_Warning($"not enough arguments for method %s::%s (%d given, expected %d)\n",
9326                      methodType.methodClass.fullName, methodType.method.name, exp.call.arguments ? exp.call.arguments->count : 0,
9327                      functionType.params.count + extra);
9328                else
9329                   Compiler_Warning($"not enough arguments for function %s (%d given, expected %d)\n",
9330                      name /*exp.call.exp.identifier.string*/, exp.call.arguments ? exp.call.arguments->count : 0,
9331                      functionType.params.count + extra);
9332             }
9333             yylloc = oldyylloc;
9334             if(type && !type.refCount) FreeType(type);
9335          }
9336          else
9337          {
9338             functionType = Type
9339             {
9340                refCount = 0;
9341                kind = TypeKind::functionType;
9342             };
9343
9344             if(exp.call.exp.type == identifierExp)
9345             {
9346                char * string = exp.call.exp.identifier.string;
9347                if(inCompiler)
9348                {
9349                   Symbol symbol;
9350                   Location oldyylloc = yylloc;
9351
9352                   yylloc = exp.call.exp.identifier.loc;
9353                   if(strstr(string, "__builtin_") == string)
9354                   {
9355                      if(exp.destType)
9356                      {
9357                         functionType.returnType = exp.destType;
9358                         exp.destType.refCount++;
9359                      }
9360                   }
9361                   else
9362                      Compiler_Warning($"%s undefined; assuming extern returning int\n", string);
9363                   symbol = Symbol { string = CopyString(string), type = ProcessTypeString("int()", true) };
9364                   globalContext.symbols.Add((BTNode)symbol);
9365                   if(strstr(symbol.string, "::"))
9366                      globalContext.hasNameSpace = true;
9367
9368                   yylloc = oldyylloc;
9369                }
9370             }
9371             else if(exp.call.exp.type == memberExp)
9372             {
9373                /*Compiler_Warning($"%s undefined; assuming returning int\n",
9374                   exp.call.exp.member.member.string);*/
9375             }
9376             else
9377                Compiler_Warning($"callable object undefined; extern assuming returning int\n");
9378
9379             if(!functionType.returnType)
9380             {
9381                functionType.returnType = Type
9382                {
9383                   refCount = 1;
9384                   kind = intType;
9385                };
9386             }
9387          }
9388          if(functionType && functionType.kind == TypeKind::functionType)
9389          {
9390             exp.expType = functionType.returnType;
9391
9392             if(functionType.returnType)
9393                functionType.returnType.refCount++;
9394
9395             if(!functionType.refCount)
9396                FreeType(functionType);
9397          }
9398
9399          if(exp.call.arguments)
9400          {
9401             for(e = exp.call.arguments->first; e; e = e.next)
9402             {
9403                Type destType = e.destType;
9404                ProcessExpressionType(e);
9405             }
9406          }
9407          break;
9408       }
9409       case memberExp:
9410       {
9411          Type type;
9412          Location oldyylloc = yylloc;
9413          bool thisPtr;
9414          Expression checkExp = exp.member.exp;
9415          while(checkExp)
9416          {
9417             if(checkExp.type == castExp)
9418                checkExp = checkExp.cast.exp;
9419             else if(checkExp.type == bracketsExp)
9420                checkExp = checkExp.list ? checkExp.list->first : null;
9421             else
9422                break;
9423          }
9424
9425          thisPtr = (checkExp && checkExp.type == identifierExp && !strcmp(checkExp.identifier.string, "this"));
9426          exp.thisPtr = thisPtr;
9427
9428          // DOING THIS LATER NOW...
9429          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
9430          {
9431             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
9432             /* TODO: Name Space Fix ups
9433             if(!exp.member.member.classSym)
9434                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.fullName);
9435             */
9436          }
9437
9438          ProcessExpressionType(exp.member.exp);
9439          if(exp.member.exp.expType && exp.member.exp.expType.kind == classType && exp.member.exp.expType._class &&
9440             exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == normalClass)
9441          {
9442             exp.isConstant = false;
9443          }
9444          else
9445             exp.isConstant = exp.member.exp.isConstant;
9446          type = exp.member.exp.expType;
9447
9448          yylloc = exp.loc;
9449
9450          if(type && (type.kind == templateType))
9451          {
9452             Class _class = thisClass ? thisClass : currentClass;
9453             ClassTemplateParameter param = null;
9454             if(_class)
9455             {
9456                for(param = _class.templateParams.first; param; param = param.next)
9457                {
9458                   if(param.type == identifier && exp.member.member && exp.member.member.string && !strcmp(param.name, exp.member.member.string))
9459                      break;
9460                }
9461             }
9462             if(param && param.defaultArg.member)
9463             {
9464                Expression argExp = GetTemplateArgExpByName(param.name, thisClass, TemplateParameterType::identifier);
9465                if(argExp)
9466                {
9467                   Expression expMember = exp.member.exp;
9468                   Declarator decl;
9469                   OldList * specs = MkList();
9470                   char thisClassTypeString[1024];
9471
9472                   FreeIdentifier(exp.member.member);
9473
9474                   ProcessExpressionType(argExp);
9475
9476                   {
9477                      char * colon = strstr(param.defaultArg.memberString, "::");
9478                      if(colon)
9479                      {
9480                         char className[1024];
9481                         Class sClass;
9482
9483                         memcpy(thisClassTypeString, param.defaultArg.memberString, colon - param.defaultArg.memberString);
9484                         thisClassTypeString[colon - param.defaultArg.memberString] = '\0';
9485                      }
9486                      else
9487                         strcpy(thisClassTypeString, _class.fullName);
9488                   }
9489
9490                   decl = SpecDeclFromString(param.defaultArg.member.dataTypeString, specs, null);
9491
9492                   exp.expType = ProcessType(specs, decl);
9493                   if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.templateClass)
9494                   {
9495                      Class expClass = exp.expType._class.registered;
9496                      Class cClass = null;
9497                      int c;
9498                      int paramCount = 0;
9499                      int lastParam = -1;
9500
9501                      char templateString[1024];
9502                      ClassTemplateParameter param;
9503                      sprintf(templateString, "%s<", expClass.templateClass.fullName);
9504                      for(cClass = expClass; cClass; cClass = cClass.base)
9505                      {
9506                         int p = 0;
9507                         for(param = cClass.templateParams.first; param; param = param.next)
9508                         {
9509                            int id = p;
9510                            Class sClass;
9511                            ClassTemplateArgument arg;
9512                            for(sClass = cClass.base; sClass; sClass = sClass.base) id += sClass.templateParams.count;
9513                            arg = expClass.templateArgs[id];
9514
9515                            for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
9516                            {
9517                               ClassTemplateParameter cParam;
9518                               //int p = numParams - sClass.templateParams.count;
9519                               int p = 0;
9520                               Class nextClass;
9521                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) p += nextClass.templateParams.count;
9522
9523                               for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
9524                               {
9525                                  if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
9526                                  {
9527                                     if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9528                                     {
9529                                        arg.dataTypeString = _class.templateArgs[p].dataTypeString;
9530                                        arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
9531                                        break;
9532                                     }
9533                                  }
9534                               }
9535                            }
9536
9537                            {
9538                               char argument[256];
9539                               argument[0] = '\0';
9540                               /*if(arg.name)
9541                               {
9542                                  strcat(argument, arg.name.string);
9543                                  strcat(argument, " = ");
9544                               }*/
9545                               switch(param.type)
9546                               {
9547                                  case expression:
9548                                  {
9549                                     // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
9550                                     char expString[1024];
9551                                     OldList * specs = MkList();
9552                                     Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
9553                                     Expression exp;
9554                                     char * string = PrintHexUInt64(arg.expression.ui64);
9555                                     exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
9556                                     delete string;
9557
9558                                     ProcessExpressionType(exp);
9559                                     ComputeExpression(exp);
9560                                     expString[0] = '\0';
9561                                     PrintExpression(exp, expString);
9562                                     strcat(argument, expString);
9563                                     // delete exp;
9564                                     FreeExpression(exp);
9565                                     break;
9566                                  }
9567                                  case identifier:
9568                                  {
9569                                     strcat(argument, arg.member.name);
9570                                     break;
9571                                  }
9572                                  case TemplateParameterType::type:
9573                                  {
9574                                     if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9575                                     {
9576                                        if(!strcmp(arg.dataTypeString, "thisclass"))
9577                                           strcat(argument, thisClassTypeString);
9578                                        else
9579                                           strcat(argument, arg.dataTypeString);
9580                                     }
9581                                     break;
9582                                  }
9583                               }
9584                               if(argument[0])
9585                               {
9586                                  if(paramCount) strcat(templateString, ", ");
9587                                  if(lastParam != p - 1)
9588                                  {
9589                                     strcat(templateString, param.name);
9590                                     strcat(templateString, " = ");
9591                                  }
9592                                  strcat(templateString, argument);
9593                                  paramCount++;
9594                                  lastParam = p;
9595                               }
9596                               p++;
9597                            }
9598                         }
9599                      }
9600                      {
9601                         int len = strlen(templateString);
9602                         if(templateString[len-1] == '>') templateString[len++] = ' ';
9603                         templateString[len++] = '>';
9604                         templateString[len++] = '\0';
9605                      }
9606                      {
9607                         Context context = SetupTemplatesContext(_class);
9608                         FreeType(exp.expType);
9609                         exp.expType = ProcessTypeString(templateString, false);
9610                         FinishTemplatesContext(context);
9611                      }
9612                   }
9613
9614                   // *([expType] *)(((byte *)[exp.member.exp]) + [argExp].member.offset)
9615                   exp.type = bracketsExp;
9616                   exp.list = MkListOne(MkExpOp(null, '*',
9617                   /*opExp;
9618                   exp.op.op = '*';
9619                   exp.op.exp1 = null;
9620                   exp.op.exp2 = */
9621                   MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpBrackets(MkListOne(MkExpOp(
9622                      MkExpBrackets(MkListOne(
9623                         MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), expMember))),
9624                            '+',
9625                            MkExpOp(MkExpMember(MkExpMember(argExp, MkIdentifier("member")), MkIdentifier("offset")),
9626                            '+',
9627                            MkExpMember(MkExpMember(MkExpMember(CopyExpression(argExp), MkIdentifier("member")), MkIdentifier("_class")), MkIdentifier("offset")))))))
9628
9629                            ));
9630                }
9631             }
9632             else if(type.templateParameter && type.templateParameter.type == TemplateParameterType::type &&
9633                (type.templateParameter.dataType || type.templateParameter.dataTypeString))
9634             {
9635                type = ProcessTemplateParameterType(type.templateParameter);
9636             }
9637          }
9638          // TODO: *** This seems to be where we should add method support for all basic types ***
9639          if(type && (type.kind == templateType));
9640          else if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType ||
9641                           type.kind == int64Type || type.kind == shortType || type.kind == longType || type.kind == charType || type.kind == _BoolType ||
9642                           type.kind == intPtrType || type.kind == intSizeType || type.kind == floatType || type.kind == doubleType ||
9643                           (type.kind == pointerType && type.type.kind == charType)))
9644          {
9645             Identifier id = exp.member.member;
9646             TypeKind typeKind = type.kind;
9647             Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
9648             if(typeKind == subClassType && exp.member.exp.type == classExp)
9649             {
9650                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
9651                typeKind = classType;
9652             }
9653
9654             if(id)
9655             {
9656                if(typeKind == intType || typeKind == enumType)
9657                   _class = eSystem_FindClass(privateModule, "int");
9658                else if(!_class)
9659                {
9660                   if(type.kind == classType && type._class && type._class.registered)
9661                   {
9662                      _class = type._class.registered;
9663                   }
9664                   else if((type.kind == arrayType || type.kind == pointerType) && type.type && type.type.kind == charType)
9665                   {
9666                      _class = FindClass("char *").registered;
9667                   }
9668                   else if(type.kind == pointerType)
9669                   {
9670                      _class = eSystem_FindClass(privateModule, "uintptr");
9671                      FreeType(exp.expType);
9672                      exp.expType = ProcessTypeString("uintptr", false);
9673                      exp.byReference = true;
9674                   }
9675                   else
9676                   {
9677                      char string[1024] = "";
9678                      Symbol classSym;
9679                      PrintTypeNoConst(type, string, false, true);
9680                      classSym = FindClass(string);
9681                      if(classSym) _class = classSym.registered;
9682                   }
9683                }
9684             }
9685
9686             if(_class && id)
9687             {
9688                /*bool thisPtr =
9689                   (exp.member.exp.type == identifierExp &&
9690                   !strcmp(exp.member.exp.identifier.string, "this"));*/
9691                Property prop = null;
9692                Method method = null;
9693                DataMember member = null;
9694                Property revConvert = null;
9695                ClassProperty classProp = null;
9696
9697                if(id && id._class && id._class.name && !strcmp(id._class.name, "property"))
9698                   exp.member.memberType = propertyMember;
9699
9700                if(id && id._class && type._class && !eClass_IsDerived(type._class.registered, _class))
9701                   Compiler_Error($"invalid class specifier %s for object of class %s\n", _class.fullName, type._class.string);
9702
9703                if(typeKind != subClassType)
9704                {
9705                   // Prioritize data members over properties for "this"
9706                   if((exp.member.memberType == unresolvedMember && thisPtr) || exp.member.memberType == dataMember)
9707                   {
9708                      member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
9709                      if(member && member._class != (_class.templateClass ? _class.templateClass : _class) && exp.member.memberType != dataMember)
9710                      {
9711                         prop = eClass_FindProperty(_class, id.string, privateModule);
9712                         if(prop)
9713                            member = null;
9714                      }
9715                      if(!member && !prop)
9716                         prop = eClass_FindProperty(_class, id.string, privateModule);
9717                      if((member && member._class == (_class.templateClass ? _class.templateClass : _class)) ||
9718                         (prop && prop._class == (_class.templateClass ? _class.templateClass : _class)))
9719                         exp.member.thisPtr = true;
9720                   }
9721                   // Prioritize properties over data members otherwise
9722                   else
9723                   {
9724                      // First look for Public Members (Unless class specifier is provided, which skips public priority)
9725                      if(!id.classSym)
9726                      {
9727                         prop = eClass_FindProperty(_class, id.string, null);
9728                         if(!id._class || !id._class.name || strcmp(id._class.name, "property"))
9729                            member = eClass_FindDataMember(_class, id.string, null, null, null);
9730                      }
9731
9732                      if(!prop && !member)
9733                      {
9734                         method = eClass_FindMethod(_class, id.string, null);
9735                         if(!method)
9736                         {
9737                            prop = eClass_FindProperty(_class, id.string, privateModule);
9738                            if(!id._class || !id._class.name || strcmp(id._class.name, "property"))
9739                               member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
9740                         }
9741                      }
9742
9743                      if(member && prop)
9744                      {
9745                         if(member._class != prop._class && !id._class && eClass_IsDerived(member._class, prop._class))
9746                            prop = null;
9747                         else
9748                            member = null;
9749                      }
9750                   }
9751                }
9752                if(!prop && !member && !method)     // NOTE: Recently added the !method here, causes private methods to unprioritized
9753                   method = eClass_FindMethod(_class, id.string, privateModule);
9754                if(!prop && !member && !method)
9755                {
9756                   if(typeKind == subClassType)
9757                   {
9758                      classProp = eClass_FindClassProperty(type._class.registered, exp.member.member.string);
9759                      if(classProp)
9760                      {
9761                         exp.member.memberType = classPropertyMember;
9762                         exp.expType = ProcessTypeString(classProp.dataTypeString, false);
9763                      }
9764                      else
9765                      {
9766                         // Assume this is a class_data member
9767                         char structName[1024];
9768                         Identifier id = exp.member.member;
9769                         Expression classExp = exp.member.exp;
9770                         type.refCount++;
9771
9772                         FreeType(classExp.expType);
9773                         classExp.expType = ProcessTypeString("ecere::com::Class", false);
9774
9775                         strcpy(structName, "__ecereClassData_");
9776                         FullClassNameCat(structName, type._class.string, false);
9777                         exp.type = pointerExp;
9778                         exp.member.member = id;
9779
9780                         exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
9781                            MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
9782                               MkExpBrackets(MkListOne(MkExpOp(
9783                                  MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
9784                                     MkExpMember(classExp, MkIdentifier("data"))), '+',
9785                                        MkExpMember(MkExpClass(MkListOne(MkSpecifierName(type._class.string)), null), MkIdentifier("offsetClass")))))
9786                                  )));
9787
9788                         FreeType(type);
9789
9790                         ProcessExpressionType(exp);
9791                         return;
9792                      }
9793                   }
9794                   else
9795                   {
9796                      // Check for reverse conversion
9797                      // (Convert in an instantiation later, so that we can use
9798                      //  deep properties system)
9799                      Symbol classSym = FindClass(id.string);
9800                      if(classSym)
9801                      {
9802                         Class convertClass = classSym.registered;
9803                         if(convertClass)
9804                            revConvert = eClass_FindProperty(convertClass, _class.fullName, privateModule);
9805                      }
9806                   }
9807                }
9808
9809                if(prop)
9810                {
9811                   exp.member.memberType = propertyMember;
9812                   if(!prop.dataType)
9813                      ProcessPropertyType(prop);
9814                   exp.expType = prop.dataType;
9815                   if(prop.dataType) prop.dataType.refCount++;
9816                }
9817                else if(member)
9818                {
9819                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
9820                   {
9821                      FreeExpContents(exp);
9822                      exp.type = identifierExp;
9823                      exp.identifier = MkIdentifier("class");
9824                      ProcessExpressionType(exp);
9825                      return;
9826                   }
9827
9828                   exp.member.memberType = dataMember;
9829                   DeclareStruct(_class.fullName, false);
9830                   if(!member.dataType)
9831                   {
9832                      Context context = SetupTemplatesContext(_class);
9833                      member.dataType = ProcessTypeString(member.dataTypeString, false);
9834                      FinishTemplatesContext(context);
9835                   }
9836                   exp.expType = member.dataType;
9837                   if(member.dataType) member.dataType.refCount++;
9838                }
9839                else if(revConvert)
9840                {
9841                   exp.member.memberType = reverseConversionMember;
9842                   exp.expType = MkClassType(revConvert._class.fullName);
9843                }
9844                else if(method)
9845                {
9846                   //if(inCompiler)
9847                   {
9848                      /*if(id._class)
9849                      {
9850                         exp.type = identifierExp;
9851                         exp.identifier = exp.member.member;
9852                      }
9853                      else*/
9854                         exp.member.memberType = methodMember;
9855                   }
9856                   if(!method.dataType)
9857                      ProcessMethodType(method);
9858                   exp.expType = Type
9859                   {
9860                      refCount = 1;
9861                      kind = methodType;
9862                      method = method;
9863                   };
9864
9865                   // Tricky spot here... To use instance versus class virtual table
9866                   // Put it back to what it was... What did we break?
9867
9868                   // Had to put it back for overriding Main of Thread global instance
9869
9870                   //exp.expType.methodClass = _class;
9871                   exp.expType.methodClass = (id && id._class) ? _class : null;
9872
9873                   // Need the actual class used for templated classes
9874                   exp.expType.usedClass = _class;
9875                }
9876                else if(!classProp)
9877                {
9878                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
9879                   {
9880                      FreeExpContents(exp);
9881                      exp.type = identifierExp;
9882                      exp.identifier = MkIdentifier("class");
9883                      FreeType(exp.expType);
9884                      exp.expType = MkClassType("ecere::com::Class");
9885                      return;
9886                   }
9887                   yylloc = exp.member.member.loc;
9888                   Compiler_Error($"couldn't find member %s in class %s\n", id.string, _class.fullName);
9889                   if(inCompiler)
9890                      eClass_AddDataMember(_class, id.string, "int", 0, 0, publicAccess);
9891                }
9892
9893                if(_class && /*(_class.templateClass || _class.templateArgs) && */exp.expType)
9894                {
9895                   Class tClass;
9896
9897                   tClass = _class;
9898                   while(tClass && !tClass.templateClass) tClass = tClass.base;
9899
9900                   if(tClass && exp.expType.kind == templateType && exp.expType.templateParameter.type == TemplateParameterType::type)
9901                   {
9902                      int id = 0;
9903                      ClassTemplateParameter curParam = null;
9904                      Class sClass;
9905
9906                      for(sClass = tClass; sClass; sClass = sClass.base)
9907                      {
9908                         id = 0;
9909                         if(sClass.templateClass) sClass = sClass.templateClass;
9910                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9911                         {
9912                            if(curParam.type == TemplateParameterType::type && !strcmp(exp.expType.templateParameter.identifier.string, curParam.name))
9913                            {
9914                               for(sClass = sClass.base; sClass; sClass = sClass.base)
9915                                  id += sClass.templateParams.count;
9916                               break;
9917                            }
9918                            id++;
9919                         }
9920                         if(curParam) break;
9921                      }
9922
9923                      if(curParam && tClass.templateArgs[id].dataTypeString)
9924                      {
9925                         ClassTemplateArgument arg = tClass.templateArgs[id];
9926                         Context context = SetupTemplatesContext(tClass);
9927                         /*if(!arg.dataType)
9928                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9929                         FreeType(exp.expType);
9930                         exp.expType = ProcessTypeString(arg.dataTypeString, false);
9931                         if(exp.expType)
9932                         {
9933                            if(exp.expType.kind == thisClassType)
9934                            {
9935                               FreeType(exp.expType);
9936                               exp.expType = ReplaceThisClassType(_class);
9937                            }
9938
9939                            if(tClass.templateClass)
9940                               exp.expType.passAsTemplate = true;
9941                            //exp.expType.refCount++;
9942                            if(!exp.destType)
9943                            {
9944                               exp.destType = ProcessTypeString(arg.dataTypeString, false);
9945                               //exp.destType.refCount++;
9946
9947                               if(exp.destType.kind == thisClassType)
9948                               {
9949                                  FreeType(exp.destType);
9950                                  exp.destType = ReplaceThisClassType(_class);
9951                               }
9952                            }
9953                         }
9954                         FinishTemplatesContext(context);
9955                      }
9956                   }
9957                   // TODO: MORE GENERIC SUPPORT FOR DEEPER TYPES
9958                   else if(tClass && exp.expType.kind == pointerType && exp.expType.type && exp.expType.type.kind == templateType && exp.expType.type.templateParameter.type == TemplateParameterType::type)
9959                   {
9960                      int id = 0;
9961                      ClassTemplateParameter curParam = null;
9962                      Class sClass;
9963
9964                      for(sClass = tClass; sClass; sClass = sClass.base)
9965                      {
9966                         id = 0;
9967                         if(sClass.templateClass) sClass = sClass.templateClass;
9968                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9969                         {
9970                            if(curParam.type == TemplateParameterType::type &&
9971                               !strcmp(exp.expType.type.templateParameter.identifier.string, curParam.name))
9972                            {
9973                               for(sClass = sClass.base; sClass; sClass = sClass.base)
9974                                  id += sClass.templateParams.count;
9975                               break;
9976                            }
9977                            id++;
9978                         }
9979                         if(curParam) break;
9980                      }
9981
9982                      if(curParam)
9983                      {
9984                         ClassTemplateArgument arg = tClass.templateArgs[id];
9985                         Context context = SetupTemplatesContext(tClass);
9986                         Type basicType;
9987                         /*if(!arg.dataType)
9988                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9989
9990                         basicType = ProcessTypeString(arg.dataTypeString, false);
9991                         if(basicType)
9992                         {
9993                            if(basicType.kind == thisClassType)
9994                            {
9995                               FreeType(basicType);
9996                               basicType = ReplaceThisClassType(_class);
9997                            }
9998
9999                            /*    DO WE REALLY WANT THIS HERE? IT SEEMS TO BE ONLY USED WITH Array::array which was causing bug 135
10000                            if(tClass.templateClass)
10001                               basicType.passAsTemplate = true;
10002                            */
10003
10004                            FreeType(exp.expType);
10005
10006                            exp.expType = Type { refCount = 1, kind = pointerType, type = basicType };
10007                            //exp.expType.refCount++;
10008                            if(!exp.destType)
10009                            {
10010                               exp.destType = exp.expType;
10011                               exp.destType.refCount++;
10012                            }
10013
10014                            {
10015                               Expression newExp { };
10016                               OldList * specs = MkList();
10017                               Declarator decl;
10018                               decl = SpecDeclFromString(arg.dataTypeString, specs, null);
10019                               *newExp = *exp;
10020                               if(exp.destType) exp.destType.refCount++;
10021                               if(exp.expType)  exp.expType.refCount++;
10022                               exp.type = castExp;
10023                               exp.cast.typeName = MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl));
10024                               exp.cast.exp = newExp;
10025                               //FreeType(exp.expType);
10026                               //exp.expType = null;
10027                               //ProcessExpressionType(sourceExp);
10028                            }
10029                         }
10030                         FinishTemplatesContext(context);
10031                      }
10032                   }
10033                   else if(tClass && exp.expType.kind == classType && exp.expType._class && strchr(exp.expType._class.string, '<'))
10034                   {
10035                      Class expClass = exp.expType._class.registered;
10036                      if(expClass)
10037                      {
10038                         Class cClass = null;
10039                         int c;
10040                         int p = 0;
10041                         int paramCount = 0;
10042                         int lastParam = -1;
10043                         char templateString[1024];
10044                         ClassTemplateParameter param;
10045                         sprintf(templateString, "%s<", expClass.templateClass.fullName);
10046                         while(cClass != expClass)
10047                         {
10048                            Class sClass;
10049                            for(sClass = expClass; sClass && sClass.base != cClass; sClass = sClass.base);
10050                            cClass = sClass;
10051
10052                            for(param = cClass.templateParams.first; param; param = param.next)
10053                            {
10054                               Class cClassCur = null;
10055                               int c;
10056                               int cp = 0;
10057                               ClassTemplateParameter paramCur = null;
10058                               ClassTemplateArgument arg;
10059                               while(cClassCur != tClass && !paramCur)
10060                               {
10061                                  Class sClassCur;
10062                                  for(sClassCur = tClass; sClassCur && sClassCur.base != cClassCur; sClassCur = sClassCur.base);
10063                                  cClassCur = sClassCur;
10064
10065                                  for(paramCur = cClassCur.templateParams.first; paramCur; paramCur = paramCur.next)
10066                                  {
10067                                     if(!strcmp(paramCur.name, param.name))
10068                                     {
10069
10070                                        break;
10071                                     }
10072                                     cp++;
10073                                  }
10074                               }
10075                               if(paramCur && paramCur.type == TemplateParameterType::type)
10076                                  arg = tClass.templateArgs[cp];
10077                               else
10078                                  arg = expClass.templateArgs[p];
10079
10080                               {
10081                                  char argument[256];
10082                                  argument[0] = '\0';
10083                                  /*if(arg.name)
10084                                  {
10085                                     strcat(argument, arg.name.string);
10086                                     strcat(argument, " = ");
10087                                  }*/
10088                                  switch(param.type)
10089                                  {
10090                                     case expression:
10091                                     {
10092                                        // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
10093                                        char expString[1024];
10094                                        OldList * specs = MkList();
10095                                        Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
10096                                        Expression exp;
10097                                        char * string = PrintHexUInt64(arg.expression.ui64);
10098                                        exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
10099                                        delete string;
10100
10101                                        ProcessExpressionType(exp);
10102                                        ComputeExpression(exp);
10103                                        expString[0] = '\0';
10104                                        PrintExpression(exp, expString);
10105                                        strcat(argument, expString);
10106                                        // delete exp;
10107                                        FreeExpression(exp);
10108                                        break;
10109                                     }
10110                                     case identifier:
10111                                     {
10112                                        strcat(argument, arg.member.name);
10113                                        break;
10114                                     }
10115                                     case TemplateParameterType::type:
10116                                     {
10117                                        if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10118                                           strcat(argument, arg.dataTypeString);
10119                                        break;
10120                                     }
10121                                  }
10122                                  if(argument[0])
10123                                  {
10124                                     if(paramCount) strcat(templateString, ", ");
10125                                     if(lastParam != p - 1)
10126                                     {
10127                                        strcat(templateString, param.name);
10128                                        strcat(templateString, " = ");
10129                                     }
10130                                     strcat(templateString, argument);
10131                                     paramCount++;
10132                                     lastParam = p;
10133                                  }
10134                               }
10135                               p++;
10136                            }
10137                         }
10138                         {
10139                            int len = strlen(templateString);
10140                            if(templateString[len-1] == '>') templateString[len++] = ' ';
10141                            templateString[len++] = '>';
10142                            templateString[len++] = '\0';
10143                         }
10144
10145                         FreeType(exp.expType);
10146                         {
10147                            Context context = SetupTemplatesContext(tClass);
10148                            exp.expType = ProcessTypeString(templateString, false);
10149                            FinishTemplatesContext(context);
10150                         }
10151                      }
10152                   }
10153                }
10154             }
10155             else
10156                Compiler_Error($"undefined class %s\n", (id && (!id._class || id._class.name))? (id.classSym ? id.classSym.string : (type._class ? type._class.string : null)) : "(null)");
10157          }
10158          else if(type && (type.kind == structType || type.kind == unionType))
10159          {
10160             Type memberType = exp.member.member ? FindMember(type, exp.member.member.string) : null;
10161             if(memberType)
10162             {
10163                exp.expType = memberType;
10164                if(memberType)
10165                   memberType.refCount++;
10166             }
10167          }
10168          else
10169          {
10170             char expString[10240];
10171             expString[0] = '\0';
10172             if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10173             Compiler_Error($"member operator on non-structure type expression %s\n", expString);
10174          }
10175
10176          if(exp.expType && exp.expType.kind == thisClassType && (!exp.destType || exp.destType.kind != thisClassType))
10177          {
10178             if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType))
10179             {
10180                Identifier id = exp.member.member;
10181                Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10182                if(_class)
10183                {
10184                   FreeType(exp.expType);
10185                   exp.expType = ReplaceThisClassType(_class);
10186                }
10187             }
10188          }
10189          yylloc = oldyylloc;
10190          break;
10191       }
10192       // Convert x->y into (*x).y
10193       case pointerExp:
10194       {
10195          Type destType = exp.destType;
10196
10197          // DOING THIS LATER NOW...
10198          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
10199          {
10200             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
10201             /* TODO: Name Space Fix ups
10202             if(!exp.member.member.classSym)
10203                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.name);
10204             */
10205          }
10206
10207          exp.member.exp = MkExpBrackets(MkListOne(MkExpOp(null, '*', exp.member.exp)));
10208          exp.type = memberExp;
10209          if(destType)
10210             destType.count++;
10211          ProcessExpressionType(exp);
10212          if(destType)
10213             destType.count--;
10214          break;
10215       }
10216       case classSizeExp:
10217       {
10218          //ComputeExpression(exp);
10219
10220          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
10221          if(classSym && classSym.registered)
10222          {
10223             if(classSym.registered.type == noHeadClass)
10224             {
10225                char name[1024];
10226                name[0] = '\0';
10227                DeclareStruct(classSym.string, false);
10228                FreeSpecifier(exp._class);
10229                exp.type = typeSizeExp;
10230                FullClassNameCat(name, classSym.string, false);
10231                exp.typeName = MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null);
10232             }
10233             else
10234             {
10235                if(classSym.registered.fixed)
10236                {
10237                   FreeSpecifier(exp._class);
10238                   exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
10239                   exp.type = constantExp;
10240                }
10241                else
10242                {
10243                   char className[1024];
10244                   strcpy(className, "__ecereClass_");
10245                   FullClassNameCat(className, classSym.string, true);
10246                   MangleClassName(className);
10247
10248                   DeclareClass(classSym, className);
10249
10250                   FreeExpContents(exp);
10251                   exp.type = pointerExp;
10252                   exp.member.exp = MkExpIdentifier(MkIdentifier(className));
10253                   exp.member.member = MkIdentifier("structSize");
10254                }
10255             }
10256          }
10257
10258          exp.expType = Type
10259          {
10260             refCount = 1;
10261             kind = intType;
10262          };
10263          // exp.isConstant = true;
10264          break;
10265       }
10266       case typeSizeExp:
10267       {
10268          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
10269
10270          exp.expType = Type
10271          {
10272             refCount = 1;
10273             kind = intType;
10274          };
10275          exp.isConstant = true;
10276
10277          DeclareType(type, false, false);
10278          FreeType(type);
10279          break;
10280       }
10281       case castExp:
10282       {
10283          Type type = ProcessType(exp.cast.typeName.qualifiers, exp.cast.typeName.declarator);
10284          type.count = 1;
10285          FreeType(exp.cast.exp.destType);
10286          exp.cast.exp.destType = type;
10287          type.refCount++;
10288          ProcessExpressionType(exp.cast.exp);
10289          type.count = 0;
10290          exp.expType = type;
10291          //type.refCount++;
10292
10293          // if(!NeedCast(exp.cast.exp.expType, exp.cast.exp.destType))
10294          if(!exp.cast.exp.needCast && !NeedCast(exp.cast.exp.expType, type))
10295          {
10296             void * prev = exp.prev, * next = exp.next;
10297             Type expType = exp.cast.exp.destType;
10298             Expression castExp = exp.cast.exp;
10299             Type destType = exp.destType;
10300
10301             if(expType) expType.refCount++;
10302
10303             //FreeType(exp.destType);
10304             FreeType(exp.expType);
10305             FreeTypeName(exp.cast.typeName);
10306
10307             *exp = *castExp;
10308             FreeType(exp.expType);
10309             FreeType(exp.destType);
10310
10311             exp.expType = expType;
10312             exp.destType = destType;
10313
10314             delete castExp;
10315
10316             exp.prev = prev;
10317             exp.next = next;
10318
10319          }
10320          else
10321          {
10322             exp.isConstant = exp.cast.exp.isConstant;
10323          }
10324          //FreeType(type);
10325          break;
10326       }
10327       case extensionInitializerExp:
10328       {
10329          Type type = ProcessType(exp.initializer.typeName.qualifiers, exp.initializer.typeName.declarator);
10330          // We have yet to support this... ( { } initializers are currently processed inside ProcessDeclaration()'s initDeclaration case statement
10331          // ProcessInitializer(exp.initializer.initializer, type);
10332          exp.expType = type;
10333          break;
10334       }
10335       case vaArgExp:
10336       {
10337          Type type = ProcessType(exp.vaArg.typeName.qualifiers, exp.vaArg.typeName.declarator);
10338          ProcessExpressionType(exp.vaArg.exp);
10339          exp.expType = type;
10340          break;
10341       }
10342       case conditionExp:
10343       {
10344          Expression e;
10345          exp.isConstant = true;
10346
10347          FreeType(exp.cond.cond.destType);
10348          exp.cond.cond.destType = MkClassType("bool");
10349          exp.cond.cond.destType.truth = true;
10350          ProcessExpressionType(exp.cond.cond);
10351          if(!exp.cond.cond.isConstant)
10352             exp.isConstant = false;
10353          for(e = exp.cond.exp->first; e; e = e.next)
10354          {
10355             if(!e.next)
10356             {
10357                FreeType(e.destType);
10358                e.destType = exp.destType;
10359                if(e.destType) e.destType.refCount++;
10360             }
10361             ProcessExpressionType(e);
10362             if(!e.next)
10363             {
10364                exp.expType = e.expType;
10365                if(e.expType) e.expType.refCount++;
10366             }
10367             if(!e.isConstant)
10368                exp.isConstant = false;
10369          }
10370
10371          FreeType(exp.cond.elseExp.destType);
10372          // Added this check if we failed to find an expType
10373          // exp.cond.elseExp.destType = exp.expType ? exp.expType : exp.destType;
10374
10375          // Reversed it...
10376          exp.cond.elseExp.destType = exp.destType ? exp.destType : exp.expType;
10377
10378          if(exp.cond.elseExp.destType)
10379             exp.cond.elseExp.destType.refCount++;
10380          ProcessExpressionType(exp.cond.elseExp);
10381
10382          // FIXED THIS: Was done before calling process on elseExp
10383          if(!exp.cond.elseExp.isConstant)
10384             exp.isConstant = false;
10385          break;
10386       }
10387       case extensionCompoundExp:
10388       {
10389          if(exp.compound && exp.compound.compound.statements && exp.compound.compound.statements->last)
10390          {
10391             Statement last = exp.compound.compound.statements->last;
10392             if(last.type == expressionStmt && last.expressions && last.expressions->last)
10393             {
10394                ((Expression)last.expressions->last).destType = exp.destType;
10395                if(exp.destType)
10396                   exp.destType.refCount++;
10397             }
10398             ProcessStatement(exp.compound);
10399             exp.expType = (last.expressions && last.expressions->last) ? ((Expression)last.expressions->last).expType : null;
10400             if(exp.expType)
10401                exp.expType.refCount++;
10402          }
10403          break;
10404       }
10405       case classExp:
10406       {
10407          Specifier spec = exp._classExp.specifiers->first;
10408          if(spec && spec.type == nameSpecifier)
10409          {
10410             exp.expType = MkClassType(spec.name);
10411             exp.expType.kind = subClassType;
10412             exp.byReference = true;
10413          }
10414          else
10415          {
10416             exp.expType = MkClassType("ecere::com::Class");
10417             exp.byReference = true;
10418          }
10419          break;
10420       }
10421       case classDataExp:
10422       {
10423          Class _class = thisClass ? thisClass : currentClass;
10424          if(_class)
10425          {
10426             Identifier id = exp.classData.id;
10427             char structName[1024];
10428             Expression classExp;
10429             strcpy(structName, "__ecereClassData_");
10430             FullClassNameCat(structName, _class.fullName, false);
10431             exp.type = pointerExp;
10432             exp.member.member = id;
10433             if(curCompound && FindSymbol("this", curContext, curCompound.compound.context, false, false))
10434                classExp = MkExpMember(MkExpIdentifier(MkIdentifier("this")), MkIdentifier("_class"));
10435             else
10436                classExp = MkExpIdentifier(MkIdentifier("class"));
10437
10438             exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10439                MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10440                   MkExpBrackets(MkListOne(MkExpOp(
10441                      MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10442                         MkExpMember(classExp, MkIdentifier("data"))), '+',
10443                            MkExpMember(MkExpClass(MkListOne(MkSpecifierName(_class.fullName)), null), MkIdentifier("offsetClass")))))
10444                      )));
10445
10446             ProcessExpressionType(exp);
10447             return;
10448          }
10449          break;
10450       }
10451       case arrayExp:
10452       {
10453          Type type = null;
10454          char * typeString = null;
10455          char typeStringBuf[1024];
10456          if(exp.destType && exp.destType.kind == classType && exp.destType._class && exp.destType._class.registered &&
10457             exp.destType._class.registered != containerClass && eClass_IsDerived(exp.destType._class.registered, containerClass))
10458          {
10459             Class templateClass = exp.destType._class.registered;
10460             typeString = templateClass.templateArgs[2].dataTypeString;
10461          }
10462          else if(exp.list)
10463          {
10464             // Guess type from expressions in the array
10465             Expression e;
10466             for(e = exp.list->first; e; e = e.next)
10467             {
10468                ProcessExpressionType(e);
10469                if(e.expType)
10470                {
10471                   if(!type) { type = e.expType; type.refCount++; }
10472                   else
10473                   {
10474                      // if(!MatchType(e.expType, type, null, null, null, false, false, false))
10475                      if(!MatchTypeExpression(e, type, null, false))
10476                      {
10477                         FreeType(type);
10478                         type = e.expType;
10479                         e.expType = null;
10480
10481                         e = exp.list->first;
10482                         ProcessExpressionType(e);
10483                         if(e.expType)
10484                         {
10485                            //if(!MatchTypes(e.expType, type, null, null, null, false, false, false))
10486                            if(!MatchTypeExpression(e, type, null, false))
10487                            {
10488                               FreeType(e.expType);
10489                               e.expType = null;
10490                               FreeType(type);
10491                               type = null;
10492                               break;
10493                            }
10494                         }
10495                      }
10496                   }
10497                   if(e.expType)
10498                   {
10499                      FreeType(e.expType);
10500                      e.expType = null;
10501                   }
10502                }
10503             }
10504             if(type)
10505             {
10506                typeStringBuf[0] = '\0';
10507                PrintTypeNoConst(type, typeStringBuf, false, true);
10508                typeString = typeStringBuf;
10509                FreeType(type);
10510                type = null;
10511             }
10512          }
10513          if(typeString)
10514          {
10515             /*
10516             (Container)& (struct BuiltInContainer)
10517             {
10518                ._vTbl = class(BuiltInContainer)._vTbl,
10519                ._class = class(BuiltInContainer),
10520                .refCount = 0,
10521                .data = (int[]){ 1, 7, 3, 4, 5 },
10522                .count = 5,
10523                .type = class(int),
10524             }
10525             */
10526             char templateString[1024];
10527             OldList * initializers = MkList();
10528             OldList * structInitializers = MkList();
10529             OldList * specs = MkList();
10530             Expression expExt;
10531             Declarator decl = SpecDeclFromString(typeString, specs, null);
10532             sprintf(templateString, "Container<%s>", typeString);
10533
10534             if(exp.list)
10535             {
10536                Expression e;
10537                type = ProcessTypeString(typeString, false);
10538                while(e = exp.list->first)
10539                {
10540                   exp.list->Remove(e);
10541                   e.destType = type;
10542                   type.refCount++;
10543                   ProcessExpressionType(e);
10544                   ListAdd(initializers, MkInitializerAssignment(e));
10545                }
10546                FreeType(type);
10547                delete exp.list;
10548             }
10549
10550             DeclareStruct("ecere::com::BuiltInContainer", false);
10551
10552             ListAdd(structInitializers, /*MkIdentifier("_vTbl")*/    MkInitializerAssignment(MkExpMember(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null), MkIdentifier("_vTbl"))));
10553                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10554             ListAdd(structInitializers, /*MkIdentifier("_class")*/   MkInitializerAssignment(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null)));
10555                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10556             ListAdd(structInitializers, /*MkIdentifier("_refCount")*/MkInitializerAssignment(MkExpConstant("0")));
10557                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10558             ListAdd(structInitializers, /*MkIdentifier("data")*/     MkInitializerAssignment(MkExpExtensionInitializer(
10559                MkTypeName(specs, MkDeclaratorArray(decl, null)),
10560                MkInitializerList(initializers))));
10561                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10562             ListAdd(structInitializers, /*MkIdentifier("count")*/    MkInitializerAssignment({ type = constantExp, constant = PrintString(initializers->count) }));
10563                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10564             ListAdd(structInitializers, /*MkIdentifier("type")*/     MkInitializerAssignment(MkExpClass(CopyList(specs, CopySpecifier), CopyDeclarator(decl))));
10565                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10566             exp.expType = ProcessTypeString(templateString, false);
10567             exp.type = bracketsExp;
10568             exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(templateString)), null),
10569                MkExpOp(null, '&',
10570                expExt = MkExpExtensionInitializer(MkTypeName(MkListOne(MkSpecifierName("BuiltInContainer")), null),
10571                   MkInitializerList(structInitializers)))));
10572             ProcessExpressionType(expExt);
10573          }
10574          else
10575          {
10576             exp.expType = ProcessTypeString("Container", false);
10577             Compiler_Error($"Couldn't determine type of array elements\n");
10578          }
10579          break;
10580       }
10581    }
10582
10583    if(exp.expType && exp.expType.kind == thisClassType && thisClass && (!exp.destType || exp.destType.kind != thisClassType))
10584    {
10585       FreeType(exp.expType);
10586       exp.expType = ReplaceThisClassType(thisClass);
10587    }
10588
10589    // Resolve structures here
10590    if(exp.expType && (exp.expType.kind == structType || exp.expType.kind == unionType || exp.expType.kind == enumType) && !exp.expType.members.first && exp.expType.enumName)
10591    {
10592       Symbol symbol = FindSymbol(exp.expType.enumName, curContext, globalContext, true, false);
10593       // TODO: Fix members reference...
10594       if(symbol)
10595       {
10596          if(exp.expType.kind != enumType)
10597          {
10598             Type member;
10599             String enumName = CopyString(exp.expType.enumName);
10600
10601             // Fixed a memory leak on self-referencing C structs typedefs
10602             // by instantiating a new type rather than simply copying members
10603             // into exp.expType
10604             FreeType(exp.expType);
10605             exp.expType = Type { };
10606             exp.expType.kind = symbol.type.kind;
10607             exp.expType.refCount++;
10608             exp.expType.enumName = enumName;
10609
10610             exp.expType.members = symbol.type.members;
10611             for(member = symbol.type.members.first; member; member = member.next)
10612                member.refCount++;
10613          }
10614          else
10615          {
10616             NamedLink member;
10617             for(member = symbol.type.members.first; member; member = member.next)
10618             {
10619                NamedLink value { name = CopyString(member.name) };
10620                exp.expType.members.Add(value);
10621             }
10622          }
10623       }
10624    }
10625
10626    yylloc = exp.loc;
10627    if(exp.destType && (exp.destType.kind == voidType || exp.destType.kind == dummyType) );
10628    else if(exp.destType && !exp.destType.keepCast)
10629    {
10630       if(!CheckExpressionType(exp, exp.destType, false))
10631       {
10632          if(!exp.destType.count || unresolved)
10633          {
10634             if(!exp.expType)
10635             {
10636                yylloc = exp.loc;
10637                if(exp.destType.kind != ellipsisType)
10638                {
10639                   char type2[1024];
10640                   type2[0] = '\0';
10641                   if(inCompiler)
10642                   {
10643                      char expString[10240];
10644                      expString[0] = '\0';
10645
10646                      PrintType(exp.destType, type2, false, true);
10647
10648                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10649                      if(unresolved)
10650                         Compiler_Error($"unresolved identifier %s; expected %s\n", expString, type2);
10651                      else if(exp.type != dummyExp)
10652                         Compiler_Error($"couldn't determine type of %s; expected %s\n", expString, type2);
10653                   }
10654                }
10655                else
10656                {
10657                   char expString[10240] ;
10658                   expString[0] = '\0';
10659                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10660
10661                   if(unresolved)
10662                      Compiler_Error($"unresolved identifier %s\n", expString);
10663                   else if(exp.type != dummyExp)
10664                      Compiler_Error($"couldn't determine type of %s\n", expString);
10665                }
10666             }
10667             else
10668             {
10669                char type1[1024];
10670                char type2[1024];
10671                type1[0] = '\0';
10672                type2[0] = '\0';
10673                if(inCompiler)
10674                {
10675                   PrintType(exp.expType, type1, false, true);
10676                   PrintType(exp.destType, type2, false, true);
10677                }
10678
10679                //CheckExpressionType(exp, exp.destType, false);
10680
10681                if(exp.destType.truth && exp.destType._class && exp.destType._class.registered && !strcmp(exp.destType._class.registered.name, "bool") &&
10682                   exp.expType.kind != voidType && exp.expType.kind != structType && exp.expType.kind != unionType &&
10683                   (exp.expType.kind != classType || exp.expType.classObjectType || (exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type != structClass)));
10684                else
10685                {
10686                   char expString[10240];
10687                   expString[0] = '\0';
10688                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10689
10690 #ifdef _DEBUG
10691                   CheckExpressionType(exp, exp.destType, false);
10692 #endif
10693                   // Flex & Bison generate code that triggers this, so we ignore it for a quiet sdk build:
10694                   if(!sourceFile || (strcmp(sourceFile, "src\\lexer.ec") && strcmp(sourceFile, "src/lexer.ec") && strcmp(sourceFile, "src\\grammar.ec") && strcmp(sourceFile, "src/grammar.ec")))
10695                      Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
10696
10697                   // TO CHECK: FORCING HERE TO HELP DEBUGGER
10698                   FreeType(exp.expType);
10699                   exp.destType.refCount++;
10700                   exp.expType = exp.destType;
10701                }
10702             }
10703          }
10704       }
10705       else if(exp.destType && exp.destType.kind == ellipsisType && exp.expType && exp.expType.passAsTemplate)
10706       {
10707          Expression newExp { };
10708          char typeString[1024];
10709          OldList * specs = MkList();
10710          Declarator decl;
10711
10712          typeString[0] = '\0';
10713
10714          *newExp = *exp;
10715
10716          if(exp.expType)  exp.expType.refCount++;
10717          if(exp.expType)  exp.expType.refCount++;
10718          exp.type = castExp;
10719          newExp.destType = exp.expType;
10720
10721          PrintType(exp.expType, typeString, false, false);
10722          decl = SpecDeclFromString(typeString, specs, null);
10723
10724          exp.cast.typeName = MkTypeName(specs, decl);
10725          exp.cast.exp = newExp;
10726       }
10727    }
10728    else if(unresolved)
10729    {
10730       if(exp.identifier._class && exp.identifier._class.name)
10731          Compiler_Error($"unresolved identifier %s::%s\n", exp.identifier._class.name, exp.identifier.string);
10732       else if(exp.identifier.string && exp.identifier.string[0])
10733          Compiler_Error($"unresolved identifier %s\n", exp.identifier.string);
10734    }
10735    else if(!exp.expType && exp.type != dummyExp)
10736    {
10737       char expString[10240];
10738       expString[0] = '\0';
10739       if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10740       Compiler_Error($"couldn't determine type of %s\n", expString);
10741    }
10742
10743    // Let's try to support any_object & typed_object here:
10744    if(inCompiler)
10745       ApplyAnyObjectLogic(exp);
10746
10747    // Mark nohead classes as by reference, unless we're casting them to an integral type
10748    if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
10749       exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
10750          (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
10751           exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
10752    {
10753       exp.byReference = true;
10754    }
10755    yylloc = oldyylloc;
10756 }
10757
10758 static void FindNextDataMember(Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
10759 {
10760    // THIS CODE WILL FIND NEXT MEMBER...
10761    if(*curMember)
10762    {
10763       *curMember = (*curMember).next;
10764
10765       if(subMemberStackPos && *subMemberStackPos > 0 && subMemberStack[*subMemberStackPos-1].type == unionMember)
10766       {
10767          *curMember = subMemberStack[--(*subMemberStackPos)];
10768          *curMember = (*curMember).next;
10769       }
10770
10771       // SKIP ALL PROPERTIES HERE...
10772       while((*curMember) && (*curMember).isProperty)
10773          *curMember = (*curMember).next;
10774
10775       if(subMemberStackPos)
10776       {
10777          while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
10778          {
10779             subMemberStack[(*subMemberStackPos)++] = *curMember;
10780
10781             *curMember = (*curMember).members.first;
10782             while(*curMember && (*curMember).isProperty)
10783                *curMember = (*curMember).next;
10784          }
10785       }
10786    }
10787    while(!*curMember)
10788    {
10789       if(!*curMember)
10790       {
10791          if(subMemberStackPos && *subMemberStackPos)
10792          {
10793             *curMember = subMemberStack[--(*subMemberStackPos)];
10794             *curMember = (*curMember).next;
10795          }
10796          else
10797          {
10798             Class lastCurClass = *curClass;
10799
10800             if(*curClass == _class) break;     // REACHED THE END
10801
10802             for(*curClass = _class; (*curClass).base != lastCurClass && (*curClass).base.type != systemClass; *curClass = (*curClass).base);
10803             *curMember = (*curClass).membersAndProperties.first;
10804          }
10805
10806          while((*curMember) && (*curMember).isProperty)
10807             *curMember = (*curMember).next;
10808          if(subMemberStackPos)
10809          {
10810             while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
10811             {
10812                subMemberStack[(*subMemberStackPos)++] = *curMember;
10813
10814                *curMember = (*curMember).members.first;
10815                while(*curMember && (*curMember).isProperty)
10816                   *curMember = (*curMember).next;
10817             }
10818          }
10819       }
10820    }
10821 }
10822
10823
10824 static void ProcessInitializer(Initializer init, Type type)
10825 {
10826    switch(init.type)
10827    {
10828       case expInitializer:
10829          if(!init.exp || init.exp.type != instanceExp || !init.exp.instance || init.exp.instance._class || !type || type.kind == classType)
10830          {
10831             // TESTING THIS FOR SHUTTING = 0 WARNING
10832             if(init.exp && !init.exp.destType)
10833             {
10834                FreeType(init.exp.destType);
10835                init.exp.destType = type;
10836                if(type) type.refCount++;
10837             }
10838             if(init.exp)
10839             {
10840                ProcessExpressionType(init.exp);
10841                init.isConstant = init.exp.isConstant;
10842             }
10843             break;
10844          }
10845          else
10846          {
10847             Expression exp = init.exp;
10848             Instantiation inst = exp.instance;
10849             MembersInit members;
10850
10851             init.type = listInitializer;
10852             init.list = MkList();
10853
10854             if(inst.members)
10855             {
10856                for(members = inst.members->first; members; members = members.next)
10857                {
10858                   if(members.type == dataMembersInit)
10859                   {
10860                      MemberInit member;
10861                      for(member = members.dataMembers->first; member; member = member.next)
10862                      {
10863                         ListAdd(init.list, member.initializer);
10864                         member.initializer = null;
10865                      }
10866                   }
10867                   // Discard all MembersInitMethod
10868                }
10869             }
10870             FreeExpression(exp);
10871          }
10872       case listInitializer:
10873       {
10874          Initializer i;
10875          Type initializerType = null;
10876          Class curClass = null;
10877          DataMember curMember = null;
10878          DataMember subMemberStack[256];
10879          int subMemberStackPos = 0;
10880
10881          if(type && type.kind == arrayType)
10882             initializerType = Dereference(type);
10883          else if(type && (type.kind == structType || type.kind == unionType))
10884             initializerType = type.members.first;
10885
10886          for(i = init.list->first; i; i = i.next)
10887          {
10888             if(type && type.kind == classType && type._class && type._class.registered)
10889             {
10890                // 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)
10891                FindNextDataMember(type._class.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
10892                // TODO: Generate error on initializing a private data member this way from another module...
10893                if(curMember)
10894                {
10895                   if(!curMember.dataType)
10896                      curMember.dataType = ProcessTypeString(curMember.dataTypeString, false);
10897                   initializerType = curMember.dataType;
10898                }
10899             }
10900             ProcessInitializer(i, initializerType);
10901             if(initializerType && type && (type.kind == structType || type.kind == unionType))
10902                initializerType = initializerType.next;
10903             if(!i.isConstant)
10904                init.isConstant = false;
10905          }
10906
10907          if(type && type.kind == arrayType)
10908             FreeType(initializerType);
10909
10910          if(type && type.kind != arrayType && type.kind != structType && type.kind != unionType && (type.kind != classType || !type._class.registered || type._class.registered.type != structClass))
10911          {
10912             Compiler_Error($"Assigning list initializer to non list\n");
10913          }
10914          break;
10915       }
10916    }
10917 }
10918
10919 static void ProcessSpecifier(Specifier spec, bool declareStruct)
10920 {
10921    switch(spec.type)
10922    {
10923       case baseSpecifier:
10924       {
10925          if(spec.specifier == THISCLASS)
10926          {
10927             if(thisClass)
10928             {
10929                spec.type = nameSpecifier;
10930                spec.name = ReplaceThisClass(thisClass);
10931                spec.symbol = FindClass(spec.name);
10932                ProcessSpecifier(spec, declareStruct);
10933             }
10934          }
10935          break;
10936       }
10937       case nameSpecifier:
10938       {
10939          Symbol symbol = FindType(curContext, spec.name);
10940          if(symbol)
10941             DeclareType(symbol.type, true, true);
10942          else if((symbol = spec.symbol /*FindClass(spec.name)*/) && symbol.registered && symbol.registered.type == structClass && declareStruct)
10943             DeclareStruct(spec.name, false);
10944          break;
10945       }
10946       case enumSpecifier:
10947       {
10948          Enumerator e;
10949          if(spec.list)
10950          {
10951             for(e = spec.list->first; e; e = e.next)
10952             {
10953                if(e.exp)
10954                   ProcessExpressionType(e.exp);
10955             }
10956          }
10957          break;
10958       }
10959       case structSpecifier:
10960       case unionSpecifier:
10961       {
10962          if(spec.definitions)
10963          {
10964             ClassDef def;
10965             Symbol symbol = spec.id ? FindClass(spec.id.string) : null;
10966             //if(symbol)
10967                ProcessClass(spec.definitions, symbol);
10968             /*else
10969             {
10970                for(def = spec.definitions->first; def; def = def.next)
10971                {
10972                   //if(def.type == declarationClassDef && def.decl && def.decl.type == DeclarationStruct)
10973                      ProcessDeclaration(def.decl);
10974                }
10975             }*/
10976          }
10977          break;
10978       }
10979       /*
10980       case classSpecifier:
10981       {
10982          Symbol classSym = FindClass(spec.name);
10983          if(classSym && classSym.registered && classSym.registered.type == structClass)
10984             DeclareStruct(spec.name, false);
10985          break;
10986       }
10987       */
10988    }
10989 }
10990
10991
10992 static void ProcessDeclarator(Declarator decl)
10993 {
10994    switch(decl.type)
10995    {
10996       case identifierDeclarator:
10997          if(decl.identifier.classSym /* TODO: Name Space Fix ups  || decl.identifier.nameSpace*/)
10998          {
10999             FreeSpecifier(decl.identifier._class);
11000             decl.identifier._class = null;
11001          }
11002          break;
11003       case arrayDeclarator:
11004          if(decl.array.exp)
11005             ProcessExpressionType(decl.array.exp);
11006       case structDeclarator:
11007       case bracketsDeclarator:
11008       case functionDeclarator:
11009       case pointerDeclarator:
11010       case extendedDeclarator:
11011       case extendedDeclaratorEnd:
11012          if(decl.declarator)
11013             ProcessDeclarator(decl.declarator);
11014          if(decl.type == functionDeclarator)
11015          {
11016             Identifier id = GetDeclId(decl);
11017             if(id && id._class)
11018             {
11019                TypeName param
11020                {
11021                   qualifiers = MkListOne(id._class);
11022                   declarator = null;
11023                };
11024                if(!decl.function.parameters)
11025                   decl.function.parameters = MkList();
11026                decl.function.parameters->Insert(null, param);
11027                id._class = null;
11028             }
11029             if(decl.function.parameters)
11030             {
11031                TypeName param;
11032
11033                for(param = decl.function.parameters->first; param; param = param.next)
11034                {
11035                   if(param.qualifiers && param.qualifiers->first)
11036                   {
11037                      Specifier spec = param.qualifiers->first;
11038                      if(spec && spec.specifier == TYPED_OBJECT)
11039                      {
11040                         Declarator d = param.declarator;
11041                         TypeName newParam
11042                         {
11043                            qualifiers = MkListOne(MkSpecifier(VOID));
11044                            declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11045                         };
11046
11047                         FreeList(param.qualifiers, FreeSpecifier);
11048
11049                         param.qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
11050                         param.declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
11051
11052                         decl.function.parameters->Insert(param, newParam);
11053                         param = newParam;
11054                      }
11055                      else if(spec && spec.specifier == ANY_OBJECT)
11056                      {
11057                         Declarator d = param.declarator;
11058
11059                         FreeList(param.qualifiers, FreeSpecifier);
11060
11061                         param.qualifiers = MkListOne(MkSpecifier(VOID));
11062                         param.declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11063                      }
11064                      else if(spec.specifier == THISCLASS)
11065                      {
11066                         if(thisClass)
11067                         {
11068                            spec.type = nameSpecifier;
11069                            spec.name = ReplaceThisClass(thisClass);
11070                            spec.symbol = FindClass(spec.name);
11071                            ProcessSpecifier(spec, false);
11072                         }
11073                      }
11074                   }
11075
11076                   if(param.declarator)
11077                      ProcessDeclarator(param.declarator);
11078                }
11079             }
11080          }
11081          break;
11082    }
11083 }
11084
11085 static void ProcessDeclaration(Declaration decl)
11086 {
11087    yylloc = decl.loc;
11088    switch(decl.type)
11089    {
11090       case initDeclaration:
11091       {
11092          bool declareStruct = false;
11093          /*
11094          lineNum = decl.pos.line;
11095          column = decl.pos.col;
11096          */
11097
11098          if(decl.declarators)
11099          {
11100             InitDeclarator d;
11101
11102             for(d = decl.declarators->first; d; d = d.next)
11103             {
11104                Type type, subType;
11105                ProcessDeclarator(d.declarator);
11106
11107                type = ProcessType(decl.specifiers, d.declarator);
11108
11109                if(d.initializer)
11110                {
11111                   ProcessInitializer(d.initializer, type);
11112
11113                   // Change "ColorRGB a = ColorRGB { 1,2,3 } => ColorRGB a { 1,2,3 }
11114
11115                   if(decl.declarators->count == 1 && d.initializer.type == expInitializer &&
11116                      d.initializer.exp.type == instanceExp)
11117                   {
11118                      if(type.kind == classType && type._class ==
11119                         d.initializer.exp.expType._class)
11120                      {
11121                         Instantiation inst = d.initializer.exp.instance;
11122                         inst.exp = MkExpIdentifier(CopyIdentifier(GetDeclId(d.declarator)));
11123
11124                         d.initializer.exp.instance = null;
11125                         if(decl.specifiers)
11126                            FreeList(decl.specifiers, FreeSpecifier);
11127                         FreeList(decl.declarators, FreeInitDeclarator);
11128
11129                         d = null;
11130
11131                         decl.type = instDeclaration;
11132                         decl.inst = inst;
11133                      }
11134                   }
11135                }
11136                for(subType = type; subType;)
11137                {
11138                   if(subType.kind == classType)
11139                   {
11140                      declareStruct = true;
11141                      break;
11142                   }
11143                   else if(subType.kind == pointerType)
11144                      break;
11145                   else if(subType.kind == arrayType)
11146                      subType = subType.arrayType;
11147                   else
11148                      break;
11149                }
11150
11151                FreeType(type);
11152                if(!d) break;
11153             }
11154          }
11155
11156          if(decl.specifiers)
11157          {
11158             Specifier s;
11159             for(s = decl.specifiers->first; s; s = s.next)
11160             {
11161                ProcessSpecifier(s, declareStruct);
11162             }
11163          }
11164          break;
11165       }
11166       case instDeclaration:
11167       {
11168          ProcessInstantiationType(decl.inst);
11169          break;
11170       }
11171       case structDeclaration:
11172       {
11173          Specifier spec;
11174          Declarator d;
11175          bool declareStruct = false;
11176
11177          if(decl.declarators)
11178          {
11179             for(d = decl.declarators->first; d; d = d.next)
11180             {
11181                Type type = ProcessType(decl.specifiers, d.declarator);
11182                Type subType;
11183                ProcessDeclarator(d);
11184                for(subType = type; subType;)
11185                {
11186                   if(subType.kind == classType)
11187                   {
11188                      declareStruct = true;
11189                      break;
11190                   }
11191                   else if(subType.kind == pointerType)
11192                      break;
11193                   else if(subType.kind == arrayType)
11194                      subType = subType.arrayType;
11195                   else
11196                      break;
11197                }
11198                FreeType(type);
11199             }
11200          }
11201          if(decl.specifiers)
11202          {
11203             for(spec = decl.specifiers->first; spec; spec = spec.next)
11204                ProcessSpecifier(spec, declareStruct);
11205          }
11206          break;
11207       }
11208    }
11209 }
11210
11211 static FunctionDefinition curFunction;
11212
11213 static void CreateFireWatcher(Property prop, Expression object, Statement stmt)
11214 {
11215    char propName[1024], propNameM[1024];
11216    char getName[1024], setName[1024];
11217    OldList * args;
11218
11219    DeclareProperty(prop, setName, getName);
11220
11221    // eInstance_FireWatchers(object, prop);
11222    strcpy(propName, "__ecereProp_");
11223    FullClassNameCat(propName, prop._class.fullName, false);
11224    strcat(propName, "_");
11225    // strcat(propName, prop.name);
11226    FullClassNameCat(propName, prop.name, true);
11227    MangleClassName(propName);
11228
11229    strcpy(propNameM, "__ecerePropM_");
11230    FullClassNameCat(propNameM, prop._class.fullName, false);
11231    strcat(propNameM, "_");
11232    // strcat(propNameM, prop.name);
11233    FullClassNameCat(propNameM, prop.name, true);
11234    MangleClassName(propNameM);
11235
11236    if(prop.isWatchable)
11237    {
11238       args = MkList();
11239       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11240       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11241       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11242
11243       args = MkList();
11244       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11245       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11246       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11247    }
11248
11249
11250    {
11251       args = MkList();
11252       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11253       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11254       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11255
11256       args = MkList();
11257       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11258       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11259       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11260    }
11261
11262    if(curFunction.propSet && !strcmp(curFunction.propSet.string, prop.name) &&
11263       (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
11264       curFunction.propSet.fireWatchersDone = true;
11265 }
11266
11267 static void ProcessStatement(Statement stmt)
11268 {
11269    yylloc = stmt.loc;
11270    /*
11271    lineNum = stmt.pos.line;
11272    column = stmt.pos.col;
11273    */
11274    switch(stmt.type)
11275    {
11276       case labeledStmt:
11277          ProcessStatement(stmt.labeled.stmt);
11278          break;
11279       case caseStmt:
11280          // This expression should be constant...
11281          if(stmt.caseStmt.exp)
11282          {
11283             FreeType(stmt.caseStmt.exp.destType);
11284             stmt.caseStmt.exp.destType = curSwitchType;
11285             if(curSwitchType) curSwitchType.refCount++;
11286             ProcessExpressionType(stmt.caseStmt.exp);
11287             ComputeExpression(stmt.caseStmt.exp);
11288          }
11289          if(stmt.caseStmt.stmt)
11290             ProcessStatement(stmt.caseStmt.stmt);
11291          break;
11292       case compoundStmt:
11293       {
11294          if(stmt.compound.context)
11295          {
11296             Declaration decl;
11297             Statement s;
11298
11299             Statement prevCompound = curCompound;
11300             Context prevContext = curContext;
11301
11302             if(!stmt.compound.isSwitch)
11303                curCompound = stmt;
11304             curContext = stmt.compound.context;
11305
11306             if(stmt.compound.declarations)
11307             {
11308                for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
11309                   ProcessDeclaration(decl);
11310             }
11311             if(stmt.compound.statements)
11312             {
11313                for(s = stmt.compound.statements->first; s; s = s.next)
11314                   ProcessStatement(s);
11315             }
11316
11317             curContext = prevContext;
11318             curCompound = prevCompound;
11319          }
11320          break;
11321       }
11322       case expressionStmt:
11323       {
11324          Expression exp;
11325          if(stmt.expressions)
11326          {
11327             for(exp = stmt.expressions->first; exp; exp = exp.next)
11328                ProcessExpressionType(exp);
11329          }
11330          break;
11331       }
11332       case ifStmt:
11333       {
11334          Expression exp;
11335
11336          FreeType(((Expression)stmt.ifStmt.exp->last).destType);
11337          ((Expression)stmt.ifStmt.exp->last).destType = MkClassType("bool");
11338          ((Expression)stmt.ifStmt.exp->last).destType.truth = true;
11339          for(exp = stmt.ifStmt.exp->first; exp; exp = exp.next)
11340          {
11341             ProcessExpressionType(exp);
11342          }
11343          if(stmt.ifStmt.stmt)
11344             ProcessStatement(stmt.ifStmt.stmt);
11345          if(stmt.ifStmt.elseStmt)
11346             ProcessStatement(stmt.ifStmt.elseStmt);
11347          break;
11348       }
11349       case switchStmt:
11350       {
11351          Type oldSwitchType = curSwitchType;
11352          if(stmt.switchStmt.exp)
11353          {
11354             Expression exp;
11355             for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
11356             {
11357                if(!exp.next)
11358                {
11359                   /*
11360                   Type destType
11361                   {
11362                      kind = intType;
11363                      refCount = 1;
11364                   };
11365                   e.exp.destType = destType;
11366                   */
11367
11368                   ProcessExpressionType(exp);
11369                }
11370                if(!exp.next)
11371                   curSwitchType = exp.expType;
11372             }
11373          }
11374          ProcessStatement(stmt.switchStmt.stmt);
11375          curSwitchType = oldSwitchType;
11376          break;
11377       }
11378       case whileStmt:
11379       {
11380          if(stmt.whileStmt.exp)
11381          {
11382             Expression exp;
11383
11384             FreeType(((Expression)stmt.whileStmt.exp->last).destType);
11385             ((Expression)stmt.whileStmt.exp->last).destType = MkClassType("bool");
11386             ((Expression)stmt.whileStmt.exp->last).destType.truth = true;
11387             for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
11388             {
11389                ProcessExpressionType(exp);
11390             }
11391          }
11392          if(stmt.whileStmt.stmt)
11393             ProcessStatement(stmt.whileStmt.stmt);
11394          break;
11395       }
11396       case doWhileStmt:
11397       {
11398          if(stmt.doWhile.exp)
11399          {
11400             Expression exp;
11401
11402             if(stmt.doWhile.exp->last)
11403             {
11404                FreeType(((Expression)stmt.doWhile.exp->last).destType);
11405                ((Expression)stmt.doWhile.exp->last).destType = MkClassType("bool");
11406                ((Expression)stmt.doWhile.exp->last).destType.truth = true;
11407             }
11408             for(exp = stmt.doWhile.exp->first; exp; exp = exp.next)
11409             {
11410                ProcessExpressionType(exp);
11411             }
11412          }
11413          if(stmt.doWhile.stmt)
11414             ProcessStatement(stmt.doWhile.stmt);
11415          break;
11416       }
11417       case forStmt:
11418       {
11419          Expression exp;
11420          if(stmt.forStmt.init)
11421             ProcessStatement(stmt.forStmt.init);
11422
11423          if(stmt.forStmt.check && stmt.forStmt.check.expressions)
11424          {
11425             FreeType(((Expression)stmt.forStmt.check.expressions->last).destType);
11426             ((Expression)stmt.forStmt.check.expressions->last).destType = MkClassType("bool");
11427             ((Expression)stmt.forStmt.check.expressions->last).destType.truth = true;
11428          }
11429
11430          if(stmt.forStmt.check)
11431             ProcessStatement(stmt.forStmt.check);
11432          if(stmt.forStmt.increment)
11433          {
11434             for(exp = stmt.forStmt.increment->first; exp; exp = exp.next)
11435                ProcessExpressionType(exp);
11436          }
11437
11438          if(stmt.forStmt.stmt)
11439             ProcessStatement(stmt.forStmt.stmt);
11440          break;
11441       }
11442       case forEachStmt:
11443       {
11444          Identifier id = stmt.forEachStmt.id;
11445          OldList * exp = stmt.forEachStmt.exp;
11446          OldList * filter = stmt.forEachStmt.filter;
11447          Statement block = stmt.forEachStmt.stmt;
11448          char iteratorType[1024];
11449          Type source;
11450          Expression e;
11451          bool isBuiltin = exp && exp->last &&
11452             (((Expression)exp->last).type == ExpressionType::arrayExp ||
11453               (((Expression)exp->last).type == castExp && ((Expression)exp->last).cast.exp.type == ExpressionType::arrayExp));
11454          Expression arrayExp;
11455          char * typeString = null;
11456          int builtinCount = 0;
11457
11458          for(e = exp ? exp->first : null; e; e = e.next)
11459          {
11460             if(!e.next)
11461             {
11462                FreeType(e.destType);
11463                e.destType = ProcessTypeString("Container", false);
11464             }
11465             if(!isBuiltin || e.next)
11466                ProcessExpressionType(e);
11467          }
11468
11469          source = (exp && exp->last) ? ((Expression)exp->last).expType : null;
11470          if(isBuiltin || (source && source.kind == classType && source._class && source._class.registered && source._class.registered != containerClass &&
11471             eClass_IsDerived(source._class.registered, containerClass)))
11472          {
11473             Class _class = source ? source._class.registered : null;
11474             Symbol symbol;
11475             Expression expIt = null;
11476             bool isMap = false, isArray = false, isLinkList = false, isList = false, isCustomAVLTree = false, isAVLTree = false;
11477             Class arrayClass = eSystem_FindClass(privateModule, "Array");
11478             Class linkListClass = eSystem_FindClass(privateModule, "LinkList");
11479             Class customAVLTreeClass = eSystem_FindClass(privateModule, "CustomAVLTree");
11480             stmt.type = compoundStmt;
11481
11482             stmt.compound.context = Context { };
11483             stmt.compound.context.parent = curContext;
11484             curContext = stmt.compound.context;
11485
11486             if(source && eClass_IsDerived(source._class.registered, customAVLTreeClass))
11487             {
11488                Class mapClass = eSystem_FindClass(privateModule, "Map");
11489                Class avlTreeClass = eSystem_FindClass(privateModule, "AVLTree");
11490                isCustomAVLTree = true;
11491                if(eClass_IsDerived(source._class.registered, avlTreeClass))
11492                   isAVLTree = true;
11493                else if(eClass_IsDerived(source._class.registered, mapClass))
11494                   isMap = true;
11495             }
11496             else if(source && eClass_IsDerived(source._class.registered, arrayClass)) isArray = true;
11497             else if(source && eClass_IsDerived(source._class.registered, linkListClass))
11498             {
11499                Class listClass = eSystem_FindClass(privateModule, "List");
11500                isLinkList = true;
11501                isList = eClass_IsDerived(source._class.registered, listClass);
11502             }
11503
11504             if(isArray)
11505             {
11506                Declarator decl;
11507                OldList * specs = MkList();
11508                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
11509                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
11510                stmt.compound.declarations = MkListOne(
11511                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11512                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11513                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalArray")),
11514                      MkInitializerAssignment(MkExpBrackets(exp))))));
11515             }
11516             else if(isBuiltin)
11517             {
11518                Type type = null;
11519                char typeStringBuf[1024];
11520
11521                // TODO: Merge this code?
11522                arrayExp = (((Expression)exp->last).type == ExpressionType::arrayExp) ? (Expression)exp->last : ((Expression)exp->last).cast.exp;
11523                if(((Expression)exp->last).type == castExp)
11524                {
11525                   TypeName typeName = ((Expression)exp->last).cast.typeName;
11526                   if(typeName)
11527                      arrayExp.destType = ProcessType(typeName.qualifiers, typeName.declarator);
11528                }
11529
11530                if(arrayExp.destType && arrayExp.destType.kind == classType && arrayExp.destType._class && arrayExp.destType._class.registered &&
11531                   arrayExp.destType._class.registered != containerClass && eClass_IsDerived(arrayExp.destType._class.registered, containerClass) &&
11532                   arrayExp.destType._class.registered.templateArgs)
11533                {
11534                   Class templateClass = arrayExp.destType._class.registered;
11535                   typeString = templateClass.templateArgs[2].dataTypeString;
11536                }
11537                else if(arrayExp.list)
11538                {
11539                   // Guess type from expressions in the array
11540                   Expression e;
11541                   for(e = arrayExp.list->first; e; e = e.next)
11542                   {
11543                      ProcessExpressionType(e);
11544                      if(e.expType)
11545                      {
11546                         if(!type) { type = e.expType; type.refCount++; }
11547                         else
11548                         {
11549                            // if(!MatchType(e.expType, type, null, null, null, false, false, false))
11550                            if(!MatchTypeExpression(e, type, null, false))
11551                            {
11552                               FreeType(type);
11553                               type = e.expType;
11554                               e.expType = null;
11555
11556                               e = arrayExp.list->first;
11557                               ProcessExpressionType(e);
11558                               if(e.expType)
11559                               {
11560                                  //if(!MatchTypes(e.expType, type, null, null, null, false, false, false, false))
11561                                  if(!MatchTypeExpression(e, type, null, false))
11562                                  {
11563                                     FreeType(e.expType);
11564                                     e.expType = null;
11565                                     FreeType(type);
11566                                     type = null;
11567                                     break;
11568                                  }
11569                               }
11570                            }
11571                         }
11572                         if(e.expType)
11573                         {
11574                            FreeType(e.expType);
11575                            e.expType = null;
11576                         }
11577                      }
11578                   }
11579                   if(type)
11580                   {
11581                      typeStringBuf[0] = '\0';
11582                      PrintType(type, typeStringBuf, false, true);
11583                      typeString = typeStringBuf;
11584                      FreeType(type);
11585                   }
11586                }
11587                if(typeString)
11588                {
11589                   OldList * initializers = MkList();
11590                   Declarator decl;
11591                   OldList * specs = MkList();
11592                   if(arrayExp.list)
11593                   {
11594                      Expression e;
11595
11596                      builtinCount = arrayExp.list->count;
11597                      type = ProcessTypeString(typeString, false);
11598                      while(e = arrayExp.list->first)
11599                      {
11600                         arrayExp.list->Remove(e);
11601                         e.destType = type;
11602                         type.refCount++;
11603                         ProcessExpressionType(e);
11604                         ListAdd(initializers, MkInitializerAssignment(e));
11605                      }
11606                      FreeType(type);
11607                      delete arrayExp.list;
11608                   }
11609                   decl = SpecDeclFromString(typeString, specs, MkDeclaratorIdentifier(id));
11610                   stmt.compound.declarations = MkListOne(MkDeclaration(CopyList(specs, CopySpecifier),
11611                      MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), /*CopyDeclarator(*/decl/*)*/), null))));
11612
11613                   ListAdd(stmt.compound.declarations, MkDeclaration(specs, MkListOne(MkInitDeclarator(
11614                      PlugDeclarator(
11615                         /*CopyDeclarator(*/decl/*)*/, MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__internalArray")), null)
11616                         ), MkInitializerList(initializers)))));
11617                   FreeList(exp, FreeExpression);
11618                }
11619                else
11620                {
11621                   arrayExp.expType = ProcessTypeString("Container", false);
11622                   Compiler_Error($"Couldn't determine type of array elements\n");
11623                }
11624
11625                /*
11626                Declarator decl;
11627                OldList * specs = MkList();
11628
11629                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
11630                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
11631                stmt.compound.declarations = MkListOne(
11632                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11633                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName("BuiltInContainer")),
11634                   MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(MkIdentifier("__internalArray"))),
11635                      MkInitializerAssignment(MkExpBrackets(exp))))));
11636                */
11637             }
11638             else if(isLinkList && !isList)
11639             {
11640                Declarator decl;
11641                OldList * specs = MkList();
11642                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
11643                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11644                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11645                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalLinkList")),
11646                      MkInitializerAssignment(MkExpBrackets(exp))))));
11647             }
11648             /*else if(isCustomAVLTree)
11649             {
11650                Declarator decl;
11651                OldList * specs = MkList();
11652                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
11653                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11654                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11655                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalTree")),
11656                      MkInitializerAssignment(MkExpBrackets(exp))))));
11657             }*/
11658             else if(_class.templateArgs)
11659             {
11660                if(isMap)
11661                   sprintf(iteratorType, "MapIterator<%s, %s >", _class.templateArgs[5].dataTypeString, _class.templateArgs[6].dataTypeString);
11662                else
11663                   sprintf(iteratorType, "Iterator<%s, %s >", _class.templateArgs[2].dataTypeString, _class.templateArgs[1].dataTypeString);
11664
11665                stmt.compound.declarations = MkListOne(
11666                   MkDeclarationInst(MkInstantiationNamed(MkListOne(MkSpecifierName(iteratorType)),
11667                   MkExpIdentifier(id), MkListOne(MkMembersInitList(MkListOne(MkMemberInit(isMap ? MkListOne(MkIdentifier("map")) : null,
11668                   MkInitializerAssignment(MkExpBrackets(exp)))))))));
11669             }
11670             symbol = FindSymbol(id.string, curContext, curContext, false, false);
11671
11672             if(block)
11673             {
11674                // Reparent sub-contexts in this statement
11675                switch(block.type)
11676                {
11677                   case compoundStmt:
11678                      if(block.compound.context)
11679                         block.compound.context.parent = stmt.compound.context;
11680                      break;
11681                   case ifStmt:
11682                      if(block.ifStmt.stmt && block.ifStmt.stmt.type == compoundStmt && block.ifStmt.stmt.compound.context)
11683                         block.ifStmt.stmt.compound.context.parent = stmt.compound.context;
11684                      if(block.ifStmt.elseStmt && block.ifStmt.elseStmt.type == compoundStmt && block.ifStmt.elseStmt.compound.context)
11685                         block.ifStmt.elseStmt.compound.context.parent = stmt.compound.context;
11686                      break;
11687                   case switchStmt:
11688                      if(block.switchStmt.stmt && block.switchStmt.stmt.type == compoundStmt && block.switchStmt.stmt.compound.context)
11689                         block.switchStmt.stmt.compound.context.parent = stmt.compound.context;
11690                      break;
11691                   case whileStmt:
11692                      if(block.whileStmt.stmt && block.whileStmt.stmt.type == compoundStmt && block.whileStmt.stmt.compound.context)
11693                         block.whileStmt.stmt.compound.context.parent = stmt.compound.context;
11694                      break;
11695                   case doWhileStmt:
11696                      if(block.doWhile.stmt && block.doWhile.stmt.type == compoundStmt && block.doWhile.stmt.compound.context)
11697                         block.doWhile.stmt.compound.context.parent = stmt.compound.context;
11698                      break;
11699                   case forStmt:
11700                      if(block.forStmt.stmt && block.forStmt.stmt.type == compoundStmt && block.forStmt.stmt.compound.context)
11701                         block.forStmt.stmt.compound.context.parent = stmt.compound.context;
11702                      break;
11703                   case forEachStmt:
11704                      if(block.forEachStmt.stmt && block.forEachStmt.stmt.type == compoundStmt && block.forEachStmt.stmt.compound.context)
11705                         block.forEachStmt.stmt.compound.context.parent = stmt.compound.context;
11706                      break;
11707                   /* Only handle those with compound blocks for now... (Potential limitation on compound statements within expressions)
11708                   case labeledStmt:
11709                   case caseStmt
11710                   case expressionStmt:
11711                   case gotoStmt:
11712                   case continueStmt:
11713                   case breakStmt
11714                   case returnStmt:
11715                   case asmStmt:
11716                   case badDeclarationStmt:
11717                   case fireWatchersStmt:
11718                   case stopWatchingStmt:
11719                   case watchStmt:
11720                   */
11721                }
11722             }
11723             if(filter)
11724             {
11725                block = MkIfStmt(filter, block, null);
11726             }
11727             if(isArray)
11728             {
11729                stmt.compound.statements = MkListOne(MkForStmt(
11730                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array"))))),
11731                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
11732                      MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array")), '+', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
11733                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
11734                   block));
11735               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11736               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11737               ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11738             }
11739             else if(isBuiltin)
11740             {
11741                char count[128];
11742                //OldList * specs = MkList();
11743                // Declarator decl = SpecDeclFromString(typeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
11744
11745                sprintf(count, "%d", builtinCount);
11746
11747                stmt.compound.statements = MkListOne(MkForStmt(
11748                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpIdentifier(MkIdentifier("__internalArray"))))),
11749                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
11750                      MkExpOp(MkExpIdentifier(MkIdentifier("__internalArray")), '+', MkExpConstant(count))))),
11751                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
11752                   block));
11753
11754                /*
11755                Declarator decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
11756                stmt.compound.statements = MkListOne(MkForStmt(
11757                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))))),
11758                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
11759                      MkExpOp(MkExpCast(MkTypeName(specs, decl), MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))), '+', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
11760                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
11761                   block));
11762               */
11763               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11764               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11765               ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11766             }
11767             else if(isLinkList && !isList)
11768             {
11769                Class typeClass = eSystem_FindClass(_class.module, _class.templateArgs[3].dataTypeString);
11770                Class listItemClass = eSystem_FindClass(_class.module, "ListItem");
11771                if(typeClass && eClass_IsDerived(typeClass, listItemClass) && _class.templateArgs[5].dataTypeString &&
11772                   !strcmp(_class.templateArgs[5].dataTypeString, "LT::link"))
11773                {
11774                   stmt.compound.statements = MkListOne(MkForStmt(
11775                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
11776                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
11777                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
11778                      block));
11779                }
11780                else
11781                {
11782                   OldList * specs = MkList();
11783                   Declarator decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, null);
11784                   stmt.compound.statements = MkListOne(MkForStmt(
11785                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
11786                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
11787                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpCast(MkTypeName(specs, decl), MkExpCall(
11788                         MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("GetNext")),
11789                            MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName("IteratorPointer")), null), MkExpIdentifier(CopyIdentifier(id)))))))),
11790                      block));
11791                }
11792                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11793                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11794                ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11795             }
11796             /*else if(isCustomAVLTree)
11797             {
11798                stmt.compound.statements = MkListOne(MkForStmt(
11799                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpMember(MkExpIdentifier(
11800                      MkIdentifier("__internalTree")), MkIdentifier("root")), MkIdentifier("minimum"))))),
11801                   MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
11802                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
11803                   block));
11804
11805                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11806                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11807                ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11808             }*/
11809             else
11810             {
11811                stmt.compound.statements = MkListOne(MkWhileStmt(MkListOne(MkExpCall(MkExpMember(expIt = MkExpIdentifier(CopyIdentifier(id)),
11812                   MkIdentifier("Next")), null)), block));
11813             }
11814             ProcessExpressionType(expIt);
11815             if(stmt.compound.declarations->first)
11816                ProcessDeclaration(stmt.compound.declarations->first);
11817
11818             if(symbol)
11819                symbol.isIterator = isMap ? 2 : ((isArray || isBuiltin) ? 3 : (isLinkList ? (isList ? 5 : 4) : (isCustomAVLTree ? 6 : 1)));
11820
11821             ProcessStatement(stmt);
11822             curContext = stmt.compound.context.parent;
11823             break;
11824          }
11825          else
11826          {
11827             Compiler_Error($"Expression is not a container\n");
11828          }
11829          break;
11830       }
11831       case gotoStmt:
11832          break;
11833       case continueStmt:
11834          break;
11835       case breakStmt:
11836          break;
11837       case returnStmt:
11838       {
11839          Expression exp;
11840          if(stmt.expressions)
11841          {
11842             for(exp = stmt.expressions->first; exp; exp = exp.next)
11843             {
11844                if(!exp.next)
11845                {
11846                   if(curFunction && !curFunction.type)
11847                      curFunction.type = ProcessType(
11848                         curFunction.specifiers, curFunction.declarator);
11849                   FreeType(exp.destType);
11850                   exp.destType = (curFunction && curFunction.type && curFunction.type.kind == functionType) ? curFunction.type.returnType : null;
11851                   if(exp.destType) exp.destType.refCount++;
11852                }
11853                ProcessExpressionType(exp);
11854             }
11855          }
11856          break;
11857       }
11858       case badDeclarationStmt:
11859       {
11860          ProcessDeclaration(stmt.decl);
11861          break;
11862       }
11863       case asmStmt:
11864       {
11865          AsmField field;
11866          if(stmt.asmStmt.inputFields)
11867          {
11868             for(field = stmt.asmStmt.inputFields->first; field; field = field.next)
11869                if(field.expression)
11870                   ProcessExpressionType(field.expression);
11871          }
11872          if(stmt.asmStmt.outputFields)
11873          {
11874             for(field = stmt.asmStmt.outputFields->first; field; field = field.next)
11875                if(field.expression)
11876                   ProcessExpressionType(field.expression);
11877          }
11878          if(stmt.asmStmt.clobberedFields)
11879          {
11880             for(field = stmt.asmStmt.clobberedFields->first; field; field = field.next)
11881             {
11882                if(field.expression)
11883                   ProcessExpressionType(field.expression);
11884             }
11885          }
11886          break;
11887       }
11888       case watchStmt:
11889       {
11890          PropertyWatch propWatch;
11891          OldList * watches = stmt._watch.watches;
11892          Expression object = stmt._watch.object;
11893          Expression watcher = stmt._watch.watcher;
11894          if(watcher)
11895             ProcessExpressionType(watcher);
11896          if(object)
11897             ProcessExpressionType(object);
11898
11899          if(inCompiler)
11900          {
11901             if(watcher || thisClass)
11902             {
11903                External external = curExternal;
11904                Context context = curContext;
11905
11906                stmt.type = expressionStmt;
11907                stmt.expressions = MkList();
11908
11909                curExternal = external.prev;
11910
11911                for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
11912                {
11913                   ClassFunction func;
11914                   char watcherName[1024];
11915                   Class watcherClass = watcher ?
11916                      ((watcher.expType && watcher.expType.kind == classType && watcher.expType._class) ? watcher.expType._class.registered : null) : thisClass;
11917                   External createdExternal;
11918
11919                   // Create a declaration above
11920                   External externalDecl = MkExternalDeclaration(null);
11921                   ast->Insert(curExternal.prev, externalDecl);
11922
11923                   sprintf(watcherName,"__ecerePropertyWatcher_%d", propWatcherID++);
11924                   if(propWatch.deleteWatch)
11925                      strcat(watcherName, "_delete");
11926                   else
11927                   {
11928                      Identifier propID;
11929                      for(propID = propWatch.properties->first; propID; propID = propID.next)
11930                      {
11931                         strcat(watcherName, "_");
11932                         strcat(watcherName, propID.string);
11933                      }
11934                   }
11935
11936                   if(object && object.expType && object.expType.kind == classType && object.expType._class && object.expType._class.registered)
11937                   {
11938                      // TESTING THIS STUFF... BEWARE OF SYMBOL ID ISSUES
11939                      func = MkClassFunction(MkListOne(MkSpecifier(VOID)), null, MkDeclaratorFunction(MkDeclaratorIdentifier(MkIdentifier(watcherName)),
11940                         //MkListOne(MkTypeName(MkListOne(MkSpecifier(VOID)), null))), null);
11941                         MkListOne(MkTypeName(MkListOne(MkSpecifierName(object.expType._class.string)), MkDeclaratorIdentifier(MkIdentifier("value"))))), null);
11942                      ProcessClassFunctionBody(func, propWatch.compound);
11943                      propWatch.compound = null;
11944
11945                      //afterExternal = afterExternal ? afterExternal : curExternal;
11946
11947                      //createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal.prev);
11948                      createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal, true);
11949                      // TESTING THIS...
11950                      createdExternal.symbol.idCode = external.symbol.idCode;
11951
11952                      curExternal = createdExternal;
11953                      ProcessFunction(createdExternal.function);
11954
11955
11956                      // Create a declaration above
11957                      {
11958                         Declaration decl = MkDeclaration(CopyList(createdExternal.function.specifiers, CopySpecifier),
11959                            MkListOne(MkInitDeclarator(CopyDeclarator(createdExternal.function.declarator), null)));
11960                         externalDecl.declaration = decl;
11961                         if(decl.symbol && !decl.symbol.pointerExternal)
11962                            decl.symbol.pointerExternal = externalDecl;
11963                      }
11964
11965                      if(propWatch.deleteWatch)
11966                      {
11967                         OldList * args = MkList();
11968                         ListAdd(args, CopyExpression(object));
11969                         ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
11970                         ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
11971                         ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_WatchDestruction")), args));
11972                      }
11973                      else
11974                      {
11975                         Class _class = object.expType._class.registered;
11976                         Identifier propID;
11977
11978                         for(propID = propWatch.properties->first; propID; propID = propID.next)
11979                         {
11980                            char propName[1024];
11981                            Property prop = eClass_FindProperty(_class, propID.string, privateModule);
11982                            if(prop)
11983                            {
11984                               char getName[1024], setName[1024];
11985                               OldList * args = MkList();
11986
11987                               DeclareProperty(prop, setName, getName);
11988
11989                               // eInstance_Watch(stmt.watch.object, prop, stmt.watch.watcher, callback);
11990                               strcpy(propName, "__ecereProp_");
11991                               FullClassNameCat(propName, prop._class.fullName, false);
11992                               strcat(propName, "_");
11993                               // strcat(propName, prop.name);
11994                               FullClassNameCat(propName, prop.name, true);
11995
11996                               ListAdd(args, CopyExpression(object));
11997                               ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11998                               ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
11999                               ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
12000
12001                               ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_Watch")), args));
12002                            }
12003                            else
12004                               Compiler_Error($"Property %s not found in class %s\n", prop.name, _class.fullName);
12005                         }
12006                      }
12007                   }
12008                   else
12009                      Compiler_Error($"Invalid watched object\n");
12010                }
12011
12012                curExternal = external;
12013                curContext = context;
12014
12015                if(watcher)
12016                   FreeExpression(watcher);
12017                if(object)
12018                   FreeExpression(object);
12019                FreeList(watches, FreePropertyWatch);
12020             }
12021             else
12022                Compiler_Error($"No observer specified and not inside a _class\n");
12023          }
12024          else
12025          {
12026             for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12027             {
12028                ProcessStatement(propWatch.compound);
12029             }
12030
12031          }
12032          break;
12033       }
12034       case fireWatchersStmt:
12035       {
12036          OldList * watches = stmt._watch.watches;
12037          Expression object = stmt._watch.object;
12038          Class _class;
12039          // DEBUGGER BUG: Why doesn't watches evaluate to null??
12040          // printf("%X\n", watches);
12041          // printf("%X\n", stmt._watch.watches);
12042          if(object)
12043             ProcessExpressionType(object);
12044
12045          if(inCompiler)
12046          {
12047             _class = object ?
12048                   ((object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null) : thisClass;
12049
12050             if(_class)
12051             {
12052                Identifier propID;
12053
12054                stmt.type = expressionStmt;
12055                stmt.expressions = MkList();
12056
12057                // Check if we're inside a property set
12058                if(!watches && curFunction.propSet && (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
12059                {
12060                   watches = MkListOne(MkIdentifier(curFunction.propSet.string));
12061                }
12062                else if(!watches)
12063                {
12064                   //Compiler_Error($"No property specified and not inside a property set\n");
12065                }
12066                if(watches)
12067                {
12068                   for(propID = watches->first; propID; propID = propID.next)
12069                   {
12070                      Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12071                      if(prop)
12072                      {
12073                         CreateFireWatcher(prop, object, stmt);
12074                      }
12075                      else
12076                         Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12077                   }
12078                }
12079                else
12080                {
12081                   // Fire all properties!
12082                   Property prop;
12083                   Class base;
12084                   for(base = _class; base; base = base.base)
12085                   {
12086                      for(prop = base.membersAndProperties.first; prop; prop = prop.next)
12087                      {
12088                         if(prop.isProperty && prop.isWatchable)
12089                         {
12090                            CreateFireWatcher(prop, object, stmt);
12091                         }
12092                      }
12093                   }
12094                }
12095
12096                if(object)
12097                   FreeExpression(object);
12098                FreeList(watches, FreeIdentifier);
12099             }
12100             else
12101                Compiler_Error($"Invalid object specified and not inside a class\n");
12102          }
12103          break;
12104       }
12105       case stopWatchingStmt:
12106       {
12107          OldList * watches = stmt._watch.watches;
12108          Expression object = stmt._watch.object;
12109          Expression watcher = stmt._watch.watcher;
12110          Class _class;
12111          if(object)
12112             ProcessExpressionType(object);
12113          if(watcher)
12114             ProcessExpressionType(watcher);
12115          if(inCompiler)
12116          {
12117             _class = (object && object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null;
12118
12119             if(watcher || thisClass)
12120             {
12121                if(_class)
12122                {
12123                   Identifier propID;
12124
12125                   stmt.type = expressionStmt;
12126                   stmt.expressions = MkList();
12127
12128                   if(!watches)
12129                   {
12130                      OldList * args;
12131                      // eInstance_StopWatching(object, null, watcher);
12132                      args = MkList();
12133                      ListAdd(args, CopyExpression(object));
12134                      ListAdd(args, MkExpConstant("0"));
12135                      ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12136                      ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12137                   }
12138                   else
12139                   {
12140                      for(propID = watches->first; propID; propID = propID.next)
12141                      {
12142                         char propName[1024];
12143                         Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12144                         if(prop)
12145                         {
12146                            char getName[1024], setName[1024];
12147                            OldList * args = MkList();
12148
12149                            DeclareProperty(prop, setName, getName);
12150
12151                            // eInstance_StopWatching(object, prop, watcher);
12152                            strcpy(propName, "__ecereProp_");
12153                            FullClassNameCat(propName, prop._class.fullName, false);
12154                            strcat(propName, "_");
12155                            // strcat(propName, prop.name);
12156                            FullClassNameCat(propName, prop.name, true);
12157                            MangleClassName(propName);
12158
12159                            ListAdd(args, CopyExpression(object));
12160                            ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12161                            ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12162                            ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12163                         }
12164                         else
12165                            Compiler_Error($"Property %s not found in class %s\n", prop.name, _class.fullName);
12166                      }
12167                   }
12168
12169                   if(object)
12170                      FreeExpression(object);
12171                   if(watcher)
12172                      FreeExpression(watcher);
12173                   FreeList(watches, FreeIdentifier);
12174                }
12175                else
12176                   Compiler_Error($"Invalid object specified and not inside a class\n");
12177             }
12178             else
12179                Compiler_Error($"No observer specified and not inside a class\n");
12180          }
12181          break;
12182       }
12183    }
12184 }
12185
12186 static void ProcessFunction(FunctionDefinition function)
12187 {
12188    Identifier id = GetDeclId(function.declarator);
12189    Symbol symbol = function.declarator ? function.declarator.symbol : null;
12190    Type type = symbol ? symbol.type : null;
12191    Class oldThisClass = thisClass;
12192    Context oldTopContext = topContext;
12193
12194    yylloc = function.loc;
12195    // Process thisClass
12196
12197    if(type && type.thisClass)
12198    {
12199       Symbol classSym = type.thisClass;
12200       Class _class = type.thisClass.registered;
12201       char className[1024];
12202       char structName[1024];
12203       Declarator funcDecl;
12204       Symbol thisSymbol;
12205
12206       bool typedObject = false;
12207
12208       if(_class && !_class.base)
12209       {
12210          _class = currentClass;
12211          if(_class && !_class.symbol)
12212             _class.symbol = FindClass(_class.fullName);
12213          classSym = _class ? _class.symbol : null;
12214          typedObject = true;
12215       }
12216
12217       thisClass = _class;
12218
12219       if(inCompiler && _class)
12220       {
12221          if(type.kind == functionType)
12222          {
12223             if(symbol.type.params.count == 1 && ((Type)symbol.type.params.first).kind == voidType)
12224             {
12225                //TypeName param = symbol.type.params.first;
12226                Type param = symbol.type.params.first;
12227                symbol.type.params.Remove(param);
12228                //FreeTypeName(param);
12229                FreeType(param);
12230             }
12231             if(type.classObjectType != classPointer)
12232             {
12233                symbol.type.params.Insert(null, MkClassType(_class.fullName));
12234                symbol.type.staticMethod = true;
12235                symbol.type.thisClass = null;
12236
12237                // HIGH DANGER: VERIFYING THIS...
12238                symbol.type.extraParam = false;
12239             }
12240          }
12241
12242          strcpy(className, "__ecereClass_");
12243          FullClassNameCat(className, _class.fullName, true);
12244
12245          MangleClassName(className);
12246
12247          structName[0] = 0;
12248          FullClassNameCat(structName, _class.fullName, false);
12249
12250          // [class] this
12251
12252
12253          funcDecl = GetFuncDecl(function.declarator);
12254          if(funcDecl)
12255          {
12256             if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12257             {
12258                TypeName param = funcDecl.function.parameters->first;
12259                if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12260                {
12261                   funcDecl.function.parameters->Remove(param);
12262                   FreeTypeName(param);
12263                }
12264             }
12265
12266             // DANGER: Watch for this... Check if it's a Conversion?
12267             // if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
12268
12269             // WAS TRYING THIS FOR CONVERSION PROPERTIES ON NOHEAD CLASSES: if((_class.type == structClass) || function != (FunctionDefinition)symbol.externalSet)
12270             if(!function.propertyNoThis)
12271             {
12272                TypeName thisParam;
12273
12274                if(type.classObjectType != classPointer)
12275                {
12276                   thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12277                   if(!funcDecl.function.parameters)
12278                      funcDecl.function.parameters = MkList();
12279                   funcDecl.function.parameters->Insert(null, thisParam);
12280                }
12281
12282                if(typedObject)
12283                {
12284                   if(type.classObjectType != classPointer)
12285                   {
12286                      if(type.byReference || _class.type == unitClass || _class.type == systemClass || _class.type == enumClass || _class.type == bitClass)
12287                         thisParam.declarator = MkDeclaratorPointer(MkPointer(null,null), thisParam.declarator);
12288                   }
12289
12290                   thisParam = TypeName
12291                   {
12292                      declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
12293                      qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
12294                   };
12295                   funcDecl.function.parameters->Insert(null, thisParam);
12296                }
12297             }
12298          }
12299
12300          if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
12301          {
12302             InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
12303             funcDecl = GetFuncDecl(initDecl.declarator);
12304             if(funcDecl)
12305             {
12306                if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12307                {
12308                   TypeName param = funcDecl.function.parameters->first;
12309                   if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12310                   {
12311                      funcDecl.function.parameters->Remove(param);
12312                      FreeTypeName(param);
12313                   }
12314                }
12315
12316                if(type.classObjectType != classPointer)
12317                {
12318                   // DANGER: Watch for this... Check if it's a Conversion?
12319                   if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
12320                   {
12321                      TypeName thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12322
12323                      if(!funcDecl.function.parameters)
12324                         funcDecl.function.parameters = MkList();
12325                      funcDecl.function.parameters->Insert(null, thisParam);
12326                   }
12327                }
12328             }
12329          }
12330       }
12331
12332       // Add this to the context
12333       if(function.body)
12334       {
12335          if(type.classObjectType != classPointer)
12336          {
12337             thisSymbol = Symbol
12338             {
12339                string = CopyString("this");
12340                type = classSym ? MkClassType(classSym.string) : null; //_class.fullName);
12341             };
12342             function.body.compound.context.symbols.Add((BTNode)thisSymbol);
12343
12344             if(typedObject && thisSymbol.type)
12345             {
12346                thisSymbol.type.classObjectType = ClassObjectType::typedObject;
12347                thisSymbol.type.byReference = type.byReference;
12348                thisSymbol.type.typedByReference = type.byReference;
12349                /*
12350                thisSymbol = Symbol { string = CopyString("class") };
12351                function.body.compound.context.symbols.Add(thisSymbol);
12352                */
12353             }
12354          }
12355       }
12356
12357       // Pointer to class data
12358
12359       if(inCompiler && _class && (_class.type == normalClass /*|| _class.type == noHeadClass*/) && type.classObjectType != classPointer)
12360       {
12361          DataMember member = null;
12362          {
12363             Class base;
12364             for(base = _class; base && base.type != systemClass; base = base.next)
12365             {
12366                for(member = base.membersAndProperties.first; member; member = member.next)
12367                   if(!member.isProperty)
12368                      break;
12369                if(member)
12370                   break;
12371             }
12372          }
12373          for(member = _class.membersAndProperties.first; member; member = member.next)
12374             if(!member.isProperty)
12375                break;
12376          if(member)
12377          {
12378             char pointerName[1024];
12379
12380             Declaration decl;
12381             Initializer initializer;
12382             Expression exp, bytePtr;
12383
12384             strcpy(pointerName, "__ecerePointer_");
12385             FullClassNameCat(pointerName, _class.fullName, false);
12386             {
12387                char className[1024];
12388                strcpy(className, "__ecereClass_");
12389                FullClassNameCat(className, classSym.string, true);
12390                MangleClassName(className);
12391
12392                // Testing This
12393                DeclareClass(classSym, className);
12394             }
12395
12396             // ((byte *) this)
12397             bytePtr = QBrackets(MkExpCast(QMkType("char", QMkPtrDecl(null)), QMkExpId("this")));
12398
12399             if(_class.fixed)
12400             {
12401                char string[256];
12402                sprintf(string, "%d", _class.offset);
12403                exp = QBrackets(MkExpOp(bytePtr, '+', MkExpConstant(string)));
12404             }
12405             else
12406             {
12407                // ([bytePtr] + [className]->offset)
12408                exp = QBrackets(MkExpOp(bytePtr, '+',
12409                   MkExpPointer(QMkExpId(className), MkIdentifier("offset"))));
12410             }
12411
12412             // (this ? [exp] : 0)
12413             exp = QBrackets(QMkExpCond(QMkExpId("this"), exp, MkExpConstant("0")));
12414             exp.expType = Type
12415             {
12416                refCount = 1;
12417                kind = pointerType;
12418                type = Type { refCount = 1, kind = voidType };
12419             };
12420
12421             if(function.body)
12422             {
12423                yylloc = function.body.loc;
12424                // ([structName] *) [exp]
12425                // initializer = MkInitializerAssignment(MkExpCast(QMkType(structName, QMkPtrDecl(null)), exp));
12426                initializer = MkInitializerAssignment(
12427                   MkExpCast(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)), exp));
12428
12429                // [structName] * [pointerName] = [initializer];
12430                // decl = QMkDeclaration(structName, MkInitDeclarator(QMkPtrDecl(pointerName), initializer));
12431
12432                {
12433                   Context prevContext = curContext;
12434                   curContext = function.body.compound.context;
12435
12436                   decl = MkDeclaration(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)),
12437                      MkListOne(MkInitDeclarator(QMkPtrDecl(pointerName), initializer)));
12438
12439                   curContext = prevContext;
12440                }
12441
12442                // WHY?
12443                decl.symbol = null;
12444
12445                if(!function.body.compound.declarations)
12446                   function.body.compound.declarations = MkList();
12447                function.body.compound.declarations->Insert(null, decl);
12448             }
12449          }
12450       }
12451
12452
12453       // Loop through the function and replace undeclared identifiers
12454       // which are a member of the class (methods, properties or data)
12455       // by "this.[member]"
12456    }
12457    else
12458       thisClass = null;
12459
12460    if(id)
12461    {
12462       FreeSpecifier(id._class);
12463       id._class = null;
12464
12465       if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
12466       {
12467          InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
12468          id = GetDeclId(initDecl.declarator);
12469
12470          FreeSpecifier(id._class);
12471          id._class = null;
12472       }
12473    }
12474    if(function.body)
12475       topContext = function.body.compound.context;
12476    {
12477       FunctionDefinition oldFunction = curFunction;
12478       curFunction = function;
12479       if(function.body)
12480          ProcessStatement(function.body);
12481
12482       // If this is a property set and no firewatchers has been done yet, add one here
12483       if(inCompiler && function.propSet && !function.propSet.fireWatchersDone)
12484       {
12485          Statement prevCompound = curCompound;
12486          Context prevContext = curContext;
12487
12488          Statement fireWatchers = MkFireWatchersStmt(null, null);
12489          if(!function.body.compound.statements) function.body.compound.statements = MkList();
12490          ListAdd(function.body.compound.statements, fireWatchers);
12491
12492          curCompound = function.body;
12493          curContext = function.body.compound.context;
12494
12495          ProcessStatement(fireWatchers);
12496
12497          curContext = prevContext;
12498          curCompound = prevCompound;
12499
12500       }
12501
12502       curFunction = oldFunction;
12503    }
12504
12505    if(function.declarator)
12506    {
12507       ProcessDeclarator(function.declarator);
12508    }
12509
12510    topContext = oldTopContext;
12511    thisClass = oldThisClass;
12512 }
12513
12514 /////////// INSTANTIATIONS / DATA TYPES PASS /////////////////////////////////////////////
12515 static void ProcessClass(OldList definitions, Symbol symbol)
12516 {
12517    ClassDef def;
12518    External external = curExternal;
12519    Class regClass = symbol ? symbol.registered : null;
12520
12521    // Process all functions
12522    for(def = definitions.first; def; def = def.next)
12523    {
12524       if(def.type == functionClassDef)
12525       {
12526          if(def.function.declarator)
12527             curExternal = def.function.declarator.symbol.pointerExternal;
12528          else
12529             curExternal = external;
12530
12531          ProcessFunction((FunctionDefinition)def.function);
12532       }
12533       else if(def.type == declarationClassDef)
12534       {
12535          if(def.decl.type == instDeclaration)
12536          {
12537             thisClass = regClass;
12538             ProcessInstantiationType(def.decl.inst);
12539             thisClass = null;
12540          }
12541          // Testing this
12542          else
12543          {
12544             Class backThisClass = thisClass;
12545             if(regClass) thisClass = regClass;
12546             ProcessDeclaration(def.decl);
12547             thisClass = backThisClass;
12548          }
12549       }
12550       else if(def.type == defaultPropertiesClassDef && def.defProperties)
12551       {
12552          MemberInit defProperty;
12553
12554          // Add this to the context
12555          Symbol thisSymbol = Symbol
12556          {
12557             string = CopyString("this");
12558             type = regClass ? MkClassType(regClass.fullName) : null;
12559          };
12560          globalContext.symbols.Add((BTNode)thisSymbol);
12561
12562          for(defProperty = def.defProperties->first; defProperty; defProperty = defProperty.next)
12563          {
12564             thisClass = regClass;
12565             ProcessMemberInitData(defProperty, regClass, null, null, null, null);
12566             thisClass = null;
12567          }
12568
12569          globalContext.symbols.Remove((BTNode)thisSymbol);
12570          FreeSymbol(thisSymbol);
12571       }
12572       else if(def.type == propertyClassDef && def.propertyDef)
12573       {
12574          PropertyDef prop = def.propertyDef;
12575
12576          // Add this to the context
12577          /*
12578          Symbol thisSymbol = Symbol { string = CopyString("this"), type = MkClassType(regClass.fullName) };
12579          globalContext.symbols.Add(thisSymbol);
12580          */
12581
12582          thisClass = regClass;
12583          if(prop.setStmt)
12584          {
12585             if(regClass)
12586             {
12587                Symbol thisSymbol
12588                {
12589                   string = CopyString("this");
12590                   type = MkClassType(regClass.fullName);
12591                };
12592                prop.setStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12593             }
12594
12595             curExternal = prop.symbol ? prop.symbol.externalSet : null;
12596             ProcessStatement(prop.setStmt);
12597          }
12598          if(prop.getStmt)
12599          {
12600             if(regClass)
12601             {
12602                Symbol thisSymbol
12603                {
12604                   string = CopyString("this");
12605                   type = MkClassType(regClass.fullName);
12606                };
12607                prop.getStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12608             }
12609
12610             curExternal = prop.symbol ? prop.symbol.externalGet : null;
12611             ProcessStatement(prop.getStmt);
12612          }
12613          if(prop.issetStmt)
12614          {
12615             if(regClass)
12616             {
12617                Symbol thisSymbol
12618                {
12619                   string = CopyString("this");
12620                   type = MkClassType(regClass.fullName);
12621                };
12622                prop.issetStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12623             }
12624
12625             curExternal = prop.symbol ? prop.symbol.externalIsSet : null;
12626             ProcessStatement(prop.issetStmt);
12627          }
12628
12629          thisClass = null;
12630
12631          /*
12632          globalContext.symbols.Remove(thisSymbol);
12633          FreeSymbol(thisSymbol);
12634          */
12635       }
12636       else if(def.type == propertyWatchClassDef && def.propertyWatch)
12637       {
12638          PropertyWatch propertyWatch = def.propertyWatch;
12639
12640          thisClass = regClass;
12641          if(propertyWatch.compound)
12642          {
12643             Symbol thisSymbol
12644             {
12645                string = CopyString("this");
12646                type = regClass ? MkClassType(regClass.fullName) : null;
12647             };
12648
12649             propertyWatch.compound.compound.context.symbols.Add((BTNode)thisSymbol);
12650
12651             curExternal = null;
12652             ProcessStatement(propertyWatch.compound);
12653          }
12654          thisClass = null;
12655       }
12656    }
12657 }
12658
12659 void DeclareFunctionUtil(String s)
12660 {
12661    GlobalFunction function = eSystem_FindFunction(privateModule, s);
12662    if(function)
12663    {
12664       char name[1024];
12665       name[0] = 0;
12666       if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
12667          strcpy(name, "__ecereFunction_");
12668       FullClassNameCat(name, s, false); // Why is this using FullClassNameCat ?
12669       DeclareFunction(function, name);
12670    }
12671 }
12672
12673 void ComputeDataTypes()
12674 {
12675    External external;
12676    External temp { };
12677    External after = null;
12678
12679    currentClass = null;
12680
12681    containerClass = eSystem_FindClass(GetPrivateModule(), "Container");
12682
12683    for(external = ast->first; external; external = external.next)
12684    {
12685       if(external.type == declarationExternal)
12686       {
12687          Declaration decl = external.declaration;
12688          if(decl)
12689          {
12690             OldList * decls = decl.declarators;
12691             if(decls)
12692             {
12693                InitDeclarator initDecl = decls->first;
12694                if(initDecl)
12695                {
12696                   Declarator declarator = initDecl.declarator;
12697                   if(declarator && declarator.type == identifierDeclarator)
12698                   {
12699                      Identifier id = declarator.identifier;
12700                      if(id && id.string)
12701                      {
12702                         if(!strcmp(id.string, "uintptr_t") || !strcmp(id.string, "intptr_t") || !strcmp(id.string, "size_t") || !strcmp(id.string, "ssize_t"))
12703                         {
12704                            external.symbol.id = -1001, external.symbol.idCode = -1001;
12705                            after = external;
12706                         }
12707                      }
12708                   }
12709                }
12710             }
12711          }
12712        }
12713    }
12714
12715    temp.symbol = Symbol { id = -1000, idCode = -1000 };
12716    ast->Insert(after, temp);
12717    curExternal = temp;
12718
12719    DeclareFunctionUtil("eSystem_New");
12720    DeclareFunctionUtil("eSystem_New0");
12721    DeclareFunctionUtil("eSystem_Renew");
12722    DeclareFunctionUtil("eSystem_Renew0");
12723    DeclareFunctionUtil("eSystem_Delete");
12724    DeclareFunctionUtil("eClass_GetProperty");
12725    DeclareFunctionUtil("eInstance_FireSelfWatchers");
12726
12727    DeclareStruct("ecere::com::Class", false);
12728    DeclareStruct("ecere::com::Instance", false);
12729    DeclareStruct("ecere::com::Property", false);
12730    DeclareStruct("ecere::com::DataMember", false);
12731    DeclareStruct("ecere::com::Method", false);
12732    DeclareStruct("ecere::com::SerialBuffer", false);
12733    DeclareStruct("ecere::com::ClassTemplateArgument", false);
12734
12735    ast->Remove(temp);
12736
12737    for(external = ast->first; external; external = external.next)
12738    {
12739       afterExternal = curExternal = external;
12740       if(external.type == functionExternal)
12741       {
12742          currentClass = external.function._class;
12743          ProcessFunction(external.function);
12744       }
12745       // There shouldn't be any _class member access here anyways...
12746       else if(external.type == declarationExternal)
12747       {
12748          currentClass = null;
12749          ProcessDeclaration(external.declaration);
12750       }
12751       else if(external.type == classExternal)
12752       {
12753          ClassDefinition _class = external._class;
12754          currentClass = external.symbol.registered;
12755          if(_class.definitions)
12756          {
12757             ProcessClass(_class.definitions, _class.symbol);
12758          }
12759          if(inCompiler)
12760          {
12761             // Free class data...
12762             ast->Remove(external);
12763             delete external;
12764          }
12765       }
12766       else if(external.type == nameSpaceExternal)
12767       {
12768          thisNameSpace = external.id.string;
12769       }
12770    }
12771    currentClass = null;
12772    thisNameSpace = null;
12773
12774    delete temp.symbol;
12775    delete temp;
12776 }