compiler/libec: Improved handling 64 bit constants
[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 > MAXINT)
205       sprintf(temp, FORMAT64HEX /*"0x%I64XLL"*/, result);
206    else
207       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
208    if(result > MAXINT || result < MININT)
209       strcat(temp, "LL");
210    return CopyString(temp);
211 }
212
213 public char * PrintUInt(uint64 result)
214 {
215    char temp[100];
216    if(result > MAXDWORD)
217       sprintf(temp, FORMAT64HEXLL /*"0x%I64XLL"*/, result);
218    else if(result > MAXINT)
219       sprintf(temp, FORMAT64HEX /*"0x%I64X"*/, result);
220    else
221       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
222    return CopyString(temp);
223 }
224
225 public char * PrintInt64(int64 result)
226 {
227    char temp[100];
228    sprintf(temp, FORMAT64DLL /*"%I64d"*/, result);
229    return CopyString(temp);
230 }
231
232 public char * PrintUInt64(uint64 result)
233 {
234    char temp[100];
235    if(result > MAXINT64)
236       sprintf(temp, FORMAT64HEXLL /*"0x%I64XLL"*/, result);
237    else
238       sprintf(temp, FORMAT64DLL /*"%I64d"*/, result);
239    return CopyString(temp);
240 }
241
242 public char * PrintHexUInt(uint64 result)
243 {
244    char temp[100];
245    if(result > MAXDWORD)
246       sprintf(temp, FORMAT64HEXLL /*"0x%I64xLL"*/, result);
247    else
248       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
249    return CopyString(temp);
250 }
251
252 public char * PrintHexUInt64(uint64 result)
253 {
254    char temp[100];
255    if(result > MAXDWORD)
256       sprintf(temp, FORMAT64HEXLL /*"0x%I64xLL"*/, result);
257    else
258       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
259    return CopyString(temp);
260 }
261
262 public char * PrintShort(short result)
263 {
264    char temp[100];
265    sprintf(temp, "%d", (unsigned short)result);
266    return CopyString(temp);
267 }
268
269 public char * PrintUShort(unsigned short result)
270 {
271    char temp[100];
272    if(result > 32767)
273       sprintf(temp, "0x%X", (int)result);
274    else
275       sprintf(temp, "%d", (int)result);
276    return CopyString(temp);
277 }
278
279 public char * PrintChar(char result)
280 {
281    char temp[100];
282    if(result > 0 && isprint(result))
283       sprintf(temp, "'%c'", result);
284    else if(result < 0)
285       sprintf(temp, "%d", (int)result);
286    else
287       //sprintf(temp, "%#X", result);
288       sprintf(temp, "0x%X", (unsigned char)result);
289    return CopyString(temp);
290 }
291
292 public char * PrintUChar(unsigned char result)
293 {
294    char temp[100];
295    sprintf(temp, "0x%X", result);
296    return CopyString(temp);
297 }
298
299 public char * PrintFloat(float result)
300 {
301    char temp[350];
302    if(result.isInf)
303    {
304       if(result.signBit)
305          strcpy(temp, "-inf");
306       else
307          strcpy(temp, "inf");
308    }
309    else if(result.isNan)
310    {
311       if(result.signBit)
312          strcpy(temp, "-nan");
313       else
314          strcpy(temp, "nan");
315    }
316    else
317       sprintf(temp, "%.16ff", result);
318    return CopyString(temp);
319 }
320
321 public char * PrintDouble(double result)
322 {
323    char temp[350];
324    if(result.isInf)
325    {
326       if(result.signBit)
327          strcpy(temp, "-inf");
328       else
329          strcpy(temp, "inf");
330    }
331    else if(result.isNan)
332    {
333       if(result.signBit)
334          strcpy(temp, "-nan");
335       else
336          strcpy(temp, "nan");
337    }
338    else
339       sprintf(temp, "%.16f", result);
340    return CopyString(temp);
341 }
342
343 ////////////////////////////////////////////////////////////////////////
344 ////////////////////////////////////////////////////////////////////////
345
346 //public Operand GetOperand(Expression exp);
347
348 #define GETVALUE(name, t) \
349    public bool GetOp##name(Operand op2, t * value2) \
350    {                                                        \
351       if(op2.kind == intType && op2.type.isSigned) *value2 = (t) op2.i; \
352       else if(op2.kind == intType) *value2 = (t) op2.ui;                 \
353       else if(op2.kind == int64Type && op2.type.isSigned) *value2 = (t) op2.i64; \
354       else if(op2.kind == int64Type) *value2 = (t) op2.ui64;                 \
355       else if(op2.kind == intSizeType && op2.type.isSigned) *value2 = (t) op2.i64; \
356       else if(op2.kind == intSizeType) *value2 = (t) op2.ui64; \
357       else if(op2.kind == intPtrType && op2.type.isSigned) *value2 = (t) op2.i64; \
358       else if(op2.kind == intPtrType) *value2 = (t) op2.ui64;                 \
359       else if(op2.kind == shortType && op2.type.isSigned) *value2 = (t) op2.s;   \
360       else if(op2.kind == shortType) *value2 = (t) op2.us;                        \
361       else if(op2.kind == charType && op2.type.isSigned) *value2 = (t) op2.c;    \
362       else if(op2.kind == _BoolType || op2.kind == charType) *value2 = (t) op2.uc; \
363       else if(op2.kind == floatType) *value2 = (t) op2.f;                         \
364       else if(op2.kind == doubleType) *value2 = (t) op2.d;                        \
365       else if(op2.kind == pointerType) *value2 = (t) op2.ui64;                    \
366       else                                                                          \
367          return false;                                                              \
368       return true;                                                                  \
369    } \
370    public bool Get##name(Expression exp, t * value2) \
371    {                                                        \
372       Operand op2 = GetOperand(exp);                        \
373       return GetOp##name(op2, value2); \
374    }
375
376 // To help the deubugger currently not preprocessing...
377 #define HELP(x) x
378
379 GETVALUE(Int, HELP(int));
380 GETVALUE(UInt, HELP(unsigned int));
381 GETVALUE(Int64, HELP(int64));
382 GETVALUE(UInt64, HELP(uint64));
383 GETVALUE(IntPtr, HELP(intptr));
384 GETVALUE(UIntPtr, HELP(uintptr));
385 GETVALUE(IntSize, HELP(intsize));
386 GETVALUE(UIntSize, HELP(uintsize));
387 GETVALUE(Short, HELP(short));
388 GETVALUE(UShort, HELP(unsigned short));
389 GETVALUE(Char, HELP(char));
390 GETVALUE(UChar, HELP(unsigned char));
391 GETVALUE(Float, HELP(float));
392 GETVALUE(Double, HELP(double));
393
394 void ComputeExpression(Expression exp);
395
396 void ComputeClassMembers(Class _class, bool isMember)
397 {
398    DataMember member = isMember ? (DataMember) _class : null;
399    Context context = isMember ? null : SetupTemplatesContext(_class);
400    if(member || ((_class.type == bitClass || _class.type == normalClass || _class.type == structClass || _class.type == noHeadClass) &&
401                  (_class.type == bitClass || (!_class.structSize || _class.structSize == _class.offset)) && _class.computeSize))
402    {
403       int c;
404       int unionMemberOffset = 0;
405       int bitFields = 0;
406
407       /*
408       if(!member && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass) && _class.memberOffset && _class.memberOffset > _class.base.structSize)
409          _class.memberOffset = (_class.base && _class.base.type != systemClass) ? _class.base.structSize : 0;
410       */
411
412       if(member)
413       {
414          member.memberOffset = 0;
415          if(targetBits < sizeof(void *) * 8)
416             member.structAlignment = 0;
417       }
418       else if(targetBits < sizeof(void *) * 8)
419          _class.structAlignment = 0;
420
421       // Confusion here: non struct classes seem to have their memberOffset restart at 0 at each hierarchy level
422       if(!member && ((_class.type == normalClass || _class.type == noHeadClass) || (_class.type == structClass && _class.memberOffset && _class.memberOffset > _class.base.structSize)))
423          _class.memberOffset = (_class.base && _class.type == structClass) ? _class.base.structSize : 0;
424
425       if(!member && _class.destructionWatchOffset)
426          _class.memberOffset += sizeof(OldList);
427
428       // To avoid reentrancy...
429       //_class.structSize = -1;
430
431       {
432          DataMember dataMember;
433          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
434          {
435             if(!dataMember.isProperty)
436             {
437                if(dataMember.type == normalMember && dataMember.dataTypeString && !dataMember.dataType)
438                {
439                   dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
440                   /*if(!dataMember.dataType)
441                      dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
442                      */
443                }
444             }
445          }
446       }
447
448       {
449          DataMember dataMember;
450          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
451          {
452             if(!dataMember.isProperty && (dataMember.type != normalMember || dataMember.dataTypeString))
453             {
454                if(!isMember && _class.type == bitClass && dataMember.dataType)
455                {
456                   BitMember bitMember = (BitMember) dataMember;
457                   uint64 mask = 0;
458                   int d;
459
460                   ComputeTypeSize(dataMember.dataType);
461
462                   if(bitMember.pos == -1) bitMember.pos = _class.memberOffset;
463                   if(!bitMember.size) bitMember.size = dataMember.dataType.size * 8;
464
465                   _class.memberOffset = bitMember.pos + bitMember.size;
466                   for(d = 0; d<bitMember.size; d++)
467                   {
468                      if(d)
469                         mask <<= 1;
470                      mask |= 1;
471                   }
472                   bitMember.mask = mask << bitMember.pos;
473                }
474                else if(dataMember.type == normalMember && dataMember.dataType)
475                {
476                   int size;
477                   int alignment = 0;
478
479                   // Prevent infinite recursion
480                   if(dataMember.dataType.kind != classType ||
481                      ((!dataMember.dataType._class || !dataMember.dataType._class.registered || dataMember.dataType._class.registered != _class ||
482                      _class.type != structClass)))
483                      ComputeTypeSize(dataMember.dataType);
484
485                   if(dataMember.dataType.bitFieldCount)
486                   {
487                      bitFields += dataMember.dataType.bitFieldCount;
488                      size = 0;
489                   }
490                   else
491                   {
492                      if(bitFields)
493                      {
494                         int size = (bitFields + 7) / 8;
495
496                         if(isMember)
497                         {
498                            // TESTING THIS PADDING CODE
499                            if(alignment)
500                            {
501                               member.structAlignment = Max(member.structAlignment, alignment);
502
503                               if(member.memberOffset % alignment)
504                                  member.memberOffset += alignment - (member.memberOffset % alignment);
505                            }
506
507                            dataMember.offset = member.memberOffset;
508                            if(member.type == unionMember)
509                               unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
510                            else
511                            {
512                               member.memberOffset += size;
513                            }
514                         }
515                         else
516                         {
517                            // TESTING THIS PADDING CODE
518                            if(alignment)
519                            {
520                               _class.structAlignment = Max(_class.structAlignment, alignment);
521
522                               if(_class.memberOffset % alignment)
523                                  _class.memberOffset += alignment - (_class.memberOffset % alignment);
524                            }
525
526                            dataMember.offset = _class.memberOffset;
527                            _class.memberOffset += size;
528                         }
529                         bitFields = 0;
530                      }
531                      size = dataMember.dataType.size;
532                      alignment = dataMember.dataType.alignment;
533                   }
534
535                   if(isMember)
536                   {
537                      // TESTING THIS PADDING CODE
538                      if(alignment)
539                      {
540                         member.structAlignment = Max(member.structAlignment, alignment);
541
542                         if(member.memberOffset % alignment)
543                            member.memberOffset += alignment - (member.memberOffset % alignment);
544                      }
545
546                      dataMember.offset = member.memberOffset;
547                      if(member.type == unionMember)
548                         unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
549                      else
550                      {
551                         member.memberOffset += size;
552                      }
553                   }
554                   else
555                   {
556                      // TESTING THIS PADDING CODE
557                      if(alignment)
558                      {
559                         _class.structAlignment = Max(_class.structAlignment, alignment);
560
561                         if(_class.memberOffset % alignment)
562                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
563                      }
564
565                      dataMember.offset = _class.memberOffset;
566                      _class.memberOffset += size;
567                   }
568                }
569                else
570                {
571                   int alignment;
572
573                   ComputeClassMembers((Class)dataMember, true);
574                   alignment = dataMember.structAlignment;
575
576                   if(isMember)
577                   {
578                      if(alignment)
579                      {
580                         if(member.memberOffset % alignment)
581                            member.memberOffset += alignment - (member.memberOffset % alignment);
582
583                         member.structAlignment = Max(member.structAlignment, alignment);
584                      }
585                      dataMember.offset = member.memberOffset;
586                      if(member.type == unionMember)
587                         unionMemberOffset = Max(unionMemberOffset, dataMember.memberOffset);
588                      else
589                         member.memberOffset += dataMember.memberOffset;
590                   }
591                   else
592                   {
593                      if(alignment)
594                      {
595                         if(_class.memberOffset % alignment)
596                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
597                         _class.structAlignment = Max(_class.structAlignment, alignment);
598                      }
599                      dataMember.offset = _class.memberOffset;
600                      _class.memberOffset += dataMember.memberOffset;
601                   }
602                }
603             }
604          }
605          if(bitFields)
606          {
607             int alignment = 0;
608             int size = (bitFields + 7) / 8;
609
610             if(isMember)
611             {
612                // TESTING THIS PADDING CODE
613                if(alignment)
614                {
615                   member.structAlignment = Max(member.structAlignment, alignment);
616
617                   if(member.memberOffset % alignment)
618                      member.memberOffset += alignment - (member.memberOffset % alignment);
619                }
620
621                if(member.type == unionMember)
622                   unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
623                else
624                {
625                   member.memberOffset += size;
626                }
627             }
628             else
629             {
630                // TESTING THIS PADDING CODE
631                if(alignment)
632                {
633                   _class.structAlignment = Max(_class.structAlignment, alignment);
634
635                   if(_class.memberOffset % alignment)
636                      _class.memberOffset += alignment - (_class.memberOffset % alignment);
637                }
638                _class.memberOffset += size;
639             }
640             bitFields = 0;
641          }
642       }
643       if(member && member.type == unionMember)
644       {
645          member.memberOffset = unionMemberOffset;
646       }
647
648       if(!isMember)
649       {
650          /*if(_class.type == structClass)
651             _class.size = _class.memberOffset;
652          else
653          */
654
655          if(_class.type != bitClass)
656          {
657             int extra = 0;
658             if(_class.structAlignment)
659             {
660                if(_class.memberOffset % _class.structAlignment)
661                   extra += _class.structAlignment - (_class.memberOffset % _class.structAlignment);
662             }
663             _class.structSize = (_class.base ? (_class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize) : 0) + _class.memberOffset + extra;
664             if(!member)
665             {
666                Property prop;
667                for(prop = _class.membersAndProperties.first; prop; prop = prop.next)
668                {
669                   if(prop.isProperty && prop.isWatchable)
670                   {
671                      prop.watcherOffset = _class.structSize;
672                      _class.structSize += sizeof(OldList);
673                   }
674                }
675             }
676
677             // Fix Derivatives
678             {
679                OldLink derivative;
680                for(derivative = _class.derivatives.first; derivative; derivative = derivative.next)
681                {
682                   Class deriv = derivative.data;
683
684                   if(deriv.computeSize)
685                   {
686                      // TESTING THIS NEW CODE HERE... TRYING TO FIX ScrollBar MEMBERS DEBUGGING
687                      deriv.offset = /*_class.offset + */_class.structSize;
688                      deriv.memberOffset = 0;
689                      // ----------------------
690
691                      deriv.structSize = deriv.offset;
692
693                      ComputeClassMembers(deriv, false);
694                   }
695                }
696             }
697          }
698       }
699    }
700    if(context)
701       FinishTemplatesContext(context);
702 }
703
704 public void ComputeModuleClasses(Module module)
705 {
706    Class _class;
707    OldLink subModule;
708
709    for(subModule = module.modules.first; subModule; subModule = subModule.next)
710       ComputeModuleClasses(subModule.data);
711    for(_class = module.classes.first; _class; _class = _class.next)
712       ComputeClassMembers(_class, false);
713 }
714
715
716 public int ComputeTypeSize(Type type)
717 {
718    uint size = type ? type.size : 0;
719    if(!size && type && !type.computing)
720    {
721       type.computing = true;
722       switch(type.kind)
723       {
724          case _BoolType: type.alignment = size = sizeof(char); break;   // Assuming 1 byte _Bool
725          case charType: type.alignment = size = sizeof(char); break;
726          case intType: type.alignment = size = sizeof(int); break;
727          case int64Type: type.alignment = size = sizeof(int64); break;
728          case intPtrType: type.alignment = size = targetBits / 8; break;
729          case intSizeType: type.alignment = size = targetBits / 8; break;
730          case longType: type.alignment = size = sizeof(long); break;
731          case shortType: type.alignment = size = sizeof(short); break;
732          case floatType: type.alignment = size = sizeof(float); break;
733          case doubleType: type.alignment = size = sizeof(double); break;
734          case classType:
735          {
736             Class _class = type._class ? type._class.registered : null;
737
738             if(_class && _class.type == structClass)
739             {
740                // Ensure all members are properly registered
741                ComputeClassMembers(_class, false);
742                type.alignment = _class.structAlignment;
743                size = _class.structSize;
744                if(type.alignment && size % type.alignment)
745                   size += type.alignment - (size % type.alignment);
746
747             }
748             else if(_class && (_class.type == unitClass ||
749                    _class.type == enumClass ||
750                    _class.type == bitClass))
751             {
752                if(!_class.dataType)
753                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
754                size = type.alignment = ComputeTypeSize(_class.dataType);
755             }
756             else
757                size = type.alignment = targetBits / 8; // sizeof(Instance *);
758             break;
759          }
760          case pointerType: case subClassType: size = type.alignment = targetBits / 8; /*sizeof(void *); */break;
761          case arrayType:
762             if(type.arraySizeExp)
763             {
764                ProcessExpressionType(type.arraySizeExp);
765                ComputeExpression(type.arraySizeExp);
766                if(!type.arraySizeExp.isConstant || (type.arraySizeExp.expType.kind != intType && type.arraySizeExp.expType.kind != enumType &&
767                   (type.arraySizeExp.expType.kind != classType || !type.arraySizeExp.expType._class.registered || type.arraySizeExp.expType._class.registered.type != enumClass)))
768                {
769                   Location oldLoc = yylloc;
770                   // bool isConstant = type.arraySizeExp.isConstant;
771                   char expression[10240];
772                   expression[0] = '\0';
773                   type.arraySizeExp.expType = null;
774                   yylloc = type.arraySizeExp.loc;
775                   if(inCompiler)
776                      PrintExpression(type.arraySizeExp, expression);
777                   Compiler_Error($"Array size not constant int (%s)\n", expression);
778                   yylloc = oldLoc;
779                }
780                GetInt(type.arraySizeExp, &type.arraySize);
781             }
782             else if(type.enumClass)
783             {
784                if(type.enumClass && type.enumClass.registered && type.enumClass.registered.type == enumClass)
785                {
786                   type.arraySize = (int)eClass_GetProperty(type.enumClass.registered, "enumSize");
787                }
788                else
789                   type.arraySize = 0;
790             }
791             else
792             {
793                // Unimplemented auto size
794                type.arraySize = 0;
795             }
796
797             size = ComputeTypeSize(type.type) * type.arraySize;
798             if(type.type)
799                type.alignment = type.type.alignment;
800
801             break;
802          case structType:
803          {
804             Type member;
805             for(member = type.members.first; member; member = member.next)
806             {
807                uint addSize = ComputeTypeSize(member);
808
809                member.offset = size;
810                if(member.alignment && size % member.alignment)
811                   member.offset += member.alignment - (size % member.alignment);
812                size = member.offset;
813
814                type.alignment = Max(type.alignment, member.alignment);
815                size += addSize;
816             }
817             if(type.alignment && size % type.alignment)
818                size += type.alignment - (size % type.alignment);
819             break;
820          }
821          case unionType:
822          {
823             Type member;
824             for(member = type.members.first; member; member = member.next)
825             {
826                uint addSize = ComputeTypeSize(member);
827
828                member.offset = size;
829                if(member.alignment && size % member.alignment)
830                   member.offset += member.alignment - (size % member.alignment);
831                size = member.offset;
832
833                type.alignment = Max(type.alignment, member.alignment);
834                size = Max(size, addSize);
835             }
836             if(type.alignment && size % type.alignment)
837                size += type.alignment - (size % type.alignment);
838             break;
839          }
840          case templateType:
841          {
842             TemplateParameter param = type.templateParameter;
843             Type baseType = ProcessTemplateParameterType(param);
844             if(baseType)
845             {
846                size = ComputeTypeSize(baseType);
847                type.alignment = baseType.alignment;
848             }
849             else
850                type.alignment = size = sizeof(uint64);
851             break;
852          }
853          case enumType:
854          {
855             type.alignment = size = sizeof(enum { test });
856             break;
857          }
858          case thisClassType:
859          {
860             type.alignment = size = targetBits / 8; //sizeof(void *);
861             break;
862          }
863       }
864       type.size = size;
865       type.computing = false;
866    }
867    return size;
868 }
869
870
871 /*static */int AddMembers(OldList * declarations, Class _class, bool isMember, uint * retSize, Class topClass, bool *addedPadding)
872 {
873    // This function is in need of a major review when implementing private members etc.
874    DataMember topMember = isMember ? (DataMember) _class : null;
875    uint totalSize = 0;
876    uint maxSize = 0;
877    int alignment, size;
878    DataMember member;
879    Context context = isMember ? null : SetupTemplatesContext(_class);
880    if(addedPadding)
881       *addedPadding = false;
882
883    if(!isMember && _class.base)
884    {
885       maxSize = _class.structSize;
886       //if(_class.base.type != systemClass) // Commented out with new Instance _class
887       {
888          // DANGER: Testing this noHeadClass here...
889          if(_class.type == structClass || _class.type == noHeadClass)
890             /*totalSize = */AddMembers(declarations, _class.base, false, &totalSize, topClass, null);
891          else
892          {
893             uint baseSize = _class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize;
894             if(maxSize > baseSize)
895                maxSize -= baseSize;
896             else
897                maxSize = 0;
898          }
899       }
900    }
901
902    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
903    {
904       if(!member.isProperty)
905       {
906          switch(member.type)
907          {
908             case normalMember:
909             {
910                if(member.dataTypeString)
911                {
912                   OldList * specs = MkList(), * decls = MkList();
913                   Declarator decl;
914
915                   decl = SpecDeclFromString(member.dataTypeString, specs,
916                      MkDeclaratorIdentifier(MkIdentifier(member.name)));
917                   ListAdd(decls, MkStructDeclarator(decl, null));
918                   ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, decls, null)));
919
920                   if(!member.dataType)
921                      member.dataType = ProcessType(specs, decl);
922
923                   ReplaceThisClassSpecifiers(specs, topClass /*member._class*/);
924
925                   {
926                      Type type = ProcessType(specs, decl);
927                      DeclareType(member.dataType, false, false);
928                      FreeType(type);
929                   }
930                   /*
931                   if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
932                      member.dataType._class.registered && member.dataType._class.registered.type == structClass)
933                      DeclareStruct(member.dataType._class.string, false);
934                   */
935
936                   ComputeTypeSize(member.dataType);
937                   size = member.dataType.size;
938                   alignment = member.dataType.alignment;
939
940                   if(alignment)
941                   {
942                      if(totalSize % alignment)
943                         totalSize += alignment - (totalSize % alignment);
944                   }
945                   totalSize += size;
946                }
947                break;
948             }
949             case unionMember:
950             case structMember:
951             {
952                OldList * specs = MkList(), * list = MkList();
953
954                size = 0;
955                AddMembers(list, (Class)member, true, &size, topClass, null);
956                ListAdd(specs,
957                   MkStructOrUnion((member.type == unionMember)?unionSpecifier:structSpecifier, null, list));
958                ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, null, null)));
959                alignment = member.structAlignment;
960
961                if(alignment)
962                {
963                   if(totalSize % alignment)
964                      totalSize += alignment - (totalSize % alignment);
965                }
966                totalSize += size;
967                break;
968             }
969          }
970       }
971    }
972    if(retSize)
973    {
974       if(topMember && topMember.type == unionMember)
975          *retSize = Max(*retSize, totalSize);
976       else
977          *retSize += totalSize;
978    }
979    else if(totalSize < maxSize && _class.type != systemClass)
980    {
981       int autoPadding = 0;
982       if(!isMember && _class.structAlignment && totalSize % _class.structAlignment)
983          autoPadding = _class.structAlignment - (totalSize % _class.structAlignment);
984       if(totalSize + autoPadding < maxSize)
985       {
986          char sizeString[50];
987          sprintf(sizeString, "%d", maxSize - totalSize);
988          ListAdd(declarations,
989             MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(CHAR)),
990             MkListOne(MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__ecere_padding")), MkExpConstant(sizeString))), null)));
991          if(addedPadding)
992             *addedPadding = true;
993       }
994    }
995    if(context)
996       FinishTemplatesContext(context);
997    return topMember ? topMember.memberID : _class.memberID;
998 }
999
1000 static int DeclareMembers(Class _class, bool isMember)
1001 {
1002    DataMember topMember = isMember ? (DataMember) _class : null;
1003    uint totalSize = 0;
1004    DataMember member;
1005    Context context = isMember ? null : SetupTemplatesContext(_class);
1006
1007    if(!isMember && (_class.type == structClass || _class.type == noHeadClass) && _class.base.type != systemClass)
1008       DeclareMembers(_class.base, false);
1009
1010    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
1011    {
1012       if(!member.isProperty)
1013       {
1014          switch(member.type)
1015          {
1016             case normalMember:
1017             {
1018                /*
1019                if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
1020                   member.dataType._class.registered && member.dataType._class.registered.type == structClass)
1021                   DeclareStruct(member.dataType._class.string, false);
1022                   */
1023                if(!member.dataType && member.dataTypeString)
1024                   member.dataType = ProcessTypeString(member.dataTypeString, false);
1025                if(member.dataType)
1026                   DeclareType(member.dataType, false, false);
1027                break;
1028             }
1029             case unionMember:
1030             case structMember:
1031             {
1032                DeclareMembers((Class)member, true);
1033                break;
1034             }
1035          }
1036       }
1037    }
1038    if(context)
1039       FinishTemplatesContext(context);
1040
1041    return topMember ? topMember.memberID : _class.memberID;
1042 }
1043
1044 void DeclareStruct(char * name, bool skipNoHead)
1045 {
1046    External external = null;
1047    Symbol classSym = FindClass(name);
1048
1049    if(!inCompiler || !classSym) return;
1050
1051    // We don't need any declaration for bit classes...
1052    if(classSym.registered &&
1053       (classSym.registered.type == bitClass || classSym.registered.type == unitClass || classSym.registered.type == enumClass))
1054       return;
1055
1056    /*if(classSym.registered.templateClass)
1057       return DeclareStruct(classSym.registered.templateClass.fullName, skipNoHead);
1058    */
1059
1060    if(classSym.registered && classSym.imported && !classSym.declaredStructSym)
1061    {
1062       // Add typedef struct
1063       Declaration decl;
1064       OldList * specifiers, * declarators;
1065       OldList * declarations = null;
1066       char structName[1024];
1067       external = (classSym.registered && classSym.registered.type == structClass) ?
1068          classSym.pointerExternal : classSym.structExternal;
1069
1070       // TEMPORARY HACK: Pass 3 will move up struct declarations without moving members
1071       // Moved this one up because DeclareClass done later will need it
1072
1073       classSym.declaring++;
1074
1075       if(strchr(classSym.string, '<'))
1076       {
1077          if(classSym.registered.templateClass)
1078          {
1079             DeclareStruct(classSym.registered.templateClass.fullName, skipNoHead);
1080             classSym.declaring--;
1081          }
1082          return;
1083       }
1084
1085       //if(!skipNoHead)
1086          DeclareMembers(classSym.registered, false);
1087
1088       structName[0] = 0;
1089       FullClassNameCat(structName, name, false);
1090
1091       /*if(!external)
1092          external = MkExternalDeclaration(null);*/
1093
1094       if(!skipNoHead)
1095       {
1096          bool addedPadding = false;
1097          classSym.declaredStructSym = true;
1098
1099          declarations = MkList();
1100
1101          AddMembers(declarations, classSym.registered, false, null, classSym.registered, &addedPadding);
1102
1103          //ListAdd(specifiers, MkSpecifier(TYPEDEF));
1104          //ListAdd(specifiers, MkStructOrUnion(structSpecifier, null, declarations));
1105
1106          if(!declarations->count || (declarations->count == 1 && addedPadding))
1107          {
1108             FreeList(declarations, FreeClassDef);
1109             declarations = null;
1110          }
1111       }
1112       if(skipNoHead || declarations)
1113       {
1114          if(external && external.declaration)
1115          {
1116             ((Specifier)external.declaration.specifiers->first).definitions = declarations;
1117
1118             if(curExternal && curExternal.symbol && curExternal.symbol.idCode < classSym.id)
1119             {
1120                // TODO: Fix this
1121                //ast->Move(classSym.structExternal ? classSym.structExternal : classSym.pointerExternal, curExternal.prev);
1122
1123                // DANGER
1124                if(classSym.structExternal)
1125                   ast->Move(classSym.structExternal, curExternal.prev);
1126                ast->Move(classSym.pointerExternal, curExternal.prev);
1127
1128                classSym.id = curExternal.symbol.idCode;
1129                classSym.idCode = curExternal.symbol.idCode;
1130                // external = classSym.pointerExternal;
1131                //external = classSym.structExternal ? classSym.structExternal : classSym.pointerExternal;
1132             }
1133          }
1134          else
1135          {
1136             if(!external)
1137                external = MkExternalDeclaration(null);
1138
1139             specifiers = MkList();
1140             declarators = MkList();
1141             ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), declarations));
1142
1143             /*
1144             d = MkDeclaratorIdentifier(MkIdentifier(structName));
1145             ListAdd(declarators, MkInitDeclarator(d, null));
1146             */
1147             external.declaration = decl = MkDeclaration(specifiers, declarators);
1148             if(decl.symbol && !decl.symbol.pointerExternal)
1149                decl.symbol.pointerExternal = external;
1150
1151             // For simple classes, keep the declaration as the external to move around
1152             if(classSym.registered && classSym.registered.type == structClass)
1153             {
1154                char className[1024];
1155                strcpy(className, "__ecereClass_");
1156                FullClassNameCat(className, classSym.string, true);
1157                MangleClassName(className);
1158
1159                // Testing This
1160                DeclareClass(classSym, className);
1161
1162                external.symbol = classSym;
1163                classSym.pointerExternal = external;
1164                classSym.id = (curExternal && curExternal.symbol) ? curExternal.symbol.idCode : 0;
1165                classSym.idCode = (curExternal && curExternal.symbol) ? curExternal.symbol.idCode : 0;
1166             }
1167             else
1168             {
1169                char className[1024];
1170                strcpy(className, "__ecereClass_");
1171                FullClassNameCat(className, classSym.string, true);
1172                MangleClassName(className);
1173
1174                // TOFIX: TESTING THIS...
1175                classSym.structExternal = external;
1176                DeclareClass(classSym, className);
1177                external.symbol = classSym;
1178             }
1179
1180             //if(curExternal)
1181                ast->Insert(curExternal ? curExternal.prev : null, external);
1182          }
1183       }
1184
1185       classSym.declaring--;
1186    }
1187    else if(curExternal && curExternal.symbol && curExternal.symbol.idCode < classSym.id)
1188    {
1189       // TEMPORARY HACK: Pass 3 will move up struct declarations without moving members
1190       // Moved this one up because DeclareClass done later will need it
1191
1192       // TESTING THIS:
1193       classSym.declaring++;
1194
1195       //if(!skipNoHead)
1196       {
1197          if(classSym.registered)
1198             DeclareMembers(classSym.registered, false);
1199       }
1200
1201       if(classSym.registered && (classSym.registered.type == structClass || classSym.registered.type == noHeadClass))
1202       {
1203          // TODO: Fix this
1204          //ast->Move(classSym.structExternal ? classSym.structExternal : classSym.pointerExternal, curExternal.prev);
1205
1206          // DANGER
1207          if(classSym.structExternal)
1208             ast->Move(classSym.structExternal, curExternal.prev);
1209          ast->Move(classSym.pointerExternal, curExternal.prev);
1210
1211          classSym.id = curExternal.symbol.idCode;
1212          classSym.idCode = curExternal.symbol.idCode;
1213          // external = classSym.pointerExternal;
1214          // external = classSym.structExternal ? classSym.structExternal : classSym.pointerExternal;
1215       }
1216
1217       classSym.declaring--;
1218    }
1219    //return external;
1220 }
1221
1222 void DeclareProperty(Property prop, char * setName, char * getName)
1223 {
1224    Symbol symbol = prop.symbol;
1225    char propName[1024];
1226
1227    strcpy(setName, "__ecereProp_");
1228    FullClassNameCat(setName, prop._class.fullName, false);
1229    strcat(setName, "_Set_");
1230    // strcat(setName, prop.name);
1231    FullClassNameCat(setName, prop.name, true);
1232
1233    strcpy(getName, "__ecereProp_");
1234    FullClassNameCat(getName, prop._class.fullName, false);
1235    strcat(getName, "_Get_");
1236    FullClassNameCat(getName, prop.name, true);
1237    // strcat(getName, prop.name);
1238
1239    strcpy(propName, "__ecereProp_");
1240    FullClassNameCat(propName, prop._class.fullName, false);
1241    strcat(propName, "_");
1242    FullClassNameCat(propName, prop.name, true);
1243    // strcat(propName, prop.name);
1244
1245    // To support "char *" property
1246    MangleClassName(getName);
1247    MangleClassName(setName);
1248    MangleClassName(propName);
1249
1250    if(prop._class.type == structClass)
1251       DeclareStruct(prop._class.fullName, false);
1252
1253    if(!symbol || curExternal.symbol.idCode < symbol.id)
1254    {
1255       bool imported = false;
1256       bool dllImport = false;
1257       if(!symbol || symbol._import)
1258       {
1259          if(!symbol)
1260          {
1261             Symbol classSym;
1262             if(!prop._class.symbol)
1263                prop._class.symbol = FindClass(prop._class.fullName);
1264             classSym = prop._class.symbol;
1265             if(classSym && !classSym._import)
1266             {
1267                ModuleImport module;
1268
1269                if(prop._class.module)
1270                   module = FindModule(prop._class.module);
1271                else
1272                   module = mainModule;
1273
1274                classSym._import = ClassImport
1275                {
1276                   name = CopyString(prop._class.fullName);
1277                   isRemote = prop._class.isRemote;
1278                };
1279                module.classes.Add(classSym._import);
1280             }
1281             symbol = prop.symbol = Symbol { };
1282             symbol._import = (ClassImport)PropertyImport
1283             {
1284                name = CopyString(prop.name);
1285                isVirtual = false; //prop.isVirtual;
1286                hasSet = prop.Set ? true : false;
1287                hasGet = prop.Get ? true : false;
1288             };
1289             if(classSym)
1290                classSym._import.properties.Add(symbol._import);
1291          }
1292          imported = true;
1293          // Ugly work around for isNan properties declared within float/double classes which are initialized with ecereCOM
1294          if((prop._class.module != privateModule || !strcmp(prop._class.name, "float") || !strcmp(prop._class.name, "double")) &&
1295             prop._class.module.importType != staticImport)
1296             dllImport = true;
1297       }
1298
1299       if(!symbol.type)
1300       {
1301          Context context = SetupTemplatesContext(prop._class);
1302          symbol.type = ProcessTypeString(prop.dataTypeString, false);
1303          FinishTemplatesContext(context);
1304       }
1305
1306       // Get
1307       if(prop.Get)
1308       {
1309          if(!symbol.externalGet || symbol.externalGet.type == functionExternal)
1310          {
1311             Declaration decl;
1312             OldList * specifiers, * declarators;
1313             Declarator d;
1314             OldList * params;
1315             Specifier spec;
1316             External external;
1317             Declarator typeDecl;
1318             bool simple = false;
1319
1320             specifiers = MkList();
1321             declarators = MkList();
1322             params = MkList();
1323
1324             ListAdd(params, MkTypeName(MkListOne(MkSpecifierName /*MkClassName*/(prop._class.fullName)),
1325                MkDeclaratorIdentifier(MkIdentifier("this"))));
1326
1327             d = MkDeclaratorIdentifier(MkIdentifier(getName));
1328             //if(imported)
1329             if(dllImport)
1330                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1331
1332             {
1333                Context context = SetupTemplatesContext(prop._class);
1334                typeDecl = SpecDeclFromString(prop.dataTypeString, specifiers, null);
1335                FinishTemplatesContext(context);
1336             }
1337
1338             // Make sure the simple _class's type is declared
1339             for(spec = specifiers->first; spec; spec = spec.next)
1340             {
1341                if(spec.type == nameSpecifier /*SpecifierClass*/)
1342                {
1343                   if((!typeDecl || typeDecl.type == identifierDeclarator))
1344                   {
1345                      Symbol classSym = spec.symbol; // FindClass(spec.name);
1346                      symbol._class = classSym.registered;
1347                      if(classSym.registered && classSym.registered.type == structClass)
1348                      {
1349                         DeclareStruct(spec.name, false);
1350                         simple = true;
1351                      }
1352                   }
1353                }
1354             }
1355
1356             if(!simple)
1357                d = PlugDeclarator(typeDecl, d);
1358             else
1359             {
1360                ListAdd(params, MkTypeName(specifiers,
1361                   PlugDeclarator(typeDecl, MkDeclaratorIdentifier(MkIdentifier("value")))));
1362                specifiers = MkList();
1363             }
1364
1365             d = MkDeclaratorFunction(d, params);
1366
1367             //if(imported)
1368             if(dllImport)
1369                specifiers->Insert(null, MkSpecifier(EXTERN));
1370             else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1371                specifiers->Insert(null, MkSpecifier(STATIC));
1372             if(simple)
1373                ListAdd(specifiers, MkSpecifier(VOID));
1374
1375             ListAdd(declarators, MkInitDeclarator(d, null));
1376
1377             decl = MkDeclaration(specifiers, declarators);
1378
1379             external = MkExternalDeclaration(decl);
1380             ast->Insert(curExternal.prev, external);
1381             external.symbol = symbol;
1382             symbol.externalGet = external;
1383
1384             ReplaceThisClassSpecifiers(specifiers, prop._class);
1385
1386             if(typeDecl)
1387                FreeDeclarator(typeDecl);
1388          }
1389          else
1390          {
1391             // Move declaration higher...
1392             ast->Move(symbol.externalGet, curExternal.prev);
1393          }
1394       }
1395
1396       // Set
1397       if(prop.Set)
1398       {
1399          if(!symbol.externalSet || symbol.externalSet.type == functionExternal)
1400          {
1401             Declaration decl;
1402             OldList * specifiers, * declarators;
1403             Declarator d;
1404             OldList * params;
1405             Specifier spec;
1406             External external;
1407             Declarator typeDecl;
1408
1409             declarators = MkList();
1410             params = MkList();
1411
1412             // TESTING COMMENTING THIS FIRST LINE OUT, what was the problem? Trying to add noHeadClass here ...
1413             if(!prop.conversion || prop._class.type == structClass)
1414             {
1415                ListAdd(params, MkTypeName(MkListOne(MkSpecifierName/*MkClassName*/(prop._class.fullName)),
1416                   MkDeclaratorIdentifier(MkIdentifier("this"))));
1417             }
1418
1419             specifiers = MkList();
1420
1421             {
1422                Context context = SetupTemplatesContext(prop._class);
1423                typeDecl = d = SpecDeclFromString(prop.dataTypeString, specifiers,
1424                   MkDeclaratorIdentifier(MkIdentifier("value")));
1425                FinishTemplatesContext(context);
1426             }
1427             ListAdd(params, MkTypeName(specifiers, d));
1428
1429             d = MkDeclaratorIdentifier(MkIdentifier(setName));
1430             //if(imported)
1431             if(dllImport)
1432                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1433             d = MkDeclaratorFunction(d, params);
1434
1435             // Make sure the simple _class's type is declared
1436             for(spec = specifiers->first; spec; spec = spec.next)
1437             {
1438                if(spec.type == nameSpecifier /*SpecifierClass*/)
1439                {
1440                   if((!typeDecl || typeDecl.type == identifierDeclarator))
1441                   {
1442                      Symbol classSym = spec.symbol; // FindClass(spec.name);
1443                      symbol._class = classSym.registered;
1444                      if(classSym.registered && classSym.registered.type == structClass)
1445                         DeclareStruct(spec.name, false);
1446                   }
1447                }
1448             }
1449
1450             ListAdd(declarators, MkInitDeclarator(d, null));
1451
1452             specifiers = MkList();
1453             //if(imported)
1454             if(dllImport)
1455                specifiers->Insert(null, MkSpecifier(EXTERN));
1456             else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1457                specifiers->Insert(null, MkSpecifier(STATIC));
1458
1459             // TESTING COMMENTING THIS FIRST LINE OUT, what was the problem? Trying to add noHeadClass here ...
1460             if(!prop.conversion || prop._class.type == structClass)
1461                ListAdd(specifiers, MkSpecifier(VOID));
1462             else
1463                ListAdd(specifiers, MkSpecifierName/*MkClassName*/(prop._class.fullName));
1464
1465             decl = MkDeclaration(specifiers, declarators);
1466
1467             external = MkExternalDeclaration(decl);
1468             ast->Insert(curExternal.prev, external);
1469             external.symbol = symbol;
1470             symbol.externalSet = external;
1471
1472             ReplaceThisClassSpecifiers(specifiers, prop._class);
1473          }
1474          else
1475          {
1476             // Move declaration higher...
1477             ast->Move(symbol.externalSet, curExternal.prev);
1478          }
1479       }
1480
1481       // Property (for Watchers)
1482       if(!symbol.externalPtr)
1483       {
1484          Declaration decl;
1485          External external;
1486          OldList * specifiers = MkList();
1487
1488          if(imported)
1489             specifiers->Insert(null, MkSpecifier(EXTERN));
1490          else
1491             specifiers->Insert(null, MkSpecifier(STATIC));
1492
1493          ListAdd(specifiers, MkSpecifierName("Property"));
1494
1495          {
1496             OldList * list = MkList();
1497             ListAdd(list, MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null),
1498                   MkDeclaratorIdentifier(MkIdentifier(propName))), null));
1499
1500             if(!imported)
1501             {
1502                strcpy(propName, "__ecerePropM_");
1503                FullClassNameCat(propName, prop._class.fullName, false);
1504                strcat(propName, "_");
1505                // strcat(propName, prop.name);
1506                FullClassNameCat(propName, prop.name, true);
1507
1508                MangleClassName(propName);
1509
1510                ListAdd(list, MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null),
1511                      MkDeclaratorIdentifier(MkIdentifier(propName))), null));
1512             }
1513             decl = MkDeclaration(specifiers, list);
1514          }
1515
1516          external = MkExternalDeclaration(decl);
1517          ast->Insert(curExternal.prev, external);
1518          external.symbol = symbol;
1519          symbol.externalPtr = external;
1520       }
1521       else
1522       {
1523          // Move declaration higher...
1524          ast->Move(symbol.externalPtr, curExternal.prev);
1525       }
1526
1527       symbol.id = curExternal.symbol.idCode;
1528    }
1529 }
1530
1531 // ***************** EXPRESSION PROCESSING ***************************
1532 public Type Dereference(Type source)
1533 {
1534    Type type = null;
1535    if(source)
1536    {
1537       if(source.kind == pointerType || source.kind == arrayType)
1538       {
1539          type = source.type;
1540          source.type.refCount++;
1541       }
1542       else if(source.kind == classType && !strcmp(source._class.string, "String"))
1543       {
1544          type = Type
1545          {
1546             kind = charType;
1547             refCount = 1;
1548          };
1549       }
1550       // Support dereferencing of no head classes for now...
1551       else if(source.kind == classType && source._class && source._class.registered && source._class.registered.type == noHeadClass)
1552       {
1553          type = source;
1554          source.refCount++;
1555       }
1556       else
1557          Compiler_Error($"cannot dereference type\n");
1558    }
1559    return type;
1560 }
1561
1562 static Type Reference(Type source)
1563 {
1564    Type type = null;
1565    if(source)
1566    {
1567       type = Type
1568       {
1569          kind = pointerType;
1570          type = source;
1571          refCount = 1;
1572       };
1573       source.refCount++;
1574    }
1575    return type;
1576 }
1577
1578 void ProcessMemberInitData(MemberInit member, Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
1579 {
1580    Identifier ident = member.identifiers ? member.identifiers->first : null;
1581    bool found = false;
1582    DataMember dataMember = null;
1583    Method method = null;
1584    bool freeType = false;
1585
1586    yylloc = member.loc;
1587
1588    if(!ident)
1589    {
1590       if(curMember)
1591       {
1592          eClass_FindNextMember(_class, curClass, curMember, subMemberStack, subMemberStackPos);
1593          if(*curMember)
1594          {
1595             found = true;
1596             dataMember = *curMember;
1597          }
1598       }
1599    }
1600    else
1601    {
1602       DataMember thisMember = (DataMember)eClass_FindProperty(_class, ident.string, privateModule);
1603       DataMember _subMemberStack[256];
1604       int _subMemberStackPos = 0;
1605
1606       // FILL MEMBER STACK
1607       if(!thisMember)
1608          thisMember = eClass_FindDataMember(_class, ident.string, privateModule, _subMemberStack, &_subMemberStackPos);
1609       if(thisMember)
1610       {
1611          dataMember = thisMember;
1612          if(curMember && thisMember.memberAccess == publicAccess)
1613          {
1614             *curMember = thisMember;
1615             *curClass = thisMember._class;
1616             memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
1617             *subMemberStackPos = _subMemberStackPos;
1618          }
1619          found = true;
1620       }
1621       else
1622       {
1623          // Setting a method
1624          method = eClass_FindMethod(_class, ident.string, privateModule);
1625          if(method && method.type == virtualMethod)
1626             found = true;
1627          else
1628             method = null;
1629       }
1630    }
1631
1632    if(found)
1633    {
1634       Type type = null;
1635       if(dataMember)
1636       {
1637          if(!dataMember.dataType && dataMember.dataTypeString)
1638          {
1639             //Context context = SetupTemplatesContext(dataMember._class);
1640             Context context = SetupTemplatesContext(_class);
1641             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
1642             FinishTemplatesContext(context);
1643          }
1644          type = dataMember.dataType;
1645       }
1646       else if(method)
1647       {
1648          // This is for destination type...
1649          if(!method.dataType)
1650             ProcessMethodType(method);
1651          //DeclareMethod(method);
1652          // method.dataType = ((Symbol)method.symbol)->type;
1653          type = method.dataType;
1654       }
1655
1656       if(ident && ident.next)
1657       {
1658          for(ident = ident.next; ident && type; ident = ident.next)
1659          {
1660             if(type.kind == classType)
1661             {
1662                dataMember = (DataMember)eClass_FindProperty(type._class.registered, ident.string, privateModule);
1663                if(!dataMember)
1664                   dataMember = eClass_FindDataMember(type._class.registered, ident.string, privateModule, null, null);
1665                if(dataMember)
1666                   type = dataMember.dataType;
1667             }
1668             else if(type.kind == structType || type.kind == unionType)
1669             {
1670                Type memberType;
1671                for(memberType = type.members.first; memberType; memberType = memberType.next)
1672                {
1673                   if(!strcmp(memberType.name, ident.string))
1674                   {
1675                      type = memberType;
1676                      break;
1677                   }
1678                }
1679             }
1680          }
1681       }
1682
1683       // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
1684       if(type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type && _class.templateArgs /* TODO: Watch out for these _class.templateClass*/)
1685       {
1686          int id = 0;
1687          ClassTemplateParameter curParam = null;
1688          Class sClass;
1689          for(sClass = _class; sClass; sClass = sClass.base)
1690          {
1691             id = 0;
1692             if(sClass.templateClass) sClass = sClass.templateClass;
1693             for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
1694             {
1695                if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
1696                {
1697                   for(sClass = sClass.base; sClass; sClass = sClass.base)
1698                   {
1699                      if(sClass.templateClass) sClass = sClass.templateClass;
1700                      id += sClass.templateParams.count;
1701                   }
1702                   break;
1703                }
1704                id++;
1705             }
1706             if(curParam) break;
1707          }
1708
1709          if(curParam)
1710          {
1711             ClassTemplateArgument arg = _class.templateArgs[id];
1712             if(arg.dataTypeString)
1713             {
1714                // FreeType(type);
1715                type = ProcessTypeString(arg.dataTypeString, false);
1716                freeType = true;
1717                if(type && _class.templateClass)
1718                   type.passAsTemplate = true;
1719                if(type)
1720                {
1721                   // type.refCount++;
1722                   /*if(!exp.destType)
1723                   {
1724                      exp.destType = ProcessTypeString(arg.dataTypeString, false);
1725                      exp.destType.refCount++;
1726                   }*/
1727                }
1728             }
1729          }
1730       }
1731       if(type && type.kind == classType && type._class && type._class.registered && strchr(type._class.registered.fullName, '<'))
1732       {
1733          Class expClass = type._class.registered;
1734          Class cClass = null;
1735          int c;
1736          int paramCount = 0;
1737          int lastParam = -1;
1738
1739          char templateString[1024];
1740          ClassTemplateParameter param;
1741          sprintf(templateString, "%s<", expClass.templateClass.fullName);
1742          for(cClass = expClass; cClass; cClass = cClass.base)
1743          {
1744             int p = 0;
1745             if(cClass.templateClass) cClass = cClass.templateClass;
1746             for(param = cClass.templateParams.first; param; param = param.next)
1747             {
1748                int id = p;
1749                Class sClass;
1750                ClassTemplateArgument arg;
1751                for(sClass = cClass.base; sClass; sClass = sClass.base)
1752                {
1753                   if(sClass.templateClass) sClass = sClass.templateClass;
1754                   id += sClass.templateParams.count;
1755                }
1756                arg = expClass.templateArgs[id];
1757
1758                for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
1759                {
1760                   ClassTemplateParameter cParam;
1761                   //int p = numParams - sClass.templateParams.count;
1762                   int p = 0;
1763                   Class nextClass;
1764                   if(sClass.templateClass) sClass = sClass.templateClass;
1765
1766                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
1767                   {
1768                      if(nextClass.templateClass) nextClass = nextClass.templateClass;
1769                      p += nextClass.templateParams.count;
1770                   }
1771
1772                   for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
1773                   {
1774                      if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
1775                      {
1776                         if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1777                         {
1778                            arg.dataTypeString = _class.templateArgs[p].dataTypeString;
1779                            arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
1780                            break;
1781                         }
1782                      }
1783                   }
1784                }
1785
1786                {
1787                   char argument[256];
1788                   argument[0] = '\0';
1789                   /*if(arg.name)
1790                   {
1791                      strcat(argument, arg.name.string);
1792                      strcat(argument, " = ");
1793                   }*/
1794                   switch(param.type)
1795                   {
1796                      case expression:
1797                      {
1798                         // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
1799                         char expString[1024];
1800                         OldList * specs = MkList();
1801                         Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
1802                         Expression exp;
1803                         char * string = PrintHexUInt64(arg.expression.ui64);
1804                         exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
1805                         delete string;
1806
1807                         ProcessExpressionType(exp);
1808                         ComputeExpression(exp);
1809                         expString[0] = '\0';
1810                         PrintExpression(exp, expString);
1811                         strcat(argument, expString);
1812                         //delete exp;
1813                         FreeExpression(exp);
1814                         break;
1815                      }
1816                      case identifier:
1817                      {
1818                         strcat(argument, arg.member.name);
1819                         break;
1820                      }
1821                      case TemplateParameterType::type:
1822                      {
1823                         if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1824                            strcat(argument, arg.dataTypeString);
1825                         break;
1826                      }
1827                   }
1828                   if(argument[0])
1829                   {
1830                      if(paramCount) strcat(templateString, ", ");
1831                      if(lastParam != p - 1)
1832                      {
1833                         strcat(templateString, param.name);
1834                         strcat(templateString, " = ");
1835                      }
1836                      strcat(templateString, argument);
1837                      paramCount++;
1838                      lastParam = p;
1839                   }
1840                   p++;
1841                }
1842             }
1843          }
1844          {
1845             int len = strlen(templateString);
1846             if(templateString[len-1] == '<')
1847                len--;
1848             else
1849             {
1850                if(templateString[len-1] == '>')
1851                   templateString[len++] = ' ';
1852                templateString[len++] = '>';
1853             }
1854             templateString[len++] = '\0';
1855          }
1856          {
1857             Context context = SetupTemplatesContext(_class);
1858             if(freeType) FreeType(type);
1859             type = ProcessTypeString(templateString, false);
1860             freeType = true;
1861             FinishTemplatesContext(context);
1862          }
1863       }
1864
1865       if(method && member.initializer && member.initializer.type == expInitializer && member.initializer.exp)
1866       {
1867          ProcessExpressionType(member.initializer.exp);
1868          if(!member.initializer.exp.expType)
1869          {
1870             if(inCompiler)
1871             {
1872                char expString[10240];
1873                expString[0] = '\0';
1874                PrintExpression(member.initializer.exp, expString);
1875                ChangeCh(expString, '\n', ' ');
1876                Compiler_Error($"unresolved symbol used as an instance method %s\n", expString);
1877             }
1878          }
1879          //else if(!MatchTypes(member.exp.expType, type, null, _class, null, true, true, false, false))
1880          else if(!MatchTypes(member.initializer.exp.expType, type, null, null, _class, true, true, false, false))
1881          {
1882             Compiler_Error($"incompatible instance method %s\n", ident.string);
1883          }
1884       }
1885       else if(member.initializer)
1886       {
1887          /*
1888          FreeType(member.exp.destType);
1889          member.exp.destType = type;
1890          if(member.exp.destType)
1891             member.exp.destType.refCount++;
1892          ProcessExpressionType(member.exp);
1893          */
1894
1895          ProcessInitializer(member.initializer, type);
1896       }
1897       if(freeType) FreeType(type);
1898    }
1899    else
1900    {
1901       if(_class && _class.type == unitClass)
1902       {
1903          if(member.initializer)
1904          {
1905             /*
1906             FreeType(member.exp.destType);
1907             member.exp.destType = MkClassType(_class.fullName);
1908             ProcessExpressionType(member.initializer, type);
1909             */
1910             Type type = MkClassType(_class.fullName);
1911             ProcessInitializer(member.initializer, type);
1912             FreeType(type);
1913          }
1914       }
1915       else
1916       {
1917          if(member.initializer)
1918          {
1919             //ProcessExpressionType(member.exp);
1920             ProcessInitializer(member.initializer, null);
1921          }
1922          if(ident)
1923          {
1924             if(method)
1925             {
1926                Compiler_Error($"couldn't find virtual method %s in class %s\n", ident.string, _class.fullName);
1927             }
1928             else if(_class)
1929             {
1930                Compiler_Error($"couldn't find member %s in class %s\n", ident.string, _class.fullName);
1931                if(inCompiler)
1932                   eClass_AddDataMember(_class, ident.string, "int", 0, 0, publicAccess);
1933             }
1934          }
1935          else if(_class)
1936             Compiler_Error($"too many initializers for instantiation of class %s\n", _class.fullName);
1937       }
1938    }
1939 }
1940
1941 void ProcessInstantiationType(Instantiation inst)
1942 {
1943    yylloc = inst.loc;
1944    if(inst._class)
1945    {
1946       MembersInit members;
1947       Symbol classSym; // = inst._class.symbol; // FindClass(inst._class.name);
1948       Class _class;
1949
1950       /*if(!inst._class.symbol)
1951          inst._class.symbol = FindClass(inst._class.name);*/
1952       classSym = inst._class.symbol;
1953       _class = classSym ? classSym.registered : null;
1954
1955       // DANGER: Patch for mutex not declaring its struct when not needed
1956       if(!_class || _class.type != noHeadClass)
1957          DeclareStruct(inst._class.name, false); //_class && _class.type == noHeadClass);
1958
1959       afterExternal = afterExternal ? afterExternal : curExternal;
1960
1961       if(inst.exp)
1962          ProcessExpressionType(inst.exp);
1963
1964       inst.isConstant = true;
1965       if(inst.members)
1966       {
1967          DataMember curMember = null;
1968          Class curClass = null;
1969          DataMember subMemberStack[256];
1970          int subMemberStackPos = 0;
1971
1972          for(members = inst.members->first; members; members = members.next)
1973          {
1974             switch(members.type)
1975             {
1976                case methodMembersInit:
1977                {
1978                   char name[1024];
1979                   static uint instMethodID = 0;
1980                   External external = curExternal;
1981                   Context context = curContext;
1982                   Declarator declarator = members.function.declarator;
1983                   Identifier nameID = GetDeclId(declarator);
1984                   char * unmangled = nameID ? nameID.string : null;
1985                   Expression exp;
1986                   External createdExternal = null;
1987
1988                   if(inCompiler)
1989                   {
1990                      char number[16];
1991                      //members.function.dontMangle = true;
1992                      strcpy(name, "__ecereInstMeth_");
1993                      FullClassNameCat(name, _class ? _class.fullName : "_UNKNOWNCLASS", false);
1994                      strcat(name, "_");
1995                      strcat(name, nameID.string);
1996                      strcat(name, "_");
1997                      sprintf(number, "_%08d", instMethodID++);
1998                      strcat(name, number);
1999                      nameID.string = CopyString(name);
2000                   }
2001
2002                   // Do modifications here...
2003                   if(declarator)
2004                   {
2005                      Symbol symbol = declarator.symbol;
2006                      Method method = eClass_FindMethod(_class, unmangled, privateModule);
2007
2008                      if(method && method.type == virtualMethod)
2009                      {
2010                         symbol.method = method;
2011                         ProcessMethodType(method);
2012
2013                         if(!symbol.type.thisClass)
2014                         {
2015                            if(method.dataType.thisClass && currentClass &&
2016                               eClass_IsDerived(currentClass, method.dataType.thisClass.registered))
2017                            {
2018                               if(!currentClass.symbol)
2019                                  currentClass.symbol = FindClass(currentClass.fullName);
2020                               symbol.type.thisClass = currentClass.symbol;
2021                            }
2022                            else
2023                            {
2024                               if(!_class.symbol)
2025                                  _class.symbol = FindClass(_class.fullName);
2026                               symbol.type.thisClass = _class.symbol;
2027                            }
2028                         }
2029                         // TESTING THIS HERE:
2030                         DeclareType(symbol.type, true, true);
2031
2032                      }
2033                      else if(classSym)
2034                      {
2035                         Compiler_Error($"couldn't find virtual method %s in class %s\n",
2036                            unmangled, classSym.string);
2037                      }
2038                   }
2039
2040                   //declarator.symbol.id = declarator.symbol.idCode = curExternal.symbol.idCode;
2041                   createdExternal = ProcessClassFunction(classSym ? classSym.registered : null, members.function, ast, afterExternal, true);
2042
2043                   if(nameID)
2044                   {
2045                      FreeSpecifier(nameID._class);
2046                      nameID._class = null;
2047                   }
2048
2049                   if(inCompiler)
2050                   {
2051
2052                      Type type = declarator.symbol.type;
2053                      External oldExternal = curExternal;
2054
2055                      // *** Commented this out... Any negative impact? Yes: makes double prototypes declarations... Why was it commented out?
2056                      // *** It was commented out for problems such as
2057                      /*
2058                            class VirtualDesktop : Window
2059                            {
2060                               clientSize = Size { };
2061                               Timer timer
2062                               {
2063                                  bool DelayExpired()
2064                                  {
2065                                     clientSize.w;
2066                                     return true;
2067                                  }
2068                               };
2069                            }
2070                      */
2071                      // Commented Out: Good for bet.ec in Poker (Otherwise: obj\bet.c:187: error: `currentBet' undeclared (first use in this function))
2072
2073                      declarator.symbol.id = declarator.symbol.idCode = curExternal.symbol.idCode;
2074
2075                      /*
2076                      if(strcmp(declarator.symbol.string, name))
2077                      {
2078                         printf("TOCHECK: Look out for this\n");
2079                         delete declarator.symbol.string;
2080                         declarator.symbol.string = CopyString(name);
2081                      }
2082
2083                      if(!declarator.symbol.parent && globalContext.symbols.root != (BTNode)declarator.symbol)
2084                      {
2085                         printf("TOCHECK: Will this ever be in a list? Yes.\n");
2086                         excludedSymbols->Remove(declarator.symbol);
2087                         globalContext.symbols.Add((BTNode)declarator.symbol);
2088                         if(strstr(declarator.symbol.string), "::")
2089                            globalContext.hasNameSpace = true;
2090
2091                      }
2092                      */
2093
2094                      //curExternal = curExternal.prev;
2095                      //afterExternal = afterExternal->next;
2096
2097                      //ProcessFunction(afterExternal->function);
2098
2099                      //curExternal = afterExternal;
2100                      {
2101                         External externalDecl;
2102                         externalDecl = MkExternalDeclaration(null);
2103                         ast->Insert(oldExternal.prev, externalDecl);
2104
2105                         // Which function does this process?
2106                         if(createdExternal.function)
2107                         {
2108                            ProcessFunction(createdExternal.function);
2109
2110                            //curExternal = oldExternal;
2111
2112                            {
2113                               //Declaration decl = MkDeclaration(members.function.specifiers, MkListOne(MkInitDeclarator(CopyDeclarator(declarator), null)));
2114
2115                               Declaration decl = MkDeclaration(CopyList(createdExternal.function.specifiers, CopySpecifier),
2116                                  MkListOne(MkInitDeclarator(CopyDeclarator(declarator), null)));
2117
2118                               //externalDecl = MkExternalDeclaration(decl);
2119
2120                               //***** ast->Insert(external.prev, externalDecl);
2121                               //ast->Insert(curExternal.prev, externalDecl);
2122                               externalDecl.declaration = decl;
2123                               if(decl.symbol && !decl.symbol.pointerExternal)
2124                                  decl.symbol.pointerExternal = externalDecl;
2125
2126                               // Trying this out...
2127                               declarator.symbol.pointerExternal = externalDecl;
2128                            }
2129                         }
2130                      }
2131                   }
2132                   else if(declarator)
2133                   {
2134                      curExternal = declarator.symbol.pointerExternal;
2135                      ProcessFunction((FunctionDefinition)members.function);
2136                   }
2137                   curExternal = external;
2138                   curContext = context;
2139
2140                   if(inCompiler)
2141                   {
2142                      FreeClassFunction(members.function);
2143
2144                      // In this pass, turn this into a MemberInitData
2145                      exp = QMkExpId(name);
2146                      members.type = dataMembersInit;
2147                      members.dataMembers = MkListOne(MkMemberInit(MkListOne(MkIdentifier(unmangled)), MkInitializerAssignment(exp)));
2148
2149                      delete unmangled;
2150                   }
2151                   break;
2152                }
2153                case dataMembersInit:
2154                {
2155                   if(members.dataMembers && classSym)
2156                   {
2157                      MemberInit member;
2158                      Location oldyyloc = yylloc;
2159                      for(member = members.dataMembers->first; member; member = member.next)
2160                      {
2161                         ProcessMemberInitData(member, classSym.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
2162                         if(member.initializer && !member.initializer.isConstant)
2163                            inst.isConstant = false;
2164                      }
2165                      yylloc = oldyyloc;
2166                   }
2167                   break;
2168                }
2169             }
2170          }
2171       }
2172    }
2173 }
2174
2175 static void DeclareType(Type type, bool declarePointers, bool declareParams)
2176 {
2177    // OPTIMIZATIONS: TESTING THIS...
2178    if(inCompiler)
2179    {
2180       if(type.kind == functionType)
2181       {
2182          Type param;
2183          if(declareParams)
2184          {
2185             for(param = type.params.first; param; param = param.next)
2186                DeclareType(param, declarePointers, true);
2187          }
2188          DeclareType(type.returnType, declarePointers, true);
2189       }
2190       else if(type.kind == pointerType && declarePointers)
2191          DeclareType(type.type, declarePointers, false);
2192       else if(type.kind == classType)
2193       {
2194          if(type._class.registered && (type._class.registered.type == structClass || type._class.registered.type == noHeadClass) && !type._class.declaring)
2195             DeclareStruct(type._class.registered.fullName, type._class.registered.type == noHeadClass);
2196       }
2197       else if(type.kind == structType || type.kind == unionType)
2198       {
2199          Type member;
2200          for(member = type.members.first; member; member = member.next)
2201             DeclareType(member, false, false);
2202       }
2203       else if(type.kind == arrayType)
2204          DeclareType(type.arrayType, declarePointers, false);
2205    }
2206 }
2207
2208 ClassTemplateArgument * FindTemplateArg(Class _class, TemplateParameter param)
2209 {
2210    ClassTemplateArgument * arg = null;
2211    int id = 0;
2212    ClassTemplateParameter curParam = null;
2213    Class sClass;
2214    for(sClass = _class; sClass; sClass = sClass.base)
2215    {
2216       id = 0;
2217       if(sClass.templateClass) sClass = sClass.templateClass;
2218       for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
2219       {
2220          if(curParam.type == TemplateParameterType::type && !strcmp(param.identifier.string, curParam.name))
2221          {
2222             for(sClass = sClass.base; sClass; sClass = sClass.base)
2223             {
2224                if(sClass.templateClass) sClass = sClass.templateClass;
2225                id += sClass.templateParams.count;
2226             }
2227             break;
2228          }
2229          id++;
2230       }
2231       if(curParam) break;
2232    }
2233    if(curParam)
2234    {
2235       arg = &_class.templateArgs[id];
2236       if(arg && param.type == type)
2237          arg->dataTypeClass = eSystem_FindClass(_class.module, arg->dataTypeString);
2238    }
2239    return arg;
2240 }
2241
2242 public Context SetupTemplatesContext(Class _class)
2243 {
2244    Context context = PushContext();
2245    context.templateTypesOnly = true;
2246    if(_class.symbol && ((Symbol)_class.symbol).templateParams)
2247    {
2248       TemplateParameter param = ((Symbol)_class.symbol).templateParams->first;
2249       for(; param; param = param.next)
2250       {
2251          if(param.type == type && param.identifier)
2252          {
2253             TemplatedType type { key = (uintptr)param.identifier.string, param = param };
2254             curContext.templateTypes.Add((BTNode)type);
2255          }
2256       }
2257    }
2258    else if(_class)
2259    {
2260       Class sClass;
2261       for(sClass = _class; sClass; sClass = sClass.base)
2262       {
2263          ClassTemplateParameter p;
2264          for(p = sClass.templateParams.first; p; p = p.next)
2265          {
2266             //OldList * specs = MkList();
2267             //Declarator decl = null;
2268             //decl = SpecDeclFromString(p.dataTypeString, specs, null);
2269             if(p.type == type)
2270             {
2271                TemplateParameter param = p.param;
2272                TemplatedType type;
2273                if(!param)
2274                {
2275                   // ADD DATA TYPE HERE...
2276                   p.param = param = TemplateParameter
2277                   {
2278                      identifier = MkIdentifier(p.name), type = p.type,
2279                      dataTypeString = p.dataTypeString /*, dataType = { specs, decl }*/
2280                   };
2281                }
2282                type = TemplatedType { key = (uintptr)p.name, param = param };
2283                curContext.templateTypes.Add((BTNode)type);
2284             }
2285          }
2286       }
2287    }
2288    return context;
2289 }
2290
2291 public void FinishTemplatesContext(Context context)
2292 {
2293    PopContext(context);
2294    FreeContext(context);
2295    delete context;
2296 }
2297
2298 public void ProcessMethodType(Method method)
2299 {
2300    if(!method.dataType)
2301    {
2302       Context context = SetupTemplatesContext(method._class);
2303
2304       method.dataType = ProcessTypeString(method.dataTypeString, false);
2305
2306       FinishTemplatesContext(context);
2307
2308       if(method.type != virtualMethod && method.dataType)
2309       {
2310          if(!method.dataType.thisClass && !method.dataType.staticMethod)
2311          {
2312             if(!method._class.symbol)
2313                method._class.symbol = FindClass(method._class.fullName);
2314             method.dataType.thisClass = method._class.symbol;
2315          }
2316       }
2317
2318       // Why was this commented out? Working fine without now...
2319
2320       /*
2321       if(method.dataType.kind == functionType && !method.dataType.staticMethod && !method.dataType.thisClass)
2322          method.dataType.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2323          */
2324    }
2325
2326    /*
2327    if(type)
2328    {
2329       char * par = strstr(type, "(");
2330       char * classOp = null;
2331       int classOpLen = 0;
2332       if(par)
2333       {
2334          int c;
2335          for(c = par-type-1; c >= 0; c++)
2336          {
2337             if(type[c] == ':' && type[c+1] == ':')
2338             {
2339                classOp = type + c - 1;
2340                for(c = c-1; c >=0 && !isspace(type[c]); c--)
2341                {
2342                   classOp--;
2343                   classOpLen++;
2344                }
2345                break;
2346             }
2347             else if(!isspace(type[c]))
2348                break;
2349          }
2350       }
2351       if(classOp)
2352       {
2353          char temp[1024];
2354          int typeLen = strlen(type);
2355          memcpy(temp, classOp, classOpLen);
2356          temp[classOpLen] = '\0';
2357          if(temp[0])
2358             _class = eSystem_FindClass(module, temp);
2359          else
2360             _class = null;
2361          method.dataTypeString = new char[typeLen - classOpLen + 1];
2362          memcpy(method.dataTypeString, type, classOp - type);
2363          memcpy(method.dataTypeString + (classOp - type), classOp + classOpLen, typeLen - (classOp - type + classOpLen));
2364       }
2365       else
2366          method.dataTypeString = type;
2367    }
2368    */
2369 }
2370
2371
2372 public void ProcessPropertyType(Property prop)
2373 {
2374    if(!prop.dataType)
2375    {
2376       Context context = SetupTemplatesContext(prop._class);
2377       prop.dataType = ProcessTypeString(prop.dataTypeString, false);
2378       FinishTemplatesContext(context);
2379    }
2380 }
2381
2382 public void DeclareMethod(Method method, char * name)
2383 {
2384    Symbol symbol = method.symbol;
2385    if(!symbol || (!symbol.pointerExternal && method.type == virtualMethod) || symbol.id > (curExternal ? curExternal.symbol.idCode : -1))
2386    {
2387       bool imported = false;
2388       bool dllImport = false;
2389
2390       if(!method.dataType)
2391          method.dataType = ProcessTypeString(method.dataTypeString, false);
2392
2393       if(!symbol || symbol._import || method.type == virtualMethod)
2394       {
2395          if(!symbol || method.type == virtualMethod)
2396          {
2397             Symbol classSym;
2398             if(!method._class.symbol)
2399                method._class.symbol = FindClass(method._class.fullName);
2400             classSym = method._class.symbol;
2401             if(!classSym._import)
2402             {
2403                ModuleImport module;
2404
2405                if(method._class.module && method._class.module.name)
2406                   module = FindModule(method._class.module);
2407                else
2408                   module = mainModule;
2409                classSym._import = ClassImport
2410                {
2411                   name = CopyString(method._class.fullName);
2412                   isRemote = method._class.isRemote;
2413                };
2414                module.classes.Add(classSym._import);
2415             }
2416             if(!symbol)
2417             {
2418                symbol = method.symbol = Symbol { };
2419             }
2420             if(!symbol._import)
2421             {
2422                symbol._import = (ClassImport)MethodImport
2423                {
2424                   name = CopyString(method.name);
2425                   isVirtual = method.type == virtualMethod;
2426                };
2427                classSym._import.methods.Add(symbol._import);
2428             }
2429             if(!symbol)
2430             {
2431                // Set the symbol type
2432                /*
2433                if(!type.thisClass)
2434                {
2435                   type.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2436                }
2437                else if(type.thisClass == (void *)-1)
2438                {
2439                   type.thisClass = null;
2440                }
2441                */
2442                // symbol.type = ProcessTypeString(method.dataTypeString, false);
2443                symbol.type = method.dataType;
2444                if(symbol.type) symbol.type.refCount++;
2445             }
2446             /*
2447             if(!method.thisClass || strcmp(method.thisClass, "void"))
2448                symbol.type.params.Insert(null,
2449                   MkClassType(method.thisClass ? method.thisClass : method._class.fullName));
2450             */
2451          }
2452          if(!method.dataType.dllExport)
2453          {
2454             imported = true;
2455             if((method._class.module != privateModule || !strcmp(method._class.name, "float") || !strcmp(method._class.name, "double")) && method._class.module.importType != staticImport)
2456                dllImport = true;
2457          }
2458       }
2459
2460       /* MOVING THIS UP
2461       if(!method.dataType)
2462          method.dataType = ((Symbol)method.symbol).type;
2463          //ProcessMethodType(method);
2464       */
2465
2466       if(method.type != virtualMethod && method.dataType)
2467          DeclareType(method.dataType, true, true);
2468
2469       if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2470       {
2471          // We need a declaration here :)
2472          Declaration decl;
2473          OldList * specifiers, * declarators;
2474          Declarator d;
2475          Declarator funcDecl;
2476          External external;
2477
2478          specifiers = MkList();
2479          declarators = MkList();
2480
2481          //if(imported)
2482          if(dllImport)
2483             ListAdd(specifiers, MkSpecifier(EXTERN));
2484          else if(method._class.symbol && ((Symbol)method._class.symbol).isStatic)
2485             ListAdd(specifiers, MkSpecifier(STATIC));
2486
2487          if(method.type == virtualMethod)
2488          {
2489             ListAdd(specifiers, MkSpecifier(INT));
2490             d = MkDeclaratorIdentifier(MkIdentifier(name));
2491          }
2492          else
2493          {
2494             d = MkDeclaratorIdentifier(MkIdentifier(name));
2495             //if(imported)
2496             if(dllImport)
2497                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2498             {
2499                Context context = SetupTemplatesContext(method._class);
2500                d = SpecDeclFromString(method.dataTypeString, specifiers, d);
2501                FinishTemplatesContext(context);
2502             }
2503             funcDecl = GetFuncDecl(d);
2504
2505             if(dllImport)
2506             {
2507                Specifier spec, next;
2508                for(spec = specifiers->first; spec; spec = next)
2509                {
2510                   next = spec.next;
2511                   if(spec.type == extendedSpecifier)
2512                   {
2513                      specifiers->Remove(spec);
2514                      FreeSpecifier(spec);
2515                   }
2516                }
2517             }
2518
2519             // Add this parameter if not a static method
2520             if(method.dataType && !method.dataType.staticMethod)
2521             {
2522                if(funcDecl && funcDecl.function.parameters && funcDecl.function.parameters->count)
2523                {
2524                   Class _class = method.dataType.thisClass ? method.dataType.thisClass.registered : method._class;
2525                   TypeName thisParam = MkTypeName(MkListOne(
2526                      MkSpecifierName/*MkClassName*/(method.dataType.thisClass ? method.dataType.thisClass.string : method._class.fullName)),
2527                      (_class && _class.type == systemClass) ? MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("this"))) : MkDeclaratorIdentifier(MkIdentifier("this")));
2528                   TypeName firstParam = ((TypeName)funcDecl.function.parameters->first);
2529                   Specifier firstSpec = firstParam.qualifiers ? firstParam.qualifiers->first : null;
2530
2531                   if(firstSpec && firstSpec.type == baseSpecifier && firstSpec.specifier == VOID && !firstParam.declarator)
2532                   {
2533                      TypeName param = funcDecl.function.parameters->first;
2534                      funcDecl.function.parameters->Remove(param);
2535                      FreeTypeName(param);
2536                   }
2537
2538                   if(!funcDecl.function.parameters)
2539                      funcDecl.function.parameters = MkList();
2540                   funcDecl.function.parameters->Insert(null, thisParam);
2541                }
2542             }
2543             // Make sure we don't have empty parameter declarations for static methods...
2544             /*
2545             else if(!funcDecl.function.parameters)
2546             {
2547                funcDecl.function.parameters = MkList();
2548                funcDecl.function.parameters->Insert(null,
2549                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2550             }*/
2551          }
2552          // TESTING THIS:
2553          ProcessDeclarator(d);
2554
2555          ListAdd(declarators, MkInitDeclarator(d, null));
2556
2557          decl = MkDeclaration(specifiers, declarators);
2558
2559          ReplaceThisClassSpecifiers(specifiers, method._class);
2560
2561          // Keep a different symbol for the function definition than the declaration...
2562          if(symbol.pointerExternal)
2563          {
2564             Symbol functionSymbol { };
2565
2566             // Copy symbol
2567             {
2568                *functionSymbol = *symbol;
2569                functionSymbol.string = CopyString(symbol.string);
2570                if(functionSymbol.type)
2571                   functionSymbol.type.refCount++;
2572             }
2573
2574             excludedSymbols->Add(functionSymbol);
2575             symbol.pointerExternal.symbol = functionSymbol;
2576          }
2577          external = MkExternalDeclaration(decl);
2578          if(curExternal)
2579             ast->Insert(curExternal ? curExternal.prev : null, external);
2580          external.symbol = symbol;
2581          symbol.pointerExternal = external;
2582       }
2583       else if(ast)
2584       {
2585          // Move declaration higher...
2586          ast->Move(symbol.pointerExternal, curExternal.prev);
2587       }
2588
2589       symbol.id = curExternal ? curExternal.symbol.idCode : MAXINT;
2590    }
2591 }
2592
2593 char * ReplaceThisClass(Class _class)
2594 {
2595    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2596    {
2597       bool first = true;
2598       int p = 0;
2599       ClassTemplateParameter param;
2600       int lastParam = -1;
2601
2602       char className[1024];
2603       strcpy(className, _class.fullName);
2604       for(param = _class.templateParams.first; param; param = param.next)
2605       {
2606          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2607          {
2608             if(first) strcat(className, "<");
2609             if(!first) strcat(className, ", ");
2610             if(lastParam + 1 != p)
2611             {
2612                strcat(className, param.name);
2613                strcat(className, " = ");
2614             }
2615             strcat(className, param.name);
2616             first = false;
2617             lastParam = p;
2618          }
2619          p++;
2620       }
2621       if(!first)
2622       {
2623          int len = strlen(className);
2624          if(className[len-1] == '>') className[len++] = ' ';
2625          className[len++] = '>';
2626          className[len++] = '\0';
2627       }
2628       return CopyString(className);
2629    }
2630    else
2631       return CopyString(_class.fullName);
2632 }
2633
2634 Type ReplaceThisClassType(Class _class)
2635 {
2636    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2637    {
2638       bool first = true;
2639       int p = 0;
2640       ClassTemplateParameter param;
2641       int lastParam = -1;
2642       char className[1024];
2643       strcpy(className, _class.fullName);
2644
2645       for(param = _class.templateParams.first; param; param = param.next)
2646       {
2647          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2648          {
2649             if(first) strcat(className, "<");
2650             if(!first) strcat(className, ", ");
2651             if(lastParam + 1 != p)
2652             {
2653                strcat(className, param.name);
2654                strcat(className, " = ");
2655             }
2656             strcat(className, param.name);
2657             first = false;
2658             lastParam = p;
2659          }
2660          p++;
2661       }
2662       if(!first)
2663       {
2664          int len = strlen(className);
2665          if(className[len-1] == '>') className[len++] = ' ';
2666          className[len++] = '>';
2667          className[len++] = '\0';
2668       }
2669       return MkClassType(className);
2670       //return ProcessTypeString(className, false);
2671    }
2672    else
2673    {
2674       return MkClassType(_class.fullName);
2675       //return ProcessTypeString(_class.fullName, false);
2676    }
2677 }
2678
2679 void ReplaceThisClassSpecifiers(OldList specs, Class _class)
2680 {
2681    if(specs != null && _class)
2682    {
2683       Specifier spec;
2684       for(spec = specs.first; spec; spec = spec.next)
2685       {
2686          if(spec.type == baseSpecifier && spec.specifier == THISCLASS)
2687          {
2688             spec.type = nameSpecifier;
2689             spec.name = ReplaceThisClass(_class);
2690             spec.symbol = FindClass(spec.name); //_class.symbol;
2691          }
2692       }
2693    }
2694 }
2695
2696 // Returns imported or not
2697 bool DeclareFunction(GlobalFunction function, char * name)
2698 {
2699    Symbol symbol = function.symbol;
2700    if(curExternal && (!symbol || symbol.id > curExternal.symbol.idCode))
2701    {
2702       bool imported = false;
2703       bool dllImport = false;
2704
2705       if(!function.dataType)
2706       {
2707          function.dataType = ProcessTypeString(function.dataTypeString, false);
2708          if(!function.dataType.thisClass)
2709             function.dataType.staticMethod = true;
2710       }
2711
2712       if(inCompiler)
2713       {
2714          if(!symbol)
2715          {
2716             ModuleImport module = FindModule(function.module);
2717             // WARNING: This is not added anywhere...
2718             symbol = function.symbol = Symbol {  };
2719
2720             if(module.name)
2721             {
2722                if(!function.dataType.dllExport)
2723                {
2724                   symbol._import = (ClassImport)FunctionImport { name = CopyString(function.name) };
2725                   module.functions.Add(symbol._import);
2726                }
2727             }
2728             // Set the symbol type
2729             {
2730                symbol.type = ProcessTypeString(function.dataTypeString, false);
2731                if(!symbol.type.thisClass)
2732                   symbol.type.staticMethod = true;
2733             }
2734          }
2735          imported = symbol._import ? true : false;
2736          if(imported && function.module != privateModule && function.module.importType != staticImport)
2737             dllImport = true;
2738       }
2739
2740       DeclareType(function.dataType, true, true);
2741
2742       if(inCompiler)
2743       {
2744          if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2745          {
2746             // We need a declaration here :)
2747             Declaration decl;
2748             OldList * specifiers, * declarators;
2749             Declarator d;
2750             Declarator funcDecl;
2751             External external;
2752
2753             specifiers = MkList();
2754             declarators = MkList();
2755
2756             //if(imported)
2757                ListAdd(specifiers, MkSpecifier(EXTERN));
2758             /*
2759             else
2760                ListAdd(specifiers, MkSpecifier(STATIC));
2761             */
2762
2763             d = MkDeclaratorIdentifier(MkIdentifier(imported ? name : function.name));
2764             //if(imported)
2765             if(dllImport)
2766                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2767
2768             d = SpecDeclFromString(function.dataTypeString, specifiers, d);
2769             // TAKE OUT THE DLL EXPORT IF STATICALLY IMPORTED:
2770             if(function.module.importType == staticImport)
2771             {
2772                Specifier spec;
2773                for(spec = specifiers->first; spec; spec = spec.next)
2774                   if(spec.type == extendedSpecifier && spec.extDecl && spec.extDecl.type == extDeclString && !strcmp(spec.extDecl.s, "dllexport"))
2775                   {
2776                      specifiers->Remove(spec);
2777                      FreeSpecifier(spec);
2778                      break;
2779                   }
2780             }
2781
2782             funcDecl = GetFuncDecl(d);
2783
2784             // Make sure we don't have empty parameter declarations for static methods...
2785             if(funcDecl && !funcDecl.function.parameters)
2786             {
2787                funcDecl.function.parameters = MkList();
2788                funcDecl.function.parameters->Insert(null,
2789                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2790             }
2791
2792             ListAdd(declarators, MkInitDeclarator(d, null));
2793
2794             {
2795                Context oldCtx = curContext;
2796                curContext = globalContext;
2797                decl = MkDeclaration(specifiers, declarators);
2798                curContext = oldCtx;
2799             }
2800
2801             // Keep a different symbol for the function definition than the declaration...
2802             if(symbol.pointerExternal)
2803             {
2804                Symbol functionSymbol { };
2805                // Copy symbol
2806                {
2807                   *functionSymbol = *symbol;
2808                   functionSymbol.string = CopyString(symbol.string);
2809                   if(functionSymbol.type)
2810                      functionSymbol.type.refCount++;
2811                }
2812
2813                excludedSymbols->Add(functionSymbol);
2814
2815                symbol.pointerExternal.symbol = functionSymbol;
2816             }
2817             external = MkExternalDeclaration(decl);
2818             if(curExternal)
2819                ast->Insert(curExternal.prev, external);
2820             external.symbol = symbol;
2821             symbol.pointerExternal = external;
2822          }
2823          else
2824          {
2825             // Move declaration higher...
2826             ast->Move(symbol.pointerExternal, curExternal.prev);
2827          }
2828
2829          if(curExternal)
2830             symbol.id = curExternal.symbol.idCode;
2831       }
2832    }
2833    return (symbol && symbol._import && function.module != privateModule && function.module.importType != staticImport) ? true : false;
2834 }
2835
2836 void DeclareGlobalData(GlobalData data)
2837 {
2838    Symbol symbol = data.symbol;
2839    if(curExternal && (!symbol || symbol.id > curExternal.symbol.idCode))
2840    {
2841       if(inCompiler)
2842       {
2843          if(!symbol)
2844             symbol = data.symbol = Symbol { };
2845       }
2846       if(!data.dataType)
2847          data.dataType = ProcessTypeString(data.dataTypeString, false);
2848       DeclareType(data.dataType, true, true);
2849       if(inCompiler)
2850       {
2851          if(!symbol.pointerExternal)
2852          {
2853             // We need a declaration here :)
2854             Declaration decl;
2855             OldList * specifiers, * declarators;
2856             Declarator d;
2857             External external;
2858
2859             specifiers = MkList();
2860             declarators = MkList();
2861
2862             ListAdd(specifiers, MkSpecifier(EXTERN));
2863             d = MkDeclaratorIdentifier(MkIdentifier(data.fullName));
2864             d = SpecDeclFromString(data.dataTypeString, specifiers, d);
2865
2866             ListAdd(declarators, MkInitDeclarator(d, null));
2867
2868             decl = MkDeclaration(specifiers, declarators);
2869             external = MkExternalDeclaration(decl);
2870             if(curExternal)
2871                ast->Insert(curExternal.prev, external);
2872             external.symbol = symbol;
2873             symbol.pointerExternal = external;
2874          }
2875          else
2876          {
2877             // Move declaration higher...
2878             ast->Move(symbol.pointerExternal, curExternal.prev);
2879          }
2880
2881          if(curExternal)
2882             symbol.id = curExternal.symbol.idCode;
2883       }
2884    }
2885 }
2886
2887 class Conversion : struct
2888 {
2889    Conversion prev, next;
2890    Property convert;
2891    bool isGet;
2892    Type resultType;
2893 };
2894
2895 public bool MatchTypes(Type source, Type dest, OldList conversions, Class owningClassSource, Class owningClassDest, bool doConversion, bool enumBaseType, bool acceptReversedParams, bool isConversionExploration)
2896 {
2897    if(source && dest)
2898    {
2899       // Property convert;
2900
2901       if(source.kind == templateType && dest.kind != templateType)
2902       {
2903          Type type = ProcessTemplateParameterType(source.templateParameter);
2904          if(type) source = type;
2905       }
2906
2907       if(dest.kind == templateType && source.kind != templateType)
2908       {
2909          Type type = ProcessTemplateParameterType(dest.templateParameter);
2910          if(type) dest = type;
2911       }
2912
2913       if(dest.classObjectType == typedObject)
2914       {
2915          if(source.classObjectType != anyObject)
2916             return true;
2917          else
2918          {
2919             // If either the source or the destination defines the class, accepts any_object as compatible for a typed_object
2920             if((dest._class && strcmp(dest._class.string, "class")) || (source._class && strcmp(source._class.string, "class")))
2921             {
2922                return true;
2923             }
2924          }
2925       }
2926       else
2927       {
2928          if(source.classObjectType == anyObject)
2929             return true;
2930          if(dest.classObjectType == anyObject && source.classObjectType != typedObject)
2931             return true;
2932       }
2933
2934       if((dest.kind == structType && source.kind == structType) ||
2935          (dest.kind == unionType && source.kind == unionType))
2936       {
2937          if((dest.enumName && source.enumName && !strcmp(dest.enumName, source.enumName)) ||
2938              (source.members.first && source.members.first == dest.members.first))
2939             return true;
2940       }
2941
2942       if(dest.kind == ellipsisType && source.kind != voidType)
2943          return true;
2944
2945       if(dest.kind == pointerType && dest.type.kind == voidType &&
2946          ((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))
2947          || source.kind == subClassType || source.kind == pointerType || source.kind == arrayType || source.kind == functionType || source.kind == thisClassType)
2948
2949          /*source.kind != voidType && source.kind != structType && source.kind != unionType  */
2950
2951          /*&& (source.kind != classType /-*|| source._class.registered.type != structClass)*/)
2952          return true;
2953       if(!isConversionExploration && source.kind == pointerType && source.type.kind == voidType &&
2954          ((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))
2955          || dest.kind == subClassType || dest.kind == pointerType || dest.kind == arrayType || dest.kind == functionType || dest.kind == thisClassType)
2956
2957          /* dest.kind != voidType && dest.kind != structType && dest.kind != unionType  */
2958
2959          /*&& (dest.kind != classType || dest._class.registered.type != structClass)*/)
2960          return true;
2961
2962       if(((source.kind == classType && dest.kind == classType) || (source.kind == subClassType && dest.kind == subClassType)) && source._class)
2963       {
2964          if(source._class.registered && source._class.registered.type == unitClass)
2965          {
2966             if(conversions != null)
2967             {
2968                if(source._class.registered == dest._class.registered)
2969                   return true;
2970             }
2971             else
2972             {
2973                Class sourceBase, destBase;
2974                for(sourceBase = source._class.registered; sourceBase && sourceBase.base.type != systemClass; sourceBase = sourceBase.base);
2975                for(destBase = dest._class.registered; destBase && destBase.base.type != systemClass; destBase = destBase.base);
2976                if(sourceBase == destBase)
2977                   return true;
2978             }
2979          }
2980          // Don't match enum inheriting from other enum if resolving enumeration values
2981          // TESTING: !dest.classObjectType
2982          else if(source._class && dest._class && (dest.classObjectType == source.classObjectType || !dest.classObjectType) &&
2983             (enumBaseType ||
2984                (!source._class.registered || source._class.registered.type != enumClass) ||
2985                (!dest._class.registered || dest._class.registered.type != enumClass)) && eClass_IsDerived(source._class.registered, dest._class.registered))
2986             return true;
2987          else
2988          {
2989             // Added this so that DefinedColor = Color doesn't go through ColorRGB property
2990             if(enumBaseType &&
2991                dest._class && dest._class.registered && dest._class.registered.type == enumClass &&
2992                ((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)
2993             {
2994                if(eClass_IsDerived(dest._class.registered, source._class.registered))
2995                {
2996                   return true;
2997                }
2998             }
2999          }
3000       }
3001
3002       // JUST ADDED THIS...
3003       if(source.kind == subClassType && dest.kind == classType && dest._class && !strcmp(dest._class.string, "ecere::com::Class"))
3004          return true;
3005
3006       if(doConversion)
3007       {
3008          // Just added this for Straight conversion of ColorAlpha => Color
3009          if(source.kind == classType)
3010          {
3011             Class _class;
3012             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3013             {
3014                Property convert;
3015                for(convert = _class.conversions.first; convert; convert = convert.next)
3016                {
3017                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3018                   {
3019                      Conversion after = (conversions != null) ? conversions.last : null;
3020
3021                      if(!convert.dataType)
3022                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3023                      if(MatchTypes(convert.dataType, dest, conversions, null, null, false, true, false, true))
3024                      {
3025                         if(!conversions && !convert.Get)
3026                            return true;
3027                         else if(conversions != null)
3028                         {
3029                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3030                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3031                               (dest.kind != classType || dest._class.registered != _class.base))
3032                               return true;
3033                            else
3034                            {
3035                               Conversion conv { convert = convert, isGet = true };
3036                               // conversions.Add(conv);
3037                               conversions.Insert(after, conv);
3038                               return true;
3039                            }
3040                         }
3041                      }
3042                   }
3043                }
3044             }
3045          }
3046
3047          // MOVING THIS??
3048
3049          if(dest.kind == classType)
3050          {
3051             Class _class;
3052             for(_class = dest._class ? dest._class.registered : null; _class; _class = _class.base)
3053             {
3054                Property convert;
3055                for(convert = _class.conversions.first; convert; convert = convert.next)
3056                {
3057                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3058                   {
3059                      // Conversion after = (conversions != null) ? conversions.last : null;
3060
3061                      if(!convert.dataType)
3062                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3063                      // Just added this equality check to prevent recursion.... Make it safer?
3064                      // Changed enumBaseType to false here to prevent all int-compatible enums to show up in AnchorValues
3065                      if(convert.dataType != dest && MatchTypes(source, convert.dataType, conversions, null, null, true, false /*true*/, false, true))
3066                      {
3067                         if(!conversions && !convert.Set)
3068                            return true;
3069                         else if(conversions != null)
3070                         {
3071                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3072                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3073                               (source.kind != classType || source._class.registered != _class.base))
3074                               return true;
3075                            else
3076                            {
3077                               // *** Testing this! ***
3078                               Conversion conv { convert = convert };
3079                               conversions.Add(conv);
3080                               //conversions.Insert(after, conv);
3081                               return true;
3082                            }
3083                         }
3084                      }
3085                   }
3086                }
3087             }
3088             /*if(dest._class.registered && !strcmp(dest._class.registered.name, "bool"))
3089             {
3090                if(source.kind != voidType && source.kind != structType && source.kind != unionType &&
3091                   (source.kind != classType || source._class.registered.type != structClass))
3092                   return true;
3093             }*/
3094
3095             // TESTING THIS... IS THIS OK??
3096             if(enumBaseType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3097             {
3098                if(!dest._class.registered.dataType)
3099                   dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3100                // Only support this for classes...
3101                if(dest._class.registered.dataType.kind == classType || source.truth || dest.truth/* ||
3102                   !strcmp(dest._class.registered.name, "bool") || (source.kind == classType && !strcmp(source._class.string, "bool"))*/)
3103                {
3104                   if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false))
3105                   {
3106                      return true;
3107                   }
3108                }
3109             }
3110          }
3111
3112          // Moved this lower
3113          if(source.kind == classType)
3114          {
3115             Class _class;
3116             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3117             {
3118                Property convert;
3119                for(convert = _class.conversions.first; convert; convert = convert.next)
3120                {
3121                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3122                   {
3123                      Conversion after = (conversions != null) ? conversions.last : null;
3124
3125                      if(!convert.dataType)
3126                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3127                      if(convert.dataType != source && MatchTypes(convert.dataType, dest, conversions, null, null, true, true, false, true))
3128                      {
3129                         if(!conversions && !convert.Get)
3130                            return true;
3131                         else if(conversions != null)
3132                         {
3133                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3134                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3135                               (dest.kind != classType || dest._class.registered != _class.base))
3136                               return true;
3137                            else
3138                            {
3139                               Conversion conv { convert = convert, isGet = true };
3140
3141                               // conversions.Add(conv);
3142                               conversions.Insert(after, conv);
3143                               return true;
3144                            }
3145                         }
3146                      }
3147                   }
3148                }
3149             }
3150
3151             // TESTING THIS... IS THIS OK??
3152             if(enumBaseType && source._class && source._class.registered && source._class.registered.type == enumClass)
3153             {
3154                if(!source._class.registered.dataType)
3155                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3156                if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, true, false, false))
3157                {
3158                   return true;
3159                }
3160             }
3161          }
3162       }
3163
3164       if(source.kind == classType || source.kind == subClassType)
3165          ;
3166       else if(dest.kind == source.kind &&
3167          (dest.kind != structType && dest.kind != unionType &&
3168           dest.kind != functionType && dest.kind != arrayType && dest.kind != pointerType && dest.kind != methodType))
3169           return true;
3170       // RECENTLY ADDED THESE
3171       else if(dest.kind == doubleType && source.kind == floatType)
3172          return true;
3173       else if(dest.kind == shortType && (source.kind == charType || source.kind == _BoolType))
3174          return true;
3175       else if(dest.kind == intType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intSizeType /* Exception here for size_t */))
3176          return true;
3177       else if(dest.kind == int64Type && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intPtrType || source.kind == intSizeType))
3178          return true;
3179       else if(dest.kind == intPtrType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intSizeType || source.kind == int64Type))
3180          return true;
3181       else if(dest.kind == intSizeType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == int64Type || source.kind == intPtrType))
3182          return true;
3183       else if(source.kind == enumType &&
3184          (dest.kind == intType || dest.kind == shortType || dest.kind == charType || source.kind == _BoolType || dest.kind == longType || dest.kind == int64Type || dest.kind == intPtrType || dest.kind == intSizeType))
3185           return true;
3186       else if(dest.kind == enumType &&
3187          (source.kind == intType || source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == longType || source.kind == int64Type || source.kind == intPtrType || source.kind == intSizeType))
3188           return true;
3189       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) &&
3190               ((source.kind == functionType || (source.kind == pointerType && source.type.kind == functionType) || source.kind == methodType)))
3191       {
3192          Type paramSource, paramDest;
3193
3194          if(dest.kind == methodType)
3195             owningClassDest = dest.methodClass ? dest.methodClass : dest.method._class;
3196          if(source.kind == methodType)
3197             owningClassSource = source.methodClass ? source.methodClass : source.method._class;
3198
3199          if(dest.kind == pointerType && dest.type.kind == functionType) dest = dest.type;
3200          if(source.kind == pointerType && source.type.kind == functionType) source = source.type;
3201          if(dest.kind == methodType)
3202             dest = dest.method.dataType;
3203          if(source.kind == methodType)
3204             source = source.method.dataType;
3205
3206          paramSource = source.params.first;
3207          if(paramSource && paramSource.kind == voidType) paramSource = null;
3208          paramDest = dest.params.first;
3209          if(paramDest && paramDest.kind == voidType) paramDest = null;
3210
3211
3212          if((dest.staticMethod || (!dest.thisClass && !owningClassDest)) &&
3213             !(source.staticMethod || (!source.thisClass && !owningClassSource)))
3214          {
3215             // Source thisClass must be derived from destination thisClass
3216             if(!paramDest || (!(paramDest.kind == pointerType && paramDest.type && paramDest.type.kind == voidType) && (paramDest.kind != classType ||
3217                !eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource,paramDest._class.registered))))
3218             {
3219                if(paramDest && paramDest.kind == classType)
3220                   Compiler_Error($"method class must be derived from %s\n", paramDest._class.string);
3221                else
3222                   Compiler_Error($"method class should not take an object\n");
3223                return false;
3224             }
3225             paramDest = paramDest.next;
3226          }
3227          else if(!dest.staticMethod && (dest.thisClass || owningClassDest))
3228          {
3229             if((source.staticMethod || (!source.thisClass && !owningClassSource)))
3230             {
3231                if(dest.thisClass)
3232                {
3233                   if(!paramSource || paramSource.kind != classType || !eClass_IsDerived(paramSource._class.registered,dest.thisClass.registered))
3234                   {
3235                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3236                      return false;
3237                   }
3238                }
3239                else
3240                {
3241                   // THIS WAS BACKWARDS:
3242                   // if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(owningClassDest, paramSource._class.registered)))
3243                   if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(paramSource._class.registered, owningClassDest)))
3244                   {
3245                      if(owningClassDest)
3246                        Compiler_Error($"%s expected to be derived from method class\n", owningClassDest.fullName);
3247                      else
3248                         Compiler_Error($"overriding class expected to be derived from method class\n");
3249                      return false;
3250                   }
3251                }
3252                paramSource = paramSource.next;
3253             }
3254             else
3255             {
3256                if(dest.thisClass)
3257                {
3258                   // Source thisClass must be derived from destination thisClass
3259                   if(!eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource, dest.thisClass.registered))
3260                   {
3261                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3262                      return false;
3263                   }
3264                }
3265                else
3266                {
3267                   // THIS WAS BACKWARDS TOO??
3268                   // if(source.thisClass && owningClassDest && !eClass_IsDerived(owningClassDest, source.thisClass.registered))
3269                   if(source.thisClass && source.thisClass.registered && owningClassDest && !eClass_IsDerived(source.thisClass.registered, owningClassDest))
3270                   {
3271                      //if(owningClass)
3272                         Compiler_Error($"%s expected to be derived from method class\n", /*owningClass.name*/ source.thisClass.registered.fullName);
3273                      //else
3274                         //Compiler_Error($"overriding class expected to be derived from method class\n");
3275                      return false;
3276                   }
3277                }
3278             }
3279          }
3280
3281
3282          // Source return type must be derived from destination return type
3283          if(!MatchTypes(source.returnType, dest.returnType, null, null, null, true, true, false, false))
3284          {
3285             Compiler_Warning($"incompatible return type for function\n");
3286             return false;
3287          }
3288
3289          // Check parameters
3290
3291          for(; paramDest; paramDest = paramDest.next)
3292          {
3293             if(!paramSource)
3294             {
3295                //Compiler_Warning($"not enough parameters\n");
3296                Compiler_Error($"not enough parameters\n");
3297                return false;
3298             }
3299             {
3300                Type paramDestType = paramDest;
3301                Type paramSourceType = paramSource;
3302                Type type = paramDestType;
3303
3304                // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
3305                if(paramDest.kind == templateType && paramDest.templateParameter.type == TemplateParameterType::type && owningClassSource &&
3306                   paramSource.kind != templateType)
3307                {
3308                   int id = 0;
3309                   ClassTemplateParameter curParam = null;
3310                   Class sClass;
3311                   for(sClass = owningClassSource; sClass; sClass = sClass.base)
3312                   {
3313                      id = 0;
3314                      if(sClass.templateClass) sClass = sClass.templateClass;
3315                      for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
3316                      {
3317                         if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
3318                         {
3319                            for(sClass = sClass.base; sClass; sClass = sClass.base)
3320                            {
3321                               if(sClass.templateClass) sClass = sClass.templateClass;
3322                               id += sClass.templateParams.count;
3323                            }
3324                            break;
3325                         }
3326                         id++;
3327                      }
3328                      if(curParam) break;
3329                   }
3330
3331                   if(curParam)
3332                   {
3333                      ClassTemplateArgument arg = owningClassSource.templateArgs[id];
3334                      paramDestType = type = ProcessTypeString(arg.dataTypeString, false);
3335                   }
3336                }
3337
3338                // paramDest must be derived from paramSource
3339                if(!MatchTypes(paramDestType, paramSourceType, null, null, null, true, true, false, false) &&
3340                   (!acceptReversedParams || !MatchTypes(paramSourceType, paramDestType, null, null, null, true, true, false, false)))
3341                {
3342                   char type[1024];
3343                   type[0] = 0;
3344                   PrintType(paramDest, type, false, true);
3345                   Compiler_Warning($"incompatible parameter %s (expected %s)\n", paramSource.name, type);
3346
3347                   if(paramDestType != paramDest)
3348                      FreeType(paramDestType);
3349                   return false;
3350                }
3351                if(paramDestType != paramDest)
3352                   FreeType(paramDestType);
3353             }
3354
3355             paramSource = paramSource.next;
3356          }
3357          if(paramSource)
3358          {
3359             Compiler_Error($"too many parameters\n");
3360             return false;
3361          }
3362          return true;
3363       }
3364       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) && (source.kind == pointerType && source.type.kind == voidType))
3365       {
3366          return true;
3367       }
3368       else if((dest.kind == pointerType || dest.kind == arrayType) &&
3369          (source.kind == arrayType || source.kind == pointerType))
3370       {
3371          if(MatchTypes(source.type, dest.type, null, null, null, true, true, false, false))
3372             return true;
3373       }
3374    }
3375    return false;
3376 }
3377
3378 static void FreeConvert(Conversion convert)
3379 {
3380    if(convert.resultType)
3381       FreeType(convert.resultType);
3382 }
3383
3384 bool MatchWithEnums_NameSpace(NameSpace nameSpace, Expression sourceExp, Type dest,
3385                               char * string, OldList conversions)
3386 {
3387    BTNamedLink link;
3388
3389    for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
3390    {
3391       Class _class = link.data;
3392       if(_class.type == enumClass)
3393       {
3394          OldList converts { };
3395          Type type { };
3396          type.kind = classType;
3397
3398          if(!_class.symbol)
3399             _class.symbol = FindClass(_class.fullName);
3400          type._class = _class.symbol;
3401
3402          if(MatchTypes(type, dest, &converts, null, null, true, false, false, false))
3403          {
3404             NamedLink value;
3405             Class enumClass = eSystem_FindClass(privateModule, "enum");
3406             if(enumClass)
3407             {
3408                Class baseClass;
3409                for(baseClass = _class ; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
3410                {
3411                   EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
3412                   for(value = e.values.first; value; value = value.next)
3413                   {
3414                      if(!strcmp(value.name, string))
3415                         break;
3416                   }
3417                   if(value)
3418                   {
3419                      FreeExpContents(sourceExp);
3420                      FreeType(sourceExp.expType);
3421
3422                      sourceExp.isConstant = true;
3423                      sourceExp.expType = MkClassType(baseClass.fullName);
3424                      //if(inCompiler)
3425                      {
3426                         char constant[256];
3427                         sourceExp.type = constantExp;
3428                         if(!strcmp(baseClass.dataTypeString, "int"))
3429                            sprintf(constant, "%d",(int)value.data);
3430                         else
3431                            sprintf(constant, "0x%X",(int)value.data);
3432                         sourceExp.constant = CopyString(constant);
3433                         //for(;baseClass.base && baseClass.base.type != systemClass; baseClass = baseClass.base);
3434                      }
3435
3436                      while(converts.first)
3437                      {
3438                         Conversion convert = converts.first;
3439                         converts.Remove(convert);
3440                         conversions.Add(convert);
3441                      }
3442                      delete type;
3443                      return true;
3444                   }
3445                }
3446             }
3447          }
3448          if(converts.first)
3449             converts.Free(FreeConvert);
3450          delete type;
3451       }
3452    }
3453    for(nameSpace = (NameSpace *)nameSpace.nameSpaces.first; nameSpace != null; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
3454       if(MatchWithEnums_NameSpace(nameSpace, sourceExp, dest, string, conversions))
3455          return true;
3456    return false;
3457 }
3458
3459 public bool ModuleVisibility(Module searchIn, Module searchFor)
3460 {
3461    SubModule subModule;
3462
3463    if(searchFor == searchIn)
3464       return true;
3465
3466    for(subModule = searchIn.modules.first; subModule; subModule = subModule.next)
3467    {
3468       if(subModule.importMode == publicAccess || searchIn == searchIn.application)
3469       {
3470          if(ModuleVisibility(subModule.module, searchFor))
3471             return true;
3472       }
3473    }
3474    return false;
3475 }
3476
3477 bool MatchWithEnums_Module(Module mainModule, Expression sourceExp, Type dest, char * string, OldList conversions)
3478 {
3479    Module module;
3480
3481    if(MatchWithEnums_NameSpace(mainModule.application.systemNameSpace, sourceExp, dest, string, conversions))
3482       return true;
3483    if(MatchWithEnums_NameSpace(mainModule.application.privateNameSpace, sourceExp, dest, string, conversions))
3484       return true;
3485    if(MatchWithEnums_NameSpace(mainModule.application.publicNameSpace, sourceExp, dest, string, conversions))
3486       return true;
3487
3488    for(module = mainModule.application.allModules.first; module; module = module.next)
3489    {
3490       if(ModuleVisibility(mainModule, module) && MatchWithEnums_NameSpace(module.publicNameSpace, sourceExp, dest, string, conversions))
3491          return true;
3492    }
3493    return false;
3494 }
3495
3496 bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, bool skipUnitBla)
3497 {
3498    Type source = sourceExp.expType;
3499    Type realDest = dest;
3500    Type backupSourceExpType = null;
3501
3502    if(dest.kind == pointerType && sourceExp.type == constantExp && !strtoul(sourceExp.constant, null, 0))
3503       return true;
3504
3505    if(!skipUnitBla && source && dest && source.kind == classType && dest.kind == classType)
3506    {
3507        if(source._class && source._class.registered && source._class.registered.type == unitClass)
3508        {
3509           Class sourceBase, destBase;
3510           for(sourceBase = source._class.registered;
3511               sourceBase && sourceBase.base && sourceBase.base.type != systemClass;
3512               sourceBase = sourceBase.base);
3513           for(destBase = dest._class.registered;
3514               destBase && destBase.base && destBase.base.type != systemClass;
3515               destBase = destBase.base);
3516           //if(source._class.registered == dest._class.registered)
3517           if(sourceBase == destBase)
3518              return true;
3519        }
3520    }
3521
3522    if(source)
3523    {
3524       OldList * specs;
3525       bool flag = false;
3526       int64 value = MAXINT;
3527
3528       source.refCount++;
3529       dest.refCount++;
3530
3531       if(sourceExp.type == constantExp)
3532       {
3533          if(source.isSigned)
3534             value = strtoll(sourceExp.constant, null, 0);
3535          else
3536             value = strtoull(sourceExp.constant, null, 0);
3537       }
3538       else if(sourceExp.type == opExp && sourceExp.op.op == '-' && !sourceExp.op.exp1 && sourceExp.op.exp2 && sourceExp.op.exp2.type == constantExp)
3539       {
3540          if(source.isSigned)
3541             value = -strtoll(sourceExp.op.exp2.constant, null, 0);
3542          else
3543             value = -strtoull(sourceExp.op.exp2.constant, null, 0);
3544       }
3545
3546       if(dest.kind != classType && source.kind == classType && source._class && source._class.registered &&
3547          !strcmp(source._class.registered.fullName, "ecere::com::unichar"))
3548       {
3549          FreeType(source);
3550          source = Type { kind = intType, isSigned = false, refCount = 1 };
3551       }
3552
3553       if(dest.kind == classType)
3554       {
3555          Class _class = dest._class ? dest._class.registered : null;
3556
3557          if(_class && _class.type == unitClass)
3558          {
3559             if(source.kind != classType)
3560             {
3561                Type tempType { };
3562                Type tempDest, tempSource;
3563
3564                for(; _class.base.type != systemClass; _class = _class.base);
3565                tempSource = dest;
3566                tempDest = tempType;
3567
3568                tempType.kind = classType;
3569                if(!_class.symbol)
3570                   _class.symbol = FindClass(_class.fullName);
3571
3572                tempType._class = _class.symbol;
3573                tempType.truth = dest.truth;
3574                if(tempType._class)
3575                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false);
3576
3577                // NOTE: To handle bad warnings on int64 vs 32 bit eda::Id incompatibilities
3578                backupSourceExpType = sourceExp.expType;
3579                sourceExp.expType = dest; dest.refCount++;
3580                //sourceExp.expType = MkClassType(_class.fullName);
3581                flag = true;
3582
3583                delete tempType;
3584             }
3585          }
3586
3587
3588          // Why wasn't there something like this?
3589          if(_class && _class.type == bitClass && source.kind != classType)
3590          {
3591             if(!dest._class.registered.dataType)
3592                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3593             if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false))
3594             {
3595                FreeType(source);
3596                FreeType(sourceExp.expType);
3597                source = sourceExp.expType = MkClassType(dest._class.string);
3598                source.refCount++;
3599
3600                //source.kind = classType;
3601                //source._class = dest._class;
3602             }
3603          }
3604
3605          // Adding two enumerations
3606          /*
3607          if(_class && _class.type == enumClass && source.kind == classType && source._class && source._class.registered && source._class.registered.type == enumClass)
3608          {
3609             if(!source._class.registered.dataType)
3610                source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3611             if(!dest._class.registered.dataType)
3612                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3613
3614             if(MatchTypes(source._class.registered.dataType, dest._class.registered.dataType, conversions, null, null, true, false, false))
3615             {
3616                FreeType(source);
3617                source = sourceExp.expType = MkClassType(dest._class.string);
3618                source.refCount++;
3619
3620                //source.kind = classType;
3621                //source._class = dest._class;
3622             }
3623          }*/
3624
3625          if(_class && !strcmp(_class.fullName, "ecere::com::Class") && source.kind == pointerType && source.type && source.type.kind == charType && sourceExp.type == stringExp)
3626          {
3627             OldList * specs = MkList();
3628             Declarator decl;
3629             char string[1024];
3630
3631             ReadString(string, sourceExp.string);
3632             decl = SpecDeclFromString(string, specs, null);
3633
3634             FreeExpContents(sourceExp);
3635             FreeType(sourceExp.expType);
3636
3637             sourceExp.type = classExp;
3638             sourceExp._classExp.specifiers = specs;
3639             sourceExp._classExp.decl = decl;
3640             sourceExp.expType = dest;
3641             dest.refCount++;
3642
3643             FreeType(source);
3644             FreeType(dest);
3645             if(backupSourceExpType) FreeType(backupSourceExpType);
3646             return true;
3647          }
3648       }
3649       else if(source.kind == classType)
3650       {
3651          Class _class = source._class ? source._class.registered : null;
3652
3653          if(_class && (_class.type == unitClass || !strcmp(_class.fullName, "bool") || /*_class.type == enumClass || */_class.type == bitClass ))  // TOCHECK: enumClass, bitClass is new here...
3654          {
3655             /*
3656             if(dest.kind != classType)
3657             {
3658                // Testing this simpler piece of code... (Broke Units Conversion to no unit Logic)
3659                if(!source._class.registered.dataType)
3660                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3661
3662                FreeType(dest);
3663                dest = MkClassType(source._class.string);
3664                //if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, false, false))
3665                //   dest = MkClassType(source._class.string);
3666             }
3667             */
3668
3669             if(dest.kind != classType)
3670             {
3671                Type tempType { };
3672                Type tempDest, tempSource;
3673
3674                if(!source._class.registered.dataType)
3675                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3676
3677                for(; _class.base.type != systemClass; _class = _class.base);
3678                tempDest = source;
3679                tempSource = tempType;
3680                tempType.kind = classType;
3681                tempType._class = FindClass(_class.fullName);
3682                tempType.truth = source.truth;
3683                tempType.classObjectType = source.classObjectType;
3684
3685                if(tempType._class)
3686                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false);
3687
3688                // PUT THIS BACK TESTING UNITS?
3689                if(conversions.last)
3690                {
3691                   ((Conversion)(conversions.last)).resultType = dest;
3692                   dest.refCount++;
3693                }
3694
3695                FreeType(sourceExp.expType);
3696                sourceExp.expType = MkClassType(_class.fullName);
3697                sourceExp.expType.truth = source.truth;
3698                sourceExp.expType.classObjectType = source.classObjectType;
3699
3700                // *** This if was commented out, put it back because "int a =^ Destroy()" shows up bool enum values in autocomplete ***
3701
3702                if(!sourceExp.destType)
3703                {
3704                   FreeType(sourceExp.destType);
3705                   sourceExp.destType = sourceExp.expType;
3706                   if(sourceExp.expType)
3707                      sourceExp.expType.refCount++;
3708                }
3709                //flag = true;
3710                //source = _class.dataType;
3711
3712
3713                // TOCHECK: TESTING THIS NEW CODE
3714                if(!_class.dataType)
3715                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3716                FreeType(dest);
3717                dest = MkClassType(source._class.string);
3718                dest.truth = source.truth;
3719                dest.classObjectType = source.classObjectType;
3720
3721                FreeType(source);
3722                source = _class.dataType;
3723                source.refCount++;
3724
3725                delete tempType;
3726             }
3727          }
3728       }
3729
3730       if(!flag)
3731       {
3732          if(MatchTypes(source, dest, conversions, null, null, true, true, false, false))
3733          {
3734             FreeType(source);
3735             FreeType(dest);
3736             return true;
3737          }
3738       }
3739
3740       // Implicit Casts
3741       /*
3742       if(source.kind == classType)
3743       {
3744          Class _class = source._class.registered;
3745          if(_class.type == unitClass)
3746          {
3747             if(!_class.dataType)
3748                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3749             source = _class.dataType;
3750          }
3751       }*/
3752
3753       if(dest.kind == classType)
3754       {
3755          Class _class = dest._class ? dest._class.registered : null;
3756          if(_class && !dest.truth && (_class.type == unitClass || !strcmp(_class.fullName, "bool") ||
3757             (/*_class.type == enumClass*/_class.type != structClass && !value && source.kind == intType) || _class.type == bitClass))   // TOCHECK: enumClass, bitClass is new here...
3758          {
3759             if(_class.type == normalClass || _class.type == noHeadClass)
3760             {
3761                Expression newExp { };
3762                *newExp = *sourceExp;
3763                if(sourceExp.destType) sourceExp.destType.refCount++;
3764                if(sourceExp.expType)  sourceExp.expType.refCount++;
3765                sourceExp.type = castExp;
3766                sourceExp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
3767                sourceExp.cast.exp = newExp;
3768                FreeType(sourceExp.expType);
3769                sourceExp.expType = null;
3770                ProcessExpressionType(sourceExp);
3771
3772                // In Debugger, this helps with addresses (e.g. null pointers) that end up casted to a void *: keeps a classType instead of a pointerType
3773                if(!inCompiler)
3774                {
3775                   FreeType(sourceExp.expType);
3776                   sourceExp.expType = dest;
3777                }
3778
3779                FreeType(source);
3780                if(inCompiler) FreeType(dest);
3781
3782                if(backupSourceExpType) FreeType(backupSourceExpType);
3783                return true;
3784             }
3785
3786             if(!_class.dataType)
3787                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3788             FreeType(dest);
3789             dest = _class.dataType;
3790             dest.refCount++;
3791          }
3792
3793          // Accept lower precision types for units, since we want to keep the unit type
3794          if(dest.kind == doubleType &&
3795             (source.kind == doubleType || source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType ||
3796              source.kind == charType || source.kind == _BoolType))
3797          {
3798             specs = MkListOne(MkSpecifier(DOUBLE));
3799          }
3800          else if(dest.kind == floatType &&
3801             (source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3802             source.kind == _BoolType || source.kind == doubleType))
3803          {
3804             specs = MkListOne(MkSpecifier(FLOAT));
3805          }
3806          else if(dest.kind == int64Type && (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3807             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3808          {
3809             specs = MkList();
3810             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3811             ListAdd(specs, MkSpecifier(INT64));
3812          }
3813          else if(dest.kind == intType && (source.kind == intType || source.kind == shortType || source.kind == charType ||
3814             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3815          {
3816             specs = MkList();
3817             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3818             ListAdd(specs, MkSpecifier(INT));
3819          }
3820          else if(dest.kind == shortType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType ||
3821             source.kind == floatType || source.kind == doubleType))
3822          {
3823             specs = MkList();
3824             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3825             ListAdd(specs, MkSpecifier(SHORT));
3826          }
3827          else if(dest.kind == charType && (source.kind == charType || source.kind == _BoolType || source.kind == shortType || source.kind == intType ||
3828             source.kind == floatType || source.kind == doubleType))
3829          {
3830             specs = MkList();
3831             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3832             ListAdd(specs, MkSpecifier(CHAR));
3833          }
3834          else
3835          {
3836             FreeType(source);
3837             FreeType(dest);
3838             if(backupSourceExpType)
3839             {
3840                // Failed to convert: revert previous exp type
3841                if(sourceExp.expType) FreeType(sourceExp.expType);
3842                sourceExp.expType = backupSourceExpType;
3843             }
3844             return false;
3845          }
3846       }
3847       else if(dest.kind == doubleType &&
3848          (source.kind == doubleType || source.kind == floatType || source.kind == int64Type || source.kind == intType || source.kind == enumType || source.kind == shortType ||
3849           source.kind == _BoolType || source.kind == charType))
3850       {
3851          specs = MkListOne(MkSpecifier(DOUBLE));
3852       }
3853       else if(dest.kind == floatType &&
3854          (source.kind == floatType || source.kind == enumType || source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3855       {
3856          specs = MkListOne(MkSpecifier(FLOAT));
3857       }
3858       else if(dest.kind == _BoolType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3859          (value == 1 || value == 0))
3860       {
3861          specs = MkList();
3862          ListAdd(specs, MkSpecifier(BOOL));
3863       }
3864       else if(dest.kind == charType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3865          (dest.isSigned ? (value >= -128 && value <= 127) : (value >= 0 && value <= 255)))
3866       {
3867          specs = MkList();
3868          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3869          ListAdd(specs, MkSpecifier(CHAR));
3870       }
3871       else if(dest.kind == shortType && (source.kind == enumType || source.kind == _BoolType || source.kind == charType || source.kind == shortType ||
3872          (source.kind == intType && (dest.isSigned ? (value >= -32768 && value <= 32767) : (value >= 0 && value <= 65535)))))
3873       {
3874          specs = MkList();
3875          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3876          ListAdd(specs, MkSpecifier(SHORT));
3877       }
3878       else if(dest.kind == intType && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType))
3879       {
3880          specs = MkList();
3881          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3882          ListAdd(specs, MkSpecifier(INT));
3883       }
3884       else if(dest.kind == int64Type && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType || source.kind == int64Type))
3885       {
3886          specs = MkList();
3887          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3888          ListAdd(specs, MkSpecifier(INT64));
3889       }
3890       else if(dest.kind == enumType &&
3891          (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3892       {
3893          specs = MkListOne(MkEnum(MkIdentifier(dest.enumName), null));
3894       }
3895       else
3896       {
3897          FreeType(source);
3898          FreeType(dest);
3899          if(backupSourceExpType)
3900          {
3901             // Failed to convert: revert previous exp type
3902             if(sourceExp.expType) FreeType(sourceExp.expType);
3903             sourceExp.expType = backupSourceExpType;
3904          }
3905          return false;
3906       }
3907
3908       if(!flag)
3909       {
3910          Expression newExp { };
3911          *newExp = *sourceExp;
3912          newExp.prev = null;
3913          newExp.next = null;
3914          if(sourceExp.destType) sourceExp.destType.refCount++;
3915          if(sourceExp.expType)  sourceExp.expType.refCount++;
3916
3917          sourceExp.type = castExp;
3918          if(realDest.kind == classType)
3919          {
3920             sourceExp.cast.typeName = QMkClass(realDest._class.string, null);
3921             FreeList(specs, FreeSpecifier);
3922          }
3923          else
3924             sourceExp.cast.typeName = MkTypeName(specs, null);
3925          if(newExp.type == opExp)
3926          {
3927             sourceExp.cast.exp = MkExpBrackets(MkListOne(newExp));
3928          }
3929          else
3930             sourceExp.cast.exp = newExp;
3931
3932          FreeType(sourceExp.expType);
3933          sourceExp.expType = null;
3934          ProcessExpressionType(sourceExp);
3935       }
3936       else
3937          FreeList(specs, FreeSpecifier);
3938
3939       FreeType(dest);
3940       FreeType(source);
3941       if(backupSourceExpType) FreeType(backupSourceExpType);
3942
3943       return true;
3944    }
3945    else
3946    {
3947       while((sourceExp.type == bracketsExp || sourceExp.type == extensionExpressionExp) && sourceExp.list) sourceExp = sourceExp.list->last;
3948       if(sourceExp.type == identifierExp)
3949       {
3950          Identifier id = sourceExp.identifier;
3951          if(dest.kind == classType)
3952          {
3953             if(dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3954             {
3955                Class _class = dest._class.registered;
3956                Class enumClass = eSystem_FindClass(privateModule, "enum");
3957                if(enumClass)
3958                {
3959                   for( ; _class && _class.type == ClassType::enumClass; _class = _class.base)
3960                   {
3961                      NamedLink value;
3962                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
3963                      for(value = e.values.first; value; value = value.next)
3964                      {
3965                         if(!strcmp(value.name, id.string))
3966                            break;
3967                      }
3968                      if(value)
3969                      {
3970                         FreeExpContents(sourceExp);
3971                         FreeType(sourceExp.expType);
3972
3973                         sourceExp.isConstant = true;
3974                         sourceExp.expType = MkClassType(_class.fullName);
3975                         //if(inCompiler)
3976                         {
3977                            char constant[256];
3978                            sourceExp.type = constantExp;
3979                            if(/*_class && */_class.dataTypeString && !strcmp(_class.dataTypeString, "int")) // _class cannot be null here!
3980                               sprintf(constant, "%d", (int) value.data);
3981                            else
3982                               sprintf(constant, "0x%X", (int) value.data);
3983                            sourceExp.constant = CopyString(constant);
3984                            //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
3985                         }
3986                         return true;
3987                      }
3988                   }
3989                }
3990             }
3991          }
3992
3993          // Loop through all enum classes
3994          if(dest.classObjectType != typedObject && dest.kind == classType /*!= ellipsisType */&& MatchWithEnums_Module(privateModule, sourceExp, dest, id.string, conversions))
3995             return true;
3996       }
3997    }
3998    return false;
3999 }
4000
4001 #define TERTIARY(o, name, m, t, p) \
4002    static bool name(Expression exp, Operand op1, Operand op2, Operand op3)   \
4003    {                                                              \
4004       exp.type = constantExp;                                    \
4005       exp.string = p(op1.m ? op2.m : op3.m);                     \
4006       if(!exp.expType) \
4007          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4008       return true;                                                \
4009    }
4010
4011 #define BINARY(o, name, m, t, p) \
4012    static bool name(Expression exp, Operand op1, Operand op2)   \
4013    {                                                              \
4014       t value2 = op2.m;                                           \
4015       exp.type = constantExp;                                    \
4016       exp.string = p(op1.m o value2);                     \
4017       if(!exp.expType) \
4018          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4019       return true;                                                \
4020    }
4021
4022 #define BINARY_DIVIDEINT(o, name, m, t, p) \
4023    static bool name(Expression exp, Operand op1, Operand op2)   \
4024    {                                                              \
4025       t value2 = op2.m;                                           \
4026       exp.type = constantExp;                                    \
4027       exp.string = p(value2 ? (op1.m o value2) : 0);             \
4028       if(!exp.expType) \
4029          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4030       return true;                                                \
4031    }
4032
4033 #define BINARY_DIVIDEREAL(o, name, m, t, p) \
4034    static bool name(Expression exp, Operand op1, Operand op2)   \
4035    {                                                              \
4036       t value2 = op2.m;                                           \
4037       exp.type = constantExp;                                    \
4038       exp.string = p(op1.m o value2);             \
4039       if(!exp.expType) \
4040          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4041       return true;                                                \
4042    }
4043
4044 #define UNARY(o, name, m, t, p) \
4045    static bool name(Expression exp, Operand op1)                \
4046    {                                                              \
4047       exp.type = constantExp;                                    \
4048       exp.string = p((t)(o op1.m));                                   \
4049       if(!exp.expType) \
4050          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4051       return true;                                                \
4052    }
4053
4054 #define OPERATOR_ALL(macro, o, name) \
4055    macro(o, Int##name, i, int, PrintInt) \
4056    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4057    macro(o, Int64##name, i64, int64, PrintInt64) \
4058    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4059    macro(o, Short##name, s, short, PrintShort) \
4060    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4061    macro(o, Char##name, c, char, PrintChar) \
4062    macro(o, UChar##name, uc, unsigned char, PrintUChar) \
4063    macro(o, Float##name, f, float, PrintFloat) \
4064    macro(o, Double##name, d, double, PrintDouble)
4065
4066 #define OPERATOR_INTTYPES(macro, o, name) \
4067    macro(o, Int##name, i, int, PrintInt) \
4068    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4069    macro(o, Int64##name, i64, int64, PrintInt64) \
4070    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4071    macro(o, Short##name, s, short, PrintShort) \
4072    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4073    macro(o, Char##name, c, char, PrintChar) \
4074    macro(o, UChar##name, uc, unsigned char, PrintUChar)
4075
4076 #define OPERATOR_REALTYPES(macro, o, name) \
4077    macro(o, Float##name, f, float, PrintFloat) \
4078    macro(o, Double##name, d, double, PrintDouble)
4079
4080 // binary arithmetic
4081 OPERATOR_ALL(BINARY, +, Add)
4082 OPERATOR_ALL(BINARY, -, Sub)
4083 OPERATOR_ALL(BINARY, *, Mul)
4084 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /, Div)
4085 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /, Div)
4086 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %, Mod)
4087
4088 // unary arithmetic
4089 OPERATOR_ALL(UNARY, -, Neg)
4090
4091 // unary arithmetic increment and decrement
4092 OPERATOR_ALL(UNARY, ++, Inc)
4093 OPERATOR_ALL(UNARY, --, Dec)
4094
4095 // binary arithmetic assignment
4096 OPERATOR_ALL(BINARY, =, Asign)
4097 OPERATOR_ALL(BINARY, +=, AddAsign)
4098 OPERATOR_ALL(BINARY, -=, SubAsign)
4099 OPERATOR_ALL(BINARY, *=, MulAsign)
4100 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /=, DivAsign)
4101 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /=, DivAsign)
4102 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %=, ModAsign)
4103
4104 // binary bitwise
4105 OPERATOR_INTTYPES(BINARY, &, BitAnd)
4106 OPERATOR_INTTYPES(BINARY, |, BitOr)
4107 OPERATOR_INTTYPES(BINARY, ^, BitXor)
4108 OPERATOR_INTTYPES(BINARY, <<, LShift)
4109 OPERATOR_INTTYPES(BINARY, >>, RShift)
4110
4111 // unary bitwise
4112 OPERATOR_INTTYPES(UNARY, ~, BitNot)
4113
4114 // binary bitwise assignment
4115 OPERATOR_INTTYPES(BINARY, &=, AndAsign)
4116 OPERATOR_INTTYPES(BINARY, |=, OrAsign)
4117 OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
4118 OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
4119 OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
4120
4121 // unary logical negation
4122 OPERATOR_INTTYPES(UNARY, !, Not)
4123
4124 // binary logical equality
4125 OPERATOR_ALL(BINARY, ==, Equ)
4126 OPERATOR_ALL(BINARY, !=, Nqu)
4127
4128 // binary logical
4129 OPERATOR_ALL(BINARY, &&, And)
4130 OPERATOR_ALL(BINARY, ||, Or)
4131
4132 // binary logical relational
4133 OPERATOR_ALL(BINARY, >, Grt)
4134 OPERATOR_ALL(BINARY, <, Sma)
4135 OPERATOR_ALL(BINARY, >=, GrtEqu)
4136 OPERATOR_ALL(BINARY, <=, SmaEqu)
4137
4138 // tertiary condition operator
4139 OPERATOR_ALL(TERTIARY, ?, Cond)
4140
4141 //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
4142 #define OPERATOR_TABLE_ALL(name, type) \
4143     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, type##Mod, \
4144                           type##Neg, \
4145                           type##Inc, type##Dec, \
4146                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, type##ModAsign, \
4147                           type##BitAnd, type##BitOr, type##BitXor, type##LShift, type##RShift, \
4148                           type##BitNot, \
4149                           type##AndAsign, type##OrAsign, type##XorAsign, type##LShiftAsign, type##RShiftAsign, \
4150                           type##Not, \
4151                           type##Equ, type##Nqu, \
4152                           type##And, type##Or, \
4153                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu, type##Cond \
4154                         }; \
4155
4156 #define OPERATOR_TABLE_INTTYPES(name, type) \
4157     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, null, \
4158                           type##Neg, \
4159                           type##Inc, type##Dec, \
4160                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, null, \
4161                           null, null, null, null, null, \
4162                           null, \
4163                           null, null, null, null, null, \
4164                           null, \
4165                           type##Equ, type##Nqu, \
4166                           type##And, type##Or, \
4167                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu \
4168                         }; \
4169
4170 OPERATOR_TABLE_ALL(int, Int)
4171 OPERATOR_TABLE_ALL(uint, UInt)
4172 OPERATOR_TABLE_ALL(int64, Int64)
4173 OPERATOR_TABLE_ALL(uint64, UInt64)
4174 OPERATOR_TABLE_ALL(short, Short)
4175 OPERATOR_TABLE_ALL(ushort, UShort)
4176 OPERATOR_TABLE_INTTYPES(float, Float)
4177 OPERATOR_TABLE_INTTYPES(double, Double)
4178 OPERATOR_TABLE_ALL(char, Char)
4179 OPERATOR_TABLE_ALL(uchar, UChar)
4180
4181 //OpTable intOps =    {    IntAdd,    IntSub,    IntMul,    IntDiv,    IntMod,    IntExp,    IntNot,    IntBwn,    IntOr,    IntAnd,    IntEqu,    IntNqu,    IntGrt,    IntSma,    IntGrtEqu,    IntSmaEqu,    IntNeg,    IntLBitSft,    IntRBitSft };
4182 //OpTable uintOps =   {   UIntAdd,   UIntSub,   UIntMul,   UIntDiv,   UIntMod,   UIntExp,   UIntNot,   UIntBwn,   UIntOr,   UIntAnd,   UIntEqu,   UIntNqu,   UIntGrt,   UIntSma,   UIntGrtEqu,   UIntSmaEqu,   UIntNeg,   UIntLBitSft,   UIntRBitSft };
4183 //OpTable shortOps =  {  ShortAdd,  ShortSub,  ShortMul,  ShortDiv,  ShortMod,  ShortExp,  ShortNot,  ShortBwn,  ShortOr,  ShortAnd,  ShortEqu,  ShortNqu,  ShortGrt,  ShortSma,  ShortGrtEqu,  ShortSmaEqu,  ShortNeg,  ShortLBitSft,  ShortRBitSft };
4184 //OpTable ushortOps = { UShortAdd, UShortSub, UShortMul, UShortDiv, UShortMod, UShortExp, UShortNot, UShortBwn, UShortOr, UShortAnd, UShortEqu, UShortNqu, UShortGrt, UShortSma, UShortGrtEqu, UShortSmaEqu, UShortNeg, UShortLBitSft, UShortRBitSft };
4185 //OpTable floatOps =  {  FloatAdd,  FloatSub,  FloatMul,  FloatDiv,      null,      null,      null,      null,     null,      null,  FloatEqu,  FloatNqu,  FloatGrt,  FloatSma,  FloatGrtEqu,  FloatSmaEqu,  FloatNeg,          null,          null };
4186 //OpTable doubleOps = { DoubleAdd, DoubleSub, DoubleMul, DoubleDiv,      null,      null,      null,      null,     null,      null, DoubleEqu, DoubleNqu, DoubleGrt, DoubleSma, DoubleGrtEqu, DoubleSmaEqu, DoubleNeg,          null,          null };
4187 //OpTable charOps =   {   CharAdd,   CharSub,   CharMul,   CharDiv,   CharMod,   CharExp,   CharNot,   CharBwn,   CharOr,   CharAnd,   CharEqu,   CharNqu,   CharGrt,   CharSma,   CharGrtEqu,   CharSmaEqu,   CharNeg,   CharLBitSft,   CharRBitSft };
4188 //OpTable ucharOps =  {  UCharAdd,  UCharSub,  UCharMul,  UCharDiv,  UCharMod,  UCharExp,  UCharNot,  UCharBwn,  UCharOr,  UCharAnd,  UCharEqu,  UCharNqu,  UCharGrt,  UCharSma,  UCharGrtEqu,  UCharSmaEqu,  UCharNeg,  UCharLBitSft,  UCharRBitSft };
4189
4190 public void ReadString(char * output,  char * string)
4191 {
4192    int len = strlen(string);
4193    int c,d = 0;
4194    bool quoted = false, escaped = false;
4195    for(c = 0; c<len; c++)
4196    {
4197       char ch = string[c];
4198       if(escaped)
4199       {
4200          switch(ch)
4201          {
4202             case 'n': output[d] = '\n'; break;
4203             case 't': output[d] = '\t'; break;
4204             case 'a': output[d] = '\a'; break;
4205             case 'b': output[d] = '\b'; break;
4206             case 'f': output[d] = '\f'; break;
4207             case 'r': output[d] = '\r'; break;
4208             case 'v': output[d] = '\v'; break;
4209             case '\\': output[d] = '\\'; break;
4210             case '\"': output[d] = '\"'; break;
4211             case '\'': output[d] = '\''; break;
4212             default: output[d] = ch;
4213          }
4214          d++;
4215          escaped = false;
4216       }
4217       else
4218       {
4219          if(ch == '\"')
4220             quoted ^= true;
4221          else if(quoted)
4222          {
4223             if(ch == '\\')
4224                escaped = true;
4225             else
4226                output[d++] = ch;
4227          }
4228       }
4229    }
4230    output[d] = '\0';
4231 }
4232
4233 // String Unescape Copy
4234
4235 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
4236 // This is the same as ReadString above (which also misses numeric escape codes) except it doesn't handle external quotes
4237 public int UnescapeString(char * d, char * s, int len)
4238 {
4239    int j = 0, k = 0;
4240    char ch;
4241    while(j < len && (ch = s[j]))
4242    {
4243       switch(ch)
4244       {
4245          case '\\':
4246             switch((ch = s[++j]))
4247             {
4248                case 'n': d[k] = '\n'; break;
4249                case 't': d[k] = '\t'; break;
4250                case 'a': d[k] = '\a'; break;
4251                case 'b': d[k] = '\b'; break;
4252                case 'f': d[k] = '\f'; break;
4253                case 'r': d[k] = '\r'; break;
4254                case 'v': d[k] = '\v'; break;
4255                case '\\': d[k] = '\\'; break;
4256                case '\"': d[k] = '\"'; break;
4257                case '\'': d[k] = '\''; break;
4258                default: d[k] = '\\'; d[k] = ch;
4259             }
4260             break;
4261          default:
4262             d[k] = ch;
4263       }
4264       j++, k++;
4265    }
4266    d[k] = '\0';
4267    return k;
4268 }
4269
4270 public char * OffsetEscapedString(char * s, int len, int offset)
4271 {
4272    char ch;
4273    int j = 0, k = 0;
4274    while(j < len && k < offset && (ch = s[j]))
4275    {
4276       if(ch == '\\') ++j;
4277       j++, k++;
4278    }
4279    return (k == offset) ? s + j : null;
4280 }
4281
4282 public Operand GetOperand(Expression exp)
4283 {
4284    Operand op { };
4285    Type type = exp.expType;
4286    if(type)
4287    {
4288       while(type.kind == classType &&
4289          type._class.registered && (type._class.registered.type == bitClass || type._class.registered.type == unitClass || type._class.registered.type == enumClass))
4290       {
4291          if(!type._class.registered.dataType)
4292             type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
4293          type = type._class.registered.dataType;
4294
4295       }
4296       if(exp.type == stringExp && op.kind == pointerType)
4297       {
4298          op.ui64 = (uint64)exp.string;
4299          op.kind = pointerType;
4300          op.ops = uint64Ops;
4301       }
4302       else if(exp.isConstant && exp.type == constantExp)
4303       {
4304          op.kind = type.kind;
4305          op.type = exp.expType;
4306
4307          switch(op.kind)
4308          {
4309             case _BoolType:
4310             case charType:
4311             {
4312                if(exp.constant[0] == '\'')
4313                {
4314                   op.c = exp.constant[1];
4315                   op.ops = charOps;
4316                }
4317                else if(type.isSigned)
4318                {
4319                   op.c = (char)strtol(exp.constant, null, 0);
4320                   op.ops = charOps;
4321                }
4322                else
4323                {
4324                   op.uc = (unsigned char)strtoul(exp.constant, null, 0);
4325                   op.ops = ucharOps;
4326                }
4327                break;
4328             }
4329             case shortType:
4330                if(type.isSigned)
4331                {
4332                   op.s = (short)strtol(exp.constant, null, 0);
4333                   op.ops = shortOps;
4334                }
4335                else
4336                {
4337                   op.us = (unsigned short)strtoul(exp.constant, null, 0);
4338                   op.ops = ushortOps;
4339                }
4340                break;
4341             case intType:
4342             case longType:
4343                if(type.isSigned)
4344                {
4345                   op.i = (int)strtol(exp.constant, null, 0);
4346                   op.ops = intOps;
4347                }
4348                else
4349                {
4350                   op.ui = (unsigned int)strtoul(exp.constant, null, 0);
4351                   op.ops = uintOps;
4352                }
4353                op.kind = intType;
4354                break;
4355             case int64Type:
4356                if(type.isSigned)
4357                {
4358                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4359                   op.ops = int64Ops;
4360                }
4361                else
4362                {
4363                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4364                   op.ops = uint64Ops;
4365                }
4366                op.kind = int64Type;
4367                break;
4368             case intPtrType:
4369                if(type.isSigned)
4370                {
4371                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4372                   op.ops = int64Ops;
4373                }
4374                else
4375                {
4376                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4377                   op.ops = uint64Ops;
4378                }
4379                op.kind = int64Type;
4380                break;
4381             case intSizeType:
4382                if(type.isSigned)
4383                {
4384                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4385                   op.ops = int64Ops;
4386                }
4387                else
4388                {
4389                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4390                   op.ops = uint64Ops;
4391                }
4392                op.kind = int64Type;
4393                break;
4394             case floatType:
4395                if(!strcmp(exp.constant, "inf")) op.f = float::inf();
4396                else if(!strcmp(exp.constant, "-inf")) op.f = -float::inf();
4397                else if(!strcmp(exp.constant, "nan")) op.f = float::nan();
4398                else if(!strcmp(exp.constant, "-nan")) op.f = -float::nan();
4399                else
4400                   op.f = (float)strtod(exp.constant, null);
4401                op.ops = floatOps;
4402                break;
4403             case doubleType:
4404                if(!strcmp(exp.constant, "inf")) op.d = double::inf();
4405                else if(!strcmp(exp.constant, "-inf")) op.d = -double::inf();
4406                else if(!strcmp(exp.constant, "nan")) op.d = double::nan();
4407                else if(!strcmp(exp.constant, "-nan")) op.d = -double::nan();
4408                else
4409                   op.d = (double)strtod(exp.constant, null);
4410                op.ops = doubleOps;
4411                break;
4412             //case classType:    For when we have operator overloading...
4413             // Pointer additions
4414             //case functionType:
4415             case arrayType:
4416             case pointerType:
4417             case classType:
4418                op.ui64 = _strtoui64(exp.constant, null, 0);
4419                op.kind = pointerType;
4420                op.ops = uint64Ops;
4421                // op.ptrSize =
4422                break;
4423          }
4424       }
4425    }
4426    return op;
4427 }
4428
4429 static void UnusedFunction()
4430 {
4431    int a;
4432    a.OnGetString(0,0,0);
4433 }
4434 default:
4435 extern int __ecereVMethodID_class_OnGetString;
4436 public:
4437
4438 static void PopulateInstanceProcessMember(Instantiation inst, OldList * memberList, DataMember parentDataMember, uint offset)
4439 {
4440    DataMember dataMember;
4441    for(dataMember = parentDataMember.members.first; dataMember; dataMember = dataMember.next)
4442    {
4443       if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4444          PopulateInstanceProcessMember(inst, memberList, dataMember, offset + dataMember.offset);
4445       else
4446       {
4447          Expression exp { };
4448          MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4449          Type type;
4450          void * ptr = inst.data + dataMember.offset + offset;
4451          char * result = null;
4452          exp.loc = member.loc = inst.loc;
4453          ((Identifier)member.identifiers->first).loc = inst.loc;
4454
4455          if(!dataMember.dataType)
4456             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4457          type = dataMember.dataType;
4458          if(type.kind == classType)
4459          {
4460             Class _class = type._class.registered;
4461             if(_class.type == enumClass)
4462             {
4463                Class enumClass = eSystem_FindClass(privateModule, "enum");
4464                if(enumClass)
4465                {
4466                   EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4467                   NamedLink item;
4468                   for(item = e.values.first; item; item = item.next)
4469                   {
4470                      if((int)item.data == *(int *)ptr)
4471                      {
4472                         result = item.name;
4473                         break;
4474                      }
4475                   }
4476                   if(result)
4477                   {
4478                      exp.identifier = MkIdentifier(result);
4479                      exp.type = identifierExp;
4480                      exp.destType = MkClassType(_class.fullName);
4481                      ProcessExpressionType(exp);
4482                   }
4483                }
4484             }
4485             if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4486             {
4487                if(!_class.dataType)
4488                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4489                type = _class.dataType;
4490             }
4491          }
4492          if(!result)
4493          {
4494             switch(type.kind)
4495             {
4496                case floatType:
4497                {
4498                   FreeExpContents(exp);
4499
4500                   exp.constant = PrintFloat(*(float*)ptr);
4501                   exp.type = constantExp;
4502                   break;
4503                }
4504                case doubleType:
4505                {
4506                   FreeExpContents(exp);
4507
4508                   exp.constant = PrintDouble(*(double*)ptr);
4509                   exp.type = constantExp;
4510                   break;
4511                }
4512                case intType:
4513                {
4514                   FreeExpContents(exp);
4515
4516                   exp.constant = PrintInt(*(int*)ptr);
4517                   exp.type = constantExp;
4518                   break;
4519                }
4520                case int64Type:
4521                {
4522                   FreeExpContents(exp);
4523
4524                   exp.constant = PrintInt64(*(int64*)ptr);
4525                   exp.type = constantExp;
4526                   break;
4527                }
4528                case intPtrType:
4529                {
4530                   FreeExpContents(exp);
4531                   // TODO: This should probably use proper type
4532                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4533                   exp.type = constantExp;
4534                   break;
4535                }
4536                case intSizeType:
4537                {
4538                   FreeExpContents(exp);
4539                   // TODO: This should probably use proper type
4540                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4541                   exp.type = constantExp;
4542                   break;
4543                }
4544                default:
4545                   Compiler_Error($"Unhandled type populating instance\n");
4546             }
4547          }
4548          ListAdd(memberList, member);
4549       }
4550
4551       if(parentDataMember.type == unionMember)
4552          break;
4553    }
4554 }
4555
4556 void PopulateInstance(Instantiation inst)
4557 {
4558    Symbol classSym = inst._class.symbol; // FindClass(inst._class.name);
4559    Class _class = classSym.registered;
4560    DataMember dataMember;
4561    OldList * memberList = MkList();
4562    // Added this check and ->Add to prevent memory leaks on bad code
4563    if(!inst.members)
4564       inst.members = MkListOne(MkMembersInitList(memberList));
4565    else
4566       inst.members->Add(MkMembersInitList(memberList));
4567    for(dataMember = _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
4568    {
4569       if(!dataMember.isProperty)
4570       {
4571          if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4572             PopulateInstanceProcessMember(inst, memberList, dataMember, dataMember.offset);
4573          else
4574          {
4575             Expression exp { };
4576             MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4577             Type type;
4578             void * ptr = inst.data + dataMember.offset;
4579             char * result = null;
4580
4581             exp.loc = member.loc = inst.loc;
4582             ((Identifier)member.identifiers->first).loc = inst.loc;
4583
4584             if(!dataMember.dataType)
4585                dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4586             type = dataMember.dataType;
4587             if(type.kind == classType)
4588             {
4589                Class _class = type._class.registered;
4590                if(_class.type == enumClass)
4591                {
4592                   Class enumClass = eSystem_FindClass(privateModule, "enum");
4593                   if(enumClass)
4594                   {
4595                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4596                      NamedLink item;
4597                      for(item = e.values.first; item; item = item.next)
4598                      {
4599                         if((int)item.data == *(int *)ptr)
4600                         {
4601                            result = item.name;
4602                            break;
4603                         }
4604                      }
4605                   }
4606                   if(result)
4607                   {
4608                      exp.identifier = MkIdentifier(result);
4609                      exp.type = identifierExp;
4610                      exp.destType = MkClassType(_class.fullName);
4611                      ProcessExpressionType(exp);
4612                   }
4613                }
4614                if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4615                {
4616                   if(!_class.dataType)
4617                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4618                   type = _class.dataType;
4619                }
4620             }
4621             if(!result)
4622             {
4623                switch(type.kind)
4624                {
4625                   case floatType:
4626                   {
4627                      exp.constant = PrintFloat(*(float*)ptr);
4628                      exp.type = constantExp;
4629                      break;
4630                   }
4631                   case doubleType:
4632                   {
4633                      exp.constant = PrintDouble(*(double*)ptr);
4634                      exp.type = constantExp;
4635                      break;
4636                   }
4637                   case intType:
4638                   {
4639                      exp.constant = PrintInt(*(int*)ptr);
4640                      exp.type = constantExp;
4641                      break;
4642                   }
4643                   case int64Type:
4644                   {
4645                      exp.constant = PrintInt64(*(int64*)ptr);
4646                      exp.type = constantExp;
4647                      break;
4648                   }
4649                   case intPtrType:
4650                   {
4651                      exp.constant = PrintInt64((int64)*(intptr*)ptr);
4652                      exp.type = constantExp;
4653                      break;
4654                   }
4655                   default:
4656                      Compiler_Error($"Unhandled type populating instance\n");
4657                }
4658             }
4659             ListAdd(memberList, member);
4660          }
4661       }
4662    }
4663 }
4664
4665 void ComputeInstantiation(Expression exp)
4666 {
4667    Instantiation inst = exp.instance;
4668    MembersInit members;
4669    Symbol classSym = inst._class ? inst._class.symbol : null; // FindClass(inst._class.name);
4670    Class _class = classSym ? classSym.registered : null;
4671    DataMember curMember = null;
4672    Class curClass = null;
4673    DataMember subMemberStack[256];
4674    int subMemberStackPos = 0;
4675    uint64 bits = 0;
4676
4677    if(_class && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass ))
4678    {
4679       // Don't recompute the instantiation...
4680       // Non Simple classes will have become constants by now
4681       if(inst.data)
4682          return;
4683
4684       if(_class.type == normalClass || _class.type == noHeadClass)
4685       {
4686          inst.data = (byte *)eInstance_New(_class);
4687          if(_class.type == normalClass)
4688             ((Instance)inst.data)._refCount++;
4689       }
4690       else
4691          inst.data = new0 byte[_class.structSize];
4692    }
4693
4694    if(inst.members)
4695    {
4696       for(members = inst.members->first; members; members = members.next)
4697       {
4698          switch(members.type)
4699          {
4700             case dataMembersInit:
4701             {
4702                if(members.dataMembers)
4703                {
4704                   MemberInit member;
4705                   for(member = members.dataMembers->first; member; member = member.next)
4706                   {
4707                      Identifier ident = member.identifiers ? member.identifiers->first : null;
4708                      bool found = false;
4709
4710                      Property prop = null;
4711                      DataMember dataMember = null;
4712                      Method method = null;
4713                      uint dataMemberOffset;
4714
4715                      if(!ident)
4716                      {
4717                         eClass_FindNextMember(_class, &curClass, &curMember, subMemberStack, &subMemberStackPos);
4718                         if(curMember)
4719                         {
4720                            if(curMember.isProperty)
4721                               prop = (Property)curMember;
4722                            else
4723                            {
4724                               dataMember = curMember;
4725
4726                               // CHANGED THIS HERE
4727                               eClass_FindDataMemberAndOffset(_class, dataMember.name, &dataMemberOffset, privateModule, null, null);
4728
4729                               // 2013/17/29 -- It seems that this was missing here!
4730                               if(_class.type == normalClass)
4731                                  dataMemberOffset += _class.base.structSize;
4732                               // dataMemberOffset = dataMember.offset;
4733                            }
4734                            found = true;
4735                         }
4736                      }
4737                      else
4738                      {
4739                         prop = eClass_FindProperty(_class, ident.string, privateModule);
4740                         if(prop)
4741                         {
4742                            found = true;
4743                            if(prop.memberAccess == publicAccess)
4744                            {
4745                               curMember = (DataMember)prop;
4746                               curClass = prop._class;
4747                            }
4748                         }
4749                         else
4750                         {
4751                            DataMember _subMemberStack[256];
4752                            int _subMemberStackPos = 0;
4753
4754                            // FILL MEMBER STACK
4755                            dataMember = eClass_FindDataMemberAndOffset(_class, ident.string, &dataMemberOffset, privateModule, _subMemberStack, &_subMemberStackPos);
4756
4757                            if(dataMember)
4758                            {
4759                               found = true;
4760                               if(dataMember.memberAccess == publicAccess)
4761                               {
4762                                  curMember = dataMember;
4763                                  curClass = dataMember._class;
4764                                  memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
4765                                  subMemberStackPos = _subMemberStackPos;
4766                               }
4767                            }
4768                         }
4769                      }
4770
4771                      if(found && member.initializer && member.initializer.type == expInitializer)
4772                      {
4773                         Expression value = member.initializer.exp;
4774                         Type type = null;
4775                         bool deepMember = false;
4776                         if(prop)
4777                         {
4778                            type = prop.dataType;
4779                         }
4780                         else if(dataMember)
4781                         {
4782                            if(!dataMember.dataType)
4783                               dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4784
4785                            type = dataMember.dataType;
4786                         }
4787
4788                         if(ident && ident.next)
4789                         {
4790                            deepMember = true;
4791
4792                            // for(; ident && type; ident = ident.next)
4793                            for(ident = ident.next; ident && type; ident = ident.next)
4794                            {
4795                               if(type.kind == classType)
4796                               {
4797                                  prop = eClass_FindProperty(type._class.registered,
4798                                     ident.string, privateModule);
4799                                  if(prop)
4800                                     type = prop.dataType;
4801                                  else
4802                                  {
4803                                     dataMember = eClass_FindDataMemberAndOffset(type._class.registered,
4804                                        ident.string, &dataMemberOffset, privateModule, null, null);
4805                                     if(dataMember)
4806                                        type = dataMember.dataType;
4807                                  }
4808                               }
4809                               else if(type.kind == structType || type.kind == unionType)
4810                               {
4811                                  Type memberType;
4812                                  for(memberType = type.members.first; memberType; memberType = memberType.next)
4813                                  {
4814                                     if(!strcmp(memberType.name, ident.string))
4815                                     {
4816                                        type = memberType;
4817                                        break;
4818                                     }
4819                                  }
4820                               }
4821                            }
4822                         }
4823                         if(value)
4824                         {
4825                            FreeType(value.destType);
4826                            value.destType = type;
4827                            if(type) type.refCount++;
4828                            ComputeExpression(value);
4829                         }
4830                         if(!deepMember && type && value && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass /*&& value.expType.kind == type.kind*/))
4831                         {
4832                            if(type.kind == classType)
4833                            {
4834                               Class _class = type._class.registered;
4835                               if(_class.type == bitClass || _class.type == unitClass ||
4836                                  _class.type == enumClass)
4837                               {
4838                                  if(!_class.dataType)
4839                                     _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4840                                  type = _class.dataType;
4841                               }
4842                            }
4843
4844                            if(dataMember)
4845                            {
4846                               void * ptr = inst.data + dataMemberOffset;
4847
4848                               if(value.type == constantExp)
4849                               {
4850                                  switch(type.kind)
4851                                  {
4852                                     case intType:
4853                                     {
4854                                        GetInt(value, (int*)ptr);
4855                                        break;
4856                                     }
4857                                     case int64Type:
4858                                     {
4859                                        GetInt64(value, (int64*)ptr);
4860                                        break;
4861                                     }
4862                                     case intPtrType:
4863                                     {
4864                                        GetIntPtr(value, (intptr*)ptr);
4865                                        break;
4866                                     }
4867                                     case intSizeType:
4868                                     {
4869                                        GetIntSize(value, (intsize*)ptr);
4870                                        break;
4871                                     }
4872                                     case floatType:
4873                                     {
4874                                        GetFloat(value, (float*)ptr);
4875                                        break;
4876                                     }
4877                                     case doubleType:
4878                                     {
4879                                        GetDouble(value, (double *)ptr);
4880                                        break;
4881                                     }
4882                                  }
4883                               }
4884                               else if(value.type == instanceExp)
4885                               {
4886                                  if(type.kind == classType)
4887                                  {
4888                                     Class _class = type._class.registered;
4889                                     if(_class.type == structClass)
4890                                     {
4891                                        ComputeTypeSize(type);
4892                                        if(value.instance.data)
4893                                           memcpy(ptr, value.instance.data, type.size);
4894                                     }
4895                                  }
4896                               }
4897                            }
4898                            else if(prop)
4899                            {
4900                               if(value.type == instanceExp && value.instance.data)
4901                               {
4902                                  if(type.kind == classType)
4903                                  {
4904                                     Class _class = type._class.registered;
4905                                     if(_class && (_class.type != normalClass || eClass_IsDerived(((Instance)value.instance.data)._class, _class)))
4906                                     {
4907                                        void (*Set)(void *, void *) = (void *)prop.Set;
4908                                        Set(inst.data, value.instance.data);
4909                                        PopulateInstance(inst);
4910                                     }
4911                                  }
4912                               }
4913                               else if(value.type == constantExp)
4914                               {
4915                                  switch(type.kind)
4916                                  {
4917                                     case doubleType:
4918                                     {
4919                                        void (*Set)(void *, double) = (void *)prop.Set;
4920                                        Set(inst.data, strtod(value.constant, null) );
4921                                        break;
4922                                     }
4923                                     case floatType:
4924                                     {
4925                                        void (*Set)(void *, float) = (void *)prop.Set;
4926                                        Set(inst.data, (float)(strtod(value.constant, null)));
4927                                        break;
4928                                     }
4929                                     case intType:
4930                                     {
4931                                        void (*Set)(void *, int) = (void *)prop.Set;
4932                                        Set(inst.data, (int)strtol(value.constant, null, 0));
4933                                        break;
4934                                     }
4935                                     case int64Type:
4936                                     {
4937                                        void (*Set)(void *, int64) = (void *)prop.Set;
4938                                        Set(inst.data, _strtoi64(value.constant, null, 0));
4939                                        break;
4940                                     }
4941                                     case intPtrType:
4942                                     {
4943                                        void (*Set)(void *, intptr) = (void *)prop.Set;
4944                                        Set(inst.data, (intptr)_strtoi64(value.constant, null, 0));
4945                                        break;
4946                                     }
4947                                     case intSizeType:
4948                                     {
4949                                        void (*Set)(void *, intsize) = (void *)prop.Set;
4950                                        Set(inst.data, (intsize)_strtoi64(value.constant, null, 0));
4951                                        break;
4952                                     }
4953                                  }
4954                               }
4955                               else if(value.type == stringExp)
4956                               {
4957                                  char temp[1024];
4958                                  ReadString(temp, value.string);
4959                                  ((void (*)(void *, void *))(void *)prop.Set)(inst.data, temp);
4960                               }
4961                            }
4962                         }
4963                         else if(!deepMember && type && _class.type == unitClass)
4964                         {
4965                            if(prop)
4966                            {
4967                               // Only support converting units to units for now...
4968                               if(value.type == constantExp)
4969                               {
4970                                  if(type.kind == classType)
4971                                  {
4972                                     Class _class = type._class.registered;
4973                                     if(_class.type == unitClass)
4974                                     {
4975                                        if(!_class.dataType)
4976                                           _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4977                                        type = _class.dataType;
4978                                     }
4979                                  }
4980                                  // TODO: Assuming same base type for units...
4981                                  switch(type.kind)
4982                                  {
4983                                     case floatType:
4984                                     {
4985                                        float fValue;
4986                                        float (*Set)(float) = (void *)prop.Set;
4987                                        GetFloat(member.initializer.exp, &fValue);
4988                                        exp.constant = PrintFloat(Set(fValue));
4989                                        exp.type = constantExp;
4990                                        break;
4991                                     }
4992                                     case doubleType:
4993                                     {
4994                                        double dValue;
4995                                        double (*Set)(double) = (void *)prop.Set;
4996                                        GetDouble(member.initializer.exp, &dValue);
4997                                        exp.constant = PrintDouble(Set(dValue));
4998                                        exp.type = constantExp;
4999                                        break;
5000                                     }
5001                                  }
5002                               }
5003                            }
5004                         }
5005                         else if(!deepMember && type && _class.type == bitClass)
5006                         {
5007                            if(prop)
5008                            {
5009                               if(value.type == instanceExp && value.instance.data)
5010                               {
5011                                  unsigned int (*Set)(void *) = (void *)prop.Set;
5012                                  bits = Set(value.instance.data);
5013                               }
5014                               else if(value.type == constantExp)
5015                               {
5016                               }
5017                            }
5018                            else if(dataMember)
5019                            {
5020                               BitMember bitMember = (BitMember) dataMember;
5021                               Type type;
5022                               int part = 0;
5023                               GetInt(value, &part);
5024                               bits = (bits & ~bitMember.mask);
5025                               if(!bitMember.dataType)
5026                                  bitMember.dataType = ProcessTypeString(bitMember.dataTypeString, false);
5027
5028                               type = bitMember.dataType;
5029
5030                               if(type.kind == classType && type._class && type._class.registered)
5031                               {
5032                                  if(!type._class.registered.dataType)
5033                                     type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
5034                                  type = type._class.registered.dataType;
5035                               }
5036
5037                               switch(type.kind)
5038                               {
5039                                  case _BoolType:
5040                                  case charType:
5041                                     if(type.isSigned)
5042                                        bits |= ((char)part << bitMember.pos);
5043                                     else
5044                                        bits |= ((unsigned char)part << bitMember.pos);
5045                                     break;
5046                                  case shortType:
5047                                     if(type.isSigned)
5048                                        bits |= ((short)part << bitMember.pos);
5049                                     else
5050                                        bits |= ((unsigned short)part << bitMember.pos);
5051                                     break;
5052                                  case intType:
5053                                  case longType:
5054                                     if(type.isSigned)
5055                                        bits |= ((int)part << bitMember.pos);
5056                                     else
5057                                        bits |= ((unsigned int)part << bitMember.pos);
5058                                     break;
5059                                  case int64Type:
5060                                     if(type.isSigned)
5061                                        bits |= ((int64)part << bitMember.pos);
5062                                     else
5063                                        bits |= ((uint64)part << bitMember.pos);
5064                                     break;
5065                                  case intPtrType:
5066                                     if(type.isSigned)
5067                                     {
5068                                        bits |= ((intptr)part << bitMember.pos);
5069                                     }
5070                                     else
5071                                     {
5072                                        bits |= ((uintptr)part << bitMember.pos);
5073                                     }
5074                                     break;
5075                                  case intSizeType:
5076                                     if(type.isSigned)
5077                                     {
5078                                        bits |= ((ssize_t)(intsize)part << bitMember.pos);
5079                                     }
5080                                     else
5081                                     {
5082                                        bits |= ((size_t) (uintsize)part << bitMember.pos);
5083                                     }
5084                                     break;
5085                               }
5086                            }
5087                         }
5088                      }
5089                      else
5090                      {
5091                         if(_class && _class.type == unitClass)
5092                         {
5093                            ComputeExpression(member.initializer.exp);
5094                            exp.constant = member.initializer.exp.constant;
5095                            exp.type = constantExp;
5096
5097                            member.initializer.exp.constant = null;
5098                         }
5099                      }
5100                   }
5101                }
5102                break;
5103             }
5104          }
5105       }
5106    }
5107    if(_class && _class.type == bitClass)
5108    {
5109       exp.constant = PrintHexUInt(bits);
5110       exp.type = constantExp;
5111    }
5112    if(exp.type != instanceExp)
5113    {
5114       FreeInstance(inst);
5115    }
5116 }
5117
5118 static bool Promote(Operand op, TypeKind kind, bool isSigned)
5119 {
5120    bool result = false;
5121    switch(kind)
5122    {
5123       case shortType:
5124          if(op.kind == charType || op.kind == enumType || op.kind == _BoolType)
5125             result = isSigned ? GetOpShort(op, &op.s) : GetOpUShort(op, &op.us);
5126          break;
5127       case intType:
5128       case longType:
5129          if(op.kind == charType || op.kind == shortType || op.kind == enumType || op.kind == _BoolType)
5130             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5131          break;
5132       case int64Type:
5133          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5134             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5135             result = isSigned ? GetOpInt64(op, &op.i64) : GetOpUInt64(op, &op.ui64);
5136          break;
5137       case floatType:
5138          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType ||
5139             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5140             result = GetOpFloat(op, &op.f);
5141          break;
5142       case doubleType:
5143          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType ||
5144             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5145             result = GetOpDouble(op, &op.d);
5146          break;
5147       case pointerType:
5148          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5149             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5150             result = GetOpUIntPtr(op, &op.ui64);
5151          break;
5152       case enumType:
5153          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5154             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5155             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5156          break;
5157       case intPtrType:
5158          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5159             result = isSigned ? GetOpIntPtr(op, &op.i64) : GetOpUIntPtr(op, &op.i64);
5160          break;
5161       case intSizeType:
5162          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5163             result = isSigned ? GetOpIntSize(op, &op.ui64) : GetOpUIntSize(op, &op.ui64);
5164          break;
5165    }
5166    return result;
5167 }
5168
5169 void CallOperator(Expression exp, Expression exp1, Expression exp2, Operand op1, Operand op2)
5170 {
5171    if(exp.op.op == SIZEOF)
5172    {
5173       FreeExpContents(exp);
5174       exp.type = constantExp;
5175       exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5176    }
5177    else
5178    {
5179       if(!exp.op.exp1)
5180       {
5181          switch(exp.op.op)
5182          {
5183             // unary arithmetic
5184             case '+':
5185             {
5186                // Provide default unary +
5187                Expression exp2 = exp.op.exp2;
5188                exp.op.exp2 = null;
5189                FreeExpContents(exp);
5190                FreeType(exp.expType);
5191                FreeType(exp.destType);
5192                *exp = *exp2;
5193                delete exp2;
5194                break;
5195             }
5196             case '-':
5197                if(op1.ops.Neg) { FreeExpContents(exp); op1.ops.Neg(exp, op1); }
5198                break;
5199             // unary arithmetic increment and decrement
5200                   //OPERATOR_ALL(UNARY, ++, Inc)
5201                   //OPERATOR_ALL(UNARY, --, Dec)
5202             // unary bitwise
5203             case '~':
5204                if(op1.ops.BitNot) { FreeExpContents(exp); op1.ops.BitNot(exp, op1); }
5205                break;
5206             // unary logical negation
5207             case '!':
5208                if(op1.ops.Not) { FreeExpContents(exp); op1.ops.Not(exp, op1); }
5209                break;
5210          }
5211       }
5212       else
5213       {
5214          if(op1 && op2 && op1.type && op2.type && op1.kind != op2.kind)
5215          {
5216             if(Promote(op2, op1.kind, op1.type.isSigned))
5217                op2.kind = op1.kind, op2.ops = op1.ops;
5218             else if(Promote(op1, op2.kind, op2.type.isSigned))
5219                op1.kind = op2.kind, op1.ops = op2.ops;
5220          }
5221          switch(exp.op.op)
5222          {
5223             // binary arithmetic
5224             case '+':
5225                if(op1.ops.Add) { FreeExpContents(exp); op1.ops.Add(exp, op1, op2); }
5226                break;
5227             case '-':
5228                if(op1.ops.Sub) { FreeExpContents(exp); op1.ops.Sub(exp, op1, op2); }
5229                break;
5230             case '*':
5231                if(op1.ops.Mul) { FreeExpContents(exp); op1.ops.Mul(exp, op1, op2); }
5232                break;
5233             case '/':
5234                if(op1.ops.Div) { FreeExpContents(exp); op1.ops.Div(exp, op1, op2); }
5235                break;
5236             case '%':
5237                if(op1.ops.Mod) { FreeExpContents(exp); op1.ops.Mod(exp, op1, op2); }
5238                break;
5239             // binary arithmetic assignment
5240                   //OPERATOR_ALL(BINARY, =, Asign)
5241                   //OPERATOR_ALL(BINARY, +=, AddAsign)
5242                   //OPERATOR_ALL(BINARY, -=, SubAsign)
5243                   //OPERATOR_ALL(BINARY, *=, MulAsign)
5244                   //OPERATOR_ALL(BINARY, /=, DivAsign)
5245                   //OPERATOR_ALL(BINARY, %=, ModAsign)
5246             // binary bitwise
5247             case '&':
5248                if(exp.op.exp2)
5249                {
5250                   if(op1.ops.BitAnd) { FreeExpContents(exp); op1.ops.BitAnd(exp, op1, op2); }
5251                }
5252                break;
5253             case '|':
5254                if(op1.ops.BitOr) { FreeExpContents(exp); op1.ops.BitOr(exp, op1, op2); }
5255                break;
5256             case '^':
5257                if(op1.ops.BitXor) { FreeExpContents(exp); op1.ops.BitXor(exp, op1, op2); }
5258                break;
5259             case LEFT_OP:
5260                if(op1.ops.LShift) { FreeExpContents(exp); op1.ops.LShift(exp, op1, op2); }
5261                break;
5262             case RIGHT_OP:
5263                if(op1.ops.RShift) { FreeExpContents(exp); op1.ops.RShift(exp, op1, op2); }
5264                break;
5265             // binary bitwise assignment
5266                   //OPERATOR_INTTYPES(BINARY, &=, AndAsign)
5267                   //OPERATOR_INTTYPES(BINARY, |=, OrAsign)
5268                   //OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
5269                   //OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
5270                   //OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
5271             // binary logical equality
5272             case EQ_OP:
5273                if(op1.ops.Equ) { FreeExpContents(exp); op1.ops.Equ(exp, op1, op2); }
5274                break;
5275             case NE_OP:
5276                if(op1.ops.Nqu) { FreeExpContents(exp); op1.ops.Nqu(exp, op1, op2); }
5277                break;
5278             // binary logical
5279             case AND_OP:
5280                if(op1.ops.And) { FreeExpContents(exp); op1.ops.And(exp, op1, op2); }
5281                break;
5282             case OR_OP:
5283                if(op1.ops.Or) { FreeExpContents(exp); op1.ops.Or(exp, op1, op2); }
5284                break;
5285             // binary logical relational
5286             case '>':
5287                if(op1.ops.Grt) { FreeExpContents(exp); op1.ops.Grt(exp, op1, op2); }
5288                break;
5289             case '<':
5290                if(op1.ops.Sma) { FreeExpContents(exp); op1.ops.Sma(exp, op1, op2); }
5291                break;
5292             case GE_OP:
5293                if(op1.ops.GrtEqu) { FreeExpContents(exp); op1.ops.GrtEqu(exp, op1, op2); }
5294                break;
5295             case LE_OP:
5296                if(op1.ops.SmaEqu) { FreeExpContents(exp); op1.ops.SmaEqu(exp, op1, op2); }
5297                break;
5298          }
5299       }
5300    }
5301 }
5302
5303 void ComputeExpression(Expression exp)
5304 {
5305    char expString[10240];
5306    expString[0] = '\0';
5307 #ifdef _DEBUG
5308    PrintExpression(exp, expString);
5309 #endif
5310
5311    switch(exp.type)
5312    {
5313       case instanceExp:
5314       {
5315          ComputeInstantiation(exp);
5316          break;
5317       }
5318       /*
5319       case constantExp:
5320          break;
5321       */
5322       case opExp:
5323       {
5324          Expression exp1, exp2 = null;
5325          Operand op1 { };
5326          Operand op2 { };
5327
5328          // We don't care about operations with only exp2 (INC_OP, DEC_OP...)
5329          if(exp.op.exp2)
5330          {
5331             Expression e = exp.op.exp2;
5332
5333             while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
5334             {
5335                if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
5336                {
5337                   if(e.type == extensionCompoundExp)
5338                      e = ((Statement)e.compound.compound.statements->last).expressions->last;
5339                   else
5340                      e = e.list->last;
5341                }
5342             }
5343             if(exp.op.op == TokenType::sizeOf && e && e.expType)
5344             {
5345                if(e.type == stringExp && e.string)
5346                {
5347                   char * string = e.string;
5348                   int len = strlen(string);
5349                   char * tmp = new char[len-2+1];
5350                   len = UnescapeString(tmp, string + 1, len - 2);
5351                   delete tmp;
5352                   FreeExpContents(exp);
5353                   exp.type = constantExp;
5354                   exp.constant = PrintUInt(len + 1);
5355                }
5356                else
5357                {
5358                   Type type = e.expType;
5359                   type.refCount++;
5360                   FreeExpContents(exp);
5361                   exp.type = constantExp;
5362                   exp.constant = PrintUInt(ComputeTypeSize(type));
5363                   FreeType(type);
5364                }
5365                break;
5366             }
5367             else
5368                ComputeExpression(exp.op.exp2);
5369          }
5370          if(exp.op.exp1)
5371          {
5372             ComputeExpression(exp.op.exp1);
5373             exp1 = exp.op.exp1;
5374             exp2 = exp.op.exp2;
5375             op1 = GetOperand(exp1);
5376             if(op1.type) op1.type.refCount++;
5377             if(exp2)
5378             {
5379                op2 = GetOperand(exp2);
5380                if(op2.type) op2.type.refCount++;
5381             }
5382          }
5383          else
5384          {
5385             exp1 = exp.op.exp2;
5386             op1 = GetOperand(exp1);
5387             if(op1.type) op1.type.refCount++;
5388          }
5389
5390          CallOperator(exp, exp1, exp2, op1, op2);
5391          /*
5392          switch(exp.op.op)
5393          {
5394             // Unary operators
5395             case '&':
5396                // Also binary
5397                if(exp.op.exp1 && exp.op.exp2)
5398                {
5399                   // Binary And
5400                   if(op1.ops.BitAnd)
5401                   {
5402                      FreeExpContents(exp);
5403                      op1.ops.BitAnd(exp, op1, op2);
5404                   }
5405                }
5406                break;
5407             case '*':
5408                if(exp.op.exp1)
5409                {
5410                   if(op1.ops.Mul)
5411                   {
5412                      FreeExpContents(exp);
5413                      op1.ops.Mul(exp, op1, op2);
5414                   }
5415                }
5416                break;
5417             case '+':
5418                if(exp.op.exp1)
5419                {
5420                   if(op1.ops.Add)
5421                   {
5422                      FreeExpContents(exp);
5423                      op1.ops.Add(exp, op1, op2);
5424                   }
5425                }
5426                else
5427                {
5428                   // Provide default unary +
5429                   Expression exp2 = exp.op.exp2;
5430                   exp.op.exp2 = null;
5431                   FreeExpContents(exp);
5432                   FreeType(exp.expType);
5433                   FreeType(exp.destType);
5434
5435                   *exp = *exp2;
5436                   delete exp2;
5437                }
5438                break;
5439             case '-':
5440                if(exp.op.exp1)
5441                {
5442                   if(op1.ops.Sub)
5443                   {
5444                      FreeExpContents(exp);
5445                      op1.ops.Sub(exp, op1, op2);
5446                   }
5447                }
5448                else
5449                {
5450                   if(op1.ops.Neg)
5451                   {
5452                      FreeExpContents(exp);
5453                      op1.ops.Neg(exp, op1);
5454                   }
5455                }
5456                break;
5457             case '~':
5458                if(op1.ops.BitNot)
5459                {
5460                   FreeExpContents(exp);
5461                   op1.ops.BitNot(exp, op1);
5462                }
5463                break;
5464             case '!':
5465                if(op1.ops.Not)
5466                {
5467                   FreeExpContents(exp);
5468                   op1.ops.Not(exp, op1);
5469                }
5470                break;
5471             // Binary only operators
5472             case '/':
5473                if(op1.ops.Div)
5474                {
5475                   FreeExpContents(exp);
5476                   op1.ops.Div(exp, op1, op2);
5477                }
5478                break;
5479             case '%':
5480                if(op1.ops.Mod)
5481                {
5482                   FreeExpContents(exp);
5483                   op1.ops.Mod(exp, op1, op2);
5484                }
5485                break;
5486             case LEFT_OP:
5487                break;
5488             case RIGHT_OP:
5489                break;
5490             case '<':
5491                if(exp.op.exp1)
5492                {
5493                   if(op1.ops.Sma)
5494                   {
5495                      FreeExpContents(exp);
5496                      op1.ops.Sma(exp, op1, op2);
5497                   }
5498                }
5499                break;
5500             case '>':
5501                if(exp.op.exp1)
5502                {
5503                   if(op1.ops.Grt)
5504                   {
5505                      FreeExpContents(exp);
5506                      op1.ops.Grt(exp, op1, op2);
5507                   }
5508                }
5509                break;
5510             case LE_OP:
5511                if(exp.op.exp1)
5512                {
5513                   if(op1.ops.SmaEqu)
5514                   {
5515                      FreeExpContents(exp);
5516                      op1.ops.SmaEqu(exp, op1, op2);
5517                   }
5518                }
5519                break;
5520             case GE_OP:
5521                if(exp.op.exp1)
5522                {
5523                   if(op1.ops.GrtEqu)
5524                   {
5525                      FreeExpContents(exp);
5526                      op1.ops.GrtEqu(exp, op1, op2);
5527                   }
5528                }
5529                break;
5530             case EQ_OP:
5531                if(exp.op.exp1)
5532                {
5533                   if(op1.ops.Equ)
5534                   {
5535                      FreeExpContents(exp);
5536                      op1.ops.Equ(exp, op1, op2);
5537                   }
5538                }
5539                break;
5540             case NE_OP:
5541                if(exp.op.exp1)
5542                {
5543                   if(op1.ops.Nqu)
5544                   {
5545                      FreeExpContents(exp);
5546                      op1.ops.Nqu(exp, op1, op2);
5547                   }
5548                }
5549                break;
5550             case '|':
5551                if(op1.ops.BitOr)
5552                {
5553                   FreeExpContents(exp);
5554                   op1.ops.BitOr(exp, op1, op2);
5555                }
5556                break;
5557             case '^':
5558                if(op1.ops.BitXor)
5559                {
5560                   FreeExpContents(exp);
5561                   op1.ops.BitXor(exp, op1, op2);
5562                }
5563                break;
5564             case AND_OP:
5565                break;
5566             case OR_OP:
5567                break;
5568             case SIZEOF:
5569                FreeExpContents(exp);
5570                exp.type = constantExp;
5571                exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5572                break;
5573          }
5574          */
5575          if(op1.type) FreeType(op1.type);
5576          if(op2.type) FreeType(op2.type);
5577          break;
5578       }
5579       case bracketsExp:
5580       case extensionExpressionExp:
5581       {
5582          Expression e, n;
5583          for(e = exp.list->first; e; e = n)
5584          {
5585             n = e.next;
5586             if(!n)
5587             {
5588                OldList * list = exp.list;
5589                ComputeExpression(e);
5590                //FreeExpContents(exp);
5591                FreeType(exp.expType);
5592                FreeType(exp.destType);
5593                *exp = *e;
5594                delete e;
5595                delete list;
5596             }
5597             else
5598             {
5599                FreeExpression(e);
5600             }
5601          }
5602          break;
5603       }
5604       /*
5605
5606       case ExpIndex:
5607       {
5608          Expression e;
5609          exp.isConstant = true;
5610
5611          ComputeExpression(exp.index.exp);
5612          if(!exp.index.exp.isConstant)
5613             exp.isConstant = false;
5614
5615          for(e = exp.index.index->first; e; e = e.next)
5616          {
5617             ComputeExpression(e);
5618             if(!e.next)
5619             {
5620                // Check if this type is int
5621             }
5622             if(!e.isConstant)
5623                exp.isConstant = false;
5624          }
5625          exp.expType = Dereference(exp.index.exp.expType);
5626          break;
5627       }
5628       */
5629       case memberExp:
5630       {
5631          Expression memberExp = exp.member.exp;
5632          Identifier memberID = exp.member.member;
5633
5634          Type type;
5635          ComputeExpression(exp.member.exp);
5636          type = exp.member.exp.expType;
5637          if(type)
5638          {
5639             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);
5640             Property prop = null;
5641             DataMember member = null;
5642             Class convertTo = null;
5643             if(type.kind == subClassType && exp.member.exp.type == classExp)
5644                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
5645
5646             if(!_class)
5647             {
5648                char string[256];
5649                Symbol classSym;
5650                string[0] = '\0';
5651                PrintTypeNoConst(type, string, false, true);
5652                classSym = FindClass(string);
5653                _class = classSym ? classSym.registered : null;
5654             }
5655
5656             if(exp.member.member)
5657             {
5658                prop = eClass_FindProperty(_class, exp.member.member.string, privateModule);
5659                if(!prop)
5660                   member = eClass_FindDataMember(_class, exp.member.member.string, privateModule, null, null);
5661             }
5662             if(!prop && !member && _class && exp.member.member)
5663             {
5664                Symbol classSym = FindClass(exp.member.member.string);
5665                convertTo = _class;
5666                _class = classSym ? classSym.registered : null;
5667                prop = eClass_FindProperty(_class, convertTo.fullName, privateModule);
5668             }
5669
5670             if(prop)
5671             {
5672                if(prop.compiled)
5673                {
5674                   Type type = prop.dataType;
5675                   // TODO: Assuming same base type for units...
5676                   if(_class.type == unitClass)
5677                   {
5678                      if(type.kind == classType)
5679                      {
5680                         Class _class = type._class.registered;
5681                         if(_class.type == unitClass)
5682                         {
5683                            if(!_class.dataType)
5684                               _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5685                            type = _class.dataType;
5686                         }
5687                      }
5688                      switch(type.kind)
5689                      {
5690                         case floatType:
5691                         {
5692                            float value;
5693                            float (*Get)(float) = (void *)prop.Get;
5694                            GetFloat(exp.member.exp, &value);
5695                            exp.constant = PrintFloat(Get ? Get(value) : value);
5696                            exp.type = constantExp;
5697                            break;
5698                         }
5699                         case doubleType:
5700                         {
5701                            double value;
5702                            double (*Get)(double);
5703                            GetDouble(exp.member.exp, &value);
5704
5705                            if(convertTo)
5706                               Get = (void *)prop.Set;
5707                            else
5708                               Get = (void *)prop.Get;
5709                            exp.constant = PrintDouble(Get ? Get(value) : value);
5710                            exp.type = constantExp;
5711                            break;
5712                         }
5713                      }
5714                   }
5715                   else
5716                   {
5717                      if(convertTo)
5718                      {
5719                         Expression value = exp.member.exp;
5720                         Type type;
5721                         if(!prop.dataType)
5722                            ProcessPropertyType(prop);
5723
5724                         type = prop.dataType;
5725                         if(!type)
5726                         {
5727                             // printf("Investigate this\n");
5728                         }
5729                         else if(_class.type == structClass)
5730                         {
5731                            switch(type.kind)
5732                            {
5733                               case classType:
5734                               {
5735                                  Class propertyClass = type._class.registered;
5736                                  if(propertyClass.type == structClass && value.type == instanceExp)
5737                                  {
5738                                     void (*Set)(void *, void *) = (void *)prop.Set;
5739                                     exp.instance = Instantiation { };
5740                                     exp.instance.data = new0 byte[_class.structSize];
5741                                     exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5742                                     exp.instance.loc = exp.loc;
5743                                     exp.type = instanceExp;
5744                                     Set(exp.instance.data, value.instance.data);
5745                                     PopulateInstance(exp.instance);
5746                                  }
5747                                  break;
5748                               }
5749                               case intType:
5750                               {
5751                                  int intValue;
5752                                  void (*Set)(void *, int) = (void *)prop.Set;
5753
5754                                  exp.instance = Instantiation { };
5755                                  exp.instance.data = new0 byte[_class.structSize];
5756                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5757                                  exp.instance.loc = exp.loc;
5758                                  exp.type = instanceExp;
5759
5760                                  GetInt(value, &intValue);
5761
5762                                  Set(exp.instance.data, intValue);
5763                                  PopulateInstance(exp.instance);
5764                                  break;
5765                               }
5766                               case int64Type:
5767                               {
5768                                  int64 intValue;
5769                                  void (*Set)(void *, int64) = (void *)prop.Set;
5770
5771                                  exp.instance = Instantiation { };
5772                                  exp.instance.data = new0 byte[_class.structSize];
5773                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5774                                  exp.instance.loc = exp.loc;
5775                                  exp.type = instanceExp;
5776
5777                                  GetInt64(value, &intValue);
5778
5779                                  Set(exp.instance.data, intValue);
5780                                  PopulateInstance(exp.instance);
5781                                  break;
5782                               }
5783                               case intPtrType:
5784                               {
5785                                  // TOFIX:
5786                                  intptr intValue;
5787                                  void (*Set)(void *, intptr) = (void *)prop.Set;
5788
5789                                  exp.instance = Instantiation { };
5790                                  exp.instance.data = new0 byte[_class.structSize];
5791                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5792                                  exp.instance.loc = exp.loc;
5793                                  exp.type = instanceExp;
5794
5795                                  GetIntPtr(value, &intValue);
5796
5797                                  Set(exp.instance.data, intValue);
5798                                  PopulateInstance(exp.instance);
5799                                  break;
5800                               }
5801                               case intSizeType:
5802                               {
5803                                  // TOFIX:
5804                                  intsize intValue;
5805                                  void (*Set)(void *, intsize) = (void *)prop.Set;
5806
5807                                  exp.instance = Instantiation { };
5808                                  exp.instance.data = new0 byte[_class.structSize];
5809                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5810                                  exp.instance.loc = exp.loc;
5811                                  exp.type = instanceExp;
5812
5813                                  GetIntSize(value, &intValue);
5814
5815                                  Set(exp.instance.data, intValue);
5816                                  PopulateInstance(exp.instance);
5817                                  break;
5818                               }
5819                               case doubleType:
5820                               {
5821                                  double doubleValue;
5822                                  void (*Set)(void *, double) = (void *)prop.Set;
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.type = instanceExp;
5829
5830                                  GetDouble(value, &doubleValue);
5831
5832                                  Set(exp.instance.data, doubleValue);
5833                                  PopulateInstance(exp.instance);
5834                                  break;
5835                               }
5836                            }
5837                         }
5838                         else if(_class.type == bitClass)
5839                         {
5840                            switch(type.kind)
5841                            {
5842                               case classType:
5843                               {
5844                                  Class propertyClass = type._class.registered;
5845                                  if(propertyClass.type == structClass && value.instance.data)
5846                                  {
5847                                     unsigned int (*Set)(void *) = (void *)prop.Set;
5848                                     unsigned int bits = Set(value.instance.data);
5849                                     exp.constant = PrintHexUInt(bits);
5850                                     exp.type = constantExp;
5851                                     break;
5852                                  }
5853                                  else if(_class.type == bitClass)
5854                                  {
5855                                     unsigned int value;
5856                                     unsigned int (*Set)(unsigned int) = (void *)prop.Set;
5857                                     unsigned int bits;
5858
5859                                     GetUInt(exp.member.exp, &value);
5860                                     bits = Set(value);
5861                                     exp.constant = PrintHexUInt(bits);
5862                                     exp.type = constantExp;
5863                                  }
5864                               }
5865                            }
5866                         }
5867                      }
5868                      else
5869                      {
5870                         if(_class.type == bitClass)
5871                         {
5872                            unsigned int value;
5873                            GetUInt(exp.member.exp, &value);
5874
5875                            switch(type.kind)
5876                            {
5877                               case classType:
5878                               {
5879                                  Class _class = type._class.registered;
5880                                  if(_class.type == structClass)
5881                                  {
5882                                     void (*Get)(unsigned int, void *) = (void *)prop.Get;
5883
5884                                     exp.instance = Instantiation { };
5885                                     exp.instance.data = new0 byte[_class.structSize];
5886                                     exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5887                                     exp.instance.loc = exp.loc;
5888                                     //exp.instance.fullSet = true;
5889                                     exp.type = instanceExp;
5890                                     Get(value, exp.instance.data);
5891                                     PopulateInstance(exp.instance);
5892                                  }
5893                                  else if(_class.type == bitClass)
5894                                  {
5895                                     unsigned int (*Get)(unsigned int) = (void *)prop.Get;
5896                                     uint64 bits = Get(value);
5897                                     exp.constant = PrintHexUInt64(bits);
5898                                     exp.type = constantExp;
5899                                  }
5900                                  break;
5901                               }
5902                            }
5903                         }
5904                         else if(_class.type == structClass)
5905                         {
5906                            char * value = (exp.member.exp.type == instanceExp ) ? exp.member.exp.instance.data : null;
5907                            switch(type.kind)
5908                            {
5909                               case classType:
5910                               {
5911                                  Class _class = type._class.registered;
5912                                  if(_class.type == structClass && value)
5913                                  {
5914                                     void (*Get)(void *, void *) = (void *)prop.Get;
5915
5916                                     exp.instance = Instantiation { };
5917                                     exp.instance.data = new0 byte[_class.structSize];
5918                                     exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5919                                     exp.instance.loc = exp.loc;
5920                                     //exp.instance.fullSet = true;
5921                                     exp.type = instanceExp;
5922                                     Get(value, exp.instance.data);
5923                                     PopulateInstance(exp.instance);
5924                                  }
5925                                  break;
5926                               }
5927                            }
5928                         }
5929                         /*else
5930                         {
5931                            char * value = exp.member.exp.instance.data;
5932                            switch(type.kind)
5933                            {
5934                               case classType:
5935                               {
5936                                  Class _class = type._class.registered;
5937                                  if(_class.type == normalClass)
5938                                  {
5939                                     void *(*Get)(void *) = (void *)prop.Get;
5940
5941                                     exp.instance = Instantiation { };
5942                                     exp.instance._class = MkSpecifierName(_class.fullName); //MkClassName(_class.fullName);
5943                                     exp.type = instanceExp;
5944                                     exp.instance.data = Get(value, exp.instance.data);
5945                                  }
5946                                  break;
5947                               }
5948                            }
5949                         }
5950                         */
5951                      }
5952                   }
5953                }
5954                else
5955                {
5956                   exp.isConstant = false;
5957                }
5958             }
5959             else if(member)
5960             {
5961             }
5962          }
5963
5964          if(exp.type != ExpressionType::memberExp)
5965          {
5966             FreeExpression(memberExp);
5967             FreeIdentifier(memberID);
5968          }
5969          break;
5970       }
5971       case typeSizeExp:
5972       {
5973          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
5974          FreeExpContents(exp);
5975          exp.constant = PrintUInt(ComputeTypeSize(type));
5976          exp.type = constantExp;
5977          FreeType(type);
5978          break;
5979       }
5980       case classSizeExp:
5981       {
5982          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
5983          if(classSym && classSym.registered)
5984          {
5985             if(classSym.registered.fixed)
5986             {
5987                FreeSpecifier(exp._class);
5988                exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
5989                exp.type = constantExp;
5990             }
5991             else
5992             {
5993                char className[1024];
5994                strcpy(className, "__ecereClass_");
5995                FullClassNameCat(className, classSym.string, true);
5996                MangleClassName(className);
5997
5998                DeclareClass(classSym, className);
5999
6000                FreeExpContents(exp);
6001                exp.type = pointerExp;
6002                exp.member.exp = MkExpIdentifier(MkIdentifier(className));
6003                exp.member.member = MkIdentifier("structSize");
6004             }
6005          }
6006          break;
6007       }
6008       case castExp:
6009       //case constantExp:
6010       {
6011          Type type;
6012          Expression e = exp;
6013          if(exp.type == castExp)
6014          {
6015             if(exp.cast.exp)
6016                ComputeExpression(exp.cast.exp);
6017             e = exp.cast.exp;
6018          }
6019          if(e && exp.expType)
6020          {
6021             /*if(exp.destType)
6022                type = exp.destType;
6023             else*/
6024                type = exp.expType;
6025             if(type.kind == classType)
6026             {
6027                Class _class = type._class.registered;
6028                if(_class && (_class.type == unitClass || _class.type == bitClass))
6029                {
6030                   if(!_class.dataType)
6031                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
6032                   type = _class.dataType;
6033                }
6034             }
6035
6036             switch(type.kind)
6037             {
6038                case _BoolType:
6039                case charType:
6040                   if(type.isSigned)
6041                   {
6042                      char value = 0;
6043                      if(GetChar(e, &value))
6044                      {
6045                         FreeExpContents(exp);
6046                         exp.constant = PrintChar(value);
6047                         exp.type = constantExp;
6048                      }
6049                   }
6050                   else
6051                   {
6052                      unsigned char value = 0;
6053                      if(GetUChar(e, &value))
6054                      {
6055                         FreeExpContents(exp);
6056                         exp.constant = PrintUChar(value);
6057                         exp.type = constantExp;
6058                      }
6059                   }
6060                   break;
6061                case shortType:
6062                   if(type.isSigned)
6063                   {
6064                      short value = 0;
6065                      if(GetShort(e, &value))
6066                      {
6067                         FreeExpContents(exp);
6068                         exp.constant = PrintShort(value);
6069                         exp.type = constantExp;
6070                      }
6071                   }
6072                   else
6073                   {
6074                      unsigned short value = 0;
6075                      if(GetUShort(e, &value))
6076                      {
6077                         FreeExpContents(exp);
6078                         exp.constant = PrintUShort(value);
6079                         exp.type = constantExp;
6080                      }
6081                   }
6082                   break;
6083                case intType:
6084                   if(type.isSigned)
6085                   {
6086                      int value = 0;
6087                      if(GetInt(e, &value))
6088                      {
6089                         FreeExpContents(exp);
6090                         exp.constant = PrintInt(value);
6091                         exp.type = constantExp;
6092                      }
6093                   }
6094                   else
6095                   {
6096                      unsigned int value = 0;
6097                      if(GetUInt(e, &value))
6098                      {
6099                         FreeExpContents(exp);
6100                         exp.constant = PrintUInt(value);
6101                         exp.type = constantExp;
6102                      }
6103                   }
6104                   break;
6105                case int64Type:
6106                   if(type.isSigned)
6107                   {
6108                      int64 value = 0;
6109                      if(GetInt64(e, &value))
6110                      {
6111                         FreeExpContents(exp);
6112                         exp.constant = PrintInt64(value);
6113                         exp.type = constantExp;
6114                      }
6115                   }
6116                   else
6117                   {
6118                      uint64 value = 0;
6119                      if(GetUInt64(e, &value))
6120                      {
6121                         FreeExpContents(exp);
6122                         exp.constant = PrintUInt64(value);
6123                         exp.type = constantExp;
6124                      }
6125                   }
6126                   break;
6127                case intPtrType:
6128                   if(type.isSigned)
6129                   {
6130                      intptr value = 0;
6131                      if(GetIntPtr(e, &value))
6132                      {
6133                         FreeExpContents(exp);
6134                         exp.constant = PrintInt64((int64)value);
6135                         exp.type = constantExp;
6136                      }
6137                   }
6138                   else
6139                   {
6140                      uintptr value = 0;
6141                      if(GetUIntPtr(e, &value))
6142                      {
6143                         FreeExpContents(exp);
6144                         exp.constant = PrintUInt64((uint64)value);
6145                         exp.type = constantExp;
6146                      }
6147                   }
6148                   break;
6149                case intSizeType:
6150                   if(type.isSigned)
6151                   {
6152                      intsize value = 0;
6153                      if(GetIntSize(e, &value))
6154                      {
6155                         FreeExpContents(exp);
6156                         exp.constant = PrintInt64((int64)value);
6157                         exp.type = constantExp;
6158                      }
6159                   }
6160                   else
6161                   {
6162                      uintsize value = 0;
6163                      if(GetUIntSize(e, &value))
6164                      {
6165                         FreeExpContents(exp);
6166                         exp.constant = PrintUInt64((uint64)value);
6167                         exp.type = constantExp;
6168                      }
6169                   }
6170                   break;
6171                case floatType:
6172                {
6173                   float value = 0;
6174                   if(GetFloat(e, &value))
6175                   {
6176                      FreeExpContents(exp);
6177                      exp.constant = PrintFloat(value);
6178                      exp.type = constantExp;
6179                   }
6180                   break;
6181                }
6182                case doubleType:
6183                {
6184                   double value = 0;
6185                   if(GetDouble(e, &value))
6186                   {
6187                      FreeExpContents(exp);
6188                      exp.constant = PrintDouble(value);
6189                      exp.type = constantExp;
6190                   }
6191                   break;
6192                }
6193             }
6194          }
6195          break;
6196       }
6197       case conditionExp:
6198       {
6199          Operand op1 { };
6200          Operand op2 { };
6201          Operand op3 { };
6202
6203          if(exp.cond.exp)
6204             // Caring only about last expression for now...
6205             ComputeExpression(exp.cond.exp->last);
6206          if(exp.cond.elseExp)
6207             ComputeExpression(exp.cond.elseExp);
6208          if(exp.cond.cond)
6209             ComputeExpression(exp.cond.cond);
6210
6211          op1 = GetOperand(exp.cond.cond);
6212          if(op1.type) op1.type.refCount++;
6213          op2 = GetOperand(exp.cond.exp->last);
6214          if(op2.type) op2.type.refCount++;
6215          op3 = GetOperand(exp.cond.elseExp);
6216          if(op3.type) op3.type.refCount++;
6217
6218          if(op1.ops.Cond) { FreeExpContents(exp); op1.ops.Cond(exp, op1, op2, op3); }
6219          if(op1.type) FreeType(op1.type);
6220          if(op2.type) FreeType(op2.type);
6221          if(op3.type) FreeType(op3.type);
6222          break;
6223       }
6224    }
6225 }
6226
6227 static bool CheckExpressionType(Expression exp, Type destType, bool skipUnitBla)
6228 {
6229    bool result = true;
6230    if(destType)
6231    {
6232       OldList converts { };
6233       Conversion convert;
6234
6235       if(destType.kind == voidType)
6236          return false;
6237
6238       if(!MatchTypeExpression(exp, destType, &converts, skipUnitBla))
6239          result = false;
6240       if(converts.count)
6241       {
6242          // for(convert = converts.last; convert; convert = convert.prev)
6243          for(convert = converts.first; convert; convert = convert.next)
6244          {
6245             bool empty = !(convert.isGet ? (void *)convert.convert.Get : (void *)convert.convert.Set);
6246             if(!empty)
6247             {
6248                Expression newExp { };
6249                ClassObjectType objectType = exp.expType ? exp.expType.classObjectType : none;
6250
6251                // TODO: Check this...
6252                *newExp = *exp;
6253                newExp.destType = null;
6254
6255                if(convert.isGet)
6256                {
6257                   // [exp].ColorRGB
6258                   exp.type = memberExp;
6259                   exp.addedThis = true;
6260                   exp.member.exp = newExp;
6261                   FreeType(exp.member.exp.expType);
6262
6263                   exp.member.exp.expType = MkClassType(convert.convert._class.fullName);
6264                   exp.member.exp.expType.classObjectType = objectType;
6265                   exp.member.member = MkIdentifier(convert.convert.dataTypeString);
6266                   exp.member.memberType = propertyMember;
6267                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6268                   // TESTING THIS... for (int)degrees
6269                   exp.needCast = true;
6270                   if(exp.expType) exp.expType.refCount++;
6271                   ApplyAnyObjectLogic(exp.member.exp);
6272                }
6273                else
6274                {
6275
6276                   /*if(exp.isConstant)
6277                   {
6278                      // Color { ColorRGB = [exp] };
6279                      exp.type = instanceExp;
6280                      exp.instance = MkInstantiation(MkSpecifierName((convert.convert._class.fullName), //MkClassName(convert.convert._class.fullName),
6281                         null, MkListOne(MkMembersInitList(MkListOne(MkMemberInit(
6282                         MkListOne(MkIdentifier(convert.convert.dataTypeString)), newExp)))));
6283                   }
6284                   else*/
6285                   {
6286                      // If not constant, don't turn it yet into an instantiation
6287                      // (Go through the deep members system first)
6288                      exp.type = memberExp;
6289                      exp.addedThis = true;
6290                      exp.member.exp = newExp;
6291
6292                      // ADDED THIS HERE TO SOLVE PROPERTY ISSUES WITH NOHEAD CLASSES
6293                      if(/*!notByReference && */newExp.expType && newExp.expType.kind == classType && newExp.expType._class && newExp.expType._class.registered &&
6294                         newExp.expType._class.registered.type == noHeadClass)
6295                      {
6296                         newExp.byReference = true;
6297                      }
6298
6299                      FreeType(exp.member.exp.expType);
6300                      /*exp.member.exp.expType = convert.convert.dataType;
6301                      if(convert.convert.dataType) convert.convert.dataType.refCount++;*/
6302                      exp.member.exp.expType = null;
6303                      if(convert.convert.dataType)
6304                      {
6305                         exp.member.exp.expType = { };
6306                         CopyTypeInto(exp.member.exp.expType, convert.convert.dataType);
6307                         exp.member.exp.expType.refCount = 1;
6308                         exp.member.exp.expType.classObjectType = objectType;
6309                         ApplyAnyObjectLogic(exp.member.exp);
6310                      }
6311
6312                      exp.member.member = MkIdentifier(convert.convert._class.fullName);
6313                      exp.member.memberType = reverseConversionMember;
6314                      exp.expType = convert.resultType ? convert.resultType :
6315                         MkClassType(convert.convert._class.fullName);
6316                      exp.needCast = true;
6317                      if(convert.resultType) convert.resultType.refCount++;
6318                   }
6319                }
6320             }
6321             else
6322             {
6323                FreeType(exp.expType);
6324                if(convert.isGet)
6325                {
6326                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6327                   exp.needCast = true;
6328                   if(exp.expType) exp.expType.refCount++;
6329                }
6330                else
6331                {
6332                   exp.expType = convert.resultType ? convert.resultType : MkClassType(convert.convert._class.fullName);
6333                   exp.needCast = true;
6334                   if(convert.resultType)
6335                      convert.resultType.refCount++;
6336                }
6337             }
6338          }
6339          if(exp.isConstant && inCompiler)
6340             ComputeExpression(exp);
6341
6342          converts.Free(FreeConvert);
6343       }
6344
6345       if(!result && exp.expType && converts.count)      // TO TEST: Added converts.count here to avoid a double warning with function type
6346       {
6347          result = MatchTypes(exp.expType, exp.destType, null, null, null, true, true, false, false);
6348       }
6349       if(!result && exp.expType && exp.destType)
6350       {
6351          if((exp.destType.kind == classType && exp.expType.kind == pointerType &&
6352              exp.expType.type.kind == classType && exp.expType.type._class == exp.destType._class && exp.destType._class.registered && exp.destType._class.registered.type == structClass) ||
6353             (exp.expType.kind == classType && exp.destType.kind == pointerType &&
6354             exp.destType.type.kind == classType && exp.destType.type._class == exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass))
6355             result = true;
6356       }
6357    }
6358    // if(result) CheckTemplateTypes(exp);
6359    return result;
6360 }
6361
6362 void CheckTemplateTypes(Expression exp)
6363 {
6364    if(exp.destType && exp.destType.passAsTemplate && exp.expType && exp.expType.kind != templateType && !exp.expType.passAsTemplate)
6365    {
6366       Expression newExp { };
6367       Statement compound;
6368       Context context;
6369       *newExp = *exp;
6370       if(exp.destType) exp.destType.refCount++;
6371       if(exp.expType)  exp.expType.refCount++;
6372       newExp.prev = null;
6373       newExp.next = null;
6374
6375       switch(exp.expType.kind)
6376       {
6377          case doubleType:
6378             if(exp.destType.classObjectType)
6379             {
6380                // We need to pass the address, just pass it along (Undo what was done above)
6381                if(exp.destType) exp.destType.refCount--;
6382                if(exp.expType)  exp.expType.refCount--;
6383                delete newExp;
6384             }
6385             else
6386             {
6387                // If we're looking for value:
6388                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6389                OldList * specs;
6390                OldList * unionDefs = MkList();
6391                OldList * statements = MkList();
6392                context = PushContext();
6393                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6394                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6395                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6396                exp.type = extensionCompoundExp;
6397                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6398                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")), '=', newExp))));
6399                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
6400                exp.compound.compound.context = context;
6401                PopContext(context);
6402             }
6403             break;
6404          default:
6405             exp.type = castExp;
6406             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6407             exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6408             break;
6409       }
6410    }
6411    else if(exp.expType && exp.expType.passAsTemplate && exp.destType && exp.usage.usageGet && exp.destType.kind != templateType && !exp.destType.passAsTemplate)
6412    {
6413       Expression newExp { };
6414       Statement compound;
6415       Context context;
6416       *newExp = *exp;
6417       if(exp.destType) exp.destType.refCount++;
6418       if(exp.expType)  exp.expType.refCount++;
6419       newExp.prev = null;
6420       newExp.next = null;
6421
6422       switch(exp.expType.kind)
6423       {
6424          case doubleType:
6425             if(exp.destType.classObjectType)
6426             {
6427                // We need to pass the address, just pass it along (Undo what was done above)
6428                if(exp.destType) exp.destType.refCount--;
6429                if(exp.expType)  exp.expType.refCount--;
6430                delete newExp;
6431             }
6432             else
6433             {
6434                // If we're looking for value:
6435                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6436                OldList * specs;
6437                OldList * unionDefs = MkList();
6438                OldList * statements = MkList();
6439                context = PushContext();
6440                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6441                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6442                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6443                exp.type = extensionCompoundExp;
6444                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6445                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
6446                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")))));
6447                exp.compound.compound.context = context;
6448                PopContext(context);
6449             }
6450             break;
6451          case classType:
6452          {
6453             if(exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass)
6454             {
6455                exp.type = bracketsExp;
6456                exp.list = MkListOne(MkExpOp(null, '*', MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)),
6457                   MkDeclaratorPointer(MkPointer(null, null), null)), newExp)));
6458                ProcessExpressionType(exp.list->first);
6459                break;
6460             }
6461             else
6462             {
6463                exp.type = bracketsExp;
6464                exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)), null), newExp));
6465                newExp.needCast = true;
6466                ProcessExpressionType(exp.list->first);
6467                break;
6468             }
6469          }
6470          default:
6471          {
6472             if(exp.expType.kind == templateType)
6473             {
6474                Type type = ProcessTemplateParameterType(exp.expType.templateParameter);
6475                if(type)
6476                {
6477                   FreeType(exp.destType);
6478                   FreeType(exp.expType);
6479                   delete newExp;
6480                   break;
6481                }
6482             }
6483             if(newExp.type == memberExp && newExp.member.memberType == dataMember)
6484             {
6485                exp.type = opExp;
6486                exp.op.op = '*';
6487                exp.op.exp1 = null;
6488                exp.op.exp2 = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uint64")), MkDeclaratorPointer(MkPointer(null, null), null)),
6489                   MkExpBrackets(MkListOne(MkExpOp(null, '&', newExp))));
6490             }
6491             else
6492             {
6493                char typeString[1024];
6494                Declarator decl;
6495                OldList * specs = MkList();
6496                typeString[0] = '\0';
6497                PrintType(exp.expType, typeString, false, false);
6498                decl = SpecDeclFromString(typeString, specs, null);
6499
6500                exp.type = castExp;
6501                //exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6502                exp.cast.typeName = MkTypeName(specs, decl);
6503                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6504                exp.cast.exp.needCast = true;
6505             }
6506             break;
6507          }
6508       }
6509    }
6510 }
6511 // TODO: The Symbol tree should be reorganized by namespaces
6512 // Name Space:
6513 //    - Tree of all symbols within (stored without namespace)
6514 //    - Tree of sub-namespaces
6515
6516 static Symbol ScanWithNameSpace(BinaryTree tree, char * nameSpace, char * name)
6517 {
6518    int nsLen = strlen(nameSpace);
6519    Symbol symbol;
6520    // Start at the name space prefix
6521    for(symbol = (Symbol)tree.FindPrefix(nameSpace); symbol; symbol = (Symbol)((BTNode)symbol).next)
6522    {
6523       char * s = symbol.string;
6524       if(!strncmp(s, nameSpace, nsLen))
6525       {
6526          // This supports e.g. matching ecere::Socket to ecere::net::Socket
6527          int c;
6528          char * namePart;
6529          for(c = strlen(s)-1; c >= 0; c--)
6530             if(s[c] == ':')
6531                break;
6532
6533          namePart = s+c+1;
6534          if(!strcmp(namePart, name))
6535          {
6536             // TODO: Error on ambiguity
6537             return symbol;
6538          }
6539       }
6540       else
6541          break;
6542    }
6543    return null;
6544 }
6545
6546 static Symbol FindWithNameSpace(BinaryTree tree, char * name)
6547 {
6548    int c;
6549    char nameSpace[1024];
6550    char * namePart;
6551    bool gotColon = false;
6552
6553    nameSpace[0] = '\0';
6554    for(c = strlen(name)-1; c >= 0; c--)
6555       if(name[c] == ':')
6556       {
6557          gotColon = true;
6558          break;
6559       }
6560
6561    namePart = name+c+1;
6562    while(c >= 0 && name[c] == ':') c--;
6563    if(c >= 0)
6564    {
6565       // Try an exact match first
6566       Symbol symbol = (Symbol)tree.FindString(name);
6567       if(symbol)
6568          return symbol;
6569
6570       // Namespace specified
6571       memcpy(nameSpace, name, c + 1);
6572       nameSpace[c+1] = 0;
6573
6574       return ScanWithNameSpace(tree, nameSpace, namePart);
6575    }
6576    else if(gotColon)
6577    {
6578       // Looking for a global symbol, e.g. ::Sleep()
6579       Symbol symbol = (Symbol)tree.FindString(namePart);
6580       return symbol;
6581    }
6582    else
6583    {
6584       // Name only (no namespace specified)
6585       Symbol symbol = (Symbol)tree.FindString(namePart);
6586       if(symbol)
6587          return symbol;
6588       return ScanWithNameSpace(tree, "", namePart);
6589    }
6590    return null;
6591 }
6592
6593 static void ProcessDeclaration(Declaration decl);
6594
6595 /*static */Symbol FindSymbol(char * name, Context startContext, Context endContext, bool isStruct, bool globalNameSpace)
6596 {
6597 #ifdef _DEBUG
6598    //Time startTime = GetTime();
6599 #endif
6600    // Optimize this later? Do this before/less?
6601    Context ctx;
6602    Symbol symbol = null;
6603    // First, check if the identifier is declared inside the function
6604    //for(ctx = curContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6605
6606    for(ctx = startContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6607    {
6608       if(ctx == globalContext && !globalNameSpace && ctx.hasNameSpace)
6609       {
6610          symbol = null;
6611          if(thisNameSpace)
6612          {
6613             char curName[1024];
6614             strcpy(curName, thisNameSpace);
6615             strcat(curName, "::");
6616             strcat(curName, name);
6617             // Try to resolve in current namespace first
6618             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, curName);
6619          }
6620          if(!symbol)
6621             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, name);
6622       }
6623       else
6624          symbol = (Symbol)(isStruct ? ctx.structSymbols : ctx.symbols).FindString(name);
6625
6626       if(symbol || ctx == endContext) break;
6627    }
6628    if(inCompiler && curExternal && symbol && ctx == globalContext && curExternal.symbol && symbol.id > curExternal.symbol.idCode && symbol.pointerExternal)
6629    {
6630       if(symbol.pointerExternal.type == functionExternal)
6631       {
6632          FunctionDefinition function = symbol.pointerExternal.function;
6633
6634          // Modified this recently...
6635          Context tmpContext = curContext;
6636          curContext = null;
6637          symbol.pointerExternal = MkExternalDeclaration(MkDeclaration(CopyList(function.specifiers, CopySpecifier), MkListOne(MkInitDeclarator(CopyDeclarator(function.declarator), null))));
6638          curContext = tmpContext;
6639
6640          symbol.pointerExternal.symbol = symbol;
6641
6642          // TESTING THIS:
6643          DeclareType(symbol.type, true, true);
6644
6645          ast->Insert(curExternal.prev, symbol.pointerExternal);
6646
6647          symbol.id = curExternal.symbol.idCode;
6648
6649       }
6650       else if(symbol.pointerExternal.type == declarationExternal && curExternal.symbol.idCode < symbol.pointerExternal.symbol.id) // Added id comparison because Global Function prototypes were broken
6651       {
6652          ast->Move(symbol.pointerExternal, curExternal.prev);
6653          symbol.id = curExternal.symbol.idCode;
6654       }
6655    }
6656 #ifdef _DEBUG
6657    //findSymbolTotalTime += GetTime() - startTime;
6658 #endif
6659    return symbol;
6660 }
6661
6662 static void GetTypeSpecs(Type type, OldList * specs)
6663 {
6664    if(!type.isSigned && type.kind != intPtrType && type.kind != intSizeType) ListAdd(specs, MkSpecifier(UNSIGNED));
6665    switch(type.kind)
6666    {
6667       case classType:
6668       {
6669          if(type._class.registered)
6670          {
6671             if(!type._class.registered.dataType)
6672                type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
6673             GetTypeSpecs(type._class.registered.dataType, specs);
6674          }
6675          break;
6676       }
6677       case doubleType: ListAdd(specs, MkSpecifier(DOUBLE)); break;
6678       case floatType: ListAdd(specs, MkSpecifier(FLOAT)); break;
6679       case charType: ListAdd(specs, MkSpecifier(CHAR)); break;
6680       case _BoolType: ListAdd(specs, MkSpecifier(_BOOL)); break;
6681       case shortType: ListAdd(specs, MkSpecifier(SHORT)); break;
6682       case int64Type: ListAdd(specs, MkSpecifier(INT64)); break;
6683       case intPtrType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intptr" : "uintptr")); break;
6684       case intSizeType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intsize" : "uintsize")); break;
6685       case intType:
6686       default:
6687          ListAdd(specs, MkSpecifier(INT)); break;
6688    }
6689 }
6690
6691 static void PrintArraySize(Type arrayType, char * string)
6692 {
6693    char size[256];
6694    size[0] = '\0';
6695    strcat(size, "[");
6696    if(arrayType.enumClass)
6697       strcat(size, arrayType.enumClass.string);
6698    else if(arrayType.arraySizeExp)
6699       PrintExpression(arrayType.arraySizeExp, size);
6700    strcat(size, "]");
6701    strcat(string, size);
6702 }
6703
6704 // WARNING : This function expects a null terminated string since it recursively concatenate...
6705 static void PrintTypeSpecs(Type type, char * string, bool fullName, bool printConst)
6706 {
6707    if(type)
6708    {
6709       if(printConst && type.constant)
6710          strcat(string, "const ");
6711       switch(type.kind)
6712       {
6713          case classType:
6714          {
6715             Symbol c = type._class;
6716             // TODO: typed_object does not fully qualify the type, as it may have taken up an actual class (Stored in _class) from overriding
6717             //       look into merging with thisclass ?
6718             if(type.classObjectType == typedObject)
6719                strcat(string, "typed_object");
6720             else if(type.classObjectType == anyObject)
6721                strcat(string, "any_object");
6722             else
6723             {
6724                if(c && c.string)
6725                   strcat(string, (fullName || !c.registered) ? c.string : c.registered.name);
6726             }
6727             if(type.byReference)
6728                strcat(string, " &");
6729             break;
6730          }
6731          case voidType: strcat(string, "void"); break;
6732          case intType:  strcat(string, type.isSigned ? "int" : "uint"); break;
6733          case int64Type:  strcat(string, type.isSigned ? "int64" : "uint64"); break;
6734          case intPtrType:  strcat(string, type.isSigned ? "intptr" : "uintptr"); break;
6735          case intSizeType:  strcat(string, type.isSigned ? "intsize" : "uintsize"); break;
6736          case charType: strcat(string, type.isSigned ? "char" : "byte"); break;
6737          case _BoolType: strcat(string, "_Bool"); break;
6738          case shortType: strcat(string, type.isSigned ? "short" : "uint16"); break;
6739          case floatType: strcat(string, "float"); break;
6740          case doubleType: strcat(string, "double"); break;
6741          case structType:
6742             if(type.enumName)
6743             {
6744                strcat(string, "struct ");
6745                strcat(string, type.enumName);
6746             }
6747             else if(type.typeName)
6748                strcat(string, type.typeName);
6749             else
6750             {
6751                Type member;
6752                strcat(string, "struct { ");
6753                for(member = type.members.first; member; member = member.next)
6754                {
6755                   PrintType(member, string, true, fullName);
6756                   strcat(string,"; ");
6757                }
6758                strcat(string,"}");
6759             }
6760             break;
6761          case unionType:
6762             if(type.enumName)
6763             {
6764                strcat(string, "union ");
6765                strcat(string, type.enumName);
6766             }
6767             else if(type.typeName)
6768                strcat(string, type.typeName);
6769             else
6770             {
6771                strcat(string, "union ");
6772                strcat(string,"(unnamed)");
6773             }
6774             break;
6775          case enumType:
6776             if(type.enumName)
6777             {
6778                strcat(string, "enum ");
6779                strcat(string, type.enumName);
6780             }
6781             else if(type.typeName)
6782                strcat(string, type.typeName);
6783             else
6784                strcat(string, "int"); // "enum");
6785             break;
6786          case ellipsisType:
6787             strcat(string, "...");
6788             break;
6789          case subClassType:
6790             strcat(string, "subclass(");
6791             strcat(string, type._class ? type._class.string : "int");
6792             strcat(string, ")");
6793             break;
6794          case templateType:
6795             strcat(string, type.templateParameter.identifier.string);
6796             break;
6797          case thisClassType:
6798             strcat(string, "thisclass");
6799             break;
6800          case vaListType:
6801             strcat(string, "__builtin_va_list");
6802             break;
6803       }
6804    }
6805 }
6806
6807 static void PrintName(Type type, char * string, bool fullName)
6808 {
6809    if(type.name && type.name[0])
6810    {
6811       if(fullName)
6812          strcat(string, type.name);
6813       else
6814       {
6815          char * name = RSearchString(type.name, "::", strlen(type.name), true, false);
6816          if(name) name += 2; else name = type.name;
6817          strcat(string, name);
6818       }
6819    }
6820 }
6821
6822 static void PrintAttribs(Type type, char * string)
6823 {
6824    if(type)
6825    {
6826       if(type.dllExport)   strcat(string, "dllexport ");
6827       if(type.attrStdcall) strcat(string, "stdcall ");
6828    }
6829 }
6830
6831 static void PrePrintType(Type type, char * string, bool fullName, Type parentType, bool printConst)
6832 {
6833    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
6834    {
6835       Type attrType = null;
6836       if((type.kind == functionType || type.kind == methodType) && (!parentType || parentType.kind != pointerType))
6837          PrintAttribs(type, string);
6838       if(printConst && type.constant && (type.kind == functionType || type.kind == methodType))
6839          strcat(string, " const");
6840       PrePrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName, type, printConst);
6841       if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
6842          strcat(string, " (");
6843       if(type.kind == pointerType)
6844       {
6845          if(type.type.kind == functionType || type.type.kind == methodType)
6846             PrintAttribs(type.type, string);
6847       }
6848       if(type.kind == pointerType)
6849       {
6850          if(type.type.kind == functionType || type.type.kind == methodType || type.type.kind == arrayType)
6851             strcat(string, "*");
6852          else
6853             strcat(string, " *");
6854       }
6855       if(printConst && type.constant && type.kind == pointerType)
6856          strcat(string, " const");
6857    }
6858    else
6859       PrintTypeSpecs(type, string, fullName, printConst);
6860 }
6861
6862 static void PostPrintType(Type type, char * string, bool fullName)
6863 {
6864    if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
6865       strcat(string, ")");
6866    if(type.kind == arrayType)
6867       PrintArraySize(type, string);
6868    else if(type.kind == functionType)
6869    {
6870       Type param;
6871       strcat(string, "(");
6872       for(param = type.params.first; param; param = param.next)
6873       {
6874          PrintType(param, string, true, fullName);
6875          if(param.next) strcat(string, ", ");
6876       }
6877       strcat(string, ")");
6878    }
6879    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
6880       PostPrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName);
6881 }
6882
6883 // *****
6884 // TODO: Add a max buffer size to avoid overflows. This function is used with static size char arrays.
6885 // *****
6886 static void _PrintType(Type type, char * string, bool printName, bool fullName, bool printConst)
6887 {
6888    PrePrintType(type, string, fullName, null, printConst);
6889
6890    if(type.thisClass || (printName && type.name && type.name[0]))
6891       strcat(string, " ");
6892    if(/*(type.kind == methodType || type.kind == functionType) && */(type.thisClass || type.staticMethod))
6893    {
6894       Symbol _class = type.thisClass;
6895       if((type.classObjectType == typedObject || type.classObjectType == classPointer) || (_class && !strcmp(_class.string, "class")))
6896       {
6897          if(type.classObjectType == classPointer)
6898             strcat(string, "class");
6899          else
6900             strcat(string, type.byReference ? "typed_object&" : "typed_object");
6901       }
6902       else if(_class && _class.string)
6903       {
6904          String s = _class.string;
6905          if(fullName)
6906             strcat(string, s);
6907          else
6908          {
6909             char * name = RSearchString(s, "::", strlen(s), true, false);
6910             if(name) name += 2; else name = s;
6911             strcat(string, name);
6912          }
6913       }
6914       strcat(string, "::");
6915    }
6916
6917    if(printName && type.name)
6918       PrintName(type, string, fullName);
6919    PostPrintType(type, string, fullName);
6920    if(type.bitFieldCount)
6921    {
6922       char count[100];
6923       sprintf(count, ":%d", type.bitFieldCount);
6924       strcat(string, count);
6925    }
6926 }
6927
6928 void PrintType(Type type, char * string, bool printName, bool fullName)
6929 {
6930    _PrintType(type, string, printName, fullName, true);
6931 }
6932
6933 void PrintTypeNoConst(Type type, char * string, bool printName, bool fullName)
6934 {
6935    _PrintType(type, string, printName, fullName, false);
6936 }
6937
6938 static Type FindMember(Type type, char * string)
6939 {
6940    Type memberType;
6941    for(memberType = type.members.first; memberType; memberType = memberType.next)
6942    {
6943       if(!memberType.name)
6944       {
6945          Type subType = FindMember(memberType, string);
6946          if(subType)
6947             return subType;
6948       }
6949       else if(!strcmp(memberType.name, string))
6950          return memberType;
6951    }
6952    return null;
6953 }
6954
6955 Type FindMemberAndOffset(Type type, char * string, uint * offset)
6956 {
6957    Type memberType;
6958    for(memberType = type.members.first; memberType; memberType = memberType.next)
6959    {
6960       if(!memberType.name)
6961       {
6962          Type subType = FindMember(memberType, string);
6963          if(subType)
6964          {
6965             *offset += memberType.offset;
6966             return subType;
6967          }
6968       }
6969       else if(!strcmp(memberType.name, string))
6970       {
6971          *offset += memberType.offset;
6972          return memberType;
6973       }
6974    }
6975    return null;
6976 }
6977
6978 public bool GetParseError() { return parseError; }
6979
6980 Expression ParseExpressionString(char * expression)
6981 {
6982    parseError = false;
6983
6984    fileInput = TempFile { };
6985    fileInput.Write(expression, 1, strlen(expression));
6986    fileInput.Seek(0, start);
6987
6988    echoOn = false;
6989    parsedExpression = null;
6990    resetScanner();
6991    expression_yyparse();
6992    delete fileInput;
6993
6994    return parsedExpression;
6995 }
6996
6997 static bool ResolveIdWithClass(Expression exp, Class _class, bool skipIDClassCheck)
6998 {
6999    Identifier id = exp.identifier;
7000    Method method = null;
7001    Property prop = null;
7002    DataMember member = null;
7003    ClassProperty classProp = null;
7004
7005    if(_class && _class.type == enumClass)
7006    {
7007       NamedLink value = null;
7008       Class enumClass = eSystem_FindClass(privateModule, "enum");
7009       if(enumClass)
7010       {
7011          Class baseClass;
7012          for(baseClass = _class; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
7013          {
7014             EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
7015             for(value = e.values.first; value; value = value.next)
7016             {
7017                if(!strcmp(value.name, id.string))
7018                   break;
7019             }
7020             if(value)
7021             {
7022                char constant[256];
7023
7024                FreeExpContents(exp);
7025
7026                exp.type = constantExp;
7027                exp.isConstant = true;
7028                if(!strcmp(baseClass.dataTypeString, "int"))
7029                   sprintf(constant, "%d",(int)value.data);
7030                else
7031                   sprintf(constant, "0x%X",(int)value.data);
7032                exp.constant = CopyString(constant);
7033                //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
7034                exp.expType = MkClassType(baseClass.fullName);
7035                break;
7036             }
7037          }
7038       }
7039       if(value)
7040          return true;
7041    }
7042    if((method = eClass_FindMethod(_class, id.string, privateModule)))
7043    {
7044       ProcessMethodType(method);
7045       exp.expType = Type
7046       {
7047          refCount = 1;
7048          kind = methodType;
7049          method = method;
7050          // Crash here?
7051          // TOCHECK: Put it back to what it was...
7052          // methodClass = _class;
7053          methodClass = (skipIDClassCheck || (id && id._class)) ? _class : null;
7054       };
7055       //id._class = null;
7056       return true;
7057    }
7058    else if((prop = eClass_FindProperty(_class, id.string, privateModule)))
7059    {
7060       if(!prop.dataType)
7061          ProcessPropertyType(prop);
7062       exp.expType = prop.dataType;
7063       if(prop.dataType) prop.dataType.refCount++;
7064       return true;
7065    }
7066    else if((member = eClass_FindDataMember(_class, id.string, privateModule, null, null)))
7067    {
7068       if(!member.dataType)
7069          member.dataType = ProcessTypeString(member.dataTypeString, false);
7070       exp.expType = member.dataType;
7071       if(member.dataType) member.dataType.refCount++;
7072       return true;
7073    }
7074    else if((classProp = eClass_FindClassProperty(_class, id.string)))
7075    {
7076       if(!classProp.dataType)
7077          classProp.dataType = ProcessTypeString(classProp.dataTypeString, false);
7078
7079       if(classProp.constant)
7080       {
7081          FreeExpContents(exp);
7082
7083          exp.isConstant = true;
7084          if(classProp.dataType.kind == pointerType && classProp.dataType.type.kind == charType)
7085          {
7086             //char constant[256];
7087             exp.type = stringExp;
7088             exp.constant = QMkString((char *)classProp.Get(_class));
7089          }
7090          else
7091          {
7092             char constant[256];
7093             exp.type = constantExp;
7094             sprintf(constant, "%d", (int)classProp.Get(_class));
7095             exp.constant = CopyString(constant);
7096          }
7097       }
7098       else
7099       {
7100          // TO IMPLEMENT...
7101       }
7102
7103       exp.expType = classProp.dataType;
7104       if(classProp.dataType) classProp.dataType.refCount++;
7105       return true;
7106    }
7107    return false;
7108 }
7109
7110 static GlobalData ScanGlobalData(NameSpace nameSpace, char * name)
7111 {
7112    BinaryTree * tree = &nameSpace.functions;
7113    GlobalData data = (GlobalData)tree->FindString(name);
7114    NameSpace * child;
7115    if(!data)
7116    {
7117       for(child = (NameSpace *)nameSpace.nameSpaces.first; child; child = (NameSpace *)((BTNode)child).next)
7118       {
7119          data = ScanGlobalData(child, name);
7120          if(data)
7121             break;
7122       }
7123    }
7124    return data;
7125 }
7126
7127 static GlobalData FindGlobalData(char * name)
7128 {
7129    int start = 0, c;
7130    NameSpace * nameSpace;
7131    nameSpace = globalData;
7132    for(c = 0; name[c]; c++)
7133    {
7134       if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
7135       {
7136          NameSpace * newSpace;
7137          char * spaceName = new char[c - start + 1];
7138          strncpy(spaceName, name + start, c - start);
7139          spaceName[c-start] = '\0';
7140          newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
7141          delete spaceName;
7142          if(!newSpace)
7143             return null;
7144          nameSpace = newSpace;
7145          if(name[c] == ':') c++;
7146          start = c+1;
7147       }
7148    }
7149    if(c - start)
7150    {
7151       return ScanGlobalData(nameSpace, name + start);
7152    }
7153    return null;
7154 }
7155
7156 static int definedExpStackPos;
7157 static void * definedExpStack[512];
7158
7159 // This function makes checkedExp equivalent to newExp, ending up freeing newExp
7160 void ReplaceExpContents(Expression checkedExp, Expression newExp)
7161 {
7162    Expression prev = checkedExp.prev, next = checkedExp.next;
7163
7164    FreeExpContents(checkedExp);
7165    FreeType(checkedExp.expType);
7166    FreeType(checkedExp.destType);
7167
7168    *checkedExp = *newExp;
7169
7170    delete newExp;
7171
7172    checkedExp.prev = prev;
7173    checkedExp.next = next;
7174 }
7175
7176 void ApplyAnyObjectLogic(Expression e)
7177 {
7178    Type destType = /*(e.destType && e.destType.kind == ellipsisType) ? ellipsisDestType : */e.destType;
7179 #ifdef _DEBUG
7180    char debugExpString[4096];
7181    debugExpString[0] = '\0';
7182    PrintExpression(e, debugExpString);
7183 #endif
7184
7185    if(destType && (/*destType.classObjectType == ClassObjectType::typedObject || */destType.classObjectType == anyObject))
7186    {
7187       //if(e.destType && e.destType.kind == ellipsisType) usedEllipsis = true;
7188       //ellipsisDestType = destType;
7189       if(e && e.expType)
7190       {
7191          Type type = e.expType;
7192          Class _class = null;
7193          //Type destType = e.destType;
7194
7195          if(type.kind == classType && type._class && type._class.registered)
7196          {
7197             _class = type._class.registered;
7198          }
7199          else if(type.kind == subClassType)
7200          {
7201             _class = FindClass("ecere::com::Class").registered;
7202          }
7203          else
7204          {
7205             char string[1024] = "";
7206             Symbol classSym;
7207
7208             PrintTypeNoConst(type, string, false, true);
7209             classSym = FindClass(string);
7210             if(classSym) _class = classSym.registered;
7211          }
7212
7213          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...
7214             (!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))) ||
7215             destType.byReference)))
7216          {
7217             if(!_class || strcmp(_class.fullName, "char *"))     // TESTING THIS WITH NEW String class...
7218             {
7219                Expression checkedExp = e, newExp;
7220
7221                while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7222                {
7223                   if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7224                   {
7225                      if(checkedExp.type == extensionCompoundExp)
7226                      {
7227                         checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7228                      }
7229                      else
7230                         checkedExp = checkedExp.list->last;
7231                   }
7232                   else if(checkedExp.type == castExp)
7233                      checkedExp = checkedExp.cast.exp;
7234                }
7235
7236                if(checkedExp && checkedExp.type == opExp && checkedExp.op.op == '*' && !checkedExp.op.exp1)
7237                {
7238                   newExp = checkedExp.op.exp2;
7239                   checkedExp.op.exp2 = null;
7240                   FreeExpContents(checkedExp);
7241
7242                   if(e.expType && e.expType.passAsTemplate)
7243                   {
7244                      char size[100];
7245                      ComputeTypeSize(e.expType);
7246                      sprintf(size, "%d", e.expType.size);
7247                      newExp = MkExpBrackets(MkListOne(MkExpOp(MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)),
7248                         MkDeclaratorPointer(MkPointer(null, null), null)), newExp), '+',
7249                            MkExpCall(MkExpIdentifier(MkIdentifier("__ENDIAN_PAD")), MkListOne(MkExpConstant(size))))));
7250                   }
7251
7252                   ReplaceExpContents(checkedExp, newExp);
7253                   e.byReference = true;
7254                }
7255                else if(!e.byReference || (_class && _class.type == noHeadClass))     // TESTING THIS HERE...
7256                {
7257                   Expression checkedExp, newExp;
7258
7259                   {
7260                      // TODO: Move code from debugTools.ec for hasAddress flag, this is just temporary
7261                      bool hasAddress =
7262                         e.type == identifierExp ||
7263                         (e.type == ExpressionType::memberExp && e.member.memberType == dataMember) ||
7264                         (e.type == ExpressionType::pointerExp && e.member.memberType == dataMember) ||
7265                         (e.type == opExp && !e.op.exp1 && e.op.op == '*') ||
7266                         e.type == indexExp;
7267
7268                      if(_class && _class.type != noHeadClass && _class.type != normalClass && _class.type != structClass && !hasAddress)
7269                      {
7270                         Context context = PushContext();
7271                         Declarator decl;
7272                         OldList * specs = MkList();
7273                         char typeString[1024];
7274                         Expression newExp { };
7275
7276                         typeString[0] = '\0';
7277                         *newExp = *e;
7278
7279                         //if(e.destType) e.destType.refCount++;
7280                         // if(exp.expType) exp.expType.refCount++;
7281                         newExp.prev = null;
7282                         newExp.next = null;
7283                         newExp.expType = null;
7284
7285                         PrintTypeNoConst(e.expType, typeString, false, true);
7286                         decl = SpecDeclFromString(typeString, specs, null);
7287                         newExp.destType = ProcessType(specs, decl);
7288
7289                         curContext = context;
7290
7291                         // We need a current compound for this
7292                         if(curCompound)
7293                         {
7294                            char name[100];
7295                            OldList * stmts = MkList();
7296                            e.type = extensionCompoundExp;
7297                            sprintf(name, "__internalValue%03X", internalValueCounter++);
7298                            if(!curCompound.compound.declarations)
7299                               curCompound.compound.declarations = MkList();
7300                            curCompound.compound.declarations->Insert(null, MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(name)), null))));
7301                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(name)), '=', newExp))));
7302                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier(name)))));
7303                            e.compound = MkCompoundStmt(null, stmts);
7304                         }
7305                         else
7306                            printf("libec: compiler error, curCompound is null in ApplyAnyObjectLogic\n");
7307
7308                         /*
7309                         e.compound = MkCompoundStmt(
7310                            MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(
7311                               MkDeclaratorIdentifier(MkIdentifier("__internalValue")), MkInitializerAssignment(newExp))))),
7312
7313                            MkListOne(MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier("__internalValue"))))));
7314                         */
7315
7316                         {
7317                            Type type = e.destType;
7318                            e.destType = { };
7319                            CopyTypeInto(e.destType, type);
7320                            e.destType.refCount = 1;
7321                            e.destType.classObjectType = none;
7322                            FreeType(type);
7323                         }
7324
7325                         e.compound.compound.context = context;
7326                         PopContext(context);
7327                         curContext = context.parent;
7328                      }
7329                   }
7330
7331                   // TODO: INTEGRATE THIS WITH VERSION ABOVE WHICH WAS ADDED TO ENCOMPASS OTHER CASE (*pointer)
7332                   checkedExp = e;
7333                   while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7334                   {
7335                      if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7336                      {
7337                         if(checkedExp.type == extensionCompoundExp)
7338                         {
7339                            checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7340                         }
7341                         else
7342                            checkedExp = checkedExp.list->last;
7343                      }
7344                      else if(checkedExp.type == castExp)
7345                         checkedExp = checkedExp.cast.exp;
7346                   }
7347                   {
7348                      Expression operand { };
7349                      operand = *checkedExp;
7350                      checkedExp.destType = null;
7351                      checkedExp.expType = null;
7352                      checkedExp.Clear();
7353                      checkedExp.type = opExp;
7354                      checkedExp.op.op = '&';
7355                      checkedExp.op.exp1 = null;
7356                      checkedExp.op.exp2 = operand;
7357
7358                      //newExp = MkExpOp(null, '&', checkedExp);
7359                   }
7360                   //ReplaceExpContents(checkedExp, newExp);
7361                }
7362             }
7363          }
7364       }
7365    }
7366    {
7367       // If expression type is a simple class, make it an address
7368       // FixReference(e, true);
7369    }
7370 //#if 0
7371    if((!destType || destType.kind == ellipsisType || destType.kind == voidType) && e.expType && (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7372       (e.expType.byReference || (e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7373          (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass ) )))
7374    {
7375       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"))
7376       {
7377          return;  // LEAVE THIS CASE (typed_object & :: methods 's this) TO PASS 2 FOR NOW
7378       }
7379       else
7380       {
7381          Expression thisExp { };
7382
7383          *thisExp = *e;
7384          thisExp.prev = null;
7385          thisExp.next = null;
7386          e.Clear();
7387
7388          e.type = bracketsExp;
7389          e.list = MkListOne(MkExpOp(null, '*', thisExp.type == identifierExp ? thisExp : MkExpBrackets(MkListOne(thisExp))));
7390          if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && thisExp.expType._class.registered.type == noHeadClass)
7391             ((Expression)e.list->first).byReference = true;
7392
7393          /*if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && !strcmp(thisExp.expType._class.registered.name, "class"))
7394          {
7395             e.expType = thisExp.expType;
7396             e.expType.refCount++;
7397          }
7398          else*/
7399          {
7400             e.expType = { };
7401             CopyTypeInto(e.expType, thisExp.expType);
7402             e.expType.byReference = false;
7403             e.expType.refCount = 1;
7404
7405             if(e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7406                (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass))
7407             {
7408                e.expType.classObjectType = none;
7409             }
7410          }
7411       }
7412    }
7413 // TOFIX: Try this for a nice IDE crash!
7414 //#endif
7415    // The other way around
7416    else
7417 //#endif
7418    if(destType && e.expType &&
7419          //e.expType.kind == classType && e.expType._class && e.expType._class.registered && !strcmp(e.expType._class.registered.name, "class") &&
7420          (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7421          !destType.classObjectType && /*(destType.kind != pointerType || !destType.type || destType.type.kind != voidType) &&*/ destType.kind != voidType)
7422    {
7423       if(destType.kind == ellipsisType)
7424       {
7425          Compiler_Error($"Unspecified type\n");
7426       }
7427       else if(!(destType.truth && e.expType.kind == classType && e.expType._class && e.expType._class.registered && e.expType._class.registered.type == structClass))
7428       {
7429          bool byReference = e.expType.byReference;
7430          Expression thisExp { };
7431          Declarator decl;
7432          OldList * specs = MkList();
7433          char typeString[1024]; // Watch buffer overruns
7434          Type type;
7435          ClassObjectType backupClassObjectType;
7436          bool backupByReference;
7437
7438          if(e.expType.kind == classType && e.expType._class && e.expType._class.registered && strcmp(e.expType._class.registered.name, "class"))
7439             type = e.expType;
7440          else
7441             type = destType;
7442
7443          backupClassObjectType = type.classObjectType;
7444          backupByReference = type.byReference;
7445
7446          type.classObjectType = none;
7447          type.byReference = false;
7448
7449          typeString[0] = '\0';
7450          PrintType(type, typeString, false, true);
7451          decl = SpecDeclFromString(typeString, specs, null);
7452
7453          type.classObjectType = backupClassObjectType;
7454          type.byReference = backupByReference;
7455
7456          *thisExp = *e;
7457          thisExp.prev = null;
7458          thisExp.next = null;
7459          e.Clear();
7460
7461          if( ( type.kind == classType && type._class && type._class.registered &&
7462                    (type._class.registered.type == systemClass || type._class.registered.type == bitClass ||
7463                     type._class.registered.type == enumClass || type._class.registered.type == unitClass) ) ||
7464              (type.kind != pointerType && type.kind != intPtrType && type.kind != arrayType && type.kind != classType) ||
7465              (!destType.byReference && byReference && (destType.kind != pointerType || type.kind != pointerType)))
7466          {
7467             e.type = opExp;
7468             e.op.op = '*';
7469             e.op.exp1 = null;
7470             e.op.exp2 = MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), thisExp);
7471
7472             e.expType = { };
7473             CopyTypeInto(e.expType, type);
7474             e.expType.byReference = false;
7475             e.expType.refCount = 1;
7476          }
7477          else
7478          {
7479             e.type = castExp;
7480             e.cast.typeName = MkTypeName(specs, decl);
7481             e.cast.exp = thisExp;
7482             e.byReference = true;
7483             e.expType = type;
7484             type.refCount++;
7485          }
7486          e.destType = destType;
7487          destType.refCount++;
7488       }
7489    }
7490 }
7491
7492 void ProcessExpressionType(Expression exp)
7493 {
7494    bool unresolved = false;
7495    Location oldyylloc = yylloc;
7496    bool notByReference = false;
7497 #ifdef _DEBUG
7498    char debugExpString[4096];
7499    debugExpString[0] = '\0';
7500    PrintExpression(exp, debugExpString);
7501 #endif
7502    if(!exp || exp.expType)
7503       return;
7504
7505    //eSystem_Logf("%s\n", expString);
7506
7507    // Testing this here
7508    yylloc = exp.loc;
7509    switch(exp.type)
7510    {
7511       case identifierExp:
7512       {
7513          Identifier id = exp.identifier;
7514          if(!id || !topContext) return;
7515
7516          // DOING THIS LATER NOW...
7517          if(id._class && id._class.name)
7518          {
7519             id.classSym = id._class.symbol; // FindClass(id._class.name);
7520             /* TODO: Name Space Fix ups
7521             if(!id.classSym)
7522                id.nameSpace = eSystem_FindNameSpace(privateModule, id._class.name);
7523             */
7524          }
7525
7526          /* WHY WAS THIS COMMENTED OUT? if(!strcmp(id.string, "__thisModule"))
7527          {
7528             exp.expType = ProcessTypeString("Module", true);
7529             break;
7530          }
7531          else */if(strstr(id.string, "__ecereClass") == id.string)
7532          {
7533             exp.expType = ProcessTypeString("ecere::com::Class", true);
7534             break;
7535          }
7536          else if(id._class && (id.classSym || (id._class.name && !strcmp(id._class.name, "property"))))
7537          {
7538             // Added this here as well
7539             ReplaceClassMembers(exp, thisClass);
7540             if(exp.type != identifierExp)
7541             {
7542                ProcessExpressionType(exp);
7543                break;
7544             }
7545
7546             if(id.classSym && ResolveIdWithClass(exp, id.classSym.registered, false))
7547                break;
7548          }
7549          else
7550          {
7551             Symbol symbol = FindSymbol(id.string, curContext, topContext /*exp.destType ? topContext : globalContext*/, false, id._class && id._class.name == null);
7552             // Enums should be resolved here (Special pass in opExp to fix identifiers not seen as enum on the first pass)
7553             if(!symbol/* && exp.destType*/)
7554             {
7555                if(exp.destType && CheckExpressionType(exp, exp.destType, false))
7556                   break;
7557                else
7558                {
7559                   if(thisClass)
7560                   {
7561                      ReplaceClassMembers(exp, thisClass ? thisClass : currentClass);
7562                      if(exp.type != identifierExp)
7563                      {
7564                         ProcessExpressionType(exp);
7565                         break;
7566                      }
7567                   }
7568                   // Static methods called from inside the _class
7569                   else if(currentClass && !id._class)
7570                   {
7571                      if(ResolveIdWithClass(exp, currentClass, true))
7572                         break;
7573                   }
7574                   symbol = FindSymbol(id.string, topContext.parent, globalContext, false, id._class && id._class.name == null);
7575                }
7576             }
7577
7578             // If we manage to resolve this symbol
7579             if(symbol)
7580             {
7581                Type type = symbol.type;
7582                Class _class = (type && type.kind == classType && type._class) ? type._class.registered : null;
7583
7584                if(_class && !strcmp(id.string, "this") && !type.classObjectType)
7585                {
7586                   Context context = SetupTemplatesContext(_class);
7587                   type = ReplaceThisClassType(_class);
7588                   FinishTemplatesContext(context);
7589                   if(type) type.refCount = 0;   // We'll be incrementing it right below...
7590                }
7591
7592                FreeSpecifier(id._class);
7593                id._class = null;
7594                delete id.string;
7595                id.string = CopyString(symbol.string);
7596
7597                id.classSym = null;
7598                exp.expType = type;
7599                if(type)
7600                   type.refCount++;
7601                if(type && (type.kind == enumType || (_class && _class.type == enumClass)))
7602                   // Add missing cases here... enum Classes...
7603                   exp.isConstant = true;
7604
7605                // TOCHECK: Why was !strcmp(id.string, "this") commented out?
7606                if(symbol.isParam || !strcmp(id.string, "this"))
7607                {
7608                   if(_class && _class.type == structClass && !type.declaredWithStruct)
7609                      exp.byReference = true;
7610
7611                   //TESTING COMMENTING THIS OUT IN FAVOR OF ApplyAnyObjectLogic
7612                   /*if(type && _class && (type.classObjectType == typedObject || type.classObjectType == anyObject) &&
7613                      ((_class.type == unitClass || _class.type == enumClass || _class.type == bitClass) ||
7614                      (type.byReference && (_class.type == normalClass || _class.type == noHeadClass))))
7615                   {
7616                      Identifier id = exp.identifier;
7617                      exp.type = bracketsExp;
7618                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(id)));
7619                   }*/
7620                }
7621
7622                if(symbol.isIterator)
7623                {
7624                   if(symbol.isIterator == 3)
7625                   {
7626                      exp.type = bracketsExp;
7627                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(exp.identifier)));
7628                      ((Expression)exp.list->first).op.exp2.expType = exp.expType;
7629                      exp.expType = null;
7630                      ProcessExpressionType(exp);
7631                   }
7632                   else if(symbol.isIterator != 4)
7633                   {
7634                      exp.type = memberExp;
7635                      exp.member.exp = MkExpIdentifier(exp.identifier);
7636                      exp.member.exp.expType = exp.expType;
7637                      /*if(symbol.isIterator == 6)
7638                         exp.member.member = MkIdentifier("key");
7639                      else*/
7640                         exp.member.member = MkIdentifier("data");
7641                      exp.expType = null;
7642                      ProcessExpressionType(exp);
7643                   }
7644                }
7645                break;
7646             }
7647             else
7648             {
7649                DefinedExpression definedExp = null;
7650                if(thisNameSpace && !(id._class && !id._class.name))
7651                {
7652                   char name[1024];
7653                   strcpy(name, thisNameSpace);
7654                   strcat(name, "::");
7655                   strcat(name, id.string);
7656                   definedExp = eSystem_FindDefine(privateModule, name);
7657                }
7658                if(!definedExp)
7659                   definedExp = eSystem_FindDefine(privateModule, id.string);
7660                if(definedExp)
7661                {
7662                   int c;
7663                   for(c = 0; c<definedExpStackPos; c++)
7664                      if(definedExpStack[c] == definedExp)
7665                         break;
7666                   if(c == definedExpStackPos && c < sizeof(definedExpStack) / sizeof(void *))
7667                   {
7668                      Location backupYylloc = yylloc;
7669                      File backInput = fileInput;
7670                      definedExpStack[definedExpStackPos++] = definedExp;
7671
7672                      fileInput = TempFile { };
7673                      fileInput.Write(definedExp.value, 1, strlen(definedExp.value));
7674                      fileInput.Seek(0, start);
7675
7676                      echoOn = false;
7677                      parsedExpression = null;
7678                      resetScanner();
7679                      expression_yyparse();
7680                      delete fileInput;
7681                      if(backInput)
7682                         fileInput = backInput;
7683
7684                      yylloc = backupYylloc;
7685
7686                      if(parsedExpression)
7687                      {
7688                         FreeIdentifier(id);
7689                         exp.type = bracketsExp;
7690                         exp.list = MkListOne(parsedExpression);
7691                         parsedExpression.loc = yylloc;
7692                         ProcessExpressionType(exp);
7693                         definedExpStackPos--;
7694                         return;
7695                      }
7696                      definedExpStackPos--;
7697                   }
7698                   else
7699                   {
7700                      if(inCompiler)
7701                      {
7702                         Compiler_Error($"Recursion in defined expression %s\n", id.string);
7703                      }
7704                   }
7705                }
7706                else
7707                {
7708                   GlobalData data = null;
7709                   if(thisNameSpace && !(id._class && !id._class.name))
7710                   {
7711                      char name[1024];
7712                      strcpy(name, thisNameSpace);
7713                      strcat(name, "::");
7714                      strcat(name, id.string);
7715                      data = FindGlobalData(name);
7716                   }
7717                   if(!data)
7718                      data = FindGlobalData(id.string);
7719                   if(data)
7720                   {
7721                      DeclareGlobalData(data);
7722                      exp.expType = data.dataType;
7723                      if(data.dataType) data.dataType.refCount++;
7724
7725                      delete id.string;
7726                      id.string = CopyString(data.fullName);
7727                      FreeSpecifier(id._class);
7728                      id._class = null;
7729
7730                      break;
7731                   }
7732                   else
7733                   {
7734                      GlobalFunction function = null;
7735                      if(thisNameSpace && !(id._class && !id._class.name))
7736                      {
7737                         char name[1024];
7738                         strcpy(name, thisNameSpace);
7739                         strcat(name, "::");
7740                         strcat(name, id.string);
7741                         function = eSystem_FindFunction(privateModule, name);
7742                      }
7743                      if(!function)
7744                         function = eSystem_FindFunction(privateModule, id.string);
7745                      if(function)
7746                      {
7747                         char name[1024];
7748                         delete id.string;
7749                         id.string = CopyString(function.name);
7750                         name[0] = 0;
7751
7752                         if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
7753                            strcpy(name, "__ecereFunction_");
7754                         FullClassNameCat(name, id.string, false); // Why is this using FullClassNameCat ?
7755                         if(DeclareFunction(function, name))
7756                         {
7757                            delete id.string;
7758                            id.string = CopyString(name);
7759                         }
7760                         exp.expType = function.dataType;
7761                         if(function.dataType) function.dataType.refCount++;
7762
7763                         FreeSpecifier(id._class);
7764                         id._class = null;
7765
7766                         break;
7767                      }
7768                   }
7769                }
7770             }
7771          }
7772          unresolved = true;
7773          break;
7774       }
7775       case instanceExp:
7776       {
7777          Class _class;
7778          // Symbol classSym;
7779
7780          if(!exp.instance._class)
7781          {
7782             if(exp.destType && exp.destType.kind == classType && exp.destType._class)
7783             {
7784                exp.instance._class = MkSpecifierName(exp.destType._class.string);
7785             }
7786          }
7787
7788          //classSym = FindClass(exp.instance._class.fullName);
7789          //_class = classSym ? classSym.registered : null;
7790
7791          ProcessInstantiationType(exp.instance);
7792          exp.isConstant = exp.instance.isConstant;
7793
7794          /*
7795          if(_class.type == unitClass && _class.base.type != systemClass)
7796          {
7797             {
7798                Type destType = exp.destType;
7799
7800                exp.destType = MkClassType(_class.base.fullName);
7801                exp.expType = MkClassType(_class.fullName);
7802                CheckExpressionType(exp, exp.destType, true);
7803
7804                exp.destType = destType;
7805             }
7806             exp.expType = MkClassType(_class.fullName);
7807          }
7808          else*/
7809          if(exp.instance._class)
7810          {
7811             exp.expType = MkClassType(exp.instance._class.name);
7812             /*if(exp.expType._class && exp.expType._class.registered &&
7813                (exp.expType._class.registered.type == normalClass || exp.expType._class.registered.type == noHeadClass))
7814                exp.expType.byReference = true;*/
7815          }
7816          break;
7817       }
7818       case constantExp:
7819       {
7820          if(!exp.expType)
7821          {
7822             char * constant = exp.constant;
7823             Type type
7824             {
7825                refCount = 1;
7826                constant = true;
7827             };
7828             exp.expType = type;
7829
7830             if(constant[0] == '\'')
7831             {
7832                if((int)((byte *)constant)[1] > 127)
7833                {
7834                   int nb;
7835                   unichar ch = UTF8GetChar(constant + 1, &nb);
7836                   if(nb < 2) ch = constant[1];
7837                   delete constant;
7838                   exp.constant = PrintUInt(ch);
7839                   // type.kind = (ch > 0xFFFF) ? intType : shortType;
7840                   type.kind = classType; //(ch > 0xFFFF) ? intType : shortType;
7841                   type._class = FindClass("unichar");
7842
7843                   type.isSigned = false;
7844                }
7845                else
7846                {
7847                   type.kind = charType;
7848                   type.isSigned = true;
7849                }
7850             }
7851             else
7852             {
7853                char * dot = strchr(constant, '.');
7854                bool isHex = (constant[0] == '0' && (constant[1] == 'x' || constant[1] == 'X'));
7855                char * exponent;
7856                if(isHex)
7857                {
7858                   exponent = strchr(constant, 'p');
7859                   if(!exponent) exponent = strchr(constant, 'P');
7860                }
7861                else
7862                {
7863                   exponent = strchr(constant, 'e');
7864                   if(!exponent) exponent = strchr(constant, 'E');
7865                }
7866
7867                if(dot || exponent)
7868                {
7869                   if(strchr(constant, 'f') || strchr(constant, 'F'))
7870                      type.kind = floatType;
7871                   else
7872                      type.kind = doubleType;
7873                   type.isSigned = true;
7874                }
7875                else
7876                {
7877                   bool isSigned = constant[0] == '-';
7878                   char * endP = null;
7879                   int64 i64 = strtoll(constant, &endP, 0);
7880                   uint64 ui64 = strtoull(constant, &endP, 0);
7881                   bool is64Bit = endP && (!strcmp(endP, "LL") || !strcmp(endP, "ll"));
7882                   if(isSigned)
7883                   {
7884                      if(i64 < MININT)
7885                         is64Bit = true;
7886                   }
7887                   else
7888                   {
7889                      if(ui64 > MAXINT)
7890                      {
7891                         if(ui64 > MAXDWORD)
7892                         {
7893                            is64Bit = true;
7894                            if(ui64 <= MAXINT64 && (constant[0] != '0' || !constant[1]))
7895                               isSigned = true;
7896                         }
7897                      }
7898                      else if(constant[0] != '0' || !constant[1])
7899                         isSigned = true;
7900                   }
7901                   type.kind = is64Bit ? int64Type : intType;
7902                   type.isSigned = isSigned;
7903                }
7904             }
7905             exp.isConstant = true;
7906             if(exp.destType && exp.destType.kind == doubleType)
7907                type.kind = doubleType;
7908             else if(exp.destType && exp.destType.kind == floatType)
7909                type.kind = floatType;
7910             else if(exp.destType && exp.destType.kind == int64Type)
7911                type.kind = int64Type;
7912          }
7913          break;
7914       }
7915       case stringExp:
7916       {
7917          exp.isConstant = true;      // Why wasn't this constant?
7918          exp.expType = Type
7919          {
7920             refCount = 1;
7921             kind = pointerType;
7922             type = Type
7923             {
7924                refCount = 1;
7925                kind = charType;
7926                constant = true;
7927                isSigned = true;
7928             }
7929          };
7930          break;
7931       }
7932       case newExp:
7933       case new0Exp:
7934          ProcessExpressionType(exp._new.size);
7935          exp.expType = Type
7936          {
7937             refCount = 1;
7938             kind = pointerType;
7939             type = ProcessType(exp._new.typeName.qualifiers, exp._new.typeName.declarator);
7940          };
7941          DeclareType(exp.expType.type, false, false);
7942          break;
7943       case renewExp:
7944       case renew0Exp:
7945          ProcessExpressionType(exp._renew.size);
7946          ProcessExpressionType(exp._renew.exp);
7947          exp.expType = Type
7948          {
7949             refCount = 1;
7950             kind = pointerType;
7951             type = ProcessType(exp._renew.typeName.qualifiers, exp._renew.typeName.declarator);
7952          };
7953          DeclareType(exp.expType.type, false, false);
7954          break;
7955       case opExp:
7956       {
7957          bool assign = false, boolResult = false, boolOps = false;
7958          Type type1 = null, type2 = null;
7959          bool useDestType = false, useSideType = false;
7960          Location oldyylloc = yylloc;
7961          bool useSideUnit = false;
7962
7963          // Dummy type to prevent ProcessExpression of operands to say unresolved identifiers yet
7964          Type dummy
7965          {
7966             count = 1;
7967             refCount = 1;
7968          };
7969
7970          switch(exp.op.op)
7971          {
7972             // Assignment Operators
7973             case '=':
7974             case MUL_ASSIGN:
7975             case DIV_ASSIGN:
7976             case MOD_ASSIGN:
7977             case ADD_ASSIGN:
7978             case SUB_ASSIGN:
7979             case LEFT_ASSIGN:
7980             case RIGHT_ASSIGN:
7981             case AND_ASSIGN:
7982             case XOR_ASSIGN:
7983             case OR_ASSIGN:
7984                assign = true;
7985                break;
7986             // boolean Operators
7987             case '!':
7988                // Expect boolean operators
7989                //boolOps = true;
7990                //boolResult = true;
7991                break;
7992             case AND_OP:
7993             case OR_OP:
7994                // Expect boolean operands
7995                boolOps = true;
7996                boolResult = true;
7997                break;
7998             // Comparisons
7999             case EQ_OP:
8000             case '<':
8001             case '>':
8002             case LE_OP:
8003             case GE_OP:
8004             case NE_OP:
8005                // Gives boolean result
8006                boolResult = true;
8007                useSideType = true;
8008                break;
8009             case '+':
8010             case '-':
8011                useSideUnit = true;
8012
8013                // Just added these... testing
8014             case '|':
8015             case '&':
8016             case '^':
8017
8018             // DANGER: Verify units
8019             case '/':
8020             case '%':
8021             case '*':
8022
8023                if(exp.op.op != '*' || exp.op.exp1)
8024                {
8025                   useSideType = true;
8026                   useDestType = true;
8027                }
8028                break;
8029
8030             /*// Implement speed etc.
8031             case '*':
8032             case '/':
8033                break;
8034             */
8035          }
8036          if(exp.op.op == '&')
8037          {
8038             // Added this here earlier for Iterator address as key
8039             if(!exp.op.exp1 && exp.op.exp2 && exp.op.exp2.type == identifierExp && exp.op.exp2.identifier)
8040             {
8041                Identifier id = exp.op.exp2.identifier;
8042                Symbol symbol = FindSymbol(id.string, curContext, topContext, false, id._class && id._class.name == null);
8043                if(symbol && symbol.isIterator == 2)
8044                {
8045                   exp.type = memberExp;
8046                   exp.member.exp = exp.op.exp2;
8047                   exp.member.member = MkIdentifier("key");
8048                   exp.expType = null;
8049                   exp.op.exp2.expType = symbol.type;
8050                   symbol.type.refCount++;
8051                   ProcessExpressionType(exp);
8052                   FreeType(dummy);
8053                   break;
8054                }
8055                // exp.op.exp2.usage.usageRef = true;
8056             }
8057          }
8058
8059          //dummy.kind = TypeDummy;
8060
8061          if(exp.op.exp1)
8062          {
8063             if(exp.destType && exp.destType.kind == classType &&
8064                exp.destType._class && exp.destType._class.registered && useDestType &&
8065
8066               ((exp.destType._class.registered.type == unitClass && useSideUnit) ||
8067                exp.destType._class.registered.type == enumClass ||
8068                exp.destType._class.registered.type == bitClass
8069                ))
8070
8071               //(exp.destType._class.registered.type == unitClass || exp.destType._class.registered.type == enumClass) && useDestType)
8072             {
8073                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8074                exp.op.exp1.destType = exp.destType;
8075                if(exp.destType)
8076                   exp.destType.refCount++;
8077             }
8078             else if(!assign)
8079             {
8080                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8081                exp.op.exp1.destType = dummy;
8082                dummy.refCount++;
8083             }
8084
8085             // TESTING THIS HERE...
8086             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count++;
8087             ProcessExpressionType(exp.op.exp1);
8088             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count--;
8089
8090             if(exp.op.exp1.destType == dummy)
8091             {
8092                FreeType(dummy);
8093                exp.op.exp1.destType = null;
8094             }
8095             type1 = exp.op.exp1.expType;
8096          }
8097
8098          if(exp.op.exp2)
8099          {
8100             char expString[10240];
8101             expString[0] = '\0';
8102             if(exp.op.exp2.type == instanceExp && !exp.op.exp2.instance._class)
8103             {
8104                if(exp.op.exp1)
8105                {
8106                   exp.op.exp2.destType = exp.op.exp1.expType;
8107                   if(exp.op.exp1.expType)
8108                      exp.op.exp1.expType.refCount++;
8109                }
8110                else
8111                {
8112                   exp.op.exp2.destType = exp.destType;
8113                   if(exp.destType)
8114                      exp.destType.refCount++;
8115                }
8116
8117                if(type1) type1.refCount++;
8118                exp.expType = type1;
8119             }
8120             else if(assign)
8121             {
8122                if(inCompiler)
8123                   PrintExpression(exp.op.exp2, expString);
8124
8125                if(type1 && type1.kind == pointerType)
8126                {
8127                   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 ||
8128                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN)
8129                      Compiler_Error($"operator %s illegal on pointer\n", exp.op.op);
8130                   else if(exp.op.op == '=')
8131                   {
8132                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8133                      exp.op.exp2.destType = type1;
8134                      if(type1)
8135                         type1.refCount++;
8136                   }
8137                }
8138                else
8139                {
8140                   // Don't convert to the type for those... (e.g.: Degrees a; a /= 2;)
8141                   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/* ||
8142                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN*/);
8143                   else
8144                   {
8145                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8146                      exp.op.exp2.destType = type1;
8147                      if(type1)
8148                         type1.refCount++;
8149                   }
8150                }
8151                if(type1) type1.refCount++;
8152                exp.expType = type1;
8153             }
8154             else if(exp.destType && exp.destType.kind == classType &&
8155                exp.destType._class && exp.destType._class.registered &&
8156
8157                   ((exp.destType._class.registered.type == unitClass && useDestType && useSideUnit) ||
8158                   (exp.destType._class.registered.type == enumClass && useDestType))
8159                   )
8160             {
8161                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8162                exp.op.exp2.destType = exp.destType;
8163                if(exp.destType)
8164                   exp.destType.refCount++;
8165             }
8166             else
8167             {
8168                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8169                exp.op.exp2.destType = dummy;
8170                dummy.refCount++;
8171             }
8172
8173             // TESTING THIS HERE... (DANGEROUS)
8174             if(type1 && boolResult && useSideType && type1.kind == classType && type1._class && type1._class.registered &&
8175                (type1._class.registered.type == bitClass || type1._class.registered.type == enumClass))
8176             {
8177                FreeType(exp.op.exp2.destType);
8178                exp.op.exp2.destType = type1;
8179                type1.refCount++;
8180             }
8181             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count++;
8182             // Cannot lose the cast on a sizeof
8183             if(exp.op.op == SIZEOF)
8184             {
8185                Expression e = exp.op.exp2;
8186                while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
8187                {
8188                   if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
8189                   {
8190                      if(e.type == extensionCompoundExp)
8191                         e = ((Statement)e.compound.compound.statements->last).expressions->last;
8192                      else
8193                         e = e.list->last;
8194                   }
8195                }
8196                if(e.type == castExp && e.cast.exp)
8197                   e.cast.exp.needCast = true;
8198             }
8199             ProcessExpressionType(exp.op.exp2);
8200             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count--;
8201
8202             if(assign && type1 && type1.kind == pointerType && exp.op.exp2.expType)
8203             {
8204                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)
8205                {
8206                   if(exp.op.op != '=' && type1.type.kind == voidType)
8207                      Compiler_Error($"void *: unknown size\n");
8208                }
8209                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||
8210                            (type1.type.kind == voidType && exp.op.exp2.expType.kind == classType && exp.op.exp2.expType._class.registered &&
8211                               (exp.op.exp2.expType._class.registered.type == normalClass ||
8212                               exp.op.exp2.expType._class.registered.type == structClass ||
8213                               exp.op.exp2.expType._class.registered.type == noHeadClass)))
8214                {
8215                   if(exp.op.op == ADD_ASSIGN)
8216                      Compiler_Error($"cannot add two pointers\n");
8217                }
8218                else if((exp.op.exp2.expType.kind == classType && type1.kind == pointerType && type1.type.kind == classType &&
8219                   type1.type._class == exp.op.exp2.expType._class && exp.op.exp2.expType._class.registered && exp.op.exp2.expType._class.registered.type == structClass))
8220                {
8221                   if(exp.op.op == ADD_ASSIGN)
8222                      Compiler_Error($"cannot add two pointers\n");
8223                }
8224                else if(inCompiler)
8225                {
8226                   char type1String[1024];
8227                   char type2String[1024];
8228                   type1String[0] = '\0';
8229                   type2String[0] = '\0';
8230
8231                   PrintType(exp.op.exp2.expType, type1String, false, true);
8232                   PrintType(type1, type2String, false, true);
8233                   ChangeCh(expString, '\n', ' ');
8234                   Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1String, type2String);
8235                }
8236             }
8237
8238             if(exp.op.exp2.destType == dummy)
8239             {
8240                FreeType(dummy);
8241                exp.op.exp2.destType = null;
8242             }
8243
8244             if(exp.op.op == '-' && !exp.op.exp1 && exp.op.exp2.expType && !exp.op.exp2.expType.isSigned)
8245             {
8246                type2 = { };
8247                type2.refCount = 1;
8248                CopyTypeInto(type2, exp.op.exp2.expType);
8249                type2.isSigned = true;
8250             }
8251             else if(exp.op.op == '~' && !exp.op.exp1 && exp.op.exp2.expType && (!exp.op.exp2.expType.isSigned || exp.op.exp2.expType.kind != intType))
8252             {
8253                type2 = { kind = intType };
8254                type2.refCount = 1;
8255                type2.isSigned = true;
8256             }
8257             else
8258             {
8259                type2 = exp.op.exp2.expType;
8260                if(type2) type2.refCount++;
8261             }
8262          }
8263
8264          dummy.kind = voidType;
8265
8266          if(exp.op.op == SIZEOF)
8267          {
8268             exp.expType = Type
8269             {
8270                refCount = 1;
8271                kind = intType;
8272             };
8273             exp.isConstant = true;
8274          }
8275          // Get type of dereferenced pointer
8276          else if(exp.op.op == '*' && !exp.op.exp1)
8277          {
8278             exp.expType = Dereference(type2);
8279             if(type2 && type2.kind == classType)
8280                notByReference = true;
8281          }
8282          else if(exp.op.op == '&' && !exp.op.exp1)
8283             exp.expType = Reference(type2);
8284          else if(!assign)
8285          {
8286             if(boolOps)
8287             {
8288                if(exp.op.exp1)
8289                {
8290                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8291                   exp.op.exp1.destType = MkClassType("bool");
8292                   exp.op.exp1.destType.truth = true;
8293                   if(!exp.op.exp1.expType)
8294                      ProcessExpressionType(exp.op.exp1);
8295                   else
8296                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8297                   FreeType(exp.op.exp1.expType);
8298                   exp.op.exp1.expType = MkClassType("bool");
8299                   exp.op.exp1.expType.truth = true;
8300                }
8301                if(exp.op.exp2)
8302                {
8303                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8304                   exp.op.exp2.destType = MkClassType("bool");
8305                   exp.op.exp2.destType.truth = true;
8306                   if(!exp.op.exp2.expType)
8307                      ProcessExpressionType(exp.op.exp2);
8308                   else
8309                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8310                   FreeType(exp.op.exp2.expType);
8311                   exp.op.exp2.expType = MkClassType("bool");
8312                   exp.op.exp2.expType.truth = true;
8313                }
8314             }
8315             else if(exp.op.exp1 && exp.op.exp2 &&
8316                ((useSideType /*&&
8317                      (useSideUnit ||
8318                         ((!type1 || type1.kind != classType || type1._class.registered.type != unitClass) &&
8319                          (!type2 || type2.kind != classType || type2._class.registered.type != unitClass)))*/) ||
8320                   ((!type1 || type1.kind != classType || !strcmp(type1._class.string, "String")) &&
8321                   (!type2 || type2.kind != classType || !strcmp(type2._class.string, "String")))))
8322             {
8323                if(type1 && type2 &&
8324                   // If either both are class or both are not class
8325                   ((type1.kind == classType && type1._class && strcmp(type1._class.string, "String")) == (type2.kind == classType && type2._class && strcmp(type2._class.string, "String"))))
8326                {
8327                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8328                   exp.op.exp2.destType = type1;
8329                   type1.refCount++;
8330                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8331                   exp.op.exp1.destType = type2;
8332                   type2.refCount++;
8333                   // Warning here for adding Radians + Degrees with no destination type
8334                   if(!boolResult && type1.kind == classType && (!exp.destType || exp.destType.kind != classType) &&
8335                      type1._class.registered && type1._class.registered.type == unitClass &&
8336                      type2._class.registered && type2._class.registered.type == unitClass &&
8337                      type1._class.registered != type2._class.registered)
8338                      Compiler_Warning($"operating on %s and %s with an untyped result, assuming %s\n",
8339                         type1._class.string, type2._class.string, type1._class.string);
8340
8341                   if(type1.kind == pointerType && type1.type.kind == templateType && type2.kind != pointerType)
8342                   {
8343                      Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8344                      if(argExp)
8345                      {
8346                         Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8347
8348                         exp.op.exp1 = MkExpBrackets(MkListOne(MkExpCast(
8349                            MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
8350                            exp.op.exp1)));
8351
8352                         ProcessExpressionType(exp.op.exp1);
8353
8354                         if(type2.kind != pointerType)
8355                         {
8356                            ProcessExpressionType(classExp);
8357
8358                            exp.op.exp2 = MkExpBrackets(MkListOne(MkExpOp(exp.op.exp2, '*',
8359                               // ((_class.type == noHeadClass || _class.type == normalClass) ? sizeof(void *) : type.size)
8360                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(MkExpOp(
8361                                  // noHeadClass
8362                                  MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpConstant("5")),
8363                                     OR_OP,
8364                                  // normalClass
8365                                  MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpConstant("0"))))),
8366                                     MkListOne(MkExpTypeSize(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(
8367                                        MkPointer(null, null), null)))),
8368                                        MkExpMember(classExp, MkIdentifier("typeSize"))))))));
8369
8370                            if(!exp.op.exp2.expType)
8371                            {
8372                               if(type2)
8373                                  FreeType(type2);
8374                               type2 = exp.op.exp2.expType = ProcessTypeString("int", false);
8375                               type2.refCount++;
8376                            }
8377
8378                            ProcessExpressionType(exp.op.exp2);
8379                         }
8380                      }
8381                   }
8382
8383                   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)))
8384                   {
8385                      if(type1.kind != classType && type1.type.kind == voidType)
8386                         Compiler_Error($"void *: unknown size\n");
8387                      exp.expType = type1;
8388                      if(type1) type1.refCount++;
8389                   }
8390                   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)))
8391                   {
8392                      if(type2.kind != classType && type2.type.kind == voidType)
8393                         Compiler_Error($"void *: unknown size\n");
8394                      exp.expType = type2;
8395                      if(type2) type2.refCount++;
8396                   }
8397                   else if((type1.kind == pointerType && type2.kind != pointerType && type2.kind != arrayType && type2.kind != functionType && type2.kind != methodType && type2.kind != classType && type2.kind != subClassType) ||
8398                           (type2.kind == pointerType && type1.kind != pointerType && type1.kind != arrayType && type1.kind != functionType && type1.kind != methodType && type1.kind != classType && type1.kind != subClassType))
8399                   {
8400                      Compiler_Warning($"different levels of indirection\n");
8401                   }
8402                   else
8403                   {
8404                      bool success = false;
8405                      if(type1.kind == pointerType && type2.kind == pointerType)
8406                      {
8407                         if(exp.op.op == '+')
8408                            Compiler_Error($"cannot add two pointers\n");
8409                         else if(exp.op.op == '-')
8410                         {
8411                            // Pointer Subtraction gives integer
8412                            if(MatchTypes(type1.type, type2.type, null, null, null, false, false, false, false))
8413                            {
8414                               exp.expType = Type
8415                               {
8416                                  kind = intType;
8417                                  refCount = 1;
8418                               };
8419                               success = true;
8420
8421                               if(type1.type.kind == templateType)
8422                               {
8423                                  Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8424                                  if(argExp)
8425                                  {
8426                                     Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8427
8428                                     ProcessExpressionType(classExp);
8429
8430                                     exp.type = bracketsExp;
8431                                     exp.list = MkListOne(MkExpOp(
8432                                        MkExpBrackets(MkListOne(MkExpOp(
8433                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp1)))
8434                                              , exp.op.op,
8435                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp2)))))), '/',
8436
8437                                              //MkExpMember(classExp, MkIdentifier("typeSize"))
8438
8439                                              // ((_class.type == noHeadClass || _class.type == normalClass) ? sizeof(void *) : type.size)
8440                                              MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(MkExpOp(
8441                                                 // noHeadClass
8442                                                 MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpIdentifier(MkIdentifier("noHeadClass"))),
8443                                                    OR_OP,
8444                                                 // normalClass
8445                                                 MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpIdentifier(MkIdentifier("normalClass")))))),
8446                                                    MkListOne(MkExpTypeSize(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(
8447                                                       MkPointer(null, null), null)))),
8448                                                       MkExpMember(classExp, MkIdentifier("typeSize")))))
8449
8450
8451                                              ));
8452
8453                                     ProcessExpressionType(((Expression)exp.list->first).op.exp2);
8454                                     FreeType(dummy);
8455                                     return;
8456                                  }
8457                               }
8458                            }
8459                         }
8460                      }
8461
8462                      if(!success && exp.op.exp1.type == constantExp)
8463                      {
8464                         // If first expression is constant, try to match that first
8465                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8466                         {
8467                            if(exp.expType) FreeType(exp.expType);
8468                            exp.expType = exp.op.exp1.destType;
8469                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8470                            success = true;
8471                         }
8472                         else if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8473                         {
8474                            if(exp.expType) FreeType(exp.expType);
8475                            exp.expType = exp.op.exp2.destType;
8476                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8477                            success = true;
8478                         }
8479                      }
8480                      else if(!success)
8481                      {
8482                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8483                         {
8484                            if(exp.expType) FreeType(exp.expType);
8485                            exp.expType = exp.op.exp2.destType;
8486                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8487                            success = true;
8488                         }
8489                         else if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8490                         {
8491                            if(exp.expType) FreeType(exp.expType);
8492                            exp.expType = exp.op.exp1.destType;
8493                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8494                            success = true;
8495                         }
8496                      }
8497                      if(!success)
8498                      {
8499                         char expString1[10240];
8500                         char expString2[10240];
8501                         char type1[1024];
8502                         char type2[1024];
8503                         expString1[0] = '\0';
8504                         expString2[0] = '\0';
8505                         type1[0] = '\0';
8506                         type2[0] = '\0';
8507                         if(inCompiler)
8508                         {
8509                            PrintExpression(exp.op.exp1, expString1);
8510                            ChangeCh(expString1, '\n', ' ');
8511                            PrintExpression(exp.op.exp2, expString2);
8512                            ChangeCh(expString2, '\n', ' ');
8513                            PrintType(exp.op.exp1.expType, type1, false, true);
8514                            PrintType(exp.op.exp2.expType, type2, false, true);
8515                         }
8516
8517                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1, expString2, type2);
8518                      }
8519                   }
8520                }
8521                // ADDED THESE TWO FROM OUTSIDE useSideType CHECK
8522                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type2 && type1 && type2.kind == classType && type1.kind != classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
8523                {
8524                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8525                   // Convert e.g. / 4 into / 4.0
8526                   exp.op.exp1.destType = type2._class.registered.dataType;
8527                   if(type2._class.registered.dataType)
8528                      type2._class.registered.dataType.refCount++;
8529                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8530                   exp.expType = type2;
8531                   if(type2) type2.refCount++;
8532                }
8533                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type1 && type2 && type1.kind == classType && type2.kind != classType && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
8534                {
8535                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8536                   // Convert e.g. / 4 into / 4.0
8537                   exp.op.exp2.destType = type1._class.registered.dataType;
8538                   if(type1._class.registered.dataType)
8539                      type1._class.registered.dataType.refCount++;
8540                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8541                   exp.expType = type1;
8542                   if(type1) type1.refCount++;
8543                }
8544                else if(type1)
8545                {
8546                   bool valid = false;
8547
8548                   if(!boolResult && useSideUnit && type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8549                   {
8550                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8551
8552                      if(!type1._class.registered.dataType)
8553                         type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
8554                      exp.op.exp2.destType = type1._class.registered.dataType;
8555                      exp.op.exp2.destType.refCount++;
8556
8557                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8558                      if(type2)
8559                         FreeType(type2);
8560                      type2 = exp.op.exp2.destType;
8561                      if(type2) type2.refCount++;
8562
8563                      exp.expType = type2;
8564                      type2.refCount++;
8565                   }
8566
8567                   if(!boolResult && useSideUnit && type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8568                   {
8569                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8570
8571                      if(!type2._class.registered.dataType)
8572                         type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
8573                      exp.op.exp1.destType = type2._class.registered.dataType;
8574                      exp.op.exp1.destType.refCount++;
8575
8576                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8577                      type1 = exp.op.exp1.destType;
8578                      exp.expType = type1;
8579                      type1.refCount++;
8580                   }
8581
8582                   // TESTING THIS NEW CODE
8583                   if(!boolResult || exp.op.op == '>' || exp.op.op == '<')
8584                   {
8585                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass && exp.op.exp2.expType)
8586                      {
8587                         if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false))
8588                         {
8589                            if(exp.expType) FreeType(exp.expType);
8590                            exp.expType = exp.op.exp1.expType;
8591                            if(exp.op.exp2.expType) exp.op.exp1.expType.refCount++;
8592                            valid = true;
8593                         }
8594                      }
8595
8596                      else if(type2 && (type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass && exp.op.exp1.expType))
8597                      {
8598                         if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false))
8599                         {
8600                            if(exp.expType) FreeType(exp.expType);
8601                            exp.expType = exp.op.exp2.expType;
8602                            if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8603                            valid = true;
8604                         }
8605                      }
8606                   }
8607
8608                   if(!valid)
8609                   {
8610                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8611                      exp.op.exp2.destType = type1;
8612                      type1.refCount++;
8613
8614                      /*
8615                      // Maybe this was meant to be an enum...
8616                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
8617                      {
8618                         Type oldType = exp.op.exp2.expType;
8619                         exp.op.exp2.expType = null;
8620                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8621                            FreeType(oldType);
8622                         else
8623                            exp.op.exp2.expType = oldType;
8624                      }
8625                      */
8626
8627                      /*
8628                      // TESTING THIS HERE... LATEST ADDITION
8629                      if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8630                      {
8631                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8632                         exp.op.exp2.destType = type2._class.registered.dataType;
8633                         if(type2._class.registered.dataType)
8634                            type2._class.registered.dataType.refCount++;
8635                         CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8636
8637                         //exp.expType = type2._class.registered.dataType; //type2;
8638                         //if(type2) type2.refCount++;
8639                      }
8640
8641                      // TESTING THIS HERE... LATEST ADDITION
8642                      if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8643                      {
8644                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8645                         exp.op.exp1.destType = type1._class.registered.dataType;
8646                         if(type1._class.registered.dataType)
8647                            type1._class.registered.dataType.refCount++;
8648                         CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8649                         exp.expType = type1._class.registered.dataType; //type1;
8650                         if(type1) type1.refCount++;
8651                      }
8652                      */
8653
8654                      if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8655                      {
8656                         if(exp.expType) FreeType(exp.expType);
8657                         exp.expType = exp.op.exp2.destType;
8658                         if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8659                      }
8660                      else if(type1 && type2)
8661                      {
8662                         char expString1[10240];
8663                         char expString2[10240];
8664                         char type1String[1024];
8665                         char type2String[1024];
8666                         expString1[0] = '\0';
8667                         expString2[0] = '\0';
8668                         type1String[0] = '\0';
8669                         type2String[0] = '\0';
8670                         if(inCompiler)
8671                         {
8672                            PrintExpression(exp.op.exp1, expString1);
8673                            ChangeCh(expString1, '\n', ' ');
8674                            PrintExpression(exp.op.exp2, expString2);
8675                            ChangeCh(expString2, '\n', ' ');
8676                            PrintType(exp.op.exp1.expType, type1String, false, true);
8677                            PrintType(exp.op.exp2.expType, type2String, false, true);
8678                         }
8679
8680                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1String, expString2, type2String);
8681
8682                         if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
8683                         {
8684                            exp.expType = exp.op.exp1.expType;
8685                            if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8686                         }
8687                         else if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
8688                         {
8689                            exp.expType = exp.op.exp2.expType;
8690                            if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8691                         }
8692                      }
8693                   }
8694                }
8695                else if(type2)
8696                {
8697                   // Maybe this was meant to be an enum...
8698                   if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
8699                   {
8700                      Type oldType = exp.op.exp1.expType;
8701                      exp.op.exp1.expType = null;
8702                      if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8703                         FreeType(oldType);
8704                      else
8705                         exp.op.exp1.expType = oldType;
8706                   }
8707
8708                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8709                   exp.op.exp1.destType = type2;
8710                   type2.refCount++;
8711                   /*
8712                   // TESTING THIS HERE... LATEST ADDITION
8713                   if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8714                   {
8715                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8716                      exp.op.exp1.destType = type1._class.registered.dataType;
8717                      if(type1._class.registered.dataType)
8718                         type1._class.registered.dataType.refCount++;
8719                   }
8720
8721                   // TESTING THIS HERE... LATEST ADDITION
8722                   if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8723                   {
8724                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8725                      exp.op.exp2.destType = type2._class.registered.dataType;
8726                      if(type2._class.registered.dataType)
8727                         type2._class.registered.dataType.refCount++;
8728                   }
8729                   */
8730
8731                   if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false))
8732                   {
8733                      if(exp.expType) FreeType(exp.expType);
8734                      exp.expType = exp.op.exp1.destType;
8735                      if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8736                   }
8737                }
8738             }
8739             else if(type2 && (!type1 || (type2.kind == classType && type1.kind != classType)))
8740             {
8741                if(type1 && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
8742                {
8743                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8744                   // Convert e.g. / 4 into / 4.0
8745                   exp.op.exp1.destType = type2._class.registered.dataType;
8746                   if(type2._class.registered.dataType)
8747                      type2._class.registered.dataType.refCount++;
8748                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8749                }
8750                if(exp.op.op == '!')
8751                {
8752                   exp.expType = MkClassType("bool");
8753                   exp.expType.truth = true;
8754                }
8755                else
8756                {
8757                   exp.expType = type2;
8758                   if(type2) type2.refCount++;
8759                }
8760             }
8761             else if(type1 && (!type2 || (type1.kind == classType && type2.kind != classType)))
8762             {
8763                if(type2 && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
8764                {
8765                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8766                   // Convert e.g. / 4 into / 4.0
8767                   exp.op.exp2.destType = type1._class.registered.dataType;
8768                   if(type1._class.registered.dataType)
8769                      type1._class.registered.dataType.refCount++;
8770                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8771                }
8772                exp.expType = type1;
8773                if(type1) type1.refCount++;
8774             }
8775          }
8776
8777          yylloc = exp.loc;
8778          if(exp.op.exp1 && !exp.op.exp1.expType)
8779          {
8780             char expString[10000];
8781             expString[0] = '\0';
8782             if(inCompiler)
8783             {
8784                PrintExpression(exp.op.exp1, expString);
8785                ChangeCh(expString, '\n', ' ');
8786             }
8787             if(expString[0])
8788                Compiler_Error($"couldn't determine type of %s\n", expString);
8789          }
8790          if(exp.op.exp2 && !exp.op.exp2.expType)
8791          {
8792             char expString[10240];
8793             expString[0] = '\0';
8794             if(inCompiler)
8795             {
8796                PrintExpression(exp.op.exp2, expString);
8797                ChangeCh(expString, '\n', ' ');
8798             }
8799             if(expString[0])
8800                Compiler_Error($"couldn't determine type of %s\n", expString);
8801          }
8802
8803          if(boolResult)
8804          {
8805             FreeType(exp.expType);
8806             exp.expType = MkClassType("bool");
8807             exp.expType.truth = true;
8808          }
8809
8810          if(exp.op.op != SIZEOF)
8811             exp.isConstant = (!exp.op.exp1 || exp.op.exp1.isConstant) &&
8812                (!exp.op.exp2 || exp.op.exp2.isConstant);
8813
8814          if(exp.op.op == SIZEOF && exp.op.exp2.expType)
8815          {
8816             DeclareType(exp.op.exp2.expType, false, false);
8817          }
8818
8819          yylloc = oldyylloc;
8820
8821          FreeType(dummy);
8822          if(type2)
8823             FreeType(type2);
8824          break;
8825       }
8826       case bracketsExp:
8827       case extensionExpressionExp:
8828       {
8829          Expression e;
8830          exp.isConstant = true;
8831          for(e = exp.list->first; e; e = e.next)
8832          {
8833             bool inced = false;
8834             if(!e.next)
8835             {
8836                FreeType(e.destType);
8837                e.destType = exp.destType;
8838                if(e.destType) { exp.destType.refCount++; e.destType.count++; inced = true; }
8839             }
8840             ProcessExpressionType(e);
8841             if(inced)
8842                exp.destType.count--;
8843             if(!exp.expType && !e.next)
8844             {
8845                exp.expType = e.expType;
8846                if(e.expType) e.expType.refCount++;
8847             }
8848             if(!e.isConstant)
8849                exp.isConstant = false;
8850          }
8851
8852          // In case a cast became a member...
8853          e = exp.list->first;
8854          if(!e.next && e.type == memberExp)
8855          {
8856             // Preserve prev, next
8857             Expression next = exp.next, prev = exp.prev;
8858
8859
8860             FreeType(exp.expType);
8861             FreeType(exp.destType);
8862             delete exp.list;
8863
8864             *exp = *e;
8865
8866             exp.prev = prev;
8867             exp.next = next;
8868
8869             delete e;
8870
8871             ProcessExpressionType(exp);
8872          }
8873          break;
8874       }
8875       case indexExp:
8876       {
8877          Expression e;
8878          exp.isConstant = true;
8879
8880          ProcessExpressionType(exp.index.exp);
8881          if(!exp.index.exp.isConstant)
8882             exp.isConstant = false;
8883
8884          if(exp.index.exp.expType)
8885          {
8886             Type source = exp.index.exp.expType;
8887             if(source.kind == classType && source._class && source._class.registered)
8888             {
8889                Class _class = source._class.registered;
8890                Class c = _class.templateClass ? _class.templateClass : _class;
8891                if(_class != containerClass && eClass_IsDerived(c, containerClass) && _class.templateArgs)
8892                {
8893                   exp.expType = ProcessTypeString(_class.templateArgs[2].dataTypeString, false);
8894
8895                   if(exp.index.index && exp.index.index->last)
8896                   {
8897                      ((Expression)exp.index.index->last).destType = ProcessTypeString(_class.templateArgs[1].dataTypeString, false);
8898                   }
8899                }
8900             }
8901          }
8902
8903          for(e = exp.index.index->first; e; e = e.next)
8904          {
8905             if(!e.next && exp.index.exp.expType && exp.index.exp.expType.kind == arrayType && exp.index.exp.expType.enumClass)
8906             {
8907                if(e.destType) FreeType(e.destType);
8908                e.destType = MkClassType(exp.index.exp.expType.enumClass.string);
8909             }
8910             ProcessExpressionType(e);
8911             if(!e.next)
8912             {
8913                // Check if this type is int
8914             }
8915             if(!e.isConstant)
8916                exp.isConstant = false;
8917          }
8918
8919          if(!exp.expType)
8920             exp.expType = Dereference(exp.index.exp.expType);
8921          if(exp.expType)
8922             DeclareType(exp.expType, false, false);
8923          break;
8924       }
8925       case callExp:
8926       {
8927          Expression e;
8928          Type functionType;
8929          Type methodType = null;
8930          char name[1024];
8931          name[0] = '\0';
8932
8933          if(inCompiler)
8934          {
8935             PrintExpression(exp.call.exp,  name);
8936             if(exp.call.exp.expType && !exp.call.exp.expType.returnType)
8937             {
8938                //exp.call.exp.expType = null;
8939                PrintExpression(exp.call.exp,  name);
8940             }
8941          }
8942          if(exp.call.exp.type == identifierExp)
8943          {
8944             Expression idExp = exp.call.exp;
8945             Identifier id = idExp.identifier;
8946             if(!strcmp(id.string, "__builtin_frame_address"))
8947             {
8948                exp.expType = ProcessTypeString("void *", true);
8949                if(exp.call.arguments && exp.call.arguments->first)
8950                   ProcessExpressionType(exp.call.arguments->first);
8951                break;
8952             }
8953             else if(!strcmp(id.string, "__ENDIAN_PAD"))
8954             {
8955                exp.expType = ProcessTypeString("int", true);
8956                if(exp.call.arguments && exp.call.arguments->first)
8957                   ProcessExpressionType(exp.call.arguments->first);
8958                break;
8959             }
8960             else if(!strcmp(id.string, "Max") ||
8961                !strcmp(id.string, "Min") ||
8962                !strcmp(id.string, "Sgn") ||
8963                !strcmp(id.string, "Abs"))
8964             {
8965                Expression a = null;
8966                Expression b = null;
8967                Expression tempExp1 = null, tempExp2 = null;
8968                if((!strcmp(id.string, "Max") ||
8969                   !strcmp(id.string, "Min")) && exp.call.arguments->count == 2)
8970                {
8971                   a = exp.call.arguments->first;
8972                   b = exp.call.arguments->last;
8973                   tempExp1 = a;
8974                   tempExp2 = b;
8975                }
8976                else if(exp.call.arguments->count == 1)
8977                {
8978                   a = exp.call.arguments->first;
8979                   tempExp1 = a;
8980                }
8981
8982                if(a)
8983                {
8984                   exp.call.arguments->Clear();
8985                   idExp.identifier = null;
8986
8987                   FreeExpContents(exp);
8988
8989                   ProcessExpressionType(a);
8990                   if(b)
8991                      ProcessExpressionType(b);
8992
8993                   exp.type = bracketsExp;
8994                   exp.list = MkList();
8995
8996                   if(a.expType && (!b || b.expType))
8997                   {
8998                      if((!a.isConstant && a.type != identifierExp) || (b && !b.isConstant && b.type != identifierExp))
8999                      {
9000                         // Use the simpleStruct name/ids for now...
9001                         if(inCompiler)
9002                         {
9003                            OldList * specs = MkList();
9004                            OldList * decls = MkList();
9005                            Declaration decl;
9006                            char temp1[1024], temp2[1024];
9007
9008                            GetTypeSpecs(a.expType, specs);
9009
9010                            if(a && !a.isConstant && a.type != identifierExp)
9011                            {
9012                               sprintf(temp1, "__simpleStruct%d", curContext.simpleID++);
9013                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp1)), null));
9014                               tempExp1 = QMkExpId(temp1);
9015                               tempExp1.expType = a.expType;
9016                               if(a.expType)
9017                                  a.expType.refCount++;
9018                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp1), '=', a));
9019                            }
9020                            if(b && !b.isConstant && b.type != identifierExp)
9021                            {
9022                               sprintf(temp2, "__simpleStruct%d", curContext.simpleID++);
9023                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp2)), null));
9024                               tempExp2 = QMkExpId(temp2);
9025                               tempExp2.expType = b.expType;
9026                               if(b.expType)
9027                                  b.expType.refCount++;
9028                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp2), '=', b));
9029                            }
9030
9031                            decl = MkDeclaration(specs, decls);
9032                            if(!curCompound.compound.declarations)
9033                               curCompound.compound.declarations = MkList();
9034                            curCompound.compound.declarations->Insert(null, decl);
9035                         }
9036                      }
9037                   }
9038
9039                   if(!strcmp(id.string, "Max") || !strcmp(id.string, "Min"))
9040                   {
9041                      int op = (!strcmp(id.string, "Max")) ? '>' : '<';
9042                      ListAdd(exp.list,
9043                         MkExpCondition(MkExpBrackets(MkListOne(
9044                            MkExpOp(CopyExpression(tempExp1), op, CopyExpression(tempExp2)))),
9045                            MkListOne(CopyExpression(tempExp1)), CopyExpression(tempExp2)));
9046                      exp.expType = a.expType;
9047                      if(a.expType)
9048                         a.expType.refCount++;
9049                   }
9050                   else if(!strcmp(id.string, "Abs"))
9051                   {
9052                      ListAdd(exp.list,
9053                         MkExpCondition(MkExpBrackets(MkListOne(
9054                            MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9055                            MkListOne(MkExpOp(null, '-', CopyExpression(tempExp1))), CopyExpression(tempExp1)));
9056                      exp.expType = a.expType;
9057                      if(a.expType)
9058                         a.expType.refCount++;
9059                   }
9060                   else if(!strcmp(id.string, "Sgn"))
9061                   {
9062                      // ((!(a))?(0):(((a)<0)?(-1):(1)))
9063                      ListAdd(exp.list,
9064                         MkExpCondition(MkExpBrackets(MkListOne(
9065                            MkExpOp(null, '!', CopyExpression(tempExp1)))), MkListOne(MkExpConstant("0")),
9066                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(
9067                                  MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9068                                  MkListOne(MkExpConstant("-1")), MkExpConstant("1"))))));
9069                      exp.expType = ProcessTypeString("int", false);
9070                   }
9071
9072                   FreeExpression(tempExp1);
9073                   if(tempExp2) FreeExpression(tempExp2);
9074
9075                   FreeIdentifier(id);
9076                   break;
9077                }
9078             }
9079          }
9080
9081          {
9082             Type dummy
9083             {
9084                count = 1;
9085                refCount = 1;
9086             };
9087             if(!exp.call.exp.destType)
9088             {
9089                exp.call.exp.destType = dummy;
9090                dummy.refCount++;
9091             }
9092             ProcessExpressionType(exp.call.exp);
9093             if(exp.call.exp.destType == dummy)
9094             {
9095                FreeType(dummy);
9096                exp.call.exp.destType = null;
9097             }
9098             FreeType(dummy);
9099          }
9100
9101          // Check argument types against parameter types
9102          functionType = exp.call.exp.expType;
9103
9104          if(functionType && functionType.kind == TypeKind::methodType)
9105          {
9106             methodType = functionType;
9107             functionType = methodType.method.dataType;
9108
9109             //if(functionType.returnType && functionType.returnType.kind == thisClassType)
9110             // TOCHECK: Instead of doing this here could this be done per param?
9111             if(exp.call.exp.expType.usedClass)
9112             {
9113                char typeString[1024];
9114                typeString[0] = '\0';
9115                {
9116                   Symbol back = functionType.thisClass;
9117                   // Do not output class specifier here (thisclass was added to this)
9118                   functionType.thisClass = null;
9119                   PrintType(functionType, typeString, true, true);
9120                   functionType.thisClass = back;
9121                }
9122                if(strstr(typeString, "thisclass"))
9123                {
9124                   OldList * specs = MkList();
9125                   Declarator decl;
9126                   {
9127                      Context context = SetupTemplatesContext(exp.call.exp.expType.usedClass);
9128
9129                      decl = SpecDeclFromString(typeString, specs, null);
9130
9131                      // SET THIS TO FALSE WHEN PROCESSING THISCLASS OUTSIDE THE CLASS
9132                      if(thisClass != (exp.call.exp.expType.usedClass.templateClass ? exp.call.exp.expType.usedClass.templateClass :
9133                         exp.call.exp.expType.usedClass))
9134                         thisClassParams = false;
9135
9136                      ReplaceThisClassSpecifiers(specs, exp.call.exp.expType.usedClass);
9137                      {
9138                         Class backupThisClass = thisClass;
9139                         thisClass = exp.call.exp.expType.usedClass;
9140                         ProcessDeclarator(decl);
9141                         thisClass = backupThisClass;
9142                      }
9143
9144                      thisClassParams = true;
9145
9146                      functionType = ProcessType(specs, decl);
9147                      functionType.refCount = 0;
9148                      FinishTemplatesContext(context);
9149                   }
9150
9151                   FreeList(specs, FreeSpecifier);
9152                   FreeDeclarator(decl);
9153                 }
9154             }
9155          }
9156          if(functionType && functionType.kind == pointerType && functionType.type && functionType.type.kind == TypeKind::functionType)
9157          {
9158             Type type = functionType.type;
9159             if(!functionType.refCount)
9160             {
9161                functionType.type = null;
9162                FreeType(functionType);
9163             }
9164             //methodType = functionType;
9165             functionType = type;
9166          }
9167          if(functionType && functionType.kind != TypeKind::functionType)
9168          {
9169             Compiler_Error($"called object %s is not a function\n", name);
9170          }
9171          else if(functionType)
9172          {
9173             bool emptyParams = false, noParams = false;
9174             Expression e = exp.call.arguments ? exp.call.arguments->first : null;
9175             Type type = functionType.params.first;
9176             Expression memberExp = (exp.call.exp.type == ExpressionType::memberExp) ? exp.call.exp : null;
9177             int extra = 0;
9178             Location oldyylloc = yylloc;
9179
9180             if(!type) emptyParams = true;
9181
9182             // WORKING ON THIS:
9183             if(functionType.extraParam && e && functionType.thisClass)
9184             {
9185                e.destType = MkClassType(functionType.thisClass.string);
9186                e = e.next;
9187             }
9188
9189             // WHY WAS THIS COMMENTED OUT ? Broke DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
9190             // Fixed #141 by adding '&& !functionType.extraParam'
9191             if(!functionType.staticMethod && !functionType.extraParam)
9192             {
9193                if(memberExp && memberExp.member.exp && memberExp.member.exp.expType && memberExp.member.exp.expType.kind == subClassType &&
9194                   memberExp.member.exp.expType._class)
9195                {
9196                   type = MkClassType(memberExp.member.exp.expType._class.string);
9197                   if(e)
9198                   {
9199                      e.destType = type;
9200                      e = e.next;
9201                      type = functionType.params.first;
9202                   }
9203                   else
9204                      type.refCount = 0;
9205                }
9206                else if(!memberExp && (functionType.thisClass || (methodType && methodType.methodClass)))
9207                {
9208                   type = MkClassType(functionType.thisClass ? functionType.thisClass.string : (methodType ? methodType.methodClass.fullName : null));
9209                   type.byReference = functionType.byReference;
9210                   type.typedByReference = functionType.typedByReference;
9211                   if(e)
9212                   {
9213                      // Allow manually passing a class for typed object
9214                      if(e.next && type.kind == classType && (functionType && functionType.thisClass) && functionType.classObjectType == typedObject)
9215                         e = e.next;
9216                      e.destType = type;
9217                      e = e.next;
9218                      type = functionType.params.first;
9219                   }
9220                   else
9221                      type.refCount = 0;
9222                   //extra = 1;
9223                }
9224             }
9225
9226             if(type && type.kind == voidType)
9227             {
9228                noParams = true;
9229                if(!type.refCount) FreeType(type);
9230                type = null;
9231             }
9232
9233             for( ; e; e = e.next)
9234             {
9235                if(!type && !emptyParams)
9236                {
9237                   yylloc = e.loc;
9238                   if(methodType && methodType.methodClass)
9239                      Compiler_Error($"too many arguments for method %s::%s (%d given, expected %d)\n",
9240                         methodType.methodClass.fullName, methodType.method.name, exp.call.arguments->count,
9241                         noParams ? 0 : functionType.params.count);
9242                   else
9243                      Compiler_Error($"too many arguments for function %s (%d given, expected %d)\n",
9244                         name /*exp.call.exp.identifier.string*/, exp.call.arguments->count,
9245                         noParams ? 0 : functionType.params.count);
9246                   break;
9247                }
9248
9249                if(methodType && type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type)
9250                {
9251                   Type templatedType = null;
9252                   Class _class = methodType.usedClass;
9253                   ClassTemplateParameter curParam = null;
9254                   int id = 0;
9255                   if(_class && _class.templateArgs /*&& _class.templateClass*/)
9256                   {
9257                      Class sClass;
9258                      for(sClass = _class; sClass; sClass = sClass.base)
9259                      {
9260                         if(sClass.templateClass) sClass = sClass.templateClass;
9261                         id = 0;
9262                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9263                         {
9264                            if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
9265                            {
9266                               Class nextClass;
9267                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
9268                               {
9269                                  if(nextClass.templateClass) nextClass = nextClass.templateClass;
9270                                  id += nextClass.templateParams.count;
9271                               }
9272                               break;
9273                            }
9274                            id++;
9275                         }
9276                         if(curParam) break;
9277                      }
9278                   }
9279                   if(curParam && _class.templateArgs[id].dataTypeString)
9280                   {
9281                      ClassTemplateArgument arg = _class.templateArgs[id];
9282                      {
9283                         Context context = SetupTemplatesContext(_class);
9284
9285                         /*if(!arg.dataType)
9286                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9287                         templatedType = ProcessTypeString(arg.dataTypeString, false);
9288                         FinishTemplatesContext(context);
9289                      }
9290                      e.destType = templatedType;
9291                      if(templatedType)
9292                      {
9293                         templatedType.passAsTemplate = true;
9294                         // templatedType.refCount++;
9295                      }
9296                   }
9297                   else
9298                   {
9299                      e.destType = type;
9300                      if(type) type.refCount++;
9301                   }
9302                }
9303                else
9304                {
9305                   if(type && type.kind == ellipsisType && type.prev && type.prev.kind == classType && type.prev.classObjectType)
9306                   {
9307                      e.destType = type.prev;
9308                      e.destType.refCount++;
9309                   }
9310                   else
9311                   {
9312                      e.destType = type;
9313                      if(type) type.refCount++;
9314                   }
9315                }
9316                // Don't reach the end for the ellipsis
9317                if(type && type.kind != ellipsisType)
9318                {
9319                   Type next = type.next;
9320                   if(!type.refCount) FreeType(type);
9321                   type = next;
9322                }
9323             }
9324
9325             if(type && type.kind != ellipsisType)
9326             {
9327                if(methodType && methodType.methodClass)
9328                   Compiler_Warning($"not enough arguments for method %s::%s (%d given, expected %d)\n",
9329                      methodType.methodClass.fullName, methodType.method.name, exp.call.arguments ? exp.call.arguments->count : 0,
9330                      functionType.params.count + extra);
9331                else
9332                   Compiler_Warning($"not enough arguments for function %s (%d given, expected %d)\n",
9333                      name /*exp.call.exp.identifier.string*/, exp.call.arguments ? exp.call.arguments->count : 0,
9334                      functionType.params.count + extra);
9335             }
9336             yylloc = oldyylloc;
9337             if(type && !type.refCount) FreeType(type);
9338          }
9339          else
9340          {
9341             functionType = Type
9342             {
9343                refCount = 0;
9344                kind = TypeKind::functionType;
9345             };
9346
9347             if(exp.call.exp.type == identifierExp)
9348             {
9349                char * string = exp.call.exp.identifier.string;
9350                if(inCompiler)
9351                {
9352                   Symbol symbol;
9353                   Location oldyylloc = yylloc;
9354
9355                   yylloc = exp.call.exp.identifier.loc;
9356                   if(strstr(string, "__builtin_") == string)
9357                   {
9358                      if(exp.destType)
9359                      {
9360                         functionType.returnType = exp.destType;
9361                         exp.destType.refCount++;
9362                      }
9363                   }
9364                   else
9365                      Compiler_Warning($"%s undefined; assuming extern returning int\n", string);
9366                   symbol = Symbol { string = CopyString(string), type = ProcessTypeString("int()", true) };
9367                   globalContext.symbols.Add((BTNode)symbol);
9368                   if(strstr(symbol.string, "::"))
9369                      globalContext.hasNameSpace = true;
9370
9371                   yylloc = oldyylloc;
9372                }
9373             }
9374             else if(exp.call.exp.type == memberExp)
9375             {
9376                /*Compiler_Warning($"%s undefined; assuming returning int\n",
9377                   exp.call.exp.member.member.string);*/
9378             }
9379             else
9380                Compiler_Warning($"callable object undefined; extern assuming returning int\n");
9381
9382             if(!functionType.returnType)
9383             {
9384                functionType.returnType = Type
9385                {
9386                   refCount = 1;
9387                   kind = intType;
9388                };
9389             }
9390          }
9391          if(functionType && functionType.kind == TypeKind::functionType)
9392          {
9393             exp.expType = functionType.returnType;
9394
9395             if(functionType.returnType)
9396                functionType.returnType.refCount++;
9397
9398             if(!functionType.refCount)
9399                FreeType(functionType);
9400          }
9401
9402          if(exp.call.arguments)
9403          {
9404             for(e = exp.call.arguments->first; e; e = e.next)
9405             {
9406                Type destType = e.destType;
9407                ProcessExpressionType(e);
9408             }
9409          }
9410          break;
9411       }
9412       case memberExp:
9413       {
9414          Type type;
9415          Location oldyylloc = yylloc;
9416          bool thisPtr;
9417          Expression checkExp = exp.member.exp;
9418          while(checkExp)
9419          {
9420             if(checkExp.type == castExp)
9421                checkExp = checkExp.cast.exp;
9422             else if(checkExp.type == bracketsExp)
9423                checkExp = checkExp.list ? checkExp.list->first : null;
9424             else
9425                break;
9426          }
9427
9428          thisPtr = (checkExp && checkExp.type == identifierExp && !strcmp(checkExp.identifier.string, "this"));
9429          exp.thisPtr = thisPtr;
9430
9431          // DOING THIS LATER NOW...
9432          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
9433          {
9434             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
9435             /* TODO: Name Space Fix ups
9436             if(!exp.member.member.classSym)
9437                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.fullName);
9438             */
9439          }
9440
9441          ProcessExpressionType(exp.member.exp);
9442          if(exp.member.exp.expType && exp.member.exp.expType.kind == classType && exp.member.exp.expType._class &&
9443             exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == normalClass)
9444          {
9445             exp.isConstant = false;
9446          }
9447          else
9448             exp.isConstant = exp.member.exp.isConstant;
9449          type = exp.member.exp.expType;
9450
9451          yylloc = exp.loc;
9452
9453          if(type && (type.kind == templateType))
9454          {
9455             Class _class = thisClass ? thisClass : currentClass;
9456             ClassTemplateParameter param = null;
9457             if(_class)
9458             {
9459                for(param = _class.templateParams.first; param; param = param.next)
9460                {
9461                   if(param.type == identifier && exp.member.member && exp.member.member.string && !strcmp(param.name, exp.member.member.string))
9462                      break;
9463                }
9464             }
9465             if(param && param.defaultArg.member)
9466             {
9467                Expression argExp = GetTemplateArgExpByName(param.name, thisClass, TemplateParameterType::identifier);
9468                if(argExp)
9469                {
9470                   Expression expMember = exp.member.exp;
9471                   Declarator decl;
9472                   OldList * specs = MkList();
9473                   char thisClassTypeString[1024];
9474
9475                   FreeIdentifier(exp.member.member);
9476
9477                   ProcessExpressionType(argExp);
9478
9479                   {
9480                      char * colon = strstr(param.defaultArg.memberString, "::");
9481                      if(colon)
9482                      {
9483                         char className[1024];
9484                         Class sClass;
9485
9486                         memcpy(thisClassTypeString, param.defaultArg.memberString, colon - param.defaultArg.memberString);
9487                         thisClassTypeString[colon - param.defaultArg.memberString] = '\0';
9488                      }
9489                      else
9490                         strcpy(thisClassTypeString, _class.fullName);
9491                   }
9492
9493                   decl = SpecDeclFromString(param.defaultArg.member.dataTypeString, specs, null);
9494
9495                   exp.expType = ProcessType(specs, decl);
9496                   if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.templateClass)
9497                   {
9498                      Class expClass = exp.expType._class.registered;
9499                      Class cClass = null;
9500                      int c;
9501                      int paramCount = 0;
9502                      int lastParam = -1;
9503
9504                      char templateString[1024];
9505                      ClassTemplateParameter param;
9506                      sprintf(templateString, "%s<", expClass.templateClass.fullName);
9507                      for(cClass = expClass; cClass; cClass = cClass.base)
9508                      {
9509                         int p = 0;
9510                         for(param = cClass.templateParams.first; param; param = param.next)
9511                         {
9512                            int id = p;
9513                            Class sClass;
9514                            ClassTemplateArgument arg;
9515                            for(sClass = cClass.base; sClass; sClass = sClass.base) id += sClass.templateParams.count;
9516                            arg = expClass.templateArgs[id];
9517
9518                            for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
9519                            {
9520                               ClassTemplateParameter cParam;
9521                               //int p = numParams - sClass.templateParams.count;
9522                               int p = 0;
9523                               Class nextClass;
9524                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) p += nextClass.templateParams.count;
9525
9526                               for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
9527                               {
9528                                  if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
9529                                  {
9530                                     if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9531                                     {
9532                                        arg.dataTypeString = _class.templateArgs[p].dataTypeString;
9533                                        arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
9534                                        break;
9535                                     }
9536                                  }
9537                               }
9538                            }
9539
9540                            {
9541                               char argument[256];
9542                               argument[0] = '\0';
9543                               /*if(arg.name)
9544                               {
9545                                  strcat(argument, arg.name.string);
9546                                  strcat(argument, " = ");
9547                               }*/
9548                               switch(param.type)
9549                               {
9550                                  case expression:
9551                                  {
9552                                     // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
9553                                     char expString[1024];
9554                                     OldList * specs = MkList();
9555                                     Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
9556                                     Expression exp;
9557                                     char * string = PrintHexUInt64(arg.expression.ui64);
9558                                     exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
9559                                     delete string;
9560
9561                                     ProcessExpressionType(exp);
9562                                     ComputeExpression(exp);
9563                                     expString[0] = '\0';
9564                                     PrintExpression(exp, expString);
9565                                     strcat(argument, expString);
9566                                     // delete exp;
9567                                     FreeExpression(exp);
9568                                     break;
9569                                  }
9570                                  case identifier:
9571                                  {
9572                                     strcat(argument, arg.member.name);
9573                                     break;
9574                                  }
9575                                  case TemplateParameterType::type:
9576                                  {
9577                                     if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9578                                     {
9579                                        if(!strcmp(arg.dataTypeString, "thisclass"))
9580                                           strcat(argument, thisClassTypeString);
9581                                        else
9582                                           strcat(argument, arg.dataTypeString);
9583                                     }
9584                                     break;
9585                                  }
9586                               }
9587                               if(argument[0])
9588                               {
9589                                  if(paramCount) strcat(templateString, ", ");
9590                                  if(lastParam != p - 1)
9591                                  {
9592                                     strcat(templateString, param.name);
9593                                     strcat(templateString, " = ");
9594                                  }
9595                                  strcat(templateString, argument);
9596                                  paramCount++;
9597                                  lastParam = p;
9598                               }
9599                               p++;
9600                            }
9601                         }
9602                      }
9603                      {
9604                         int len = strlen(templateString);
9605                         if(templateString[len-1] == '>') templateString[len++] = ' ';
9606                         templateString[len++] = '>';
9607                         templateString[len++] = '\0';
9608                      }
9609                      {
9610                         Context context = SetupTemplatesContext(_class);
9611                         FreeType(exp.expType);
9612                         exp.expType = ProcessTypeString(templateString, false);
9613                         FinishTemplatesContext(context);
9614                      }
9615                   }
9616
9617                   // *([expType] *)(((byte *)[exp.member.exp]) + [argExp].member.offset)
9618                   exp.type = bracketsExp;
9619                   exp.list = MkListOne(MkExpOp(null, '*',
9620                   /*opExp;
9621                   exp.op.op = '*';
9622                   exp.op.exp1 = null;
9623                   exp.op.exp2 = */
9624                   MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpBrackets(MkListOne(MkExpOp(
9625                      MkExpBrackets(MkListOne(
9626                         MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), expMember))),
9627                            '+',
9628                            MkExpOp(MkExpMember(MkExpMember(argExp, MkIdentifier("member")), MkIdentifier("offset")),
9629                            '+',
9630                            MkExpMember(MkExpMember(MkExpMember(CopyExpression(argExp), MkIdentifier("member")), MkIdentifier("_class")), MkIdentifier("offset")))))))
9631
9632                            ));
9633                }
9634             }
9635             else if(type.templateParameter && type.templateParameter.type == TemplateParameterType::type &&
9636                (type.templateParameter.dataType || type.templateParameter.dataTypeString))
9637             {
9638                type = ProcessTemplateParameterType(type.templateParameter);
9639             }
9640          }
9641          // TODO: *** This seems to be where we should add method support for all basic types ***
9642          if(type && (type.kind == templateType));
9643          else if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType ||
9644                           type.kind == int64Type || type.kind == shortType || type.kind == longType || type.kind == charType || type.kind == _BoolType ||
9645                           type.kind == intPtrType || type.kind == intSizeType || type.kind == floatType || type.kind == doubleType ||
9646                           (type.kind == pointerType && type.type.kind == charType)))
9647          {
9648             Identifier id = exp.member.member;
9649             TypeKind typeKind = type.kind;
9650             Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
9651             if(typeKind == subClassType && exp.member.exp.type == classExp)
9652             {
9653                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
9654                typeKind = classType;
9655             }
9656
9657             if(id)
9658             {
9659                if(typeKind == intType || typeKind == enumType)
9660                   _class = eSystem_FindClass(privateModule, "int");
9661                else if(!_class)
9662                {
9663                   if(type.kind == classType && type._class && type._class.registered)
9664                   {
9665                      _class = type._class.registered;
9666                   }
9667                   else if((type.kind == arrayType || type.kind == pointerType) && type.type && type.type.kind == charType)
9668                   {
9669                      _class = FindClass("char *").registered;
9670                   }
9671                   else if(type.kind == pointerType)
9672                   {
9673                      _class = eSystem_FindClass(privateModule, "uintptr");
9674                      FreeType(exp.expType);
9675                      exp.expType = ProcessTypeString("uintptr", false);
9676                      exp.byReference = true;
9677                   }
9678                   else
9679                   {
9680                      char string[1024] = "";
9681                      Symbol classSym;
9682                      PrintTypeNoConst(type, string, false, true);
9683                      classSym = FindClass(string);
9684                      if(classSym) _class = classSym.registered;
9685                   }
9686                }
9687             }
9688
9689             if(_class && id)
9690             {
9691                /*bool thisPtr =
9692                   (exp.member.exp.type == identifierExp &&
9693                   !strcmp(exp.member.exp.identifier.string, "this"));*/
9694                Property prop = null;
9695                Method method = null;
9696                DataMember member = null;
9697                Property revConvert = null;
9698                ClassProperty classProp = null;
9699
9700                if(id && id._class && id._class.name && !strcmp(id._class.name, "property"))
9701                   exp.member.memberType = propertyMember;
9702
9703                if(id && id._class && type._class && !eClass_IsDerived(type._class.registered, _class))
9704                   Compiler_Error($"invalid class specifier %s for object of class %s\n", _class.fullName, type._class.string);
9705
9706                if(typeKind != subClassType)
9707                {
9708                   // Prioritize data members over properties for "this"
9709                   if((exp.member.memberType == unresolvedMember && thisPtr) || exp.member.memberType == dataMember)
9710                   {
9711                      member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
9712                      if(member && member._class != (_class.templateClass ? _class.templateClass : _class) && exp.member.memberType != dataMember)
9713                      {
9714                         prop = eClass_FindProperty(_class, id.string, privateModule);
9715                         if(prop)
9716                            member = null;
9717                      }
9718                      if(!member && !prop)
9719                         prop = eClass_FindProperty(_class, id.string, privateModule);
9720                      if((member && member._class == (_class.templateClass ? _class.templateClass : _class)) ||
9721                         (prop && prop._class == (_class.templateClass ? _class.templateClass : _class)))
9722                         exp.member.thisPtr = true;
9723                   }
9724                   // Prioritize properties over data members otherwise
9725                   else
9726                   {
9727                      // First look for Public Members (Unless class specifier is provided, which skips public priority)
9728                      if(!id.classSym)
9729                      {
9730                         prop = eClass_FindProperty(_class, id.string, null);
9731                         if(!id._class || !id._class.name || strcmp(id._class.name, "property"))
9732                            member = eClass_FindDataMember(_class, id.string, null, null, null);
9733                      }
9734
9735                      if(!prop && !member)
9736                      {
9737                         method = eClass_FindMethod(_class, id.string, null);
9738                         if(!method)
9739                         {
9740                            prop = eClass_FindProperty(_class, id.string, privateModule);
9741                            if(!id._class || !id._class.name || strcmp(id._class.name, "property"))
9742                               member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
9743                         }
9744                      }
9745
9746                      if(member && prop)
9747                      {
9748                         if(member._class != prop._class && !id._class && eClass_IsDerived(member._class, prop._class))
9749                            prop = null;
9750                         else
9751                            member = null;
9752                      }
9753                   }
9754                }
9755                if(!prop && !member && !method)     // NOTE: Recently added the !method here, causes private methods to unprioritized
9756                   method = eClass_FindMethod(_class, id.string, privateModule);
9757                if(!prop && !member && !method)
9758                {
9759                   if(typeKind == subClassType)
9760                   {
9761                      classProp = eClass_FindClassProperty(type._class.registered, exp.member.member.string);
9762                      if(classProp)
9763                      {
9764                         exp.member.memberType = classPropertyMember;
9765                         exp.expType = ProcessTypeString(classProp.dataTypeString, false);
9766                      }
9767                      else
9768                      {
9769                         // Assume this is a class_data member
9770                         char structName[1024];
9771                         Identifier id = exp.member.member;
9772                         Expression classExp = exp.member.exp;
9773                         type.refCount++;
9774
9775                         FreeType(classExp.expType);
9776                         classExp.expType = ProcessTypeString("ecere::com::Class", false);
9777
9778                         strcpy(structName, "__ecereClassData_");
9779                         FullClassNameCat(structName, type._class.string, false);
9780                         exp.type = pointerExp;
9781                         exp.member.member = id;
9782
9783                         exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
9784                            MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
9785                               MkExpBrackets(MkListOne(MkExpOp(
9786                                  MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
9787                                     MkExpMember(classExp, MkIdentifier("data"))), '+',
9788                                        MkExpMember(MkExpClass(MkListOne(MkSpecifierName(type._class.string)), null), MkIdentifier("offsetClass")))))
9789                                  )));
9790
9791                         FreeType(type);
9792
9793                         ProcessExpressionType(exp);
9794                         return;
9795                      }
9796                   }
9797                   else
9798                   {
9799                      // Check for reverse conversion
9800                      // (Convert in an instantiation later, so that we can use
9801                      //  deep properties system)
9802                      Symbol classSym = FindClass(id.string);
9803                      if(classSym)
9804                      {
9805                         Class convertClass = classSym.registered;
9806                         if(convertClass)
9807                            revConvert = eClass_FindProperty(convertClass, _class.fullName, privateModule);
9808                      }
9809                   }
9810                }
9811
9812                if(prop)
9813                {
9814                   exp.member.memberType = propertyMember;
9815                   if(!prop.dataType)
9816                      ProcessPropertyType(prop);
9817                   exp.expType = prop.dataType;
9818                   if(prop.dataType) prop.dataType.refCount++;
9819                }
9820                else if(member)
9821                {
9822                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
9823                   {
9824                      FreeExpContents(exp);
9825                      exp.type = identifierExp;
9826                      exp.identifier = MkIdentifier("class");
9827                      ProcessExpressionType(exp);
9828                      return;
9829                   }
9830
9831                   exp.member.memberType = dataMember;
9832                   DeclareStruct(_class.fullName, false);
9833                   if(!member.dataType)
9834                   {
9835                      Context context = SetupTemplatesContext(_class);
9836                      member.dataType = ProcessTypeString(member.dataTypeString, false);
9837                      FinishTemplatesContext(context);
9838                   }
9839                   exp.expType = member.dataType;
9840                   if(member.dataType) member.dataType.refCount++;
9841                }
9842                else if(revConvert)
9843                {
9844                   exp.member.memberType = reverseConversionMember;
9845                   exp.expType = MkClassType(revConvert._class.fullName);
9846                }
9847                else if(method)
9848                {
9849                   //if(inCompiler)
9850                   {
9851                      /*if(id._class)
9852                      {
9853                         exp.type = identifierExp;
9854                         exp.identifier = exp.member.member;
9855                      }
9856                      else*/
9857                         exp.member.memberType = methodMember;
9858                   }
9859                   if(!method.dataType)
9860                      ProcessMethodType(method);
9861                   exp.expType = Type
9862                   {
9863                      refCount = 1;
9864                      kind = methodType;
9865                      method = method;
9866                   };
9867
9868                   // Tricky spot here... To use instance versus class virtual table
9869                   // Put it back to what it was... What did we break?
9870
9871                   // Had to put it back for overriding Main of Thread global instance
9872
9873                   //exp.expType.methodClass = _class;
9874                   exp.expType.methodClass = (id && id._class) ? _class : null;
9875
9876                   // Need the actual class used for templated classes
9877                   exp.expType.usedClass = _class;
9878                }
9879                else if(!classProp)
9880                {
9881                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
9882                   {
9883                      FreeExpContents(exp);
9884                      exp.type = identifierExp;
9885                      exp.identifier = MkIdentifier("class");
9886                      FreeType(exp.expType);
9887                      exp.expType = MkClassType("ecere::com::Class");
9888                      return;
9889                   }
9890                   yylloc = exp.member.member.loc;
9891                   Compiler_Error($"couldn't find member %s in class %s\n", id.string, _class.fullName);
9892                   if(inCompiler)
9893                      eClass_AddDataMember(_class, id.string, "int", 0, 0, publicAccess);
9894                }
9895
9896                if(_class && /*(_class.templateClass || _class.templateArgs) && */exp.expType)
9897                {
9898                   Class tClass;
9899
9900                   tClass = _class;
9901                   while(tClass && !tClass.templateClass) tClass = tClass.base;
9902
9903                   if(tClass && exp.expType.kind == templateType && exp.expType.templateParameter.type == TemplateParameterType::type)
9904                   {
9905                      int id = 0;
9906                      ClassTemplateParameter curParam = null;
9907                      Class sClass;
9908
9909                      for(sClass = tClass; sClass; sClass = sClass.base)
9910                      {
9911                         id = 0;
9912                         if(sClass.templateClass) sClass = sClass.templateClass;
9913                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9914                         {
9915                            if(curParam.type == TemplateParameterType::type && !strcmp(exp.expType.templateParameter.identifier.string, curParam.name))
9916                            {
9917                               for(sClass = sClass.base; sClass; sClass = sClass.base)
9918                                  id += sClass.templateParams.count;
9919                               break;
9920                            }
9921                            id++;
9922                         }
9923                         if(curParam) break;
9924                      }
9925
9926                      if(curParam && tClass.templateArgs[id].dataTypeString)
9927                      {
9928                         ClassTemplateArgument arg = tClass.templateArgs[id];
9929                         Context context = SetupTemplatesContext(tClass);
9930                         /*if(!arg.dataType)
9931                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9932                         FreeType(exp.expType);
9933                         exp.expType = ProcessTypeString(arg.dataTypeString, false);
9934                         if(exp.expType)
9935                         {
9936                            if(exp.expType.kind == thisClassType)
9937                            {
9938                               FreeType(exp.expType);
9939                               exp.expType = ReplaceThisClassType(_class);
9940                            }
9941
9942                            if(tClass.templateClass)
9943                               exp.expType.passAsTemplate = true;
9944                            //exp.expType.refCount++;
9945                            if(!exp.destType)
9946                            {
9947                               exp.destType = ProcessTypeString(arg.dataTypeString, false);
9948                               //exp.destType.refCount++;
9949
9950                               if(exp.destType.kind == thisClassType)
9951                               {
9952                                  FreeType(exp.destType);
9953                                  exp.destType = ReplaceThisClassType(_class);
9954                               }
9955                            }
9956                         }
9957                         FinishTemplatesContext(context);
9958                      }
9959                   }
9960                   // TODO: MORE GENERIC SUPPORT FOR DEEPER TYPES
9961                   else if(tClass && exp.expType.kind == pointerType && exp.expType.type && exp.expType.type.kind == templateType && exp.expType.type.templateParameter.type == TemplateParameterType::type)
9962                   {
9963                      int id = 0;
9964                      ClassTemplateParameter curParam = null;
9965                      Class sClass;
9966
9967                      for(sClass = tClass; sClass; sClass = sClass.base)
9968                      {
9969                         id = 0;
9970                         if(sClass.templateClass) sClass = sClass.templateClass;
9971                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9972                         {
9973                            if(curParam.type == TemplateParameterType::type &&
9974                               !strcmp(exp.expType.type.templateParameter.identifier.string, curParam.name))
9975                            {
9976                               for(sClass = sClass.base; sClass; sClass = sClass.base)
9977                                  id += sClass.templateParams.count;
9978                               break;
9979                            }
9980                            id++;
9981                         }
9982                         if(curParam) break;
9983                      }
9984
9985                      if(curParam)
9986                      {
9987                         ClassTemplateArgument arg = tClass.templateArgs[id];
9988                         Context context = SetupTemplatesContext(tClass);
9989                         Type basicType;
9990                         /*if(!arg.dataType)
9991                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9992
9993                         basicType = ProcessTypeString(arg.dataTypeString, false);
9994                         if(basicType)
9995                         {
9996                            if(basicType.kind == thisClassType)
9997                            {
9998                               FreeType(basicType);
9999                               basicType = ReplaceThisClassType(_class);
10000                            }
10001
10002                            /*    DO WE REALLY WANT THIS HERE? IT SEEMS TO BE ONLY USED WITH Array::array which was causing bug 135
10003                            if(tClass.templateClass)
10004                               basicType.passAsTemplate = true;
10005                            */
10006
10007                            FreeType(exp.expType);
10008
10009                            exp.expType = Type { refCount = 1, kind = pointerType, type = basicType };
10010                            //exp.expType.refCount++;
10011                            if(!exp.destType)
10012                            {
10013                               exp.destType = exp.expType;
10014                               exp.destType.refCount++;
10015                            }
10016
10017                            {
10018                               Expression newExp { };
10019                               OldList * specs = MkList();
10020                               Declarator decl;
10021                               decl = SpecDeclFromString(arg.dataTypeString, specs, null);
10022                               *newExp = *exp;
10023                               if(exp.destType) exp.destType.refCount++;
10024                               if(exp.expType)  exp.expType.refCount++;
10025                               exp.type = castExp;
10026                               exp.cast.typeName = MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl));
10027                               exp.cast.exp = newExp;
10028                               //FreeType(exp.expType);
10029                               //exp.expType = null;
10030                               //ProcessExpressionType(sourceExp);
10031                            }
10032                         }
10033                         FinishTemplatesContext(context);
10034                      }
10035                   }
10036                   else if(tClass && exp.expType.kind == classType && exp.expType._class && strchr(exp.expType._class.string, '<'))
10037                   {
10038                      Class expClass = exp.expType._class.registered;
10039                      if(expClass)
10040                      {
10041                         Class cClass = null;
10042                         int c;
10043                         int p = 0;
10044                         int paramCount = 0;
10045                         int lastParam = -1;
10046                         char templateString[1024];
10047                         ClassTemplateParameter param;
10048                         sprintf(templateString, "%s<", expClass.templateClass.fullName);
10049                         while(cClass != expClass)
10050                         {
10051                            Class sClass;
10052                            for(sClass = expClass; sClass && sClass.base != cClass; sClass = sClass.base);
10053                            cClass = sClass;
10054
10055                            for(param = cClass.templateParams.first; param; param = param.next)
10056                            {
10057                               Class cClassCur = null;
10058                               int c;
10059                               int cp = 0;
10060                               ClassTemplateParameter paramCur = null;
10061                               ClassTemplateArgument arg;
10062                               while(cClassCur != tClass && !paramCur)
10063                               {
10064                                  Class sClassCur;
10065                                  for(sClassCur = tClass; sClassCur && sClassCur.base != cClassCur; sClassCur = sClassCur.base);
10066                                  cClassCur = sClassCur;
10067
10068                                  for(paramCur = cClassCur.templateParams.first; paramCur; paramCur = paramCur.next)
10069                                  {
10070                                     if(!strcmp(paramCur.name, param.name))
10071                                     {
10072
10073                                        break;
10074                                     }
10075                                     cp++;
10076                                  }
10077                               }
10078                               if(paramCur && paramCur.type == TemplateParameterType::type)
10079                                  arg = tClass.templateArgs[cp];
10080                               else
10081                                  arg = expClass.templateArgs[p];
10082
10083                               {
10084                                  char argument[256];
10085                                  argument[0] = '\0';
10086                                  /*if(arg.name)
10087                                  {
10088                                     strcat(argument, arg.name.string);
10089                                     strcat(argument, " = ");
10090                                  }*/
10091                                  switch(param.type)
10092                                  {
10093                                     case expression:
10094                                     {
10095                                        // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
10096                                        char expString[1024];
10097                                        OldList * specs = MkList();
10098                                        Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
10099                                        Expression exp;
10100                                        char * string = PrintHexUInt64(arg.expression.ui64);
10101                                        exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
10102                                        delete string;
10103
10104                                        ProcessExpressionType(exp);
10105                                        ComputeExpression(exp);
10106                                        expString[0] = '\0';
10107                                        PrintExpression(exp, expString);
10108                                        strcat(argument, expString);
10109                                        // delete exp;
10110                                        FreeExpression(exp);
10111                                        break;
10112                                     }
10113                                     case identifier:
10114                                     {
10115                                        strcat(argument, arg.member.name);
10116                                        break;
10117                                     }
10118                                     case TemplateParameterType::type:
10119                                     {
10120                                        if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10121                                           strcat(argument, arg.dataTypeString);
10122                                        break;
10123                                     }
10124                                  }
10125                                  if(argument[0])
10126                                  {
10127                                     if(paramCount) strcat(templateString, ", ");
10128                                     if(lastParam != p - 1)
10129                                     {
10130                                        strcat(templateString, param.name);
10131                                        strcat(templateString, " = ");
10132                                     }
10133                                     strcat(templateString, argument);
10134                                     paramCount++;
10135                                     lastParam = p;
10136                                  }
10137                               }
10138                               p++;
10139                            }
10140                         }
10141                         {
10142                            int len = strlen(templateString);
10143                            if(templateString[len-1] == '>') templateString[len++] = ' ';
10144                            templateString[len++] = '>';
10145                            templateString[len++] = '\0';
10146                         }
10147
10148                         FreeType(exp.expType);
10149                         {
10150                            Context context = SetupTemplatesContext(tClass);
10151                            exp.expType = ProcessTypeString(templateString, false);
10152                            FinishTemplatesContext(context);
10153                         }
10154                      }
10155                   }
10156                }
10157             }
10158             else
10159                Compiler_Error($"undefined class %s\n", (id && (!id._class || id._class.name))? (id.classSym ? id.classSym.string : (type._class ? type._class.string : null)) : "(null)");
10160          }
10161          else if(type && (type.kind == structType || type.kind == unionType))
10162          {
10163             Type memberType = exp.member.member ? FindMember(type, exp.member.member.string) : null;
10164             if(memberType)
10165             {
10166                exp.expType = memberType;
10167                if(memberType)
10168                   memberType.refCount++;
10169             }
10170          }
10171          else
10172          {
10173             char expString[10240];
10174             expString[0] = '\0';
10175             if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10176             Compiler_Error($"member operator on non-structure type expression %s\n", expString);
10177          }
10178
10179          if(exp.expType && exp.expType.kind == thisClassType && (!exp.destType || exp.destType.kind != thisClassType))
10180          {
10181             if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType))
10182             {
10183                Identifier id = exp.member.member;
10184                Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10185                if(_class)
10186                {
10187                   FreeType(exp.expType);
10188                   exp.expType = ReplaceThisClassType(_class);
10189                }
10190             }
10191          }
10192          yylloc = oldyylloc;
10193          break;
10194       }
10195       // Convert x->y into (*x).y
10196       case pointerExp:
10197       {
10198          Type destType = exp.destType;
10199
10200          // DOING THIS LATER NOW...
10201          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
10202          {
10203             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
10204             /* TODO: Name Space Fix ups
10205             if(!exp.member.member.classSym)
10206                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.name);
10207             */
10208          }
10209
10210          exp.member.exp = MkExpBrackets(MkListOne(MkExpOp(null, '*', exp.member.exp)));
10211          exp.type = memberExp;
10212          if(destType)
10213             destType.count++;
10214          ProcessExpressionType(exp);
10215          if(destType)
10216             destType.count--;
10217          break;
10218       }
10219       case classSizeExp:
10220       {
10221          //ComputeExpression(exp);
10222
10223          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
10224          if(classSym && classSym.registered)
10225          {
10226             if(classSym.registered.type == noHeadClass)
10227             {
10228                char name[1024];
10229                name[0] = '\0';
10230                DeclareStruct(classSym.string, false);
10231                FreeSpecifier(exp._class);
10232                exp.type = typeSizeExp;
10233                FullClassNameCat(name, classSym.string, false);
10234                exp.typeName = MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null);
10235             }
10236             else
10237             {
10238                if(classSym.registered.fixed)
10239                {
10240                   FreeSpecifier(exp._class);
10241                   exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
10242                   exp.type = constantExp;
10243                }
10244                else
10245                {
10246                   char className[1024];
10247                   strcpy(className, "__ecereClass_");
10248                   FullClassNameCat(className, classSym.string, true);
10249                   MangleClassName(className);
10250
10251                   DeclareClass(classSym, className);
10252
10253                   FreeExpContents(exp);
10254                   exp.type = pointerExp;
10255                   exp.member.exp = MkExpIdentifier(MkIdentifier(className));
10256                   exp.member.member = MkIdentifier("structSize");
10257                }
10258             }
10259          }
10260
10261          exp.expType = Type
10262          {
10263             refCount = 1;
10264             kind = intType;
10265          };
10266          // exp.isConstant = true;
10267          break;
10268       }
10269       case typeSizeExp:
10270       {
10271          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
10272
10273          exp.expType = Type
10274          {
10275             refCount = 1;
10276             kind = intType;
10277          };
10278          exp.isConstant = true;
10279
10280          DeclareType(type, false, false);
10281          FreeType(type);
10282          break;
10283       }
10284       case castExp:
10285       {
10286          Type type = ProcessType(exp.cast.typeName.qualifiers, exp.cast.typeName.declarator);
10287          type.count = 1;
10288          FreeType(exp.cast.exp.destType);
10289          exp.cast.exp.destType = type;
10290          type.refCount++;
10291          ProcessExpressionType(exp.cast.exp);
10292          type.count = 0;
10293          exp.expType = type;
10294          //type.refCount++;
10295
10296          // if(!NeedCast(exp.cast.exp.expType, exp.cast.exp.destType))
10297          if(!exp.cast.exp.needCast && !NeedCast(exp.cast.exp.expType, type))
10298          {
10299             void * prev = exp.prev, * next = exp.next;
10300             Type expType = exp.cast.exp.destType;
10301             Expression castExp = exp.cast.exp;
10302             Type destType = exp.destType;
10303
10304             if(expType) expType.refCount++;
10305
10306             //FreeType(exp.destType);
10307             FreeType(exp.expType);
10308             FreeTypeName(exp.cast.typeName);
10309
10310             *exp = *castExp;
10311             FreeType(exp.expType);
10312             FreeType(exp.destType);
10313
10314             exp.expType = expType;
10315             exp.destType = destType;
10316
10317             delete castExp;
10318
10319             exp.prev = prev;
10320             exp.next = next;
10321
10322          }
10323          else
10324          {
10325             exp.isConstant = exp.cast.exp.isConstant;
10326          }
10327          //FreeType(type);
10328          break;
10329       }
10330       case extensionInitializerExp:
10331       {
10332          Type type = ProcessType(exp.initializer.typeName.qualifiers, exp.initializer.typeName.declarator);
10333          // We have yet to support this... ( { } initializers are currently processed inside ProcessDeclaration()'s initDeclaration case statement
10334          // ProcessInitializer(exp.initializer.initializer, type);
10335          exp.expType = type;
10336          break;
10337       }
10338       case vaArgExp:
10339       {
10340          Type type = ProcessType(exp.vaArg.typeName.qualifiers, exp.vaArg.typeName.declarator);
10341          ProcessExpressionType(exp.vaArg.exp);
10342          exp.expType = type;
10343          break;
10344       }
10345       case conditionExp:
10346       {
10347          Expression e;
10348          exp.isConstant = true;
10349
10350          FreeType(exp.cond.cond.destType);
10351          exp.cond.cond.destType = MkClassType("bool");
10352          exp.cond.cond.destType.truth = true;
10353          ProcessExpressionType(exp.cond.cond);
10354          if(!exp.cond.cond.isConstant)
10355             exp.isConstant = false;
10356          for(e = exp.cond.exp->first; e; e = e.next)
10357          {
10358             if(!e.next)
10359             {
10360                FreeType(e.destType);
10361                e.destType = exp.destType;
10362                if(e.destType) e.destType.refCount++;
10363             }
10364             ProcessExpressionType(e);
10365             if(!e.next)
10366             {
10367                exp.expType = e.expType;
10368                if(e.expType) e.expType.refCount++;
10369             }
10370             if(!e.isConstant)
10371                exp.isConstant = false;
10372          }
10373
10374          FreeType(exp.cond.elseExp.destType);
10375          // Added this check if we failed to find an expType
10376          // exp.cond.elseExp.destType = exp.expType ? exp.expType : exp.destType;
10377
10378          // Reversed it...
10379          exp.cond.elseExp.destType = exp.destType ? exp.destType : exp.expType;
10380
10381          if(exp.cond.elseExp.destType)
10382             exp.cond.elseExp.destType.refCount++;
10383          ProcessExpressionType(exp.cond.elseExp);
10384
10385          // FIXED THIS: Was done before calling process on elseExp
10386          if(!exp.cond.elseExp.isConstant)
10387             exp.isConstant = false;
10388          break;
10389       }
10390       case extensionCompoundExp:
10391       {
10392          if(exp.compound && exp.compound.compound.statements && exp.compound.compound.statements->last)
10393          {
10394             Statement last = exp.compound.compound.statements->last;
10395             if(last.type == expressionStmt && last.expressions && last.expressions->last)
10396             {
10397                ((Expression)last.expressions->last).destType = exp.destType;
10398                if(exp.destType)
10399                   exp.destType.refCount++;
10400             }
10401             ProcessStatement(exp.compound);
10402             exp.expType = (last.expressions && last.expressions->last) ? ((Expression)last.expressions->last).expType : null;
10403             if(exp.expType)
10404                exp.expType.refCount++;
10405          }
10406          break;
10407       }
10408       case classExp:
10409       {
10410          Specifier spec = exp._classExp.specifiers->first;
10411          if(spec && spec.type == nameSpecifier)
10412          {
10413             exp.expType = MkClassType(spec.name);
10414             exp.expType.kind = subClassType;
10415             exp.byReference = true;
10416          }
10417          else
10418          {
10419             exp.expType = MkClassType("ecere::com::Class");
10420             exp.byReference = true;
10421          }
10422          break;
10423       }
10424       case classDataExp:
10425       {
10426          Class _class = thisClass ? thisClass : currentClass;
10427          if(_class)
10428          {
10429             Identifier id = exp.classData.id;
10430             char structName[1024];
10431             Expression classExp;
10432             strcpy(structName, "__ecereClassData_");
10433             FullClassNameCat(structName, _class.fullName, false);
10434             exp.type = pointerExp;
10435             exp.member.member = id;
10436             if(curCompound && FindSymbol("this", curContext, curCompound.compound.context, false, false))
10437                classExp = MkExpMember(MkExpIdentifier(MkIdentifier("this")), MkIdentifier("_class"));
10438             else
10439                classExp = MkExpIdentifier(MkIdentifier("class"));
10440
10441             exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10442                MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10443                   MkExpBrackets(MkListOne(MkExpOp(
10444                      MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10445                         MkExpMember(classExp, MkIdentifier("data"))), '+',
10446                            MkExpMember(MkExpClass(MkListOne(MkSpecifierName(_class.fullName)), null), MkIdentifier("offsetClass")))))
10447                      )));
10448
10449             ProcessExpressionType(exp);
10450             return;
10451          }
10452          break;
10453       }
10454       case arrayExp:
10455       {
10456          Type type = null;
10457          char * typeString = null;
10458          char typeStringBuf[1024];
10459          if(exp.destType && exp.destType.kind == classType && exp.destType._class && exp.destType._class.registered &&
10460             exp.destType._class.registered != containerClass && eClass_IsDerived(exp.destType._class.registered, containerClass))
10461          {
10462             Class templateClass = exp.destType._class.registered;
10463             typeString = templateClass.templateArgs[2].dataTypeString;
10464          }
10465          else if(exp.list)
10466          {
10467             // Guess type from expressions in the array
10468             Expression e;
10469             for(e = exp.list->first; e; e = e.next)
10470             {
10471                ProcessExpressionType(e);
10472                if(e.expType)
10473                {
10474                   if(!type) { type = e.expType; type.refCount++; }
10475                   else
10476                   {
10477                      // if(!MatchType(e.expType, type, null, null, null, false, false, false))
10478                      if(!MatchTypeExpression(e, type, null, false))
10479                      {
10480                         FreeType(type);
10481                         type = e.expType;
10482                         e.expType = null;
10483
10484                         e = exp.list->first;
10485                         ProcessExpressionType(e);
10486                         if(e.expType)
10487                         {
10488                            //if(!MatchTypes(e.expType, type, null, null, null, false, false, false))
10489                            if(!MatchTypeExpression(e, type, null, false))
10490                            {
10491                               FreeType(e.expType);
10492                               e.expType = null;
10493                               FreeType(type);
10494                               type = null;
10495                               break;
10496                            }
10497                         }
10498                      }
10499                   }
10500                   if(e.expType)
10501                   {
10502                      FreeType(e.expType);
10503                      e.expType = null;
10504                   }
10505                }
10506             }
10507             if(type)
10508             {
10509                typeStringBuf[0] = '\0';
10510                PrintTypeNoConst(type, typeStringBuf, false, true);
10511                typeString = typeStringBuf;
10512                FreeType(type);
10513                type = null;
10514             }
10515          }
10516          if(typeString)
10517          {
10518             /*
10519             (Container)& (struct BuiltInContainer)
10520             {
10521                ._vTbl = class(BuiltInContainer)._vTbl,
10522                ._class = class(BuiltInContainer),
10523                .refCount = 0,
10524                .data = (int[]){ 1, 7, 3, 4, 5 },
10525                .count = 5,
10526                .type = class(int),
10527             }
10528             */
10529             char templateString[1024];
10530             OldList * initializers = MkList();
10531             OldList * structInitializers = MkList();
10532             OldList * specs = MkList();
10533             Expression expExt;
10534             Declarator decl = SpecDeclFromString(typeString, specs, null);
10535             sprintf(templateString, "Container<%s>", typeString);
10536
10537             if(exp.list)
10538             {
10539                Expression e;
10540                type = ProcessTypeString(typeString, false);
10541                while(e = exp.list->first)
10542                {
10543                   exp.list->Remove(e);
10544                   e.destType = type;
10545                   type.refCount++;
10546                   ProcessExpressionType(e);
10547                   ListAdd(initializers, MkInitializerAssignment(e));
10548                }
10549                FreeType(type);
10550                delete exp.list;
10551             }
10552
10553             DeclareStruct("ecere::com::BuiltInContainer", false);
10554
10555             ListAdd(structInitializers, /*MkIdentifier("_vTbl")*/    MkInitializerAssignment(MkExpMember(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null), MkIdentifier("_vTbl"))));
10556                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10557             ListAdd(structInitializers, /*MkIdentifier("_class")*/   MkInitializerAssignment(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null)));
10558                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10559             ListAdd(structInitializers, /*MkIdentifier("_refCount")*/MkInitializerAssignment(MkExpConstant("0")));
10560                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10561             ListAdd(structInitializers, /*MkIdentifier("data")*/     MkInitializerAssignment(MkExpExtensionInitializer(
10562                MkTypeName(specs, MkDeclaratorArray(decl, null)),
10563                MkInitializerList(initializers))));
10564                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10565             ListAdd(structInitializers, /*MkIdentifier("count")*/    MkInitializerAssignment({ type = constantExp, constant = PrintString(initializers->count) }));
10566                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10567             ListAdd(structInitializers, /*MkIdentifier("type")*/     MkInitializerAssignment(MkExpClass(CopyList(specs, CopySpecifier), CopyDeclarator(decl))));
10568                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10569             exp.expType = ProcessTypeString(templateString, false);
10570             exp.type = bracketsExp;
10571             exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(templateString)), null),
10572                MkExpOp(null, '&',
10573                expExt = MkExpExtensionInitializer(MkTypeName(MkListOne(MkSpecifierName("BuiltInContainer")), null),
10574                   MkInitializerList(structInitializers)))));
10575             ProcessExpressionType(expExt);
10576          }
10577          else
10578          {
10579             exp.expType = ProcessTypeString("Container", false);
10580             Compiler_Error($"Couldn't determine type of array elements\n");
10581          }
10582          break;
10583       }
10584    }
10585
10586    if(exp.expType && exp.expType.kind == thisClassType && thisClass && (!exp.destType || exp.destType.kind != thisClassType))
10587    {
10588       FreeType(exp.expType);
10589       exp.expType = ReplaceThisClassType(thisClass);
10590    }
10591
10592    // Resolve structures here
10593    if(exp.expType && (exp.expType.kind == structType || exp.expType.kind == unionType || exp.expType.kind == enumType) && !exp.expType.members.first && exp.expType.enumName)
10594    {
10595       Symbol symbol = FindSymbol(exp.expType.enumName, curContext, globalContext, true, false);
10596       // TODO: Fix members reference...
10597       if(symbol)
10598       {
10599          if(exp.expType.kind != enumType)
10600          {
10601             Type member;
10602             String enumName = CopyString(exp.expType.enumName);
10603
10604             // Fixed a memory leak on self-referencing C structs typedefs
10605             // by instantiating a new type rather than simply copying members
10606             // into exp.expType
10607             FreeType(exp.expType);
10608             exp.expType = Type { };
10609             exp.expType.kind = symbol.type.kind;
10610             exp.expType.refCount++;
10611             exp.expType.enumName = enumName;
10612
10613             exp.expType.members = symbol.type.members;
10614             for(member = symbol.type.members.first; member; member = member.next)
10615                member.refCount++;
10616          }
10617          else
10618          {
10619             NamedLink member;
10620             for(member = symbol.type.members.first; member; member = member.next)
10621             {
10622                NamedLink value { name = CopyString(member.name) };
10623                exp.expType.members.Add(value);
10624             }
10625          }
10626       }
10627    }
10628
10629    yylloc = exp.loc;
10630    if(exp.destType && (exp.destType.kind == voidType || exp.destType.kind == dummyType) );
10631    else if(exp.destType && !exp.destType.keepCast)
10632    {
10633       if(!CheckExpressionType(exp, exp.destType, false))
10634       {
10635          if(!exp.destType.count || unresolved)
10636          {
10637             if(!exp.expType)
10638             {
10639                yylloc = exp.loc;
10640                if(exp.destType.kind != ellipsisType)
10641                {
10642                   char type2[1024];
10643                   type2[0] = '\0';
10644                   if(inCompiler)
10645                   {
10646                      char expString[10240];
10647                      expString[0] = '\0';
10648
10649                      PrintType(exp.destType, type2, false, true);
10650
10651                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10652                      if(unresolved)
10653                         Compiler_Error($"unresolved identifier %s; expected %s\n", expString, type2);
10654                      else if(exp.type != dummyExp)
10655                         Compiler_Error($"couldn't determine type of %s; expected %s\n", expString, type2);
10656                   }
10657                }
10658                else
10659                {
10660                   char expString[10240] ;
10661                   expString[0] = '\0';
10662                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10663
10664                   if(unresolved)
10665                      Compiler_Error($"unresolved identifier %s\n", expString);
10666                   else if(exp.type != dummyExp)
10667                      Compiler_Error($"couldn't determine type of %s\n", expString);
10668                }
10669             }
10670             else
10671             {
10672                char type1[1024];
10673                char type2[1024];
10674                type1[0] = '\0';
10675                type2[0] = '\0';
10676                if(inCompiler)
10677                {
10678                   PrintType(exp.expType, type1, false, true);
10679                   PrintType(exp.destType, type2, false, true);
10680                }
10681
10682                //CheckExpressionType(exp, exp.destType, false);
10683
10684                if(exp.destType.truth && exp.destType._class && exp.destType._class.registered && !strcmp(exp.destType._class.registered.name, "bool") &&
10685                   exp.expType.kind != voidType && exp.expType.kind != structType && exp.expType.kind != unionType &&
10686                   (exp.expType.kind != classType || exp.expType.classObjectType || (exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type != structClass)));
10687                else
10688                {
10689                   char expString[10240];
10690                   expString[0] = '\0';
10691                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10692
10693 #ifdef _DEBUG
10694                   CheckExpressionType(exp, exp.destType, false);
10695 #endif
10696                   // Flex & Bison generate code that triggers this, so we ignore it for a quiet sdk build:
10697                   if(!sourceFile || (strcmp(sourceFile, "src\\lexer.ec") && strcmp(sourceFile, "src/lexer.ec") && strcmp(sourceFile, "src\\grammar.ec") && strcmp(sourceFile, "src/grammar.ec")))
10698                      Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
10699
10700                   // TO CHECK: FORCING HERE TO HELP DEBUGGER
10701                   FreeType(exp.expType);
10702                   exp.destType.refCount++;
10703                   exp.expType = exp.destType;
10704                }
10705             }
10706          }
10707       }
10708       else if(exp.destType && exp.destType.kind == ellipsisType && exp.expType && exp.expType.passAsTemplate)
10709       {
10710          Expression newExp { };
10711          char typeString[1024];
10712          OldList * specs = MkList();
10713          Declarator decl;
10714
10715          typeString[0] = '\0';
10716
10717          *newExp = *exp;
10718
10719          if(exp.expType)  exp.expType.refCount++;
10720          if(exp.expType)  exp.expType.refCount++;
10721          exp.type = castExp;
10722          newExp.destType = exp.expType;
10723
10724          PrintType(exp.expType, typeString, false, false);
10725          decl = SpecDeclFromString(typeString, specs, null);
10726
10727          exp.cast.typeName = MkTypeName(specs, decl);
10728          exp.cast.exp = newExp;
10729       }
10730    }
10731    else if(unresolved)
10732    {
10733       if(exp.identifier._class && exp.identifier._class.name)
10734          Compiler_Error($"unresolved identifier %s::%s\n", exp.identifier._class.name, exp.identifier.string);
10735       else if(exp.identifier.string && exp.identifier.string[0])
10736          Compiler_Error($"unresolved identifier %s\n", exp.identifier.string);
10737    }
10738    else if(!exp.expType && exp.type != dummyExp)
10739    {
10740       char expString[10240];
10741       expString[0] = '\0';
10742       if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10743       Compiler_Error($"couldn't determine type of %s\n", expString);
10744    }
10745
10746    // Let's try to support any_object & typed_object here:
10747    if(inCompiler)
10748       ApplyAnyObjectLogic(exp);
10749
10750    // Mark nohead classes as by reference, unless we're casting them to an integral type
10751    if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
10752       exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
10753          (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
10754           exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
10755    {
10756       exp.byReference = true;
10757    }
10758    yylloc = oldyylloc;
10759 }
10760
10761 static void FindNextDataMember(Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
10762 {
10763    // THIS CODE WILL FIND NEXT MEMBER...
10764    if(*curMember)
10765    {
10766       *curMember = (*curMember).next;
10767
10768       if(subMemberStackPos && *subMemberStackPos > 0 && subMemberStack[*subMemberStackPos-1].type == unionMember)
10769       {
10770          *curMember = subMemberStack[--(*subMemberStackPos)];
10771          *curMember = (*curMember).next;
10772       }
10773
10774       // SKIP ALL PROPERTIES HERE...
10775       while((*curMember) && (*curMember).isProperty)
10776          *curMember = (*curMember).next;
10777
10778       if(subMemberStackPos)
10779       {
10780          while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
10781          {
10782             subMemberStack[(*subMemberStackPos)++] = *curMember;
10783
10784             *curMember = (*curMember).members.first;
10785             while(*curMember && (*curMember).isProperty)
10786                *curMember = (*curMember).next;
10787          }
10788       }
10789    }
10790    while(!*curMember)
10791    {
10792       if(!*curMember)
10793       {
10794          if(subMemberStackPos && *subMemberStackPos)
10795          {
10796             *curMember = subMemberStack[--(*subMemberStackPos)];
10797             *curMember = (*curMember).next;
10798          }
10799          else
10800          {
10801             Class lastCurClass = *curClass;
10802
10803             if(*curClass == _class) break;     // REACHED THE END
10804
10805             for(*curClass = _class; (*curClass).base != lastCurClass && (*curClass).base.type != systemClass; *curClass = (*curClass).base);
10806             *curMember = (*curClass).membersAndProperties.first;
10807          }
10808
10809          while((*curMember) && (*curMember).isProperty)
10810             *curMember = (*curMember).next;
10811          if(subMemberStackPos)
10812          {
10813             while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
10814             {
10815                subMemberStack[(*subMemberStackPos)++] = *curMember;
10816
10817                *curMember = (*curMember).members.first;
10818                while(*curMember && (*curMember).isProperty)
10819                   *curMember = (*curMember).next;
10820             }
10821          }
10822       }
10823    }
10824 }
10825
10826
10827 static void ProcessInitializer(Initializer init, Type type)
10828 {
10829    switch(init.type)
10830    {
10831       case expInitializer:
10832          if(!init.exp || init.exp.type != instanceExp || !init.exp.instance || init.exp.instance._class || !type || type.kind == classType)
10833          {
10834             // TESTING THIS FOR SHUTTING = 0 WARNING
10835             if(init.exp && !init.exp.destType)
10836             {
10837                FreeType(init.exp.destType);
10838                init.exp.destType = type;
10839                if(type) type.refCount++;
10840             }
10841             if(init.exp)
10842             {
10843                ProcessExpressionType(init.exp);
10844                init.isConstant = init.exp.isConstant;
10845             }
10846             break;
10847          }
10848          else
10849          {
10850             Expression exp = init.exp;
10851             Instantiation inst = exp.instance;
10852             MembersInit members;
10853
10854             init.type = listInitializer;
10855             init.list = MkList();
10856
10857             if(inst.members)
10858             {
10859                for(members = inst.members->first; members; members = members.next)
10860                {
10861                   if(members.type == dataMembersInit)
10862                   {
10863                      MemberInit member;
10864                      for(member = members.dataMembers->first; member; member = member.next)
10865                      {
10866                         ListAdd(init.list, member.initializer);
10867                         member.initializer = null;
10868                      }
10869                   }
10870                   // Discard all MembersInitMethod
10871                }
10872             }
10873             FreeExpression(exp);
10874          }
10875       case listInitializer:
10876       {
10877          Initializer i;
10878          Type initializerType = null;
10879          Class curClass = null;
10880          DataMember curMember = null;
10881          DataMember subMemberStack[256];
10882          int subMemberStackPos = 0;
10883
10884          if(type && type.kind == arrayType)
10885             initializerType = Dereference(type);
10886          else if(type && (type.kind == structType || type.kind == unionType))
10887             initializerType = type.members.first;
10888
10889          for(i = init.list->first; i; i = i.next)
10890          {
10891             if(type && type.kind == classType && type._class && type._class.registered)
10892             {
10893                // 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)
10894                FindNextDataMember(type._class.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
10895                // TODO: Generate error on initializing a private data member this way from another module...
10896                if(curMember)
10897                {
10898                   if(!curMember.dataType)
10899                      curMember.dataType = ProcessTypeString(curMember.dataTypeString, false);
10900                   initializerType = curMember.dataType;
10901                }
10902             }
10903             ProcessInitializer(i, initializerType);
10904             if(initializerType && type && (type.kind == structType || type.kind == unionType))
10905                initializerType = initializerType.next;
10906             if(!i.isConstant)
10907                init.isConstant = false;
10908          }
10909
10910          if(type && type.kind == arrayType)
10911             FreeType(initializerType);
10912
10913          if(type && type.kind != arrayType && type.kind != structType && type.kind != unionType && (type.kind != classType || !type._class.registered || type._class.registered.type != structClass))
10914          {
10915             Compiler_Error($"Assigning list initializer to non list\n");
10916          }
10917          break;
10918       }
10919    }
10920 }
10921
10922 static void ProcessSpecifier(Specifier spec, bool declareStruct)
10923 {
10924    switch(spec.type)
10925    {
10926       case baseSpecifier:
10927       {
10928          if(spec.specifier == THISCLASS)
10929          {
10930             if(thisClass)
10931             {
10932                spec.type = nameSpecifier;
10933                spec.name = ReplaceThisClass(thisClass);
10934                spec.symbol = FindClass(spec.name);
10935                ProcessSpecifier(spec, declareStruct);
10936             }
10937          }
10938          break;
10939       }
10940       case nameSpecifier:
10941       {
10942          Symbol symbol = FindType(curContext, spec.name);
10943          if(symbol)
10944             DeclareType(symbol.type, true, true);
10945          else if((symbol = spec.symbol /*FindClass(spec.name)*/) && symbol.registered && symbol.registered.type == structClass && declareStruct)
10946             DeclareStruct(spec.name, false);
10947          break;
10948       }
10949       case enumSpecifier:
10950       {
10951          Enumerator e;
10952          if(spec.list)
10953          {
10954             for(e = spec.list->first; e; e = e.next)
10955             {
10956                if(e.exp)
10957                   ProcessExpressionType(e.exp);
10958             }
10959          }
10960          break;
10961       }
10962       case structSpecifier:
10963       case unionSpecifier:
10964       {
10965          if(spec.definitions)
10966          {
10967             ClassDef def;
10968             Symbol symbol = spec.id ? FindClass(spec.id.string) : null;
10969             //if(symbol)
10970                ProcessClass(spec.definitions, symbol);
10971             /*else
10972             {
10973                for(def = spec.definitions->first; def; def = def.next)
10974                {
10975                   //if(def.type == declarationClassDef && def.decl && def.decl.type == DeclarationStruct)
10976                      ProcessDeclaration(def.decl);
10977                }
10978             }*/
10979          }
10980          break;
10981       }
10982       /*
10983       case classSpecifier:
10984       {
10985          Symbol classSym = FindClass(spec.name);
10986          if(classSym && classSym.registered && classSym.registered.type == structClass)
10987             DeclareStruct(spec.name, false);
10988          break;
10989       }
10990       */
10991    }
10992 }
10993
10994
10995 static void ProcessDeclarator(Declarator decl)
10996 {
10997    switch(decl.type)
10998    {
10999       case identifierDeclarator:
11000          if(decl.identifier.classSym /* TODO: Name Space Fix ups  || decl.identifier.nameSpace*/)
11001          {
11002             FreeSpecifier(decl.identifier._class);
11003             decl.identifier._class = null;
11004          }
11005          break;
11006       case arrayDeclarator:
11007          if(decl.array.exp)
11008             ProcessExpressionType(decl.array.exp);
11009       case structDeclarator:
11010       case bracketsDeclarator:
11011       case functionDeclarator:
11012       case pointerDeclarator:
11013       case extendedDeclarator:
11014       case extendedDeclaratorEnd:
11015          if(decl.declarator)
11016             ProcessDeclarator(decl.declarator);
11017          if(decl.type == functionDeclarator)
11018          {
11019             Identifier id = GetDeclId(decl);
11020             if(id && id._class)
11021             {
11022                TypeName param
11023                {
11024                   qualifiers = MkListOne(id._class);
11025                   declarator = null;
11026                };
11027                if(!decl.function.parameters)
11028                   decl.function.parameters = MkList();
11029                decl.function.parameters->Insert(null, param);
11030                id._class = null;
11031             }
11032             if(decl.function.parameters)
11033             {
11034                TypeName param;
11035
11036                for(param = decl.function.parameters->first; param; param = param.next)
11037                {
11038                   if(param.qualifiers && param.qualifiers->first)
11039                   {
11040                      Specifier spec = param.qualifiers->first;
11041                      if(spec && spec.specifier == TYPED_OBJECT)
11042                      {
11043                         Declarator d = param.declarator;
11044                         TypeName newParam
11045                         {
11046                            qualifiers = MkListOne(MkSpecifier(VOID));
11047                            declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11048                         };
11049
11050                         FreeList(param.qualifiers, FreeSpecifier);
11051
11052                         param.qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
11053                         param.declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
11054
11055                         decl.function.parameters->Insert(param, newParam);
11056                         param = newParam;
11057                      }
11058                      else if(spec && spec.specifier == ANY_OBJECT)
11059                      {
11060                         Declarator d = param.declarator;
11061
11062                         FreeList(param.qualifiers, FreeSpecifier);
11063
11064                         param.qualifiers = MkListOne(MkSpecifier(VOID));
11065                         param.declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11066                      }
11067                      else if(spec.specifier == THISCLASS)
11068                      {
11069                         if(thisClass)
11070                         {
11071                            spec.type = nameSpecifier;
11072                            spec.name = ReplaceThisClass(thisClass);
11073                            spec.symbol = FindClass(spec.name);
11074                            ProcessSpecifier(spec, false);
11075                         }
11076                      }
11077                   }
11078
11079                   if(param.declarator)
11080                      ProcessDeclarator(param.declarator);
11081                }
11082             }
11083          }
11084          break;
11085    }
11086 }
11087
11088 static void ProcessDeclaration(Declaration decl)
11089 {
11090    yylloc = decl.loc;
11091    switch(decl.type)
11092    {
11093       case initDeclaration:
11094       {
11095          bool declareStruct = false;
11096          /*
11097          lineNum = decl.pos.line;
11098          column = decl.pos.col;
11099          */
11100
11101          if(decl.declarators)
11102          {
11103             InitDeclarator d;
11104
11105             for(d = decl.declarators->first; d; d = d.next)
11106             {
11107                Type type, subType;
11108                ProcessDeclarator(d.declarator);
11109
11110                type = ProcessType(decl.specifiers, d.declarator);
11111
11112                if(d.initializer)
11113                {
11114                   ProcessInitializer(d.initializer, type);
11115
11116                   // Change "ColorRGB a = ColorRGB { 1,2,3 } => ColorRGB a { 1,2,3 }
11117
11118                   if(decl.declarators->count == 1 && d.initializer.type == expInitializer &&
11119                      d.initializer.exp.type == instanceExp)
11120                   {
11121                      if(type.kind == classType && type._class ==
11122                         d.initializer.exp.expType._class)
11123                      {
11124                         Instantiation inst = d.initializer.exp.instance;
11125                         inst.exp = MkExpIdentifier(CopyIdentifier(GetDeclId(d.declarator)));
11126
11127                         d.initializer.exp.instance = null;
11128                         if(decl.specifiers)
11129                            FreeList(decl.specifiers, FreeSpecifier);
11130                         FreeList(decl.declarators, FreeInitDeclarator);
11131
11132                         d = null;
11133
11134                         decl.type = instDeclaration;
11135                         decl.inst = inst;
11136                      }
11137                   }
11138                }
11139                for(subType = type; subType;)
11140                {
11141                   if(subType.kind == classType)
11142                   {
11143                      declareStruct = true;
11144                      break;
11145                   }
11146                   else if(subType.kind == pointerType)
11147                      break;
11148                   else if(subType.kind == arrayType)
11149                      subType = subType.arrayType;
11150                   else
11151                      break;
11152                }
11153
11154                FreeType(type);
11155                if(!d) break;
11156             }
11157          }
11158
11159          if(decl.specifiers)
11160          {
11161             Specifier s;
11162             for(s = decl.specifiers->first; s; s = s.next)
11163             {
11164                ProcessSpecifier(s, declareStruct);
11165             }
11166          }
11167          break;
11168       }
11169       case instDeclaration:
11170       {
11171          ProcessInstantiationType(decl.inst);
11172          break;
11173       }
11174       case structDeclaration:
11175       {
11176          Specifier spec;
11177          Declarator d;
11178          bool declareStruct = false;
11179
11180          if(decl.declarators)
11181          {
11182             for(d = decl.declarators->first; d; d = d.next)
11183             {
11184                Type type = ProcessType(decl.specifiers, d.declarator);
11185                Type subType;
11186                ProcessDeclarator(d);
11187                for(subType = type; subType;)
11188                {
11189                   if(subType.kind == classType)
11190                   {
11191                      declareStruct = true;
11192                      break;
11193                   }
11194                   else if(subType.kind == pointerType)
11195                      break;
11196                   else if(subType.kind == arrayType)
11197                      subType = subType.arrayType;
11198                   else
11199                      break;
11200                }
11201                FreeType(type);
11202             }
11203          }
11204          if(decl.specifiers)
11205          {
11206             for(spec = decl.specifiers->first; spec; spec = spec.next)
11207                ProcessSpecifier(spec, declareStruct);
11208          }
11209          break;
11210       }
11211    }
11212 }
11213
11214 static FunctionDefinition curFunction;
11215
11216 static void CreateFireWatcher(Property prop, Expression object, Statement stmt)
11217 {
11218    char propName[1024], propNameM[1024];
11219    char getName[1024], setName[1024];
11220    OldList * args;
11221
11222    DeclareProperty(prop, setName, getName);
11223
11224    // eInstance_FireWatchers(object, prop);
11225    strcpy(propName, "__ecereProp_");
11226    FullClassNameCat(propName, prop._class.fullName, false);
11227    strcat(propName, "_");
11228    // strcat(propName, prop.name);
11229    FullClassNameCat(propName, prop.name, true);
11230    MangleClassName(propName);
11231
11232    strcpy(propNameM, "__ecerePropM_");
11233    FullClassNameCat(propNameM, prop._class.fullName, false);
11234    strcat(propNameM, "_");
11235    // strcat(propNameM, prop.name);
11236    FullClassNameCat(propNameM, prop.name, true);
11237    MangleClassName(propNameM);
11238
11239    if(prop.isWatchable)
11240    {
11241       args = MkList();
11242       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11243       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11244       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11245
11246       args = MkList();
11247       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11248       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11249       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11250    }
11251
11252
11253    {
11254       args = MkList();
11255       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11256       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11257       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11258
11259       args = MkList();
11260       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11261       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11262       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11263    }
11264
11265    if(curFunction.propSet && !strcmp(curFunction.propSet.string, prop.name) &&
11266       (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
11267       curFunction.propSet.fireWatchersDone = true;
11268 }
11269
11270 static void ProcessStatement(Statement stmt)
11271 {
11272    yylloc = stmt.loc;
11273    /*
11274    lineNum = stmt.pos.line;
11275    column = stmt.pos.col;
11276    */
11277    switch(stmt.type)
11278    {
11279       case labeledStmt:
11280          ProcessStatement(stmt.labeled.stmt);
11281          break;
11282       case caseStmt:
11283          // This expression should be constant...
11284          if(stmt.caseStmt.exp)
11285          {
11286             FreeType(stmt.caseStmt.exp.destType);
11287             stmt.caseStmt.exp.destType = curSwitchType;
11288             if(curSwitchType) curSwitchType.refCount++;
11289             ProcessExpressionType(stmt.caseStmt.exp);
11290             ComputeExpression(stmt.caseStmt.exp);
11291          }
11292          if(stmt.caseStmt.stmt)
11293             ProcessStatement(stmt.caseStmt.stmt);
11294          break;
11295       case compoundStmt:
11296       {
11297          if(stmt.compound.context)
11298          {
11299             Declaration decl;
11300             Statement s;
11301
11302             Statement prevCompound = curCompound;
11303             Context prevContext = curContext;
11304
11305             if(!stmt.compound.isSwitch)
11306                curCompound = stmt;
11307             curContext = stmt.compound.context;
11308
11309             if(stmt.compound.declarations)
11310             {
11311                for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
11312                   ProcessDeclaration(decl);
11313             }
11314             if(stmt.compound.statements)
11315             {
11316                for(s = stmt.compound.statements->first; s; s = s.next)
11317                   ProcessStatement(s);
11318             }
11319
11320             curContext = prevContext;
11321             curCompound = prevCompound;
11322          }
11323          break;
11324       }
11325       case expressionStmt:
11326       {
11327          Expression exp;
11328          if(stmt.expressions)
11329          {
11330             for(exp = stmt.expressions->first; exp; exp = exp.next)
11331                ProcessExpressionType(exp);
11332          }
11333          break;
11334       }
11335       case ifStmt:
11336       {
11337          Expression exp;
11338
11339          FreeType(((Expression)stmt.ifStmt.exp->last).destType);
11340          ((Expression)stmt.ifStmt.exp->last).destType = MkClassType("bool");
11341          ((Expression)stmt.ifStmt.exp->last).destType.truth = true;
11342          for(exp = stmt.ifStmt.exp->first; exp; exp = exp.next)
11343          {
11344             ProcessExpressionType(exp);
11345          }
11346          if(stmt.ifStmt.stmt)
11347             ProcessStatement(stmt.ifStmt.stmt);
11348          if(stmt.ifStmt.elseStmt)
11349             ProcessStatement(stmt.ifStmt.elseStmt);
11350          break;
11351       }
11352       case switchStmt:
11353       {
11354          Type oldSwitchType = curSwitchType;
11355          if(stmt.switchStmt.exp)
11356          {
11357             Expression exp;
11358             for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
11359             {
11360                if(!exp.next)
11361                {
11362                   /*
11363                   Type destType
11364                   {
11365                      kind = intType;
11366                      refCount = 1;
11367                   };
11368                   e.exp.destType = destType;
11369                   */
11370
11371                   ProcessExpressionType(exp);
11372                }
11373                if(!exp.next)
11374                   curSwitchType = exp.expType;
11375             }
11376          }
11377          ProcessStatement(stmt.switchStmt.stmt);
11378          curSwitchType = oldSwitchType;
11379          break;
11380       }
11381       case whileStmt:
11382       {
11383          if(stmt.whileStmt.exp)
11384          {
11385             Expression exp;
11386
11387             FreeType(((Expression)stmt.whileStmt.exp->last).destType);
11388             ((Expression)stmt.whileStmt.exp->last).destType = MkClassType("bool");
11389             ((Expression)stmt.whileStmt.exp->last).destType.truth = true;
11390             for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
11391             {
11392                ProcessExpressionType(exp);
11393             }
11394          }
11395          if(stmt.whileStmt.stmt)
11396             ProcessStatement(stmt.whileStmt.stmt);
11397          break;
11398       }
11399       case doWhileStmt:
11400       {
11401          if(stmt.doWhile.exp)
11402          {
11403             Expression exp;
11404
11405             if(stmt.doWhile.exp->last)
11406             {
11407                FreeType(((Expression)stmt.doWhile.exp->last).destType);
11408                ((Expression)stmt.doWhile.exp->last).destType = MkClassType("bool");
11409                ((Expression)stmt.doWhile.exp->last).destType.truth = true;
11410             }
11411             for(exp = stmt.doWhile.exp->first; exp; exp = exp.next)
11412             {
11413                ProcessExpressionType(exp);
11414             }
11415          }
11416          if(stmt.doWhile.stmt)
11417             ProcessStatement(stmt.doWhile.stmt);
11418          break;
11419       }
11420       case forStmt:
11421       {
11422          Expression exp;
11423          if(stmt.forStmt.init)
11424             ProcessStatement(stmt.forStmt.init);
11425
11426          if(stmt.forStmt.check && stmt.forStmt.check.expressions)
11427          {
11428             FreeType(((Expression)stmt.forStmt.check.expressions->last).destType);
11429             ((Expression)stmt.forStmt.check.expressions->last).destType = MkClassType("bool");
11430             ((Expression)stmt.forStmt.check.expressions->last).destType.truth = true;
11431          }
11432
11433          if(stmt.forStmt.check)
11434             ProcessStatement(stmt.forStmt.check);
11435          if(stmt.forStmt.increment)
11436          {
11437             for(exp = stmt.forStmt.increment->first; exp; exp = exp.next)
11438                ProcessExpressionType(exp);
11439          }
11440
11441          if(stmt.forStmt.stmt)
11442             ProcessStatement(stmt.forStmt.stmt);
11443          break;
11444       }
11445       case forEachStmt:
11446       {
11447          Identifier id = stmt.forEachStmt.id;
11448          OldList * exp = stmt.forEachStmt.exp;
11449          OldList * filter = stmt.forEachStmt.filter;
11450          Statement block = stmt.forEachStmt.stmt;
11451          char iteratorType[1024];
11452          Type source;
11453          Expression e;
11454          bool isBuiltin = exp && exp->last &&
11455             (((Expression)exp->last).type == ExpressionType::arrayExp ||
11456               (((Expression)exp->last).type == castExp && ((Expression)exp->last).cast.exp.type == ExpressionType::arrayExp));
11457          Expression arrayExp;
11458          char * typeString = null;
11459          int builtinCount = 0;
11460
11461          for(e = exp ? exp->first : null; e; e = e.next)
11462          {
11463             if(!e.next)
11464             {
11465                FreeType(e.destType);
11466                e.destType = ProcessTypeString("Container", false);
11467             }
11468             if(!isBuiltin || e.next)
11469                ProcessExpressionType(e);
11470          }
11471
11472          source = (exp && exp->last) ? ((Expression)exp->last).expType : null;
11473          if(isBuiltin || (source && source.kind == classType && source._class && source._class.registered && source._class.registered != containerClass &&
11474             eClass_IsDerived(source._class.registered, containerClass)))
11475          {
11476             Class _class = source ? source._class.registered : null;
11477             Symbol symbol;
11478             Expression expIt = null;
11479             bool isMap = false, isArray = false, isLinkList = false, isList = false, isCustomAVLTree = false, isAVLTree = false;
11480             Class arrayClass = eSystem_FindClass(privateModule, "Array");
11481             Class linkListClass = eSystem_FindClass(privateModule, "LinkList");
11482             Class customAVLTreeClass = eSystem_FindClass(privateModule, "CustomAVLTree");
11483             stmt.type = compoundStmt;
11484
11485             stmt.compound.context = Context { };
11486             stmt.compound.context.parent = curContext;
11487             curContext = stmt.compound.context;
11488
11489             if(source && eClass_IsDerived(source._class.registered, customAVLTreeClass))
11490             {
11491                Class mapClass = eSystem_FindClass(privateModule, "Map");
11492                Class avlTreeClass = eSystem_FindClass(privateModule, "AVLTree");
11493                isCustomAVLTree = true;
11494                if(eClass_IsDerived(source._class.registered, avlTreeClass))
11495                   isAVLTree = true;
11496                else if(eClass_IsDerived(source._class.registered, mapClass))
11497                   isMap = true;
11498             }
11499             else if(source && eClass_IsDerived(source._class.registered, arrayClass)) isArray = true;
11500             else if(source && eClass_IsDerived(source._class.registered, linkListClass))
11501             {
11502                Class listClass = eSystem_FindClass(privateModule, "List");
11503                isLinkList = true;
11504                isList = eClass_IsDerived(source._class.registered, listClass);
11505             }
11506
11507             if(isArray)
11508             {
11509                Declarator decl;
11510                OldList * specs = MkList();
11511                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
11512                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
11513                stmt.compound.declarations = MkListOne(
11514                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11515                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11516                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalArray")),
11517                      MkInitializerAssignment(MkExpBrackets(exp))))));
11518             }
11519             else if(isBuiltin)
11520             {
11521                Type type = null;
11522                char typeStringBuf[1024];
11523
11524                // TODO: Merge this code?
11525                arrayExp = (((Expression)exp->last).type == ExpressionType::arrayExp) ? (Expression)exp->last : ((Expression)exp->last).cast.exp;
11526                if(((Expression)exp->last).type == castExp)
11527                {
11528                   TypeName typeName = ((Expression)exp->last).cast.typeName;
11529                   if(typeName)
11530                      arrayExp.destType = ProcessType(typeName.qualifiers, typeName.declarator);
11531                }
11532
11533                if(arrayExp.destType && arrayExp.destType.kind == classType && arrayExp.destType._class && arrayExp.destType._class.registered &&
11534                   arrayExp.destType._class.registered != containerClass && eClass_IsDerived(arrayExp.destType._class.registered, containerClass) &&
11535                   arrayExp.destType._class.registered.templateArgs)
11536                {
11537                   Class templateClass = arrayExp.destType._class.registered;
11538                   typeString = templateClass.templateArgs[2].dataTypeString;
11539                }
11540                else if(arrayExp.list)
11541                {
11542                   // Guess type from expressions in the array
11543                   Expression e;
11544                   for(e = arrayExp.list->first; e; e = e.next)
11545                   {
11546                      ProcessExpressionType(e);
11547                      if(e.expType)
11548                      {
11549                         if(!type) { type = e.expType; type.refCount++; }
11550                         else
11551                         {
11552                            // if(!MatchType(e.expType, type, null, null, null, false, false, false))
11553                            if(!MatchTypeExpression(e, type, null, false))
11554                            {
11555                               FreeType(type);
11556                               type = e.expType;
11557                               e.expType = null;
11558
11559                               e = arrayExp.list->first;
11560                               ProcessExpressionType(e);
11561                               if(e.expType)
11562                               {
11563                                  //if(!MatchTypes(e.expType, type, null, null, null, false, false, false, false))
11564                                  if(!MatchTypeExpression(e, type, null, false))
11565                                  {
11566                                     FreeType(e.expType);
11567                                     e.expType = null;
11568                                     FreeType(type);
11569                                     type = null;
11570                                     break;
11571                                  }
11572                               }
11573                            }
11574                         }
11575                         if(e.expType)
11576                         {
11577                            FreeType(e.expType);
11578                            e.expType = null;
11579                         }
11580                      }
11581                   }
11582                   if(type)
11583                   {
11584                      typeStringBuf[0] = '\0';
11585                      PrintType(type, typeStringBuf, false, true);
11586                      typeString = typeStringBuf;
11587                      FreeType(type);
11588                   }
11589                }
11590                if(typeString)
11591                {
11592                   OldList * initializers = MkList();
11593                   Declarator decl;
11594                   OldList * specs = MkList();
11595                   if(arrayExp.list)
11596                   {
11597                      Expression e;
11598
11599                      builtinCount = arrayExp.list->count;
11600                      type = ProcessTypeString(typeString, false);
11601                      while(e = arrayExp.list->first)
11602                      {
11603                         arrayExp.list->Remove(e);
11604                         e.destType = type;
11605                         type.refCount++;
11606                         ProcessExpressionType(e);
11607                         ListAdd(initializers, MkInitializerAssignment(e));
11608                      }
11609                      FreeType(type);
11610                      delete arrayExp.list;
11611                   }
11612                   decl = SpecDeclFromString(typeString, specs, MkDeclaratorIdentifier(id));
11613                   stmt.compound.declarations = MkListOne(MkDeclaration(CopyList(specs, CopySpecifier),
11614                      MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), /*CopyDeclarator(*/decl/*)*/), null))));
11615
11616                   ListAdd(stmt.compound.declarations, MkDeclaration(specs, MkListOne(MkInitDeclarator(
11617                      PlugDeclarator(
11618                         /*CopyDeclarator(*/decl/*)*/, MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__internalArray")), null)
11619                         ), MkInitializerList(initializers)))));
11620                   FreeList(exp, FreeExpression);
11621                }
11622                else
11623                {
11624                   arrayExp.expType = ProcessTypeString("Container", false);
11625                   Compiler_Error($"Couldn't determine type of array elements\n");
11626                }
11627
11628                /*
11629                Declarator decl;
11630                OldList * specs = MkList();
11631
11632                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
11633                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
11634                stmt.compound.declarations = MkListOne(
11635                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11636                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName("BuiltInContainer")),
11637                   MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(MkIdentifier("__internalArray"))),
11638                      MkInitializerAssignment(MkExpBrackets(exp))))));
11639                */
11640             }
11641             else if(isLinkList && !isList)
11642             {
11643                Declarator decl;
11644                OldList * specs = MkList();
11645                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
11646                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11647                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11648                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalLinkList")),
11649                      MkInitializerAssignment(MkExpBrackets(exp))))));
11650             }
11651             /*else if(isCustomAVLTree)
11652             {
11653                Declarator decl;
11654                OldList * specs = MkList();
11655                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
11656                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11657                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11658                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalTree")),
11659                      MkInitializerAssignment(MkExpBrackets(exp))))));
11660             }*/
11661             else if(_class.templateArgs)
11662             {
11663                if(isMap)
11664                   sprintf(iteratorType, "MapIterator<%s, %s >", _class.templateArgs[5].dataTypeString, _class.templateArgs[6].dataTypeString);
11665                else
11666                   sprintf(iteratorType, "Iterator<%s, %s >", _class.templateArgs[2].dataTypeString, _class.templateArgs[1].dataTypeString);
11667
11668                stmt.compound.declarations = MkListOne(
11669                   MkDeclarationInst(MkInstantiationNamed(MkListOne(MkSpecifierName(iteratorType)),
11670                   MkExpIdentifier(id), MkListOne(MkMembersInitList(MkListOne(MkMemberInit(isMap ? MkListOne(MkIdentifier("map")) : null,
11671                   MkInitializerAssignment(MkExpBrackets(exp)))))))));
11672             }
11673             symbol = FindSymbol(id.string, curContext, curContext, false, false);
11674
11675             if(block)
11676             {
11677                // Reparent sub-contexts in this statement
11678                switch(block.type)
11679                {
11680                   case compoundStmt:
11681                      if(block.compound.context)
11682                         block.compound.context.parent = stmt.compound.context;
11683                      break;
11684                   case ifStmt:
11685                      if(block.ifStmt.stmt && block.ifStmt.stmt.type == compoundStmt && block.ifStmt.stmt.compound.context)
11686                         block.ifStmt.stmt.compound.context.parent = stmt.compound.context;
11687                      if(block.ifStmt.elseStmt && block.ifStmt.elseStmt.type == compoundStmt && block.ifStmt.elseStmt.compound.context)
11688                         block.ifStmt.elseStmt.compound.context.parent = stmt.compound.context;
11689                      break;
11690                   case switchStmt:
11691                      if(block.switchStmt.stmt && block.switchStmt.stmt.type == compoundStmt && block.switchStmt.stmt.compound.context)
11692                         block.switchStmt.stmt.compound.context.parent = stmt.compound.context;
11693                      break;
11694                   case whileStmt:
11695                      if(block.whileStmt.stmt && block.whileStmt.stmt.type == compoundStmt && block.whileStmt.stmt.compound.context)
11696                         block.whileStmt.stmt.compound.context.parent = stmt.compound.context;
11697                      break;
11698                   case doWhileStmt:
11699                      if(block.doWhile.stmt && block.doWhile.stmt.type == compoundStmt && block.doWhile.stmt.compound.context)
11700                         block.doWhile.stmt.compound.context.parent = stmt.compound.context;
11701                      break;
11702                   case forStmt:
11703                      if(block.forStmt.stmt && block.forStmt.stmt.type == compoundStmt && block.forStmt.stmt.compound.context)
11704                         block.forStmt.stmt.compound.context.parent = stmt.compound.context;
11705                      break;
11706                   case forEachStmt:
11707                      if(block.forEachStmt.stmt && block.forEachStmt.stmt.type == compoundStmt && block.forEachStmt.stmt.compound.context)
11708                         block.forEachStmt.stmt.compound.context.parent = stmt.compound.context;
11709                      break;
11710                   /* Only handle those with compound blocks for now... (Potential limitation on compound statements within expressions)
11711                   case labeledStmt:
11712                   case caseStmt
11713                   case expressionStmt:
11714                   case gotoStmt:
11715                   case continueStmt:
11716                   case breakStmt
11717                   case returnStmt:
11718                   case asmStmt:
11719                   case badDeclarationStmt:
11720                   case fireWatchersStmt:
11721                   case stopWatchingStmt:
11722                   case watchStmt:
11723                   */
11724                }
11725             }
11726             if(filter)
11727             {
11728                block = MkIfStmt(filter, block, null);
11729             }
11730             if(isArray)
11731             {
11732                stmt.compound.statements = MkListOne(MkForStmt(
11733                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array"))))),
11734                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
11735                      MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array")), '+', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
11736                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
11737                   block));
11738               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11739               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11740               ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11741             }
11742             else if(isBuiltin)
11743             {
11744                char count[128];
11745                //OldList * specs = MkList();
11746                // Declarator decl = SpecDeclFromString(typeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
11747
11748                sprintf(count, "%d", builtinCount);
11749
11750                stmt.compound.statements = MkListOne(MkForStmt(
11751                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpIdentifier(MkIdentifier("__internalArray"))))),
11752                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
11753                      MkExpOp(MkExpIdentifier(MkIdentifier("__internalArray")), '+', MkExpConstant(count))))),
11754                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
11755                   block));
11756
11757                /*
11758                Declarator decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
11759                stmt.compound.statements = MkListOne(MkForStmt(
11760                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))))),
11761                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
11762                      MkExpOp(MkExpCast(MkTypeName(specs, decl), MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))), '+', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
11763                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
11764                   block));
11765               */
11766               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11767               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11768               ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11769             }
11770             else if(isLinkList && !isList)
11771             {
11772                Class typeClass = eSystem_FindClass(_class.module, _class.templateArgs[3].dataTypeString);
11773                Class listItemClass = eSystem_FindClass(_class.module, "ListItem");
11774                if(typeClass && eClass_IsDerived(typeClass, listItemClass) && _class.templateArgs[5].dataTypeString &&
11775                   !strcmp(_class.templateArgs[5].dataTypeString, "LT::link"))
11776                {
11777                   stmt.compound.statements = MkListOne(MkForStmt(
11778                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
11779                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
11780                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
11781                      block));
11782                }
11783                else
11784                {
11785                   OldList * specs = MkList();
11786                   Declarator decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, null);
11787                   stmt.compound.statements = MkListOne(MkForStmt(
11788                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
11789                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
11790                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpCast(MkTypeName(specs, decl), MkExpCall(
11791                         MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("GetNext")),
11792                            MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName("IteratorPointer")), null), MkExpIdentifier(CopyIdentifier(id)))))))),
11793                      block));
11794                }
11795                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11796                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11797                ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11798             }
11799             /*else if(isCustomAVLTree)
11800             {
11801                stmt.compound.statements = MkListOne(MkForStmt(
11802                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpMember(MkExpIdentifier(
11803                      MkIdentifier("__internalTree")), MkIdentifier("root")), MkIdentifier("minimum"))))),
11804                   MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
11805                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
11806                   block));
11807
11808                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
11809                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
11810                ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
11811             }*/
11812             else
11813             {
11814                stmt.compound.statements = MkListOne(MkWhileStmt(MkListOne(MkExpCall(MkExpMember(expIt = MkExpIdentifier(CopyIdentifier(id)),
11815                   MkIdentifier("Next")), null)), block));
11816             }
11817             ProcessExpressionType(expIt);
11818             if(stmt.compound.declarations->first)
11819                ProcessDeclaration(stmt.compound.declarations->first);
11820
11821             if(symbol)
11822                symbol.isIterator = isMap ? 2 : ((isArray || isBuiltin) ? 3 : (isLinkList ? (isList ? 5 : 4) : (isCustomAVLTree ? 6 : 1)));
11823
11824             ProcessStatement(stmt);
11825             curContext = stmt.compound.context.parent;
11826             break;
11827          }
11828          else
11829          {
11830             Compiler_Error($"Expression is not a container\n");
11831          }
11832          break;
11833       }
11834       case gotoStmt:
11835          break;
11836       case continueStmt:
11837          break;
11838       case breakStmt:
11839          break;
11840       case returnStmt:
11841       {
11842          Expression exp;
11843          if(stmt.expressions)
11844          {
11845             for(exp = stmt.expressions->first; exp; exp = exp.next)
11846             {
11847                if(!exp.next)
11848                {
11849                   if(curFunction && !curFunction.type)
11850                      curFunction.type = ProcessType(
11851                         curFunction.specifiers, curFunction.declarator);
11852                   FreeType(exp.destType);
11853                   exp.destType = (curFunction && curFunction.type && curFunction.type.kind == functionType) ? curFunction.type.returnType : null;
11854                   if(exp.destType) exp.destType.refCount++;
11855                }
11856                ProcessExpressionType(exp);
11857             }
11858          }
11859          break;
11860       }
11861       case badDeclarationStmt:
11862       {
11863          ProcessDeclaration(stmt.decl);
11864          break;
11865       }
11866       case asmStmt:
11867       {
11868          AsmField field;
11869          if(stmt.asmStmt.inputFields)
11870          {
11871             for(field = stmt.asmStmt.inputFields->first; field; field = field.next)
11872                if(field.expression)
11873                   ProcessExpressionType(field.expression);
11874          }
11875          if(stmt.asmStmt.outputFields)
11876          {
11877             for(field = stmt.asmStmt.outputFields->first; field; field = field.next)
11878                if(field.expression)
11879                   ProcessExpressionType(field.expression);
11880          }
11881          if(stmt.asmStmt.clobberedFields)
11882          {
11883             for(field = stmt.asmStmt.clobberedFields->first; field; field = field.next)
11884             {
11885                if(field.expression)
11886                   ProcessExpressionType(field.expression);
11887             }
11888          }
11889          break;
11890       }
11891       case watchStmt:
11892       {
11893          PropertyWatch propWatch;
11894          OldList * watches = stmt._watch.watches;
11895          Expression object = stmt._watch.object;
11896          Expression watcher = stmt._watch.watcher;
11897          if(watcher)
11898             ProcessExpressionType(watcher);
11899          if(object)
11900             ProcessExpressionType(object);
11901
11902          if(inCompiler)
11903          {
11904             if(watcher || thisClass)
11905             {
11906                External external = curExternal;
11907                Context context = curContext;
11908
11909                stmt.type = expressionStmt;
11910                stmt.expressions = MkList();
11911
11912                curExternal = external.prev;
11913
11914                for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
11915                {
11916                   ClassFunction func;
11917                   char watcherName[1024];
11918                   Class watcherClass = watcher ?
11919                      ((watcher.expType && watcher.expType.kind == classType && watcher.expType._class) ? watcher.expType._class.registered : null) : thisClass;
11920                   External createdExternal;
11921
11922                   // Create a declaration above
11923                   External externalDecl = MkExternalDeclaration(null);
11924                   ast->Insert(curExternal.prev, externalDecl);
11925
11926                   sprintf(watcherName,"__ecerePropertyWatcher_%d", propWatcherID++);
11927                   if(propWatch.deleteWatch)
11928                      strcat(watcherName, "_delete");
11929                   else
11930                   {
11931                      Identifier propID;
11932                      for(propID = propWatch.properties->first; propID; propID = propID.next)
11933                      {
11934                         strcat(watcherName, "_");
11935                         strcat(watcherName, propID.string);
11936                      }
11937                   }
11938
11939                   if(object && object.expType && object.expType.kind == classType && object.expType._class && object.expType._class.registered)
11940                   {
11941                      // TESTING THIS STUFF... BEWARE OF SYMBOL ID ISSUES
11942                      func = MkClassFunction(MkListOne(MkSpecifier(VOID)), null, MkDeclaratorFunction(MkDeclaratorIdentifier(MkIdentifier(watcherName)),
11943                         //MkListOne(MkTypeName(MkListOne(MkSpecifier(VOID)), null))), null);
11944                         MkListOne(MkTypeName(MkListOne(MkSpecifierName(object.expType._class.string)), MkDeclaratorIdentifier(MkIdentifier("value"))))), null);
11945                      ProcessClassFunctionBody(func, propWatch.compound);
11946                      propWatch.compound = null;
11947
11948                      //afterExternal = afterExternal ? afterExternal : curExternal;
11949
11950                      //createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal.prev);
11951                      createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal, true);
11952                      // TESTING THIS...
11953                      createdExternal.symbol.idCode = external.symbol.idCode;
11954
11955                      curExternal = createdExternal;
11956                      ProcessFunction(createdExternal.function);
11957
11958
11959                      // Create a declaration above
11960                      {
11961                         Declaration decl = MkDeclaration(CopyList(createdExternal.function.specifiers, CopySpecifier),
11962                            MkListOne(MkInitDeclarator(CopyDeclarator(createdExternal.function.declarator), null)));
11963                         externalDecl.declaration = decl;
11964                         if(decl.symbol && !decl.symbol.pointerExternal)
11965                            decl.symbol.pointerExternal = externalDecl;
11966                      }
11967
11968                      if(propWatch.deleteWatch)
11969                      {
11970                         OldList * args = MkList();
11971                         ListAdd(args, CopyExpression(object));
11972                         ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
11973                         ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
11974                         ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_WatchDestruction")), args));
11975                      }
11976                      else
11977                      {
11978                         Class _class = object.expType._class.registered;
11979                         Identifier propID;
11980
11981                         for(propID = propWatch.properties->first; propID; propID = propID.next)
11982                         {
11983                            char propName[1024];
11984                            Property prop = eClass_FindProperty(_class, propID.string, privateModule);
11985                            if(prop)
11986                            {
11987                               char getName[1024], setName[1024];
11988                               OldList * args = MkList();
11989
11990                               DeclareProperty(prop, setName, getName);
11991
11992                               // eInstance_Watch(stmt.watch.object, prop, stmt.watch.watcher, callback);
11993                               strcpy(propName, "__ecereProp_");
11994                               FullClassNameCat(propName, prop._class.fullName, false);
11995                               strcat(propName, "_");
11996                               // strcat(propName, prop.name);
11997                               FullClassNameCat(propName, prop.name, true);
11998
11999                               ListAdd(args, CopyExpression(object));
12000                               ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12001                               ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12002                               ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
12003
12004                               ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_Watch")), args));
12005                            }
12006                            else
12007                               Compiler_Error($"Property %s not found in class %s\n", prop.name, _class.fullName);
12008                         }
12009                      }
12010                   }
12011                   else
12012                      Compiler_Error($"Invalid watched object\n");
12013                }
12014
12015                curExternal = external;
12016                curContext = context;
12017
12018                if(watcher)
12019                   FreeExpression(watcher);
12020                if(object)
12021                   FreeExpression(object);
12022                FreeList(watches, FreePropertyWatch);
12023             }
12024             else
12025                Compiler_Error($"No observer specified and not inside a _class\n");
12026          }
12027          else
12028          {
12029             for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12030             {
12031                ProcessStatement(propWatch.compound);
12032             }
12033
12034          }
12035          break;
12036       }
12037       case fireWatchersStmt:
12038       {
12039          OldList * watches = stmt._watch.watches;
12040          Expression object = stmt._watch.object;
12041          Class _class;
12042          // DEBUGGER BUG: Why doesn't watches evaluate to null??
12043          // printf("%X\n", watches);
12044          // printf("%X\n", stmt._watch.watches);
12045          if(object)
12046             ProcessExpressionType(object);
12047
12048          if(inCompiler)
12049          {
12050             _class = object ?
12051                   ((object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null) : thisClass;
12052
12053             if(_class)
12054             {
12055                Identifier propID;
12056
12057                stmt.type = expressionStmt;
12058                stmt.expressions = MkList();
12059
12060                // Check if we're inside a property set
12061                if(!watches && curFunction.propSet && (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
12062                {
12063                   watches = MkListOne(MkIdentifier(curFunction.propSet.string));
12064                }
12065                else if(!watches)
12066                {
12067                   //Compiler_Error($"No property specified and not inside a property set\n");
12068                }
12069                if(watches)
12070                {
12071                   for(propID = watches->first; propID; propID = propID.next)
12072                   {
12073                      Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12074                      if(prop)
12075                      {
12076                         CreateFireWatcher(prop, object, stmt);
12077                      }
12078                      else
12079                         Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12080                   }
12081                }
12082                else
12083                {
12084                   // Fire all properties!
12085                   Property prop;
12086                   Class base;
12087                   for(base = _class; base; base = base.base)
12088                   {
12089                      for(prop = base.membersAndProperties.first; prop; prop = prop.next)
12090                      {
12091                         if(prop.isProperty && prop.isWatchable)
12092                         {
12093                            CreateFireWatcher(prop, object, stmt);
12094                         }
12095                      }
12096                   }
12097                }
12098
12099                if(object)
12100                   FreeExpression(object);
12101                FreeList(watches, FreeIdentifier);
12102             }
12103             else
12104                Compiler_Error($"Invalid object specified and not inside a class\n");
12105          }
12106          break;
12107       }
12108       case stopWatchingStmt:
12109       {
12110          OldList * watches = stmt._watch.watches;
12111          Expression object = stmt._watch.object;
12112          Expression watcher = stmt._watch.watcher;
12113          Class _class;
12114          if(object)
12115             ProcessExpressionType(object);
12116          if(watcher)
12117             ProcessExpressionType(watcher);
12118          if(inCompiler)
12119          {
12120             _class = (object && object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null;
12121
12122             if(watcher || thisClass)
12123             {
12124                if(_class)
12125                {
12126                   Identifier propID;
12127
12128                   stmt.type = expressionStmt;
12129                   stmt.expressions = MkList();
12130
12131                   if(!watches)
12132                   {
12133                      OldList * args;
12134                      // eInstance_StopWatching(object, null, watcher);
12135                      args = MkList();
12136                      ListAdd(args, CopyExpression(object));
12137                      ListAdd(args, MkExpConstant("0"));
12138                      ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12139                      ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12140                   }
12141                   else
12142                   {
12143                      for(propID = watches->first; propID; propID = propID.next)
12144                      {
12145                         char propName[1024];
12146                         Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12147                         if(prop)
12148                         {
12149                            char getName[1024], setName[1024];
12150                            OldList * args = MkList();
12151
12152                            DeclareProperty(prop, setName, getName);
12153
12154                            // eInstance_StopWatching(object, prop, watcher);
12155                            strcpy(propName, "__ecereProp_");
12156                            FullClassNameCat(propName, prop._class.fullName, false);
12157                            strcat(propName, "_");
12158                            // strcat(propName, prop.name);
12159                            FullClassNameCat(propName, prop.name, true);
12160                            MangleClassName(propName);
12161
12162                            ListAdd(args, CopyExpression(object));
12163                            ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12164                            ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12165                            ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12166                         }
12167                         else
12168                            Compiler_Error($"Property %s not found in class %s\n", prop.name, _class.fullName);
12169                      }
12170                   }
12171
12172                   if(object)
12173                      FreeExpression(object);
12174                   if(watcher)
12175                      FreeExpression(watcher);
12176                   FreeList(watches, FreeIdentifier);
12177                }
12178                else
12179                   Compiler_Error($"Invalid object specified and not inside a class\n");
12180             }
12181             else
12182                Compiler_Error($"No observer specified and not inside a class\n");
12183          }
12184          break;
12185       }
12186    }
12187 }
12188
12189 static void ProcessFunction(FunctionDefinition function)
12190 {
12191    Identifier id = GetDeclId(function.declarator);
12192    Symbol symbol = function.declarator ? function.declarator.symbol : null;
12193    Type type = symbol ? symbol.type : null;
12194    Class oldThisClass = thisClass;
12195    Context oldTopContext = topContext;
12196
12197    yylloc = function.loc;
12198    // Process thisClass
12199
12200    if(type && type.thisClass)
12201    {
12202       Symbol classSym = type.thisClass;
12203       Class _class = type.thisClass.registered;
12204       char className[1024];
12205       char structName[1024];
12206       Declarator funcDecl;
12207       Symbol thisSymbol;
12208
12209       bool typedObject = false;
12210
12211       if(_class && !_class.base)
12212       {
12213          _class = currentClass;
12214          if(_class && !_class.symbol)
12215             _class.symbol = FindClass(_class.fullName);
12216          classSym = _class ? _class.symbol : null;
12217          typedObject = true;
12218       }
12219
12220       thisClass = _class;
12221
12222       if(inCompiler && _class)
12223       {
12224          if(type.kind == functionType)
12225          {
12226             if(symbol.type.params.count == 1 && ((Type)symbol.type.params.first).kind == voidType)
12227             {
12228                //TypeName param = symbol.type.params.first;
12229                Type param = symbol.type.params.first;
12230                symbol.type.params.Remove(param);
12231                //FreeTypeName(param);
12232                FreeType(param);
12233             }
12234             if(type.classObjectType != classPointer)
12235             {
12236                symbol.type.params.Insert(null, MkClassType(_class.fullName));
12237                symbol.type.staticMethod = true;
12238                symbol.type.thisClass = null;
12239
12240                // HIGH DANGER: VERIFYING THIS...
12241                symbol.type.extraParam = false;
12242             }
12243          }
12244
12245          strcpy(className, "__ecereClass_");
12246          FullClassNameCat(className, _class.fullName, true);
12247
12248          MangleClassName(className);
12249
12250          structName[0] = 0;
12251          FullClassNameCat(structName, _class.fullName, false);
12252
12253          // [class] this
12254
12255
12256          funcDecl = GetFuncDecl(function.declarator);
12257          if(funcDecl)
12258          {
12259             if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12260             {
12261                TypeName param = funcDecl.function.parameters->first;
12262                if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12263                {
12264                   funcDecl.function.parameters->Remove(param);
12265                   FreeTypeName(param);
12266                }
12267             }
12268
12269             // DANGER: Watch for this... Check if it's a Conversion?
12270             // if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
12271
12272             // WAS TRYING THIS FOR CONVERSION PROPERTIES ON NOHEAD CLASSES: if((_class.type == structClass) || function != (FunctionDefinition)symbol.externalSet)
12273             if(!function.propertyNoThis)
12274             {
12275                TypeName thisParam;
12276
12277                if(type.classObjectType != classPointer)
12278                {
12279                   thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12280                   if(!funcDecl.function.parameters)
12281                      funcDecl.function.parameters = MkList();
12282                   funcDecl.function.parameters->Insert(null, thisParam);
12283                }
12284
12285                if(typedObject)
12286                {
12287                   if(type.classObjectType != classPointer)
12288                   {
12289                      if(type.byReference || _class.type == unitClass || _class.type == systemClass || _class.type == enumClass || _class.type == bitClass)
12290                         thisParam.declarator = MkDeclaratorPointer(MkPointer(null,null), thisParam.declarator);
12291                   }
12292
12293                   thisParam = TypeName
12294                   {
12295                      declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
12296                      qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
12297                   };
12298                   funcDecl.function.parameters->Insert(null, thisParam);
12299                }
12300             }
12301          }
12302
12303          if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
12304          {
12305             InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
12306             funcDecl = GetFuncDecl(initDecl.declarator);
12307             if(funcDecl)
12308             {
12309                if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12310                {
12311                   TypeName param = funcDecl.function.parameters->first;
12312                   if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12313                   {
12314                      funcDecl.function.parameters->Remove(param);
12315                      FreeTypeName(param);
12316                   }
12317                }
12318
12319                if(type.classObjectType != classPointer)
12320                {
12321                   // DANGER: Watch for this... Check if it's a Conversion?
12322                   if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
12323                   {
12324                      TypeName thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12325
12326                      if(!funcDecl.function.parameters)
12327                         funcDecl.function.parameters = MkList();
12328                      funcDecl.function.parameters->Insert(null, thisParam);
12329                   }
12330                }
12331             }
12332          }
12333       }
12334
12335       // Add this to the context
12336       if(function.body)
12337       {
12338          if(type.classObjectType != classPointer)
12339          {
12340             thisSymbol = Symbol
12341             {
12342                string = CopyString("this");
12343                type = classSym ? MkClassType(classSym.string) : null; //_class.fullName);
12344             };
12345             function.body.compound.context.symbols.Add((BTNode)thisSymbol);
12346
12347             if(typedObject && thisSymbol.type)
12348             {
12349                thisSymbol.type.classObjectType = ClassObjectType::typedObject;
12350                thisSymbol.type.byReference = type.byReference;
12351                thisSymbol.type.typedByReference = type.byReference;
12352                /*
12353                thisSymbol = Symbol { string = CopyString("class") };
12354                function.body.compound.context.symbols.Add(thisSymbol);
12355                */
12356             }
12357          }
12358       }
12359
12360       // Pointer to class data
12361
12362       if(inCompiler && _class && (_class.type == normalClass /*|| _class.type == noHeadClass*/) && type.classObjectType != classPointer)
12363       {
12364          DataMember member = null;
12365          {
12366             Class base;
12367             for(base = _class; base && base.type != systemClass; base = base.next)
12368             {
12369                for(member = base.membersAndProperties.first; member; member = member.next)
12370                   if(!member.isProperty)
12371                      break;
12372                if(member)
12373                   break;
12374             }
12375          }
12376          for(member = _class.membersAndProperties.first; member; member = member.next)
12377             if(!member.isProperty)
12378                break;
12379          if(member)
12380          {
12381             char pointerName[1024];
12382
12383             Declaration decl;
12384             Initializer initializer;
12385             Expression exp, bytePtr;
12386
12387             strcpy(pointerName, "__ecerePointer_");
12388             FullClassNameCat(pointerName, _class.fullName, false);
12389             {
12390                char className[1024];
12391                strcpy(className, "__ecereClass_");
12392                FullClassNameCat(className, classSym.string, true);
12393                MangleClassName(className);
12394
12395                // Testing This
12396                DeclareClass(classSym, className);
12397             }
12398
12399             // ((byte *) this)
12400             bytePtr = QBrackets(MkExpCast(QMkType("char", QMkPtrDecl(null)), QMkExpId("this")));
12401
12402             if(_class.fixed)
12403             {
12404                char string[256];
12405                sprintf(string, "%d", _class.offset);
12406                exp = QBrackets(MkExpOp(bytePtr, '+', MkExpConstant(string)));
12407             }
12408             else
12409             {
12410                // ([bytePtr] + [className]->offset)
12411                exp = QBrackets(MkExpOp(bytePtr, '+',
12412                   MkExpPointer(QMkExpId(className), MkIdentifier("offset"))));
12413             }
12414
12415             // (this ? [exp] : 0)
12416             exp = QBrackets(QMkExpCond(QMkExpId("this"), exp, MkExpConstant("0")));
12417             exp.expType = Type
12418             {
12419                refCount = 1;
12420                kind = pointerType;
12421                type = Type { refCount = 1, kind = voidType };
12422             };
12423
12424             if(function.body)
12425             {
12426                yylloc = function.body.loc;
12427                // ([structName] *) [exp]
12428                // initializer = MkInitializerAssignment(MkExpCast(QMkType(structName, QMkPtrDecl(null)), exp));
12429                initializer = MkInitializerAssignment(
12430                   MkExpCast(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)), exp));
12431
12432                // [structName] * [pointerName] = [initializer];
12433                // decl = QMkDeclaration(structName, MkInitDeclarator(QMkPtrDecl(pointerName), initializer));
12434
12435                {
12436                   Context prevContext = curContext;
12437                   curContext = function.body.compound.context;
12438
12439                   decl = MkDeclaration(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)),
12440                      MkListOne(MkInitDeclarator(QMkPtrDecl(pointerName), initializer)));
12441
12442                   curContext = prevContext;
12443                }
12444
12445                // WHY?
12446                decl.symbol = null;
12447
12448                if(!function.body.compound.declarations)
12449                   function.body.compound.declarations = MkList();
12450                function.body.compound.declarations->Insert(null, decl);
12451             }
12452          }
12453       }
12454
12455
12456       // Loop through the function and replace undeclared identifiers
12457       // which are a member of the class (methods, properties or data)
12458       // by "this.[member]"
12459    }
12460    else
12461       thisClass = null;
12462
12463    if(id)
12464    {
12465       FreeSpecifier(id._class);
12466       id._class = null;
12467
12468       if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
12469       {
12470          InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
12471          id = GetDeclId(initDecl.declarator);
12472
12473          FreeSpecifier(id._class);
12474          id._class = null;
12475       }
12476    }
12477    if(function.body)
12478       topContext = function.body.compound.context;
12479    {
12480       FunctionDefinition oldFunction = curFunction;
12481       curFunction = function;
12482       if(function.body)
12483          ProcessStatement(function.body);
12484
12485       // If this is a property set and no firewatchers has been done yet, add one here
12486       if(inCompiler && function.propSet && !function.propSet.fireWatchersDone)
12487       {
12488          Statement prevCompound = curCompound;
12489          Context prevContext = curContext;
12490
12491          Statement fireWatchers = MkFireWatchersStmt(null, null);
12492          if(!function.body.compound.statements) function.body.compound.statements = MkList();
12493          ListAdd(function.body.compound.statements, fireWatchers);
12494
12495          curCompound = function.body;
12496          curContext = function.body.compound.context;
12497
12498          ProcessStatement(fireWatchers);
12499
12500          curContext = prevContext;
12501          curCompound = prevCompound;
12502
12503       }
12504
12505       curFunction = oldFunction;
12506    }
12507
12508    if(function.declarator)
12509    {
12510       ProcessDeclarator(function.declarator);
12511    }
12512
12513    topContext = oldTopContext;
12514    thisClass = oldThisClass;
12515 }
12516
12517 /////////// INSTANTIATIONS / DATA TYPES PASS /////////////////////////////////////////////
12518 static void ProcessClass(OldList definitions, Symbol symbol)
12519 {
12520    ClassDef def;
12521    External external = curExternal;
12522    Class regClass = symbol ? symbol.registered : null;
12523
12524    // Process all functions
12525    for(def = definitions.first; def; def = def.next)
12526    {
12527       if(def.type == functionClassDef)
12528       {
12529          if(def.function.declarator)
12530             curExternal = def.function.declarator.symbol.pointerExternal;
12531          else
12532             curExternal = external;
12533
12534          ProcessFunction((FunctionDefinition)def.function);
12535       }
12536       else if(def.type == declarationClassDef)
12537       {
12538          if(def.decl.type == instDeclaration)
12539          {
12540             thisClass = regClass;
12541             ProcessInstantiationType(def.decl.inst);
12542             thisClass = null;
12543          }
12544          // Testing this
12545          else
12546          {
12547             Class backThisClass = thisClass;
12548             if(regClass) thisClass = regClass;
12549             ProcessDeclaration(def.decl);
12550             thisClass = backThisClass;
12551          }
12552       }
12553       else if(def.type == defaultPropertiesClassDef && def.defProperties)
12554       {
12555          MemberInit defProperty;
12556
12557          // Add this to the context
12558          Symbol thisSymbol = Symbol
12559          {
12560             string = CopyString("this");
12561             type = regClass ? MkClassType(regClass.fullName) : null;
12562          };
12563          globalContext.symbols.Add((BTNode)thisSymbol);
12564
12565          for(defProperty = def.defProperties->first; defProperty; defProperty = defProperty.next)
12566          {
12567             thisClass = regClass;
12568             ProcessMemberInitData(defProperty, regClass, null, null, null, null);
12569             thisClass = null;
12570          }
12571
12572          globalContext.symbols.Remove((BTNode)thisSymbol);
12573          FreeSymbol(thisSymbol);
12574       }
12575       else if(def.type == propertyClassDef && def.propertyDef)
12576       {
12577          PropertyDef prop = def.propertyDef;
12578
12579          // Add this to the context
12580          /*
12581          Symbol thisSymbol = Symbol { string = CopyString("this"), type = MkClassType(regClass.fullName) };
12582          globalContext.symbols.Add(thisSymbol);
12583          */
12584
12585          thisClass = regClass;
12586          if(prop.setStmt)
12587          {
12588             if(regClass)
12589             {
12590                Symbol thisSymbol
12591                {
12592                   string = CopyString("this");
12593                   type = MkClassType(regClass.fullName);
12594                };
12595                prop.setStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12596             }
12597
12598             curExternal = prop.symbol ? prop.symbol.externalSet : null;
12599             ProcessStatement(prop.setStmt);
12600          }
12601          if(prop.getStmt)
12602          {
12603             if(regClass)
12604             {
12605                Symbol thisSymbol
12606                {
12607                   string = CopyString("this");
12608                   type = MkClassType(regClass.fullName);
12609                };
12610                prop.getStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12611             }
12612
12613             curExternal = prop.symbol ? prop.symbol.externalGet : null;
12614             ProcessStatement(prop.getStmt);
12615          }
12616          if(prop.issetStmt)
12617          {
12618             if(regClass)
12619             {
12620                Symbol thisSymbol
12621                {
12622                   string = CopyString("this");
12623                   type = MkClassType(regClass.fullName);
12624                };
12625                prop.issetStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12626             }
12627
12628             curExternal = prop.symbol ? prop.symbol.externalIsSet : null;
12629             ProcessStatement(prop.issetStmt);
12630          }
12631
12632          thisClass = null;
12633
12634          /*
12635          globalContext.symbols.Remove(thisSymbol);
12636          FreeSymbol(thisSymbol);
12637          */
12638       }
12639       else if(def.type == propertyWatchClassDef && def.propertyWatch)
12640       {
12641          PropertyWatch propertyWatch = def.propertyWatch;
12642
12643          thisClass = regClass;
12644          if(propertyWatch.compound)
12645          {
12646             Symbol thisSymbol
12647             {
12648                string = CopyString("this");
12649                type = regClass ? MkClassType(regClass.fullName) : null;
12650             };
12651
12652             propertyWatch.compound.compound.context.symbols.Add((BTNode)thisSymbol);
12653
12654             curExternal = null;
12655             ProcessStatement(propertyWatch.compound);
12656          }
12657          thisClass = null;
12658       }
12659    }
12660 }
12661
12662 void DeclareFunctionUtil(String s)
12663 {
12664    GlobalFunction function = eSystem_FindFunction(privateModule, s);
12665    if(function)
12666    {
12667       char name[1024];
12668       name[0] = 0;
12669       if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
12670          strcpy(name, "__ecereFunction_");
12671       FullClassNameCat(name, s, false); // Why is this using FullClassNameCat ?
12672       DeclareFunction(function, name);
12673    }
12674 }
12675
12676 void ComputeDataTypes()
12677 {
12678    External external;
12679    External temp { };
12680    External after = null;
12681
12682    currentClass = null;
12683
12684    containerClass = eSystem_FindClass(GetPrivateModule(), "Container");
12685
12686    for(external = ast->first; external; external = external.next)
12687    {
12688       if(external.type == declarationExternal)
12689       {
12690          Declaration decl = external.declaration;
12691          if(decl)
12692          {
12693             OldList * decls = decl.declarators;
12694             if(decls)
12695             {
12696                InitDeclarator initDecl = decls->first;
12697                if(initDecl)
12698                {
12699                   Declarator declarator = initDecl.declarator;
12700                   if(declarator && declarator.type == identifierDeclarator)
12701                   {
12702                      Identifier id = declarator.identifier;
12703                      if(id && id.string)
12704                      {
12705                         if(!strcmp(id.string, "uintptr_t") || !strcmp(id.string, "intptr_t") || !strcmp(id.string, "size_t") || !strcmp(id.string, "ssize_t"))
12706                         {
12707                            external.symbol.id = -1001, external.symbol.idCode = -1001;
12708                            after = external;
12709                         }
12710                      }
12711                   }
12712                }
12713             }
12714          }
12715        }
12716    }
12717
12718    temp.symbol = Symbol { id = -1000, idCode = -1000 };
12719    ast->Insert(after, temp);
12720    curExternal = temp;
12721
12722    DeclareFunctionUtil("eSystem_New");
12723    DeclareFunctionUtil("eSystem_New0");
12724    DeclareFunctionUtil("eSystem_Renew");
12725    DeclareFunctionUtil("eSystem_Renew0");
12726    DeclareFunctionUtil("eSystem_Delete");
12727    DeclareFunctionUtil("eClass_GetProperty");
12728    DeclareFunctionUtil("eInstance_FireSelfWatchers");
12729
12730    DeclareStruct("ecere::com::Class", false);
12731    DeclareStruct("ecere::com::Instance", false);
12732    DeclareStruct("ecere::com::Property", false);
12733    DeclareStruct("ecere::com::DataMember", false);
12734    DeclareStruct("ecere::com::Method", false);
12735    DeclareStruct("ecere::com::SerialBuffer", false);
12736    DeclareStruct("ecere::com::ClassTemplateArgument", false);
12737
12738    ast->Remove(temp);
12739
12740    for(external = ast->first; external; external = external.next)
12741    {
12742       afterExternal = curExternal = external;
12743       if(external.type == functionExternal)
12744       {
12745          currentClass = external.function._class;
12746          ProcessFunction(external.function);
12747       }
12748       // There shouldn't be any _class member access here anyways...
12749       else if(external.type == declarationExternal)
12750       {
12751          currentClass = null;
12752          ProcessDeclaration(external.declaration);
12753       }
12754       else if(external.type == classExternal)
12755       {
12756          ClassDefinition _class = external._class;
12757          currentClass = external.symbol.registered;
12758          if(_class.definitions)
12759          {
12760             ProcessClass(_class.definitions, _class.symbol);
12761          }
12762          if(inCompiler)
12763          {
12764             // Free class data...
12765             ast->Remove(external);
12766             delete external;
12767          }
12768       }
12769       else if(external.type == nameSpaceExternal)
12770       {
12771          thisNameSpace = external.id.string;
12772       }
12773    }
12774    currentClass = null;
12775    thisNameSpace = null;
12776
12777    delete temp.symbol;
12778    delete temp;
12779 }