compiler/libec; ide/debugger: Fixed potentially uninitialized Operands
[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    sprintf(temp, "%.16ff", result);
301    return CopyString(temp);
302 }
303
304 public char * PrintDouble(double result)
305 {
306    char temp[350];
307    sprintf(temp, "%.16f", result);
308    return CopyString(temp);
309 }
310
311 ////////////////////////////////////////////////////////////////////////
312 ////////////////////////////////////////////////////////////////////////
313
314 //public Operand GetOperand(Expression exp);
315
316 #define GETVALUE(name, t) \
317    public bool GetOp##name(Operand op2, t * value2) \
318    {                                                        \
319       if(op2.kind == intType && op2.type.isSigned) *value2 = (t) op2.i; \
320       else if(op2.kind == intType) *value2 = (t) op2.ui;                 \
321       else if(op2.kind == int64Type && op2.type.isSigned) *value2 = (t) op2.i64; \
322       else if(op2.kind == int64Type) *value2 = (t) op2.ui64;                 \
323       else if(op2.kind == intSizeType && op2.type.isSigned) *value2 = (t) op2.i64; \
324       else if(op2.kind == intSizeType) *value2 = (t) op2.ui64; \
325       else if(op2.kind == intPtrType && op2.type.isSigned) *value2 = (t) op2.i64; \
326       else if(op2.kind == intPtrType) *value2 = (t) op2.ui64;                 \
327       else if(op2.kind == shortType && op2.type.isSigned) *value2 = (t) op2.s;   \
328       else if(op2.kind == shortType) *value2 = (t) op2.us;                        \
329       else if(op2.kind == charType && op2.type.isSigned) *value2 = (t) op2.c;    \
330       else if(op2.kind == _BoolType || op2.kind == charType) *value2 = (t) op2.uc; \
331       else if(op2.kind == floatType) *value2 = (t) op2.f;                         \
332       else if(op2.kind == doubleType) *value2 = (t) op2.d;                        \
333       else if(op2.kind == pointerType) *value2 = (t) op2.ui64;                    \
334       else                                                                          \
335          return false;                                                              \
336       return true;                                                                  \
337    } \
338    public bool Get##name(Expression exp, t * value2) \
339    {                                                        \
340       Operand op2 = GetOperand(exp);                        \
341       return GetOp##name(op2, value2); \
342    }
343
344 // To help the deubugger currently not preprocessing...
345 #define HELP(x) x
346
347 GETVALUE(Int, HELP(int));
348 GETVALUE(UInt, HELP(unsigned int));
349 GETVALUE(Int64, HELP(int64));
350 GETVALUE(UInt64, HELP(uint64));
351 GETVALUE(IntPtr, HELP(intptr));
352 GETVALUE(UIntPtr, HELP(uintptr));
353 GETVALUE(IntSize, HELP(intsize));
354 GETVALUE(UIntSize, HELP(uintsize));
355 GETVALUE(Short, HELP(short));
356 GETVALUE(UShort, HELP(unsigned short));
357 GETVALUE(Char, HELP(char));
358 GETVALUE(UChar, HELP(unsigned char));
359 GETVALUE(Float, HELP(float));
360 GETVALUE(Double, HELP(double));
361
362 void ComputeExpression(Expression exp);
363
364 void ComputeClassMembers(Class _class, bool isMember)
365 {
366    DataMember member = isMember ? (DataMember) _class : null;
367    Context context = isMember ? null : SetupTemplatesContext(_class);
368    if(member || ((_class.type == bitClass || _class.type == normalClass || _class.type == structClass || _class.type == noHeadClass) &&
369                  (_class.type == bitClass || (!_class.structSize || _class.structSize == _class.offset)) && _class.computeSize))
370    {
371       int c;
372       int unionMemberOffset = 0;
373       int bitFields = 0;
374
375       /*
376       if(!member && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass) && _class.memberOffset && _class.memberOffset > _class.base.structSize)
377          _class.memberOffset = (_class.base && _class.base.type != systemClass) ? _class.base.structSize : 0;
378       */
379
380       if(member)
381       {
382          member.memberOffset = 0;
383          if(targetBits < sizeof(void *) * 8)
384             member.structAlignment = 0;
385       }
386       else if(targetBits < sizeof(void *) * 8)
387          _class.structAlignment = 0;
388
389       // Confusion here: non struct classes seem to have their memberOffset restart at 0 at each hierarchy level
390       if(!member && ((_class.type == normalClass || _class.type == noHeadClass) || (_class.type == structClass && _class.memberOffset && _class.memberOffset > _class.base.structSize)))
391          _class.memberOffset = (_class.base && _class.type == structClass) ? _class.base.structSize : 0;
392
393       if(!member && _class.destructionWatchOffset)
394          _class.memberOffset += sizeof(OldList);
395
396       // To avoid reentrancy...
397       //_class.structSize = -1;
398
399       {
400          DataMember dataMember;
401          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
402          {
403             if(!dataMember.isProperty)
404             {
405                if(dataMember.type == normalMember && dataMember.dataTypeString && !dataMember.dataType)
406                {
407                   dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
408                   /*if(!dataMember.dataType)
409                      dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
410                      */
411                }
412             }
413          }
414       }
415
416       {
417          DataMember dataMember;
418          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
419          {
420             if(!dataMember.isProperty && (dataMember.type != normalMember || dataMember.dataTypeString))
421             {
422                if(!isMember && _class.type == bitClass && dataMember.dataType)
423                {
424                   BitMember bitMember = (BitMember) dataMember;
425                   uint64 mask = 0;
426                   int d;
427
428                   ComputeTypeSize(dataMember.dataType);
429
430                   if(bitMember.pos == -1) bitMember.pos = _class.memberOffset;
431                   if(!bitMember.size) bitMember.size = dataMember.dataType.size * 8;
432
433                   _class.memberOffset = bitMember.pos + bitMember.size;
434                   for(d = 0; d<bitMember.size; d++)
435                   {
436                      if(d)
437                         mask <<= 1;
438                      mask |= 1;
439                   }
440                   bitMember.mask = mask << bitMember.pos;
441                }
442                else if(dataMember.type == normalMember && dataMember.dataType)
443                {
444                   int size;
445                   int alignment = 0;
446
447                   // Prevent infinite recursion
448                   if(dataMember.dataType.kind != classType ||
449                      ((!dataMember.dataType._class || !dataMember.dataType._class.registered || dataMember.dataType._class.registered != _class ||
450                      _class.type != structClass)))
451                      ComputeTypeSize(dataMember.dataType);
452
453                   if(dataMember.dataType.bitFieldCount)
454                   {
455                      bitFields += dataMember.dataType.bitFieldCount;
456                      size = 0;
457                   }
458                   else
459                   {
460                      if(bitFields)
461                      {
462                         int size = (bitFields + 7) / 8;
463
464                         if(isMember)
465                         {
466                            // TESTING THIS PADDING CODE
467                            if(alignment)
468                            {
469                               member.structAlignment = Max(member.structAlignment, alignment);
470
471                               if(member.memberOffset % alignment)
472                                  member.memberOffset += alignment - (member.memberOffset % alignment);
473                            }
474
475                            dataMember.offset = member.memberOffset;
476                            if(member.type == unionMember)
477                               unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
478                            else
479                            {
480                               member.memberOffset += size;
481                            }
482                         }
483                         else
484                         {
485                            // TESTING THIS PADDING CODE
486                            if(alignment)
487                            {
488                               _class.structAlignment = Max(_class.structAlignment, alignment);
489
490                               if(_class.memberOffset % alignment)
491                                  _class.memberOffset += alignment - (_class.memberOffset % alignment);
492                            }
493
494                            dataMember.offset = _class.memberOffset;
495                            _class.memberOffset += size;
496                         }
497                         bitFields = 0;
498                      }
499                      size = dataMember.dataType.size;
500                      alignment = dataMember.dataType.alignment;
501                   }
502
503                   if(isMember)
504                   {
505                      // TESTING THIS PADDING CODE
506                      if(alignment)
507                      {
508                         member.structAlignment = Max(member.structAlignment, alignment);
509
510                         if(member.memberOffset % alignment)
511                            member.memberOffset += alignment - (member.memberOffset % alignment);
512                      }
513
514                      dataMember.offset = member.memberOffset;
515                      if(member.type == unionMember)
516                         unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
517                      else
518                      {
519                         member.memberOffset += size;
520                      }
521                   }
522                   else
523                   {
524                      // TESTING THIS PADDING CODE
525                      if(alignment)
526                      {
527                         _class.structAlignment = Max(_class.structAlignment, alignment);
528
529                         if(_class.memberOffset % alignment)
530                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
531                      }
532
533                      dataMember.offset = _class.memberOffset;
534                      _class.memberOffset += size;
535                   }
536                }
537                else
538                {
539                   int alignment;
540
541                   ComputeClassMembers((Class)dataMember, true);
542                   alignment = dataMember.structAlignment;
543
544                   if(isMember)
545                   {
546                      if(alignment)
547                      {
548                         if(member.memberOffset % alignment)
549                            member.memberOffset += alignment - (member.memberOffset % alignment);
550
551                         member.structAlignment = Max(member.structAlignment, alignment);
552                      }
553                      dataMember.offset = member.memberOffset;
554                      if(member.type == unionMember)
555                         unionMemberOffset = Max(unionMemberOffset, dataMember.memberOffset);
556                      else
557                         member.memberOffset += dataMember.memberOffset;
558                   }
559                   else
560                   {
561                      if(alignment)
562                      {
563                         if(_class.memberOffset % alignment)
564                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
565                         _class.structAlignment = Max(_class.structAlignment, alignment);
566                      }
567                      dataMember.offset = _class.memberOffset;
568                      _class.memberOffset += dataMember.memberOffset;
569                   }
570                }
571             }
572          }
573          if(bitFields)
574          {
575             int alignment = 0;
576             int size = (bitFields + 7) / 8;
577
578             if(isMember)
579             {
580                // TESTING THIS PADDING CODE
581                if(alignment)
582                {
583                   member.structAlignment = Max(member.structAlignment, alignment);
584
585                   if(member.memberOffset % alignment)
586                      member.memberOffset += alignment - (member.memberOffset % alignment);
587                }
588
589                if(member.type == unionMember)
590                   unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
591                else
592                {
593                   member.memberOffset += size;
594                }
595             }
596             else
597             {
598                // TESTING THIS PADDING CODE
599                if(alignment)
600                {
601                   _class.structAlignment = Max(_class.structAlignment, alignment);
602
603                   if(_class.memberOffset % alignment)
604                      _class.memberOffset += alignment - (_class.memberOffset % alignment);
605                }
606                _class.memberOffset += size;
607             }
608             bitFields = 0;
609          }
610       }
611       if(member && member.type == unionMember)
612       {
613          member.memberOffset = unionMemberOffset;
614       }
615
616       if(!isMember)
617       {
618          /*if(_class.type == structClass)
619             _class.size = _class.memberOffset;
620          else
621          */
622
623          if(_class.type != bitClass)
624          {
625             int extra = 0;
626             if(_class.structAlignment)
627             {
628                if(_class.memberOffset % _class.structAlignment)
629                   extra += _class.structAlignment - (_class.memberOffset % _class.structAlignment);
630             }
631             _class.structSize = (_class.base ? (_class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize) : 0) + _class.memberOffset + extra;
632             if(!member)
633             {
634                Property prop;
635                for(prop = _class.membersAndProperties.first; prop; prop = prop.next)
636                {
637                   if(prop.isProperty && prop.isWatchable)
638                   {
639                      prop.watcherOffset = _class.structSize;
640                      _class.structSize += sizeof(OldList);
641                   }
642                }
643             }
644
645             // Fix Derivatives
646             {
647                OldLink derivative;
648                for(derivative = _class.derivatives.first; derivative; derivative = derivative.next)
649                {
650                   Class deriv = derivative.data;
651
652                   if(deriv.computeSize)
653                   {
654                      // TESTING THIS NEW CODE HERE... TRYING TO FIX ScrollBar MEMBERS DEBUGGING
655                      deriv.offset = /*_class.offset + */_class.structSize;
656                      deriv.memberOffset = 0;
657                      // ----------------------
658
659                      deriv.structSize = deriv.offset;
660
661                      ComputeClassMembers(deriv, false);
662                   }
663                }
664             }
665          }
666       }
667    }
668    if(context)
669       FinishTemplatesContext(context);
670 }
671
672 public void ComputeModuleClasses(Module module)
673 {
674    Class _class;
675    OldLink subModule;
676
677    for(subModule = module.modules.first; subModule; subModule = subModule.next)
678       ComputeModuleClasses(subModule.data);
679    for(_class = module.classes.first; _class; _class = _class.next)
680       ComputeClassMembers(_class, false);
681 }
682
683
684 public int ComputeTypeSize(Type type)
685 {
686    uint size = type ? type.size : 0;
687    if(!size && type && !type.computing)
688    {
689       type.computing = true;
690       switch(type.kind)
691       {
692          case _BoolType: type.alignment = size = sizeof(char); break;   // Assuming 1 byte _Bool
693          case charType: type.alignment = size = sizeof(char); break;
694          case intType: type.alignment = size = sizeof(int); break;
695          case int64Type: type.alignment = size = sizeof(int64); break;
696          case intPtrType: type.alignment = size = targetBits / 8; break;
697          case intSizeType: type.alignment = size = targetBits / 8; break;
698          case longType: type.alignment = size = sizeof(long); break;
699          case shortType: type.alignment = size = sizeof(short); break;
700          case floatType: type.alignment = size = sizeof(float); break;
701          case doubleType: type.alignment = size = sizeof(double); break;
702          case classType:
703          {
704             Class _class = type._class ? type._class.registered : null;
705
706             if(_class && _class.type == structClass)
707             {
708                // Ensure all members are properly registered
709                ComputeClassMembers(_class, false);
710                type.alignment = _class.structAlignment;
711                size = _class.structSize;
712                if(type.alignment && size % type.alignment)
713                   size += type.alignment - (size % type.alignment);
714
715             }
716             else if(_class && (_class.type == unitClass ||
717                    _class.type == enumClass ||
718                    _class.type == bitClass))
719             {
720                if(!_class.dataType)
721                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
722                size = type.alignment = ComputeTypeSize(_class.dataType);
723             }
724             else
725                size = type.alignment = targetBits / 8; // sizeof(Instance *);
726             break;
727          }
728          case pointerType: case subClassType: size = type.alignment = targetBits / 8; /*sizeof(void *); */break;
729          case arrayType:
730             if(type.arraySizeExp)
731             {
732                ProcessExpressionType(type.arraySizeExp);
733                ComputeExpression(type.arraySizeExp);
734                if(!type.arraySizeExp.isConstant || (type.arraySizeExp.expType.kind != intType && type.arraySizeExp.expType.kind != enumType &&
735                   (type.arraySizeExp.expType.kind != classType || !type.arraySizeExp.expType._class.registered || type.arraySizeExp.expType._class.registered.type != enumClass)))
736                {
737                   Location oldLoc = yylloc;
738                   // bool isConstant = type.arraySizeExp.isConstant;
739                   char expression[10240];
740                   expression[0] = '\0';
741                   type.arraySizeExp.expType = null;
742                   yylloc = type.arraySizeExp.loc;
743                   if(inCompiler)
744                      PrintExpression(type.arraySizeExp, expression);
745                   Compiler_Error($"Array size not constant int (%s)\n", expression);
746                   yylloc = oldLoc;
747                }
748                GetInt(type.arraySizeExp, &type.arraySize);
749             }
750             else if(type.enumClass)
751             {
752                if(type.enumClass && type.enumClass.registered && type.enumClass.registered.type == enumClass)
753                {
754                   type.arraySize = (int)eClass_GetProperty(type.enumClass.registered, "enumSize");
755                }
756                else
757                   type.arraySize = 0;
758             }
759             else
760             {
761                // Unimplemented auto size
762                type.arraySize = 0;
763             }
764
765             size = ComputeTypeSize(type.type) * type.arraySize;
766             if(type.type)
767                type.alignment = type.type.alignment;
768
769             break;
770          case structType:
771          {
772             Type member;
773             for(member = type.members.first; member; member = member.next)
774             {
775                uint addSize = ComputeTypeSize(member);
776
777                member.offset = size;
778                if(member.alignment && size % member.alignment)
779                   member.offset += member.alignment - (size % member.alignment);
780                size = member.offset;
781
782                type.alignment = Max(type.alignment, member.alignment);
783                size += addSize;
784             }
785             if(type.alignment && size % type.alignment)
786                size += type.alignment - (size % type.alignment);
787             break;
788          }
789          case unionType:
790          {
791             Type member;
792             for(member = type.members.first; member; member = member.next)
793             {
794                uint addSize = ComputeTypeSize(member);
795
796                member.offset = size;
797                if(member.alignment && size % member.alignment)
798                   member.offset += member.alignment - (size % member.alignment);
799                size = member.offset;
800
801                type.alignment = Max(type.alignment, member.alignment);
802                size = Max(size, addSize);
803             }
804             if(type.alignment && size % type.alignment)
805                size += type.alignment - (size % type.alignment);
806             break;
807          }
808          case templateType:
809          {
810             TemplateParameter param = type.templateParameter;
811             Type baseType = ProcessTemplateParameterType(param);
812             if(baseType)
813             {
814                size = ComputeTypeSize(baseType);
815                type.alignment = baseType.alignment;
816             }
817             else
818                type.alignment = size = sizeof(uint64);
819             break;
820          }
821          case enumType:
822          {
823             type.alignment = size = sizeof(enum { test });
824             break;
825          }
826          case thisClassType:
827          {
828             type.alignment = size = targetBits / 8; //sizeof(void *);
829             break;
830          }
831       }
832       type.size = size;
833       type.computing = false;
834    }
835    return size;
836 }
837
838
839 /*static */int AddMembers(OldList * declarations, Class _class, bool isMember, uint * retSize, Class topClass, bool *addedPadding)
840 {
841    // This function is in need of a major review when implementing private members etc.
842    DataMember topMember = isMember ? (DataMember) _class : null;
843    uint totalSize = 0;
844    uint maxSize = 0;
845    int alignment, size;
846    DataMember member;
847    Context context = isMember ? null : SetupTemplatesContext(_class);
848    if(addedPadding)
849       *addedPadding = false;
850
851    if(!isMember && _class.base)
852    {
853       maxSize = _class.structSize;
854       //if(_class.base.type != systemClass) // Commented out with new Instance _class
855       {
856          // DANGER: Testing this noHeadClass here...
857          if(_class.type == structClass || _class.type == noHeadClass)
858             /*totalSize = */AddMembers(declarations, _class.base, false, &totalSize, topClass, null);
859          else
860          {
861             uint baseSize = _class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize;
862             if(maxSize > baseSize)
863                maxSize -= baseSize;
864             else
865                maxSize = 0;
866          }
867       }
868    }
869
870    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
871    {
872       if(!member.isProperty)
873       {
874          switch(member.type)
875          {
876             case normalMember:
877             {
878                if(member.dataTypeString)
879                {
880                   OldList * specs = MkList(), * decls = MkList();
881                   Declarator decl;
882
883                   decl = SpecDeclFromString(member.dataTypeString, specs,
884                      MkDeclaratorIdentifier(MkIdentifier(member.name)));
885                   ListAdd(decls, MkStructDeclarator(decl, null));
886                   ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, decls, null)));
887
888                   if(!member.dataType)
889                      member.dataType = ProcessType(specs, decl);
890
891                   ReplaceThisClassSpecifiers(specs, topClass /*member._class*/);
892
893                   {
894                      Type type = ProcessType(specs, decl);
895                      DeclareType(member.dataType, false, false);
896                      FreeType(type);
897                   }
898                   /*
899                   if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
900                      member.dataType._class.registered && member.dataType._class.registered.type == structClass)
901                      DeclareStruct(member.dataType._class.string, false);
902                   */
903
904                   ComputeTypeSize(member.dataType);
905                   size = member.dataType.size;
906                   alignment = member.dataType.alignment;
907
908                   if(alignment)
909                   {
910                      if(totalSize % alignment)
911                         totalSize += alignment - (totalSize % alignment);
912                   }
913                   totalSize += size;
914                }
915                break;
916             }
917             case unionMember:
918             case structMember:
919             {
920                OldList * specs = MkList(), * list = MkList();
921
922                size = 0;
923                AddMembers(list, (Class)member, true, &size, topClass, null);
924                ListAdd(specs,
925                   MkStructOrUnion((member.type == unionMember)?unionSpecifier:structSpecifier, null, list));
926                ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, null, null)));
927                alignment = member.structAlignment;
928
929                if(alignment)
930                {
931                   if(totalSize % alignment)
932                      totalSize += alignment - (totalSize % alignment);
933                }
934                totalSize += size;
935                break;
936             }
937          }
938       }
939    }
940    if(retSize)
941    {
942       if(topMember && topMember.type == unionMember)
943          *retSize = Max(*retSize, totalSize);
944       else
945          *retSize += totalSize;
946    }
947    else if(totalSize < maxSize && _class.type != systemClass)
948    {
949       int autoPadding = 0;
950       if(!isMember && _class.structAlignment && totalSize % _class.structAlignment)
951          autoPadding = _class.structAlignment - (totalSize % _class.structAlignment);
952       if(totalSize + autoPadding < maxSize)
953       {
954          char sizeString[50];
955          sprintf(sizeString, "%d", maxSize - totalSize);
956          ListAdd(declarations,
957             MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(CHAR)),
958             MkListOne(MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__ecere_padding")), MkExpConstant(sizeString))), null)));
959          if(addedPadding)
960             *addedPadding = true;
961       }
962    }
963    if(context)
964       FinishTemplatesContext(context);
965    return topMember ? topMember.memberID : _class.memberID;
966 }
967
968 static int DeclareMembers(Class _class, bool isMember)
969 {
970    DataMember topMember = isMember ? (DataMember) _class : null;
971    uint totalSize = 0;
972    DataMember member;
973    Context context = isMember ? null : SetupTemplatesContext(_class);
974
975    if(!isMember && (_class.type == structClass || _class.type == noHeadClass) && _class.base.type != systemClass)
976       DeclareMembers(_class.base, false);
977
978    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
979    {
980       if(!member.isProperty)
981       {
982          switch(member.type)
983          {
984             case normalMember:
985             {
986                /*
987                if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
988                   member.dataType._class.registered && member.dataType._class.registered.type == structClass)
989                   DeclareStruct(member.dataType._class.string, false);
990                   */
991                if(!member.dataType && member.dataTypeString)
992                   member.dataType = ProcessTypeString(member.dataTypeString, false);
993                if(member.dataType)
994                   DeclareType(member.dataType, false, false);
995                break;
996             }
997             case unionMember:
998             case structMember:
999             {
1000                DeclareMembers((Class)member, true);
1001                break;
1002             }
1003          }
1004       }
1005    }
1006    if(context)
1007       FinishTemplatesContext(context);
1008
1009    return topMember ? topMember.memberID : _class.memberID;
1010 }
1011
1012 void DeclareStruct(char * name, bool skipNoHead)
1013 {
1014    External external = null;
1015    Symbol classSym = FindClass(name);
1016
1017    if(!inCompiler || !classSym) return;
1018
1019    // We don't need any declaration for bit classes...
1020    if(classSym.registered &&
1021       (classSym.registered.type == bitClass || classSym.registered.type == unitClass || classSym.registered.type == enumClass))
1022       return;
1023
1024    /*if(classSym.registered.templateClass)
1025       return DeclareStruct(classSym.registered.templateClass.fullName, skipNoHead);
1026    */
1027
1028    if(classSym.registered && classSym.imported && !classSym.declaredStructSym)
1029    {
1030       // Add typedef struct
1031       Declaration decl;
1032       OldList * specifiers, * declarators;
1033       OldList * declarations = null;
1034       char structName[1024];
1035       external = (classSym.registered && classSym.registered.type == structClass) ?
1036          classSym.pointerExternal : classSym.structExternal;
1037
1038       // TEMPORARY HACK: Pass 3 will move up struct declarations without moving members
1039       // Moved this one up because DeclareClass done later will need it
1040
1041       classSym.declaring++;
1042
1043       if(strchr(classSym.string, '<'))
1044       {
1045          if(classSym.registered.templateClass)
1046          {
1047             DeclareStruct(classSym.registered.templateClass.fullName, skipNoHead);
1048             classSym.declaring--;
1049          }
1050          return;
1051       }
1052
1053       //if(!skipNoHead)
1054          DeclareMembers(classSym.registered, false);
1055
1056       structName[0] = 0;
1057       FullClassNameCat(structName, name, false);
1058
1059       /*if(!external)
1060          external = MkExternalDeclaration(null);*/
1061
1062       if(!skipNoHead)
1063       {
1064          bool addedPadding = false;
1065          classSym.declaredStructSym = true;
1066
1067          declarations = MkList();
1068
1069          AddMembers(declarations, classSym.registered, false, null, classSym.registered, &addedPadding);
1070
1071          //ListAdd(specifiers, MkSpecifier(TYPEDEF));
1072          //ListAdd(specifiers, MkStructOrUnion(structSpecifier, null, declarations));
1073
1074          if(!declarations->count || (declarations->count == 1 && addedPadding))
1075          {
1076             FreeList(declarations, FreeClassDef);
1077             declarations = null;
1078          }
1079       }
1080       if(skipNoHead || declarations)
1081       {
1082          if(external && external.declaration)
1083          {
1084             ((Specifier)external.declaration.specifiers->first).definitions = declarations;
1085
1086             if(curExternal && curExternal.symbol && curExternal.symbol.idCode < classSym.id)
1087             {
1088                // TODO: Fix this
1089                //ast->Move(classSym.structExternal ? classSym.structExternal : classSym.pointerExternal, curExternal.prev);
1090
1091                // DANGER
1092                if(classSym.structExternal)
1093                   ast->Move(classSym.structExternal, curExternal.prev);
1094                ast->Move(classSym.pointerExternal, curExternal.prev);
1095
1096                classSym.id = curExternal.symbol.idCode;
1097                classSym.idCode = curExternal.symbol.idCode;
1098                // external = classSym.pointerExternal;
1099                //external = classSym.structExternal ? classSym.structExternal : classSym.pointerExternal;
1100             }
1101          }
1102          else
1103          {
1104             if(!external)
1105                external = MkExternalDeclaration(null);
1106
1107             specifiers = MkList();
1108             declarators = MkList();
1109             ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), declarations));
1110
1111             /*
1112             d = MkDeclaratorIdentifier(MkIdentifier(structName));
1113             ListAdd(declarators, MkInitDeclarator(d, null));
1114             */
1115             external.declaration = decl = MkDeclaration(specifiers, declarators);
1116             if(decl.symbol && !decl.symbol.pointerExternal)
1117                decl.symbol.pointerExternal = external;
1118
1119             // For simple classes, keep the declaration as the external to move around
1120             if(classSym.registered && classSym.registered.type == structClass)
1121             {
1122                char className[1024];
1123                strcpy(className, "__ecereClass_");
1124                FullClassNameCat(className, classSym.string, true);
1125                MangleClassName(className);
1126
1127                // Testing This
1128                DeclareClass(classSym, className);
1129
1130                external.symbol = classSym;
1131                classSym.pointerExternal = external;
1132                classSym.id = (curExternal && curExternal.symbol) ? curExternal.symbol.idCode : 0;
1133                classSym.idCode = (curExternal && curExternal.symbol) ? curExternal.symbol.idCode : 0;
1134             }
1135             else
1136             {
1137                char className[1024];
1138                strcpy(className, "__ecereClass_");
1139                FullClassNameCat(className, classSym.string, true);
1140                MangleClassName(className);
1141
1142                // TOFIX: TESTING THIS...
1143                classSym.structExternal = external;
1144                DeclareClass(classSym, className);
1145                external.symbol = classSym;
1146             }
1147
1148             //if(curExternal)
1149                ast->Insert(curExternal ? curExternal.prev : null, external);
1150          }
1151       }
1152
1153       classSym.declaring--;
1154    }
1155    else if(curExternal && curExternal.symbol && curExternal.symbol.idCode < classSym.id)
1156    {
1157       // TEMPORARY HACK: Pass 3 will move up struct declarations without moving members
1158       // Moved this one up because DeclareClass done later will need it
1159
1160       // TESTING THIS:
1161       classSym.declaring++;
1162
1163       //if(!skipNoHead)
1164       {
1165          if(classSym.registered)
1166             DeclareMembers(classSym.registered, false);
1167       }
1168
1169       if(classSym.registered && (classSym.registered.type == structClass || classSym.registered.type == noHeadClass))
1170       {
1171          // TODO: Fix this
1172          //ast->Move(classSym.structExternal ? classSym.structExternal : classSym.pointerExternal, curExternal.prev);
1173
1174          // DANGER
1175          if(classSym.structExternal)
1176             ast->Move(classSym.structExternal, curExternal.prev);
1177          ast->Move(classSym.pointerExternal, curExternal.prev);
1178
1179          classSym.id = curExternal.symbol.idCode;
1180          classSym.idCode = curExternal.symbol.idCode;
1181          // external = classSym.pointerExternal;
1182          // external = classSym.structExternal ? classSym.structExternal : classSym.pointerExternal;
1183       }
1184
1185       classSym.declaring--;
1186    }
1187    //return external;
1188 }
1189
1190 void DeclareProperty(Property prop, char * setName, char * getName)
1191 {
1192    Symbol symbol = prop.symbol;
1193    char propName[1024];
1194
1195    strcpy(setName, "__ecereProp_");
1196    FullClassNameCat(setName, prop._class.fullName, false);
1197    strcat(setName, "_Set_");
1198    // strcat(setName, prop.name);
1199    FullClassNameCat(setName, prop.name, true);
1200
1201    strcpy(getName, "__ecereProp_");
1202    FullClassNameCat(getName, prop._class.fullName, false);
1203    strcat(getName, "_Get_");
1204    FullClassNameCat(getName, prop.name, true);
1205    // strcat(getName, prop.name);
1206
1207    strcpy(propName, "__ecereProp_");
1208    FullClassNameCat(propName, prop._class.fullName, false);
1209    strcat(propName, "_");
1210    FullClassNameCat(propName, prop.name, true);
1211    // strcat(propName, prop.name);
1212
1213    // To support "char *" property
1214    MangleClassName(getName);
1215    MangleClassName(setName);
1216    MangleClassName(propName);
1217
1218    if(prop._class.type == structClass)
1219       DeclareStruct(prop._class.fullName, false);
1220
1221    if(!symbol || curExternal.symbol.idCode < symbol.id)
1222    {
1223       bool imported = false;
1224       bool dllImport = false;
1225       if(!symbol || symbol._import)
1226       {
1227          if(!symbol)
1228          {
1229             Symbol classSym;
1230             if(!prop._class.symbol)
1231                prop._class.symbol = FindClass(prop._class.fullName);
1232             classSym = prop._class.symbol;
1233             if(classSym && !classSym._import)
1234             {
1235                ModuleImport module;
1236
1237                if(prop._class.module)
1238                   module = FindModule(prop._class.module);
1239                else
1240                   module = mainModule;
1241
1242                classSym._import = ClassImport
1243                {
1244                   name = CopyString(prop._class.fullName);
1245                   isRemote = prop._class.isRemote;
1246                };
1247                module.classes.Add(classSym._import);
1248             }
1249             symbol = prop.symbol = Symbol { };
1250             symbol._import = (ClassImport)PropertyImport
1251             {
1252                name = CopyString(prop.name);
1253                isVirtual = false; //prop.isVirtual;
1254                hasSet = prop.Set ? true : false;
1255                hasGet = prop.Get ? true : false;
1256             };
1257             if(classSym)
1258                classSym._import.properties.Add(symbol._import);
1259          }
1260          imported = true;
1261          if(prop._class.module != privateModule && prop._class.module.importType != staticImport)
1262             dllImport = true;
1263       }
1264
1265       if(!symbol.type)
1266       {
1267          Context context = SetupTemplatesContext(prop._class);
1268          symbol.type = ProcessTypeString(prop.dataTypeString, false);
1269          FinishTemplatesContext(context);
1270       }
1271
1272       // Get
1273       if(prop.Get)
1274       {
1275          if(!symbol.externalGet || symbol.externalGet.type == functionExternal)
1276          {
1277             Declaration decl;
1278             OldList * specifiers, * declarators;
1279             Declarator d;
1280             OldList * params;
1281             Specifier spec;
1282             External external;
1283             Declarator typeDecl;
1284             bool simple = false;
1285
1286             specifiers = MkList();
1287             declarators = MkList();
1288             params = MkList();
1289
1290             ListAdd(params, MkTypeName(MkListOne(MkSpecifierName /*MkClassName*/(prop._class.fullName)),
1291                MkDeclaratorIdentifier(MkIdentifier("this"))));
1292
1293             d = MkDeclaratorIdentifier(MkIdentifier(getName));
1294             //if(imported)
1295             if(dllImport)
1296                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1297
1298             {
1299                Context context = SetupTemplatesContext(prop._class);
1300                typeDecl = SpecDeclFromString(prop.dataTypeString, specifiers, null);
1301                FinishTemplatesContext(context);
1302             }
1303
1304             // Make sure the simple _class's type is declared
1305             for(spec = specifiers->first; spec; spec = spec.next)
1306             {
1307                if(spec.type == nameSpecifier /*SpecifierClass*/)
1308                {
1309                   if((!typeDecl || typeDecl.type == identifierDeclarator))
1310                   {
1311                      Symbol classSym = spec.symbol; // FindClass(spec.name);
1312                      symbol._class = classSym.registered;
1313                      if(classSym.registered && classSym.registered.type == structClass)
1314                      {
1315                         DeclareStruct(spec.name, false);
1316                         simple = true;
1317                      }
1318                   }
1319                }
1320             }
1321
1322             if(!simple)
1323                d = PlugDeclarator(typeDecl, d);
1324             else
1325             {
1326                ListAdd(params, MkTypeName(specifiers,
1327                   PlugDeclarator(typeDecl, MkDeclaratorIdentifier(MkIdentifier("value")))));
1328                specifiers = MkList();
1329             }
1330
1331             d = MkDeclaratorFunction(d, params);
1332
1333             //if(imported)
1334             if(dllImport)
1335                specifiers->Insert(null, MkSpecifier(EXTERN));
1336             else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1337                specifiers->Insert(null, MkSpecifier(STATIC));
1338             if(simple)
1339                ListAdd(specifiers, MkSpecifier(VOID));
1340
1341             ListAdd(declarators, MkInitDeclarator(d, null));
1342
1343             decl = MkDeclaration(specifiers, declarators);
1344
1345             external = MkExternalDeclaration(decl);
1346             ast->Insert(curExternal.prev, external);
1347             external.symbol = symbol;
1348             symbol.externalGet = external;
1349
1350             ReplaceThisClassSpecifiers(specifiers, prop._class);
1351
1352             if(typeDecl)
1353                FreeDeclarator(typeDecl);
1354          }
1355          else
1356          {
1357             // Move declaration higher...
1358             ast->Move(symbol.externalGet, curExternal.prev);
1359          }
1360       }
1361
1362       // Set
1363       if(prop.Set)
1364       {
1365          if(!symbol.externalSet || symbol.externalSet.type == functionExternal)
1366          {
1367             Declaration decl;
1368             OldList * specifiers, * declarators;
1369             Declarator d;
1370             OldList * params;
1371             Specifier spec;
1372             External external;
1373             Declarator typeDecl;
1374
1375             declarators = MkList();
1376             params = MkList();
1377
1378             // TESTING COMMENTING THIS FIRST LINE OUT, what was the problem? Trying to add noHeadClass here ...
1379             if(!prop.conversion || prop._class.type == structClass)
1380             {
1381                ListAdd(params, MkTypeName(MkListOne(MkSpecifierName/*MkClassName*/(prop._class.fullName)),
1382                   MkDeclaratorIdentifier(MkIdentifier("this"))));
1383             }
1384
1385             specifiers = MkList();
1386
1387             {
1388                Context context = SetupTemplatesContext(prop._class);
1389                typeDecl = d = SpecDeclFromString(prop.dataTypeString, specifiers,
1390                   MkDeclaratorIdentifier(MkIdentifier("value")));
1391                FinishTemplatesContext(context);
1392             }
1393             ListAdd(params, MkTypeName(specifiers, d));
1394
1395             d = MkDeclaratorIdentifier(MkIdentifier(setName));
1396             //if(imported)
1397             if(dllImport)
1398                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1399             d = MkDeclaratorFunction(d, params);
1400
1401             // Make sure the simple _class's type is declared
1402             for(spec = specifiers->first; spec; spec = spec.next)
1403             {
1404                if(spec.type == nameSpecifier /*SpecifierClass*/)
1405                {
1406                   if((!typeDecl || typeDecl.type == identifierDeclarator))
1407                   {
1408                      Symbol classSym = spec.symbol; // FindClass(spec.name);
1409                      symbol._class = classSym.registered;
1410                      if(classSym.registered && classSym.registered.type == structClass)
1411                         DeclareStruct(spec.name, false);
1412                   }
1413                }
1414             }
1415
1416             ListAdd(declarators, MkInitDeclarator(d, null));
1417
1418             specifiers = MkList();
1419             //if(imported)
1420             if(dllImport)
1421                specifiers->Insert(null, MkSpecifier(EXTERN));
1422             else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1423                specifiers->Insert(null, MkSpecifier(STATIC));
1424
1425             // TESTING COMMENTING THIS FIRST LINE OUT, what was the problem? Trying to add noHeadClass here ...
1426             if(!prop.conversion || prop._class.type == structClass)
1427                ListAdd(specifiers, MkSpecifier(VOID));
1428             else
1429                ListAdd(specifiers, MkSpecifierName/*MkClassName*/(prop._class.fullName));
1430
1431             decl = MkDeclaration(specifiers, declarators);
1432
1433             external = MkExternalDeclaration(decl);
1434             ast->Insert(curExternal.prev, external);
1435             external.symbol = symbol;
1436             symbol.externalSet = external;
1437
1438             ReplaceThisClassSpecifiers(specifiers, prop._class);
1439          }
1440          else
1441          {
1442             // Move declaration higher...
1443             ast->Move(symbol.externalSet, curExternal.prev);
1444          }
1445       }
1446
1447       // Property (for Watchers)
1448       if(!symbol.externalPtr)
1449       {
1450          Declaration decl;
1451          External external;
1452          OldList * specifiers = MkList();
1453
1454          if(imported)
1455             specifiers->Insert(null, MkSpecifier(EXTERN));
1456          else
1457             specifiers->Insert(null, MkSpecifier(STATIC));
1458
1459          ListAdd(specifiers, MkSpecifierName("Property"));
1460
1461          {
1462             OldList * list = MkList();
1463             ListAdd(list, MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null),
1464                   MkDeclaratorIdentifier(MkIdentifier(propName))), null));
1465
1466             if(!imported)
1467             {
1468                strcpy(propName, "__ecerePropM_");
1469                FullClassNameCat(propName, prop._class.fullName, false);
1470                strcat(propName, "_");
1471                // strcat(propName, prop.name);
1472                FullClassNameCat(propName, prop.name, true);
1473
1474                MangleClassName(propName);
1475
1476                ListAdd(list, MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null),
1477                      MkDeclaratorIdentifier(MkIdentifier(propName))), null));
1478             }
1479             decl = MkDeclaration(specifiers, list);
1480          }
1481
1482          external = MkExternalDeclaration(decl);
1483          ast->Insert(curExternal.prev, external);
1484          external.symbol = symbol;
1485          symbol.externalPtr = external;
1486       }
1487       else
1488       {
1489          // Move declaration higher...
1490          ast->Move(symbol.externalPtr, curExternal.prev);
1491       }
1492
1493       symbol.id = curExternal.symbol.idCode;
1494    }
1495 }
1496
1497 // ***************** EXPRESSION PROCESSING ***************************
1498 public Type Dereference(Type source)
1499 {
1500    Type type = null;
1501    if(source)
1502    {
1503       if(source.kind == pointerType || source.kind == arrayType)
1504       {
1505          type = source.type;
1506          source.type.refCount++;
1507       }
1508       else if(source.kind == classType && !strcmp(source._class.string, "String"))
1509       {
1510          type = Type
1511          {
1512             kind = charType;
1513             refCount = 1;
1514          };
1515       }
1516       // Support dereferencing of no head classes for now...
1517       else if(source.kind == classType && source._class && source._class.registered && source._class.registered.type == noHeadClass)
1518       {
1519          type = source;
1520          source.refCount++;
1521       }
1522       else
1523          Compiler_Error($"cannot dereference type\n");
1524    }
1525    return type;
1526 }
1527
1528 static Type Reference(Type source)
1529 {
1530    Type type = null;
1531    if(source)
1532    {
1533       type = Type
1534       {
1535          kind = pointerType;
1536          type = source;
1537          refCount = 1;
1538       };
1539       source.refCount++;
1540    }
1541    return type;
1542 }
1543
1544 void ProcessMemberInitData(MemberInit member, Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
1545 {
1546    Identifier ident = member.identifiers ? member.identifiers->first : null;
1547    bool found = false;
1548    DataMember dataMember = null;
1549    Method method = null;
1550    bool freeType = false;
1551
1552    yylloc = member.loc;
1553
1554    if(!ident)
1555    {
1556       if(curMember)
1557       {
1558          eClass_FindNextMember(_class, curClass, curMember, subMemberStack, subMemberStackPos);
1559          if(*curMember)
1560          {
1561             found = true;
1562             dataMember = *curMember;
1563          }
1564       }
1565    }
1566    else
1567    {
1568       DataMember thisMember = (DataMember)eClass_FindProperty(_class, ident.string, privateModule);
1569       DataMember _subMemberStack[256];
1570       int _subMemberStackPos = 0;
1571
1572       // FILL MEMBER STACK
1573       if(!thisMember)
1574          thisMember = eClass_FindDataMember(_class, ident.string, privateModule, _subMemberStack, &_subMemberStackPos);
1575       if(thisMember)
1576       {
1577          dataMember = thisMember;
1578          if(curMember && thisMember.memberAccess == publicAccess)
1579          {
1580             *curMember = thisMember;
1581             *curClass = thisMember._class;
1582             memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
1583             *subMemberStackPos = _subMemberStackPos;
1584          }
1585          found = true;
1586       }
1587       else
1588       {
1589          // Setting a method
1590          method = eClass_FindMethod(_class, ident.string, privateModule);
1591          if(method && method.type == virtualMethod)
1592             found = true;
1593          else
1594             method = null;
1595       }
1596    }
1597
1598    if(found)
1599    {
1600       Type type = null;
1601       if(dataMember)
1602       {
1603          if(!dataMember.dataType && dataMember.dataTypeString)
1604          {
1605             //Context context = SetupTemplatesContext(dataMember._class);
1606             Context context = SetupTemplatesContext(_class);
1607             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
1608             FinishTemplatesContext(context);
1609          }
1610          type = dataMember.dataType;
1611       }
1612       else if(method)
1613       {
1614          // This is for destination type...
1615          if(!method.dataType)
1616             ProcessMethodType(method);
1617          //DeclareMethod(method);
1618          // method.dataType = ((Symbol)method.symbol)->type;
1619          type = method.dataType;
1620       }
1621
1622       if(ident && ident.next)
1623       {
1624          for(ident = ident.next; ident && type; ident = ident.next)
1625          {
1626             if(type.kind == classType)
1627             {
1628                dataMember = (DataMember)eClass_FindProperty(type._class.registered, ident.string, privateModule);
1629                if(!dataMember)
1630                   dataMember = eClass_FindDataMember(type._class.registered, ident.string, privateModule, null, null);
1631                if(dataMember)
1632                   type = dataMember.dataType;
1633             }
1634             else if(type.kind == structType || type.kind == unionType)
1635             {
1636                Type memberType;
1637                for(memberType = type.members.first; memberType; memberType = memberType.next)
1638                {
1639                   if(!strcmp(memberType.name, ident.string))
1640                   {
1641                      type = memberType;
1642                      break;
1643                   }
1644                }
1645             }
1646          }
1647       }
1648
1649       // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
1650       if(type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type && _class.templateArgs /* TODO: Watch out for these _class.templateClass*/)
1651       {
1652          int id = 0;
1653          ClassTemplateParameter curParam = null;
1654          Class sClass;
1655          for(sClass = _class; sClass; sClass = sClass.base)
1656          {
1657             id = 0;
1658             if(sClass.templateClass) sClass = sClass.templateClass;
1659             for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
1660             {
1661                if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
1662                {
1663                   for(sClass = sClass.base; sClass; sClass = sClass.base)
1664                   {
1665                      if(sClass.templateClass) sClass = sClass.templateClass;
1666                      id += sClass.templateParams.count;
1667                   }
1668                   break;
1669                }
1670                id++;
1671             }
1672             if(curParam) break;
1673          }
1674
1675          if(curParam)
1676          {
1677             ClassTemplateArgument arg = _class.templateArgs[id];
1678             if(arg.dataTypeString)
1679             {
1680                // FreeType(type);
1681                type = ProcessTypeString(arg.dataTypeString, false);
1682                freeType = true;
1683                if(type && _class.templateClass)
1684                   type.passAsTemplate = true;
1685                if(type)
1686                {
1687                   // type.refCount++;
1688                   /*if(!exp.destType)
1689                   {
1690                      exp.destType = ProcessTypeString(arg.dataTypeString, false);
1691                      exp.destType.refCount++;
1692                   }*/
1693                }
1694             }
1695          }
1696       }
1697       if(type && type.kind == classType && type._class && type._class.registered && strchr(type._class.registered.fullName, '<'))
1698       {
1699          Class expClass = type._class.registered;
1700          Class cClass = null;
1701          int c;
1702          int paramCount = 0;
1703          int lastParam = -1;
1704
1705          char templateString[1024];
1706          ClassTemplateParameter param;
1707          sprintf(templateString, "%s<", expClass.templateClass.fullName);
1708          for(cClass = expClass; cClass; cClass = cClass.base)
1709          {
1710             int p = 0;
1711             if(cClass.templateClass) cClass = cClass.templateClass;
1712             for(param = cClass.templateParams.first; param; param = param.next)
1713             {
1714                int id = p;
1715                Class sClass;
1716                ClassTemplateArgument arg;
1717                for(sClass = cClass.base; sClass; sClass = sClass.base)
1718                {
1719                   if(sClass.templateClass) sClass = sClass.templateClass;
1720                   id += sClass.templateParams.count;
1721                }
1722                arg = expClass.templateArgs[id];
1723
1724                for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
1725                {
1726                   ClassTemplateParameter cParam;
1727                   //int p = numParams - sClass.templateParams.count;
1728                   int p = 0;
1729                   Class nextClass;
1730                   if(sClass.templateClass) sClass = sClass.templateClass;
1731
1732                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
1733                   {
1734                      if(nextClass.templateClass) nextClass = nextClass.templateClass;
1735                      p += nextClass.templateParams.count;
1736                   }
1737
1738                   for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
1739                   {
1740                      if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
1741                      {
1742                         if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1743                         {
1744                            arg.dataTypeString = _class.templateArgs[p].dataTypeString;
1745                            arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
1746                            break;
1747                         }
1748                      }
1749                   }
1750                }
1751
1752                {
1753                   char argument[256];
1754                   argument[0] = '\0';
1755                   /*if(arg.name)
1756                   {
1757                      strcat(argument, arg.name.string);
1758                      strcat(argument, " = ");
1759                   }*/
1760                   switch(param.type)
1761                   {
1762                      case expression:
1763                      {
1764                         // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
1765                         char expString[1024];
1766                         OldList * specs = MkList();
1767                         Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
1768                         Expression exp;
1769                         char * string = PrintHexUInt64(arg.expression.ui64);
1770                         exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
1771                         delete string;
1772
1773                         ProcessExpressionType(exp);
1774                         ComputeExpression(exp);
1775                         expString[0] = '\0';
1776                         PrintExpression(exp, expString);
1777                         strcat(argument, expString);
1778                         //delete exp;
1779                         FreeExpression(exp);
1780                         break;
1781                      }
1782                      case identifier:
1783                      {
1784                         strcat(argument, arg.member.name);
1785                         break;
1786                      }
1787                      case TemplateParameterType::type:
1788                      {
1789                         if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1790                            strcat(argument, arg.dataTypeString);
1791                         break;
1792                      }
1793                   }
1794                   if(argument[0])
1795                   {
1796                      if(paramCount) strcat(templateString, ", ");
1797                      if(lastParam != p - 1)
1798                      {
1799                         strcat(templateString, param.name);
1800                         strcat(templateString, " = ");
1801                      }
1802                      strcat(templateString, argument);
1803                      paramCount++;
1804                      lastParam = p;
1805                   }
1806                   p++;
1807                }
1808             }
1809          }
1810          {
1811             int len = strlen(templateString);
1812             if(templateString[len-1] == '<')
1813                len--;
1814             else
1815             {
1816                if(templateString[len-1] == '>')
1817                   templateString[len++] = ' ';
1818                templateString[len++] = '>';
1819             }
1820             templateString[len++] = '\0';
1821          }
1822          {
1823             Context context = SetupTemplatesContext(_class);
1824             if(freeType) FreeType(type);
1825             type = ProcessTypeString(templateString, false);
1826             freeType = true;
1827             FinishTemplatesContext(context);
1828          }
1829       }
1830
1831       if(method && member.initializer && member.initializer.type == expInitializer && member.initializer.exp)
1832       {
1833          ProcessExpressionType(member.initializer.exp);
1834          if(!member.initializer.exp.expType)
1835          {
1836             if(inCompiler)
1837             {
1838                char expString[10240];
1839                expString[0] = '\0';
1840                PrintExpression(member.initializer.exp, expString);
1841                ChangeCh(expString, '\n', ' ');
1842                Compiler_Error($"unresolved symbol used as an instance method %s\n", expString);
1843             }
1844          }
1845          //else if(!MatchTypes(member.exp.expType, type, null, _class, null, true, true, false, false))
1846          else if(!MatchTypes(member.initializer.exp.expType, type, null, null, _class, true, true, false, false))
1847          {
1848             Compiler_Error($"incompatible instance method %s\n", ident.string);
1849          }
1850       }
1851       else if(member.initializer)
1852       {
1853          /*
1854          FreeType(member.exp.destType);
1855          member.exp.destType = type;
1856          if(member.exp.destType)
1857             member.exp.destType.refCount++;
1858          ProcessExpressionType(member.exp);
1859          */
1860
1861          ProcessInitializer(member.initializer, type);
1862       }
1863       if(freeType) FreeType(type);
1864    }
1865    else
1866    {
1867       if(_class && _class.type == unitClass)
1868       {
1869          if(member.initializer)
1870          {
1871             /*
1872             FreeType(member.exp.destType);
1873             member.exp.destType = MkClassType(_class.fullName);
1874             ProcessExpressionType(member.initializer, type);
1875             */
1876             Type type = MkClassType(_class.fullName);
1877             ProcessInitializer(member.initializer, type);
1878             FreeType(type);
1879          }
1880       }
1881       else
1882       {
1883          if(member.initializer)
1884          {
1885             //ProcessExpressionType(member.exp);
1886             ProcessInitializer(member.initializer, null);
1887          }
1888          if(ident)
1889          {
1890             if(method)
1891             {
1892                Compiler_Error($"couldn't find virtual method %s in class %s\n", ident.string, _class.fullName);
1893             }
1894             else if(_class)
1895             {
1896                Compiler_Error($"couldn't find member %s in class %s\n", ident.string, _class.fullName);
1897                if(inCompiler)
1898                   eClass_AddDataMember(_class, ident.string, "int", 0, 0, publicAccess);
1899             }
1900          }
1901          else if(_class)
1902             Compiler_Error($"too many initializers for instantiation of class %s\n", _class.fullName);
1903       }
1904    }
1905 }
1906
1907 void ProcessInstantiationType(Instantiation inst)
1908 {
1909    yylloc = inst.loc;
1910    if(inst._class)
1911    {
1912       MembersInit members;
1913       Symbol classSym; // = inst._class.symbol; // FindClass(inst._class.name);
1914       Class _class;
1915
1916       /*if(!inst._class.symbol)
1917          inst._class.symbol = FindClass(inst._class.name);*/
1918       classSym = inst._class.symbol;
1919       _class = classSym ? classSym.registered : null;
1920
1921       // DANGER: Patch for mutex not declaring its struct when not needed
1922       if(!_class || _class.type != noHeadClass)
1923          DeclareStruct(inst._class.name, false); //_class && _class.type == noHeadClass);
1924
1925       afterExternal = afterExternal ? afterExternal : curExternal;
1926
1927       if(inst.exp)
1928          ProcessExpressionType(inst.exp);
1929
1930       inst.isConstant = true;
1931       if(inst.members)
1932       {
1933          DataMember curMember = null;
1934          Class curClass = null;
1935          DataMember subMemberStack[256];
1936          int subMemberStackPos = 0;
1937
1938          for(members = inst.members->first; members; members = members.next)
1939          {
1940             switch(members.type)
1941             {
1942                case methodMembersInit:
1943                {
1944                   char name[1024];
1945                   static uint instMethodID = 0;
1946                   External external = curExternal;
1947                   Context context = curContext;
1948                   Declarator declarator = members.function.declarator;
1949                   Identifier nameID = GetDeclId(declarator);
1950                   char * unmangled = nameID ? nameID.string : null;
1951                   Expression exp;
1952                   External createdExternal = null;
1953
1954                   if(inCompiler)
1955                   {
1956                      char number[16];
1957                      //members.function.dontMangle = true;
1958                      strcpy(name, "__ecereInstMeth_");
1959                      FullClassNameCat(name, _class ? _class.fullName : "_UNKNOWNCLASS", false);
1960                      strcat(name, "_");
1961                      strcat(name, nameID.string);
1962                      strcat(name, "_");
1963                      sprintf(number, "_%08d", instMethodID++);
1964                      strcat(name, number);
1965                      nameID.string = CopyString(name);
1966                   }
1967
1968                   // Do modifications here...
1969                   if(declarator)
1970                   {
1971                      Symbol symbol = declarator.symbol;
1972                      Method method = eClass_FindMethod(_class, unmangled, privateModule);
1973
1974                      if(method && method.type == virtualMethod)
1975                      {
1976                         symbol.method = method;
1977                         ProcessMethodType(method);
1978
1979                         if(!symbol.type.thisClass)
1980                         {
1981                            if(method.dataType.thisClass && currentClass &&
1982                               eClass_IsDerived(currentClass, method.dataType.thisClass.registered))
1983                            {
1984                               if(!currentClass.symbol)
1985                                  currentClass.symbol = FindClass(currentClass.fullName);
1986                               symbol.type.thisClass = currentClass.symbol;
1987                            }
1988                            else
1989                            {
1990                               if(!_class.symbol)
1991                                  _class.symbol = FindClass(_class.fullName);
1992                               symbol.type.thisClass = _class.symbol;
1993                            }
1994                         }
1995                         // TESTING THIS HERE:
1996                         DeclareType(symbol.type, true, true);
1997
1998                      }
1999                      else if(classSym)
2000                      {
2001                         Compiler_Error($"couldn't find virtual method %s in class %s\n",
2002                            unmangled, classSym.string);
2003                      }
2004                   }
2005
2006                   //declarator.symbol.id = declarator.symbol.idCode = curExternal.symbol.idCode;
2007                   createdExternal = ProcessClassFunction(classSym ? classSym.registered : null, members.function, ast, afterExternal, true);
2008
2009                   if(nameID)
2010                   {
2011                      FreeSpecifier(nameID._class);
2012                      nameID._class = null;
2013                   }
2014
2015                   if(inCompiler)
2016                   {
2017
2018                      Type type = declarator.symbol.type;
2019                      External oldExternal = curExternal;
2020
2021                      // *** Commented this out... Any negative impact? Yes: makes double prototypes declarations... Why was it commented out?
2022                      // *** It was commented out for problems such as
2023                      /*
2024                            class VirtualDesktop : Window
2025                            {
2026                               clientSize = Size { };
2027                               Timer timer
2028                               {
2029                                  bool DelayExpired()
2030                                  {
2031                                     clientSize.w;
2032                                     return true;
2033                                  }
2034                               };
2035                            }
2036                      */
2037                      // Commented Out: Good for bet.ec in Poker (Otherwise: obj\bet.c:187: error: `currentBet' undeclared (first use in this function))
2038
2039                      declarator.symbol.id = declarator.symbol.idCode = curExternal.symbol.idCode;
2040
2041                      /*
2042                      if(strcmp(declarator.symbol.string, name))
2043                      {
2044                         printf("TOCHECK: Look out for this\n");
2045                         delete declarator.symbol.string;
2046                         declarator.symbol.string = CopyString(name);
2047                      }
2048
2049                      if(!declarator.symbol.parent && globalContext.symbols.root != (BTNode)declarator.symbol)
2050                      {
2051                         printf("TOCHECK: Will this ever be in a list? Yes.\n");
2052                         excludedSymbols->Remove(declarator.symbol);
2053                         globalContext.symbols.Add((BTNode)declarator.symbol);
2054                         if(strstr(declarator.symbol.string), "::")
2055                            globalContext.hasNameSpace = true;
2056
2057                      }
2058                      */
2059
2060                      //curExternal = curExternal.prev;
2061                      //afterExternal = afterExternal->next;
2062
2063                      //ProcessFunction(afterExternal->function);
2064
2065                      //curExternal = afterExternal;
2066                      {
2067                         External externalDecl;
2068                         externalDecl = MkExternalDeclaration(null);
2069                         ast->Insert(oldExternal.prev, externalDecl);
2070
2071                         // Which function does this process?
2072                         if(createdExternal.function)
2073                         {
2074                            ProcessFunction(createdExternal.function);
2075
2076                            //curExternal = oldExternal;
2077
2078                            {
2079                               //Declaration decl = MkDeclaration(members.function.specifiers, MkListOne(MkInitDeclarator(CopyDeclarator(declarator), null)));
2080
2081                               Declaration decl = MkDeclaration(CopyList(createdExternal.function.specifiers, CopySpecifier),
2082                                  MkListOne(MkInitDeclarator(CopyDeclarator(declarator), null)));
2083
2084                               //externalDecl = MkExternalDeclaration(decl);
2085
2086                               //***** ast->Insert(external.prev, externalDecl);
2087                               //ast->Insert(curExternal.prev, externalDecl);
2088                               externalDecl.declaration = decl;
2089                               if(decl.symbol && !decl.symbol.pointerExternal)
2090                                  decl.symbol.pointerExternal = externalDecl;
2091
2092                               // Trying this out...
2093                               declarator.symbol.pointerExternal = externalDecl;
2094                            }
2095                         }
2096                      }
2097                   }
2098                   else if(declarator)
2099                   {
2100                      curExternal = declarator.symbol.pointerExternal;
2101                      ProcessFunction((FunctionDefinition)members.function);
2102                   }
2103                   curExternal = external;
2104                   curContext = context;
2105
2106                   if(inCompiler)
2107                   {
2108                      FreeClassFunction(members.function);
2109
2110                      // In this pass, turn this into a MemberInitData
2111                      exp = QMkExpId(name);
2112                      members.type = dataMembersInit;
2113                      members.dataMembers = MkListOne(MkMemberInit(MkListOne(MkIdentifier(unmangled)), MkInitializerAssignment(exp)));
2114
2115                      delete unmangled;
2116                   }
2117                   break;
2118                }
2119                case dataMembersInit:
2120                {
2121                   if(members.dataMembers && classSym)
2122                   {
2123                      MemberInit member;
2124                      Location oldyyloc = yylloc;
2125                      for(member = members.dataMembers->first; member; member = member.next)
2126                      {
2127                         ProcessMemberInitData(member, classSym.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
2128                         if(member.initializer && !member.initializer.isConstant)
2129                            inst.isConstant = false;
2130                      }
2131                      yylloc = oldyyloc;
2132                   }
2133                   break;
2134                }
2135             }
2136          }
2137       }
2138    }
2139 }
2140
2141 static void DeclareType(Type type, bool declarePointers, bool declareParams)
2142 {
2143    // OPTIMIZATIONS: TESTING THIS...
2144    if(inCompiler)
2145    {
2146       if(type.kind == functionType)
2147       {
2148          Type param;
2149          if(declareParams)
2150          {
2151             for(param = type.params.first; param; param = param.next)
2152                DeclareType(param, declarePointers, true);
2153          }
2154          DeclareType(type.returnType, declarePointers, true);
2155       }
2156       else if(type.kind == pointerType && declarePointers)
2157          DeclareType(type.type, declarePointers, false);
2158       else if(type.kind == classType)
2159       {
2160          if(type._class.registered && (type._class.registered.type == structClass || type._class.registered.type == noHeadClass) && !type._class.declaring)
2161             DeclareStruct(type._class.registered.fullName, type._class.registered.type == noHeadClass);
2162       }
2163       else if(type.kind == structType || type.kind == unionType)
2164       {
2165          Type member;
2166          for(member = type.members.first; member; member = member.next)
2167             DeclareType(member, false, false);
2168       }
2169       else if(type.kind == arrayType)
2170          DeclareType(type.arrayType, declarePointers, false);
2171    }
2172 }
2173
2174 ClassTemplateArgument * FindTemplateArg(Class _class, TemplateParameter param)
2175 {
2176    ClassTemplateArgument * arg = null;
2177    int id = 0;
2178    ClassTemplateParameter curParam = null;
2179    Class sClass;
2180    for(sClass = _class; sClass; sClass = sClass.base)
2181    {
2182       id = 0;
2183       if(sClass.templateClass) sClass = sClass.templateClass;
2184       for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
2185       {
2186          if(curParam.type == TemplateParameterType::type && !strcmp(param.identifier.string, curParam.name))
2187          {
2188             for(sClass = sClass.base; sClass; sClass = sClass.base)
2189             {
2190                if(sClass.templateClass) sClass = sClass.templateClass;
2191                id += sClass.templateParams.count;
2192             }
2193             break;
2194          }
2195          id++;
2196       }
2197       if(curParam) break;
2198    }
2199    if(curParam)
2200    {
2201       arg = &_class.templateArgs[id];
2202       if(arg && param.type == type)
2203          arg->dataTypeClass = eSystem_FindClass(_class.module, arg->dataTypeString);
2204    }
2205    return arg;
2206 }
2207
2208 public Context SetupTemplatesContext(Class _class)
2209 {
2210    Context context = PushContext();
2211    context.templateTypesOnly = true;
2212    if(_class.symbol && ((Symbol)_class.symbol).templateParams)
2213    {
2214       TemplateParameter param = ((Symbol)_class.symbol).templateParams->first;
2215       for(; param; param = param.next)
2216       {
2217          if(param.type == type && param.identifier)
2218          {
2219             TemplatedType type { key = (uintptr)param.identifier.string, param = param };
2220             curContext.templateTypes.Add((BTNode)type);
2221          }
2222       }
2223    }
2224    else if(_class)
2225    {
2226       Class sClass;
2227       for(sClass = _class; sClass; sClass = sClass.base)
2228       {
2229          ClassTemplateParameter p;
2230          for(p = sClass.templateParams.first; p; p = p.next)
2231          {
2232             //OldList * specs = MkList();
2233             //Declarator decl = null;
2234             //decl = SpecDeclFromString(p.dataTypeString, specs, null);
2235             if(p.type == type)
2236             {
2237                TemplateParameter param = p.param;
2238                TemplatedType type;
2239                if(!param)
2240                {
2241                   // ADD DATA TYPE HERE...
2242                   p.param = param = TemplateParameter
2243                   {
2244                      identifier = MkIdentifier(p.name), type = p.type,
2245                      dataTypeString = p.dataTypeString /*, dataType = { specs, decl }*/
2246                   };
2247                }
2248                type = TemplatedType { key = (uintptr)p.name, param = param };
2249                curContext.templateTypes.Add((BTNode)type);
2250             }
2251          }
2252       }
2253    }
2254    return context;
2255 }
2256
2257 public void FinishTemplatesContext(Context context)
2258 {
2259    PopContext(context);
2260    FreeContext(context);
2261    delete context;
2262 }
2263
2264 public void ProcessMethodType(Method method)
2265 {
2266    if(!method.dataType)
2267    {
2268       Context context = SetupTemplatesContext(method._class);
2269
2270       method.dataType = ProcessTypeString(method.dataTypeString, false);
2271
2272       FinishTemplatesContext(context);
2273
2274       if(method.type != virtualMethod && method.dataType)
2275       {
2276          if(!method.dataType.thisClass && !method.dataType.staticMethod)
2277          {
2278             if(!method._class.symbol)
2279                method._class.symbol = FindClass(method._class.fullName);
2280             method.dataType.thisClass = method._class.symbol;
2281          }
2282       }
2283
2284       // Why was this commented out? Working fine without now...
2285
2286       /*
2287       if(method.dataType.kind == functionType && !method.dataType.staticMethod && !method.dataType.thisClass)
2288          method.dataType.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2289          */
2290    }
2291
2292    /*
2293    if(type)
2294    {
2295       char * par = strstr(type, "(");
2296       char * classOp = null;
2297       int classOpLen = 0;
2298       if(par)
2299       {
2300          int c;
2301          for(c = par-type-1; c >= 0; c++)
2302          {
2303             if(type[c] == ':' && type[c+1] == ':')
2304             {
2305                classOp = type + c - 1;
2306                for(c = c-1; c >=0 && !isspace(type[c]); c--)
2307                {
2308                   classOp--;
2309                   classOpLen++;
2310                }
2311                break;
2312             }
2313             else if(!isspace(type[c]))
2314                break;
2315          }
2316       }
2317       if(classOp)
2318       {
2319          char temp[1024];
2320          int typeLen = strlen(type);
2321          memcpy(temp, classOp, classOpLen);
2322          temp[classOpLen] = '\0';
2323          if(temp[0])
2324             _class = eSystem_FindClass(module, temp);
2325          else
2326             _class = null;
2327          method.dataTypeString = new char[typeLen - classOpLen + 1];
2328          memcpy(method.dataTypeString, type, classOp - type);
2329          memcpy(method.dataTypeString + (classOp - type), classOp + classOpLen, typeLen - (classOp - type + classOpLen));
2330       }
2331       else
2332          method.dataTypeString = type;
2333    }
2334    */
2335 }
2336
2337
2338 public void ProcessPropertyType(Property prop)
2339 {
2340    if(!prop.dataType)
2341    {
2342       Context context = SetupTemplatesContext(prop._class);
2343       prop.dataType = ProcessTypeString(prop.dataTypeString, false);
2344       FinishTemplatesContext(context);
2345    }
2346 }
2347
2348 public void DeclareMethod(Method method, char * name)
2349 {
2350    Symbol symbol = method.symbol;
2351    if(!symbol || (!symbol.pointerExternal && method.type == virtualMethod) || symbol.id > (curExternal ? curExternal.symbol.idCode : -1))
2352    {
2353       bool imported = false;
2354       bool dllImport = false;
2355
2356       if(!method.dataType)
2357          method.dataType = ProcessTypeString(method.dataTypeString, false);
2358
2359       if(!symbol || symbol._import || method.type == virtualMethod)
2360       {
2361          if(!symbol || method.type == virtualMethod)
2362          {
2363             Symbol classSym;
2364             if(!method._class.symbol)
2365                method._class.symbol = FindClass(method._class.fullName);
2366             classSym = method._class.symbol;
2367             if(!classSym._import)
2368             {
2369                ModuleImport module;
2370
2371                if(method._class.module && method._class.module.name)
2372                   module = FindModule(method._class.module);
2373                else
2374                   module = mainModule;
2375                classSym._import = ClassImport
2376                {
2377                   name = CopyString(method._class.fullName);
2378                   isRemote = method._class.isRemote;
2379                };
2380                module.classes.Add(classSym._import);
2381             }
2382             if(!symbol)
2383             {
2384                symbol = method.symbol = Symbol { };
2385             }
2386             if(!symbol._import)
2387             {
2388                symbol._import = (ClassImport)MethodImport
2389                {
2390                   name = CopyString(method.name);
2391                   isVirtual = method.type == virtualMethod;
2392                };
2393                classSym._import.methods.Add(symbol._import);
2394             }
2395             if(!symbol)
2396             {
2397                // Set the symbol type
2398                /*
2399                if(!type.thisClass)
2400                {
2401                   type.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2402                }
2403                else if(type.thisClass == (void *)-1)
2404                {
2405                   type.thisClass = null;
2406                }
2407                */
2408                // symbol.type = ProcessTypeString(method.dataTypeString, false);
2409                symbol.type = method.dataType;
2410                if(symbol.type) symbol.type.refCount++;
2411             }
2412             /*
2413             if(!method.thisClass || strcmp(method.thisClass, "void"))
2414                symbol.type.params.Insert(null,
2415                   MkClassType(method.thisClass ? method.thisClass : method._class.fullName));
2416             */
2417          }
2418          if(!method.dataType.dllExport)
2419          {
2420             imported = true;
2421             if(method._class.module != privateModule && method._class.module.importType != staticImport)
2422                dllImport = true;
2423          }
2424       }
2425
2426       /* MOVING THIS UP
2427       if(!method.dataType)
2428          method.dataType = ((Symbol)method.symbol).type;
2429          //ProcessMethodType(method);
2430       */
2431
2432       if(method.type != virtualMethod && method.dataType)
2433          DeclareType(method.dataType, true, true);
2434
2435       if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2436       {
2437          // We need a declaration here :)
2438          Declaration decl;
2439          OldList * specifiers, * declarators;
2440          Declarator d;
2441          Declarator funcDecl;
2442          External external;
2443
2444          specifiers = MkList();
2445          declarators = MkList();
2446
2447          //if(imported)
2448          if(dllImport)
2449             ListAdd(specifiers, MkSpecifier(EXTERN));
2450          else if(method._class.symbol && ((Symbol)method._class.symbol).isStatic)
2451             ListAdd(specifiers, MkSpecifier(STATIC));
2452
2453          if(method.type == virtualMethod)
2454          {
2455             ListAdd(specifiers, MkSpecifier(INT));
2456             d = MkDeclaratorIdentifier(MkIdentifier(name));
2457          }
2458          else
2459          {
2460             d = MkDeclaratorIdentifier(MkIdentifier(name));
2461             //if(imported)
2462             if(dllImport)
2463                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2464             {
2465                Context context = SetupTemplatesContext(method._class);
2466                d = SpecDeclFromString(method.dataTypeString, specifiers, d);
2467                FinishTemplatesContext(context);
2468             }
2469             funcDecl = GetFuncDecl(d);
2470
2471             if(dllImport)
2472             {
2473                Specifier spec, next;
2474                for(spec = specifiers->first; spec; spec = next)
2475                {
2476                   next = spec.next;
2477                   if(spec.type == extendedSpecifier)
2478                   {
2479                      specifiers->Remove(spec);
2480                      FreeSpecifier(spec);
2481                   }
2482                }
2483             }
2484
2485             // Add this parameter if not a static method
2486             if(method.dataType && !method.dataType.staticMethod)
2487             {
2488                if(funcDecl && funcDecl.function.parameters && funcDecl.function.parameters->count)
2489                {
2490                   Class _class = method.dataType.thisClass ? method.dataType.thisClass.registered : method._class;
2491                   TypeName thisParam = MkTypeName(MkListOne(
2492                      MkSpecifierName/*MkClassName*/(method.dataType.thisClass ? method.dataType.thisClass.string : method._class.fullName)),
2493                      (_class && _class.type == systemClass) ? MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("this"))) : MkDeclaratorIdentifier(MkIdentifier("this")));
2494                   TypeName firstParam = ((TypeName)funcDecl.function.parameters->first);
2495                   Specifier firstSpec = firstParam.qualifiers ? firstParam.qualifiers->first : null;
2496
2497                   if(firstSpec && firstSpec.type == baseSpecifier && firstSpec.specifier == VOID && !firstParam.declarator)
2498                   {
2499                      TypeName param = funcDecl.function.parameters->first;
2500                      funcDecl.function.parameters->Remove(param);
2501                      FreeTypeName(param);
2502                   }
2503
2504                   if(!funcDecl.function.parameters)
2505                      funcDecl.function.parameters = MkList();
2506                   funcDecl.function.parameters->Insert(null, thisParam);
2507                }
2508             }
2509             // Make sure we don't have empty parameter declarations for static methods...
2510             /*
2511             else if(!funcDecl.function.parameters)
2512             {
2513                funcDecl.function.parameters = MkList();
2514                funcDecl.function.parameters->Insert(null,
2515                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2516             }*/
2517          }
2518          // TESTING THIS:
2519          ProcessDeclarator(d);
2520
2521          ListAdd(declarators, MkInitDeclarator(d, null));
2522
2523          decl = MkDeclaration(specifiers, declarators);
2524
2525          ReplaceThisClassSpecifiers(specifiers, method._class);
2526
2527          // Keep a different symbol for the function definition than the declaration...
2528          if(symbol.pointerExternal)
2529          {
2530             Symbol functionSymbol { };
2531
2532             // Copy symbol
2533             {
2534                *functionSymbol = *symbol;
2535                functionSymbol.string = CopyString(symbol.string);
2536                if(functionSymbol.type)
2537                   functionSymbol.type.refCount++;
2538             }
2539
2540             excludedSymbols->Add(functionSymbol);
2541             symbol.pointerExternal.symbol = functionSymbol;
2542          }
2543          external = MkExternalDeclaration(decl);
2544          if(curExternal)
2545             ast->Insert(curExternal ? curExternal.prev : null, external);
2546          external.symbol = symbol;
2547          symbol.pointerExternal = external;
2548       }
2549       else if(ast)
2550       {
2551          // Move declaration higher...
2552          ast->Move(symbol.pointerExternal, curExternal.prev);
2553       }
2554
2555       symbol.id = curExternal ? curExternal.symbol.idCode : MAXINT;
2556    }
2557 }
2558
2559 char * ReplaceThisClass(Class _class)
2560 {
2561    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2562    {
2563       bool first = true;
2564       int p = 0;
2565       ClassTemplateParameter param;
2566       int lastParam = -1;
2567
2568       char className[1024];
2569       strcpy(className, _class.fullName);
2570       for(param = _class.templateParams.first; param; param = param.next)
2571       {
2572          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2573          {
2574             if(first) strcat(className, "<");
2575             if(!first) strcat(className, ", ");
2576             if(lastParam + 1 != p)
2577             {
2578                strcat(className, param.name);
2579                strcat(className, " = ");
2580             }
2581             strcat(className, param.name);
2582             first = false;
2583             lastParam = p;
2584          }
2585          p++;
2586       }
2587       if(!first)
2588       {
2589          int len = strlen(className);
2590          if(className[len-1] == '>') className[len++] = ' ';
2591          className[len++] = '>';
2592          className[len++] = '\0';
2593       }
2594       return CopyString(className);
2595    }
2596    else
2597       return CopyString(_class.fullName);
2598 }
2599
2600 Type ReplaceThisClassType(Class _class)
2601 {
2602    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2603    {
2604       bool first = true;
2605       int p = 0;
2606       ClassTemplateParameter param;
2607       int lastParam = -1;
2608       char className[1024];
2609       strcpy(className, _class.fullName);
2610
2611       for(param = _class.templateParams.first; param; param = param.next)
2612       {
2613          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2614          {
2615             if(first) strcat(className, "<");
2616             if(!first) strcat(className, ", ");
2617             if(lastParam + 1 != p)
2618             {
2619                strcat(className, param.name);
2620                strcat(className, " = ");
2621             }
2622             strcat(className, param.name);
2623             first = false;
2624             lastParam = p;
2625          }
2626          p++;
2627       }
2628       if(!first)
2629       {
2630          int len = strlen(className);
2631          if(className[len-1] == '>') className[len++] = ' ';
2632          className[len++] = '>';
2633          className[len++] = '\0';
2634       }
2635       return MkClassType(className);
2636       //return ProcessTypeString(className, false);
2637    }
2638    else
2639    {
2640       return MkClassType(_class.fullName);
2641       //return ProcessTypeString(_class.fullName, false);
2642    }
2643 }
2644
2645 void ReplaceThisClassSpecifiers(OldList specs, Class _class)
2646 {
2647    if(specs != null && _class)
2648    {
2649       Specifier spec;
2650       for(spec = specs.first; spec; spec = spec.next)
2651       {
2652          if(spec.type == baseSpecifier && spec.specifier == THISCLASS)
2653          {
2654             spec.type = nameSpecifier;
2655             spec.name = ReplaceThisClass(_class);
2656             spec.symbol = FindClass(spec.name); //_class.symbol;
2657          }
2658       }
2659    }
2660 }
2661
2662 // Returns imported or not
2663 bool DeclareFunction(GlobalFunction function, char * name)
2664 {
2665    Symbol symbol = function.symbol;
2666    if(curExternal && (!symbol || symbol.id > curExternal.symbol.idCode))
2667    {
2668       bool imported = false;
2669       bool dllImport = false;
2670
2671       if(!function.dataType)
2672       {
2673          function.dataType = ProcessTypeString(function.dataTypeString, false);
2674          if(!function.dataType.thisClass)
2675             function.dataType.staticMethod = true;
2676       }
2677
2678       if(inCompiler)
2679       {
2680          if(!symbol)
2681          {
2682             ModuleImport module = FindModule(function.module);
2683             // WARNING: This is not added anywhere...
2684             symbol = function.symbol = Symbol {  };
2685
2686             if(module.name)
2687             {
2688                if(!function.dataType.dllExport)
2689                {
2690                   symbol._import = (ClassImport)FunctionImport { name = CopyString(function.name) };
2691                   module.functions.Add(symbol._import);
2692                }
2693             }
2694             // Set the symbol type
2695             {
2696                symbol.type = ProcessTypeString(function.dataTypeString, false);
2697                if(!symbol.type.thisClass)
2698                   symbol.type.staticMethod = true;
2699             }
2700          }
2701          imported = symbol._import ? true : false;
2702          if(imported && function.module != privateModule && function.module.importType != staticImport)
2703             dllImport = true;
2704       }
2705
2706       DeclareType(function.dataType, true, true);
2707
2708       if(inCompiler)
2709       {
2710          if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2711          {
2712             // We need a declaration here :)
2713             Declaration decl;
2714             OldList * specifiers, * declarators;
2715             Declarator d;
2716             Declarator funcDecl;
2717             External external;
2718
2719             specifiers = MkList();
2720             declarators = MkList();
2721
2722             //if(imported)
2723                ListAdd(specifiers, MkSpecifier(EXTERN));
2724             /*
2725             else
2726                ListAdd(specifiers, MkSpecifier(STATIC));
2727             */
2728
2729             d = MkDeclaratorIdentifier(MkIdentifier(imported ? name : function.name));
2730             //if(imported)
2731             if(dllImport)
2732                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2733
2734             d = SpecDeclFromString(function.dataTypeString, specifiers, d);
2735             // TAKE OUT THE DLL EXPORT IF STATICALLY IMPORTED:
2736             if(function.module.importType == staticImport)
2737             {
2738                Specifier spec;
2739                for(spec = specifiers->first; spec; spec = spec.next)
2740                   if(spec.type == extendedSpecifier && spec.extDecl && spec.extDecl.type == extDeclString && !strcmp(spec.extDecl.s, "dllexport"))
2741                   {
2742                      specifiers->Remove(spec);
2743                      FreeSpecifier(spec);
2744                      break;
2745                   }
2746             }
2747
2748             funcDecl = GetFuncDecl(d);
2749
2750             // Make sure we don't have empty parameter declarations for static methods...
2751             if(funcDecl && !funcDecl.function.parameters)
2752             {
2753                funcDecl.function.parameters = MkList();
2754                funcDecl.function.parameters->Insert(null,
2755                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2756             }
2757
2758             ListAdd(declarators, MkInitDeclarator(d, null));
2759
2760             {
2761                Context oldCtx = curContext;
2762                curContext = globalContext;
2763                decl = MkDeclaration(specifiers, declarators);
2764                curContext = oldCtx;
2765             }
2766
2767             // Keep a different symbol for the function definition than the declaration...
2768             if(symbol.pointerExternal)
2769             {
2770                Symbol functionSymbol { };
2771                // Copy symbol
2772                {
2773                   *functionSymbol = *symbol;
2774                   functionSymbol.string = CopyString(symbol.string);
2775                   if(functionSymbol.type)
2776                      functionSymbol.type.refCount++;
2777                }
2778
2779                excludedSymbols->Add(functionSymbol);
2780
2781                symbol.pointerExternal.symbol = functionSymbol;
2782             }
2783             external = MkExternalDeclaration(decl);
2784             if(curExternal)
2785                ast->Insert(curExternal.prev, external);
2786             external.symbol = symbol;
2787             symbol.pointerExternal = external;
2788          }
2789          else
2790          {
2791             // Move declaration higher...
2792             ast->Move(symbol.pointerExternal, curExternal.prev);
2793          }
2794
2795          if(curExternal)
2796             symbol.id = curExternal.symbol.idCode;
2797       }
2798    }
2799    return (symbol && symbol._import && function.module != privateModule && function.module.importType != staticImport) ? true : false;
2800 }
2801
2802 void DeclareGlobalData(GlobalData data)
2803 {
2804    Symbol symbol = data.symbol;
2805    if(curExternal && (!symbol || symbol.id > curExternal.symbol.idCode))
2806    {
2807       if(inCompiler)
2808       {
2809          if(!symbol)
2810             symbol = data.symbol = Symbol { };
2811       }
2812       if(!data.dataType)
2813          data.dataType = ProcessTypeString(data.dataTypeString, false);
2814       DeclareType(data.dataType, true, true);
2815       if(inCompiler)
2816       {
2817          if(!symbol.pointerExternal)
2818          {
2819             // We need a declaration here :)
2820             Declaration decl;
2821             OldList * specifiers, * declarators;
2822             Declarator d;
2823             External external;
2824
2825             specifiers = MkList();
2826             declarators = MkList();
2827
2828             ListAdd(specifiers, MkSpecifier(EXTERN));
2829             d = MkDeclaratorIdentifier(MkIdentifier(data.fullName));
2830             d = SpecDeclFromString(data.dataTypeString, specifiers, d);
2831
2832             ListAdd(declarators, MkInitDeclarator(d, null));
2833
2834             decl = MkDeclaration(specifiers, declarators);
2835             external = MkExternalDeclaration(decl);
2836             if(curExternal)
2837                ast->Insert(curExternal.prev, external);
2838             external.symbol = symbol;
2839             symbol.pointerExternal = external;
2840          }
2841          else
2842          {
2843             // Move declaration higher...
2844             ast->Move(symbol.pointerExternal, curExternal.prev);
2845          }
2846
2847          if(curExternal)
2848             symbol.id = curExternal.symbol.idCode;
2849       }
2850    }
2851 }
2852
2853 class Conversion : struct
2854 {
2855    Conversion prev, next;
2856    Property convert;
2857    bool isGet;
2858    Type resultType;
2859 };
2860
2861 public bool MatchTypes(Type source, Type dest, OldList conversions, Class owningClassSource, Class owningClassDest, bool doConversion, bool enumBaseType, bool acceptReversedParams, bool isConversionExploration)
2862 {
2863    if(source && dest)
2864    {
2865       // Property convert;
2866
2867       if(source.kind == templateType && dest.kind != templateType)
2868       {
2869          Type type = ProcessTemplateParameterType(source.templateParameter);
2870          if(type) source = type;
2871       }
2872
2873       if(dest.kind == templateType && source.kind != templateType)
2874       {
2875          Type type = ProcessTemplateParameterType(dest.templateParameter);
2876          if(type) dest = type;
2877       }
2878
2879       if(dest.classObjectType == typedObject)
2880       {
2881          if(source.classObjectType != anyObject)
2882             return true;
2883          else
2884          {
2885             // If either the source or the destination defines the class, accepts any_object as compatible for a typed_object
2886             if((dest._class && strcmp(dest._class.string, "class")) || (source._class && strcmp(source._class.string, "class")))
2887             {
2888                return true;
2889             }
2890          }
2891       }
2892       else
2893       {
2894          if(source.classObjectType == anyObject)
2895             return true;
2896          if(dest.classObjectType == anyObject && source.classObjectType != typedObject)
2897             return true;
2898       }
2899
2900       if((dest.kind == structType && source.kind == structType) ||
2901          (dest.kind == unionType && source.kind == unionType))
2902       {
2903          if((dest.enumName && source.enumName && !strcmp(dest.enumName, source.enumName)) ||
2904              (source.members.first && source.members.first == dest.members.first))
2905             return true;
2906       }
2907
2908       if(dest.kind == ellipsisType && source.kind != voidType)
2909          return true;
2910
2911       if(dest.kind == pointerType && dest.type.kind == voidType &&
2912          ((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))
2913          || source.kind == subClassType || source.kind == pointerType || source.kind == arrayType || source.kind == functionType || source.kind == thisClassType)
2914
2915          /*source.kind != voidType && source.kind != structType && source.kind != unionType  */
2916
2917          /*&& (source.kind != classType /-*|| source._class.registered.type != structClass)*/)
2918          return true;
2919       if(!isConversionExploration && source.kind == pointerType && source.type.kind == voidType &&
2920          ((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))
2921          || dest.kind == subClassType || dest.kind == pointerType || dest.kind == arrayType || dest.kind == functionType || dest.kind == thisClassType)
2922
2923          /* dest.kind != voidType && dest.kind != structType && dest.kind != unionType  */
2924
2925          /*&& (dest.kind != classType || dest._class.registered.type != structClass)*/)
2926          return true;
2927
2928       if(((source.kind == classType && dest.kind == classType) || (source.kind == subClassType && dest.kind == subClassType)) && source._class)
2929       {
2930          if(source._class.registered && source._class.registered.type == unitClass)
2931          {
2932             if(conversions != null)
2933             {
2934                if(source._class.registered == dest._class.registered)
2935                   return true;
2936             }
2937             else
2938             {
2939                Class sourceBase, destBase;
2940                for(sourceBase = source._class.registered; sourceBase && sourceBase.base.type != systemClass; sourceBase = sourceBase.base);
2941                for(destBase = dest._class.registered; destBase && destBase.base.type != systemClass; destBase = destBase.base);
2942                if(sourceBase == destBase)
2943                   return true;
2944             }
2945          }
2946          // Don't match enum inheriting from other enum if resolving enumeration values
2947          // TESTING: !dest.classObjectType
2948          else if(source._class && dest._class && (dest.classObjectType == source.classObjectType || !dest.classObjectType) &&
2949             (enumBaseType ||
2950                (!source._class.registered || source._class.registered.type != enumClass) ||
2951                (!dest._class.registered || dest._class.registered.type != enumClass)) && eClass_IsDerived(source._class.registered, dest._class.registered))
2952             return true;
2953          else
2954          {
2955             // Added this so that DefinedColor = Color doesn't go through ColorRGB property
2956             if(enumBaseType &&
2957                dest._class && dest._class.registered && dest._class.registered.type == enumClass &&
2958                ((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)
2959             {
2960                if(eClass_IsDerived(dest._class.registered, source._class.registered))
2961                {
2962                   return true;
2963                }
2964             }
2965          }
2966       }
2967
2968       // JUST ADDED THIS...
2969       if(source.kind == subClassType && dest.kind == classType && dest._class && !strcmp(dest._class.string, "ecere::com::Class"))
2970          return true;
2971
2972       if(doConversion)
2973       {
2974          // Just added this for Straight conversion of ColorAlpha => Color
2975          if(source.kind == classType)
2976          {
2977             Class _class;
2978             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
2979             {
2980                Property convert;
2981                for(convert = _class.conversions.first; convert; convert = convert.next)
2982                {
2983                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
2984                   {
2985                      Conversion after = (conversions != null) ? conversions.last : null;
2986
2987                      if(!convert.dataType)
2988                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
2989                      if(MatchTypes(convert.dataType, dest, conversions, null, null, false, true, false, true))
2990                      {
2991                         if(!conversions && !convert.Get)
2992                            return true;
2993                         else if(conversions != null)
2994                         {
2995                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
2996                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
2997                               (dest.kind != classType || dest._class.registered != _class.base))
2998                               return true;
2999                            else
3000                            {
3001                               Conversion conv { convert = convert, isGet = true };
3002                               // conversions.Add(conv);
3003                               conversions.Insert(after, conv);
3004                               return true;
3005                            }
3006                         }
3007                      }
3008                   }
3009                }
3010             }
3011          }
3012
3013          // MOVING THIS??
3014
3015          if(dest.kind == classType)
3016          {
3017             Class _class;
3018             for(_class = dest._class ? dest._class.registered : null; _class; _class = _class.base)
3019             {
3020                Property convert;
3021                for(convert = _class.conversions.first; convert; convert = convert.next)
3022                {
3023                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3024                   {
3025                      // Conversion after = (conversions != null) ? conversions.last : null;
3026
3027                      if(!convert.dataType)
3028                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3029                      // Just added this equality check to prevent recursion.... Make it safer?
3030                      // Changed enumBaseType to false here to prevent all int-compatible enums to show up in AnchorValues
3031                      if(convert.dataType != dest && MatchTypes(source, convert.dataType, conversions, null, null, true, false /*true*/, false, true))
3032                      {
3033                         if(!conversions && !convert.Set)
3034                            return true;
3035                         else if(conversions != null)
3036                         {
3037                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3038                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3039                               (source.kind != classType || source._class.registered != _class.base))
3040                               return true;
3041                            else
3042                            {
3043                               // *** Testing this! ***
3044                               Conversion conv { convert = convert };
3045                               conversions.Add(conv);
3046                               //conversions.Insert(after, conv);
3047                               return true;
3048                            }
3049                         }
3050                      }
3051                   }
3052                }
3053             }
3054             /*if(dest._class.registered && !strcmp(dest._class.registered.name, "bool"))
3055             {
3056                if(source.kind != voidType && source.kind != structType && source.kind != unionType &&
3057                   (source.kind != classType || source._class.registered.type != structClass))
3058                   return true;
3059             }*/
3060
3061             // TESTING THIS... IS THIS OK??
3062             if(enumBaseType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3063             {
3064                if(!dest._class.registered.dataType)
3065                   dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3066                // Only support this for classes...
3067                if(dest._class.registered.dataType.kind == classType || source.truth || dest.truth/* ||
3068                   !strcmp(dest._class.registered.name, "bool") || (source.kind == classType && !strcmp(source._class.string, "bool"))*/)
3069                {
3070                   if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false))
3071                   {
3072                      return true;
3073                   }
3074                }
3075             }
3076          }
3077
3078          // Moved this lower
3079          if(source.kind == classType)
3080          {
3081             Class _class;
3082             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3083             {
3084                Property convert;
3085                for(convert = _class.conversions.first; convert; convert = convert.next)
3086                {
3087                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3088                   {
3089                      Conversion after = (conversions != null) ? conversions.last : null;
3090
3091                      if(!convert.dataType)
3092                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3093                      if(convert.dataType != source && MatchTypes(convert.dataType, dest, conversions, null, null, true, true, false, true))
3094                      {
3095                         if(!conversions && !convert.Get)
3096                            return true;
3097                         else if(conversions != null)
3098                         {
3099                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3100                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3101                               (dest.kind != classType || dest._class.registered != _class.base))
3102                               return true;
3103                            else
3104                            {
3105                               Conversion conv { convert = convert, isGet = true };
3106
3107                               // conversions.Add(conv);
3108                               conversions.Insert(after, conv);
3109                               return true;
3110                            }
3111                         }
3112                      }
3113                   }
3114                }
3115             }
3116
3117             // TESTING THIS... IS THIS OK??
3118             if(enumBaseType && source._class && source._class.registered && source._class.registered.type == enumClass)
3119             {
3120                if(!source._class.registered.dataType)
3121                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3122                if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, true, false, false))
3123                {
3124                   return true;
3125                }
3126             }
3127          }
3128       }
3129
3130       if(source.kind == classType || source.kind == subClassType)
3131          ;
3132       else if(dest.kind == source.kind &&
3133          (dest.kind != structType && dest.kind != unionType &&
3134           dest.kind != functionType && dest.kind != arrayType && dest.kind != pointerType && dest.kind != methodType))
3135           return true;
3136       // RECENTLY ADDED THESE
3137       else if(dest.kind == doubleType && source.kind == floatType)
3138          return true;
3139       else if(dest.kind == shortType && (source.kind == charType || source.kind == _BoolType))
3140          return true;
3141       else if(dest.kind == intType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intSizeType /* Exception here for size_t */))
3142          return true;
3143       else if(dest.kind == int64Type && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intPtrType || source.kind == intSizeType))
3144          return true;
3145       else if(dest.kind == intPtrType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intSizeType || source.kind == int64Type))
3146          return true;
3147       else if(dest.kind == intSizeType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == int64Type || source.kind == intPtrType))
3148          return true;
3149       else if(source.kind == enumType &&
3150          (dest.kind == intType || dest.kind == shortType || dest.kind == charType || source.kind == _BoolType || dest.kind == longType || dest.kind == int64Type || dest.kind == intPtrType || dest.kind == intSizeType))
3151           return true;
3152       else if(dest.kind == enumType &&
3153          (source.kind == intType || source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == longType || source.kind == int64Type || source.kind == intPtrType || source.kind == intSizeType))
3154           return true;
3155       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) &&
3156               ((source.kind == functionType || (source.kind == pointerType && source.type.kind == functionType) || source.kind == methodType)))
3157       {
3158          Type paramSource, paramDest;
3159
3160          if(dest.kind == methodType)
3161             owningClassDest = dest.methodClass ? dest.methodClass : dest.method._class;
3162          if(source.kind == methodType)
3163             owningClassSource = source.methodClass ? source.methodClass : source.method._class;
3164
3165          if(dest.kind == pointerType && dest.type.kind == functionType) dest = dest.type;
3166          if(source.kind == pointerType && source.type.kind == functionType) source = source.type;
3167          if(dest.kind == methodType)
3168             dest = dest.method.dataType;
3169          if(source.kind == methodType)
3170             source = source.method.dataType;
3171
3172          paramSource = source.params.first;
3173          if(paramSource && paramSource.kind == voidType) paramSource = null;
3174          paramDest = dest.params.first;
3175          if(paramDest && paramDest.kind == voidType) paramDest = null;
3176
3177
3178          if((dest.staticMethod || (!dest.thisClass && !owningClassDest)) &&
3179             !(source.staticMethod || (!source.thisClass && !owningClassSource)))
3180          {
3181             // Source thisClass must be derived from destination thisClass
3182             if(!paramDest || (!(paramDest.kind == pointerType && paramDest.type && paramDest.type.kind == voidType) && (paramDest.kind != classType ||
3183                !eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource,paramDest._class.registered))))
3184             {
3185                if(paramDest && paramDest.kind == classType)
3186                   Compiler_Error($"method class must be derived from %s\n", paramDest._class.string);
3187                else
3188                   Compiler_Error($"method class should not take an object\n");
3189                return false;
3190             }
3191             paramDest = paramDest.next;
3192          }
3193          else if(!dest.staticMethod && (dest.thisClass || owningClassDest))
3194          {
3195             if((source.staticMethod || (!source.thisClass && !owningClassSource)))
3196             {
3197                if(dest.thisClass)
3198                {
3199                   if(!paramSource || paramSource.kind != classType || !eClass_IsDerived(paramSource._class.registered,dest.thisClass.registered))
3200                   {
3201                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3202                      return false;
3203                   }
3204                }
3205                else
3206                {
3207                   // THIS WAS BACKWARDS:
3208                   // if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(owningClassDest, paramSource._class.registered)))
3209                   if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(paramSource._class.registered, owningClassDest)))
3210                   {
3211                      if(owningClassDest)
3212                        Compiler_Error($"%s expected to be derived from method class\n", owningClassDest.fullName);
3213                      else
3214                         Compiler_Error($"overriding class expected to be derived from method class\n");
3215                      return false;
3216                   }
3217                }
3218                paramSource = paramSource.next;
3219             }
3220             else
3221             {
3222                if(dest.thisClass)
3223                {
3224                   // Source thisClass must be derived from destination thisClass
3225                   if(!eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource, dest.thisClass.registered))
3226                   {
3227                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3228                      return false;
3229                   }
3230                }
3231                else
3232                {
3233                   // THIS WAS BACKWARDS TOO??
3234                   // if(source.thisClass && owningClassDest && !eClass_IsDerived(owningClassDest, source.thisClass.registered))
3235                   if(source.thisClass && source.thisClass.registered && owningClassDest && !eClass_IsDerived(source.thisClass.registered, owningClassDest))
3236                   {
3237                      //if(owningClass)
3238                         Compiler_Error($"%s expected to be derived from method class\n", /*owningClass.name*/ source.thisClass.registered.fullName);
3239                      //else
3240                         //Compiler_Error($"overriding class expected to be derived from method class\n");
3241                      return false;
3242                   }
3243                }
3244             }
3245          }
3246
3247
3248          // Source return type must be derived from destination return type
3249          if(!MatchTypes(source.returnType, dest.returnType, null, null, null, true, true, false, false))
3250          {
3251             Compiler_Warning($"incompatible return type for function\n");
3252             return false;
3253          }
3254
3255          // Check parameters
3256
3257          for(; paramDest; paramDest = paramDest.next)
3258          {
3259             if(!paramSource)
3260             {
3261                //Compiler_Warning($"not enough parameters\n");
3262                Compiler_Error($"not enough parameters\n");
3263                return false;
3264             }
3265             {
3266                Type paramDestType = paramDest;
3267                Type paramSourceType = paramSource;
3268                Type type = paramDestType;
3269
3270                // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
3271                if(paramDest.kind == templateType && paramDest.templateParameter.type == TemplateParameterType::type && owningClassSource &&
3272                   paramSource.kind != templateType)
3273                {
3274                   int id = 0;
3275                   ClassTemplateParameter curParam = null;
3276                   Class sClass;
3277                   for(sClass = owningClassSource; sClass; sClass = sClass.base)
3278                   {
3279                      id = 0;
3280                      if(sClass.templateClass) sClass = sClass.templateClass;
3281                      for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
3282                      {
3283                         if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
3284                         {
3285                            for(sClass = sClass.base; sClass; sClass = sClass.base)
3286                            {
3287                               if(sClass.templateClass) sClass = sClass.templateClass;
3288                               id += sClass.templateParams.count;
3289                            }
3290                            break;
3291                         }
3292                         id++;
3293                      }
3294                      if(curParam) break;
3295                   }
3296
3297                   if(curParam)
3298                   {
3299                      ClassTemplateArgument arg = owningClassSource.templateArgs[id];
3300                      paramDestType = type = ProcessTypeString(arg.dataTypeString, false);
3301                   }
3302                }
3303
3304                // paramDest must be derived from paramSource
3305                if(!MatchTypes(paramDestType, paramSourceType, null, null, null, true, true, false, false) &&
3306                   (!acceptReversedParams || !MatchTypes(paramSourceType, paramDestType, null, null, null, true, true, false, false)))
3307                {
3308                   char type[1024];
3309                   type[0] = 0;
3310                   PrintType(paramDest, type, false, true);
3311                   Compiler_Warning($"incompatible parameter %s (expected %s)\n", paramSource.name, type);
3312
3313                   if(paramDestType != paramDest)
3314                      FreeType(paramDestType);
3315                   return false;
3316                }
3317                if(paramDestType != paramDest)
3318                   FreeType(paramDestType);
3319             }
3320
3321             paramSource = paramSource.next;
3322          }
3323          if(paramSource)
3324          {
3325             Compiler_Error($"too many parameters\n");
3326             return false;
3327          }
3328          return true;
3329       }
3330       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) && (source.kind == pointerType && source.type.kind == voidType))
3331       {
3332          return true;
3333       }
3334       else if((dest.kind == pointerType || dest.kind == arrayType) &&
3335          (source.kind == arrayType || source.kind == pointerType))
3336       {
3337          if(MatchTypes(source.type, dest.type, null, null, null, true, true, false, false))
3338             return true;
3339       }
3340    }
3341    return false;
3342 }
3343
3344 static void FreeConvert(Conversion convert)
3345 {
3346    if(convert.resultType)
3347       FreeType(convert.resultType);
3348 }
3349
3350 bool MatchWithEnums_NameSpace(NameSpace nameSpace, Expression sourceExp, Type dest,
3351                               char * string, OldList conversions)
3352 {
3353    BTNamedLink link;
3354
3355    for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
3356    {
3357       Class _class = link.data;
3358       if(_class.type == enumClass)
3359       {
3360          OldList converts { };
3361          Type type { };
3362          type.kind = classType;
3363
3364          if(!_class.symbol)
3365             _class.symbol = FindClass(_class.fullName);
3366          type._class = _class.symbol;
3367
3368          if(MatchTypes(type, dest, &converts, null, null, true, false, false, false))
3369          {
3370             NamedLink value;
3371             Class enumClass = eSystem_FindClass(privateModule, "enum");
3372             if(enumClass)
3373             {
3374                Class baseClass;
3375                for(baseClass = _class ; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
3376                {
3377                   EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
3378                   for(value = e.values.first; value; value = value.next)
3379                   {
3380                      if(!strcmp(value.name, string))
3381                         break;
3382                   }
3383                   if(value)
3384                   {
3385                      FreeExpContents(sourceExp);
3386                      FreeType(sourceExp.expType);
3387
3388                      sourceExp.isConstant = true;
3389                      sourceExp.expType = MkClassType(baseClass.fullName);
3390                      //if(inCompiler)
3391                      {
3392                         char constant[256];
3393                         sourceExp.type = constantExp;
3394                         if(!strcmp(baseClass.dataTypeString, "int"))
3395                            sprintf(constant, "%d",(int)value.data);
3396                         else
3397                            sprintf(constant, "0x%X",(int)value.data);
3398                         sourceExp.constant = CopyString(constant);
3399                         //for(;baseClass.base && baseClass.base.type != systemClass; baseClass = baseClass.base);
3400                      }
3401
3402                      while(converts.first)
3403                      {
3404                         Conversion convert = converts.first;
3405                         converts.Remove(convert);
3406                         conversions.Add(convert);
3407                      }
3408                      delete type;
3409                      return true;
3410                   }
3411                }
3412             }
3413          }
3414          if(converts.first)
3415             converts.Free(FreeConvert);
3416          delete type;
3417       }
3418    }
3419    for(nameSpace = (NameSpace *)nameSpace.nameSpaces.first; nameSpace != null; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
3420       if(MatchWithEnums_NameSpace(nameSpace, sourceExp, dest, string, conversions))
3421          return true;
3422    return false;
3423 }
3424
3425 public bool ModuleVisibility(Module searchIn, Module searchFor)
3426 {
3427    SubModule subModule;
3428
3429    if(searchFor == searchIn)
3430       return true;
3431
3432    for(subModule = searchIn.modules.first; subModule; subModule = subModule.next)
3433    {
3434       if(subModule.importMode == publicAccess || searchIn == searchIn.application)
3435       {
3436          if(ModuleVisibility(subModule.module, searchFor))
3437             return true;
3438       }
3439    }
3440    return false;
3441 }
3442
3443 bool MatchWithEnums_Module(Module mainModule, Expression sourceExp, Type dest, char * string, OldList conversions)
3444 {
3445    Module module;
3446
3447    if(MatchWithEnums_NameSpace(mainModule.application.systemNameSpace, sourceExp, dest, string, conversions))
3448       return true;
3449    if(MatchWithEnums_NameSpace(mainModule.application.privateNameSpace, sourceExp, dest, string, conversions))
3450       return true;
3451    if(MatchWithEnums_NameSpace(mainModule.application.publicNameSpace, sourceExp, dest, string, conversions))
3452       return true;
3453
3454    for(module = mainModule.application.allModules.first; module; module = module.next)
3455    {
3456       if(ModuleVisibility(mainModule, module) && MatchWithEnums_NameSpace(module.publicNameSpace, sourceExp, dest, string, conversions))
3457          return true;
3458    }
3459    return false;
3460 }
3461
3462 bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, bool skipUnitBla)
3463 {
3464    Type source = sourceExp.expType;
3465    Type realDest = dest;
3466    Type backupSourceExpType = null;
3467
3468    if(dest.kind == pointerType && sourceExp.type == constantExp && !strtoul(sourceExp.constant, null, 0))
3469       return true;
3470
3471    if(!skipUnitBla && source && dest && source.kind == classType && dest.kind == classType)
3472    {
3473        if(source._class && source._class.registered && source._class.registered.type == unitClass)
3474        {
3475           Class sourceBase, destBase;
3476           for(sourceBase = source._class.registered;
3477               sourceBase && sourceBase.base && sourceBase.base.type != systemClass;
3478               sourceBase = sourceBase.base);
3479           for(destBase = dest._class.registered;
3480               destBase && destBase.base && destBase.base.type != systemClass;
3481               destBase = destBase.base);
3482           //if(source._class.registered == dest._class.registered)
3483           if(sourceBase == destBase)
3484              return true;
3485        }
3486    }
3487
3488    if(source)
3489    {
3490       OldList * specs;
3491       bool flag = false;
3492       int64 value = MAXINT;
3493
3494       source.refCount++;
3495       dest.refCount++;
3496
3497       if(sourceExp.type == constantExp)
3498       {
3499          if(source.isSigned)
3500             value = strtoll(sourceExp.constant, null, 0);
3501          else
3502             value = strtoull(sourceExp.constant, null, 0);
3503       }
3504       else if(sourceExp.type == opExp && sourceExp.op.op == '-' && !sourceExp.op.exp1 && sourceExp.op.exp2 && sourceExp.op.exp2.type == constantExp)
3505       {
3506          if(source.isSigned)
3507             value = -strtoll(sourceExp.op.exp2.constant, null, 0);
3508          else
3509             value = -strtoull(sourceExp.op.exp2.constant, null, 0);
3510       }
3511
3512       if(dest.kind != classType && source.kind == classType && source._class && source._class.registered &&
3513          !strcmp(source._class.registered.fullName, "ecere::com::unichar"))
3514       {
3515          FreeType(source);
3516          source = Type { kind = intType, isSigned = false, refCount = 1 };
3517       }
3518
3519       if(dest.kind == classType)
3520       {
3521          Class _class = dest._class ? dest._class.registered : null;
3522
3523          if(_class && _class.type == unitClass)
3524          {
3525             if(source.kind != classType)
3526             {
3527                Type tempType { };
3528                Type tempDest, tempSource;
3529
3530                for(; _class.base.type != systemClass; _class = _class.base);
3531                tempSource = dest;
3532                tempDest = tempType;
3533
3534                tempType.kind = classType;
3535                if(!_class.symbol)
3536                   _class.symbol = FindClass(_class.fullName);
3537
3538                tempType._class = _class.symbol;
3539                tempType.truth = dest.truth;
3540                if(tempType._class)
3541                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false);
3542
3543                // NOTE: To handle bad warnings on int64 vs 32 bit eda::Id incompatibilities
3544                backupSourceExpType = sourceExp.expType;
3545                sourceExp.expType = dest; dest.refCount++;
3546                //sourceExp.expType = MkClassType(_class.fullName);
3547                flag = true;
3548
3549                delete tempType;
3550             }
3551          }
3552
3553
3554          // Why wasn't there something like this?
3555          if(_class && _class.type == bitClass && source.kind != classType)
3556          {
3557             if(!dest._class.registered.dataType)
3558                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3559             if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false))
3560             {
3561                FreeType(source);
3562                FreeType(sourceExp.expType);
3563                source = sourceExp.expType = MkClassType(dest._class.string);
3564                source.refCount++;
3565
3566                //source.kind = classType;
3567                //source._class = dest._class;
3568             }
3569          }
3570
3571          // Adding two enumerations
3572          /*
3573          if(_class && _class.type == enumClass && source.kind == classType && source._class && source._class.registered && source._class.registered.type == enumClass)
3574          {
3575             if(!source._class.registered.dataType)
3576                source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3577             if(!dest._class.registered.dataType)
3578                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3579
3580             if(MatchTypes(source._class.registered.dataType, dest._class.registered.dataType, conversions, null, null, true, false, false))
3581             {
3582                FreeType(source);
3583                source = sourceExp.expType = MkClassType(dest._class.string);
3584                source.refCount++;
3585
3586                //source.kind = classType;
3587                //source._class = dest._class;
3588             }
3589          }*/
3590
3591          if(_class && !strcmp(_class.fullName, "ecere::com::Class") && source.kind == pointerType && source.type && source.type.kind == charType && sourceExp.type == stringExp)
3592          {
3593             OldList * specs = MkList();
3594             Declarator decl;
3595             char string[1024];
3596
3597             ReadString(string, sourceExp.string);
3598             decl = SpecDeclFromString(string, specs, null);
3599
3600             FreeExpContents(sourceExp);
3601             FreeType(sourceExp.expType);
3602
3603             sourceExp.type = classExp;
3604             sourceExp._classExp.specifiers = specs;
3605             sourceExp._classExp.decl = decl;
3606             sourceExp.expType = dest;
3607             dest.refCount++;
3608
3609             FreeType(source);
3610             FreeType(dest);
3611             if(backupSourceExpType) FreeType(backupSourceExpType);
3612             return true;
3613          }
3614       }
3615       else if(source.kind == classType)
3616       {
3617          Class _class = source._class ? source._class.registered : null;
3618
3619          if(_class && (_class.type == unitClass || !strcmp(_class.fullName, "bool") || /*_class.type == enumClass || */_class.type == bitClass ))  // TOCHECK: enumClass, bitClass is new here...
3620          {
3621             /*
3622             if(dest.kind != classType)
3623             {
3624                // Testing this simpler piece of code... (Broke Units Conversion to no unit Logic)
3625                if(!source._class.registered.dataType)
3626                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3627
3628                FreeType(dest);
3629                dest = MkClassType(source._class.string);
3630                //if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, false, false))
3631                //   dest = MkClassType(source._class.string);
3632             }
3633             */
3634
3635             if(dest.kind != classType)
3636             {
3637                Type tempType { };
3638                Type tempDest, tempSource;
3639
3640                if(!source._class.registered.dataType)
3641                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3642
3643                for(; _class.base.type != systemClass; _class = _class.base);
3644                tempDest = source;
3645                tempSource = tempType;
3646                tempType.kind = classType;
3647                tempType._class = FindClass(_class.fullName);
3648                tempType.truth = source.truth;
3649                tempType.classObjectType = source.classObjectType;
3650
3651                if(tempType._class)
3652                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false);
3653
3654                // PUT THIS BACK TESTING UNITS?
3655                if(conversions.last)
3656                {
3657                   ((Conversion)(conversions.last)).resultType = dest;
3658                   dest.refCount++;
3659                }
3660
3661                FreeType(sourceExp.expType);
3662                sourceExp.expType = MkClassType(_class.fullName);
3663                sourceExp.expType.truth = source.truth;
3664                sourceExp.expType.classObjectType = source.classObjectType;
3665
3666                // *** This if was commented out, put it back because "int a =^ Destroy()" shows up bool enum values in autocomplete ***
3667
3668                if(!sourceExp.destType)
3669                {
3670                   FreeType(sourceExp.destType);
3671                   sourceExp.destType = sourceExp.expType;
3672                   if(sourceExp.expType)
3673                      sourceExp.expType.refCount++;
3674                }
3675                //flag = true;
3676                //source = _class.dataType;
3677
3678
3679                // TOCHECK: TESTING THIS NEW CODE
3680                if(!_class.dataType)
3681                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3682                FreeType(dest);
3683                dest = MkClassType(source._class.string);
3684                dest.truth = source.truth;
3685                dest.classObjectType = source.classObjectType;
3686
3687                FreeType(source);
3688                source = _class.dataType;
3689                source.refCount++;
3690
3691                delete tempType;
3692             }
3693          }
3694       }
3695
3696       if(!flag)
3697       {
3698          if(MatchTypes(source, dest, conversions, null, null, true, true, false, false))
3699          {
3700             FreeType(source);
3701             FreeType(dest);
3702             return true;
3703          }
3704       }
3705
3706       // Implicit Casts
3707       /*
3708       if(source.kind == classType)
3709       {
3710          Class _class = source._class.registered;
3711          if(_class.type == unitClass)
3712          {
3713             if(!_class.dataType)
3714                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3715             source = _class.dataType;
3716          }
3717       }*/
3718
3719       if(dest.kind == classType)
3720       {
3721          Class _class = dest._class ? dest._class.registered : null;
3722          if(_class && !dest.truth && (_class.type == unitClass || !strcmp(_class.fullName, "bool") ||
3723             (/*_class.type == enumClass*/_class.type != structClass && !value && source.kind == intType) || _class.type == bitClass))   // TOCHECK: enumClass, bitClass is new here...
3724          {
3725             if(_class.type == normalClass || _class.type == noHeadClass)
3726             {
3727                Expression newExp { };
3728                *newExp = *sourceExp;
3729                if(sourceExp.destType) sourceExp.destType.refCount++;
3730                if(sourceExp.expType)  sourceExp.expType.refCount++;
3731                sourceExp.type = castExp;
3732                sourceExp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
3733                sourceExp.cast.exp = newExp;
3734                FreeType(sourceExp.expType);
3735                sourceExp.expType = null;
3736                ProcessExpressionType(sourceExp);
3737
3738                // In Debugger, this helps with addresses (e.g. null pointers) that end up casted to a void *: keeps a classType instead of a pointerType
3739                if(!inCompiler)
3740                {
3741                   FreeType(sourceExp.expType);
3742                   sourceExp.expType = dest;
3743                }
3744
3745                FreeType(source);
3746                if(inCompiler) FreeType(dest);
3747
3748                if(backupSourceExpType) FreeType(backupSourceExpType);
3749                return true;
3750             }
3751
3752             if(!_class.dataType)
3753                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3754             FreeType(dest);
3755             dest = _class.dataType;
3756             dest.refCount++;
3757          }
3758
3759          // Accept lower precision types for units, since we want to keep the unit type
3760          if(dest.kind == doubleType &&
3761             (source.kind == doubleType || source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType ||
3762              source.kind == charType || source.kind == _BoolType))
3763          {
3764             specs = MkListOne(MkSpecifier(DOUBLE));
3765          }
3766          else if(dest.kind == floatType &&
3767             (source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3768             source.kind == _BoolType || source.kind == doubleType))
3769          {
3770             specs = MkListOne(MkSpecifier(FLOAT));
3771          }
3772          else if(dest.kind == int64Type && (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3773             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3774          {
3775             specs = MkList();
3776             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3777             ListAdd(specs, MkSpecifier(INT64));
3778          }
3779          else if(dest.kind == intType && (source.kind == intType || source.kind == shortType || source.kind == charType ||
3780             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3781          {
3782             specs = MkList();
3783             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3784             ListAdd(specs, MkSpecifier(INT));
3785          }
3786          else if(dest.kind == shortType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType ||
3787             source.kind == floatType || source.kind == doubleType))
3788          {
3789             specs = MkList();
3790             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3791             ListAdd(specs, MkSpecifier(SHORT));
3792          }
3793          else if(dest.kind == charType && (source.kind == charType || source.kind == _BoolType || source.kind == shortType || source.kind == intType ||
3794             source.kind == floatType || source.kind == doubleType))
3795          {
3796             specs = MkList();
3797             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3798             ListAdd(specs, MkSpecifier(CHAR));
3799          }
3800          else
3801          {
3802             FreeType(source);
3803             FreeType(dest);
3804             if(backupSourceExpType)
3805             {
3806                // Failed to convert: revert previous exp type
3807                if(sourceExp.expType) FreeType(sourceExp.expType);
3808                sourceExp.expType = backupSourceExpType;
3809             }
3810             return false;
3811          }
3812       }
3813       else if(dest.kind == doubleType &&
3814          (source.kind == doubleType || source.kind == floatType || source.kind == int64Type || source.kind == intType || source.kind == enumType || source.kind == shortType ||
3815           source.kind == _BoolType || source.kind == charType))
3816       {
3817          specs = MkListOne(MkSpecifier(DOUBLE));
3818       }
3819       else if(dest.kind == floatType &&
3820          (source.kind == floatType || source.kind == enumType || source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3821       {
3822          specs = MkListOne(MkSpecifier(FLOAT));
3823       }
3824       else if(dest.kind == _BoolType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3825          (value == 1 || value == 0))
3826       {
3827          specs = MkList();
3828          ListAdd(specs, MkSpecifier(BOOL));
3829       }
3830       else if(dest.kind == charType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3831          (dest.isSigned ? (value >= -128 && value <= 127) : (value >= 0 && value <= 255)))
3832       {
3833          specs = MkList();
3834          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3835          ListAdd(specs, MkSpecifier(CHAR));
3836       }
3837       else if(dest.kind == shortType && (source.kind == enumType || source.kind == _BoolType || source.kind == charType || source.kind == shortType ||
3838          (source.kind == intType && (dest.isSigned ? (value >= -32768 && value <= 32767) : (value >= 0 && value <= 65535)))))
3839       {
3840          specs = MkList();
3841          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3842          ListAdd(specs, MkSpecifier(SHORT));
3843       }
3844       else if(dest.kind == intType && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType))
3845       {
3846          specs = MkList();
3847          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3848          ListAdd(specs, MkSpecifier(INT));
3849       }
3850       else if(dest.kind == int64Type && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType || source.kind == int64Type))
3851       {
3852          specs = MkList();
3853          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3854          ListAdd(specs, MkSpecifier(INT64));
3855       }
3856       else if(dest.kind == enumType &&
3857          (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3858       {
3859          specs = MkListOne(MkEnum(MkIdentifier(dest.enumName), null));
3860       }
3861       else
3862       {
3863          FreeType(source);
3864          FreeType(dest);
3865          if(backupSourceExpType)
3866          {
3867             // Failed to convert: revert previous exp type
3868             if(sourceExp.expType) FreeType(sourceExp.expType);
3869             sourceExp.expType = backupSourceExpType;
3870          }
3871          return false;
3872       }
3873
3874       if(!flag)
3875       {
3876          Expression newExp { };
3877          *newExp = *sourceExp;
3878          newExp.prev = null;
3879          newExp.next = null;
3880          if(sourceExp.destType) sourceExp.destType.refCount++;
3881          if(sourceExp.expType)  sourceExp.expType.refCount++;
3882
3883          sourceExp.type = castExp;
3884          if(realDest.kind == classType)
3885          {
3886             sourceExp.cast.typeName = QMkClass(realDest._class.string, null);
3887             FreeList(specs, FreeSpecifier);
3888          }
3889          else
3890             sourceExp.cast.typeName = MkTypeName(specs, null);
3891          if(newExp.type == opExp)
3892          {
3893             sourceExp.cast.exp = MkExpBrackets(MkListOne(newExp));
3894          }
3895          else
3896             sourceExp.cast.exp = newExp;
3897
3898          FreeType(sourceExp.expType);
3899          sourceExp.expType = null;
3900          ProcessExpressionType(sourceExp);
3901       }
3902       else
3903          FreeList(specs, FreeSpecifier);
3904
3905       FreeType(dest);
3906       FreeType(source);
3907       if(backupSourceExpType) FreeType(backupSourceExpType);
3908
3909       return true;
3910    }
3911    else
3912    {
3913       while((sourceExp.type == bracketsExp || sourceExp.type == extensionExpressionExp) && sourceExp.list) sourceExp = sourceExp.list->last;
3914       if(sourceExp.type == identifierExp)
3915       {
3916          Identifier id = sourceExp.identifier;
3917          if(dest.kind == classType)
3918          {
3919             if(dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3920             {
3921                Class _class = dest._class.registered;
3922                Class enumClass = eSystem_FindClass(privateModule, "enum");
3923                if(enumClass)
3924                {
3925                   for( ; _class && _class.type == ClassType::enumClass; _class = _class.base)
3926                   {
3927                      NamedLink value;
3928                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
3929                      for(value = e.values.first; value; value = value.next)
3930                      {
3931                         if(!strcmp(value.name, id.string))
3932                            break;
3933                      }
3934                      if(value)
3935                      {
3936                         FreeExpContents(sourceExp);
3937                         FreeType(sourceExp.expType);
3938
3939                         sourceExp.isConstant = true;
3940                         sourceExp.expType = MkClassType(_class.fullName);
3941                         //if(inCompiler)
3942                         {
3943                            char constant[256];
3944                            sourceExp.type = constantExp;
3945                            if(/*_class && */_class.dataTypeString && !strcmp(_class.dataTypeString, "int")) // _class cannot be null here!
3946                               sprintf(constant, "%d", (int) value.data);
3947                            else
3948                               sprintf(constant, "0x%X", (int) value.data);
3949                            sourceExp.constant = CopyString(constant);
3950                            //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
3951                         }
3952                         return true;
3953                      }
3954                   }
3955                }
3956             }
3957          }
3958
3959          // Loop through all enum classes
3960          if(dest.classObjectType != typedObject && dest.kind == classType /*!= ellipsisType */&& MatchWithEnums_Module(privateModule, sourceExp, dest, id.string, conversions))
3961             return true;
3962       }
3963    }
3964    return false;
3965 }
3966
3967 #define TERTIARY(o, name, m, t, p) \
3968    static bool name(Expression exp, Operand op1, Operand op2, Operand op3)   \
3969    {                                                              \
3970       exp.type = constantExp;                                    \
3971       exp.string = p(op1.m ? op2.m : op3.m);                     \
3972       if(!exp.expType) \
3973          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
3974       return true;                                                \
3975    }
3976
3977 #define BINARY(o, name, m, t, p) \
3978    static bool name(Expression exp, Operand op1, Operand op2)   \
3979    {                                                              \
3980       t value2 = op2.m;                                           \
3981       exp.type = constantExp;                                    \
3982       exp.string = p(op1.m o value2);                     \
3983       if(!exp.expType) \
3984          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
3985       return true;                                                \
3986    }
3987
3988 #define BINARY_DIVIDE(o, name, m, t, p) \
3989    static bool name(Expression exp, Operand op1, Operand op2)   \
3990    {                                                              \
3991       t value2 = op2.m;                                           \
3992       exp.type = constantExp;                                    \
3993       exp.string = p(value2 ? (op1.m o value2) : 0);             \
3994       if(!exp.expType) \
3995          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
3996       return true;                                                \
3997    }
3998
3999 #define UNARY(o, name, m, t, p) \
4000    static bool name(Expression exp, Operand op1)                \
4001    {                                                              \
4002       exp.type = constantExp;                                    \
4003       exp.string = p((t)(o op1.m));                                   \
4004       if(!exp.expType) \
4005          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4006       return true;                                                \
4007    }
4008
4009 #define OPERATOR_ALL(macro, o, name) \
4010    macro(o, Int##name, i, int, PrintInt) \
4011    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4012    macro(o, Int64##name, i64, int64, PrintInt64) \
4013    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4014    macro(o, Short##name, s, short, PrintShort) \
4015    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4016    macro(o, Char##name, c, char, PrintChar) \
4017    macro(o, UChar##name, uc, unsigned char, PrintUChar) \
4018    macro(o, Float##name, f, float, PrintFloat) \
4019    macro(o, Double##name, d, double, PrintDouble)
4020
4021 #define OPERATOR_INTTYPES(macro, o, name) \
4022    macro(o, Int##name, i, int, PrintInt) \
4023    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4024    macro(o, Int64##name, i64, int64, PrintInt64) \
4025    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4026    macro(o, Short##name, s, short, PrintShort) \
4027    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4028    macro(o, Char##name, c, char, PrintChar) \
4029    macro(o, UChar##name, uc, unsigned char, PrintUChar)
4030
4031
4032 // binary arithmetic
4033 OPERATOR_ALL(BINARY, +, Add)
4034 OPERATOR_ALL(BINARY, -, Sub)
4035 OPERATOR_ALL(BINARY, *, Mul)
4036 OPERATOR_ALL(BINARY_DIVIDE, /, Div)
4037 OPERATOR_INTTYPES(BINARY_DIVIDE, %, Mod)
4038
4039 // unary arithmetic
4040 OPERATOR_ALL(UNARY, -, Neg)
4041
4042 // unary arithmetic increment and decrement
4043 OPERATOR_ALL(UNARY, ++, Inc)
4044 OPERATOR_ALL(UNARY, --, Dec)
4045
4046 // binary arithmetic assignment
4047 OPERATOR_ALL(BINARY, =, Asign)
4048 OPERATOR_ALL(BINARY, +=, AddAsign)
4049 OPERATOR_ALL(BINARY, -=, SubAsign)
4050 OPERATOR_ALL(BINARY, *=, MulAsign)
4051 OPERATOR_ALL(BINARY_DIVIDE, /=, DivAsign)
4052 OPERATOR_INTTYPES(BINARY_DIVIDE, %=, ModAsign)
4053
4054 // binary bitwise
4055 OPERATOR_INTTYPES(BINARY, &, BitAnd)
4056 OPERATOR_INTTYPES(BINARY, |, BitOr)
4057 OPERATOR_INTTYPES(BINARY, ^, BitXor)
4058 OPERATOR_INTTYPES(BINARY, <<, LShift)
4059 OPERATOR_INTTYPES(BINARY, >>, RShift)
4060
4061 // unary bitwise
4062 OPERATOR_INTTYPES(UNARY, ~, BitNot)
4063
4064 // binary bitwise assignment
4065 OPERATOR_INTTYPES(BINARY, &=, AndAsign)
4066 OPERATOR_INTTYPES(BINARY, |=, OrAsign)
4067 OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
4068 OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
4069 OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
4070
4071 // unary logical negation
4072 OPERATOR_INTTYPES(UNARY, !, Not)
4073
4074 // binary logical equality
4075 OPERATOR_ALL(BINARY, ==, Equ)
4076 OPERATOR_ALL(BINARY, !=, Nqu)
4077
4078 // binary logical
4079 OPERATOR_ALL(BINARY, &&, And)
4080 OPERATOR_ALL(BINARY, ||, Or)
4081
4082 // binary logical relational
4083 OPERATOR_ALL(BINARY, >, Grt)
4084 OPERATOR_ALL(BINARY, <, Sma)
4085 OPERATOR_ALL(BINARY, >=, GrtEqu)
4086 OPERATOR_ALL(BINARY, <=, SmaEqu)
4087
4088 // tertiary condition operator
4089 OPERATOR_ALL(TERTIARY, ?, Cond)
4090
4091 //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
4092 #define OPERATOR_TABLE_ALL(name, type) \
4093     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, type##Mod, \
4094                           type##Neg, \
4095                           type##Inc, type##Dec, \
4096                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, type##ModAsign, \
4097                           type##BitAnd, type##BitOr, type##BitXor, type##LShift, type##RShift, \
4098                           type##BitNot, \
4099                           type##AndAsign, type##OrAsign, type##XorAsign, type##LShiftAsign, type##RShiftAsign, \
4100                           type##Not, \
4101                           type##Equ, type##Nqu, \
4102                           type##And, type##Or, \
4103                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu, type##Cond \
4104                         }; \
4105
4106 #define OPERATOR_TABLE_INTTYPES(name, type) \
4107     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, null, \
4108                           type##Neg, \
4109                           type##Inc, type##Dec, \
4110                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, null, \
4111                           null, null, null, null, null, \
4112                           null, \
4113                           null, null, null, null, null, \
4114                           null, \
4115                           type##Equ, type##Nqu, \
4116                           type##And, type##Or, \
4117                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu \
4118                         }; \
4119
4120 OPERATOR_TABLE_ALL(int, Int)
4121 OPERATOR_TABLE_ALL(uint, UInt)
4122 OPERATOR_TABLE_ALL(int64, Int64)
4123 OPERATOR_TABLE_ALL(uint64, UInt64)
4124 OPERATOR_TABLE_ALL(short, Short)
4125 OPERATOR_TABLE_ALL(ushort, UShort)
4126 OPERATOR_TABLE_INTTYPES(float, Float)
4127 OPERATOR_TABLE_INTTYPES(double, Double)
4128 OPERATOR_TABLE_ALL(char, Char)
4129 OPERATOR_TABLE_ALL(uchar, UChar)
4130
4131 //OpTable intOps =    {    IntAdd,    IntSub,    IntMul,    IntDiv,    IntMod,    IntExp,    IntNot,    IntBwn,    IntOr,    IntAnd,    IntEqu,    IntNqu,    IntGrt,    IntSma,    IntGrtEqu,    IntSmaEqu,    IntNeg,    IntLBitSft,    IntRBitSft };
4132 //OpTable uintOps =   {   UIntAdd,   UIntSub,   UIntMul,   UIntDiv,   UIntMod,   UIntExp,   UIntNot,   UIntBwn,   UIntOr,   UIntAnd,   UIntEqu,   UIntNqu,   UIntGrt,   UIntSma,   UIntGrtEqu,   UIntSmaEqu,   UIntNeg,   UIntLBitSft,   UIntRBitSft };
4133 //OpTable shortOps =  {  ShortAdd,  ShortSub,  ShortMul,  ShortDiv,  ShortMod,  ShortExp,  ShortNot,  ShortBwn,  ShortOr,  ShortAnd,  ShortEqu,  ShortNqu,  ShortGrt,  ShortSma,  ShortGrtEqu,  ShortSmaEqu,  ShortNeg,  ShortLBitSft,  ShortRBitSft };
4134 //OpTable ushortOps = { UShortAdd, UShortSub, UShortMul, UShortDiv, UShortMod, UShortExp, UShortNot, UShortBwn, UShortOr, UShortAnd, UShortEqu, UShortNqu, UShortGrt, UShortSma, UShortGrtEqu, UShortSmaEqu, UShortNeg, UShortLBitSft, UShortRBitSft };
4135 //OpTable floatOps =  {  FloatAdd,  FloatSub,  FloatMul,  FloatDiv,      null,      null,      null,      null,     null,      null,  FloatEqu,  FloatNqu,  FloatGrt,  FloatSma,  FloatGrtEqu,  FloatSmaEqu,  FloatNeg,          null,          null };
4136 //OpTable doubleOps = { DoubleAdd, DoubleSub, DoubleMul, DoubleDiv,      null,      null,      null,      null,     null,      null, DoubleEqu, DoubleNqu, DoubleGrt, DoubleSma, DoubleGrtEqu, DoubleSmaEqu, DoubleNeg,          null,          null };
4137 //OpTable charOps =   {   CharAdd,   CharSub,   CharMul,   CharDiv,   CharMod,   CharExp,   CharNot,   CharBwn,   CharOr,   CharAnd,   CharEqu,   CharNqu,   CharGrt,   CharSma,   CharGrtEqu,   CharSmaEqu,   CharNeg,   CharLBitSft,   CharRBitSft };
4138 //OpTable ucharOps =  {  UCharAdd,  UCharSub,  UCharMul,  UCharDiv,  UCharMod,  UCharExp,  UCharNot,  UCharBwn,  UCharOr,  UCharAnd,  UCharEqu,  UCharNqu,  UCharGrt,  UCharSma,  UCharGrtEqu,  UCharSmaEqu,  UCharNeg,  UCharLBitSft,  UCharRBitSft };
4139
4140 public void ReadString(char * output,  char * string)
4141 {
4142    int len = strlen(string);
4143    int c,d = 0;
4144    bool quoted = false, escaped = false;
4145    for(c = 0; c<len; c++)
4146    {
4147       char ch = string[c];
4148       if(escaped)
4149       {
4150          switch(ch)
4151          {
4152             case 'n': output[d] = '\n'; break;
4153             case 't': output[d] = '\t'; break;
4154             case 'a': output[d] = '\a'; break;
4155             case 'b': output[d] = '\b'; break;
4156             case 'f': output[d] = '\f'; break;
4157             case 'r': output[d] = '\r'; break;
4158             case 'v': output[d] = '\v'; break;
4159             case '\\': output[d] = '\\'; break;
4160             case '\"': output[d] = '\"'; break;
4161             case '\'': output[d] = '\''; break;
4162             default: output[d] = ch;
4163          }
4164          d++;
4165          escaped = false;
4166       }
4167       else
4168       {
4169          if(ch == '\"')
4170             quoted ^= true;
4171          else if(quoted)
4172          {
4173             if(ch == '\\')
4174                escaped = true;
4175             else
4176                output[d++] = ch;
4177          }
4178       }
4179    }
4180    output[d] = '\0';
4181 }
4182
4183 // String Unescape Copy
4184
4185 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
4186 // This is the same as ReadString above (which also misses numeric escape codes) except it doesn't handle external quotes
4187 public int UnescapeString(char * d, char * s, int len)
4188 {
4189    int j = 0, k = 0;
4190    char ch;
4191    while(j < len && (ch = s[j]))
4192    {
4193       switch(ch)
4194       {
4195          case '\\':
4196             switch((ch = s[++j]))
4197             {
4198                case 'n': d[k] = '\n'; break;
4199                case 't': d[k] = '\t'; break;
4200                case 'a': d[k] = '\a'; break;
4201                case 'b': d[k] = '\b'; break;
4202                case 'f': d[k] = '\f'; break;
4203                case 'r': d[k] = '\r'; break;
4204                case 'v': d[k] = '\v'; break;
4205                case '\\': d[k] = '\\'; break;
4206                case '\"': d[k] = '\"'; break;
4207                case '\'': d[k] = '\''; break;
4208                default: d[k] = '\\'; d[k] = ch;
4209             }
4210             break;
4211          default:
4212             d[k] = ch;
4213       }
4214       j++, k++;
4215    }
4216    d[k] = '\0';
4217    return k;
4218 }
4219
4220 public char * OffsetEscapedString(char * s, int len, int offset)
4221 {
4222    char ch;
4223    int j = 0, k = 0;
4224    while(j < len && k < offset && (ch = s[j]))
4225    {
4226       if(ch == '\\') ++j;
4227       j++, k++;
4228    }
4229    return (k == offset) ? s + j : null;
4230 }
4231
4232 public Operand GetOperand(Expression exp)
4233 {
4234    Operand op { };
4235    Type type = exp.expType;
4236    if(type)
4237    {
4238       while(type.kind == classType &&
4239          type._class.registered && (type._class.registered.type == bitClass || type._class.registered.type == unitClass || type._class.registered.type == enumClass))
4240       {
4241          if(!type._class.registered.dataType)
4242             type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
4243          type = type._class.registered.dataType;
4244
4245       }
4246       if(exp.type == stringExp && op.kind == pointerType)
4247       {
4248          op.ui64 = (uint64)exp.string;
4249          op.kind = pointerType;
4250          op.ops = uint64Ops;
4251       }
4252       else if(exp.isConstant && exp.type == constantExp)
4253       {
4254          op.kind = type.kind;
4255          op.type = exp.expType;
4256
4257          switch(op.kind)
4258          {
4259             case _BoolType:
4260             case charType:
4261             {
4262                if(exp.constant[0] == '\'')
4263                {
4264                   op.c = exp.constant[1];
4265                   op.ops = charOps;
4266                }
4267                else if(type.isSigned)
4268                {
4269                   op.c = (char)strtol(exp.constant, null, 0);
4270                   op.ops = charOps;
4271                }
4272                else
4273                {
4274                   op.uc = (unsigned char)strtoul(exp.constant, null, 0);
4275                   op.ops = ucharOps;
4276                }
4277                break;
4278             }
4279             case shortType:
4280                if(type.isSigned)
4281                {
4282                   op.s = (short)strtol(exp.constant, null, 0);
4283                   op.ops = shortOps;
4284                }
4285                else
4286                {
4287                   op.us = (unsigned short)strtoul(exp.constant, null, 0);
4288                   op.ops = ushortOps;
4289                }
4290                break;
4291             case intType:
4292             case longType:
4293                if(type.isSigned)
4294                {
4295                   op.i = (int)strtol(exp.constant, null, 0);
4296                   op.ops = intOps;
4297                }
4298                else
4299                {
4300                   op.ui = (unsigned int)strtoul(exp.constant, null, 0);
4301                   op.ops = uintOps;
4302                }
4303                op.kind = intType;
4304                break;
4305             case int64Type:
4306                if(type.isSigned)
4307                {
4308                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4309                   op.ops = intOps;
4310                }
4311                else
4312                {
4313                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4314                   op.ops = uintOps;
4315                }
4316                op.kind = int64Type;
4317                break;
4318             case intPtrType:
4319                if(type.isSigned)
4320                {
4321                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4322                   op.ops = int64Ops;
4323                }
4324                else
4325                {
4326                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4327                   op.ops = uint64Ops;
4328                }
4329                op.kind = int64Type;
4330                break;
4331             case intSizeType:
4332                if(type.isSigned)
4333                {
4334                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4335                   op.ops = int64Ops;
4336                }
4337                else
4338                {
4339                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4340                   op.ops = uint64Ops;
4341                }
4342                op.kind = int64Type;
4343                break;
4344             case floatType:
4345                op.f = (float)strtod(exp.constant, null);
4346                op.ops = floatOps;
4347                break;
4348             case doubleType:
4349                op.d = (double)strtod(exp.constant, null);
4350                op.ops = doubleOps;
4351                break;
4352             //case classType:    For when we have operator overloading...
4353             // Pointer additions
4354             //case functionType:
4355             case arrayType:
4356             case pointerType:
4357             case classType:
4358                op.ui64 = _strtoui64(exp.constant, null, 0);
4359                op.kind = pointerType;
4360                op.ops = uint64Ops;
4361                // op.ptrSize =
4362                break;
4363          }
4364       }
4365    }
4366    return op;
4367 }
4368
4369 static void UnusedFunction()
4370 {
4371    int a;
4372    a.OnGetString(0,0,0);
4373 }
4374 default:
4375 extern int __ecereVMethodID_class_OnGetString;
4376 public:
4377
4378 static void PopulateInstanceProcessMember(Instantiation inst, OldList * memberList, DataMember parentDataMember, uint offset)
4379 {
4380    DataMember dataMember;
4381    for(dataMember = parentDataMember.members.first; dataMember; dataMember = dataMember.next)
4382    {
4383       if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4384          PopulateInstanceProcessMember(inst, memberList, dataMember, offset + dataMember.offset);
4385       else
4386       {
4387          Expression exp { };
4388          MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4389          Type type;
4390          void * ptr = inst.data + dataMember.offset + offset;
4391          char * result = null;
4392          exp.loc = member.loc = inst.loc;
4393          ((Identifier)member.identifiers->first).loc = inst.loc;
4394
4395          if(!dataMember.dataType)
4396             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4397          type = dataMember.dataType;
4398          if(type.kind == classType)
4399          {
4400             Class _class = type._class.registered;
4401             if(_class.type == enumClass)
4402             {
4403                Class enumClass = eSystem_FindClass(privateModule, "enum");
4404                if(enumClass)
4405                {
4406                   EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4407                   NamedLink item;
4408                   for(item = e.values.first; item; item = item.next)
4409                   {
4410                      if((int)item.data == *(int *)ptr)
4411                      {
4412                         result = item.name;
4413                         break;
4414                      }
4415                   }
4416                   if(result)
4417                   {
4418                      exp.identifier = MkIdentifier(result);
4419                      exp.type = identifierExp;
4420                      exp.destType = MkClassType(_class.fullName);
4421                      ProcessExpressionType(exp);
4422                   }
4423                }
4424             }
4425             if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4426             {
4427                if(!_class.dataType)
4428                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4429                type = _class.dataType;
4430             }
4431          }
4432          if(!result)
4433          {
4434             switch(type.kind)
4435             {
4436                case floatType:
4437                {
4438                   FreeExpContents(exp);
4439
4440                   exp.constant = PrintFloat(*(float*)ptr);
4441                   exp.type = constantExp;
4442                   break;
4443                }
4444                case doubleType:
4445                {
4446                   FreeExpContents(exp);
4447
4448                   exp.constant = PrintDouble(*(double*)ptr);
4449                   exp.type = constantExp;
4450                   break;
4451                }
4452                case intType:
4453                {
4454                   FreeExpContents(exp);
4455
4456                   exp.constant = PrintInt(*(int*)ptr);
4457                   exp.type = constantExp;
4458                   break;
4459                }
4460                case int64Type:
4461                {
4462                   FreeExpContents(exp);
4463
4464                   exp.constant = PrintInt64(*(int64*)ptr);
4465                   exp.type = constantExp;
4466                   break;
4467                }
4468                case intPtrType:
4469                {
4470                   FreeExpContents(exp);
4471                   // TODO: This should probably use proper type
4472                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4473                   exp.type = constantExp;
4474                   break;
4475                }
4476                case intSizeType:
4477                {
4478                   FreeExpContents(exp);
4479                   // TODO: This should probably use proper type
4480                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4481                   exp.type = constantExp;
4482                   break;
4483                }
4484                default:
4485                   Compiler_Error($"Unhandled type populating instance\n");
4486             }
4487          }
4488          ListAdd(memberList, member);
4489       }
4490
4491       if(parentDataMember.type == unionMember)
4492          break;
4493    }
4494 }
4495
4496 void PopulateInstance(Instantiation inst)
4497 {
4498    Symbol classSym = inst._class.symbol; // FindClass(inst._class.name);
4499    Class _class = classSym.registered;
4500    DataMember dataMember;
4501    OldList * memberList = MkList();
4502    // Added this check and ->Add to prevent memory leaks on bad code
4503    if(!inst.members)
4504       inst.members = MkListOne(MkMembersInitList(memberList));
4505    else
4506       inst.members->Add(MkMembersInitList(memberList));
4507    for(dataMember = _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
4508    {
4509       if(!dataMember.isProperty)
4510       {
4511          if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4512             PopulateInstanceProcessMember(inst, memberList, dataMember, dataMember.offset);
4513          else
4514          {
4515             Expression exp { };
4516             MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4517             Type type;
4518             void * ptr = inst.data + dataMember.offset;
4519             char * result = null;
4520
4521             exp.loc = member.loc = inst.loc;
4522             ((Identifier)member.identifiers->first).loc = inst.loc;
4523
4524             if(!dataMember.dataType)
4525                dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4526             type = dataMember.dataType;
4527             if(type.kind == classType)
4528             {
4529                Class _class = type._class.registered;
4530                if(_class.type == enumClass)
4531                {
4532                   Class enumClass = eSystem_FindClass(privateModule, "enum");
4533                   if(enumClass)
4534                   {
4535                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4536                      NamedLink item;
4537                      for(item = e.values.first; item; item = item.next)
4538                      {
4539                         if((int)item.data == *(int *)ptr)
4540                         {
4541                            result = item.name;
4542                            break;
4543                         }
4544                      }
4545                   }
4546                   if(result)
4547                   {
4548                      exp.identifier = MkIdentifier(result);
4549                      exp.type = identifierExp;
4550                      exp.destType = MkClassType(_class.fullName);
4551                      ProcessExpressionType(exp);
4552                   }
4553                }
4554                if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4555                {
4556                   if(!_class.dataType)
4557                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4558                   type = _class.dataType;
4559                }
4560             }
4561             if(!result)
4562             {
4563                switch(type.kind)
4564                {
4565                   case floatType:
4566                   {
4567                      exp.constant = PrintFloat(*(float*)ptr);
4568                      exp.type = constantExp;
4569                      break;
4570                   }
4571                   case doubleType:
4572                   {
4573                      exp.constant = PrintDouble(*(double*)ptr);
4574                      exp.type = constantExp;
4575                      break;
4576                   }
4577                   case intType:
4578                   {
4579                      exp.constant = PrintInt(*(int*)ptr);
4580                      exp.type = constantExp;
4581                      break;
4582                   }
4583                   case int64Type:
4584                   {
4585                      exp.constant = PrintInt64(*(int64*)ptr);
4586                      exp.type = constantExp;
4587                      break;
4588                   }
4589                   case intPtrType:
4590                   {
4591                      exp.constant = PrintInt64((int64)*(intptr*)ptr);
4592                      exp.type = constantExp;
4593                      break;
4594                   }
4595                   default:
4596                      Compiler_Error($"Unhandled type populating instance\n");
4597                }
4598             }
4599             ListAdd(memberList, member);
4600          }
4601       }
4602    }
4603 }
4604
4605 void ComputeInstantiation(Expression exp)
4606 {
4607    Instantiation inst = exp.instance;
4608    MembersInit members;
4609    Symbol classSym = inst._class ? inst._class.symbol : null; // FindClass(inst._class.name);
4610    Class _class = classSym ? classSym.registered : null;
4611    DataMember curMember = null;
4612    Class curClass = null;
4613    DataMember subMemberStack[256];
4614    int subMemberStackPos = 0;
4615    uint64 bits = 0;
4616
4617    if(_class && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass ))
4618    {
4619       // Don't recompute the instantiation...
4620       // Non Simple classes will have become constants by now
4621       if(inst.data)
4622          return;
4623
4624       if(_class.type == normalClass || _class.type == noHeadClass)
4625       {
4626          inst.data = (byte *)eInstance_New(_class);
4627          if(_class.type == normalClass)
4628             ((Instance)inst.data)._refCount++;
4629       }
4630       else
4631          inst.data = new0 byte[_class.structSize];
4632    }
4633
4634    if(inst.members)
4635    {
4636       for(members = inst.members->first; members; members = members.next)
4637       {
4638          switch(members.type)
4639          {
4640             case dataMembersInit:
4641             {
4642                if(members.dataMembers)
4643                {
4644                   MemberInit member;
4645                   for(member = members.dataMembers->first; member; member = member.next)
4646                   {
4647                      Identifier ident = member.identifiers ? member.identifiers->first : null;
4648                      bool found = false;
4649
4650                      Property prop = null;
4651                      DataMember dataMember = null;
4652                      Method method = null;
4653                      uint dataMemberOffset;
4654
4655                      if(!ident)
4656                      {
4657                         eClass_FindNextMember(_class, &curClass, &curMember, subMemberStack, &subMemberStackPos);
4658                         if(curMember)
4659                         {
4660                            if(curMember.isProperty)
4661                               prop = (Property)curMember;
4662                            else
4663                            {
4664                               dataMember = curMember;
4665
4666                               // CHANGED THIS HERE
4667                               eClass_FindDataMemberAndOffset(_class, dataMember.name, &dataMemberOffset, privateModule, null, null);
4668
4669                               // 2013/17/29 -- It seems that this was missing here!
4670                               if(_class.type == normalClass)
4671                                  dataMemberOffset += _class.base.structSize;
4672                               // dataMemberOffset = dataMember.offset;
4673                            }
4674                            found = true;
4675                         }
4676                      }
4677                      else
4678                      {
4679                         prop = eClass_FindProperty(_class, ident.string, privateModule);
4680                         if(prop)
4681                         {
4682                            found = true;
4683                            if(prop.memberAccess == publicAccess)
4684                            {
4685                               curMember = (DataMember)prop;
4686                               curClass = prop._class;
4687                            }
4688                         }
4689                         else
4690                         {
4691                            DataMember _subMemberStack[256];
4692                            int _subMemberStackPos = 0;
4693
4694                            // FILL MEMBER STACK
4695                            dataMember = eClass_FindDataMemberAndOffset(_class, ident.string, &dataMemberOffset, privateModule, _subMemberStack, &_subMemberStackPos);
4696
4697                            if(dataMember)
4698                            {
4699                               found = true;
4700                               if(dataMember.memberAccess == publicAccess)
4701                               {
4702                                  curMember = dataMember;
4703                                  curClass = dataMember._class;
4704                                  memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
4705                                  subMemberStackPos = _subMemberStackPos;
4706                               }
4707                            }
4708                         }
4709                      }
4710
4711                      if(found && member.initializer && member.initializer.type == expInitializer)
4712                      {
4713                         Expression value = member.initializer.exp;
4714                         Type type = null;
4715                         bool deepMember = false;
4716                         if(prop)
4717                         {
4718                            type = prop.dataType;
4719                         }
4720                         else if(dataMember)
4721                         {
4722                            if(!dataMember.dataType)
4723                               dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4724
4725                            type = dataMember.dataType;
4726                         }
4727
4728                         if(ident && ident.next)
4729                         {
4730                            deepMember = true;
4731
4732                            // for(; ident && type; ident = ident.next)
4733                            for(ident = ident.next; ident && type; ident = ident.next)
4734                            {
4735                               if(type.kind == classType)
4736                               {
4737                                  prop = eClass_FindProperty(type._class.registered,
4738                                     ident.string, privateModule);
4739                                  if(prop)
4740                                     type = prop.dataType;
4741                                  else
4742                                  {
4743                                     dataMember = eClass_FindDataMemberAndOffset(type._class.registered,
4744                                        ident.string, &dataMemberOffset, privateModule, null, null);
4745                                     if(dataMember)
4746                                        type = dataMember.dataType;
4747                                  }
4748                               }
4749                               else if(type.kind == structType || type.kind == unionType)
4750                               {
4751                                  Type memberType;
4752                                  for(memberType = type.members.first; memberType; memberType = memberType.next)
4753                                  {
4754                                     if(!strcmp(memberType.name, ident.string))
4755                                     {
4756                                        type = memberType;
4757                                        break;
4758                                     }
4759                                  }
4760                               }
4761                            }
4762                         }
4763                         if(value)
4764                         {
4765                            FreeType(value.destType);
4766                            value.destType = type;
4767                            if(type) type.refCount++;
4768                            ComputeExpression(value);
4769                         }
4770                         if(!deepMember && type && value && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass /*&& value.expType.kind == type.kind*/))
4771                         {
4772                            if(type.kind == classType)
4773                            {
4774                               Class _class = type._class.registered;
4775                               if(_class.type == bitClass || _class.type == unitClass ||
4776                                  _class.type == enumClass)
4777                               {
4778                                  if(!_class.dataType)
4779                                     _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4780                                  type = _class.dataType;
4781                               }
4782                            }
4783
4784                            if(dataMember)
4785                            {
4786                               void * ptr = inst.data + dataMemberOffset;
4787
4788                               if(value.type == constantExp)
4789                               {
4790                                  switch(type.kind)
4791                                  {
4792                                     case intType:
4793                                     {
4794                                        GetInt(value, (int*)ptr);
4795                                        break;
4796                                     }
4797                                     case int64Type:
4798                                     {
4799                                        GetInt64(value, (int64*)ptr);
4800                                        break;
4801                                     }
4802                                     case intPtrType:
4803                                     {
4804                                        GetIntPtr(value, (intptr*)ptr);
4805                                        break;
4806                                     }
4807                                     case intSizeType:
4808                                     {
4809                                        GetIntSize(value, (intsize*)ptr);
4810                                        break;
4811                                     }
4812                                     case floatType:
4813                                     {
4814                                        GetFloat(value, (float*)ptr);
4815                                        break;
4816                                     }
4817                                     case doubleType:
4818                                     {
4819                                        GetDouble(value, (double *)ptr);
4820                                        break;
4821                                     }
4822                                  }
4823                               }
4824                               else if(value.type == instanceExp)
4825                               {
4826                                  if(type.kind == classType)
4827                                  {
4828                                     Class _class = type._class.registered;
4829                                     if(_class.type == structClass)
4830                                     {
4831                                        ComputeTypeSize(type);
4832                                        if(value.instance.data)
4833                                           memcpy(ptr, value.instance.data, type.size);
4834                                     }
4835                                  }
4836                               }
4837                            }
4838                            else if(prop)
4839                            {
4840                               if(value.type == instanceExp && value.instance.data)
4841                               {
4842                                  if(type.kind == classType)
4843                                  {
4844                                     Class _class = type._class.registered;
4845                                     if(_class && (_class.type != normalClass || eClass_IsDerived(((Instance)value.instance.data)._class, _class)))
4846                                     {
4847                                        void (*Set)(void *, void *) = (void *)prop.Set;
4848                                        Set(inst.data, value.instance.data);
4849                                        PopulateInstance(inst);
4850                                     }
4851                                  }
4852                               }
4853                               else if(value.type == constantExp)
4854                               {
4855                                  switch(type.kind)
4856                                  {
4857                                     case doubleType:
4858                                     {
4859                                        void (*Set)(void *, double) = (void *)prop.Set;
4860                                        Set(inst.data, strtod(value.constant, null) );
4861                                        break;
4862                                     }
4863                                     case floatType:
4864                                     {
4865                                        void (*Set)(void *, float) = (void *)prop.Set;
4866                                        Set(inst.data, (float)(strtod(value.constant, null)));
4867                                        break;
4868                                     }
4869                                     case intType:
4870                                     {
4871                                        void (*Set)(void *, int) = (void *)prop.Set;
4872                                        Set(inst.data, (int)strtol(value.constant, null, 0));
4873                                        break;
4874                                     }
4875                                     case int64Type:
4876                                     {
4877                                        void (*Set)(void *, int64) = (void *)prop.Set;
4878                                        Set(inst.data, _strtoi64(value.constant, null, 0));
4879                                        break;
4880                                     }
4881                                     case intPtrType:
4882                                     {
4883                                        void (*Set)(void *, intptr) = (void *)prop.Set;
4884                                        Set(inst.data, (intptr)_strtoi64(value.constant, null, 0));
4885                                        break;
4886                                     }
4887                                     case intSizeType:
4888                                     {
4889                                        void (*Set)(void *, intsize) = (void *)prop.Set;
4890                                        Set(inst.data, (intsize)_strtoi64(value.constant, null, 0));
4891                                        break;
4892                                     }
4893                                  }
4894                               }
4895                               else if(value.type == stringExp)
4896                               {
4897                                  char temp[1024];
4898                                  ReadString(temp, value.string);
4899                                  ((void (*)(void *, void *))(void *)prop.Set)(inst.data, temp);
4900                               }
4901                            }
4902                         }
4903                         else if(!deepMember && type && _class.type == unitClass)
4904                         {
4905                            if(prop)
4906                            {
4907                               // Only support converting units to units for now...
4908                               if(value.type == constantExp)
4909                               {
4910                                  if(type.kind == classType)
4911                                  {
4912                                     Class _class = type._class.registered;
4913                                     if(_class.type == unitClass)
4914                                     {
4915                                        if(!_class.dataType)
4916                                           _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4917                                        type = _class.dataType;
4918                                     }
4919                                  }
4920                                  // TODO: Assuming same base type for units...
4921                                  switch(type.kind)
4922                                  {
4923                                     case floatType:
4924                                     {
4925                                        float fValue;
4926                                        float (*Set)(float) = (void *)prop.Set;
4927                                        GetFloat(member.initializer.exp, &fValue);
4928                                        exp.constant = PrintFloat(Set(fValue));
4929                                        exp.type = constantExp;
4930                                        break;
4931                                     }
4932                                     case doubleType:
4933                                     {
4934                                        double dValue;
4935                                        double (*Set)(double) = (void *)prop.Set;
4936                                        GetDouble(member.initializer.exp, &dValue);
4937                                        exp.constant = PrintDouble(Set(dValue));
4938                                        exp.type = constantExp;
4939                                        break;
4940                                     }
4941                                  }
4942                               }
4943                            }
4944                         }
4945                         else if(!deepMember && type && _class.type == bitClass)
4946                         {
4947                            if(prop)
4948                            {
4949                               if(value.type == instanceExp && value.instance.data)
4950                               {
4951                                  unsigned int (*Set)(void *) = (void *)prop.Set;
4952                                  bits = Set(value.instance.data);
4953                               }
4954                               else if(value.type == constantExp)
4955                               {
4956                               }
4957                            }
4958                            else if(dataMember)
4959                            {
4960                               BitMember bitMember = (BitMember) dataMember;
4961                               Type type;
4962                               int part = 0;
4963                               GetInt(value, &part);
4964                               bits = (bits & ~bitMember.mask);
4965                               if(!bitMember.dataType)
4966                                  bitMember.dataType = ProcessTypeString(bitMember.dataTypeString, false);
4967
4968                               type = bitMember.dataType;
4969
4970                               if(type.kind == classType && type._class && type._class.registered)
4971                               {
4972                                  if(!type._class.registered.dataType)
4973                                     type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
4974                                  type = type._class.registered.dataType;
4975                               }
4976
4977                               switch(type.kind)
4978                               {
4979                                  case _BoolType:
4980                                  case charType:
4981                                     if(type.isSigned)
4982                                        bits |= ((char)part << bitMember.pos);
4983                                     else
4984                                        bits |= ((unsigned char)part << bitMember.pos);
4985                                     break;
4986                                  case shortType:
4987                                     if(type.isSigned)
4988                                        bits |= ((short)part << bitMember.pos);
4989                                     else
4990                                        bits |= ((unsigned short)part << bitMember.pos);
4991                                     break;
4992                                  case intType:
4993                                  case longType:
4994                                     if(type.isSigned)
4995                                        bits |= ((int)part << bitMember.pos);
4996                                     else
4997                                        bits |= ((unsigned int)part << bitMember.pos);
4998                                     break;
4999                                  case int64Type:
5000                                     if(type.isSigned)
5001                                        bits |= ((int64)part << bitMember.pos);
5002                                     else
5003                                        bits |= ((uint64)part << bitMember.pos);
5004                                     break;
5005                                  case intPtrType:
5006                                     if(type.isSigned)
5007                                     {
5008                                        bits |= ((intptr)part << bitMember.pos);
5009                                     }
5010                                     else
5011                                     {
5012                                        bits |= ((uintptr)part << bitMember.pos);
5013                                     }
5014                                     break;
5015                                  case intSizeType:
5016                                     if(type.isSigned)
5017                                     {
5018                                        bits |= ((ssize_t)(intsize)part << bitMember.pos);
5019                                     }
5020                                     else
5021                                     {
5022                                        bits |= ((size_t) (uintsize)part << bitMember.pos);
5023                                     }
5024                                     break;
5025                               }
5026                            }
5027                         }
5028                      }
5029                      else
5030                      {
5031                         if(_class && _class.type == unitClass)
5032                         {
5033                            ComputeExpression(member.initializer.exp);
5034                            exp.constant = member.initializer.exp.constant;
5035                            exp.type = constantExp;
5036
5037                            member.initializer.exp.constant = null;
5038                         }
5039                      }
5040                   }
5041                }
5042                break;
5043             }
5044          }
5045       }
5046    }
5047    if(_class && _class.type == bitClass)
5048    {
5049       exp.constant = PrintHexUInt(bits);
5050       exp.type = constantExp;
5051    }
5052    if(exp.type != instanceExp)
5053    {
5054       FreeInstance(inst);
5055    }
5056 }
5057
5058 static bool Promote(Operand op, TypeKind kind, bool isSigned)
5059 {
5060    bool result = false;
5061    switch(kind)
5062    {
5063       case shortType:
5064          if(op.kind == charType || op.kind == enumType || op.kind == _BoolType)
5065             result = isSigned ? GetOpShort(op, &op.s) : GetOpUShort(op, &op.us);
5066          break;
5067       case intType:
5068       case longType:
5069          if(op.kind == charType || op.kind == shortType || op.kind == enumType || op.kind == _BoolType)
5070             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5071          break;
5072       case int64Type:
5073          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5074             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5075          result = isSigned ? GetOpInt64(op, &op.i64) : GetOpUInt64(op, &op.ui64);
5076          break;
5077       case floatType:
5078          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType ||
5079             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5080          result = GetOpFloat(op, &op.f);
5081          break;
5082       case doubleType:
5083          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType ||
5084             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5085          result = GetOpDouble(op, &op.d);
5086          break;
5087       case pointerType:
5088          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5089             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5090             result = GetOpUIntPtr(op, &op.ui64);
5091          break;
5092       case enumType:
5093          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5094             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5095             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5096          break;
5097       case intPtrType:
5098          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5099             result = isSigned ? GetOpIntPtr(op, &op.i64) : GetOpUIntPtr(op, &op.i64);
5100          break;
5101       case intSizeType:
5102          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5103             result = isSigned ? GetOpIntSize(op, &op.ui64) : GetOpUIntSize(op, &op.ui64);
5104          break;
5105    }
5106    return result;
5107 }
5108
5109 void CallOperator(Expression exp, Expression exp1, Expression exp2, Operand op1, Operand op2)
5110 {
5111    if(exp.op.op == SIZEOF)
5112    {
5113       FreeExpContents(exp);
5114       exp.type = constantExp;
5115       exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5116    }
5117    else
5118    {
5119       if(!exp.op.exp1)
5120       {
5121          switch(exp.op.op)
5122          {
5123             // unary arithmetic
5124             case '+':
5125             {
5126                // Provide default unary +
5127                Expression exp2 = exp.op.exp2;
5128                exp.op.exp2 = null;
5129                FreeExpContents(exp);
5130                FreeType(exp.expType);
5131                FreeType(exp.destType);
5132                *exp = *exp2;
5133                delete exp2;
5134                break;
5135             }
5136             case '-':
5137                if(op1.ops.Neg) { FreeExpContents(exp); op1.ops.Neg(exp, op1); }
5138                break;
5139             // unary arithmetic increment and decrement
5140                   //OPERATOR_ALL(UNARY, ++, Inc)
5141                   //OPERATOR_ALL(UNARY, --, Dec)
5142             // unary bitwise
5143             case '~':
5144                if(op1.ops.BitNot) { FreeExpContents(exp); op1.ops.BitNot(exp, op1); }
5145                break;
5146             // unary logical negation
5147             case '!':
5148                if(op1.ops.Not) { FreeExpContents(exp); op1.ops.Not(exp, op1); }
5149                break;
5150          }
5151       }
5152       else
5153       {
5154          if(op1 && op2 && op1.type && op2.type && op1.kind != op2.kind)
5155          {
5156             if(Promote(op2, op1.kind, op1.type.isSigned))
5157                op2.kind = op1.kind, op2.ops = op1.ops;
5158             else if(Promote(op1, op2.kind, op2.type.isSigned))
5159                op1.kind = op2.kind, op1.ops = op2.ops;
5160          }
5161          switch(exp.op.op)
5162          {
5163             // binary arithmetic
5164             case '+':
5165                if(op1.ops.Add) { FreeExpContents(exp); op1.ops.Add(exp, op1, op2); }
5166                break;
5167             case '-':
5168                if(op1.ops.Sub) { FreeExpContents(exp); op1.ops.Sub(exp, op1, op2); }
5169                break;
5170             case '*':
5171                if(op1.ops.Mul) { FreeExpContents(exp); op1.ops.Mul(exp, op1, op2); }
5172                break;
5173             case '/':
5174                if(op1.ops.Div) { FreeExpContents(exp); op1.ops.Div(exp, op1, op2); }
5175                break;
5176             case '%':
5177                if(op1.ops.Mod) { FreeExpContents(exp); op1.ops.Mod(exp, op1, op2); }
5178                break;
5179             // binary arithmetic assignment
5180                   //OPERATOR_ALL(BINARY, =, Asign)
5181                   //OPERATOR_ALL(BINARY, +=, AddAsign)
5182                   //OPERATOR_ALL(BINARY, -=, SubAsign)
5183                   //OPERATOR_ALL(BINARY, *=, MulAsign)
5184                   //OPERATOR_ALL(BINARY, /=, DivAsign)
5185                   //OPERATOR_ALL(BINARY, %=, ModAsign)
5186             // binary bitwise
5187             case '&':
5188                if(exp.op.exp2)
5189                {
5190                   if(op1.ops.BitAnd) { FreeExpContents(exp); op1.ops.BitAnd(exp, op1, op2); }
5191                }
5192                break;
5193             case '|':
5194                if(op1.ops.BitOr) { FreeExpContents(exp); op1.ops.BitOr(exp, op1, op2); }
5195                break;
5196             case '^':
5197                if(op1.ops.BitXor) { FreeExpContents(exp); op1.ops.BitXor(exp, op1, op2); }
5198                break;
5199             case LEFT_OP:
5200                if(op1.ops.LShift) { FreeExpContents(exp); op1.ops.LShift(exp, op1, op2); }
5201                break;
5202             case RIGHT_OP:
5203                if(op1.ops.RShift) { FreeExpContents(exp); op1.ops.RShift(exp, op1, op2); }
5204                break;
5205             // binary bitwise assignment
5206                   //OPERATOR_INTTYPES(BINARY, &=, AndAsign)
5207                   //OPERATOR_INTTYPES(BINARY, |=, OrAsign)
5208                   //OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
5209                   //OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
5210                   //OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
5211             // binary logical equality
5212             case EQ_OP:
5213                if(op1.ops.Equ) { FreeExpContents(exp); op1.ops.Equ(exp, op1, op2); }
5214                break;
5215             case NE_OP:
5216                if(op1.ops.Nqu) { FreeExpContents(exp); op1.ops.Nqu(exp, op1, op2); }
5217                break;
5218             // binary logical
5219             case AND_OP:
5220                if(op1.ops.And) { FreeExpContents(exp); op1.ops.And(exp, op1, op2); }
5221                break;
5222             case OR_OP:
5223                if(op1.ops.Or) { FreeExpContents(exp); op1.ops.Or(exp, op1, op2); }
5224                break;
5225             // binary logical relational
5226             case '>':
5227                if(op1.ops.Grt) { FreeExpContents(exp); op1.ops.Grt(exp, op1, op2); }
5228                break;
5229             case '<':
5230                if(op1.ops.Sma) { FreeExpContents(exp); op1.ops.Sma(exp, op1, op2); }
5231                break;
5232             case GE_OP:
5233                if(op1.ops.GrtEqu) { FreeExpContents(exp); op1.ops.GrtEqu(exp, op1, op2); }
5234                break;
5235             case LE_OP:
5236                if(op1.ops.SmaEqu) { FreeExpContents(exp); op1.ops.SmaEqu(exp, op1, op2); }
5237                break;
5238          }
5239       }
5240    }
5241 }
5242
5243 void ComputeExpression(Expression exp)
5244 {
5245    char expString[10240];
5246    expString[0] = '\0';
5247 #ifdef _DEBUG
5248    PrintExpression(exp, expString);
5249 #endif
5250
5251    switch(exp.type)
5252    {
5253       case instanceExp:
5254       {
5255          ComputeInstantiation(exp);
5256          break;
5257       }
5258       /*
5259       case constantExp:
5260          break;
5261       */
5262       case opExp:
5263       {
5264          Expression exp1, exp2 = null;
5265          Operand op1 { };
5266          Operand op2 { };
5267
5268          // We don't care about operations with only exp2 (INC_OP, DEC_OP...)
5269          if(exp.op.exp2)
5270          {
5271             Expression e = exp.op.exp2;
5272
5273             while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
5274             {
5275                if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
5276                {
5277                   if(e.type == extensionCompoundExp)
5278                      e = ((Statement)e.compound.compound.statements->last).expressions->last;
5279                   else
5280                      e = e.list->last;
5281                }
5282             }
5283             if(exp.op.op == TokenType::sizeOf && e && e.expType)
5284             {
5285                if(e.type == stringExp && e.string)
5286                {
5287                   char * string = e.string;
5288                   int len = strlen(string);
5289                   char * tmp = new char[len-2+1];
5290                   len = UnescapeString(tmp, string + 1, len - 2);
5291                   delete tmp;
5292                   FreeExpContents(exp);
5293                   exp.type = constantExp;
5294                   exp.constant = PrintUInt(len + 1);
5295                }
5296                else
5297                {
5298                   Type type = e.expType;
5299                   type.refCount++;
5300                   FreeExpContents(exp);
5301                   exp.type = constantExp;
5302                   exp.constant = PrintUInt(ComputeTypeSize(type));
5303                   FreeType(type);
5304                }
5305                break;
5306             }
5307             else
5308                ComputeExpression(exp.op.exp2);
5309          }
5310          if(exp.op.exp1)
5311          {
5312             ComputeExpression(exp.op.exp1);
5313             exp1 = exp.op.exp1;
5314             exp2 = exp.op.exp2;
5315             op1 = GetOperand(exp1);
5316             if(op1.type) op1.type.refCount++;
5317             if(exp2)
5318             {
5319                op2 = GetOperand(exp2);
5320                if(op2.type) op2.type.refCount++;
5321             }
5322          }
5323          else
5324          {
5325             exp1 = exp.op.exp2;
5326             op1 = GetOperand(exp1);
5327             if(op1.type) op1.type.refCount++;
5328          }
5329
5330          CallOperator(exp, exp1, exp2, op1, op2);
5331          /*
5332          switch(exp.op.op)
5333          {
5334             // Unary operators
5335             case '&':
5336                // Also binary
5337                if(exp.op.exp1 && exp.op.exp2)
5338                {
5339                   // Binary And
5340                   if(op1.ops.BitAnd)
5341                   {
5342                      FreeExpContents(exp);
5343                      op1.ops.BitAnd(exp, op1, op2);
5344                   }
5345                }
5346                break;
5347             case '*':
5348                if(exp.op.exp1)
5349                {
5350                   if(op1.ops.Mul)
5351                   {
5352                      FreeExpContents(exp);
5353                      op1.ops.Mul(exp, op1, op2);
5354                   }
5355                }
5356                break;
5357             case '+':
5358                if(exp.op.exp1)
5359                {
5360                   if(op1.ops.Add)
5361                   {
5362                      FreeExpContents(exp);
5363                      op1.ops.Add(exp, op1, op2);
5364                   }
5365                }
5366                else
5367                {
5368                   // Provide default unary +
5369                   Expression exp2 = exp.op.exp2;
5370                   exp.op.exp2 = null;
5371                   FreeExpContents(exp);
5372                   FreeType(exp.expType);
5373                   FreeType(exp.destType);
5374
5375                   *exp = *exp2;
5376                   delete exp2;
5377                }
5378                break;
5379             case '-':
5380                if(exp.op.exp1)
5381                {
5382                   if(op1.ops.Sub)
5383                   {
5384                      FreeExpContents(exp);
5385                      op1.ops.Sub(exp, op1, op2);
5386                   }
5387                }
5388                else
5389                {
5390                   if(op1.ops.Neg)
5391                   {
5392                      FreeExpContents(exp);
5393                      op1.ops.Neg(exp, op1);
5394                   }
5395                }
5396                break;
5397             case '~':
5398                if(op1.ops.BitNot)
5399                {
5400                   FreeExpContents(exp);
5401                   op1.ops.BitNot(exp, op1);
5402                }
5403                break;
5404             case '!':
5405                if(op1.ops.Not)
5406                {
5407                   FreeExpContents(exp);
5408                   op1.ops.Not(exp, op1);
5409                }
5410                break;
5411             // Binary only operators
5412             case '/':
5413                if(op1.ops.Div)
5414                {
5415                   FreeExpContents(exp);
5416                   op1.ops.Div(exp, op1, op2);
5417                }
5418                break;
5419             case '%':
5420                if(op1.ops.Mod)
5421                {
5422                   FreeExpContents(exp);
5423                   op1.ops.Mod(exp, op1, op2);
5424                }
5425                break;
5426             case LEFT_OP:
5427                break;
5428             case RIGHT_OP:
5429                break;
5430             case '<':
5431                if(exp.op.exp1)
5432                {
5433                   if(op1.ops.Sma)
5434                   {
5435                      FreeExpContents(exp);
5436                      op1.ops.Sma(exp, op1, op2);
5437                   }
5438                }
5439                break;
5440             case '>':
5441                if(exp.op.exp1)
5442                {
5443                   if(op1.ops.Grt)
5444                   {
5445                      FreeExpContents(exp);
5446                      op1.ops.Grt(exp, op1, op2);
5447                   }
5448                }
5449                break;
5450             case LE_OP:
5451                if(exp.op.exp1)
5452                {
5453                   if(op1.ops.SmaEqu)
5454                   {
5455                      FreeExpContents(exp);
5456                      op1.ops.SmaEqu(exp, op1, op2);
5457                   }
5458                }
5459                break;
5460             case GE_OP:
5461                if(exp.op.exp1)
5462                {
5463                   if(op1.ops.GrtEqu)
5464                   {
5465                      FreeExpContents(exp);
5466                      op1.ops.GrtEqu(exp, op1, op2);
5467                   }
5468                }
5469                break;
5470             case EQ_OP:
5471                if(exp.op.exp1)
5472                {
5473                   if(op1.ops.Equ)
5474                   {
5475                      FreeExpContents(exp);
5476                      op1.ops.Equ(exp, op1, op2);
5477                   }
5478                }
5479                break;
5480             case NE_OP:
5481                if(exp.op.exp1)
5482                {
5483                   if(op1.ops.Nqu)
5484                   {
5485                      FreeExpContents(exp);
5486                      op1.ops.Nqu(exp, op1, op2);
5487                   }
5488                }
5489                break;
5490             case '|':
5491                if(op1.ops.BitOr)
5492                {
5493                   FreeExpContents(exp);
5494                   op1.ops.BitOr(exp, op1, op2);
5495                }
5496                break;
5497             case '^':
5498                if(op1.ops.BitXor)
5499                {
5500                   FreeExpContents(exp);
5501                   op1.ops.BitXor(exp, op1, op2);
5502                }
5503                break;
5504             case AND_OP:
5505                break;
5506             case OR_OP:
5507                break;
5508             case SIZEOF:
5509                FreeExpContents(exp);
5510                exp.type = constantExp;
5511                exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5512                break;
5513          }
5514          */
5515          if(op1.type) FreeType(op1.type);
5516          if(op2.type) FreeType(op2.type);
5517          break;
5518       }
5519       case bracketsExp:
5520       case extensionExpressionExp:
5521       {
5522          Expression e, n;
5523          for(e = exp.list->first; e; e = n)
5524          {
5525             n = e.next;
5526             if(!n)
5527             {
5528                OldList * list = exp.list;
5529                ComputeExpression(e);
5530                //FreeExpContents(exp);
5531                FreeType(exp.expType);
5532                FreeType(exp.destType);
5533                *exp = *e;
5534                delete e;
5535                delete list;
5536             }
5537             else
5538             {
5539                FreeExpression(e);
5540             }
5541          }
5542          break;
5543       }
5544       /*
5545
5546       case ExpIndex:
5547       {
5548          Expression e;
5549          exp.isConstant = true;
5550
5551          ComputeExpression(exp.index.exp);
5552          if(!exp.index.exp.isConstant)
5553             exp.isConstant = false;
5554
5555          for(e = exp.index.index->first; e; e = e.next)
5556          {
5557             ComputeExpression(e);
5558             if(!e.next)
5559             {
5560                // Check if this type is int
5561             }
5562             if(!e.isConstant)
5563                exp.isConstant = false;
5564          }
5565          exp.expType = Dereference(exp.index.exp.expType);
5566          break;
5567       }
5568       */
5569       case memberExp:
5570       {
5571          Expression memberExp = exp.member.exp;
5572          Identifier memberID = exp.member.member;
5573
5574          Type type;
5575          ComputeExpression(exp.member.exp);
5576          type = exp.member.exp.expType;
5577          if(type)
5578          {
5579             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);
5580             Property prop = null;
5581             DataMember member = null;
5582             Class convertTo = null;
5583             if(type.kind == subClassType && exp.member.exp.type == classExp)
5584                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
5585
5586             if(!_class)
5587             {
5588                char string[256];
5589                Symbol classSym;
5590                string[0] = '\0';
5591                PrintTypeNoConst(type, string, false, true);
5592                classSym = FindClass(string);
5593                _class = classSym ? classSym.registered : null;
5594             }
5595
5596             if(exp.member.member)
5597             {
5598                prop = eClass_FindProperty(_class, exp.member.member.string, privateModule);
5599                if(!prop)
5600                   member = eClass_FindDataMember(_class, exp.member.member.string, privateModule, null, null);
5601             }
5602             if(!prop && !member && _class && exp.member.member)
5603             {
5604                Symbol classSym = FindClass(exp.member.member.string);
5605                convertTo = _class;
5606                _class = classSym ? classSym.registered : null;
5607                prop = eClass_FindProperty(_class, convertTo.fullName, privateModule);
5608             }
5609
5610             if(prop)
5611             {
5612                if(prop.compiled)
5613                {
5614                   Type type = prop.dataType;
5615                   // TODO: Assuming same base type for units...
5616                   if(_class.type == unitClass)
5617                   {
5618                      if(type.kind == classType)
5619                      {
5620                         Class _class = type._class.registered;
5621                         if(_class.type == unitClass)
5622                         {
5623                            if(!_class.dataType)
5624                               _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5625                            type = _class.dataType;
5626                         }
5627                      }
5628                      switch(type.kind)
5629                      {
5630                         case floatType:
5631                         {
5632                            float value;
5633                            float (*Get)(float) = (void *)prop.Get;
5634                            GetFloat(exp.member.exp, &value);
5635                            exp.constant = PrintFloat(Get ? Get(value) : value);
5636                            exp.type = constantExp;
5637                            break;
5638                         }
5639                         case doubleType:
5640                         {
5641                            double value;
5642                            double (*Get)(double);
5643                            GetDouble(exp.member.exp, &value);
5644
5645                            if(convertTo)
5646                               Get = (void *)prop.Set;
5647                            else
5648                               Get = (void *)prop.Get;
5649                            exp.constant = PrintDouble(Get ? Get(value) : value);
5650                            exp.type = constantExp;
5651                            break;
5652                         }
5653                      }
5654                   }
5655                   else
5656                   {
5657                      if(convertTo)
5658                      {
5659                         Expression value = exp.member.exp;
5660                         Type type;
5661                         if(!prop.dataType)
5662                            ProcessPropertyType(prop);
5663
5664                         type = prop.dataType;
5665                         if(!type)
5666                         {
5667                             // printf("Investigate this\n");
5668                         }
5669                         else if(_class.type == structClass)
5670                         {
5671                            switch(type.kind)
5672                            {
5673                               case classType:
5674                               {
5675                                  Class propertyClass = type._class.registered;
5676                                  if(propertyClass.type == structClass && value.type == instanceExp)
5677                                  {
5678                                     void (*Set)(void *, void *) = (void *)prop.Set;
5679                                     exp.instance = Instantiation { };
5680                                     exp.instance.data = new0 byte[_class.structSize];
5681                                     exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5682                                     exp.instance.loc = exp.loc;
5683                                     exp.type = instanceExp;
5684                                     Set(exp.instance.data, value.instance.data);
5685                                     PopulateInstance(exp.instance);
5686                                  }
5687                                  break;
5688                               }
5689                               case intType:
5690                               {
5691                                  int intValue;
5692                                  void (*Set)(void *, int) = (void *)prop.Set;
5693
5694                                  exp.instance = Instantiation { };
5695                                  exp.instance.data = new0 byte[_class.structSize];
5696                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5697                                  exp.instance.loc = exp.loc;
5698                                  exp.type = instanceExp;
5699
5700                                  GetInt(value, &intValue);
5701
5702                                  Set(exp.instance.data, intValue);
5703                                  PopulateInstance(exp.instance);
5704                                  break;
5705                               }
5706                               case int64Type:
5707                               {
5708                                  int64 intValue;
5709                                  void (*Set)(void *, int64) = (void *)prop.Set;
5710
5711                                  exp.instance = Instantiation { };
5712                                  exp.instance.data = new0 byte[_class.structSize];
5713                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5714                                  exp.instance.loc = exp.loc;
5715                                  exp.type = instanceExp;
5716
5717                                  GetInt64(value, &intValue);
5718
5719                                  Set(exp.instance.data, intValue);
5720                                  PopulateInstance(exp.instance);
5721                                  break;
5722                               }
5723                               case intPtrType:
5724                               {
5725                                  // TOFIX:
5726                                  intptr intValue;
5727                                  void (*Set)(void *, intptr) = (void *)prop.Set;
5728
5729                                  exp.instance = Instantiation { };
5730                                  exp.instance.data = new0 byte[_class.structSize];
5731                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5732                                  exp.instance.loc = exp.loc;
5733                                  exp.type = instanceExp;
5734
5735                                  GetIntPtr(value, &intValue);
5736
5737                                  Set(exp.instance.data, intValue);
5738                                  PopulateInstance(exp.instance);
5739                                  break;
5740                               }
5741                               case intSizeType:
5742                               {
5743                                  // TOFIX:
5744                                  intsize intValue;
5745                                  void (*Set)(void *, intsize) = (void *)prop.Set;
5746
5747                                  exp.instance = Instantiation { };
5748                                  exp.instance.data = new0 byte[_class.structSize];
5749                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5750                                  exp.instance.loc = exp.loc;
5751                                  exp.type = instanceExp;
5752
5753                                  GetIntSize(value, &intValue);
5754
5755                                  Set(exp.instance.data, intValue);
5756                                  PopulateInstance(exp.instance);
5757                                  break;
5758                               }
5759                               case doubleType:
5760                               {
5761                                  double doubleValue;
5762                                  void (*Set)(void *, double) = (void *)prop.Set;
5763
5764                                  exp.instance = Instantiation { };
5765                                  exp.instance.data = new0 byte[_class.structSize];
5766                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5767                                  exp.instance.loc = exp.loc;
5768                                  exp.type = instanceExp;
5769
5770                                  GetDouble(value, &doubleValue);
5771
5772                                  Set(exp.instance.data, doubleValue);
5773                                  PopulateInstance(exp.instance);
5774                                  break;
5775                               }
5776                            }
5777                         }
5778                         else if(_class.type == bitClass)
5779                         {
5780                            switch(type.kind)
5781                            {
5782                               case classType:
5783                               {
5784                                  Class propertyClass = type._class.registered;
5785                                  if(propertyClass.type == structClass && value.instance.data)
5786                                  {
5787                                     unsigned int (*Set)(void *) = (void *)prop.Set;
5788                                     unsigned int bits = Set(value.instance.data);
5789                                     exp.constant = PrintHexUInt(bits);
5790                                     exp.type = constantExp;
5791                                     break;
5792                                  }
5793                                  else if(_class.type == bitClass)
5794                                  {
5795                                     unsigned int value;
5796                                     unsigned int (*Set)(unsigned int) = (void *)prop.Set;
5797                                     unsigned int bits;
5798
5799                                     GetUInt(exp.member.exp, &value);
5800                                     bits = Set(value);
5801                                     exp.constant = PrintHexUInt(bits);
5802                                     exp.type = constantExp;
5803                                  }
5804                               }
5805                            }
5806                         }
5807                      }
5808                      else
5809                      {
5810                         if(_class.type == bitClass)
5811                         {
5812                            unsigned int value;
5813                            GetUInt(exp.member.exp, &value);
5814
5815                            switch(type.kind)
5816                            {
5817                               case classType:
5818                               {
5819                                  Class _class = type._class.registered;
5820                                  if(_class.type == structClass)
5821                                  {
5822                                     void (*Get)(unsigned int, void *) = (void *)prop.Get;
5823
5824                                     exp.instance = Instantiation { };
5825                                     exp.instance.data = new0 byte[_class.structSize];
5826                                     exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5827                                     exp.instance.loc = exp.loc;
5828                                     //exp.instance.fullSet = true;
5829                                     exp.type = instanceExp;
5830                                     Get(value, exp.instance.data);
5831                                     PopulateInstance(exp.instance);
5832                                  }
5833                                  else if(_class.type == bitClass)
5834                                  {
5835                                     unsigned int (*Get)(unsigned int) = (void *)prop.Get;
5836                                     uint64 bits = Get(value);
5837                                     exp.constant = PrintHexUInt64(bits);
5838                                     exp.type = constantExp;
5839                                  }
5840                                  break;
5841                               }
5842                            }
5843                         }
5844                         else if(_class.type == structClass)
5845                         {
5846                            char * value = (exp.member.exp.type == instanceExp ) ? exp.member.exp.instance.data : null;
5847                            switch(type.kind)
5848                            {
5849                               case classType:
5850                               {
5851                                  Class _class = type._class.registered;
5852                                  if(_class.type == structClass && value)
5853                                  {
5854                                     void (*Get)(void *, void *) = (void *)prop.Get;
5855
5856                                     exp.instance = Instantiation { };
5857                                     exp.instance.data = new0 byte[_class.structSize];
5858                                     exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5859                                     exp.instance.loc = exp.loc;
5860                                     //exp.instance.fullSet = true;
5861                                     exp.type = instanceExp;
5862                                     Get(value, exp.instance.data);
5863                                     PopulateInstance(exp.instance);
5864                                  }
5865                                  break;
5866                               }
5867                            }
5868                         }
5869                         /*else
5870                         {
5871                            char * value = exp.member.exp.instance.data;
5872                            switch(type.kind)
5873                            {
5874                               case classType:
5875                               {
5876                                  Class _class = type._class.registered;
5877                                  if(_class.type == normalClass)
5878                                  {
5879                                     void *(*Get)(void *) = (void *)prop.Get;
5880
5881                                     exp.instance = Instantiation { };
5882                                     exp.instance._class = MkSpecifierName(_class.fullName); //MkClassName(_class.fullName);
5883                                     exp.type = instanceExp;
5884                                     exp.instance.data = Get(value, exp.instance.data);
5885                                  }
5886                                  break;
5887                               }
5888                            }
5889                         }
5890                         */
5891                      }
5892                   }
5893                }
5894                else
5895                {
5896                   exp.isConstant = false;
5897                }
5898             }
5899             else if(member)
5900             {
5901             }
5902          }
5903
5904          if(exp.type != ExpressionType::memberExp)
5905          {
5906             FreeExpression(memberExp);
5907             FreeIdentifier(memberID);
5908          }
5909          break;
5910       }
5911       case typeSizeExp:
5912       {
5913          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
5914          FreeExpContents(exp);
5915          exp.constant = PrintUInt(ComputeTypeSize(type));
5916          exp.type = constantExp;
5917          FreeType(type);
5918          break;
5919       }
5920       case classSizeExp:
5921       {
5922          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
5923          if(classSym && classSym.registered)
5924          {
5925             if(classSym.registered.fixed)
5926             {
5927                FreeSpecifier(exp._class);
5928                exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
5929                exp.type = constantExp;
5930             }
5931             else
5932             {
5933                char className[1024];
5934                strcpy(className, "__ecereClass_");
5935                FullClassNameCat(className, classSym.string, true);
5936                MangleClassName(className);
5937
5938                DeclareClass(classSym, className);
5939
5940                FreeExpContents(exp);
5941                exp.type = pointerExp;
5942                exp.member.exp = MkExpIdentifier(MkIdentifier(className));
5943                exp.member.member = MkIdentifier("structSize");
5944             }
5945          }
5946          break;
5947       }
5948       case castExp:
5949       //case constantExp:
5950       {
5951          Type type;
5952          Expression e = exp;
5953          if(exp.type == castExp)
5954          {
5955             if(exp.cast.exp)
5956                ComputeExpression(exp.cast.exp);
5957             e = exp.cast.exp;
5958          }
5959          if(e && exp.expType)
5960          {
5961             /*if(exp.destType)
5962                type = exp.destType;
5963             else*/
5964                type = exp.expType;
5965             if(type.kind == classType)
5966             {
5967                Class _class = type._class.registered;
5968                if(_class && (_class.type == unitClass || _class.type == bitClass))
5969                {
5970                   if(!_class.dataType)
5971                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5972                   type = _class.dataType;
5973                }
5974             }
5975
5976             switch(type.kind)
5977             {
5978                case _BoolType:
5979                case charType:
5980                   if(type.isSigned)
5981                   {
5982                      char value = 0;
5983                      if(GetChar(e, &value))
5984                      {
5985                         FreeExpContents(exp);
5986                         exp.constant = PrintChar(value);
5987                         exp.type = constantExp;
5988                      }
5989                   }
5990                   else
5991                   {
5992                      unsigned char value = 0;
5993                      if(GetUChar(e, &value))
5994                      {
5995                         FreeExpContents(exp);
5996                         exp.constant = PrintUChar(value);
5997                         exp.type = constantExp;
5998                      }
5999                   }
6000                   break;
6001                case shortType:
6002                   if(type.isSigned)
6003                   {
6004                      short value = 0;
6005                      if(GetShort(e, &value))
6006                      {
6007                         FreeExpContents(exp);
6008                         exp.constant = PrintShort(value);
6009                         exp.type = constantExp;
6010                      }
6011                   }
6012                   else
6013                   {
6014                      unsigned short value = 0;
6015                      if(GetUShort(e, &value))
6016                      {
6017                         FreeExpContents(exp);
6018                         exp.constant = PrintUShort(value);
6019                         exp.type = constantExp;
6020                      }
6021                   }
6022                   break;
6023                case intType:
6024                   if(type.isSigned)
6025                   {
6026                      int value = 0;
6027                      if(GetInt(e, &value))
6028                      {
6029                         FreeExpContents(exp);
6030                         exp.constant = PrintInt(value);
6031                         exp.type = constantExp;
6032                      }
6033                   }
6034                   else
6035                   {
6036                      unsigned int value = 0;
6037                      if(GetUInt(e, &value))
6038                      {
6039                         FreeExpContents(exp);
6040                         exp.constant = PrintUInt(value);
6041                         exp.type = constantExp;
6042                      }
6043                   }
6044                   break;
6045                case int64Type:
6046                   if(type.isSigned)
6047                   {
6048                      int64 value = 0;
6049                      if(GetInt64(e, &value))
6050                      {
6051                         FreeExpContents(exp);
6052                         exp.constant = PrintInt64(value);
6053                         exp.type = constantExp;
6054                      }
6055                   }
6056                   else
6057                   {
6058                      uint64 value = 0;
6059                      if(GetUInt64(e, &value))
6060                      {
6061                         FreeExpContents(exp);
6062                         exp.constant = PrintUInt64(value);
6063                         exp.type = constantExp;
6064                      }
6065                   }
6066                   break;
6067                case intPtrType:
6068                   if(type.isSigned)
6069                   {
6070                      intptr value = 0;
6071                      if(GetIntPtr(e, &value))
6072                      {
6073                         FreeExpContents(exp);
6074                         exp.constant = PrintInt64((int64)value);
6075                         exp.type = constantExp;
6076                      }
6077                   }
6078                   else
6079                   {
6080                      uintptr value = 0;
6081                      if(GetUIntPtr(e, &value))
6082                      {
6083                         FreeExpContents(exp);
6084                         exp.constant = PrintUInt64((uint64)value);
6085                         exp.type = constantExp;
6086                      }
6087                   }
6088                   break;
6089                case intSizeType:
6090                   if(type.isSigned)
6091                   {
6092                      intsize value = 0;
6093                      if(GetIntSize(e, &value))
6094                      {
6095                         FreeExpContents(exp);
6096                         exp.constant = PrintInt64((int64)value);
6097                         exp.type = constantExp;
6098                      }
6099                   }
6100                   else
6101                   {
6102                      uintsize value = 0;
6103                      if(GetUIntSize(e, &value))
6104                      {
6105                         FreeExpContents(exp);
6106                         exp.constant = PrintUInt64((uint64)value);
6107                         exp.type = constantExp;
6108                      }
6109                   }
6110                   break;
6111                case floatType:
6112                {
6113                   float value = 0;
6114                   if(GetFloat(e, &value))
6115                   {
6116                      FreeExpContents(exp);
6117                      exp.constant = PrintFloat(value);
6118                      exp.type = constantExp;
6119                   }
6120                   break;
6121                }
6122                case doubleType:
6123                {
6124                   double value = 0;
6125                   if(GetDouble(e, &value))
6126                   {
6127                      FreeExpContents(exp);
6128                      exp.constant = PrintDouble(value);
6129                      exp.type = constantExp;
6130                   }
6131                   break;
6132                }
6133             }
6134          }
6135          break;
6136       }
6137       case conditionExp:
6138       {
6139          Operand op1 { };
6140          Operand op2 { };
6141          Operand op3 { };
6142
6143          if(exp.cond.exp)
6144             // Caring only about last expression for now...
6145             ComputeExpression(exp.cond.exp->last);
6146          if(exp.cond.elseExp)
6147             ComputeExpression(exp.cond.elseExp);
6148          if(exp.cond.cond)
6149             ComputeExpression(exp.cond.cond);
6150
6151          op1 = GetOperand(exp.cond.cond);
6152          if(op1.type) op1.type.refCount++;
6153          op2 = GetOperand(exp.cond.exp->last);
6154          if(op2.type) op2.type.refCount++;
6155          op3 = GetOperand(exp.cond.elseExp);
6156          if(op3.type) op3.type.refCount++;
6157
6158          if(op1.ops.Cond) { FreeExpContents(exp); op1.ops.Cond(exp, op1, op2, op3); }
6159          if(op1.type) FreeType(op1.type);
6160          if(op2.type) FreeType(op2.type);
6161          if(op3.type) FreeType(op3.type);
6162          break;
6163       }
6164    }
6165 }
6166
6167 static bool CheckExpressionType(Expression exp, Type destType, bool skipUnitBla)
6168 {
6169    bool result = true;
6170    if(destType)
6171    {
6172       OldList converts { };
6173       Conversion convert;
6174
6175       if(destType.kind == voidType)
6176          return false;
6177
6178       if(!MatchTypeExpression(exp, destType, &converts, skipUnitBla))
6179          result = false;
6180       if(converts.count)
6181       {
6182          // for(convert = converts.last; convert; convert = convert.prev)
6183          for(convert = converts.first; convert; convert = convert.next)
6184          {
6185             bool empty = !(convert.isGet ? (void *)convert.convert.Get : (void *)convert.convert.Set);
6186             if(!empty)
6187             {
6188                Expression newExp { };
6189                ClassObjectType objectType = exp.expType ? exp.expType.classObjectType : none;
6190
6191                // TODO: Check this...
6192                *newExp = *exp;
6193                newExp.destType = null;
6194
6195                if(convert.isGet)
6196                {
6197                   // [exp].ColorRGB
6198                   exp.type = memberExp;
6199                   exp.addedThis = true;
6200                   exp.member.exp = newExp;
6201                   FreeType(exp.member.exp.expType);
6202
6203                   exp.member.exp.expType = MkClassType(convert.convert._class.fullName);
6204                   exp.member.exp.expType.classObjectType = objectType;
6205                   exp.member.member = MkIdentifier(convert.convert.dataTypeString);
6206                   exp.member.memberType = propertyMember;
6207                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6208                   // TESTING THIS... for (int)degrees
6209                   exp.needCast = true;
6210                   if(exp.expType) exp.expType.refCount++;
6211                   ApplyAnyObjectLogic(exp.member.exp);
6212                }
6213                else
6214                {
6215
6216                   /*if(exp.isConstant)
6217                   {
6218                      // Color { ColorRGB = [exp] };
6219                      exp.type = instanceExp;
6220                      exp.instance = MkInstantiation(MkSpecifierName((convert.convert._class.fullName), //MkClassName(convert.convert._class.fullName),
6221                         null, MkListOne(MkMembersInitList(MkListOne(MkMemberInit(
6222                         MkListOne(MkIdentifier(convert.convert.dataTypeString)), newExp)))));
6223                   }
6224                   else*/
6225                   {
6226                      // If not constant, don't turn it yet into an instantiation
6227                      // (Go through the deep members system first)
6228                      exp.type = memberExp;
6229                      exp.addedThis = true;
6230                      exp.member.exp = newExp;
6231
6232                      // ADDED THIS HERE TO SOLVE PROPERTY ISSUES WITH NOHEAD CLASSES
6233                      if(/*!notByReference && */newExp.expType && newExp.expType.kind == classType && newExp.expType._class && newExp.expType._class.registered &&
6234                         newExp.expType._class.registered.type == noHeadClass)
6235                      {
6236                         newExp.byReference = true;
6237                      }
6238
6239                      FreeType(exp.member.exp.expType);
6240                      /*exp.member.exp.expType = convert.convert.dataType;
6241                      if(convert.convert.dataType) convert.convert.dataType.refCount++;*/
6242                      exp.member.exp.expType = null;
6243                      if(convert.convert.dataType)
6244                      {
6245                         exp.member.exp.expType = { };
6246                         CopyTypeInto(exp.member.exp.expType, convert.convert.dataType);
6247                         exp.member.exp.expType.refCount = 1;
6248                         exp.member.exp.expType.classObjectType = objectType;
6249                         ApplyAnyObjectLogic(exp.member.exp);
6250                      }
6251
6252                      exp.member.member = MkIdentifier(convert.convert._class.fullName);
6253                      exp.member.memberType = reverseConversionMember;
6254                      exp.expType = convert.resultType ? convert.resultType :
6255                         MkClassType(convert.convert._class.fullName);
6256                      exp.needCast = true;
6257                      if(convert.resultType) convert.resultType.refCount++;
6258                   }
6259                }
6260             }
6261             else
6262             {
6263                FreeType(exp.expType);
6264                if(convert.isGet)
6265                {
6266                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6267                   exp.needCast = true;
6268                   if(exp.expType) exp.expType.refCount++;
6269                }
6270                else
6271                {
6272                   exp.expType = convert.resultType ? convert.resultType : MkClassType(convert.convert._class.fullName);
6273                   exp.needCast = true;
6274                   if(convert.resultType)
6275                      convert.resultType.refCount++;
6276                }
6277             }
6278          }
6279          if(exp.isConstant && inCompiler)
6280             ComputeExpression(exp);
6281
6282          converts.Free(FreeConvert);
6283       }
6284
6285       if(!result && exp.expType && converts.count)      // TO TEST: Added converts.count here to avoid a double warning with function type
6286       {
6287          result = MatchTypes(exp.expType, exp.destType, null, null, null, true, true, false, false);
6288       }
6289       if(!result && exp.expType && exp.destType)
6290       {
6291          if((exp.destType.kind == classType && exp.expType.kind == pointerType &&
6292              exp.expType.type.kind == classType && exp.expType.type._class == exp.destType._class && exp.destType._class.registered && exp.destType._class.registered.type == structClass) ||
6293             (exp.expType.kind == classType && exp.destType.kind == pointerType &&
6294             exp.destType.type.kind == classType && exp.destType.type._class == exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass))
6295             result = true;
6296       }
6297    }
6298    // if(result) CheckTemplateTypes(exp);
6299    return result;
6300 }
6301
6302 void CheckTemplateTypes(Expression exp)
6303 {
6304    if(exp.destType && exp.destType.passAsTemplate && exp.expType && exp.expType.kind != templateType && !exp.expType.passAsTemplate)
6305    {
6306       Expression newExp { };
6307       Statement compound;
6308       Context context;
6309       *newExp = *exp;
6310       if(exp.destType) exp.destType.refCount++;
6311       if(exp.expType)  exp.expType.refCount++;
6312       newExp.prev = null;
6313       newExp.next = null;
6314
6315       switch(exp.expType.kind)
6316       {
6317          case doubleType:
6318             if(exp.destType.classObjectType)
6319             {
6320                // We need to pass the address, just pass it along (Undo what was done above)
6321                if(exp.destType) exp.destType.refCount--;
6322                if(exp.expType)  exp.expType.refCount--;
6323                delete newExp;
6324             }
6325             else
6326             {
6327                // If we're looking for value:
6328                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6329                OldList * specs;
6330                OldList * unionDefs = MkList();
6331                OldList * statements = MkList();
6332                context = PushContext();
6333                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6334                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6335                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6336                exp.type = extensionCompoundExp;
6337                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6338                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")), '=', newExp))));
6339                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
6340                exp.compound.compound.context = context;
6341                PopContext(context);
6342             }
6343             break;
6344          default:
6345             exp.type = castExp;
6346             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6347             exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6348             break;
6349       }
6350    }
6351    else if(exp.expType && exp.expType.passAsTemplate && exp.destType && exp.usage.usageGet && exp.destType.kind != templateType && !exp.destType.passAsTemplate)
6352    {
6353       Expression newExp { };
6354       Statement compound;
6355       Context context;
6356       *newExp = *exp;
6357       if(exp.destType) exp.destType.refCount++;
6358       if(exp.expType)  exp.expType.refCount++;
6359       newExp.prev = null;
6360       newExp.next = null;
6361
6362       switch(exp.expType.kind)
6363       {
6364          case doubleType:
6365             if(exp.destType.classObjectType)
6366             {
6367                // We need to pass the address, just pass it along (Undo what was done above)
6368                if(exp.destType) exp.destType.refCount--;
6369                if(exp.expType)  exp.expType.refCount--;
6370                delete newExp;
6371             }
6372             else
6373             {
6374                // If we're looking for value:
6375                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6376                OldList * specs;
6377                OldList * unionDefs = MkList();
6378                OldList * statements = MkList();
6379                context = PushContext();
6380                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6381                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6382                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6383                exp.type = extensionCompoundExp;
6384                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6385                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
6386                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")))));
6387                exp.compound.compound.context = context;
6388                PopContext(context);
6389             }
6390             break;
6391          case classType:
6392          {
6393             if(exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass)
6394             {
6395                exp.type = bracketsExp;
6396                exp.list = MkListOne(MkExpOp(null, '*', MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)),
6397                   MkDeclaratorPointer(MkPointer(null, null), null)), newExp)));
6398                ProcessExpressionType(exp.list->first);
6399                break;
6400             }
6401             else
6402             {
6403                exp.type = bracketsExp;
6404                exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)), null), newExp));
6405                newExp.needCast = true;
6406                ProcessExpressionType(exp.list->first);
6407                break;
6408             }
6409          }
6410          default:
6411          {
6412             if(exp.expType.kind == templateType)
6413             {
6414                Type type = ProcessTemplateParameterType(exp.expType.templateParameter);
6415                if(type)
6416                {
6417                   FreeType(exp.destType);
6418                   FreeType(exp.expType);
6419                   delete newExp;
6420                   break;
6421                }
6422             }
6423             if(newExp.type == memberExp && newExp.member.memberType == dataMember)
6424             {
6425                exp.type = opExp;
6426                exp.op.op = '*';
6427                exp.op.exp1 = null;
6428                exp.op.exp2 = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uint64")), MkDeclaratorPointer(MkPointer(null, null), null)),
6429                   MkExpBrackets(MkListOne(MkExpOp(null, '&', newExp))));
6430             }
6431             else
6432             {
6433                char typeString[1024];
6434                Declarator decl;
6435                OldList * specs = MkList();
6436                typeString[0] = '\0';
6437                PrintType(exp.expType, typeString, false, false);
6438                decl = SpecDeclFromString(typeString, specs, null);
6439
6440                exp.type = castExp;
6441                //exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6442                exp.cast.typeName = MkTypeName(specs, decl);
6443                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6444                exp.cast.exp.needCast = true;
6445             }
6446             break;
6447          }
6448       }
6449    }
6450 }
6451 // TODO: The Symbol tree should be reorganized by namespaces
6452 // Name Space:
6453 //    - Tree of all symbols within (stored without namespace)
6454 //    - Tree of sub-namespaces
6455
6456 static Symbol ScanWithNameSpace(BinaryTree tree, char * nameSpace, char * name)
6457 {
6458    int nsLen = strlen(nameSpace);
6459    Symbol symbol;
6460    // Start at the name space prefix
6461    for(symbol = (Symbol)tree.FindPrefix(nameSpace); symbol; symbol = (Symbol)((BTNode)symbol).next)
6462    {
6463       char * s = symbol.string;
6464       if(!strncmp(s, nameSpace, nsLen))
6465       {
6466          // This supports e.g. matching ecere::Socket to ecere::net::Socket
6467          int c;
6468          char * namePart;
6469          for(c = strlen(s)-1; c >= 0; c--)
6470             if(s[c] == ':')
6471                break;
6472
6473          namePart = s+c+1;
6474          if(!strcmp(namePart, name))
6475          {
6476             // TODO: Error on ambiguity
6477             return symbol;
6478          }
6479       }
6480       else
6481          break;
6482    }
6483    return null;
6484 }
6485
6486 static Symbol FindWithNameSpace(BinaryTree tree, char * name)
6487 {
6488    int c;
6489    char nameSpace[1024];
6490    char * namePart;
6491    bool gotColon = false;
6492
6493    nameSpace[0] = '\0';
6494    for(c = strlen(name)-1; c >= 0; c--)
6495       if(name[c] == ':')
6496       {
6497          gotColon = true;
6498          break;
6499       }
6500
6501    namePart = name+c+1;
6502    while(c >= 0 && name[c] == ':') c--;
6503    if(c >= 0)
6504    {
6505       // Try an exact match first
6506       Symbol symbol = (Symbol)tree.FindString(name);
6507       if(symbol)
6508          return symbol;
6509
6510       // Namespace specified
6511       memcpy(nameSpace, name, c + 1);
6512       nameSpace[c+1] = 0;
6513
6514       return ScanWithNameSpace(tree, nameSpace, namePart);
6515    }
6516    else if(gotColon)
6517    {
6518       // Looking for a global symbol, e.g. ::Sleep()
6519       Symbol symbol = (Symbol)tree.FindString(namePart);
6520       return symbol;
6521    }
6522    else
6523    {
6524       // Name only (no namespace specified)
6525       Symbol symbol = (Symbol)tree.FindString(namePart);
6526       if(symbol)
6527          return symbol;
6528       return ScanWithNameSpace(tree, "", namePart);
6529    }
6530    return null;
6531 }
6532
6533 static void ProcessDeclaration(Declaration decl);
6534
6535 /*static */Symbol FindSymbol(char * name, Context startContext, Context endContext, bool isStruct, bool globalNameSpace)
6536 {
6537 #ifdef _DEBUG
6538    //Time startTime = GetTime();
6539 #endif
6540    // Optimize this later? Do this before/less?
6541    Context ctx;
6542    Symbol symbol = null;
6543    // First, check if the identifier is declared inside the function
6544    //for(ctx = curContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6545
6546    for(ctx = startContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6547    {
6548       if(ctx == globalContext && !globalNameSpace && ctx.hasNameSpace)
6549       {
6550          symbol = null;
6551          if(thisNameSpace)
6552          {
6553             char curName[1024];
6554             strcpy(curName, thisNameSpace);
6555             strcat(curName, "::");
6556             strcat(curName, name);
6557             // Try to resolve in current namespace first
6558             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, curName);
6559          }
6560          if(!symbol)
6561             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, name);
6562       }
6563       else
6564          symbol = (Symbol)(isStruct ? ctx.structSymbols : ctx.symbols).FindString(name);
6565
6566       if(symbol || ctx == endContext) break;
6567    }
6568    if(inCompiler && curExternal && symbol && ctx == globalContext && curExternal.symbol && symbol.id > curExternal.symbol.idCode && symbol.pointerExternal)
6569    {
6570       if(symbol.pointerExternal.type == functionExternal)
6571       {
6572          FunctionDefinition function = symbol.pointerExternal.function;
6573
6574          // Modified this recently...
6575          Context tmpContext = curContext;
6576          curContext = null;
6577          symbol.pointerExternal = MkExternalDeclaration(MkDeclaration(CopyList(function.specifiers, CopySpecifier), MkListOne(MkInitDeclarator(CopyDeclarator(function.declarator), null))));
6578          curContext = tmpContext;
6579
6580          symbol.pointerExternal.symbol = symbol;
6581
6582          // TESTING THIS:
6583          DeclareType(symbol.type, true, true);
6584
6585          ast->Insert(curExternal.prev, symbol.pointerExternal);
6586
6587          symbol.id = curExternal.symbol.idCode;
6588
6589       }
6590       else if(symbol.pointerExternal.type == declarationExternal && curExternal.symbol.idCode < symbol.pointerExternal.symbol.id) // Added id comparison because Global Function prototypes were broken
6591       {
6592          ast->Move(symbol.pointerExternal, curExternal.prev);
6593          symbol.id = curExternal.symbol.idCode;
6594       }
6595    }
6596 #ifdef _DEBUG
6597    //findSymbolTotalTime += GetTime() - startTime;
6598 #endif
6599    return symbol;
6600 }
6601
6602 static void GetTypeSpecs(Type type, OldList * specs)
6603 {
6604    if(!type.isSigned && type.kind != intPtrType && type.kind != intSizeType) ListAdd(specs, MkSpecifier(UNSIGNED));
6605    switch(type.kind)
6606    {
6607       case classType:
6608       {
6609          if(type._class.registered)
6610          {
6611             if(!type._class.registered.dataType)
6612                type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
6613             GetTypeSpecs(type._class.registered.dataType, specs);
6614          }
6615          break;
6616       }
6617       case doubleType: ListAdd(specs, MkSpecifier(DOUBLE)); break;
6618       case floatType: ListAdd(specs, MkSpecifier(FLOAT)); break;
6619       case charType: ListAdd(specs, MkSpecifier(CHAR)); break;
6620       case _BoolType: ListAdd(specs, MkSpecifier(_BOOL)); break;
6621       case shortType: ListAdd(specs, MkSpecifier(SHORT)); break;
6622       case int64Type: ListAdd(specs, MkSpecifier(INT64)); break;
6623       case intPtrType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intptr" : "uintptr")); break;
6624       case intSizeType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intsize" : "uintsize")); break;
6625       case intType:
6626       default:
6627          ListAdd(specs, MkSpecifier(INT)); break;
6628    }
6629 }
6630
6631 static void PrintArraySize(Type arrayType, char * string)
6632 {
6633    char size[256];
6634    size[0] = '\0';
6635    strcat(size, "[");
6636    if(arrayType.enumClass)
6637       strcat(size, arrayType.enumClass.string);
6638    else if(arrayType.arraySizeExp)
6639       PrintExpression(arrayType.arraySizeExp, size);
6640    strcat(size, "]");
6641    strcat(string, size);
6642 }
6643
6644 // WARNING : This function expects a null terminated string since it recursively concatenate...
6645 static void PrintTypeSpecs(Type type, char * string, bool fullName, bool printConst)
6646 {
6647    if(type)
6648    {
6649       if(printConst && type.constant)
6650          strcat(string, "const ");
6651       switch(type.kind)
6652       {
6653          case classType:
6654          {
6655             Symbol c = type._class;
6656             // TODO: typed_object does not fully qualify the type, as it may have taken up an actual class (Stored in _class) from overriding
6657             //       look into merging with thisclass ?
6658             if(type.classObjectType == typedObject)
6659                strcat(string, "typed_object");
6660             else if(type.classObjectType == anyObject)
6661                strcat(string, "any_object");
6662             else
6663             {
6664                if(c && c.string)
6665                   strcat(string, (fullName || !c.registered) ? c.string : c.registered.name);
6666             }
6667             if(type.byReference)
6668                strcat(string, " &");
6669             break;
6670          }
6671          case voidType: strcat(string, "void"); break;
6672          case intType:  strcat(string, type.isSigned ? "int" : "uint"); break;
6673          case int64Type:  strcat(string, type.isSigned ? "int64" : "uint64"); break;
6674          case intPtrType:  strcat(string, type.isSigned ? "intptr" : "uintptr"); break;
6675          case intSizeType:  strcat(string, type.isSigned ? "intsize" : "uintsize"); break;
6676          case charType: strcat(string, type.isSigned ? "char" : "byte"); break;
6677          case _BoolType: strcat(string, "_Bool"); break;
6678          case shortType: strcat(string, type.isSigned ? "short" : "uint16"); break;
6679          case floatType: strcat(string, "float"); break;
6680          case doubleType: strcat(string, "double"); break;
6681          case structType:
6682             if(type.enumName)
6683             {
6684                strcat(string, "struct ");
6685                strcat(string, type.enumName);
6686             }
6687             else if(type.typeName)
6688                strcat(string, type.typeName);
6689             else
6690             {
6691                Type member;
6692                strcat(string, "struct { ");
6693                for(member = type.members.first; member; member = member.next)
6694                {
6695                   PrintType(member, string, true, fullName);
6696                   strcat(string,"; ");
6697                }
6698                strcat(string,"}");
6699             }
6700             break;
6701          case unionType:
6702             if(type.enumName)
6703             {
6704                strcat(string, "union ");
6705                strcat(string, type.enumName);
6706             }
6707             else if(type.typeName)
6708                strcat(string, type.typeName);
6709             else
6710             {
6711                strcat(string, "union ");
6712                strcat(string,"(unnamed)");
6713             }
6714             break;
6715          case enumType:
6716             if(type.enumName)
6717             {
6718                strcat(string, "enum ");
6719                strcat(string, type.enumName);
6720             }
6721             else if(type.typeName)
6722                strcat(string, type.typeName);
6723             else
6724                strcat(string, "int"); // "enum");
6725             break;
6726          case ellipsisType:
6727             strcat(string, "...");
6728             break;
6729          case subClassType:
6730             strcat(string, "subclass(");
6731             strcat(string, type._class ? type._class.string : "int");
6732             strcat(string, ")");
6733             break;
6734          case templateType:
6735             strcat(string, type.templateParameter.identifier.string);
6736             break;
6737          case thisClassType:
6738             strcat(string, "thisclass");
6739             break;
6740          case vaListType:
6741             strcat(string, "__builtin_va_list");
6742             break;
6743       }
6744    }
6745 }
6746
6747 static void PrintName(Type type, char * string, bool fullName)
6748 {
6749    if(type.name && type.name[0])
6750    {
6751       if(fullName)
6752          strcat(string, type.name);
6753       else
6754       {
6755          char * name = RSearchString(type.name, "::", strlen(type.name), true, false);
6756          if(name) name += 2; else name = type.name;
6757          strcat(string, name);
6758       }
6759    }
6760 }
6761
6762 static void PrintAttribs(Type type, char * string)
6763 {
6764    if(type)
6765    {
6766       if(type.dllExport)   strcat(string, "dllexport ");
6767       if(type.attrStdcall) strcat(string, "stdcall ");
6768    }
6769 }
6770
6771 static void PrePrintType(Type type, char * string, bool fullName, Type parentType, bool printConst)
6772 {
6773    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
6774    {
6775       Type attrType = null;
6776       if((type.kind == functionType || type.kind == methodType) && (!parentType || parentType.kind != pointerType))
6777          PrintAttribs(type, string);
6778       if(printConst && type.constant && (type.kind == functionType || type.kind == methodType))
6779          strcat(string, " const");
6780       PrePrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName, type, printConst);
6781       if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
6782          strcat(string, " (");
6783       if(type.kind == pointerType)
6784       {
6785          if(type.type.kind == functionType || type.type.kind == methodType)
6786             PrintAttribs(type.type, string);
6787       }
6788       if(type.kind == pointerType)
6789       {
6790          if(type.type.kind == functionType || type.type.kind == methodType || type.type.kind == arrayType)
6791             strcat(string, "*");
6792          else
6793             strcat(string, " *");
6794       }
6795       if(printConst && type.constant && type.kind == pointerType)
6796          strcat(string, " const");
6797    }
6798    else
6799       PrintTypeSpecs(type, string, fullName, printConst);
6800 }
6801
6802 static void PostPrintType(Type type, char * string, bool fullName)
6803 {
6804    if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
6805       strcat(string, ")");
6806    if(type.kind == arrayType)
6807       PrintArraySize(type, string);
6808    else if(type.kind == functionType)
6809    {
6810       Type param;
6811       strcat(string, "(");
6812       for(param = type.params.first; param; param = param.next)
6813       {
6814          PrintType(param, string, true, fullName);
6815          if(param.next) strcat(string, ", ");
6816       }
6817       strcat(string, ")");
6818    }
6819    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
6820       PostPrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName);
6821 }
6822
6823 // *****
6824 // TODO: Add a max buffer size to avoid overflows. This function is used with static size char arrays.
6825 // *****
6826 static void _PrintType(Type type, char * string, bool printName, bool fullName, bool printConst)
6827 {
6828    PrePrintType(type, string, fullName, null, printConst);
6829
6830    if(type.thisClass || (printName && type.name && type.name[0]))
6831       strcat(string, " ");
6832    if(/*(type.kind == methodType || type.kind == functionType) && */(type.thisClass || type.staticMethod))
6833    {
6834       Symbol _class = type.thisClass;
6835       if((type.classObjectType == typedObject || type.classObjectType == classPointer) || (_class && !strcmp(_class.string, "class")))
6836       {
6837          if(type.classObjectType == classPointer)
6838             strcat(string, "class");
6839          else
6840             strcat(string, type.byReference ? "typed_object&" : "typed_object");
6841       }
6842       else if(_class && _class.string)
6843       {
6844          String s = _class.string;
6845          if(fullName)
6846             strcat(string, s);
6847          else
6848          {
6849             char * name = RSearchString(s, "::", strlen(s), true, false);
6850             if(name) name += 2; else name = s;
6851             strcat(string, name);
6852          }
6853       }
6854       strcat(string, "::");
6855    }
6856
6857    if(printName && type.name)
6858       PrintName(type, string, fullName);
6859    PostPrintType(type, string, fullName);
6860    if(type.bitFieldCount)
6861    {
6862       char count[100];
6863       sprintf(count, ":%d", type.bitFieldCount);
6864       strcat(string, count);
6865    }
6866 }
6867
6868 void PrintType(Type type, char * string, bool printName, bool fullName)
6869 {
6870    _PrintType(type, string, printName, fullName, true);
6871 }
6872
6873 void PrintTypeNoConst(Type type, char * string, bool printName, bool fullName)
6874 {
6875    _PrintType(type, string, printName, fullName, false);
6876 }
6877
6878 static Type FindMember(Type type, char * string)
6879 {
6880    Type memberType;
6881    for(memberType = type.members.first; memberType; memberType = memberType.next)
6882    {
6883       if(!memberType.name)
6884       {
6885          Type subType = FindMember(memberType, string);
6886          if(subType)
6887             return subType;
6888       }
6889       else if(!strcmp(memberType.name, string))
6890          return memberType;
6891    }
6892    return null;
6893 }
6894
6895 Type FindMemberAndOffset(Type type, char * string, uint * offset)
6896 {
6897    Type memberType;
6898    for(memberType = type.members.first; memberType; memberType = memberType.next)
6899    {
6900       if(!memberType.name)
6901       {
6902          Type subType = FindMember(memberType, string);
6903          if(subType)
6904          {
6905             *offset += memberType.offset;
6906             return subType;
6907          }
6908       }
6909       else if(!strcmp(memberType.name, string))
6910       {
6911          *offset += memberType.offset;
6912          return memberType;
6913       }
6914    }
6915    return null;
6916 }
6917
6918 public bool GetParseError() { return parseError; }
6919
6920 Expression ParseExpressionString(char * expression)
6921 {
6922    parseError = false;
6923
6924    fileInput = TempFile { };
6925    fileInput.Write(expression, 1, strlen(expression));
6926    fileInput.Seek(0, start);
6927
6928    echoOn = false;
6929    parsedExpression = null;
6930    resetScanner();
6931    expression_yyparse();
6932    delete fileInput;
6933
6934    return parsedExpression;
6935 }
6936
6937 static bool ResolveIdWithClass(Expression exp, Class _class, bool skipIDClassCheck)
6938 {
6939    Identifier id = exp.identifier;
6940    Method method = null;
6941    Property prop = null;
6942    DataMember member = null;
6943    ClassProperty classProp = null;
6944
6945    if(_class && _class.type == enumClass)
6946    {
6947       NamedLink value = null;
6948       Class enumClass = eSystem_FindClass(privateModule, "enum");
6949       if(enumClass)
6950       {
6951          Class baseClass;
6952          for(baseClass = _class; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
6953          {
6954             EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
6955             for(value = e.values.first; value; value = value.next)
6956             {
6957                if(!strcmp(value.name, id.string))
6958                   break;
6959             }
6960             if(value)
6961             {
6962                char constant[256];
6963
6964                FreeExpContents(exp);
6965
6966                exp.type = constantExp;
6967                exp.isConstant = true;
6968                if(!strcmp(baseClass.dataTypeString, "int"))
6969                   sprintf(constant, "%d",(int)value.data);
6970                else
6971                   sprintf(constant, "0x%X",(int)value.data);
6972                exp.constant = CopyString(constant);
6973                //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
6974                exp.expType = MkClassType(baseClass.fullName);
6975                break;
6976             }
6977          }
6978       }
6979       if(value)
6980          return true;
6981    }
6982    if((method = eClass_FindMethod(_class, id.string, privateModule)))
6983    {
6984       ProcessMethodType(method);
6985       exp.expType = Type
6986       {
6987          refCount = 1;
6988          kind = methodType;
6989          method = method;
6990          // Crash here?
6991          // TOCHECK: Put it back to what it was...
6992          // methodClass = _class;
6993          methodClass = (skipIDClassCheck || (id && id._class)) ? _class : null;
6994       };
6995       //id._class = null;
6996       return true;
6997    }
6998    else if((prop = eClass_FindProperty(_class, id.string, privateModule)))
6999    {
7000       if(!prop.dataType)
7001          ProcessPropertyType(prop);
7002       exp.expType = prop.dataType;
7003       if(prop.dataType) prop.dataType.refCount++;
7004       return true;
7005    }
7006    else if((member = eClass_FindDataMember(_class, id.string, privateModule, null, null)))
7007    {
7008       if(!member.dataType)
7009          member.dataType = ProcessTypeString(member.dataTypeString, false);
7010       exp.expType = member.dataType;
7011       if(member.dataType) member.dataType.refCount++;
7012       return true;
7013    }
7014    else if((classProp = eClass_FindClassProperty(_class, id.string)))
7015    {
7016       if(!classProp.dataType)
7017          classProp.dataType = ProcessTypeString(classProp.dataTypeString, false);
7018
7019       if(classProp.constant)
7020       {
7021          FreeExpContents(exp);
7022
7023          exp.isConstant = true;
7024          if(classProp.dataType.kind == pointerType && classProp.dataType.type.kind == charType)
7025          {
7026             //char constant[256];
7027             exp.type = stringExp;
7028             exp.constant = QMkString((char *)classProp.Get(_class));
7029          }
7030          else
7031          {
7032             char constant[256];
7033             exp.type = constantExp;
7034             sprintf(constant, "%d", (int)classProp.Get(_class));
7035             exp.constant = CopyString(constant);
7036          }
7037       }
7038       else
7039       {
7040          // TO IMPLEMENT...
7041       }
7042
7043       exp.expType = classProp.dataType;
7044       if(classProp.dataType) classProp.dataType.refCount++;
7045       return true;
7046    }
7047    return false;
7048 }
7049
7050 static GlobalData ScanGlobalData(NameSpace nameSpace, char * name)
7051 {
7052    BinaryTree * tree = &nameSpace.functions;
7053    GlobalData data = (GlobalData)tree->FindString(name);
7054    NameSpace * child;
7055    if(!data)
7056    {
7057       for(child = (NameSpace *)nameSpace.nameSpaces.first; child; child = (NameSpace *)((BTNode)child).next)
7058       {
7059          data = ScanGlobalData(child, name);
7060          if(data)
7061             break;
7062       }
7063    }
7064    return data;
7065 }
7066
7067 static GlobalData FindGlobalData(char * name)
7068 {
7069    int start = 0, c;
7070    NameSpace * nameSpace;
7071    nameSpace = globalData;
7072    for(c = 0; name[c]; c++)
7073    {
7074       if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
7075       {
7076          NameSpace * newSpace;
7077          char * spaceName = new char[c - start + 1];
7078          strncpy(spaceName, name + start, c - start);
7079          spaceName[c-start] = '\0';
7080          newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
7081          delete spaceName;
7082          if(!newSpace)
7083             return null;
7084          nameSpace = newSpace;
7085          if(name[c] == ':') c++;
7086          start = c+1;
7087       }
7088    }
7089    if(c - start)
7090    {
7091       return ScanGlobalData(nameSpace, name + start);
7092    }
7093    return null;
7094 }
7095
7096 static int definedExpStackPos;
7097 static void * definedExpStack[512];
7098
7099 // This function makes checkedExp equivalent to newExp, ending up freeing newExp
7100 void ReplaceExpContents(Expression checkedExp, Expression newExp)
7101 {
7102    Expression prev = checkedExp.prev, next = checkedExp.next;
7103
7104    FreeExpContents(checkedExp);
7105    FreeType(checkedExp.expType);
7106    FreeType(checkedExp.destType);
7107
7108    *checkedExp = *newExp;
7109
7110    delete newExp;
7111
7112    checkedExp.prev = prev;
7113    checkedExp.next = next;
7114 }
7115
7116 void ApplyAnyObjectLogic(Expression e)
7117 {
7118    Type destType = /*(e.destType && e.destType.kind == ellipsisType) ? ellipsisDestType : */e.destType;
7119 #ifdef _DEBUG
7120    char debugExpString[4096];
7121    debugExpString[0] = '\0';
7122    PrintExpression(e, debugExpString);
7123 #endif
7124
7125    if(destType && (/*destType.classObjectType == ClassObjectType::typedObject || */destType.classObjectType == anyObject))
7126    {
7127       //if(e.destType && e.destType.kind == ellipsisType) usedEllipsis = true;
7128       //ellipsisDestType = destType;
7129       if(e && e.expType)
7130       {
7131          Type type = e.expType;
7132          Class _class = null;
7133          //Type destType = e.destType;
7134
7135          if(type.kind == classType && type._class && type._class.registered)
7136          {
7137             _class = type._class.registered;
7138          }
7139          else if(type.kind == subClassType)
7140          {
7141             _class = FindClass("ecere::com::Class").registered;
7142          }
7143          else
7144          {
7145             char string[1024] = "";
7146             Symbol classSym;
7147
7148             PrintTypeNoConst(type, string, false, true);
7149             classSym = FindClass(string);
7150             if(classSym) _class = classSym.registered;
7151          }
7152
7153          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...
7154             (!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))) ||
7155             destType.byReference)))
7156          {
7157             if(!_class || strcmp(_class.fullName, "char *"))     // TESTING THIS WITH NEW String class...
7158             {
7159                Expression checkedExp = e, newExp;
7160
7161                while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7162                {
7163                   if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7164                   {
7165                      if(checkedExp.type == extensionCompoundExp)
7166                      {
7167                         checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7168                      }
7169                      else
7170                         checkedExp = checkedExp.list->last;
7171                   }
7172                   else if(checkedExp.type == castExp)
7173                      checkedExp = checkedExp.cast.exp;
7174                }
7175
7176                if(checkedExp && checkedExp.type == opExp && checkedExp.op.op == '*' && !checkedExp.op.exp1)
7177                {
7178                   newExp = checkedExp.op.exp2;
7179                   checkedExp.op.exp2 = null;
7180                   FreeExpContents(checkedExp);
7181
7182                   if(e.expType && e.expType.passAsTemplate)
7183                   {
7184                      char size[100];
7185                      ComputeTypeSize(e.expType);
7186                      sprintf(size, "%d", e.expType.size);
7187                      newExp = MkExpBrackets(MkListOne(MkExpOp(MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)),
7188                         MkDeclaratorPointer(MkPointer(null, null), null)), newExp), '+',
7189                            MkExpCall(MkExpIdentifier(MkIdentifier("__ENDIAN_PAD")), MkListOne(MkExpConstant(size))))));
7190                   }
7191
7192                   ReplaceExpContents(checkedExp, newExp);
7193                   e.byReference = true;
7194                }
7195                else if(!e.byReference || (_class && _class.type == noHeadClass))     // TESTING THIS HERE...
7196                {
7197                   Expression checkedExp, newExp;
7198
7199                   {
7200                      // TODO: Move code from debugTools.ec for hasAddress flag, this is just temporary
7201                      bool hasAddress =
7202                         e.type == identifierExp ||
7203                         (e.type == ExpressionType::memberExp && e.member.memberType == dataMember) ||
7204                         (e.type == ExpressionType::pointerExp && e.member.memberType == dataMember) ||
7205                         (e.type == opExp && !e.op.exp1 && e.op.op == '*') ||
7206                         e.type == indexExp;
7207
7208                      if(_class && _class.type != noHeadClass && _class.type != normalClass && _class.type != structClass && !hasAddress)
7209                      {
7210                         Context context = PushContext();
7211                         Declarator decl;
7212                         OldList * specs = MkList();
7213                         char typeString[1024];
7214                         Expression newExp { };
7215
7216                         typeString[0] = '\0';
7217                         *newExp = *e;
7218
7219                         //if(e.destType) e.destType.refCount++;
7220                         // if(exp.expType) exp.expType.refCount++;
7221                         newExp.prev = null;
7222                         newExp.next = null;
7223                         newExp.expType = null;
7224
7225                         PrintTypeNoConst(e.expType, typeString, false, true);
7226                         decl = SpecDeclFromString(typeString, specs, null);
7227                         newExp.destType = ProcessType(specs, decl);
7228
7229                         curContext = context;
7230
7231                         // We need a current compound for this
7232                         if(curCompound)
7233                         {
7234                            char name[100];
7235                            OldList * stmts = MkList();
7236                            e.type = extensionCompoundExp;
7237                            sprintf(name, "__internalValue%03X", internalValueCounter++);
7238                            if(!curCompound.compound.declarations)
7239                               curCompound.compound.declarations = MkList();
7240                            curCompound.compound.declarations->Insert(null, MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(name)), null))));
7241                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(name)), '=', newExp))));
7242                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier(name)))));
7243                            e.compound = MkCompoundStmt(null, stmts);
7244                         }
7245                         else
7246                            printf("libec: compiler error, curCompound is null in ApplyAnyObjectLogic\n");
7247
7248                         /*
7249                         e.compound = MkCompoundStmt(
7250                            MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(
7251                               MkDeclaratorIdentifier(MkIdentifier("__internalValue")), MkInitializerAssignment(newExp))))),
7252
7253                            MkListOne(MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier("__internalValue"))))));
7254                         */
7255
7256                         {
7257                            Type type = e.destType;
7258                            e.destType = { };
7259                            CopyTypeInto(e.destType, type);
7260                            e.destType.refCount = 1;
7261                            e.destType.classObjectType = none;
7262                            FreeType(type);
7263                         }
7264
7265                         e.compound.compound.context = context;
7266                         PopContext(context);
7267                         curContext = context.parent;
7268                      }
7269                   }
7270
7271                   // TODO: INTEGRATE THIS WITH VERSION ABOVE WHICH WAS ADDED TO ENCOMPASS OTHER CASE (*pointer)
7272                   checkedExp = e;
7273                   while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7274                   {
7275                      if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7276                      {
7277                         if(checkedExp.type == extensionCompoundExp)
7278                         {
7279                            checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7280                         }
7281                         else
7282                            checkedExp = checkedExp.list->last;
7283                      }
7284                      else if(checkedExp.type == castExp)
7285                         checkedExp = checkedExp.cast.exp;
7286                   }
7287                   {
7288                      Expression operand { };
7289                      operand = *checkedExp;
7290                      checkedExp.destType = null;
7291                      checkedExp.expType = null;
7292                      checkedExp.Clear();
7293                      checkedExp.type = opExp;
7294                      checkedExp.op.op = '&';
7295                      checkedExp.op.exp1 = null;
7296                      checkedExp.op.exp2 = operand;
7297
7298                      //newExp = MkExpOp(null, '&', checkedExp);
7299                   }
7300                   //ReplaceExpContents(checkedExp, newExp);
7301                }
7302             }
7303          }
7304       }
7305    }
7306    {
7307       // If expression type is a simple class, make it an address
7308       // FixReference(e, true);
7309    }
7310 //#if 0
7311    if((!destType || destType.kind == ellipsisType || destType.kind == voidType) && e.expType && (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7312       (e.expType.byReference || (e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7313          (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass ) )))
7314    {
7315       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"))
7316       {
7317          return;  // LEAVE THIS CASE (typed_object & :: methods 's this) TO PASS 2 FOR NOW
7318       }
7319       else
7320       {
7321          Expression thisExp { };
7322
7323          *thisExp = *e;
7324          thisExp.prev = null;
7325          thisExp.next = null;
7326          e.Clear();
7327
7328          e.type = bracketsExp;
7329          e.list = MkListOne(MkExpOp(null, '*', thisExp.type == identifierExp ? thisExp : MkExpBrackets(MkListOne(thisExp))));
7330          if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && thisExp.expType._class.registered.type == noHeadClass)
7331             ((Expression)e.list->first).byReference = true;
7332
7333          /*if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && !strcmp(thisExp.expType._class.registered.name, "class"))
7334          {
7335             e.expType = thisExp.expType;
7336             e.expType.refCount++;
7337          }
7338          else*/
7339          {
7340             e.expType = { };
7341             CopyTypeInto(e.expType, thisExp.expType);
7342             e.expType.byReference = false;
7343             e.expType.refCount = 1;
7344
7345             if(e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7346                (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass))
7347             {
7348                e.expType.classObjectType = none;
7349             }
7350          }
7351       }
7352    }
7353 // TOFIX: Try this for a nice IDE crash!
7354 //#endif
7355    // The other way around
7356    else
7357 //#endif
7358    if(destType && e.expType &&
7359          //e.expType.kind == classType && e.expType._class && e.expType._class.registered && !strcmp(e.expType._class.registered.name, "class") &&
7360          (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7361          !destType.classObjectType && /*(destType.kind != pointerType || !destType.type || destType.type.kind != voidType) &&*/ destType.kind != voidType)
7362    {
7363       if(destType.kind == ellipsisType)
7364       {
7365          Compiler_Error($"Unspecified type\n");
7366       }
7367       else if(!(destType.truth && e.expType.kind == classType && e.expType._class && e.expType._class.registered && e.expType._class.registered.type == structClass))
7368       {
7369          bool byReference = e.expType.byReference;
7370          Expression thisExp { };
7371          Declarator decl;
7372          OldList * specs = MkList();
7373          char typeString[1024]; // Watch buffer overruns
7374          Type type;
7375          ClassObjectType backupClassObjectType;
7376          bool backupByReference;
7377
7378          if(e.expType.kind == classType && e.expType._class && e.expType._class.registered && strcmp(e.expType._class.registered.name, "class"))
7379             type = e.expType;
7380          else
7381             type = destType;
7382
7383          backupClassObjectType = type.classObjectType;
7384          backupByReference = type.byReference;
7385
7386          type.classObjectType = none;
7387          type.byReference = false;
7388
7389          typeString[0] = '\0';
7390          PrintType(type, typeString, false, true);
7391          decl = SpecDeclFromString(typeString, specs, null);
7392
7393          type.classObjectType = backupClassObjectType;
7394          type.byReference = backupByReference;
7395
7396          *thisExp = *e;
7397          thisExp.prev = null;
7398          thisExp.next = null;
7399          e.Clear();
7400
7401          if( ( type.kind == classType && type._class && type._class.registered &&
7402                    (type._class.registered.type == systemClass || type._class.registered.type == bitClass ||
7403                     type._class.registered.type == enumClass || type._class.registered.type == unitClass) ) ||
7404              (type.kind != pointerType && type.kind != intPtrType && type.kind != arrayType && type.kind != classType) ||
7405              (!destType.byReference && byReference && (destType.kind != pointerType || type.kind != pointerType)))
7406          {
7407             e.type = opExp;
7408             e.op.op = '*';
7409             e.op.exp1 = null;
7410             e.op.exp2 = MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), thisExp);
7411
7412             e.expType = { };
7413             CopyTypeInto(e.expType, type);
7414             e.expType.byReference = false;
7415             e.expType.refCount = 1;
7416          }
7417          else
7418          {
7419             e.type = castExp;
7420             e.cast.typeName = MkTypeName(specs, decl);
7421             e.cast.exp = thisExp;
7422             e.byReference = true;
7423             e.expType = type;
7424             type.refCount++;
7425          }
7426          e.destType = destType;
7427          destType.refCount++;
7428       }
7429    }
7430 }
7431
7432 void ProcessExpressionType(Expression exp)
7433 {
7434    bool unresolved = false;
7435    Location oldyylloc = yylloc;
7436    bool notByReference = false;
7437 #ifdef _DEBUG
7438    char debugExpString[4096];
7439    debugExpString[0] = '\0';
7440    PrintExpression(exp, debugExpString);
7441 #endif
7442    if(!exp || exp.expType)
7443       return;
7444
7445    //eSystem_Logf("%s\n", expString);
7446
7447    // Testing this here
7448    yylloc = exp.loc;
7449    switch(exp.type)
7450    {
7451       case identifierExp:
7452       {
7453          Identifier id = exp.identifier;
7454          if(!id || !topContext) return;
7455
7456          // DOING THIS LATER NOW...
7457          if(id._class && id._class.name)
7458          {
7459             id.classSym = id._class.symbol; // FindClass(id._class.name);
7460             /* TODO: Name Space Fix ups
7461             if(!id.classSym)
7462                id.nameSpace = eSystem_FindNameSpace(privateModule, id._class.name);
7463             */
7464          }
7465
7466          /* WHY WAS THIS COMMENTED OUT? if(!strcmp(id.string, "__thisModule"))
7467          {
7468             exp.expType = ProcessTypeString("Module", true);
7469             break;
7470          }
7471          else */if(strstr(id.string, "__ecereClass") == id.string)
7472          {
7473             exp.expType = ProcessTypeString("ecere::com::Class", true);
7474             break;
7475          }
7476          else if(id._class && (id.classSym || (id._class.name && !strcmp(id._class.name, "property"))))
7477          {
7478             // Added this here as well
7479             ReplaceClassMembers(exp, thisClass);
7480             if(exp.type != identifierExp)
7481             {
7482                ProcessExpressionType(exp);
7483                break;
7484             }
7485
7486             if(id.classSym && ResolveIdWithClass(exp, id.classSym.registered, false))
7487                break;
7488          }
7489          else
7490          {
7491             Symbol symbol = FindSymbol(id.string, curContext, topContext /*exp.destType ? topContext : globalContext*/, false, id._class && id._class.name == null);
7492             // Enums should be resolved here (Special pass in opExp to fix identifiers not seen as enum on the first pass)
7493             if(!symbol/* && exp.destType*/)
7494             {
7495                if(exp.destType && CheckExpressionType(exp, exp.destType, false))
7496                   break;
7497                else
7498                {
7499                   if(thisClass)
7500                   {
7501                      ReplaceClassMembers(exp, thisClass ? thisClass : currentClass);
7502                      if(exp.type != identifierExp)
7503                      {
7504                         ProcessExpressionType(exp);
7505                         break;
7506                      }
7507                   }
7508                   // Static methods called from inside the _class
7509                   else if(currentClass && !id._class)
7510                   {
7511                      if(ResolveIdWithClass(exp, currentClass, true))
7512                         break;
7513                   }
7514                   symbol = FindSymbol(id.string, topContext.parent, globalContext, false, id._class && id._class.name == null);
7515                }
7516             }
7517
7518             // If we manage to resolve this symbol
7519             if(symbol)
7520             {
7521                Type type = symbol.type;
7522                Class _class = (type && type.kind == classType && type._class) ? type._class.registered : null;
7523
7524                if(_class && !strcmp(id.string, "this") && !type.classObjectType)
7525                {
7526                   Context context = SetupTemplatesContext(_class);
7527                   type = ReplaceThisClassType(_class);
7528                   FinishTemplatesContext(context);
7529                   if(type) type.refCount = 0;   // We'll be incrementing it right below...
7530                }
7531
7532                FreeSpecifier(id._class);
7533                id._class = null;
7534                delete id.string;
7535                id.string = CopyString(symbol.string);
7536
7537                id.classSym = null;
7538                exp.expType = type;
7539                if(type)
7540                   type.refCount++;
7541                if(type && (type.kind == enumType || (_class && _class.type == enumClass)))
7542                   // Add missing cases here... enum Classes...
7543                   exp.isConstant = true;
7544
7545                // TOCHECK: Why was !strcmp(id.string, "this") commented out?
7546                if(symbol.isParam || !strcmp(id.string, "this"))
7547                {
7548                   if(_class && _class.type == structClass && !type.declaredWithStruct)
7549                      exp.byReference = true;
7550
7551                   //TESTING COMMENTING THIS OUT IN FAVOR OF ApplyAnyObjectLogic
7552                   /*if(type && _class && (type.classObjectType == typedObject || type.classObjectType == anyObject) &&
7553                      ((_class.type == unitClass || _class.type == enumClass || _class.type == bitClass) ||
7554                      (type.byReference && (_class.type == normalClass || _class.type == noHeadClass))))
7555                   {
7556                      Identifier id = exp.identifier;
7557                      exp.type = bracketsExp;
7558                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(id)));
7559                   }*/
7560                }
7561
7562                if(symbol.isIterator)
7563                {
7564                   if(symbol.isIterator == 3)
7565                   {
7566                      exp.type = bracketsExp;
7567                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(exp.identifier)));
7568                      ((Expression)exp.list->first).op.exp2.expType = exp.expType;
7569                      exp.expType = null;
7570                      ProcessExpressionType(exp);
7571                   }
7572                   else if(symbol.isIterator != 4)
7573                   {
7574                      exp.type = memberExp;
7575                      exp.member.exp = MkExpIdentifier(exp.identifier);
7576                      exp.member.exp.expType = exp.expType;
7577                      /*if(symbol.isIterator == 6)
7578                         exp.member.member = MkIdentifier("key");
7579                      else*/
7580                         exp.member.member = MkIdentifier("data");
7581                      exp.expType = null;
7582                      ProcessExpressionType(exp);
7583                   }
7584                }
7585                break;
7586             }
7587             else
7588             {
7589                DefinedExpression definedExp = null;
7590                if(thisNameSpace && !(id._class && !id._class.name))
7591                {
7592                   char name[1024];
7593                   strcpy(name, thisNameSpace);
7594                   strcat(name, "::");
7595                   strcat(name, id.string);
7596                   definedExp = eSystem_FindDefine(privateModule, name);
7597                }
7598                if(!definedExp)
7599                   definedExp = eSystem_FindDefine(privateModule, id.string);
7600                if(definedExp)
7601                {
7602                   int c;
7603                   for(c = 0; c<definedExpStackPos; c++)
7604                      if(definedExpStack[c] == definedExp)
7605                         break;
7606                   if(c == definedExpStackPos && c < sizeof(definedExpStack) / sizeof(void *))
7607                   {
7608                      Location backupYylloc = yylloc;
7609                      File backInput = fileInput;
7610                      definedExpStack[definedExpStackPos++] = definedExp;
7611
7612                      fileInput = TempFile { };
7613                      fileInput.Write(definedExp.value, 1, strlen(definedExp.value));
7614                      fileInput.Seek(0, start);
7615
7616                      echoOn = false;
7617                      parsedExpression = null;
7618                      resetScanner();
7619                      expression_yyparse();
7620                      delete fileInput;
7621                      if(backInput)
7622                         fileInput = backInput;
7623
7624                      yylloc = backupYylloc;
7625
7626                      if(parsedExpression)
7627                      {
7628                         FreeIdentifier(id);
7629                         exp.type = bracketsExp;
7630                         exp.list = MkListOne(parsedExpression);
7631                         parsedExpression.loc = yylloc;
7632                         ProcessExpressionType(exp);
7633                         definedExpStackPos--;
7634                         return;
7635                      }
7636                      definedExpStackPos--;
7637                   }
7638                   else
7639                   {
7640                      if(inCompiler)
7641                      {
7642                         Compiler_Error($"Recursion in defined expression %s\n", id.string);
7643                      }
7644                   }
7645                }
7646                else
7647                {
7648                   GlobalData data = null;
7649                   if(thisNameSpace && !(id._class && !id._class.name))
7650                   {
7651                      char name[1024];
7652                      strcpy(name, thisNameSpace);
7653                      strcat(name, "::");
7654                      strcat(name, id.string);
7655                      data = FindGlobalData(name);
7656                   }
7657                   if(!data)
7658                      data = FindGlobalData(id.string);
7659                   if(data)
7660                   {
7661                      DeclareGlobalData(data);
7662                      exp.expType = data.dataType;
7663                      if(data.dataType) data.dataType.refCount++;
7664
7665                      delete id.string;
7666                      id.string = CopyString(data.fullName);
7667                      FreeSpecifier(id._class);
7668                      id._class = null;
7669
7670                      break;
7671                   }
7672                   else
7673                   {
7674                      GlobalFunction function = null;
7675                      if(thisNameSpace && !(id._class && !id._class.name))
7676                      {
7677                         char name[1024];
7678                         strcpy(name, thisNameSpace);
7679                         strcat(name, "::");
7680                         strcat(name, id.string);
7681                         function = eSystem_FindFunction(privateModule, name);
7682                      }
7683                      if(!function)
7684                         function = eSystem_FindFunction(privateModule, id.string);
7685                      if(function)
7686                      {
7687                         char name[1024];
7688                         delete id.string;
7689                         id.string = CopyString(function.name);
7690                         name[0] = 0;
7691
7692                         if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
7693                            strcpy(name, "__ecereFunction_");
7694                         FullClassNameCat(name, id.string, false); // Why is this using FullClassNameCat ?
7695                         if(DeclareFunction(function, name))
7696                         {
7697                            delete id.string;
7698                            id.string = CopyString(name);
7699                         }
7700                         exp.expType = function.dataType;
7701                         if(function.dataType) function.dataType.refCount++;
7702
7703                         FreeSpecifier(id._class);
7704                         id._class = null;
7705
7706                         break;
7707                      }
7708                   }
7709                }
7710             }
7711          }
7712          unresolved = true;
7713          break;
7714       }
7715       case instanceExp:
7716       {
7717          Class _class;
7718          // Symbol classSym;
7719
7720          if(!exp.instance._class)
7721          {
7722             if(exp.destType && exp.destType.kind == classType && exp.destType._class)
7723             {
7724                exp.instance._class = MkSpecifierName(exp.destType._class.string);
7725             }
7726          }
7727
7728          //classSym = FindClass(exp.instance._class.fullName);
7729          //_class = classSym ? classSym.registered : null;
7730
7731          ProcessInstantiationType(exp.instance);
7732          exp.isConstant = exp.instance.isConstant;
7733
7734          /*
7735          if(_class.type == unitClass && _class.base.type != systemClass)
7736          {
7737             {
7738                Type destType = exp.destType;
7739
7740                exp.destType = MkClassType(_class.base.fullName);
7741                exp.expType = MkClassType(_class.fullName);
7742                CheckExpressionType(exp, exp.destType, true);
7743
7744                exp.destType = destType;
7745             }
7746             exp.expType = MkClassType(_class.fullName);
7747          }
7748          else*/
7749          if(exp.instance._class)
7750          {
7751             exp.expType = MkClassType(exp.instance._class.name);
7752             /*if(exp.expType._class && exp.expType._class.registered &&
7753                (exp.expType._class.registered.type == normalClass || exp.expType._class.registered.type == noHeadClass))
7754                exp.expType.byReference = true;*/
7755          }
7756          break;
7757       }
7758       case constantExp:
7759       {
7760          if(!exp.expType)
7761          {
7762             char * constant = exp.constant;
7763             Type type
7764             {
7765                refCount = 1;
7766                constant = true;
7767             };
7768             exp.expType = type;
7769
7770             if(constant[0] == '\'')
7771             {
7772                if((int)((byte *)constant)[1] > 127)
7773                {
7774                   int nb;
7775                   unichar ch = UTF8GetChar(constant + 1, &nb);
7776                   if(nb < 2) ch = constant[1];
7777                   delete constant;
7778                   exp.constant = PrintUInt(ch);
7779                   // type.kind = (ch > 0xFFFF) ? intType : shortType;
7780                   type.kind = classType; //(ch > 0xFFFF) ? intType : shortType;
7781                   type._class = FindClass("unichar");
7782
7783                   type.isSigned = false;
7784                }
7785                else
7786                {
7787                   type.kind = charType;
7788                   type.isSigned = true;
7789                }
7790             }
7791             else
7792             {
7793                char * dot = strchr(constant, '.');
7794                bool isHex = (constant[0] == '0' && (constant[1] == 'x' || constant[1] == 'X'));
7795                char * exponent;
7796                if(isHex)
7797                {
7798                   exponent = strchr(constant, 'p');
7799                   if(!exponent) exponent = strchr(constant, 'P');
7800                }
7801                else
7802                {
7803                   exponent = strchr(constant, 'e');
7804                   if(!exponent) exponent = strchr(constant, 'E');
7805                }
7806
7807                if(dot || exponent)
7808                {
7809                   if(strchr(constant, 'f') || strchr(constant, 'F'))
7810                      type.kind = floatType;
7811                   else
7812                      type.kind = doubleType;
7813                   type.isSigned = true;
7814                }
7815                else
7816                {
7817                   bool isSigned = constant[0] == '-';
7818                   int64 i64 = strtoll(constant, null, 0);
7819                   uint64 ui64 = strtoull(constant, null, 0);
7820                   bool is64Bit = false;
7821                   if(isSigned)
7822                   {
7823                      if(i64 < MININT)
7824                         is64Bit = true;
7825                   }
7826                   else
7827                   {
7828                      if(ui64 > MAXINT)
7829                      {
7830                         if(ui64 > MAXDWORD)
7831                         {
7832                            is64Bit = true;
7833                            if(ui64 <= MAXINT64 && (constant[0] != '0' || !constant[1]))
7834                               isSigned = true;
7835                         }
7836                      }
7837                      else if(constant[0] != '0' || !constant[1])
7838                         isSigned = true;
7839                   }
7840                   type.kind = is64Bit ? int64Type : intType;
7841                   type.isSigned = isSigned;
7842                }
7843             }
7844             exp.isConstant = true;
7845             if(exp.destType && exp.destType.kind == doubleType)
7846                type.kind = doubleType;
7847             else if(exp.destType && exp.destType.kind == floatType)
7848                type.kind = floatType;
7849             else if(exp.destType && exp.destType.kind == int64Type)
7850                type.kind = int64Type;
7851          }
7852          break;
7853       }
7854       case stringExp:
7855       {
7856          exp.isConstant = true;      // Why wasn't this constant?
7857          exp.expType = Type
7858          {
7859             refCount = 1;
7860             kind = pointerType;
7861             type = Type
7862             {
7863                refCount = 1;
7864                kind = charType;
7865                constant = true;
7866                isSigned = true;
7867             }
7868          };
7869          break;
7870       }
7871       case newExp:
7872       case new0Exp:
7873          ProcessExpressionType(exp._new.size);
7874          exp.expType = Type
7875          {
7876             refCount = 1;
7877             kind = pointerType;
7878             type = ProcessType(exp._new.typeName.qualifiers, exp._new.typeName.declarator);
7879          };
7880          DeclareType(exp.expType.type, false, false);
7881          break;
7882       case renewExp:
7883       case renew0Exp:
7884          ProcessExpressionType(exp._renew.size);
7885          ProcessExpressionType(exp._renew.exp);
7886          exp.expType = Type
7887          {
7888             refCount = 1;
7889             kind = pointerType;
7890             type = ProcessType(exp._renew.typeName.qualifiers, exp._renew.typeName.declarator);
7891          };
7892          DeclareType(exp.expType.type, false, false);
7893          break;
7894       case opExp:
7895       {
7896          bool assign = false, boolResult = false, boolOps = false;
7897          Type type1 = null, type2 = null;
7898          bool useDestType = false, useSideType = false;
7899          Location oldyylloc = yylloc;
7900          bool useSideUnit = false;
7901
7902          // Dummy type to prevent ProcessExpression of operands to say unresolved identifiers yet
7903          Type dummy
7904          {
7905             count = 1;
7906             refCount = 1;
7907          };
7908
7909          switch(exp.op.op)
7910          {
7911             // Assignment Operators
7912             case '=':
7913             case MUL_ASSIGN:
7914             case DIV_ASSIGN:
7915             case MOD_ASSIGN:
7916             case ADD_ASSIGN:
7917             case SUB_ASSIGN:
7918             case LEFT_ASSIGN:
7919             case RIGHT_ASSIGN:
7920             case AND_ASSIGN:
7921             case XOR_ASSIGN:
7922             case OR_ASSIGN:
7923                assign = true;
7924                break;
7925             // boolean Operators
7926             case '!':
7927                // Expect boolean operators
7928                //boolOps = true;
7929                //boolResult = true;
7930                break;
7931             case AND_OP:
7932             case OR_OP:
7933                // Expect boolean operands
7934                boolOps = true;
7935                boolResult = true;
7936                break;
7937             // Comparisons
7938             case EQ_OP:
7939             case '<':
7940             case '>':
7941             case LE_OP:
7942             case GE_OP:
7943             case NE_OP:
7944                // Gives boolean result
7945                boolResult = true;
7946                useSideType = true;
7947                break;
7948             case '+':
7949             case '-':
7950                useSideUnit = true;
7951
7952                // Just added these... testing
7953             case '|':
7954             case '&':
7955             case '^':
7956
7957             // DANGER: Verify units
7958             case '/':
7959             case '%':
7960             case '*':
7961
7962                if(exp.op.op != '*' || exp.op.exp1)
7963                {
7964                   useSideType = true;
7965                   useDestType = true;
7966                }
7967                break;
7968
7969             /*// Implement speed etc.
7970             case '*':
7971             case '/':
7972                break;
7973             */
7974          }
7975          if(exp.op.op == '&')
7976          {
7977             // Added this here earlier for Iterator address as key
7978             if(!exp.op.exp1 && exp.op.exp2 && exp.op.exp2.type == identifierExp && exp.op.exp2.identifier)
7979             {
7980                Identifier id = exp.op.exp2.identifier;
7981                Symbol symbol = FindSymbol(id.string, curContext, topContext, false, id._class && id._class.name == null);
7982                if(symbol && symbol.isIterator == 2)
7983                {
7984                   exp.type = memberExp;
7985                   exp.member.exp = exp.op.exp2;
7986                   exp.member.member = MkIdentifier("key");
7987                   exp.expType = null;
7988                   exp.op.exp2.expType = symbol.type;
7989                   symbol.type.refCount++;
7990                   ProcessExpressionType(exp);
7991                   FreeType(dummy);
7992                   break;
7993                }
7994                // exp.op.exp2.usage.usageRef = true;
7995             }
7996          }
7997
7998          //dummy.kind = TypeDummy;
7999
8000          if(exp.op.exp1)
8001          {
8002             if(exp.destType && exp.destType.kind == classType &&
8003                exp.destType._class && exp.destType._class.registered && useDestType &&
8004
8005               ((exp.destType._class.registered.type == unitClass && useSideUnit) ||
8006                exp.destType._class.registered.type == enumClass ||
8007                exp.destType._class.registered.type == bitClass
8008                ))
8009
8010               //(exp.destType._class.registered.type == unitClass || exp.destType._class.registered.type == enumClass) && useDestType)
8011             {
8012                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8013                exp.op.exp1.destType = exp.destType;
8014                if(exp.destType)
8015                   exp.destType.refCount++;
8016             }
8017             else if(!assign)
8018             {
8019                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8020                exp.op.exp1.destType = dummy;
8021                dummy.refCount++;
8022             }
8023
8024             // TESTING THIS HERE...
8025             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count++;
8026             ProcessExpressionType(exp.op.exp1);
8027             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count--;
8028
8029             if(exp.op.exp1.destType == dummy)
8030             {
8031                FreeType(dummy);
8032                exp.op.exp1.destType = null;
8033             }
8034             type1 = exp.op.exp1.expType;
8035          }
8036
8037          if(exp.op.exp2)
8038          {
8039             char expString[10240];
8040             expString[0] = '\0';
8041             if(exp.op.exp2.type == instanceExp && !exp.op.exp2.instance._class)
8042             {
8043                if(exp.op.exp1)
8044                {
8045                   exp.op.exp2.destType = exp.op.exp1.expType;
8046                   if(exp.op.exp1.expType)
8047                      exp.op.exp1.expType.refCount++;
8048                }
8049                else
8050                {
8051                   exp.op.exp2.destType = exp.destType;
8052                   if(exp.destType)
8053                      exp.destType.refCount++;
8054                }
8055
8056                if(type1) type1.refCount++;
8057                exp.expType = type1;
8058             }
8059             else if(assign)
8060             {
8061                if(inCompiler)
8062                   PrintExpression(exp.op.exp2, expString);
8063
8064                if(type1 && type1.kind == pointerType)
8065                {
8066                   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 ||
8067                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN)
8068                      Compiler_Error($"operator %s illegal on pointer\n", exp.op.op);
8069                   else if(exp.op.op == '=')
8070                   {
8071                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8072                      exp.op.exp2.destType = type1;
8073                      if(type1)
8074                         type1.refCount++;
8075                   }
8076                }
8077                else
8078                {
8079                   // Don't convert to the type for those... (e.g.: Degrees a; a /= 2;)
8080                   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/* ||
8081                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN*/);
8082                   else
8083                   {
8084                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8085                      exp.op.exp2.destType = type1;
8086                      if(type1)
8087                         type1.refCount++;
8088                   }
8089                }
8090                if(type1) type1.refCount++;
8091                exp.expType = type1;
8092             }
8093             else if(exp.destType && exp.destType.kind == classType &&
8094                exp.destType._class && exp.destType._class.registered &&
8095
8096                   ((exp.destType._class.registered.type == unitClass && useDestType && useSideUnit) ||
8097                   (exp.destType._class.registered.type == enumClass && useDestType))
8098                   )
8099             {
8100                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8101                exp.op.exp2.destType = exp.destType;
8102                if(exp.destType)
8103                   exp.destType.refCount++;
8104             }
8105             else
8106             {
8107                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8108                exp.op.exp2.destType = dummy;
8109                dummy.refCount++;
8110             }
8111
8112             // TESTING THIS HERE... (DANGEROUS)
8113             if(type1 && boolResult && useSideType && type1.kind == classType && type1._class && type1._class.registered &&
8114                (type1._class.registered.type == bitClass || type1._class.registered.type == enumClass))
8115             {
8116                FreeType(exp.op.exp2.destType);
8117                exp.op.exp2.destType = type1;
8118                type1.refCount++;
8119             }
8120             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count++;
8121             // Cannot lose the cast on a sizeof
8122             if(exp.op.op == SIZEOF)
8123             {
8124                Expression e = exp.op.exp2;
8125                while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
8126                {
8127                   if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
8128                   {
8129                      if(e.type == extensionCompoundExp)
8130                         e = ((Statement)e.compound.compound.statements->last).expressions->last;
8131                      else
8132                         e = e.list->last;
8133                   }
8134                }
8135                if(e.type == castExp && e.cast.exp)
8136                   e.cast.exp.needCast = true;
8137             }
8138             ProcessExpressionType(exp.op.exp2);
8139             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count--;
8140
8141             if(assign && type1 && type1.kind == pointerType && exp.op.exp2.expType)
8142             {
8143                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)
8144                {
8145                   if(exp.op.op != '=' && type1.type.kind == voidType)
8146                      Compiler_Error($"void *: unknown size\n");
8147                }
8148                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||
8149                            (type1.type.kind == voidType && exp.op.exp2.expType.kind == classType && exp.op.exp2.expType._class.registered &&
8150                               (exp.op.exp2.expType._class.registered.type == normalClass ||
8151                               exp.op.exp2.expType._class.registered.type == structClass ||
8152                               exp.op.exp2.expType._class.registered.type == noHeadClass)))
8153                {
8154                   if(exp.op.op == ADD_ASSIGN)
8155                      Compiler_Error($"cannot add two pointers\n");
8156                }
8157                else if((exp.op.exp2.expType.kind == classType && type1.kind == pointerType && type1.type.kind == classType &&
8158                   type1.type._class == exp.op.exp2.expType._class && exp.op.exp2.expType._class.registered && exp.op.exp2.expType._class.registered.type == structClass))
8159                {
8160                   if(exp.op.op == ADD_ASSIGN)
8161                      Compiler_Error($"cannot add two pointers\n");
8162                }
8163                else if(inCompiler)
8164                {
8165                   char type1String[1024];
8166                   char type2String[1024];
8167                   type1String[0] = '\0';
8168                   type2String[0] = '\0';
8169
8170                   PrintType(exp.op.exp2.expType, type1String, false, true);
8171                   PrintType(type1, type2String, false, true);
8172                   ChangeCh(expString, '\n', ' ');
8173                   Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1String, type2String);
8174                }
8175             }
8176
8177             if(exp.op.exp2.destType == dummy)
8178             {
8179                FreeType(dummy);
8180                exp.op.exp2.destType = null;
8181             }
8182
8183             if(exp.op.op == '-' && !exp.op.exp1 && exp.op.exp2.expType && !exp.op.exp2.expType.isSigned)
8184             {
8185                type2 = { };
8186                type2.refCount = 1;
8187                CopyTypeInto(type2, exp.op.exp2.expType);
8188                type2.isSigned = true;
8189             }
8190             else if(exp.op.op == '~' && !exp.op.exp1 && exp.op.exp2.expType && (!exp.op.exp2.expType.isSigned || exp.op.exp2.expType.kind != intType))
8191             {
8192                type2 = { kind = intType };
8193                type2.refCount = 1;
8194                type2.isSigned = true;
8195             }
8196             else
8197             {
8198                type2 = exp.op.exp2.expType;
8199                if(type2) type2.refCount++;
8200             }
8201          }
8202
8203          dummy.kind = voidType;
8204
8205          if(exp.op.op == SIZEOF)
8206          {
8207             exp.expType = Type
8208             {
8209                refCount = 1;
8210                kind = intType;
8211             };
8212             exp.isConstant = true;
8213          }
8214          // Get type of dereferenced pointer
8215          else if(exp.op.op == '*' && !exp.op.exp1)
8216          {
8217             exp.expType = Dereference(type2);
8218             if(type2 && type2.kind == classType)
8219                notByReference = true;
8220          }
8221          else if(exp.op.op == '&' && !exp.op.exp1)
8222             exp.expType = Reference(type2);
8223          else if(!assign)
8224          {
8225             if(boolOps)
8226             {
8227                if(exp.op.exp1)
8228                {
8229                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8230                   exp.op.exp1.destType = MkClassType("bool");
8231                   exp.op.exp1.destType.truth = true;
8232                   if(!exp.op.exp1.expType)
8233                      ProcessExpressionType(exp.op.exp1);
8234                   else
8235                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8236                   FreeType(exp.op.exp1.expType);
8237                   exp.op.exp1.expType = MkClassType("bool");
8238                   exp.op.exp1.expType.truth = true;
8239                }
8240                if(exp.op.exp2)
8241                {
8242                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8243                   exp.op.exp2.destType = MkClassType("bool");
8244                   exp.op.exp2.destType.truth = true;
8245                   if(!exp.op.exp2.expType)
8246                      ProcessExpressionType(exp.op.exp2);
8247                   else
8248                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8249                   FreeType(exp.op.exp2.expType);
8250                   exp.op.exp2.expType = MkClassType("bool");
8251                   exp.op.exp2.expType.truth = true;
8252                }
8253             }
8254             else if(exp.op.exp1 && exp.op.exp2 &&
8255                ((useSideType /*&&
8256                      (useSideUnit ||
8257                         ((!type1 || type1.kind != classType || type1._class.registered.type != unitClass) &&
8258                          (!type2 || type2.kind != classType || type2._class.registered.type != unitClass)))*/) ||
8259                   ((!type1 || type1.kind != classType || !strcmp(type1._class.string, "String")) &&
8260                   (!type2 || type2.kind != classType || !strcmp(type2._class.string, "String")))))
8261             {
8262                if(type1 && type2 &&
8263                   // If either both are class or both are not class
8264                   ((type1.kind == classType && type1._class && strcmp(type1._class.string, "String")) == (type2.kind == classType && type2._class && strcmp(type2._class.string, "String"))))
8265                {
8266                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8267                   exp.op.exp2.destType = type1;
8268                   type1.refCount++;
8269                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8270                   exp.op.exp1.destType = type2;
8271                   type2.refCount++;
8272                   // Warning here for adding Radians + Degrees with no destination type
8273                   if(!boolResult && type1.kind == classType && (!exp.destType || exp.destType.kind != classType) &&
8274                      type1._class.registered && type1._class.registered.type == unitClass &&
8275                      type2._class.registered && type2._class.registered.type == unitClass &&
8276                      type1._class.registered != type2._class.registered)
8277                      Compiler_Warning($"operating on %s and %s with an untyped result, assuming %s\n",
8278                         type1._class.string, type2._class.string, type1._class.string);
8279
8280                   if(type1.kind == pointerType && type1.type.kind == templateType && type2.kind != pointerType)
8281                   {
8282                      Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8283                      if(argExp)
8284                      {
8285                         Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8286
8287                         exp.op.exp1 = MkExpBrackets(MkListOne(MkExpCast(
8288                            MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
8289                            exp.op.exp1)));
8290
8291                         ProcessExpressionType(exp.op.exp1);
8292
8293                         if(type2.kind != pointerType)
8294                         {
8295                            ProcessExpressionType(classExp);
8296
8297                            exp.op.exp2 = MkExpBrackets(MkListOne(MkExpOp(exp.op.exp2, '*',
8298                               // ((_class.type == noHeadClass || _class.type == normalClass) ? sizeof(void *) : type.size)
8299                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(MkExpOp(
8300                                  // noHeadClass
8301                                  MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpConstant("5")),
8302                                     OR_OP,
8303                                  // normalClass
8304                                  MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpConstant("0"))))),
8305                                     MkListOne(MkExpTypeSize(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(
8306                                        MkPointer(null, null), null)))),
8307                                        MkExpMember(classExp, MkIdentifier("typeSize"))))))));
8308
8309                            if(!exp.op.exp2.expType)
8310                            {
8311                               if(type2)
8312                                  FreeType(type2);
8313                               type2 = exp.op.exp2.expType = ProcessTypeString("int", false);
8314                               type2.refCount++;
8315                            }
8316
8317                            ProcessExpressionType(exp.op.exp2);
8318                         }
8319                      }
8320                   }
8321
8322                   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)))
8323                   {
8324                      if(type1.kind != classType && type1.type.kind == voidType)
8325                         Compiler_Error($"void *: unknown size\n");
8326                      exp.expType = type1;
8327                      if(type1) type1.refCount++;
8328                   }
8329                   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)))
8330                   {
8331                      if(type2.kind != classType && type2.type.kind == voidType)
8332                         Compiler_Error($"void *: unknown size\n");
8333                      exp.expType = type2;
8334                      if(type2) type2.refCount++;
8335                   }
8336                   else if((type1.kind == pointerType && type2.kind != pointerType && type2.kind != arrayType && type2.kind != functionType && type2.kind != methodType && type2.kind != classType && type2.kind != subClassType) ||
8337                           (type2.kind == pointerType && type1.kind != pointerType && type1.kind != arrayType && type1.kind != functionType && type1.kind != methodType && type1.kind != classType && type1.kind != subClassType))
8338                   {
8339                      Compiler_Warning($"different levels of indirection\n");
8340                   }
8341                   else
8342                   {
8343                      bool success = false;
8344                      if(type1.kind == pointerType && type2.kind == pointerType)
8345                      {
8346                         if(exp.op.op == '+')
8347                            Compiler_Error($"cannot add two pointers\n");
8348                         else if(exp.op.op == '-')
8349                         {
8350                            // Pointer Subtraction gives integer
8351                            if(MatchTypes(type1.type, type2.type, null, null, null, false, false, false, false))
8352                            {
8353                               exp.expType = Type
8354                               {
8355                                  kind = intType;
8356                                  refCount = 1;
8357                               };
8358                               success = true;
8359
8360                               if(type1.type.kind == templateType)
8361                               {
8362                                  Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8363                                  if(argExp)
8364                                  {
8365                                     Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8366
8367                                     ProcessExpressionType(classExp);
8368
8369                                     exp.type = bracketsExp;
8370                                     exp.list = MkListOne(MkExpOp(
8371                                        MkExpBrackets(MkListOne(MkExpOp(
8372                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp1)))
8373                                              , exp.op.op,
8374                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp2)))))), '/',
8375
8376                                              //MkExpMember(classExp, MkIdentifier("typeSize"))
8377
8378                                              // ((_class.type == noHeadClass || _class.type == normalClass) ? sizeof(void *) : type.size)
8379                                              MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(MkExpOp(
8380                                                 // noHeadClass
8381                                                 MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpIdentifier(MkIdentifier("noHeadClass"))),
8382                                                    OR_OP,
8383                                                 // normalClass
8384                                                 MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpIdentifier(MkIdentifier("normalClass")))))),
8385                                                    MkListOne(MkExpTypeSize(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(
8386                                                       MkPointer(null, null), null)))),
8387                                                       MkExpMember(classExp, MkIdentifier("typeSize")))))
8388
8389
8390                                              ));
8391
8392                                     ProcessExpressionType(((Expression)exp.list->first).op.exp2);
8393                                     FreeType(dummy);
8394                                     return;
8395                                  }
8396                               }
8397                            }
8398                         }
8399                      }
8400
8401                      if(!success && exp.op.exp1.type == constantExp)
8402                      {
8403                         // If first expression is constant, try to match that first
8404                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8405                         {
8406                            if(exp.expType) FreeType(exp.expType);
8407                            exp.expType = exp.op.exp1.destType;
8408                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8409                            success = true;
8410                         }
8411                         else if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8412                         {
8413                            if(exp.expType) FreeType(exp.expType);
8414                            exp.expType = exp.op.exp2.destType;
8415                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8416                            success = true;
8417                         }
8418                      }
8419                      else if(!success)
8420                      {
8421                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8422                         {
8423                            if(exp.expType) FreeType(exp.expType);
8424                            exp.expType = exp.op.exp2.destType;
8425                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8426                            success = true;
8427                         }
8428                         else if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8429                         {
8430                            if(exp.expType) FreeType(exp.expType);
8431                            exp.expType = exp.op.exp1.destType;
8432                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8433                            success = true;
8434                         }
8435                      }
8436                      if(!success)
8437                      {
8438                         char expString1[10240];
8439                         char expString2[10240];
8440                         char type1[1024];
8441                         char type2[1024];
8442                         expString1[0] = '\0';
8443                         expString2[0] = '\0';
8444                         type1[0] = '\0';
8445                         type2[0] = '\0';
8446                         if(inCompiler)
8447                         {
8448                            PrintExpression(exp.op.exp1, expString1);
8449                            ChangeCh(expString1, '\n', ' ');
8450                            PrintExpression(exp.op.exp2, expString2);
8451                            ChangeCh(expString2, '\n', ' ');
8452                            PrintType(exp.op.exp1.expType, type1, false, true);
8453                            PrintType(exp.op.exp2.expType, type2, false, true);
8454                         }
8455
8456                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1, expString2, type2);
8457                      }
8458                   }
8459                }
8460                // ADDED THESE TWO FROM OUTSIDE useSideType CHECK
8461                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type2 && type1 && type2.kind == classType && type1.kind != classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
8462                {
8463                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8464                   // Convert e.g. / 4 into / 4.0
8465                   exp.op.exp1.destType = type2._class.registered.dataType;
8466                   if(type2._class.registered.dataType)
8467                      type2._class.registered.dataType.refCount++;
8468                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8469                   exp.expType = type2;
8470                   if(type2) type2.refCount++;
8471                }
8472                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type1 && type2 && type1.kind == classType && type2.kind != classType && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
8473                {
8474                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8475                   // Convert e.g. / 4 into / 4.0
8476                   exp.op.exp2.destType = type1._class.registered.dataType;
8477                   if(type1._class.registered.dataType)
8478                      type1._class.registered.dataType.refCount++;
8479                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8480                   exp.expType = type1;
8481                   if(type1) type1.refCount++;
8482                }
8483                else if(type1)
8484                {
8485                   bool valid = false;
8486
8487                   if(!boolResult && useSideUnit && type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8488                   {
8489                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8490
8491                      if(!type1._class.registered.dataType)
8492                         type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
8493                      exp.op.exp2.destType = type1._class.registered.dataType;
8494                      exp.op.exp2.destType.refCount++;
8495
8496                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8497                      if(type2)
8498                         FreeType(type2);
8499                      type2 = exp.op.exp2.destType;
8500                      if(type2) type2.refCount++;
8501
8502                      exp.expType = type2;
8503                      type2.refCount++;
8504                   }
8505
8506                   if(!boolResult && useSideUnit && type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8507                   {
8508                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8509
8510                      if(!type2._class.registered.dataType)
8511                         type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
8512                      exp.op.exp1.destType = type2._class.registered.dataType;
8513                      exp.op.exp1.destType.refCount++;
8514
8515                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8516                      type1 = exp.op.exp1.destType;
8517                      exp.expType = type1;
8518                      type1.refCount++;
8519                   }
8520
8521                   // TESTING THIS NEW CODE
8522                   if(!boolResult || exp.op.op == '>' || exp.op.op == '<')
8523                   {
8524                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass && exp.op.exp2.expType)
8525                      {
8526                         if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false))
8527                         {
8528                            if(exp.expType) FreeType(exp.expType);
8529                            exp.expType = exp.op.exp1.expType;
8530                            if(exp.op.exp2.expType) exp.op.exp1.expType.refCount++;
8531                            valid = true;
8532                         }
8533                      }
8534
8535                      else if(type2 && (type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass && exp.op.exp1.expType))
8536                      {
8537                         if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false))
8538                         {
8539                            if(exp.expType) FreeType(exp.expType);
8540                            exp.expType = exp.op.exp2.expType;
8541                            if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8542                            valid = true;
8543                         }
8544                      }
8545                   }
8546
8547                   if(!valid)
8548                   {
8549                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8550                      exp.op.exp2.destType = type1;
8551                      type1.refCount++;
8552
8553                      /*
8554                      // Maybe this was meant to be an enum...
8555                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
8556                      {
8557                         Type oldType = exp.op.exp2.expType;
8558                         exp.op.exp2.expType = null;
8559                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8560                            FreeType(oldType);
8561                         else
8562                            exp.op.exp2.expType = oldType;
8563                      }
8564                      */
8565
8566                      /*
8567                      // TESTING THIS HERE... LATEST ADDITION
8568                      if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8569                      {
8570                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8571                         exp.op.exp2.destType = type2._class.registered.dataType;
8572                         if(type2._class.registered.dataType)
8573                            type2._class.registered.dataType.refCount++;
8574                         CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8575
8576                         //exp.expType = type2._class.registered.dataType; //type2;
8577                         //if(type2) type2.refCount++;
8578                      }
8579
8580                      // TESTING THIS HERE... LATEST ADDITION
8581                      if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8582                      {
8583                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8584                         exp.op.exp1.destType = type1._class.registered.dataType;
8585                         if(type1._class.registered.dataType)
8586                            type1._class.registered.dataType.refCount++;
8587                         CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8588                         exp.expType = type1._class.registered.dataType; //type1;
8589                         if(type1) type1.refCount++;
8590                      }
8591                      */
8592
8593                      if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8594                      {
8595                         if(exp.expType) FreeType(exp.expType);
8596                         exp.expType = exp.op.exp2.destType;
8597                         if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8598                      }
8599                      else if(type1 && type2)
8600                      {
8601                         char expString1[10240];
8602                         char expString2[10240];
8603                         char type1String[1024];
8604                         char type2String[1024];
8605                         expString1[0] = '\0';
8606                         expString2[0] = '\0';
8607                         type1String[0] = '\0';
8608                         type2String[0] = '\0';
8609                         if(inCompiler)
8610                         {
8611                            PrintExpression(exp.op.exp1, expString1);
8612                            ChangeCh(expString1, '\n', ' ');
8613                            PrintExpression(exp.op.exp2, expString2);
8614                            ChangeCh(expString2, '\n', ' ');
8615                            PrintType(exp.op.exp1.expType, type1String, false, true);
8616                            PrintType(exp.op.exp2.expType, type2String, false, true);
8617                         }
8618
8619                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1String, expString2, type2String);
8620
8621                         if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
8622                         {
8623                            exp.expType = exp.op.exp1.expType;
8624                            if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8625                         }
8626                         else if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
8627                         {
8628                            exp.expType = exp.op.exp2.expType;
8629                            if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8630                         }
8631                      }
8632                   }
8633                }
8634                else if(type2)
8635                {
8636                   // Maybe this was meant to be an enum...
8637                   if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
8638                   {
8639                      Type oldType = exp.op.exp1.expType;
8640                      exp.op.exp1.expType = null;
8641                      if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8642                         FreeType(oldType);
8643                      else
8644                         exp.op.exp1.expType = oldType;
8645                   }
8646
8647                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8648                   exp.op.exp1.destType = type2;
8649                   type2.refCount++;
8650                   /*
8651                   // TESTING THIS HERE... LATEST ADDITION
8652                   if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8653                   {
8654                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8655                      exp.op.exp1.destType = type1._class.registered.dataType;
8656                      if(type1._class.registered.dataType)
8657                         type1._class.registered.dataType.refCount++;
8658                   }
8659
8660                   // TESTING THIS HERE... LATEST ADDITION
8661                   if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8662                   {
8663                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8664                      exp.op.exp2.destType = type2._class.registered.dataType;
8665                      if(type2._class.registered.dataType)
8666                         type2._class.registered.dataType.refCount++;
8667                   }
8668                   */
8669
8670                   if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8671                   {
8672                      if(exp.expType) FreeType(exp.expType);
8673                      exp.expType = exp.op.exp1.destType;
8674                      if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8675                   }
8676                }
8677             }
8678             else if(type2 && (!type1 || (type2.kind == classType && type1.kind != classType)))
8679             {
8680                if(type1 && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
8681                {
8682                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8683                   // Convert e.g. / 4 into / 4.0
8684                   exp.op.exp1.destType = type2._class.registered.dataType;
8685                   if(type2._class.registered.dataType)
8686                      type2._class.registered.dataType.refCount++;
8687                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8688                }
8689                if(exp.op.op == '!')
8690                {
8691                   exp.expType = MkClassType("bool");
8692                   exp.expType.truth = true;
8693                }
8694                else
8695                {
8696                   exp.expType = type2;
8697                   if(type2) type2.refCount++;
8698                }
8699             }
8700             else if(type1 && (!type2 || (type1.kind == classType && type2.kind != classType)))
8701             {
8702                if(type2 && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
8703                {
8704                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8705                   // Convert e.g. / 4 into / 4.0
8706                   exp.op.exp2.destType = type1._class.registered.dataType;
8707                   if(type1._class.registered.dataType)
8708                      type1._class.registered.dataType.refCount++;
8709                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8710                }
8711                exp.expType = type1;
8712                if(type1) type1.refCount++;
8713             }
8714          }
8715
8716          yylloc = exp.loc;
8717          if(exp.op.exp1 && !exp.op.exp1.expType)
8718          {
8719             char expString[10000];
8720             expString[0] = '\0';
8721             if(inCompiler)
8722             {
8723                PrintExpression(exp.op.exp1, expString);
8724                ChangeCh(expString, '\n', ' ');
8725             }
8726             if(expString[0])
8727                Compiler_Error($"couldn't determine type of %s\n", expString);
8728          }
8729          if(exp.op.exp2 && !exp.op.exp2.expType)
8730          {
8731             char expString[10240];
8732             expString[0] = '\0';
8733             if(inCompiler)
8734             {
8735                PrintExpression(exp.op.exp2, expString);
8736                ChangeCh(expString, '\n', ' ');
8737             }
8738             if(expString[0])
8739                Compiler_Error($"couldn't determine type of %s\n", expString);
8740          }
8741
8742          if(boolResult)
8743          {
8744             FreeType(exp.expType);
8745             exp.expType = MkClassType("bool");
8746             exp.expType.truth = true;
8747          }
8748
8749          if(exp.op.op != SIZEOF)
8750             exp.isConstant = (!exp.op.exp1 || exp.op.exp1.isConstant) &&
8751                (!exp.op.exp2 || exp.op.exp2.isConstant);
8752
8753          if(exp.op.op == SIZEOF && exp.op.exp2.expType)
8754          {
8755             DeclareType(exp.op.exp2.expType, false, false);
8756          }
8757
8758          yylloc = oldyylloc;
8759
8760          FreeType(dummy);
8761          if(type2)
8762             FreeType(type2);
8763          break;
8764       }
8765       case bracketsExp:
8766       case extensionExpressionExp:
8767       {
8768          Expression e;
8769          exp.isConstant = true;
8770          for(e = exp.list->first; e; e = e.next)
8771          {
8772             bool inced = false;
8773             if(!e.next)
8774             {
8775                FreeType(e.destType);
8776                e.destType = exp.destType;
8777                if(e.destType) { exp.destType.refCount++; e.destType.count++; inced = true; }
8778             }
8779             ProcessExpressionType(e);
8780             if(inced)
8781                exp.destType.count--;
8782             if(!exp.expType && !e.next)
8783             {
8784                exp.expType = e.expType;
8785                if(e.expType) e.expType.refCount++;
8786             }
8787             if(!e.isConstant)
8788                exp.isConstant = false;
8789          }
8790
8791          // In case a cast became a member...
8792          e = exp.list->first;
8793          if(!e.next && e.type == memberExp)
8794          {
8795             // Preserve prev, next
8796             Expression next = exp.next, prev = exp.prev;
8797
8798
8799             FreeType(exp.expType);
8800             FreeType(exp.destType);
8801             delete exp.list;
8802
8803             *exp = *e;
8804
8805             exp.prev = prev;
8806             exp.next = next;
8807
8808             delete e;
8809
8810             ProcessExpressionType(exp);
8811          }
8812          break;
8813       }
8814       case indexExp:
8815       {
8816          Expression e;
8817          exp.isConstant = true;
8818
8819          ProcessExpressionType(exp.index.exp);
8820          if(!exp.index.exp.isConstant)
8821             exp.isConstant = false;
8822
8823          if(exp.index.exp.expType)
8824          {
8825             Type source = exp.index.exp.expType;
8826             if(source.kind == classType && source._class && source._class.registered)
8827             {
8828                Class _class = source._class.registered;
8829                Class c = _class.templateClass ? _class.templateClass : _class;
8830                if(_class != containerClass && eClass_IsDerived(c, containerClass) && _class.templateArgs)
8831                {
8832                   exp.expType = ProcessTypeString(_class.templateArgs[2].dataTypeString, false);
8833
8834                   if(exp.index.index && exp.index.index->last)
8835                   {
8836                      ((Expression)exp.index.index->last).destType = ProcessTypeString(_class.templateArgs[1].dataTypeString, false);
8837                   }
8838                }
8839             }
8840          }
8841
8842          for(e = exp.index.index->first; e; e = e.next)
8843          {
8844             if(!e.next && exp.index.exp.expType && exp.index.exp.expType.kind == arrayType && exp.index.exp.expType.enumClass)
8845             {
8846                if(e.destType) FreeType(e.destType);
8847                e.destType = MkClassType(exp.index.exp.expType.enumClass.string);
8848             }
8849             ProcessExpressionType(e);
8850             if(!e.next)
8851             {
8852                // Check if this type is int
8853             }
8854             if(!e.isConstant)
8855                exp.isConstant = false;
8856          }
8857
8858          if(!exp.expType)
8859             exp.expType = Dereference(exp.index.exp.expType);
8860          if(exp.expType)
8861             DeclareType(exp.expType, false, false);
8862          break;
8863       }
8864       case callExp:
8865       {
8866          Expression e;
8867          Type functionType;
8868          Type methodType = null;
8869          char name[1024];
8870          name[0] = '\0';
8871
8872          if(inCompiler)
8873          {
8874             PrintExpression(exp.call.exp,  name);
8875             if(exp.call.exp.expType && !exp.call.exp.expType.returnType)
8876             {
8877                //exp.call.exp.expType = null;
8878                PrintExpression(exp.call.exp,  name);
8879             }
8880          }
8881          if(exp.call.exp.type == identifierExp)
8882          {
8883             Expression idExp = exp.call.exp;
8884             Identifier id = idExp.identifier;
8885             if(!strcmp(id.string, "__builtin_frame_address"))
8886             {
8887                exp.expType = ProcessTypeString("void *", true);
8888                if(exp.call.arguments && exp.call.arguments->first)
8889                   ProcessExpressionType(exp.call.arguments->first);
8890                break;
8891             }
8892             else if(!strcmp(id.string, "__ENDIAN_PAD"))
8893             {
8894                exp.expType = ProcessTypeString("int", true);
8895                if(exp.call.arguments && exp.call.arguments->first)
8896                   ProcessExpressionType(exp.call.arguments->first);
8897                break;
8898             }
8899             else if(!strcmp(id.string, "Max") ||
8900                !strcmp(id.string, "Min") ||
8901                !strcmp(id.string, "Sgn") ||
8902                !strcmp(id.string, "Abs"))
8903             {
8904                Expression a = null;
8905                Expression b = null;
8906                Expression tempExp1 = null, tempExp2 = null;
8907                if((!strcmp(id.string, "Max") ||
8908                   !strcmp(id.string, "Min")) && exp.call.arguments->count == 2)
8909                {
8910                   a = exp.call.arguments->first;
8911                   b = exp.call.arguments->last;
8912                   tempExp1 = a;
8913                   tempExp2 = b;
8914                }
8915                else if(exp.call.arguments->count == 1)
8916                {
8917                   a = exp.call.arguments->first;
8918                   tempExp1 = a;
8919                }
8920
8921                if(a)
8922                {
8923                   exp.call.arguments->Clear();
8924                   idExp.identifier = null;
8925
8926                   FreeExpContents(exp);
8927
8928                   ProcessExpressionType(a);
8929                   if(b)
8930                      ProcessExpressionType(b);
8931
8932                   exp.type = bracketsExp;
8933                   exp.list = MkList();
8934
8935                   if(a.expType && (!b || b.expType))
8936                   {
8937                      if((!a.isConstant && a.type != identifierExp) || (b && !b.isConstant && b.type != identifierExp))
8938                      {
8939                         // Use the simpleStruct name/ids for now...
8940                         if(inCompiler)
8941                         {
8942                            OldList * specs = MkList();
8943                            OldList * decls = MkList();
8944                            Declaration decl;
8945                            char temp1[1024], temp2[1024];
8946
8947                            GetTypeSpecs(a.expType, specs);
8948
8949                            if(a && !a.isConstant && a.type != identifierExp)
8950                            {
8951                               sprintf(temp1, "__simpleStruct%d", curContext.simpleID++);
8952                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp1)), null));
8953                               tempExp1 = QMkExpId(temp1);
8954                               tempExp1.expType = a.expType;
8955                               if(a.expType)
8956                                  a.expType.refCount++;
8957                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp1), '=', a));
8958                            }
8959                            if(b && !b.isConstant && b.type != identifierExp)
8960                            {
8961                               sprintf(temp2, "__simpleStruct%d", curContext.simpleID++);
8962                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp2)), null));
8963                               tempExp2 = QMkExpId(temp2);
8964                               tempExp2.expType = b.expType;
8965                               if(b.expType)
8966                                  b.expType.refCount++;
8967                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp2), '=', b));
8968                            }
8969
8970                            decl = MkDeclaration(specs, decls);
8971                            if(!curCompound.compound.declarations)
8972                               curCompound.compound.declarations = MkList();
8973                            curCompound.compound.declarations->Insert(null, decl);
8974                         }
8975                      }
8976                   }
8977
8978                   if(!strcmp(id.string, "Max") || !strcmp(id.string, "Min"))
8979                   {
8980                      int op = (!strcmp(id.string, "Max")) ? '>' : '<';
8981                      ListAdd(exp.list,
8982                         MkExpCondition(MkExpBrackets(MkListOne(
8983                            MkExpOp(CopyExpression(tempExp1), op, CopyExpression(tempExp2)))),
8984                            MkListOne(CopyExpression(tempExp1)), CopyExpression(tempExp2)));
8985                      exp.expType = a.expType;
8986                      if(a.expType)
8987                         a.expType.refCount++;
8988                   }
8989                   else if(!strcmp(id.string, "Abs"))
8990                   {
8991                      ListAdd(exp.list,
8992                         MkExpCondition(MkExpBrackets(MkListOne(
8993                            MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
8994                            MkListOne(MkExpOp(null, '-', CopyExpression(tempExp1))), CopyExpression(tempExp1)));
8995                      exp.expType = a.expType;
8996                      if(a.expType)
8997                         a.expType.refCount++;
8998                   }
8999                   else if(!strcmp(id.string, "Sgn"))
9000                   {
9001                      // ((!(a))?(0):(((a)<0)?(-1):(1)))
9002                      ListAdd(exp.list,
9003                         MkExpCondition(MkExpBrackets(MkListOne(
9004                            MkExpOp(null, '!', CopyExpression(tempExp1)))), MkListOne(MkExpConstant("0")),
9005                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(
9006                                  MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9007                                  MkListOne(MkExpConstant("-1")), MkExpConstant("1"))))));
9008                      exp.expType = ProcessTypeString("int", false);
9009                   }
9010
9011                   FreeExpression(tempExp1);
9012                   if(tempExp2) FreeExpression(tempExp2);
9013
9014                   FreeIdentifier(id);
9015                   break;
9016                }
9017             }
9018          }
9019
9020          {
9021             Type dummy
9022             {
9023                count = 1;
9024                refCount = 1;
9025             };
9026             if(!exp.call.exp.destType)
9027             {
9028                exp.call.exp.destType = dummy;
9029                dummy.refCount++;
9030             }
9031             ProcessExpressionType(exp.call.exp);
9032             if(exp.call.exp.destType == dummy)
9033             {
9034                FreeType(dummy);
9035                exp.call.exp.destType = null;
9036             }
9037             FreeType(dummy);
9038          }
9039
9040          // Check argument types against parameter types
9041          functionType = exp.call.exp.expType;
9042
9043          if(functionType && functionType.kind == TypeKind::methodType)
9044          {
9045             methodType = functionType;
9046             functionType = methodType.method.dataType;
9047
9048             //if(functionType.returnType && functionType.returnType.kind == thisClassType)
9049             // TOCHECK: Instead of doing this here could this be done per param?
9050             if(exp.call.exp.expType.usedClass)
9051             {
9052                char typeString[1024];
9053                typeString[0] = '\0';
9054                {
9055                   Symbol back = functionType.thisClass;
9056                   // Do not output class specifier here (thisclass was added to this)
9057                   functionType.thisClass = null;
9058                   PrintType(functionType, typeString, true, true);
9059                   functionType.thisClass = back;
9060                }
9061                if(strstr(typeString, "thisclass"))
9062                {
9063                   OldList * specs = MkList();
9064                   Declarator decl;
9065                   {
9066                      Context context = SetupTemplatesContext(exp.call.exp.expType.usedClass);
9067
9068                      decl = SpecDeclFromString(typeString, specs, null);
9069
9070                      // SET THIS TO FALSE WHEN PROCESSING THISCLASS OUTSIDE THE CLASS
9071                      if(thisClass != (exp.call.exp.expType.usedClass.templateClass ? exp.call.exp.expType.usedClass.templateClass :
9072                         exp.call.exp.expType.usedClass))
9073                         thisClassParams = false;
9074
9075                      ReplaceThisClassSpecifiers(specs, exp.call.exp.expType.usedClass);
9076                      {
9077                         Class backupThisClass = thisClass;
9078                         thisClass = exp.call.exp.expType.usedClass;
9079                         ProcessDeclarator(decl);
9080                         thisClass = backupThisClass;
9081                      }
9082
9083                      thisClassParams = true;
9084
9085                      functionType = ProcessType(specs, decl);
9086                      functionType.refCount = 0;
9087                      FinishTemplatesContext(context);
9088                   }
9089
9090                   FreeList(specs, FreeSpecifier);
9091                   FreeDeclarator(decl);
9092                 }
9093             }
9094          }
9095          if(functionType && functionType.kind == pointerType && functionType.type && functionType.type.kind == TypeKind::functionType)
9096          {
9097             Type type = functionType.type;
9098             if(!functionType.refCount)
9099             {
9100                functionType.type = null;
9101                FreeType(functionType);
9102             }
9103             //methodType = functionType;
9104             functionType = type;
9105          }
9106          if(functionType && functionType.kind != TypeKind::functionType)
9107          {
9108             Compiler_Error($"called object %s is not a function\n", name);
9109          }
9110          else if(functionType)
9111          {
9112             bool emptyParams = false, noParams = false;
9113             Expression e = exp.call.arguments ? exp.call.arguments->first : null;
9114             Type type = functionType.params.first;
9115             Expression memberExp = (exp.call.exp.type == ExpressionType::memberExp) ? exp.call.exp : null;
9116             int extra = 0;
9117             Location oldyylloc = yylloc;
9118
9119             if(!type) emptyParams = true;
9120
9121             // WORKING ON THIS:
9122             if(functionType.extraParam && e && functionType.thisClass)
9123             {
9124                e.destType = MkClassType(functionType.thisClass.string);
9125                e = e.next;
9126             }
9127
9128             // WHY WAS THIS COMMENTED OUT ? Broke DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
9129             // Fixed #141 by adding '&& !functionType.extraParam'
9130             if(!functionType.staticMethod && !functionType.extraParam)
9131             {
9132                if(memberExp && memberExp.member.exp && memberExp.member.exp.expType && memberExp.member.exp.expType.kind == subClassType &&
9133                   memberExp.member.exp.expType._class)
9134                {
9135                   type = MkClassType(memberExp.member.exp.expType._class.string);
9136                   if(e)
9137                   {
9138                      e.destType = type;
9139                      e = e.next;
9140                      type = functionType.params.first;
9141                   }
9142                   else
9143                      type.refCount = 0;
9144                }
9145                else if(!memberExp && (functionType.thisClass || (methodType && methodType.methodClass)))
9146                {
9147                   type = MkClassType(functionType.thisClass ? functionType.thisClass.string : (methodType ? methodType.methodClass.fullName : null));
9148                   type.byReference = functionType.byReference;
9149                   type.typedByReference = functionType.typedByReference;
9150                   if(e)
9151                   {
9152                      // Allow manually passing a class for typed object
9153                      if(e.next && type.kind == classType && (functionType && functionType.thisClass) && functionType.classObjectType == typedObject)
9154                         e = e.next;
9155                      e.destType = type;
9156                      e = e.next;
9157                      type = functionType.params.first;
9158                   }
9159                   else
9160                      type.refCount = 0;
9161                   //extra = 1;
9162                }
9163             }
9164
9165             if(type && type.kind == voidType)
9166             {
9167                noParams = true;
9168                if(!type.refCount) FreeType(type);
9169                type = null;
9170             }
9171
9172             for( ; e; e = e.next)
9173             {
9174                if(!type && !emptyParams)
9175                {
9176                   yylloc = e.loc;
9177                   if(methodType && methodType.methodClass)
9178                      Compiler_Error($"too many arguments for method %s::%s (%d given, expected %d)\n",
9179                         methodType.methodClass.fullName, methodType.method.name, exp.call.arguments->count,
9180                         noParams ? 0 : functionType.params.count);
9181                   else
9182                      Compiler_Error($"too many arguments for function %s (%d given, expected %d)\n",
9183                         name /*exp.call.exp.identifier.string*/, exp.call.arguments->count,
9184                         noParams ? 0 : functionType.params.count);
9185                   break;
9186                }
9187
9188                if(methodType && type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type)
9189                {
9190                   Type templatedType = null;
9191                   Class _class = methodType.usedClass;
9192                   ClassTemplateParameter curParam = null;
9193                   int id = 0;
9194                   if(_class && _class.templateArgs /*&& _class.templateClass*/)
9195                   {
9196                      Class sClass;
9197                      for(sClass = _class; sClass; sClass = sClass.base)
9198                      {
9199                         if(sClass.templateClass) sClass = sClass.templateClass;
9200                         id = 0;
9201                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9202                         {
9203                            if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
9204                            {
9205                               Class nextClass;
9206                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
9207                               {
9208                                  if(nextClass.templateClass) nextClass = nextClass.templateClass;
9209                                  id += nextClass.templateParams.count;
9210                               }
9211                               break;
9212                            }
9213                            id++;
9214                         }
9215                         if(curParam) break;
9216                      }
9217                   }
9218                   if(curParam && _class.templateArgs[id].dataTypeString)
9219                   {
9220                      ClassTemplateArgument arg = _class.templateArgs[id];
9221                      {
9222                         Context context = SetupTemplatesContext(_class);
9223
9224                         /*if(!arg.dataType)
9225                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9226                         templatedType = ProcessTypeString(arg.dataTypeString, false);
9227                         FinishTemplatesContext(context);
9228                      }
9229                      e.destType = templatedType;
9230                      if(templatedType)
9231                      {
9232                         templatedType.passAsTemplate = true;
9233                         // templatedType.refCount++;
9234                      }
9235                   }
9236                   else
9237                   {
9238                      e.destType = type;
9239                      if(type) type.refCount++;
9240                   }
9241                }
9242                else
9243                {
9244                   if(type && type.kind == ellipsisType && type.prev && type.prev.kind == classType && type.prev.classObjectType)
9245                   {
9246                      e.destType = type.prev;
9247                      e.destType.refCount++;
9248                   }
9249                   else
9250                   {
9251                      e.destType = type;
9252                      if(type) type.refCount++;
9253                   }
9254                }
9255                // Don't reach the end for the ellipsis
9256                if(type && type.kind != ellipsisType)
9257                {
9258                   Type next = type.next;
9259                   if(!type.refCount) FreeType(type);
9260                   type = next;
9261                }
9262             }
9263
9264             if(type && type.kind != ellipsisType)
9265             {
9266                if(methodType && methodType.methodClass)
9267                   Compiler_Warning($"not enough arguments for method %s::%s (%d given, expected %d)\n",
9268                      methodType.methodClass.fullName, methodType.method.name, exp.call.arguments ? exp.call.arguments->count : 0,
9269                      functionType.params.count + extra);
9270                else
9271                   Compiler_Warning($"not enough arguments for function %s (%d given, expected %d)\n",
9272                      name /*exp.call.exp.identifier.string*/, exp.call.arguments ? exp.call.arguments->count : 0,
9273                      functionType.params.count + extra);
9274             }
9275             yylloc = oldyylloc;
9276             if(type && !type.refCount) FreeType(type);
9277          }
9278          else
9279          {
9280             functionType = Type
9281             {
9282                refCount = 0;
9283                kind = TypeKind::functionType;
9284             };
9285
9286             if(exp.call.exp.type == identifierExp)
9287             {
9288                char * string = exp.call.exp.identifier.string;
9289                if(inCompiler)
9290                {
9291                   Symbol symbol;
9292                   Location oldyylloc = yylloc;
9293
9294                   yylloc = exp.call.exp.identifier.loc;
9295                   if(strstr(string, "__builtin_") == string)
9296                   {
9297                      if(exp.destType)
9298                      {
9299                         functionType.returnType = exp.destType;
9300                         exp.destType.refCount++;
9301                      }
9302                   }
9303                   else
9304                      Compiler_Warning($"%s undefined; assuming extern returning int\n", string);
9305                   symbol = Symbol { string = CopyString(string), type = ProcessTypeString("int()", true) };
9306                   globalContext.symbols.Add((BTNode)symbol);
9307                   if(strstr(symbol.string, "::"))
9308                      globalContext.hasNameSpace = true;
9309
9310                   yylloc = oldyylloc;
9311                }
9312             }
9313             else if(exp.call.exp.type == memberExp)
9314             {
9315                /*Compiler_Warning($"%s undefined; assuming returning int\n",
9316                   exp.call.exp.member.member.string);*/
9317             }
9318             else
9319                Compiler_Warning($"callable object undefined; extern assuming returning int\n");
9320
9321             if(!functionType.returnType)
9322             {
9323                functionType.returnType = Type
9324                {
9325                   refCount = 1;
9326                   kind = intType;
9327                };
9328             }
9329          }
9330          if(functionType && functionType.kind == TypeKind::functionType)
9331          {
9332             exp.expType = functionType.returnType;
9333
9334             if(functionType.returnType)
9335                functionType.returnType.refCount++;
9336
9337             if(!functionType.refCount)
9338                FreeType(functionType);
9339          }
9340
9341          if(exp.call.arguments)
9342          {
9343             for(e = exp.call.arguments->first; e; e = e.next)
9344             {
9345                Type destType = e.destType;
9346                ProcessExpressionType(e);
9347             }
9348          }
9349          break;
9350       }
9351       case memberExp:
9352       {
9353          Type type;
9354          Location oldyylloc = yylloc;
9355          bool thisPtr;
9356          Expression checkExp = exp.member.exp;
9357          while(checkExp)
9358          {
9359             if(checkExp.type == castExp)
9360                checkExp = checkExp.cast.exp;
9361             else if(checkExp.type == bracketsExp)
9362                checkExp = checkExp.list ? checkExp.list->first : null;
9363             else
9364                break;
9365          }
9366
9367          thisPtr = (checkExp && checkExp.type == identifierExp && !strcmp(checkExp.identifier.string, "this"));
9368          exp.thisPtr = thisPtr;
9369
9370          // DOING THIS LATER NOW...
9371          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
9372          {
9373             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
9374             /* TODO: Name Space Fix ups
9375             if(!exp.member.member.classSym)
9376                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.fullName);
9377             */
9378          }
9379
9380          ProcessExpressionType(exp.member.exp);
9381          if(exp.member.exp.expType && exp.member.exp.expType.kind == classType && exp.member.exp.expType._class &&
9382             exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == normalClass)
9383          {
9384             exp.isConstant = false;
9385          }
9386          else
9387             exp.isConstant = exp.member.exp.isConstant;
9388          type = exp.member.exp.expType;
9389
9390          yylloc = exp.loc;
9391
9392          if(type && (type.kind == templateType))
9393          {
9394             Class _class = thisClass ? thisClass : currentClass;
9395             ClassTemplateParameter param = null;
9396             if(_class)
9397             {
9398                for(param = _class.templateParams.first; param; param = param.next)
9399                {
9400                   if(param.type == identifier && exp.member.member && exp.member.member.string && !strcmp(param.name, exp.member.member.string))
9401                      break;
9402                }
9403             }
9404             if(param && param.defaultArg.member)
9405             {
9406                Expression argExp = GetTemplateArgExpByName(param.name, thisClass, TemplateParameterType::identifier);
9407                if(argExp)
9408                {
9409                   Expression expMember = exp.member.exp;
9410                   Declarator decl;
9411                   OldList * specs = MkList();
9412                   char thisClassTypeString[1024];
9413
9414                   FreeIdentifier(exp.member.member);
9415
9416                   ProcessExpressionType(argExp);
9417
9418                   {
9419                      char * colon = strstr(param.defaultArg.memberString, "::");
9420                      if(colon)
9421                      {
9422                         char className[1024];
9423                         Class sClass;
9424
9425                         memcpy(thisClassTypeString, param.defaultArg.memberString, colon - param.defaultArg.memberString);
9426                         thisClassTypeString[colon - param.defaultArg.memberString] = '\0';
9427                      }
9428                      else
9429                         strcpy(thisClassTypeString, _class.fullName);
9430                   }
9431
9432                   decl = SpecDeclFromString(param.defaultArg.member.dataTypeString, specs, null);
9433
9434                   exp.expType = ProcessType(specs, decl);
9435                   if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.templateClass)
9436                   {
9437                      Class expClass = exp.expType._class.registered;
9438                      Class cClass = null;
9439                      int c;
9440                      int paramCount = 0;
9441                      int lastParam = -1;
9442
9443                      char templateString[1024];
9444                      ClassTemplateParameter param;
9445                      sprintf(templateString, "%s<", expClass.templateClass.fullName);
9446                      for(cClass = expClass; cClass; cClass = cClass.base)
9447                      {
9448                         int p = 0;
9449                         for(param = cClass.templateParams.first; param; param = param.next)
9450                         {
9451                            int id = p;
9452                            Class sClass;
9453                            ClassTemplateArgument arg;
9454                            for(sClass = cClass.base; sClass; sClass = sClass.base) id += sClass.templateParams.count;
9455                            arg = expClass.templateArgs[id];
9456
9457                            for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
9458                            {
9459                               ClassTemplateParameter cParam;
9460                               //int p = numParams - sClass.templateParams.count;
9461                               int p = 0;
9462                               Class nextClass;
9463                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) p += nextClass.templateParams.count;
9464
9465                               for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
9466                               {
9467                                  if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
9468                                  {
9469                                     if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9470                                     {
9471                                        arg.dataTypeString = _class.templateArgs[p].dataTypeString;
9472                                        arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
9473                                        break;
9474                                     }
9475                                  }
9476                               }
9477                            }
9478
9479                            {
9480                               char argument[256];
9481                               argument[0] = '\0';
9482                               /*if(arg.name)
9483                               {
9484                                  strcat(argument, arg.name.string);
9485                                  strcat(argument, " = ");
9486                               }*/
9487                               switch(param.type)
9488                               {
9489                                  case expression:
9490                                  {
9491                                     // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
9492                                     char expString[1024];
9493                                     OldList * specs = MkList();
9494                                     Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
9495                                     Expression exp;
9496                                     char * string = PrintHexUInt64(arg.expression.ui64);
9497                                     exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
9498                                     delete string;
9499
9500                                     ProcessExpressionType(exp);
9501                                     ComputeExpression(exp);
9502                                     expString[0] = '\0';
9503                                     PrintExpression(exp, expString);
9504                                     strcat(argument, expString);
9505                                     // delete exp;
9506                                     FreeExpression(exp);
9507                                     break;
9508                                  }
9509                                  case identifier:
9510                                  {
9511                                     strcat(argument, arg.member.name);
9512                                     break;
9513                                  }
9514                                  case TemplateParameterType::type:
9515                                  {
9516                                     if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9517                                     {
9518                                        if(!strcmp(arg.dataTypeString, "thisclass"))
9519                                           strcat(argument, thisClassTypeString);
9520                                        else
9521                                           strcat(argument, arg.dataTypeString);
9522                                     }
9523                                     break;
9524                                  }
9525                               }
9526                               if(argument[0])
9527                               {
9528                                  if(paramCount) strcat(templateString, ", ");
9529                                  if(lastParam != p - 1)
9530                                  {
9531                                     strcat(templateString, param.name);
9532                                     strcat(templateString, " = ");
9533                                  }
9534                                  strcat(templateString, argument);
9535                                  paramCount++;
9536                                  lastParam = p;
9537                               }
9538                               p++;
9539                            }
9540                         }
9541                      }
9542                      {
9543                         int len = strlen(templateString);
9544                         if(templateString[len-1] == '>') templateString[len++] = ' ';
9545                         templateString[len++] = '>';
9546                         templateString[len++] = '\0';
9547                      }
9548                      {
9549                         Context context = SetupTemplatesContext(_class);
9550                         FreeType(exp.expType);
9551                         exp.expType = ProcessTypeString(templateString, false);
9552                         FinishTemplatesContext(context);
9553                      }
9554                   }
9555
9556                   // *([expType] *)(((byte *)[exp.member.exp]) + [argExp].member.offset)
9557                   exp.type = bracketsExp;
9558                   exp.list = MkListOne(MkExpOp(null, '*',
9559                   /*opExp;
9560                   exp.op.op = '*';
9561                   exp.op.exp1 = null;
9562                   exp.op.exp2 = */
9563                   MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpBrackets(MkListOne(MkExpOp(
9564                      MkExpBrackets(MkListOne(
9565                         MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), expMember))),
9566                            '+',
9567                            MkExpOp(MkExpMember(MkExpMember(argExp, MkIdentifier("member")), MkIdentifier("offset")),
9568                            '+',
9569                            MkExpMember(MkExpMember(MkExpMember(CopyExpression(argExp), MkIdentifier("member")), MkIdentifier("_class")), MkIdentifier("offset")))))))
9570
9571                            ));
9572                }
9573             }
9574             else if(type.templateParameter && type.templateParameter.type == TemplateParameterType::type &&
9575                (type.templateParameter.dataType || type.templateParameter.dataTypeString))
9576             {
9577                type = ProcessTemplateParameterType(type.templateParameter);
9578             }
9579          }
9580          // TODO: *** This seems to be where we should add method support for all basic types ***
9581          if(type && (type.kind == templateType));
9582          else if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType ||
9583                           type.kind == int64Type || type.kind == shortType || type.kind == longType || type.kind == charType || type.kind == _BoolType ||
9584                           type.kind == intPtrType || type.kind == intSizeType || type.kind == floatType || type.kind == doubleType ||
9585                           (type.kind == pointerType && type.type.kind == charType)))
9586          {
9587             Identifier id = exp.member.member;
9588             TypeKind typeKind = type.kind;
9589             Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
9590             if(typeKind == subClassType && exp.member.exp.type == classExp)
9591             {
9592                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
9593                typeKind = classType;
9594             }
9595
9596             if(id)
9597             {
9598                if(typeKind == intType || typeKind == enumType)
9599                   _class = eSystem_FindClass(privateModule, "int");
9600                else if(!_class)
9601                {
9602                   if(type.kind == classType && type._class && type._class.registered)
9603                   {
9604                      _class = type._class.registered;
9605                   }
9606                   else if((type.kind == arrayType || type.kind == pointerType) && type.type && type.type.kind == charType)
9607                   {
9608                      _class = FindClass("char *").registered;
9609                   }
9610                   else if(type.kind == pointerType)
9611                   {
9612                      _class = eSystem_FindClass(privateModule, "uintptr");
9613                      FreeType(exp.expType);
9614                      exp.expType = ProcessTypeString("uintptr", false);
9615                      exp.byReference = true;
9616                   }
9617                   else
9618                   {
9619                      char string[1024] = "";
9620                      Symbol classSym;
9621                      PrintTypeNoConst(type, string, false, true);
9622                      classSym = FindClass(string);
9623                      if(classSym) _class = classSym.registered;
9624                   }
9625                }
9626             }
9627
9628             if(_class && id)
9629             {
9630                /*bool thisPtr =
9631                   (exp.member.exp.type == identifierExp &&
9632                   !strcmp(exp.member.exp.identifier.string, "this"));*/
9633                Property prop = null;
9634                Method method = null;
9635                DataMember member = null;
9636                Property revConvert = null;
9637                ClassProperty classProp = null;
9638
9639                if(id && id._class && id._class.name && !strcmp(id._class.name, "property"))
9640                   exp.member.memberType = propertyMember;
9641
9642                if(id && id._class && type._class && !eClass_IsDerived(type._class.registered, _class))
9643                   Compiler_Error($"invalid class specifier %s for object of class %s\n", _class.fullName, type._class.string);
9644
9645                if(typeKind != subClassType)
9646                {
9647                   // Prioritize data members over properties for "this"
9648                   if((exp.member.memberType == unresolvedMember && thisPtr) || exp.member.memberType == dataMember)
9649                   {
9650                      member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
9651                      if(member && member._class != (_class.templateClass ? _class.templateClass : _class) && exp.member.memberType != dataMember)
9652                      {
9653                         prop = eClass_FindProperty(_class, id.string, privateModule);
9654                         if(prop)
9655                            member = null;
9656                      }
9657                      if(!member && !prop)
9658                         prop = eClass_FindProperty(_class, id.string, privateModule);
9659                      if((member && member._class == (_class.templateClass ? _class.templateClass : _class)) ||
9660                         (prop && prop._class == (_class.templateClass ? _class.templateClass : _class)))
9661                         exp.member.thisPtr = true;
9662                   }
9663                   // Prioritize properties over data members otherwise
9664                   else
9665                   {
9666                      // First look for Public Members (Unless class specifier is provided, which skips public priority)
9667                      if(!id.classSym)
9668                      {
9669                         prop = eClass_FindProperty(_class, id.string, null);
9670                         if(!id._class || !id._class.name || strcmp(id._class.name, "property"))
9671                            member = eClass_FindDataMember(_class, id.string, null, null, null);
9672                      }
9673
9674                      if(!prop && !member)
9675                      {
9676                         method = eClass_FindMethod(_class, id.string, null);
9677                         if(!method)
9678                         {
9679                            prop = eClass_FindProperty(_class, id.string, privateModule);
9680                            if(!id._class || !id._class.name || strcmp(id._class.name, "property"))
9681                               member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
9682                         }
9683                      }
9684
9685                      if(member && prop)
9686                      {
9687                         if(member._class != prop._class && !id._class && eClass_IsDerived(member._class, prop._class))
9688                            prop = null;
9689                         else
9690                            member = null;
9691                      }
9692                   }
9693                }
9694                if(!prop && !member && !method)     // NOTE: Recently added the !method here, causes private methods to unprioritized
9695                   method = eClass_FindMethod(_class, id.string, privateModule);
9696                if(!prop && !member && !method)
9697                {
9698                   if(typeKind == subClassType)
9699                   {
9700                      classProp = eClass_FindClassProperty(type._class.registered, exp.member.member.string);
9701                      if(classProp)
9702                      {
9703                         exp.member.memberType = classPropertyMember;
9704                         exp.expType = ProcessTypeString(classProp.dataTypeString, false);
9705                      }
9706                      else
9707                      {
9708                         // Assume this is a class_data member
9709                         char structName[1024];
9710                         Identifier id = exp.member.member;
9711                         Expression classExp = exp.member.exp;
9712                         type.refCount++;
9713
9714                         FreeType(classExp.expType);
9715                         classExp.expType = ProcessTypeString("ecere::com::Class", false);
9716
9717                         strcpy(structName, "__ecereClassData_");
9718                         FullClassNameCat(structName, type._class.string, false);
9719                         exp.type = pointerExp;
9720                         exp.member.member = id;
9721
9722                         exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
9723                            MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
9724                               MkExpBrackets(MkListOne(MkExpOp(
9725                                  MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
9726                                     MkExpMember(classExp, MkIdentifier("data"))), '+',
9727                                        MkExpMember(MkExpClass(MkListOne(MkSpecifierName(type._class.string)), null), MkIdentifier("offsetClass")))))
9728                                  )));
9729
9730                         FreeType(type);
9731
9732                         ProcessExpressionType(exp);
9733                         return;
9734                      }
9735                   }
9736                   else
9737                   {
9738                      // Check for reverse conversion
9739                      // (Convert in an instantiation later, so that we can use
9740                      //  deep properties system)
9741                      Symbol classSym = FindClass(id.string);
9742                      if(classSym)
9743                      {
9744                         Class convertClass = classSym.registered;
9745                         if(convertClass)
9746                            revConvert = eClass_FindProperty(convertClass, _class.fullName, privateModule);
9747                      }
9748                   }
9749                }
9750
9751                if(prop)
9752                {
9753                   exp.member.memberType = propertyMember;
9754                   if(!prop.dataType)
9755                      ProcessPropertyType(prop);
9756                   exp.expType = prop.dataType;
9757                   if(prop.dataType) prop.dataType.refCount++;
9758                }
9759                else if(member)
9760                {
9761                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
9762                   {
9763                      FreeExpContents(exp);
9764                      exp.type = identifierExp;
9765                      exp.identifier = MkIdentifier("class");
9766                      ProcessExpressionType(exp);
9767                      return;
9768                   }
9769
9770                   exp.member.memberType = dataMember;
9771                   DeclareStruct(_class.fullName, false);
9772                   if(!member.dataType)
9773                   {
9774                      Context context = SetupTemplatesContext(_class);
9775                      member.dataType = ProcessTypeString(member.dataTypeString, false);
9776                      FinishTemplatesContext(context);
9777                   }
9778                   exp.expType = member.dataType;
9779                   if(member.dataType) member.dataType.refCount++;
9780                }
9781                else if(revConvert)
9782                {
9783                   exp.member.memberType = reverseConversionMember;
9784                   exp.expType = MkClassType(revConvert._class.fullName);
9785                }
9786                else if(method)
9787                {
9788                   //if(inCompiler)
9789                   {
9790                      /*if(id._class)
9791                      {
9792                         exp.type = identifierExp;
9793                         exp.identifier = exp.member.member;
9794                      }
9795                      else*/
9796                         exp.member.memberType = methodMember;
9797                   }
9798                   if(!method.dataType)
9799                      ProcessMethodType(method);
9800                   exp.expType = Type
9801                   {
9802                      refCount = 1;
9803                      kind = methodType;
9804                      method = method;
9805                   };
9806
9807                   // Tricky spot here... To use instance versus class virtual table
9808                   // Put it back to what it was... What did we break?
9809
9810                   // Had to put it back for overriding Main of Thread global instance
9811
9812                   //exp.expType.methodClass = _class;
9813                   exp.expType.methodClass = (id && id._class) ? _class : null;
9814
9815                   // Need the actual class used for templated classes
9816                   exp.expType.usedClass = _class;
9817                }
9818                else if(!classProp)
9819                {
9820                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
9821                   {
9822                      FreeExpContents(exp);
9823                      exp.type = identifierExp;
9824                      exp.identifier = MkIdentifier("class");
9825                      FreeType(exp.expType);
9826                      exp.expType = MkClassType("ecere::com::Class");
9827                      return;
9828                   }
9829                   yylloc = exp.member.member.loc;
9830                   Compiler_Error($"couldn't find member %s in class %s\n", id.string, _class.fullName);
9831                   if(inCompiler)
9832                      eClass_AddDataMember(_class, id.string, "int", 0, 0, publicAccess);
9833                }
9834
9835                if(_class && /*(_class.templateClass || _class.templateArgs) && */exp.expType)
9836                {
9837                   Class tClass;
9838
9839                   tClass = _class;
9840                   while(tClass && !tClass.templateClass) tClass = tClass.base;
9841
9842                   if(tClass && exp.expType.kind == templateType && exp.expType.templateParameter.type == TemplateParameterType::type)
9843                   {
9844                      int id = 0;
9845                      ClassTemplateParameter curParam = null;
9846                      Class sClass;
9847
9848                      for(sClass = tClass; sClass; sClass = sClass.base)
9849                      {
9850                         id = 0;
9851                         if(sClass.templateClass) sClass = sClass.templateClass;
9852                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9853                         {
9854                            if(curParam.type == TemplateParameterType::type && !strcmp(exp.expType.templateParameter.identifier.string, curParam.name))
9855                            {
9856                               for(sClass = sClass.base; sClass; sClass = sClass.base)
9857                                  id += sClass.templateParams.count;
9858                               break;
9859                            }
9860                            id++;
9861                         }
9862                         if(curParam) break;
9863                      }
9864
9865                      if(curParam && tClass.templateArgs[id].dataTypeString)
9866                      {
9867                         ClassTemplateArgument arg = tClass.templateArgs[id];
9868                         Context context = SetupTemplatesContext(tClass);
9869                         /*if(!arg.dataType)
9870                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9871                         FreeType(exp.expType);
9872                         exp.expType = ProcessTypeString(arg.dataTypeString, false);
9873                         if(exp.expType)
9874                         {
9875                            if(exp.expType.kind == thisClassType)
9876                            {
9877                               FreeType(exp.expType);
9878                               exp.expType = ReplaceThisClassType(_class);
9879                            }
9880
9881                            if(tClass.templateClass)
9882                               exp.expType.passAsTemplate = true;
9883                            //exp.expType.refCount++;
9884                            if(!exp.destType)
9885                            {
9886                               exp.destType = ProcessTypeString(arg.dataTypeString, false);
9887                               //exp.destType.refCount++;
9888
9889                               if(exp.destType.kind == thisClassType)
9890                               {
9891                                  FreeType(exp.destType);
9892                                  exp.destType = ReplaceThisClassType(_class);
9893                               }
9894                            }
9895                         }
9896                         FinishTemplatesContext(context);
9897                      }
9898                   }
9899                   // TODO: MORE GENERIC SUPPORT FOR DEEPER TYPES
9900                   else if(tClass && exp.expType.kind == pointerType && exp.expType.type && exp.expType.type.kind == templateType && exp.expType.type.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 &&
9913                               !strcmp(exp.expType.type.templateParameter.identifier.string, curParam.name))
9914                            {
9915                               for(sClass = sClass.base; sClass; sClass = sClass.base)
9916                                  id += sClass.templateParams.count;
9917                               break;
9918                            }
9919                            id++;
9920                         }
9921                         if(curParam) break;
9922                      }
9923
9924                      if(curParam)
9925                      {
9926                         ClassTemplateArgument arg = tClass.templateArgs[id];
9927                         Context context = SetupTemplatesContext(tClass);
9928                         Type basicType;
9929                         /*if(!arg.dataType)
9930                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9931
9932                         basicType = ProcessTypeString(arg.dataTypeString, false);
9933                         if(basicType)
9934                         {
9935                            if(basicType.kind == thisClassType)
9936                            {
9937                               FreeType(basicType);
9938                               basicType = ReplaceThisClassType(_class);
9939                            }
9940
9941                            /*    DO WE REALLY WANT THIS HERE? IT SEEMS TO BE ONLY USED WITH Array::array which was causing bug 135
9942                            if(tClass.templateClass)
9943                               basicType.passAsTemplate = true;
9944                            */
9945
9946                            FreeType(exp.expType);
9947
9948                            exp.expType = Type { refCount = 1, kind = pointerType, type = basicType };
9949                            //exp.expType.refCount++;
9950                            if(!exp.destType)
9951                            {
9952                               exp.destType = exp.expType;
9953                               exp.destType.refCount++;
9954                            }
9955
9956                            {
9957                               Expression newExp { };
9958                               OldList * specs = MkList();
9959                               Declarator decl;
9960                               decl = SpecDeclFromString(arg.dataTypeString, specs, null);
9961                               *newExp = *exp;
9962                               if(exp.destType) exp.destType.refCount++;
9963                               if(exp.expType)  exp.expType.refCount++;
9964                               exp.type = castExp;
9965                               exp.cast.typeName = MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl));
9966                               exp.cast.exp = newExp;
9967                               //FreeType(exp.expType);
9968                               //exp.expType = null;
9969                               //ProcessExpressionType(sourceExp);
9970                            }
9971                         }
9972                         FinishTemplatesContext(context);
9973                      }
9974                   }
9975                   else if(tClass && exp.expType.kind == classType && exp.expType._class && strchr(exp.expType._class.string, '<'))
9976                   {
9977                      Class expClass = exp.expType._class.registered;
9978                      if(expClass)
9979                      {
9980                         Class cClass = null;
9981                         int c;
9982                         int p = 0;
9983                         int paramCount = 0;
9984                         int lastParam = -1;
9985                         char templateString[1024];
9986                         ClassTemplateParameter param;
9987                         sprintf(templateString, "%s<", expClass.templateClass.fullName);
9988                         while(cClass != expClass)
9989                         {
9990                            Class sClass;
9991                            for(sClass = expClass; sClass && sClass.base != cClass; sClass = sClass.base);
9992                            cClass = sClass;
9993
9994                            for(param = cClass.templateParams.first; param; param = param.next)
9995                            {
9996                               Class cClassCur = null;
9997                               int c;
9998                               int cp = 0;
9999                               ClassTemplateParameter paramCur = null;
10000                               ClassTemplateArgument arg;
10001                               while(cClassCur != tClass && !paramCur)
10002                               {
10003                                  Class sClassCur;
10004                                  for(sClassCur = tClass; sClassCur && sClassCur.base != cClassCur; sClassCur = sClassCur.base);
10005                                  cClassCur = sClassCur;
10006
10007                                  for(paramCur = cClassCur.templateParams.first; paramCur; paramCur = paramCur.next)
10008                                  {
10009                                     if(!strcmp(paramCur.name, param.name))
10010                                     {
10011
10012                                        break;
10013                                     }
10014                                     cp++;
10015                                  }
10016                               }
10017                               if(paramCur && paramCur.type == TemplateParameterType::type)
10018                                  arg = tClass.templateArgs[cp];
10019                               else
10020                                  arg = expClass.templateArgs[p];
10021
10022                               {
10023                                  char argument[256];
10024                                  argument[0] = '\0';
10025                                  /*if(arg.name)
10026                                  {
10027                                     strcat(argument, arg.name.string);
10028                                     strcat(argument, " = ");
10029                                  }*/
10030                                  switch(param.type)
10031                                  {
10032                                     case expression:
10033                                     {
10034                                        // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
10035                                        char expString[1024];
10036                                        OldList * specs = MkList();
10037                                        Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
10038                                        Expression exp;
10039                                        char * string = PrintHexUInt64(arg.expression.ui64);
10040                                        exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
10041                                        delete string;
10042
10043                                        ProcessExpressionType(exp);
10044                                        ComputeExpression(exp);
10045                                        expString[0] = '\0';
10046                                        PrintExpression(exp, expString);
10047                                        strcat(argument, expString);
10048                                        // delete exp;
10049                                        FreeExpression(exp);
10050                                        break;
10051                                     }
10052                                     case identifier:
10053                                     {
10054                                        strcat(argument, arg.member.name);
10055                                        break;
10056                                     }
10057                                     case TemplateParameterType::type:
10058                                     {
10059                                        if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10060                                           strcat(argument, arg.dataTypeString);
10061                                        break;
10062                                     }
10063                                  }
10064                                  if(argument[0])
10065                                  {
10066                                     if(paramCount) strcat(templateString, ", ");
10067                                     if(lastParam != p - 1)
10068                                     {
10069                                        strcat(templateString, param.name);
10070                                        strcat(templateString, " = ");
10071                                     }
10072                                     strcat(templateString, argument);
10073                                     paramCount++;
10074                                     lastParam = p;
10075                                  }
10076                               }
10077                               p++;
10078                            }
10079                         }
10080                         {
10081                            int len = strlen(templateString);
10082                            if(templateString[len-1] == '>') templateString[len++] = ' ';
10083                            templateString[len++] = '>';
10084                            templateString[len++] = '\0';
10085                         }
10086
10087                         FreeType(exp.expType);
10088                         {
10089                            Context context = SetupTemplatesContext(tClass);
10090                            exp.expType = ProcessTypeString(templateString, false);
10091                            FinishTemplatesContext(context);
10092                         }
10093                      }
10094                   }
10095                }
10096             }
10097             else
10098                Compiler_Error($"undefined class %s\n", (id && (!id._class || id._class.name))? (id.classSym ? id.classSym.string : (type._class ? type._class.string : null)) : "(null)");
10099          }
10100          else if(type && (type.kind == structType || type.kind == unionType))
10101          {
10102             Type memberType = exp.member.member ? FindMember(type, exp.member.member.string) : null;
10103             if(memberType)
10104             {
10105                exp.expType = memberType;
10106                if(memberType)
10107                   memberType.refCount++;
10108             }
10109          }
10110          else
10111          {
10112             char expString[10240];
10113             expString[0] = '\0';
10114             if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10115             Compiler_Error($"member operator on non-structure type expression %s\n", expString);
10116          }
10117
10118          if(exp.expType && exp.expType.kind == thisClassType && (!exp.destType || exp.destType.kind != thisClassType))
10119          {
10120             if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType))
10121             {
10122                Identifier id = exp.member.member;
10123                Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10124                if(_class)
10125                {
10126                   FreeType(exp.expType);
10127                   exp.expType = ReplaceThisClassType(_class);
10128                }
10129             }
10130          }
10131          yylloc = oldyylloc;
10132          break;
10133       }
10134       // Convert x->y into (*x).y
10135       case pointerExp:
10136       {
10137          Type destType = exp.destType;
10138
10139          // DOING THIS LATER NOW...
10140          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
10141          {
10142             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
10143             /* TODO: Name Space Fix ups
10144             if(!exp.member.member.classSym)
10145                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.name);
10146             */
10147          }
10148
10149          exp.member.exp = MkExpBrackets(MkListOne(MkExpOp(null, '*', exp.member.exp)));
10150          exp.type = memberExp;
10151          if(destType)
10152             destType.count++;
10153          ProcessExpressionType(exp);
10154          if(destType)
10155             destType.count--;
10156          break;
10157       }
10158       case classSizeExp:
10159       {
10160          //ComputeExpression(exp);
10161
10162          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
10163          if(classSym && classSym.registered)
10164          {
10165             if(classSym.registered.type == noHeadClass)
10166             {
10167                char name[1024];
10168                name[0] = '\0';
10169                DeclareStruct(classSym.string, false);
10170                FreeSpecifier(exp._class);
10171                exp.type = typeSizeExp;
10172                FullClassNameCat(name, classSym.string, false);
10173                exp.typeName = MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null);
10174             }
10175             else
10176             {
10177                if(classSym.registered.fixed)
10178                {
10179                   FreeSpecifier(exp._class);
10180                   exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
10181                   exp.type = constantExp;
10182                }
10183                else
10184                {
10185                   char className[1024];
10186                   strcpy(className, "__ecereClass_");
10187                   FullClassNameCat(className, classSym.string, true);
10188                   MangleClassName(className);
10189
10190                   DeclareClass(classSym, className);
10191
10192                   FreeExpContents(exp);
10193                   exp.type = pointerExp;
10194                   exp.member.exp = MkExpIdentifier(MkIdentifier(className));
10195                   exp.member.member = MkIdentifier("structSize");
10196                }
10197             }
10198          }
10199
10200          exp.expType = Type
10201          {
10202             refCount = 1;
10203             kind = intType;
10204          };
10205          // exp.isConstant = true;
10206          break;
10207       }
10208       case typeSizeExp:
10209       {
10210          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
10211
10212          exp.expType = Type
10213          {
10214             refCount = 1;
10215             kind = intType;
10216          };
10217          exp.isConstant = true;
10218
10219          DeclareType(type, false, false);
10220          FreeType(type);
10221          break;
10222       }
10223       case castExp:
10224       {
10225          Type type = ProcessType(exp.cast.typeName.qualifiers, exp.cast.typeName.declarator);
10226          type.count = 1;
10227          FreeType(exp.cast.exp.destType);
10228          exp.cast.exp.destType = type;
10229          type.refCount++;
10230          ProcessExpressionType(exp.cast.exp);
10231          type.count = 0;
10232          exp.expType = type;
10233          //type.refCount++;
10234
10235          // if(!NeedCast(exp.cast.exp.expType, exp.cast.exp.destType))
10236          if(!exp.cast.exp.needCast && !NeedCast(exp.cast.exp.expType, type))
10237          {
10238             void * prev = exp.prev, * next = exp.next;
10239             Type expType = exp.cast.exp.destType;
10240             Expression castExp = exp.cast.exp;
10241             Type destType = exp.destType;
10242
10243             if(expType) expType.refCount++;
10244
10245             //FreeType(exp.destType);
10246             FreeType(exp.expType);
10247             FreeTypeName(exp.cast.typeName);
10248
10249             *exp = *castExp;
10250             FreeType(exp.expType);
10251             FreeType(exp.destType);
10252
10253             exp.expType = expType;
10254             exp.destType = destType;
10255
10256             delete castExp;
10257
10258             exp.prev = prev;
10259             exp.next = next;
10260
10261          }
10262          else
10263          {
10264             exp.isConstant = exp.cast.exp.isConstant;
10265          }
10266          //FreeType(type);
10267          break;
10268       }
10269       case extensionInitializerExp:
10270       {
10271          Type type = ProcessType(exp.initializer.typeName.qualifiers, exp.initializer.typeName.declarator);
10272          // We have yet to support this... ( { } initializers are currently processed inside ProcessDeclaration()'s initDeclaration case statement
10273          // ProcessInitializer(exp.initializer.initializer, type);
10274          exp.expType = type;
10275          break;
10276       }
10277       case vaArgExp:
10278       {
10279          Type type = ProcessType(exp.vaArg.typeName.qualifiers, exp.vaArg.typeName.declarator);
10280          ProcessExpressionType(exp.vaArg.exp);
10281          exp.expType = type;
10282          break;
10283       }
10284       case conditionExp:
10285       {
10286          Expression e;
10287          exp.isConstant = true;
10288
10289          FreeType(exp.cond.cond.destType);
10290          exp.cond.cond.destType = MkClassType("bool");
10291          exp.cond.cond.destType.truth = true;
10292          ProcessExpressionType(exp.cond.cond);
10293          if(!exp.cond.cond.isConstant)
10294             exp.isConstant = false;
10295          for(e = exp.cond.exp->first; e; e = e.next)
10296          {
10297             if(!e.next)
10298             {
10299                FreeType(e.destType);
10300                e.destType = exp.destType;
10301                if(e.destType) e.destType.refCount++;
10302             }
10303             ProcessExpressionType(e);
10304             if(!e.next)
10305             {
10306                exp.expType = e.expType;
10307                if(e.expType) e.expType.refCount++;
10308             }
10309             if(!e.isConstant)
10310                exp.isConstant = false;
10311          }
10312
10313          FreeType(exp.cond.elseExp.destType);
10314          // Added this check if we failed to find an expType
10315          // exp.cond.elseExp.destType = exp.expType ? exp.expType : exp.destType;
10316
10317          // Reversed it...
10318          exp.cond.elseExp.destType = exp.destType ? exp.destType : exp.expType;
10319
10320          if(exp.cond.elseExp.destType)
10321             exp.cond.elseExp.destType.refCount++;
10322          ProcessExpressionType(exp.cond.elseExp);
10323
10324          // FIXED THIS: Was done before calling process on elseExp
10325          if(!exp.cond.elseExp.isConstant)
10326             exp.isConstant = false;
10327          break;
10328       }
10329       case extensionCompoundExp:
10330       {
10331          if(exp.compound && exp.compound.compound.statements && exp.compound.compound.statements->last)
10332          {
10333             Statement last = exp.compound.compound.statements->last;
10334             if(last.type == expressionStmt && last.expressions && last.expressions->last)
10335             {
10336                ((Expression)last.expressions->last).destType = exp.destType;
10337                if(exp.destType)
10338                   exp.destType.refCount++;
10339             }
10340             ProcessStatement(exp.compound);
10341             exp.expType = (last.expressions && last.expressions->last) ? ((Expression)last.expressions->last).expType : null;
10342             if(exp.expType)
10343                exp.expType.refCount++;
10344          }
10345          break;
10346       }
10347       case classExp:
10348       {
10349          Specifier spec = exp._classExp.specifiers->first;
10350          if(spec && spec.type == nameSpecifier)
10351          {
10352             exp.expType = MkClassType(spec.name);
10353             exp.expType.kind = subClassType;
10354             exp.byReference = true;
10355          }
10356          else
10357          {
10358             exp.expType = MkClassType("ecere::com::Class");
10359             exp.byReference = true;
10360          }
10361          break;
10362       }
10363       case classDataExp:
10364       {
10365          Class _class = thisClass ? thisClass : currentClass;
10366          if(_class)
10367          {
10368             Identifier id = exp.classData.id;
10369             char structName[1024];
10370             Expression classExp;
10371             strcpy(structName, "__ecereClassData_");
10372             FullClassNameCat(structName, _class.fullName, false);
10373             exp.type = pointerExp;
10374             exp.member.member = id;
10375             if(curCompound && FindSymbol("this", curContext, curCompound.compound.context, false, false))
10376                classExp = MkExpMember(MkExpIdentifier(MkIdentifier("this")), MkIdentifier("_class"));
10377             else
10378                classExp = MkExpIdentifier(MkIdentifier("class"));
10379
10380             exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10381                MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10382                   MkExpBrackets(MkListOne(MkExpOp(
10383                      MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10384                         MkExpMember(classExp, MkIdentifier("data"))), '+',
10385                            MkExpMember(MkExpClass(MkListOne(MkSpecifierName(_class.fullName)), null), MkIdentifier("offsetClass")))))
10386                      )));
10387
10388             ProcessExpressionType(exp);
10389             return;
10390          }
10391          break;
10392       }
10393       case arrayExp:
10394       {
10395          Type type = null;
10396          char * typeString = null;
10397          char typeStringBuf[1024];
10398          if(exp.destType && exp.destType.kind == classType && exp.destType._class && exp.destType._class.registered &&
10399             exp.destType._class.registered != containerClass && eClass_IsDerived(exp.destType._class.registered, containerClass))
10400          {
10401             Class templateClass = exp.destType._class.registered;
10402             typeString = templateClass.templateArgs[2].dataTypeString;
10403          }
10404          else if(exp.list)
10405          {
10406             // Guess type from expressions in the array
10407             Expression e;
10408             for(e = exp.list->first; e; e = e.next)
10409             {
10410                ProcessExpressionType(e);
10411                if(e.expType)
10412                {
10413                   if(!type) { type = e.expType; type.refCount++; }
10414                   else
10415                   {
10416                      // if(!MatchType(e.expType, type, null, null, null, false, false, false))
10417                      if(!MatchTypeExpression(e, type, null, false))
10418                      {
10419                         FreeType(type);
10420                         type = e.expType;
10421                         e.expType = null;
10422
10423                         e = exp.list->first;
10424                         ProcessExpressionType(e);
10425                         if(e.expType)
10426                         {
10427                            //if(!MatchTypes(e.expType, type, null, null, null, false, false, false))
10428                            if(!MatchTypeExpression(e, type, null, false))
10429                            {
10430                               FreeType(e.expType);
10431                               e.expType = null;
10432                               FreeType(type);
10433                               type = null;
10434                               break;
10435                            }
10436                         }
10437                      }
10438                   }
10439                   if(e.expType)
10440                   {
10441                      FreeType(e.expType);
10442                      e.expType = null;
10443                   }
10444                }
10445             }
10446             if(type)
10447             {
10448                typeStringBuf[0] = '\0';
10449                PrintTypeNoConst(type, typeStringBuf, false, true);
10450                typeString = typeStringBuf;
10451                FreeType(type);
10452                type = null;
10453             }
10454          }
10455          if(typeString)
10456          {
10457             /*
10458             (Container)& (struct BuiltInContainer)
10459             {
10460                ._vTbl = class(BuiltInContainer)._vTbl,
10461                ._class = class(BuiltInContainer),
10462                .refCount = 0,
10463                .data = (int[]){ 1, 7, 3, 4, 5 },
10464                .count = 5,
10465                .type = class(int),
10466             }
10467             */
10468             char templateString[1024];
10469             OldList * initializers = MkList();
10470             OldList * structInitializers = MkList();
10471             OldList * specs = MkList();
10472             Expression expExt;
10473             Declarator decl = SpecDeclFromString(typeString, specs, null);
10474             sprintf(templateString, "Container<%s>", typeString);
10475
10476             if(exp.list)
10477             {
10478                Expression e;
10479                type = ProcessTypeString(typeString, false);
10480                while(e = exp.list->first)
10481                {
10482                   exp.list->Remove(e);
10483                   e.destType = type;
10484                   type.refCount++;
10485                   ProcessExpressionType(e);
10486                   ListAdd(initializers, MkInitializerAssignment(e));
10487                }
10488                FreeType(type);
10489                delete exp.list;
10490             }
10491
10492             DeclareStruct("ecere::com::BuiltInContainer", false);
10493
10494             ListAdd(structInitializers, /*MkIdentifier("_vTbl")*/    MkInitializerAssignment(MkExpMember(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null), MkIdentifier("_vTbl"))));
10495                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10496             ListAdd(structInitializers, /*MkIdentifier("_class")*/   MkInitializerAssignment(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null)));
10497                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10498             ListAdd(structInitializers, /*MkIdentifier("_refCount")*/MkInitializerAssignment(MkExpConstant("0")));
10499                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10500             ListAdd(structInitializers, /*MkIdentifier("data")*/     MkInitializerAssignment(MkExpExtensionInitializer(
10501                MkTypeName(specs, MkDeclaratorArray(decl, null)),
10502                MkInitializerList(initializers))));
10503                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10504             ListAdd(structInitializers, /*MkIdentifier("count")*/    MkInitializerAssignment({ type = constantExp, constant = PrintString(initializers->count) }));
10505                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10506             ListAdd(structInitializers, /*MkIdentifier("type")*/     MkInitializerAssignment(MkExpClass(CopyList(specs, CopySpecifier), CopyDeclarator(decl))));
10507                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10508             exp.expType = ProcessTypeString(templateString, false);
10509             exp.type = bracketsExp;
10510             exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(templateString)), null),
10511                MkExpOp(null, '&',
10512                expExt = MkExpExtensionInitializer(MkTypeName(MkListOne(MkSpecifierName("BuiltInContainer")), null),
10513                   MkInitializerList(structInitializers)))));
10514             ProcessExpressionType(expExt);
10515          }
10516          else
10517          {
10518             exp.expType = ProcessTypeString("Container", false);
10519             Compiler_Error($"Couldn't determine type of array elements\n");
10520          }
10521          break;
10522       }
10523    }
10524
10525    if(exp.expType && exp.expType.kind == thisClassType && thisClass && (!exp.destType || exp.destType.kind != thisClassType))
10526    {
10527       FreeType(exp.expType);
10528       exp.expType = ReplaceThisClassType(thisClass);
10529    }
10530
10531    // Resolve structures here
10532    if(exp.expType && (exp.expType.kind == structType || exp.expType.kind == unionType || exp.expType.kind == enumType) && !exp.expType.members.first && exp.expType.enumName)
10533    {
10534       Symbol symbol = FindSymbol(exp.expType.enumName, curContext, globalContext, true, false);
10535       // TODO: Fix members reference...
10536       if(symbol)
10537       {
10538          if(exp.expType.kind != enumType)
10539          {
10540             Type member;
10541             String enumName = CopyString(exp.expType.enumName);
10542
10543             // Fixed a memory leak on self-referencing C structs typedefs
10544             // by instantiating a new type rather than simply copying members
10545             // into exp.expType
10546             FreeType(exp.expType);
10547             exp.expType = Type { };
10548             exp.expType.kind = symbol.type.kind;
10549             exp.expType.refCount++;
10550             exp.expType.enumName = enumName;
10551
10552             exp.expType.members = symbol.type.members;
10553             for(member = symbol.type.members.first; member; member = member.next)
10554                member.refCount++;
10555          }
10556          else
10557          {
10558             NamedLink member;
10559             for(member = symbol.type.members.first; member; member = member.next)
10560             {
10561                NamedLink value { name = CopyString(member.name) };
10562                exp.expType.members.Add(value);
10563             }
10564          }
10565       }
10566    }
10567
10568    yylloc = exp.loc;
10569    if(exp.destType && (exp.destType.kind == voidType || exp.destType.kind == dummyType) );
10570    else if(exp.destType && !exp.destType.keepCast)
10571    {
10572       if(!CheckExpressionType(exp, exp.destType, false))
10573       {
10574          if(!exp.destType.count || unresolved)
10575          {
10576             if(!exp.expType)
10577             {
10578                yylloc = exp.loc;
10579                if(exp.destType.kind != ellipsisType)
10580                {
10581                   char type2[1024];
10582                   type2[0] = '\0';
10583                   if(inCompiler)
10584                   {
10585                      char expString[10240];
10586                      expString[0] = '\0';
10587
10588                      PrintType(exp.destType, type2, false, true);
10589
10590                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10591                      if(unresolved)
10592                         Compiler_Error($"unresolved identifier %s; expected %s\n", expString, type2);
10593                      else if(exp.type != dummyExp)
10594                         Compiler_Error($"couldn't determine type of %s; expected %s\n", expString, type2);
10595                   }
10596                }
10597                else
10598                {
10599                   char expString[10240] ;
10600                   expString[0] = '\0';
10601                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10602
10603                   if(unresolved)
10604                      Compiler_Error($"unresolved identifier %s\n", expString);
10605                   else if(exp.type != dummyExp)
10606                      Compiler_Error($"couldn't determine type of %s\n", expString);
10607                }
10608             }
10609             else
10610             {
10611                char type1[1024];
10612                char type2[1024];
10613                type1[0] = '\0';
10614                type2[0] = '\0';
10615                if(inCompiler)
10616                {
10617                   PrintType(exp.expType, type1, false, true);
10618                   PrintType(exp.destType, type2, false, true);
10619                }
10620
10621                //CheckExpressionType(exp, exp.destType, false);
10622
10623                if(exp.destType.truth && exp.destType._class && exp.destType._class.registered && !strcmp(exp.destType._class.registered.name, "bool") &&
10624                   exp.expType.kind != voidType && exp.expType.kind != structType && exp.expType.kind != unionType &&
10625                   (exp.expType.kind != classType || exp.expType.classObjectType || (exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type != structClass)));
10626                else
10627                {
10628                   char expString[10240];
10629                   expString[0] = '\0';
10630                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10631
10632 #ifdef _DEBUG
10633                   CheckExpressionType(exp, exp.destType, false);
10634 #endif
10635                   // Flex & Bison generate code that triggers this, so we ignore it for a quiet sdk build:
10636                   if(!sourceFile || (strcmp(sourceFile, "src\\lexer.ec") && strcmp(sourceFile, "src/lexer.ec") && strcmp(sourceFile, "src\\grammar.ec") && strcmp(sourceFile, "src/grammar.ec")))
10637                      Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
10638
10639                   // TO CHECK: FORCING HERE TO HELP DEBUGGER
10640                   FreeType(exp.expType);
10641                   exp.destType.refCount++;
10642                   exp.expType = exp.destType;
10643                }
10644             }
10645          }
10646       }
10647       else if(exp.destType && exp.destType.kind == ellipsisType && exp.expType && exp.expType.passAsTemplate)
10648       {
10649          Expression newExp { };
10650          char typeString[1024];
10651          OldList * specs = MkList();
10652          Declarator decl;
10653
10654          typeString[0] = '\0';
10655
10656          *newExp = *exp;
10657
10658          if(exp.expType)  exp.expType.refCount++;
10659          if(exp.expType)  exp.expType.refCount++;
10660          exp.type = castExp;
10661          newExp.destType = exp.expType;
10662
10663          PrintType(exp.expType, typeString, false, false);
10664          decl = SpecDeclFromString(typeString, specs, null);
10665
10666          exp.cast.typeName = MkTypeName(specs, decl);
10667          exp.cast.exp = newExp;
10668       }
10669    }
10670    else if(unresolved)
10671    {
10672       if(exp.identifier._class && exp.identifier._class.name)
10673          Compiler_Error($"unresolved identifier %s::%s\n", exp.identifier._class.name, exp.identifier.string);
10674       else if(exp.identifier.string && exp.identifier.string[0])
10675          Compiler_Error($"unresolved identifier %s\n", exp.identifier.string);
10676    }
10677    else if(!exp.expType && exp.type != dummyExp)
10678    {
10679       char expString[10240];
10680       expString[0] = '\0';
10681       if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10682       Compiler_Error($"couldn't determine type of %s\n", expString);
10683    }
10684
10685    // Let's try to support any_object & typed_object here:
10686    if(inCompiler)
10687       ApplyAnyObjectLogic(exp);
10688
10689    // Mark nohead classes as by reference, unless we're casting them to an integral type
10690    if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
10691       exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
10692          (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
10693           exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
10694    {
10695       exp.byReference = true;
10696    }
10697    yylloc = oldyylloc;
10698 }
10699
10700 static void FindNextDataMember(Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
10701 {
10702    // THIS CODE WILL FIND NEXT MEMBER...
10703    if(*curMember)
10704    {
10705       *curMember = (*curMember).next;
10706
10707       if(subMemberStackPos && *subMemberStackPos > 0 && subMemberStack[*subMemberStackPos-1].type == unionMember)
10708       {
10709          *curMember = subMemberStack[--(*subMemberStackPos)];
10710          *curMember = (*curMember).next;
10711       }
10712
10713       // SKIP ALL PROPERTIES HERE...
10714       while((*curMember) && (*curMember).isProperty)
10715          *curMember = (*curMember).next;
10716
10717       if(subMemberStackPos)
10718       {
10719          while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
10720          {
10721             subMemberStack[(*subMemberStackPos)++] = *curMember;
10722
10723             *curMember = (*curMember).members.first;
10724             while(*curMember && (*curMember).isProperty)
10725                *curMember = (*curMember).next;
10726          }
10727       }
10728    }
10729    while(!*curMember)
10730    {
10731       if(!*curMember)
10732       {
10733          if(subMemberStackPos && *subMemberStackPos)
10734          {
10735             *curMember = subMemberStack[--(*subMemberStackPos)];
10736             *curMember = (*curMember).next;
10737          }
10738          else
10739          {
10740             Class lastCurClass = *curClass;
10741
10742             if(*curClass == _class) break;     // REACHED THE END
10743
10744             for(*curClass = _class; (*curClass).base != lastCurClass && (*curClass).base.type != systemClass; *curClass = (*curClass).base);
10745             *curMember = (*curClass).membersAndProperties.first;
10746          }
10747
10748          while((*curMember) && (*curMember).isProperty)
10749             *curMember = (*curMember).next;
10750          if(subMemberStackPos)
10751          {
10752             while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
10753             {
10754                subMemberStack[(*subMemberStackPos)++] = *curMember;
10755
10756                *curMember = (*curMember).members.first;
10757                while(*curMember && (*curMember).isProperty)
10758                   *curMember = (*curMember).next;
10759             }
10760          }
10761       }
10762    }
10763 }
10764
10765
10766 static void ProcessInitializer(Initializer init, Type type)
10767 {
10768    switch(init.type)
10769    {
10770       case expInitializer:
10771          if(!init.exp || init.exp.type != instanceExp || !init.exp.instance || init.exp.instance._class || !type || type.kind == classType)
10772          {
10773             // TESTING THIS FOR SHUTTING = 0 WARNING
10774             if(init.exp && !init.exp.destType)
10775             {
10776                FreeType(init.exp.destType);
10777                init.exp.destType = type;
10778                if(type) type.refCount++;
10779             }
10780             if(init.exp)
10781             {
10782                ProcessExpressionType(init.exp);
10783                init.isConstant = init.exp.isConstant;
10784             }
10785             break;
10786          }
10787          else
10788          {
10789             Expression exp = init.exp;
10790             Instantiation inst = exp.instance;
10791             MembersInit members;
10792
10793             init.type = listInitializer;
10794             init.list = MkList();
10795
10796             if(inst.members)
10797             {
10798                for(members = inst.members->first; members; members = members.next)
10799                {
10800                   if(members.type == dataMembersInit)
10801                   {
10802                      MemberInit member;
10803                      for(member = members.dataMembers->first; member; member = member.next)
10804                      {
10805                         ListAdd(init.list, member.initializer);
10806                         member.initializer = null;
10807                      }
10808                   }
10809                   // Discard all MembersInitMethod
10810                }
10811             }
10812             FreeExpression(exp);
10813          }
10814       case listInitializer:
10815       {
10816          Initializer i;
10817          Type initializerType = null;
10818          Class curClass = null;
10819          DataMember curMember = null;
10820          DataMember subMemberStack[256];
10821          int subMemberStackPos = 0;
10822
10823          if(type && type.kind == arrayType)
10824             initializerType = Dereference(type);
10825          else if(type && (type.kind == structType || type.kind == unionType))
10826             initializerType = type.members.first;
10827
10828          for(i = init.list->first; i; i = i.next)
10829          {
10830             if(type && type.kind == classType && type._class && type._class.registered)
10831             {
10832                // 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)
10833                FindNextDataMember(type._class.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
10834                // TODO: Generate error on initializing a private data member this way from another module...
10835                if(curMember)
10836                {
10837                   if(!curMember.dataType)
10838                      curMember.dataType = ProcessTypeString(curMember.dataTypeString, false);
10839                   initializerType = curMember.dataType;
10840                }
10841             }
10842             ProcessInitializer(i, initializerType);
10843             if(initializerType && type && (type.kind == structType || type.kind == unionType))
10844                initializerType = initializerType.next;
10845             if(!i.isConstant)
10846                init.isConstant = false;
10847          }
10848
10849          if(type && type.kind == arrayType)
10850             FreeType(initializerType);
10851
10852          if(type && type.kind != arrayType && type.kind != structType && type.kind != unionType && (type.kind != classType || !type._class.registered || type._class.registered.type != structClass))
10853          {
10854             Compiler_Error($"Assigning list initializer to non list\n");
10855          }
10856          break;
10857       }
10858    }
10859 }
10860
10861 static void ProcessSpecifier(Specifier spec, bool declareStruct)
10862 {
10863    switch(spec.type)
10864    {
10865       case baseSpecifier:
10866       {
10867          if(spec.specifier == THISCLASS)
10868          {
10869             if(thisClass)
10870             {
10871                spec.type = nameSpecifier;
10872                spec.name = ReplaceThisClass(thisClass);
10873                spec.symbol = FindClass(spec.name);
10874                ProcessSpecifier(spec, declareStruct);
10875             }
10876          }
10877          break;
10878       }
10879       case nameSpecifier:
10880       {
10881          Symbol symbol = FindType(curContext, spec.name);
10882          if(symbol)
10883             DeclareType(symbol.type, true, true);
10884          else if((symbol = spec.symbol /*FindClass(spec.name)*/) && symbol.registered && symbol.registered.type == structClass && declareStruct)
10885             DeclareStruct(spec.name, false);
10886          break;
10887       }
10888       case enumSpecifier:
10889       {
10890          Enumerator e;
10891          if(spec.list)
10892          {
10893             for(e = spec.list->first; e; e = e.next)
10894             {
10895                if(e.exp)
10896                   ProcessExpressionType(e.exp);
10897             }
10898          }
10899          break;
10900       }
10901       case structSpecifier:
10902       case unionSpecifier:
10903       {
10904          if(spec.definitions)
10905          {
10906             ClassDef def;
10907             Symbol symbol = spec.id ? FindClass(spec.id.string) : null;
10908             //if(symbol)
10909                ProcessClass(spec.definitions, symbol);
10910             /*else
10911             {
10912                for(def = spec.definitions->first; def; def = def.next)
10913                {
10914                   //if(def.type == declarationClassDef && def.decl && def.decl.type == DeclarationStruct)
10915                      ProcessDeclaration(def.decl);
10916                }
10917             }*/
10918          }
10919          break;
10920       }
10921       /*
10922       case classSpecifier:
10923       {
10924          Symbol classSym = FindClass(spec.name);
10925          if(classSym && classSym.registered && classSym.registered.type == structClass)
10926             DeclareStruct(spec.name, false);
10927          break;
10928       }
10929       */
10930    }
10931 }
10932
10933
10934 static void ProcessDeclarator(Declarator decl)
10935 {
10936    switch(decl.type)
10937    {
10938       case identifierDeclarator:
10939          if(decl.identifier.classSym /* TODO: Name Space Fix ups  || decl.identifier.nameSpace*/)
10940          {
10941             FreeSpecifier(decl.identifier._class);
10942             decl.identifier._class = null;
10943          }
10944          break;
10945       case arrayDeclarator:
10946          if(decl.array.exp)
10947             ProcessExpressionType(decl.array.exp);
10948       case structDeclarator:
10949       case bracketsDeclarator:
10950       case functionDeclarator:
10951       case pointerDeclarator:
10952       case extendedDeclarator:
10953       case extendedDeclaratorEnd:
10954          if(decl.declarator)
10955             ProcessDeclarator(decl.declarator);
10956          if(decl.type == functionDeclarator)
10957          {
10958             Identifier id = GetDeclId(decl);
10959             if(id && id._class)
10960             {
10961                TypeName param
10962                {
10963                   qualifiers = MkListOne(id._class);
10964                   declarator = null;
10965                };
10966                if(!decl.function.parameters)
10967                   decl.function.parameters = MkList();
10968                decl.function.parameters->Insert(null, param);
10969                id._class = null;
10970             }
10971             if(decl.function.parameters)
10972             {
10973                TypeName param;
10974
10975                for(param = decl.function.parameters->first; param; param = param.next)
10976                {
10977                   if(param.qualifiers && param.qualifiers->first)
10978                   {
10979                      Specifier spec = param.qualifiers->first;
10980                      if(spec && spec.specifier == TYPED_OBJECT)
10981                      {
10982                         Declarator d = param.declarator;
10983                         TypeName newParam
10984                         {
10985                            qualifiers = MkListOne(MkSpecifier(VOID));
10986                            declarator = MkDeclaratorPointer(MkPointer(null,null), d);
10987                         };
10988
10989                         FreeList(param.qualifiers, FreeSpecifier);
10990
10991                         param.qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
10992                         param.declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
10993
10994                         decl.function.parameters->Insert(param, newParam);
10995                         param = newParam;
10996                      }
10997                      else if(spec && spec.specifier == ANY_OBJECT)
10998                      {
10999                         Declarator d = param.declarator;
11000
11001                         FreeList(param.qualifiers, FreeSpecifier);
11002
11003                         param.qualifiers = MkListOne(MkSpecifier(VOID));
11004                         param.declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11005                      }
11006                      else if(spec.specifier == THISCLASS)
11007                      {
11008                         if(thisClass)
11009                         {
11010                            spec.type = nameSpecifier;
11011                            spec.name = ReplaceThisClass(thisClass);
11012                            spec.symbol = FindClass(spec.name);
11013                            ProcessSpecifier(spec, false);
11014                         }
11015                      }
11016                   }
11017
11018                   if(param.declarator)
11019                      ProcessDeclarator(param.declarator);
11020                }
11021             }
11022          }
11023          break;
11024    }
11025 }
11026
11027 static void ProcessDeclaration(Declaration decl)
11028 {
11029    yylloc = decl.loc;
11030    switch(decl.type)
11031    {
11032       case initDeclaration:
11033       {
11034          bool declareStruct = false;
11035          /*
11036          lineNum = decl.pos.line;
11037          column = decl.pos.col;
11038          */
11039
11040          if(decl.declarators)
11041          {
11042             InitDeclarator d;
11043
11044             for(d = decl.declarators->first; d; d = d.next)
11045             {
11046                Type type, subType;
11047                ProcessDeclarator(d.declarator);
11048
11049                type = ProcessType(decl.specifiers, d.declarator);
11050
11051                if(d.initializer)
11052                {
11053                   ProcessInitializer(d.initializer, type);
11054
11055                   // Change "ColorRGB a = ColorRGB { 1,2,3 } => ColorRGB a { 1,2,3 }
11056
11057                   if(decl.declarators->count == 1 && d.initializer.type == expInitializer &&
11058                      d.initializer.exp.type == instanceExp)
11059                   {
11060                      if(type.kind == classType && type._class ==
11061                         d.initializer.exp.expType._class)
11062                      {
11063                         Instantiation inst = d.initializer.exp.instance;
11064                         inst.exp = MkExpIdentifier(CopyIdentifier(GetDeclId(d.declarator)));
11065
11066                         d.initializer.exp.instance = null;
11067                         if(decl.specifiers)
11068                            FreeList(decl.specifiers, FreeSpecifier);
11069                         FreeList(decl.declarators, FreeInitDeclarator);
11070
11071                         d = null;
11072
11073                         decl.type = instDeclaration;
11074                         decl.inst = inst;
11075                      }
11076                   }
11077                }
11078                for(subType = type; subType;)
11079                {
11080                   if(subType.kind == classType)
11081                   {
11082                      declareStruct = true;
11083                      break;
11084                   }
11085                   else if(subType.kind == pointerType)
11086                      break;
11087                   else if(subType.kind == arrayType)
11088                      subType = subType.arrayType;
11089                   else
11090                      break;
11091                }
11092
11093                FreeType(type);
11094                if(!d) break;
11095             }
11096          }
11097
11098          if(decl.specifiers)
11099          {
11100             Specifier s;
11101             for(s = decl.specifiers->first; s; s = s.next)
11102             {
11103                ProcessSpecifier(s, declareStruct);
11104             }
11105          }
11106          break;
11107       }
11108       case instDeclaration:
11109       {
11110          ProcessInstantiationType(decl.inst);
11111          break;
11112       }
11113       case structDeclaration:
11114       {
11115          Specifier spec;
11116          Declarator d;
11117          bool declareStruct = false;
11118
11119          if(decl.declarators)
11120          {
11121             for(d = decl.declarators->first; d; d = d.next)
11122             {
11123                Type type = ProcessType(decl.specifiers, d.declarator);
11124                Type subType;
11125                ProcessDeclarator(d);
11126                for(subType = type; subType;)
11127                {
11128                   if(subType.kind == classType)
11129                   {
11130                      declareStruct = true;
11131                      break;
11132                   }
11133                   else if(subType.kind == pointerType)
11134                      break;
11135                   else if(subType.kind == arrayType)
11136                      subType = subType.arrayType;
11137                   else
11138                      break;
11139                }
11140                FreeType(type);
11141             }
11142          }
11143          if(decl.specifiers)
11144          {
11145             for(spec = decl.specifiers->first; spec; spec = spec.next)
11146                ProcessSpecifier(spec, declareStruct);
11147          }
11148          break;
11149       }
11150    }
11151 }
11152
11153 static FunctionDefinition curFunction;
11154
11155 static void CreateFireWatcher(Property prop, Expression object, Statement stmt)
11156 {
11157    char propName[1024], propNameM[1024];
11158    char getName[1024], setName[1024];
11159    OldList * args;
11160
11161    DeclareProperty(prop, setName, getName);
11162
11163    // eInstance_FireWatchers(object, prop);
11164    strcpy(propName, "__ecereProp_");
11165    FullClassNameCat(propName, prop._class.fullName, false);
11166    strcat(propName, "_");
11167    // strcat(propName, prop.name);
11168    FullClassNameCat(propName, prop.name, true);
11169    MangleClassName(propName);
11170
11171    strcpy(propNameM, "__ecerePropM_");
11172    FullClassNameCat(propNameM, prop._class.fullName, false);
11173    strcat(propNameM, "_");
11174    // strcat(propNameM, prop.name);
11175    FullClassNameCat(propNameM, prop.name, true);
11176    MangleClassName(propNameM);
11177
11178    if(prop.isWatchable)
11179    {
11180       args = MkList();
11181       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11182       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11183       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11184
11185       args = MkList();
11186       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11187       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11188       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11189    }
11190
11191
11192    {
11193       args = MkList();
11194       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11195       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11196       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11197
11198       args = MkList();
11199       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11200       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11201       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11202    }
11203
11204    if(curFunction.propSet && !strcmp(curFunction.propSet.string, prop.name) &&
11205       (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
11206       curFunction.propSet.fireWatchersDone = true;
11207 }
11208
11209 static void ProcessStatement(Statement stmt)
11210 {
11211    yylloc = stmt.loc;
11212    /*
11213    lineNum = stmt.pos.line;
11214    column = stmt.pos.col;
11215    */
11216    switch(stmt.type)
11217    {
11218       case labeledStmt:
11219          ProcessStatement(stmt.labeled.stmt);
11220          break;
11221       case caseStmt:
11222          // This expression should be constant...
11223          if(stmt.caseStmt.exp)
11224          {
11225             FreeType(stmt.caseStmt.exp.destType);
11226             stmt.caseStmt.exp.destType = curSwitchType;
11227             if(curSwitchType) curSwitchType.refCount++;
11228             ProcessExpressionType(stmt.caseStmt.exp);
11229             ComputeExpression(stmt.caseStmt.exp);
11230          }
11231          if(stmt.caseStmt.stmt)
11232             ProcessStatement(stmt.caseStmt.stmt);
11233          break;
11234       case compoundStmt:
11235       {
11236          if(stmt.compound.context)
11237          {
11238             Declaration decl;
11239             Statement s;
11240
11241             Statement prevCompound = curCompound;
11242             Context prevContext = curContext;
11243
11244             if(!stmt.compound.isSwitch)
11245                curCompound = stmt;
11246             curContext = stmt.compound.context;
11247
11248             if(stmt.compound.declarations)
11249             {
11250                for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
11251                   ProcessDeclaration(decl);
11252             }
11253             if(stmt.compound.statements)
11254             {
11255                for(s = stmt.compound.statements->first; s; s = s.next)
11256                   ProcessStatement(s);
11257             }
11258
11259             curContext = prevContext;
11260             curCompound = prevCompound;
11261          }
11262          break;
11263       }
11264       case expressionStmt:
11265       {
11266          Expression exp;
11267          if(stmt.expressions)
11268          {
11269             for(exp = stmt.expressions->first; exp; exp = exp.next)
11270                ProcessExpressionType(exp);
11271          }
11272          break;
11273       }
11274       case ifStmt:
11275       {
11276          Expression exp;
11277
11278          FreeType(((Expression)stmt.ifStmt.exp->last).destType);
11279          ((Expression)stmt.ifStmt.exp->last).destType = MkClassType("bool");
11280          ((Expression)stmt.ifStmt.exp->last).destType.truth = true;
11281          for(exp = stmt.ifStmt.exp->first; exp; exp = exp.next)
11282          {
11283             ProcessExpressionType(exp);
11284          }
11285          if(stmt.ifStmt.stmt)
11286             ProcessStatement(stmt.ifStmt.stmt);
11287          if(stmt.ifStmt.elseStmt)
11288             ProcessStatement(stmt.ifStmt.elseStmt);
11289          break;
11290       }
11291       case switchStmt:
11292       {
11293          Type oldSwitchType = curSwitchType;
11294          if(stmt.switchStmt.exp)
11295          {
11296             Expression exp;
11297             for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
11298             {
11299                if(!exp.next)
11300                {
11301                   /*
11302                   Type destType
11303                   {
11304                      kind = intType;
11305                      refCount = 1;
11306                   };
11307                   e.exp.destType = destType;
11308                   */
11309
11310                   ProcessExpressionType(exp);
11311                }
11312                if(!exp.next)
11313                   curSwitchType = exp.expType;
11314             }
11315          }
11316          ProcessStatement(stmt.switchStmt.stmt);
11317          curSwitchType = oldSwitchType;
11318          break;
11319       }
11320       case whileStmt:
11321       {
11322          if(stmt.whileStmt.exp)
11323          {
11324             Expression exp;
11325
11326             FreeType(((Expression)stmt.whileStmt.exp->last).destType);
11327             ((Expression)stmt.whileStmt.exp->last).destType = MkClassType("bool");
11328             ((Expression)stmt.whileStmt.exp->last).destType.truth = true;
11329             for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
11330             {
11331                ProcessExpressionType(exp);
11332             }
11333          }
11334          if(stmt.whileStmt.stmt)
11335             ProcessStatement(stmt.whileStmt.stmt);
11336          break;
11337       }
11338       case doWhileStmt:
11339       {
11340          if(stmt.doWhile.exp)
11341          {
11342             Expression exp;
11343
11344             if(stmt.doWhile.exp->last)
11345             {
11346                FreeType(((Expression)stmt.doWhile.exp->last).destType);
11347                ((Expression)stmt.doWhile.exp->last).destType = MkClassType("bool");
11348                ((Expression)stmt.doWhile.exp->last).destType.truth = true;
11349             }
11350             for(exp = stmt.doWhile.exp->first; exp; exp = exp.next)
11351             {
11352                ProcessExpressionType(exp);
11353             }
11354          }
11355          if(stmt.doWhile.stmt)
11356             ProcessStatement(stmt.doWhile.stmt);
11357          break;
11358       }
11359       case forStmt:
11360       {
11361          Expression exp;
11362          if(stmt.forStmt.init)
11363             ProcessStatement(stmt.forStmt.init);
11364
11365          if(stmt.forStmt.check && stmt.forStmt.check.expressions)
11366          {
11367             FreeType(((Expression)stmt.forStmt.check.expressions->last).destType);
11368             ((Expression)stmt.forStmt.check.expressions->last).destType = MkClassType("bool");
11369             ((Expression)stmt.forStmt.check.expressions->last).destType.truth = true;
11370          }
11371
11372          if(stmt.forStmt.check)
11373             ProcessStatement(stmt.forStmt.check);
11374          if(stmt.forStmt.increment)
11375          {
11376             for(exp = stmt.forStmt.increment->first; exp; exp = exp.next)
11377                ProcessExpressionType(exp);
11378          }
11379
11380          if(stmt.forStmt.stmt)
11381             ProcessStatement(stmt.forStmt.stmt);
11382          break;
11383       }
11384       case forEachStmt:
11385       {
11386          Identifier id = stmt.forEachStmt.id;
11387          OldList * exp = stmt.forEachStmt.exp;
11388          OldList * filter = stmt.forEachStmt.filter;
11389          Statement block = stmt.forEachStmt.stmt;
11390          char iteratorType[1024];
11391          Type source;
11392          Expression e;
11393          bool isBuiltin = exp && exp->last &&
11394             (((Expression)exp->last).type == ExpressionType::arrayExp ||
11395               (((Expression)exp->last).type == castExp && ((Expression)exp->last).cast.exp.type == ExpressionType::arrayExp));
11396          Expression arrayExp;
11397          char * typeString = null;
11398          int builtinCount = 0;
11399
11400          for(e = exp ? exp->first : null; e; e = e.next)
11401          {
11402             if(!e.next)
11403             {
11404                FreeType(e.destType);
11405                e.destType = ProcessTypeString("Container", false);
11406             }
11407             if(!isBuiltin || e.next)
11408                ProcessExpressionType(e);
11409          }
11410
11411          source = (exp && exp->last) ? ((Expression)exp->last).expType : null;
11412          if(isBuiltin || (source && source.kind == classType && source._class && source._class.registered && source._class.registered != containerClass &&
11413             eClass_IsDerived(source._class.registered, containerClass)))
11414          {
11415             Class _class = source ? source._class.registered : null;
11416             Symbol symbol;
11417             Expression expIt = null;
11418             bool isMap = false, isArray = false, isLinkList = false, isList = false, isCustomAVLTree = false, isAVLTree = false;
11419             Class arrayClass = eSystem_FindClass(privateModule, "Array");
11420             Class linkListClass = eSystem_FindClass(privateModule, "LinkList");
11421             Class customAVLTreeClass = eSystem_FindClass(privateModule, "CustomAVLTree");
11422             stmt.type = compoundStmt;
11423
11424             stmt.compound.context = Context { };
11425             stmt.compound.context.parent = curContext;
11426             curContext = stmt.compound.context;
11427
11428             if(source && eClass_IsDerived(source._class.registered, customAVLTreeClass))
11429             {
11430                Class mapClass = eSystem_FindClass(privateModule, "Map");
11431                Class avlTreeClass = eSystem_FindClass(privateModule, "AVLTree");
11432                isCustomAVLTree = true;
11433                if(eClass_IsDerived(source._class.registered, avlTreeClass))
11434                   isAVLTree = true;
11435                else if(eClass_IsDerived(source._class.registered, mapClass))
11436                   isMap = true;
11437             }
11438             else if(source && eClass_IsDerived(source._class.registered, arrayClass)) isArray = true;
11439             else if(source && eClass_IsDerived(source._class.registered, linkListClass))
11440             {
11441                Class listClass = eSystem_FindClass(privateModule, "List");
11442                isLinkList = true;
11443                isList = eClass_IsDerived(source._class.registered, listClass);
11444             }
11445
11446             if(isArray)
11447             {
11448                Declarator decl;
11449                OldList * specs = MkList();
11450                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
11451                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
11452                stmt.compound.declarations = MkListOne(
11453                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11454                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11455                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalArray")),
11456                      MkInitializerAssignment(MkExpBrackets(exp))))));
11457             }
11458             else if(isBuiltin)
11459             {
11460                Type type = null;
11461                char typeStringBuf[1024];
11462
11463                // TODO: Merge this code?
11464                arrayExp = (((Expression)exp->last).type == ExpressionType::arrayExp) ? (Expression)exp->last : ((Expression)exp->last).cast.exp;
11465                if(((Expression)exp->last).type == castExp)
11466                {
11467                   TypeName typeName = ((Expression)exp->last).cast.typeName;
11468                   if(typeName)
11469                      arrayExp.destType = ProcessType(typeName.qualifiers, typeName.declarator);
11470                }
11471
11472                if(arrayExp.destType && arrayExp.destType.kind == classType && arrayExp.destType._class && arrayExp.destType._class.registered &&
11473                   arrayExp.destType._class.registered != containerClass && eClass_IsDerived(arrayExp.destType._class.registered, containerClass) &&
11474                   arrayExp.destType._class.registered.templateArgs)
11475                {
11476                   Class templateClass = arrayExp.destType._class.registered;
11477                   typeString = templateClass.templateArgs[2].dataTypeString;
11478                }
11479                else if(arrayExp.list)
11480                {
11481                   // Guess type from expressions in the array
11482                   Expression e;
11483                   for(e = arrayExp.list->first; e; e = e.next)
11484                   {
11485                      ProcessExpressionType(e);
11486                      if(e.expType)
11487                      {
11488                         if(!type) { type = e.expType; type.refCount++; }
11489                         else
11490                         {
11491                            // if(!MatchType(e.expType, type, null, null, null, false, false, false))
11492                            if(!MatchTypeExpression(e, type, null, false))
11493                            {
11494                               FreeType(type);
11495                               type = e.expType;
11496                               e.expType = null;
11497
11498                               e = arrayExp.list->first;
11499                               ProcessExpressionType(e);
11500                               if(e.expType)
11501                               {
11502                                  //if(!MatchTypes(e.expType, type, null, null, null, false, false, false, false))
11503                                  if(!MatchTypeExpression(e, type, null, false))
11504                                  {
11505                                     FreeType(e.expType);
11506                                     e.expType = null;
11507                                     FreeType(type);
11508                                     type = null;
11509                                     break;
11510                                  }
11511                               }
11512                            }
11513                         }
11514                         if(e.expType)
11515                         {
11516                            FreeType(e.expType);
11517                            e.expType = null;
11518                         }
11519                      }
11520                   }
11521                   if(type)
11522                   {
11523                      typeStringBuf[0] = '\0';
11524                      PrintType(type, typeStringBuf, false, true);
11525                      typeString = typeStringBuf;
11526                      FreeType(type);
11527                   }
11528                }
11529                if(typeString)
11530                {
11531                   OldList * initializers = MkList();
11532                   Declarator decl;
11533                   OldList * specs = MkList();
11534                   if(arrayExp.list)
11535                   {
11536                      Expression e;
11537
11538                      builtinCount = arrayExp.list->count;
11539                      type = ProcessTypeString(typeString, false);
11540                      while(e = arrayExp.list->first)
11541                      {
11542                         arrayExp.list->Remove(e);
11543                         e.destType = type;
11544                         type.refCount++;
11545                         ProcessExpressionType(e);
11546                         ListAdd(initializers, MkInitializerAssignment(e));
11547                      }
11548                      FreeType(type);
11549                      delete arrayExp.list;
11550                   }
11551                   decl = SpecDeclFromString(typeString, specs, MkDeclaratorIdentifier(id));
11552                   stmt.compound.declarations = MkListOne(MkDeclaration(CopyList(specs, CopySpecifier),
11553                      MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), /*CopyDeclarator(*/decl/*)*/), null))));
11554
11555                   ListAdd(stmt.compound.declarations, MkDeclaration(specs, MkListOne(MkInitDeclarator(
11556                      PlugDeclarator(
11557                         /*CopyDeclarator(*/decl/*)*/, MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__internalArray")), null)
11558                         ), MkInitializerList(initializers)))));
11559                   FreeList(exp, FreeExpression);
11560                }
11561                else
11562                {
11563                   arrayExp.expType = ProcessTypeString("Container", false);
11564                   Compiler_Error($"Couldn't determine type of array elements\n");
11565                }
11566
11567                /*
11568                Declarator decl;
11569                OldList * specs = MkList();
11570
11571                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
11572                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
11573                stmt.compound.declarations = MkListOne(
11574                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11575                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName("BuiltInContainer")),
11576                   MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(MkIdentifier("__internalArray"))),
11577                      MkInitializerAssignment(MkExpBrackets(exp))))));
11578                */
11579             }
11580             else if(isLinkList && !isList)
11581             {
11582                Declarator decl;
11583                OldList * specs = MkList();
11584                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
11585                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11586                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11587                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalLinkList")),
11588                      MkInitializerAssignment(MkExpBrackets(exp))))));
11589             }
11590             /*else if(isCustomAVLTree)
11591             {
11592                Declarator decl;
11593                OldList * specs = MkList();
11594                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
11595                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11596                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11597                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalTree")),
11598                      MkInitializerAssignment(MkExpBrackets(exp))))));
11599             }*/
11600             else if(_class.templateArgs)
11601             {
11602                if(isMap)
11603                   sprintf(iteratorType, "MapIterator<%s, %s >", _class.templateArgs[5].dataTypeString, _class.templateArgs[6].dataTypeString);
11604                else
11605                   sprintf(iteratorType, "Iterator<%s, %s >", _class.templateArgs[2].dataTypeString, _class.templateArgs[1].dataTypeString);
11606
11607                stmt.compound.declarations = MkListOne(
11608                   MkDeclarationInst(MkInstantiationNamed(MkListOne(MkSpecifierName(iteratorType)),
11609                   MkExpIdentifier(id), MkListOne(MkMembersInitList(MkListOne(MkMemberInit(isMap ? MkListOne(MkIdentifier("map")) : null,
11610                   MkInitializerAssignment(MkExpBrackets(exp)))))))));
11611             }
11612             symbol = FindSymbol(id.string, curContext, curContext, false, false);
11613
11614             if(block)
11615             {
11616                // Reparent sub-contexts in this statement
11617                switch(block.type)
11618                {
11619                   case compoundStmt:
11620                      if(block.compound.context)
11621                         block.compound.context.parent = stmt.compound.context;
11622                      break;
11623                   case ifStmt:
11624                      if(block.ifStmt.stmt && block.ifStmt.stmt.type == compoundStmt && block.ifStmt.stmt.compound.context)
11625                         block.ifStmt.stmt.compound.context.parent = stmt.compound.context;
11626                      if(block.ifStmt.elseStmt && block.ifStmt.elseStmt.type == compoundStmt && block.ifStmt.elseStmt.compound.context)
11627                         block.ifStmt.elseStmt.compound.context.parent = stmt.compound.context;
11628                      break;
11629                   case switchStmt:
11630                      if(block.switchStmt.stmt && block.switchStmt.stmt.type == compoundStmt && block.switchStmt.stmt.compound.context)
11631                         block.switchStmt.stmt.compound.context.parent = stmt.compound.context;
11632                      break;
11633                   case whileStmt:
11634                      if(block.whileStmt.stmt && block.whileStmt.stmt.type == compoundStmt && block.whileStmt.stmt.compound.context)
11635                         block.whileStmt.stmt.compound.context.parent = stmt.compound.context;
11636                      break;
11637                   case doWhileStmt:
11638                      if(block.doWhile.stmt && block.doWhile.stmt.type == compoundStmt && block.doWhile.stmt.compound.context)
11639                         block.doWhile.stmt.compound.context.parent = stmt.compound.context;
11640                      break;
11641                   case forStmt:
11642                      if(block.forStmt.stmt && block.forStmt.stmt.type == compoundStmt && block.forStmt.stmt.compound.context)
11643                         block.forStmt.stmt.compound.context.parent = stmt.compound.context;
11644                      break;
11645                   case forEachStmt:
11646                      if(block.forEachStmt.stmt && block.forEachStmt.stmt.type == compoundStmt && block.forEachStmt.stmt.compound.context)
11647                         block.forEachStmt.stmt.compound.context.parent = stmt.compound.context;
11648                      break;
11649                   /* Only handle those with compound blocks for now... (Potential limitation on compound statements within expressions)
11650                   case labeledStmt:
11651                   case caseStmt
11652                   case expressionStmt:
11653                   case gotoStmt:
11654                   case continueStmt:
11655                   case breakStmt
11656                   case returnStmt:
11657                   case asmStmt:
11658                   case badDeclarationStmt:
11659                   case fireWatchersStmt:
11660                   case stopWatchingStmt:
11661                   case watchStmt:
11662                   */
11663                }
11664             }
11665             if(filter)
11666             {
11667                block = MkIfStmt(filter, block, null);
11668             }
11669             if(isArray)
11670             {
11671                stmt.compound.statements = MkListOne(MkForStmt(
11672                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array"))))),
11673                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
11674                      MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array")), '+', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
11675                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
11676                   block));
11677               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11678               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11679               ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11680             }
11681             else if(isBuiltin)
11682             {
11683                char count[128];
11684                //OldList * specs = MkList();
11685                // Declarator decl = SpecDeclFromString(typeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
11686
11687                sprintf(count, "%d", builtinCount);
11688
11689                stmt.compound.statements = MkListOne(MkForStmt(
11690                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpIdentifier(MkIdentifier("__internalArray"))))),
11691                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
11692                      MkExpOp(MkExpIdentifier(MkIdentifier("__internalArray")), '+', MkExpConstant(count))))),
11693                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
11694                   block));
11695
11696                /*
11697                Declarator decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
11698                stmt.compound.statements = MkListOne(MkForStmt(
11699                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))))),
11700                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
11701                      MkExpOp(MkExpCast(MkTypeName(specs, decl), MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))), '+', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
11702                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
11703                   block));
11704               */
11705               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11706               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11707               ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11708             }
11709             else if(isLinkList && !isList)
11710             {
11711                Class typeClass = eSystem_FindClass(_class.module, _class.templateArgs[3].dataTypeString);
11712                Class listItemClass = eSystem_FindClass(_class.module, "ListItem");
11713                if(typeClass && eClass_IsDerived(typeClass, listItemClass) && _class.templateArgs[5].dataTypeString &&
11714                   !strcmp(_class.templateArgs[5].dataTypeString, "LT::link"))
11715                {
11716                   stmt.compound.statements = MkListOne(MkForStmt(
11717                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
11718                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
11719                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
11720                      block));
11721                }
11722                else
11723                {
11724                   OldList * specs = MkList();
11725                   Declarator decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, null);
11726                   stmt.compound.statements = MkListOne(MkForStmt(
11727                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
11728                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
11729                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpCast(MkTypeName(specs, decl), MkExpCall(
11730                         MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("GetNext")),
11731                            MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName("IteratorPointer")), null), MkExpIdentifier(CopyIdentifier(id)))))))),
11732                      block));
11733                }
11734                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11735                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11736                ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11737             }
11738             /*else if(isCustomAVLTree)
11739             {
11740                stmt.compound.statements = MkListOne(MkForStmt(
11741                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpMember(MkExpIdentifier(
11742                      MkIdentifier("__internalTree")), MkIdentifier("root")), MkIdentifier("minimum"))))),
11743                   MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
11744                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
11745                   block));
11746
11747                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11748                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11749                ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11750             }*/
11751             else
11752             {
11753                stmt.compound.statements = MkListOne(MkWhileStmt(MkListOne(MkExpCall(MkExpMember(expIt = MkExpIdentifier(CopyIdentifier(id)),
11754                   MkIdentifier("Next")), null)), block));
11755             }
11756             ProcessExpressionType(expIt);
11757             if(stmt.compound.declarations->first)
11758                ProcessDeclaration(stmt.compound.declarations->first);
11759
11760             if(symbol)
11761                symbol.isIterator = isMap ? 2 : ((isArray || isBuiltin) ? 3 : (isLinkList ? (isList ? 5 : 4) : (isCustomAVLTree ? 6 : 1)));
11762
11763             ProcessStatement(stmt);
11764             curContext = stmt.compound.context.parent;
11765             break;
11766          }
11767          else
11768          {
11769             Compiler_Error($"Expression is not a container\n");
11770          }
11771          break;
11772       }
11773       case gotoStmt:
11774          break;
11775       case continueStmt:
11776          break;
11777       case breakStmt:
11778          break;
11779       case returnStmt:
11780       {
11781          Expression exp;
11782          if(stmt.expressions)
11783          {
11784             for(exp = stmt.expressions->first; exp; exp = exp.next)
11785             {
11786                if(!exp.next)
11787                {
11788                   if(curFunction && !curFunction.type)
11789                      curFunction.type = ProcessType(
11790                         curFunction.specifiers, curFunction.declarator);
11791                   FreeType(exp.destType);
11792                   exp.destType = (curFunction && curFunction.type && curFunction.type.kind == functionType) ? curFunction.type.returnType : null;
11793                   if(exp.destType) exp.destType.refCount++;
11794                }
11795                ProcessExpressionType(exp);
11796             }
11797          }
11798          break;
11799       }
11800       case badDeclarationStmt:
11801       {
11802          ProcessDeclaration(stmt.decl);
11803          break;
11804       }
11805       case asmStmt:
11806       {
11807          AsmField field;
11808          if(stmt.asmStmt.inputFields)
11809          {
11810             for(field = stmt.asmStmt.inputFields->first; field; field = field.next)
11811                if(field.expression)
11812                   ProcessExpressionType(field.expression);
11813          }
11814          if(stmt.asmStmt.outputFields)
11815          {
11816             for(field = stmt.asmStmt.outputFields->first; field; field = field.next)
11817                if(field.expression)
11818                   ProcessExpressionType(field.expression);
11819          }
11820          if(stmt.asmStmt.clobberedFields)
11821          {
11822             for(field = stmt.asmStmt.clobberedFields->first; field; field = field.next)
11823             {
11824                if(field.expression)
11825                   ProcessExpressionType(field.expression);
11826             }
11827          }
11828          break;
11829       }
11830       case watchStmt:
11831       {
11832          PropertyWatch propWatch;
11833          OldList * watches = stmt._watch.watches;
11834          Expression object = stmt._watch.object;
11835          Expression watcher = stmt._watch.watcher;
11836          if(watcher)
11837             ProcessExpressionType(watcher);
11838          if(object)
11839             ProcessExpressionType(object);
11840
11841          if(inCompiler)
11842          {
11843             if(watcher || thisClass)
11844             {
11845                External external = curExternal;
11846                Context context = curContext;
11847
11848                stmt.type = expressionStmt;
11849                stmt.expressions = MkList();
11850
11851                curExternal = external.prev;
11852
11853                for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
11854                {
11855                   ClassFunction func;
11856                   char watcherName[1024];
11857                   Class watcherClass = watcher ?
11858                      ((watcher.expType && watcher.expType.kind == classType && watcher.expType._class) ? watcher.expType._class.registered : null) : thisClass;
11859                   External createdExternal;
11860
11861                   // Create a declaration above
11862                   External externalDecl = MkExternalDeclaration(null);
11863                   ast->Insert(curExternal.prev, externalDecl);
11864
11865                   sprintf(watcherName,"__ecerePropertyWatcher_%d", propWatcherID++);
11866                   if(propWatch.deleteWatch)
11867                      strcat(watcherName, "_delete");
11868                   else
11869                   {
11870                      Identifier propID;
11871                      for(propID = propWatch.properties->first; propID; propID = propID.next)
11872                      {
11873                         strcat(watcherName, "_");
11874                         strcat(watcherName, propID.string);
11875                      }
11876                   }
11877
11878                   if(object && object.expType && object.expType.kind == classType && object.expType._class && object.expType._class.registered)
11879                   {
11880                      // TESTING THIS STUFF... BEWARE OF SYMBOL ID ISSUES
11881                      func = MkClassFunction(MkListOne(MkSpecifier(VOID)), null, MkDeclaratorFunction(MkDeclaratorIdentifier(MkIdentifier(watcherName)),
11882                         //MkListOne(MkTypeName(MkListOne(MkSpecifier(VOID)), null))), null);
11883                         MkListOne(MkTypeName(MkListOne(MkSpecifierName(object.expType._class.string)), MkDeclaratorIdentifier(MkIdentifier("value"))))), null);
11884                      ProcessClassFunctionBody(func, propWatch.compound);
11885                      propWatch.compound = null;
11886
11887                      //afterExternal = afterExternal ? afterExternal : curExternal;
11888
11889                      //createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal.prev);
11890                      createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal, true);
11891                      // TESTING THIS...
11892                      createdExternal.symbol.idCode = external.symbol.idCode;
11893
11894                      curExternal = createdExternal;
11895                      ProcessFunction(createdExternal.function);
11896
11897
11898                      // Create a declaration above
11899                      {
11900                         Declaration decl = MkDeclaration(CopyList(createdExternal.function.specifiers, CopySpecifier),
11901                            MkListOne(MkInitDeclarator(CopyDeclarator(createdExternal.function.declarator), null)));
11902                         externalDecl.declaration = decl;
11903                         if(decl.symbol && !decl.symbol.pointerExternal)
11904                            decl.symbol.pointerExternal = externalDecl;
11905                      }
11906
11907                      if(propWatch.deleteWatch)
11908                      {
11909                         OldList * args = MkList();
11910                         ListAdd(args, CopyExpression(object));
11911                         ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
11912                         ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
11913                         ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_WatchDestruction")), args));
11914                      }
11915                      else
11916                      {
11917                         Class _class = object.expType._class.registered;
11918                         Identifier propID;
11919
11920                         for(propID = propWatch.properties->first; propID; propID = propID.next)
11921                         {
11922                            char propName[1024];
11923                            Property prop = eClass_FindProperty(_class, propID.string, privateModule);
11924                            if(prop)
11925                            {
11926                               char getName[1024], setName[1024];
11927                               OldList * args = MkList();
11928
11929                               DeclareProperty(prop, setName, getName);
11930
11931                               // eInstance_Watch(stmt.watch.object, prop, stmt.watch.watcher, callback);
11932                               strcpy(propName, "__ecereProp_");
11933                               FullClassNameCat(propName, prop._class.fullName, false);
11934                               strcat(propName, "_");
11935                               // strcat(propName, prop.name);
11936                               FullClassNameCat(propName, prop.name, true);
11937
11938                               ListAdd(args, CopyExpression(object));
11939                               ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11940                               ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
11941                               ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
11942
11943                               ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_Watch")), args));
11944                            }
11945                            else
11946                               Compiler_Error($"Property %s not found in class %s\n", prop.name, _class.fullName);
11947                         }
11948                      }
11949                   }
11950                   else
11951                      Compiler_Error($"Invalid watched object\n");
11952                }
11953
11954                curExternal = external;
11955                curContext = context;
11956
11957                if(watcher)
11958                   FreeExpression(watcher);
11959                if(object)
11960                   FreeExpression(object);
11961                FreeList(watches, FreePropertyWatch);
11962             }
11963             else
11964                Compiler_Error($"No observer specified and not inside a _class\n");
11965          }
11966          else
11967          {
11968             for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
11969             {
11970                ProcessStatement(propWatch.compound);
11971             }
11972
11973          }
11974          break;
11975       }
11976       case fireWatchersStmt:
11977       {
11978          OldList * watches = stmt._watch.watches;
11979          Expression object = stmt._watch.object;
11980          Class _class;
11981          // DEBUGGER BUG: Why doesn't watches evaluate to null??
11982          // printf("%X\n", watches);
11983          // printf("%X\n", stmt._watch.watches);
11984          if(object)
11985             ProcessExpressionType(object);
11986
11987          if(inCompiler)
11988          {
11989             _class = object ?
11990                   ((object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null) : thisClass;
11991
11992             if(_class)
11993             {
11994                Identifier propID;
11995
11996                stmt.type = expressionStmt;
11997                stmt.expressions = MkList();
11998
11999                // Check if we're inside a property set
12000                if(!watches && curFunction.propSet && (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
12001                {
12002                   watches = MkListOne(MkIdentifier(curFunction.propSet.string));
12003                }
12004                else if(!watches)
12005                {
12006                   //Compiler_Error($"No property specified and not inside a property set\n");
12007                }
12008                if(watches)
12009                {
12010                   for(propID = watches->first; propID; propID = propID.next)
12011                   {
12012                      Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12013                      if(prop)
12014                      {
12015                         CreateFireWatcher(prop, object, stmt);
12016                      }
12017                      else
12018                         Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12019                   }
12020                }
12021                else
12022                {
12023                   // Fire all properties!
12024                   Property prop;
12025                   Class base;
12026                   for(base = _class; base; base = base.base)
12027                   {
12028                      for(prop = base.membersAndProperties.first; prop; prop = prop.next)
12029                      {
12030                         if(prop.isProperty && prop.isWatchable)
12031                         {
12032                            CreateFireWatcher(prop, object, stmt);
12033                         }
12034                      }
12035                   }
12036                }
12037
12038                if(object)
12039                   FreeExpression(object);
12040                FreeList(watches, FreeIdentifier);
12041             }
12042             else
12043                Compiler_Error($"Invalid object specified and not inside a class\n");
12044          }
12045          break;
12046       }
12047       case stopWatchingStmt:
12048       {
12049          OldList * watches = stmt._watch.watches;
12050          Expression object = stmt._watch.object;
12051          Expression watcher = stmt._watch.watcher;
12052          Class _class;
12053          if(object)
12054             ProcessExpressionType(object);
12055          if(watcher)
12056             ProcessExpressionType(watcher);
12057          if(inCompiler)
12058          {
12059             _class = (object && object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null;
12060
12061             if(watcher || thisClass)
12062             {
12063                if(_class)
12064                {
12065                   Identifier propID;
12066
12067                   stmt.type = expressionStmt;
12068                   stmt.expressions = MkList();
12069
12070                   if(!watches)
12071                   {
12072                      OldList * args;
12073                      // eInstance_StopWatching(object, null, watcher);
12074                      args = MkList();
12075                      ListAdd(args, CopyExpression(object));
12076                      ListAdd(args, MkExpConstant("0"));
12077                      ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12078                      ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12079                   }
12080                   else
12081                   {
12082                      for(propID = watches->first; propID; propID = propID.next)
12083                      {
12084                         char propName[1024];
12085                         Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12086                         if(prop)
12087                         {
12088                            char getName[1024], setName[1024];
12089                            OldList * args = MkList();
12090
12091                            DeclareProperty(prop, setName, getName);
12092
12093                            // eInstance_StopWatching(object, prop, watcher);
12094                            strcpy(propName, "__ecereProp_");
12095                            FullClassNameCat(propName, prop._class.fullName, false);
12096                            strcat(propName, "_");
12097                            // strcat(propName, prop.name);
12098                            FullClassNameCat(propName, prop.name, true);
12099                            MangleClassName(propName);
12100
12101                            ListAdd(args, CopyExpression(object));
12102                            ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12103                            ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12104                            ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12105                         }
12106                         else
12107                            Compiler_Error($"Property %s not found in class %s\n", prop.name, _class.fullName);
12108                      }
12109                   }
12110
12111                   if(object)
12112                      FreeExpression(object);
12113                   if(watcher)
12114                      FreeExpression(watcher);
12115                   FreeList(watches, FreeIdentifier);
12116                }
12117                else
12118                   Compiler_Error($"Invalid object specified and not inside a class\n");
12119             }
12120             else
12121                Compiler_Error($"No observer specified and not inside a class\n");
12122          }
12123          break;
12124       }
12125    }
12126 }
12127
12128 static void ProcessFunction(FunctionDefinition function)
12129 {
12130    Identifier id = GetDeclId(function.declarator);
12131    Symbol symbol = function.declarator ? function.declarator.symbol : null;
12132    Type type = symbol ? symbol.type : null;
12133    Class oldThisClass = thisClass;
12134    Context oldTopContext = topContext;
12135
12136    yylloc = function.loc;
12137    // Process thisClass
12138
12139    if(type && type.thisClass)
12140    {
12141       Symbol classSym = type.thisClass;
12142       Class _class = type.thisClass.registered;
12143       char className[1024];
12144       char structName[1024];
12145       Declarator funcDecl;
12146       Symbol thisSymbol;
12147
12148       bool typedObject = false;
12149
12150       if(_class && !_class.base)
12151       {
12152          _class = currentClass;
12153          if(_class && !_class.symbol)
12154             _class.symbol = FindClass(_class.fullName);
12155          classSym = _class ? _class.symbol : null;
12156          typedObject = true;
12157       }
12158
12159       thisClass = _class;
12160
12161       if(inCompiler && _class)
12162       {
12163          if(type.kind == functionType)
12164          {
12165             if(symbol.type.params.count == 1 && ((Type)symbol.type.params.first).kind == voidType)
12166             {
12167                //TypeName param = symbol.type.params.first;
12168                Type param = symbol.type.params.first;
12169                symbol.type.params.Remove(param);
12170                //FreeTypeName(param);
12171                FreeType(param);
12172             }
12173             if(type.classObjectType != classPointer)
12174             {
12175                symbol.type.params.Insert(null, MkClassType(_class.fullName));
12176                symbol.type.staticMethod = true;
12177                symbol.type.thisClass = null;
12178
12179                // HIGH DANGER: VERIFYING THIS...
12180                symbol.type.extraParam = false;
12181             }
12182          }
12183
12184          strcpy(className, "__ecereClass_");
12185          FullClassNameCat(className, _class.fullName, true);
12186
12187          MangleClassName(className);
12188
12189          structName[0] = 0;
12190          FullClassNameCat(structName, _class.fullName, false);
12191
12192          // [class] this
12193
12194
12195          funcDecl = GetFuncDecl(function.declarator);
12196          if(funcDecl)
12197          {
12198             if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12199             {
12200                TypeName param = funcDecl.function.parameters->first;
12201                if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12202                {
12203                   funcDecl.function.parameters->Remove(param);
12204                   FreeTypeName(param);
12205                }
12206             }
12207
12208             // DANGER: Watch for this... Check if it's a Conversion?
12209             // if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
12210
12211             // WAS TRYING THIS FOR CONVERSION PROPERTIES ON NOHEAD CLASSES: if((_class.type == structClass) || function != (FunctionDefinition)symbol.externalSet)
12212             if(!function.propertyNoThis)
12213             {
12214                TypeName thisParam;
12215
12216                if(type.classObjectType != classPointer)
12217                {
12218                   thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12219                   if(!funcDecl.function.parameters)
12220                      funcDecl.function.parameters = MkList();
12221                   funcDecl.function.parameters->Insert(null, thisParam);
12222                }
12223
12224                if(typedObject)
12225                {
12226                   if(type.classObjectType != classPointer)
12227                   {
12228                      if(type.byReference || _class.type == unitClass || _class.type == systemClass || _class.type == enumClass || _class.type == bitClass)
12229                         thisParam.declarator = MkDeclaratorPointer(MkPointer(null,null), thisParam.declarator);
12230                   }
12231
12232                   thisParam = TypeName
12233                   {
12234                      declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
12235                      qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
12236                   };
12237                   funcDecl.function.parameters->Insert(null, thisParam);
12238                }
12239             }
12240          }
12241
12242          if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
12243          {
12244             InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
12245             funcDecl = GetFuncDecl(initDecl.declarator);
12246             if(funcDecl)
12247             {
12248                if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12249                {
12250                   TypeName param = funcDecl.function.parameters->first;
12251                   if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12252                   {
12253                      funcDecl.function.parameters->Remove(param);
12254                      FreeTypeName(param);
12255                   }
12256                }
12257
12258                if(type.classObjectType != classPointer)
12259                {
12260                   // DANGER: Watch for this... Check if it's a Conversion?
12261                   if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
12262                   {
12263                      TypeName thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12264
12265                      if(!funcDecl.function.parameters)
12266                         funcDecl.function.parameters = MkList();
12267                      funcDecl.function.parameters->Insert(null, thisParam);
12268                   }
12269                }
12270             }
12271          }
12272       }
12273
12274       // Add this to the context
12275       if(function.body)
12276       {
12277          if(type.classObjectType != classPointer)
12278          {
12279             thisSymbol = Symbol
12280             {
12281                string = CopyString("this");
12282                type = classSym ? MkClassType(classSym.string) : null; //_class.fullName);
12283             };
12284             function.body.compound.context.symbols.Add((BTNode)thisSymbol);
12285
12286             if(typedObject && thisSymbol.type)
12287             {
12288                thisSymbol.type.classObjectType = ClassObjectType::typedObject;
12289                thisSymbol.type.byReference = type.byReference;
12290                thisSymbol.type.typedByReference = type.byReference;
12291                /*
12292                thisSymbol = Symbol { string = CopyString("class") };
12293                function.body.compound.context.symbols.Add(thisSymbol);
12294                */
12295             }
12296          }
12297       }
12298
12299       // Pointer to class data
12300
12301       if(inCompiler && _class && (_class.type == normalClass /*|| _class.type == noHeadClass*/) && type.classObjectType != classPointer)
12302       {
12303          DataMember member = null;
12304          {
12305             Class base;
12306             for(base = _class; base && base.type != systemClass; base = base.next)
12307             {
12308                for(member = base.membersAndProperties.first; member; member = member.next)
12309                   if(!member.isProperty)
12310                      break;
12311                if(member)
12312                   break;
12313             }
12314          }
12315          for(member = _class.membersAndProperties.first; member; member = member.next)
12316             if(!member.isProperty)
12317                break;
12318          if(member)
12319          {
12320             char pointerName[1024];
12321
12322             Declaration decl;
12323             Initializer initializer;
12324             Expression exp, bytePtr;
12325
12326             strcpy(pointerName, "__ecerePointer_");
12327             FullClassNameCat(pointerName, _class.fullName, false);
12328             {
12329                char className[1024];
12330                strcpy(className, "__ecereClass_");
12331                FullClassNameCat(className, classSym.string, true);
12332                MangleClassName(className);
12333
12334                // Testing This
12335                DeclareClass(classSym, className);
12336             }
12337
12338             // ((byte *) this)
12339             bytePtr = QBrackets(MkExpCast(QMkType("char", QMkPtrDecl(null)), QMkExpId("this")));
12340
12341             if(_class.fixed)
12342             {
12343                char string[256];
12344                sprintf(string, "%d", _class.offset);
12345                exp = QBrackets(MkExpOp(bytePtr, '+', MkExpConstant(string)));
12346             }
12347             else
12348             {
12349                // ([bytePtr] + [className]->offset)
12350                exp = QBrackets(MkExpOp(bytePtr, '+',
12351                   MkExpPointer(QMkExpId(className), MkIdentifier("offset"))));
12352             }
12353
12354             // (this ? [exp] : 0)
12355             exp = QBrackets(QMkExpCond(QMkExpId("this"), exp, MkExpConstant("0")));
12356             exp.expType = Type
12357             {
12358                refCount = 1;
12359                kind = pointerType;
12360                type = Type { refCount = 1, kind = voidType };
12361             };
12362
12363             if(function.body)
12364             {
12365                yylloc = function.body.loc;
12366                // ([structName] *) [exp]
12367                // initializer = MkInitializerAssignment(MkExpCast(QMkType(structName, QMkPtrDecl(null)), exp));
12368                initializer = MkInitializerAssignment(
12369                   MkExpCast(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)), exp));
12370
12371                // [structName] * [pointerName] = [initializer];
12372                // decl = QMkDeclaration(structName, MkInitDeclarator(QMkPtrDecl(pointerName), initializer));
12373
12374                {
12375                   Context prevContext = curContext;
12376                   curContext = function.body.compound.context;
12377
12378                   decl = MkDeclaration(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)),
12379                      MkListOne(MkInitDeclarator(QMkPtrDecl(pointerName), initializer)));
12380
12381                   curContext = prevContext;
12382                }
12383
12384                // WHY?
12385                decl.symbol = null;
12386
12387                if(!function.body.compound.declarations)
12388                   function.body.compound.declarations = MkList();
12389                function.body.compound.declarations->Insert(null, decl);
12390             }
12391          }
12392       }
12393
12394
12395       // Loop through the function and replace undeclared identifiers
12396       // which are a member of the class (methods, properties or data)
12397       // by "this.[member]"
12398    }
12399    else
12400       thisClass = null;
12401
12402    if(id)
12403    {
12404       FreeSpecifier(id._class);
12405       id._class = null;
12406
12407       if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
12408       {
12409          InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
12410          id = GetDeclId(initDecl.declarator);
12411
12412          FreeSpecifier(id._class);
12413          id._class = null;
12414       }
12415    }
12416    if(function.body)
12417       topContext = function.body.compound.context;
12418    {
12419       FunctionDefinition oldFunction = curFunction;
12420       curFunction = function;
12421       if(function.body)
12422          ProcessStatement(function.body);
12423
12424       // If this is a property set and no firewatchers has been done yet, add one here
12425       if(inCompiler && function.propSet && !function.propSet.fireWatchersDone)
12426       {
12427          Statement prevCompound = curCompound;
12428          Context prevContext = curContext;
12429
12430          Statement fireWatchers = MkFireWatchersStmt(null, null);
12431          if(!function.body.compound.statements) function.body.compound.statements = MkList();
12432          ListAdd(function.body.compound.statements, fireWatchers);
12433
12434          curCompound = function.body;
12435          curContext = function.body.compound.context;
12436
12437          ProcessStatement(fireWatchers);
12438
12439          curContext = prevContext;
12440          curCompound = prevCompound;
12441
12442       }
12443
12444       curFunction = oldFunction;
12445    }
12446
12447    if(function.declarator)
12448    {
12449       ProcessDeclarator(function.declarator);
12450    }
12451
12452    topContext = oldTopContext;
12453    thisClass = oldThisClass;
12454 }
12455
12456 /////////// INSTANTIATIONS / DATA TYPES PASS /////////////////////////////////////////////
12457 static void ProcessClass(OldList definitions, Symbol symbol)
12458 {
12459    ClassDef def;
12460    External external = curExternal;
12461    Class regClass = symbol ? symbol.registered : null;
12462
12463    // Process all functions
12464    for(def = definitions.first; def; def = def.next)
12465    {
12466       if(def.type == functionClassDef)
12467       {
12468          if(def.function.declarator)
12469             curExternal = def.function.declarator.symbol.pointerExternal;
12470          else
12471             curExternal = external;
12472
12473          ProcessFunction((FunctionDefinition)def.function);
12474       }
12475       else if(def.type == declarationClassDef)
12476       {
12477          if(def.decl.type == instDeclaration)
12478          {
12479             thisClass = regClass;
12480             ProcessInstantiationType(def.decl.inst);
12481             thisClass = null;
12482          }
12483          // Testing this
12484          else
12485          {
12486             Class backThisClass = thisClass;
12487             if(regClass) thisClass = regClass;
12488             ProcessDeclaration(def.decl);
12489             thisClass = backThisClass;
12490          }
12491       }
12492       else if(def.type == defaultPropertiesClassDef && def.defProperties)
12493       {
12494          MemberInit defProperty;
12495
12496          // Add this to the context
12497          Symbol thisSymbol = Symbol
12498          {
12499             string = CopyString("this");
12500             type = regClass ? MkClassType(regClass.fullName) : null;
12501          };
12502          globalContext.symbols.Add((BTNode)thisSymbol);
12503
12504          for(defProperty = def.defProperties->first; defProperty; defProperty = defProperty.next)
12505          {
12506             thisClass = regClass;
12507             ProcessMemberInitData(defProperty, regClass, null, null, null, null);
12508             thisClass = null;
12509          }
12510
12511          globalContext.symbols.Remove((BTNode)thisSymbol);
12512          FreeSymbol(thisSymbol);
12513       }
12514       else if(def.type == propertyClassDef && def.propertyDef)
12515       {
12516          PropertyDef prop = def.propertyDef;
12517
12518          // Add this to the context
12519          /*
12520          Symbol thisSymbol = Symbol { string = CopyString("this"), type = MkClassType(regClass.fullName) };
12521          globalContext.symbols.Add(thisSymbol);
12522          */
12523
12524          thisClass = regClass;
12525          if(prop.setStmt)
12526          {
12527             if(regClass)
12528             {
12529                Symbol thisSymbol
12530                {
12531                   string = CopyString("this");
12532                   type = MkClassType(regClass.fullName);
12533                };
12534                prop.setStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12535             }
12536
12537             curExternal = prop.symbol ? prop.symbol.externalSet : null;
12538             ProcessStatement(prop.setStmt);
12539          }
12540          if(prop.getStmt)
12541          {
12542             if(regClass)
12543             {
12544                Symbol thisSymbol
12545                {
12546                   string = CopyString("this");
12547                   type = MkClassType(regClass.fullName);
12548                };
12549                prop.getStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12550             }
12551
12552             curExternal = prop.symbol ? prop.symbol.externalGet : null;
12553             ProcessStatement(prop.getStmt);
12554          }
12555          if(prop.issetStmt)
12556          {
12557             if(regClass)
12558             {
12559                Symbol thisSymbol
12560                {
12561                   string = CopyString("this");
12562                   type = MkClassType(regClass.fullName);
12563                };
12564                prop.issetStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12565             }
12566
12567             curExternal = prop.symbol ? prop.symbol.externalIsSet : null;
12568             ProcessStatement(prop.issetStmt);
12569          }
12570
12571          thisClass = null;
12572
12573          /*
12574          globalContext.symbols.Remove(thisSymbol);
12575          FreeSymbol(thisSymbol);
12576          */
12577       }
12578       else if(def.type == propertyWatchClassDef && def.propertyWatch)
12579       {
12580          PropertyWatch propertyWatch = def.propertyWatch;
12581
12582          thisClass = regClass;
12583          if(propertyWatch.compound)
12584          {
12585             Symbol thisSymbol
12586             {
12587                string = CopyString("this");
12588                type = regClass ? MkClassType(regClass.fullName) : null;
12589             };
12590
12591             propertyWatch.compound.compound.context.symbols.Add((BTNode)thisSymbol);
12592
12593             curExternal = null;
12594             ProcessStatement(propertyWatch.compound);
12595          }
12596          thisClass = null;
12597       }
12598    }
12599 }
12600
12601 void DeclareFunctionUtil(String s)
12602 {
12603    GlobalFunction function = eSystem_FindFunction(privateModule, s);
12604    if(function)
12605    {
12606       char name[1024];
12607       name[0] = 0;
12608       if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
12609          strcpy(name, "__ecereFunction_");
12610       FullClassNameCat(name, s, false); // Why is this using FullClassNameCat ?
12611       DeclareFunction(function, name);
12612    }
12613 }
12614
12615 void ComputeDataTypes()
12616 {
12617    External external;
12618    External temp { };
12619    External after = null;
12620
12621    currentClass = null;
12622
12623    containerClass = eSystem_FindClass(GetPrivateModule(), "Container");
12624
12625    for(external = ast->first; external; external = external.next)
12626    {
12627       if(external.type == declarationExternal)
12628       {
12629          Declaration decl = external.declaration;
12630          if(decl)
12631          {
12632             OldList * decls = decl.declarators;
12633             if(decls)
12634             {
12635                InitDeclarator initDecl = decls->first;
12636                if(initDecl)
12637                {
12638                   Declarator declarator = initDecl.declarator;
12639                   if(declarator && declarator.type == identifierDeclarator)
12640                   {
12641                      Identifier id = declarator.identifier;
12642                      if(id && id.string)
12643                      {
12644                         if(!strcmp(id.string, "uintptr_t") || !strcmp(id.string, "intptr_t") || !strcmp(id.string, "size_t") || !strcmp(id.string, "ssize_t"))
12645                         {
12646                            external.symbol.id = -1001, external.symbol.idCode = -1001;
12647                            after = external;
12648                         }
12649                      }
12650                   }
12651                }
12652             }
12653          }
12654        }
12655    }
12656
12657    temp.symbol = Symbol { id = -1000, idCode = -1000 };
12658    ast->Insert(after, temp);
12659    curExternal = temp;
12660
12661    DeclareFunctionUtil("eSystem_New");
12662    DeclareFunctionUtil("eSystem_New0");
12663    DeclareFunctionUtil("eSystem_Renew");
12664    DeclareFunctionUtil("eSystem_Renew0");
12665    DeclareFunctionUtil("eSystem_Delete");
12666    DeclareFunctionUtil("eClass_GetProperty");
12667    DeclareFunctionUtil("eInstance_FireSelfWatchers");
12668
12669    DeclareStruct("ecere::com::Class", false);
12670    DeclareStruct("ecere::com::Instance", false);
12671    DeclareStruct("ecere::com::Property", false);
12672    DeclareStruct("ecere::com::DataMember", false);
12673    DeclareStruct("ecere::com::Method", false);
12674    DeclareStruct("ecere::com::SerialBuffer", false);
12675    DeclareStruct("ecere::com::ClassTemplateArgument", false);
12676
12677    ast->Remove(temp);
12678
12679    for(external = ast->first; external; external = external.next)
12680    {
12681       afterExternal = curExternal = external;
12682       if(external.type == functionExternal)
12683       {
12684          currentClass = external.function._class;
12685          ProcessFunction(external.function);
12686       }
12687       // There shouldn't be any _class member access here anyways...
12688       else if(external.type == declarationExternal)
12689       {
12690          currentClass = null;
12691          ProcessDeclaration(external.declaration);
12692       }
12693       else if(external.type == classExternal)
12694       {
12695          ClassDefinition _class = external._class;
12696          currentClass = external.symbol.registered;
12697          if(_class.definitions)
12698          {
12699             ProcessClass(_class.definitions, _class.symbol);
12700          }
12701          if(inCompiler)
12702          {
12703             // Free class data...
12704             ast->Remove(external);
12705             delete external;
12706          }
12707       }
12708       else if(external.type == nameSpaceExternal)
12709       {
12710          thisNameSpace = external.id.string;
12711       }
12712    }
12713    currentClass = null;
12714    thisNameSpace = null;
12715
12716    delete temp.symbol;
12717    delete temp;
12718 }