697d078d3ca755a59b8c901048e6bdfd0d53c50a
[sdk] / compiler / libec / src / pass15.ec
1 import "ecdefs"
2
3 // UNTIL IMPLEMENTED IN GRAMMAR
4 #define ACCESS_CLASSDATA(_class, baseClass) \
5    (_class ? ((void *)(((char *)_class.data) + baseClass.offsetClass)) : null)
6
7 #define YYLTYPE Location
8 #include "grammar.h"
9
10 extern OldList * ast;
11 extern int returnCode;
12 extern Expression parsedExpression;
13 extern bool yydebug;
14 public void SetYydebug(bool b) { yydebug = b; }
15 extern bool echoOn;
16
17 void resetScanner();
18
19 // TODO: Reset this to 0 on reinitialization
20 int propWatcherID;
21
22 int expression_yyparse();
23 static Statement curCompound;
24 External curExternal, afterExternal;
25 static Type curSwitchType;
26 static Class currentClass;
27 Class thisClass;
28 public void SetThisClass(Class c) { thisClass = c; } public Class GetThisClass() { return thisClass; }
29 static char * thisNameSpace;
30 /*static */Class containerClass;
31 bool thisClassParams = true;
32
33 uint internalValueCounter;
34
35 #ifdef _DEBUG
36 Time findSymbolTotalTime;
37 #endif
38
39 // WARNING: PrintExpression CONCATENATES to string. Please initialize.
40 /*static */public void PrintExpression(Expression exp, char * string)
41 {
42    //if(inCompiler)
43    {
44       TempFile f { };
45       int count;
46       bool backOutputLineNumbers = outputLineNumbers;
47       outputLineNumbers = false;
48
49       if(exp)
50          OutputExpression(exp, f);
51       f.Seek(0, start);
52       count = strlen(string);
53       count += f.Read(string + count, 1, 1023);
54       string[count] = '\0';
55       delete f;
56
57       outputLineNumbers = backOutputLineNumbers;
58    }
59 }
60
61 Type ProcessTemplateParameterType(TemplateParameter param)
62 {
63    if(param && param.type == TemplateParameterType::type && (param.dataType || param.dataTypeString))
64    {
65       // TOFIX: Will need to free this Type
66       if(!param.baseType)
67       {
68          if(param.dataTypeString)
69             param.baseType = ProcessTypeString(param.dataTypeString, false);
70          else
71             param.baseType = ProcessType(param.dataType.specifiers, param.dataType.decl);
72       }
73       return param.baseType;
74    }
75    return null;
76 }
77
78 bool NeedCast(Type type1, Type type2)
79 {
80    if(!type1 || !type2 || type1.keepCast || type2.keepCast) return true;
81
82    if(type1.kind == templateType && type2.kind == int64Type && type2.passAsTemplate == false)
83    {
84       return false;
85    }
86
87    if(type1.kind == type2.kind && type1.isLong == type2.isLong)
88    {
89       switch(type1.kind)
90       {
91          case _BoolType:
92          case charType:
93          case shortType:
94          case intType:
95          case int64Type:
96          case intPtrType:
97          case intSizeType:
98             if(type1.passAsTemplate && !type2.passAsTemplate)
99                return true;
100             return type1.isSigned != type2.isSigned;
101          case classType:
102             return type1._class != type2._class;
103          case pointerType:
104             return (type1.type && type2.type && type1.type.constant != type2.type.constant) || NeedCast(type1.type, type2.type);
105          default:
106             return true; //false; ????
107       }
108    }
109    return true;
110 }
111
112 static void ReplaceClassMembers(Expression exp, Class _class)
113 {
114    if(exp.type == identifierExp && exp.identifier)
115    {
116       Identifier id = exp.identifier;
117       Context ctx;
118       Symbol symbol = null;
119       if(!id._class || !id._class.name || strcmp(id._class.name, "property"))
120       {
121          // First, check if the identifier is declared inside the function
122          for(ctx = curContext; ctx != topContext.parent && !symbol; ctx = ctx.parent)
123          {
124             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%I64X"*/, 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    if(result > MAXINT || result < MININT)
229       sprintf(temp, FORMAT64DLL /*"%I64d"*/, result);
230    else
231       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
232    return CopyString(temp);
233 }
234
235 public char * PrintUInt64(uint64 result)
236 {
237    char temp[100];
238    if(result > MAXDWORD)
239       sprintf(temp, FORMAT64HEXLL /*"0x%I64XLL"*/, result);
240    else if(result > MAXINT)
241       sprintf(temp, FORMAT64HEX /*"0x%I64XLL"*/, result);
242    else
243       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
244    return CopyString(temp);
245 }
246
247 public char * PrintHexUInt(uint64 result)
248 {
249    char temp[100];
250    if(result > MAXDWORD)
251       sprintf(temp, FORMAT64HEX /*"0x%I64xLL"*/, result);
252    else
253       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
254    if(result > MAXDWORD)
255       strcat(temp, "LL");
256    return CopyString(temp);
257 }
258
259 public char * PrintHexUInt64(uint64 result)
260 {
261    char temp[100];
262    if(result > MAXDWORD)
263       sprintf(temp, FORMAT64HEXLL /*"0x%I64xLL"*/, result);
264    else
265       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
266    return CopyString(temp);
267 }
268
269 public char * PrintShort(short result)
270 {
271    char temp[100];
272    sprintf(temp, "%d", (unsigned short)result);
273    return CopyString(temp);
274 }
275
276 public char * PrintUShort(unsigned short result)
277 {
278    char temp[100];
279    if(result > 32767)
280       sprintf(temp, "0x%X", (int)result);
281    else
282       sprintf(temp, "%d", (int)result);
283    return CopyString(temp);
284 }
285
286 public char * PrintChar(char result)
287 {
288    char temp[100];
289    if(result > 0 && isprint(result))
290       sprintf(temp, "'%c'", result);
291    else if(result < 0)
292       sprintf(temp, "%d", (int)result);
293    else
294       //sprintf(temp, "%#X", result);
295       sprintf(temp, "0x%X", (unsigned char)result);
296    return CopyString(temp);
297 }
298
299 public char * PrintUChar(unsigned char result)
300 {
301    char temp[100];
302    sprintf(temp, "0x%X", result);
303    return CopyString(temp);
304 }
305
306 public char * PrintFloat(float result)
307 {
308    char temp[350];
309    if(result.isInf)
310    {
311       if(result.signBit)
312          strcpy(temp, "-inf");
313       else
314          strcpy(temp, "inf");
315    }
316    else if(result.isNan)
317    {
318       if(result.signBit)
319          strcpy(temp, "-nan");
320       else
321          strcpy(temp, "nan");
322    }
323    else
324       sprintf(temp, "%.16ff", result);
325    return CopyString(temp);
326 }
327
328 public char * PrintDouble(double result)
329 {
330    char temp[350];
331    if(result.isInf)
332    {
333       if(result.signBit)
334          strcpy(temp, "-inf");
335       else
336          strcpy(temp, "inf");
337    }
338    else if(result.isNan)
339    {
340       if(result.signBit)
341          strcpy(temp, "-nan");
342       else
343          strcpy(temp, "nan");
344    }
345    else
346       sprintf(temp, "%.16f", result);
347    return CopyString(temp);
348 }
349
350 ////////////////////////////////////////////////////////////////////////
351 ////////////////////////////////////////////////////////////////////////
352
353 //public Operand GetOperand(Expression exp);
354
355 #define GETVALUE(name, t) \
356    public bool GetOp##name(Operand op2, t * value2) \
357    {                                                        \
358       if(op2.kind == intType && op2.type.isSigned) *value2 = (t) op2.i; \
359       else if(op2.kind == intType) *value2 = (t) op2.ui;                 \
360       else if(op2.kind == int64Type && op2.type.isSigned) *value2 = (t) op2.i64; \
361       else if(op2.kind == int64Type) *value2 = (t) op2.ui64;                 \
362       else if(op2.kind == intSizeType && op2.type.isSigned) *value2 = (t) op2.i64; \
363       else if(op2.kind == intSizeType) *value2 = (t) op2.ui64; \
364       else if(op2.kind == intPtrType && op2.type.isSigned) *value2 = (t) op2.i64; \
365       else if(op2.kind == intPtrType) *value2 = (t) op2.ui64;                 \
366       else if(op2.kind == shortType && op2.type.isSigned) *value2 = (t) op2.s;   \
367       else if(op2.kind == shortType) *value2 = (t) op2.us;                        \
368       else if(op2.kind == charType && op2.type.isSigned) *value2 = (t) op2.c;    \
369       else if(op2.kind == _BoolType || op2.kind == charType) *value2 = (t) op2.uc; \
370       else if(op2.kind == floatType) *value2 = (t) op2.f;                         \
371       else if(op2.kind == doubleType) *value2 = (t) op2.d;                        \
372       else if(op2.kind == pointerType) *value2 = (t) op2.ui64;                    \
373       else                                                                          \
374          return false;                                                              \
375       return true;                                                                  \
376    } \
377    public bool Get##name(Expression exp, t * value2) \
378    {                                                        \
379       Operand op2 = GetOperand(exp);                        \
380       return GetOp##name(op2, value2); \
381    }
382
383 // To help the debugger currently not preprocessing...
384 #define HELP(x) x
385
386 GETVALUE(Int, HELP(int));
387 GETVALUE(UInt, HELP(unsigned int));
388 GETVALUE(Int64, HELP(int64));
389 GETVALUE(UInt64, HELP(uint64));
390 GETVALUE(IntPtr, HELP(intptr));
391 GETVALUE(UIntPtr, HELP(uintptr));
392 GETVALUE(IntSize, HELP(intsize));
393 GETVALUE(UIntSize, HELP(uintsize));
394 GETVALUE(Short, HELP(short));
395 GETVALUE(UShort, HELP(unsigned short));
396 GETVALUE(Char, HELP(char));
397 GETVALUE(UChar, HELP(unsigned char));
398 GETVALUE(Float, HELP(float));
399 GETVALUE(Double, HELP(double));
400
401 void ComputeExpression(Expression exp);
402
403 void ComputeClassMembers(Class _class, bool isMember)
404 {
405    DataMember member = isMember ? (DataMember) _class : null;
406    Context context = isMember ? null : SetupTemplatesContext(_class);
407    if(member || ((_class.type == bitClass || _class.type == normalClass || _class.type == structClass || _class.type == noHeadClass) &&
408                  (_class.type == bitClass || (!_class.structSize || _class.structSize == _class.offset)) && _class.computeSize))
409    {
410       int unionMemberOffset = 0;
411       int bitFields = 0;
412
413       /*
414       if(!member && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass) && _class.memberOffset && _class.memberOffset > _class.base.structSize)
415          _class.memberOffset = (_class.base && _class.base.type != systemClass) ? _class.base.structSize : 0;
416       */
417
418       if(member)
419       {
420          member.memberOffset = 0;
421          if(targetBits < sizeof(void *) * 8)
422             member.structAlignment = 0;
423       }
424       else if(targetBits < sizeof(void *) * 8)
425          _class.structAlignment = 0;
426
427       // Confusion here: non struct classes seem to have their memberOffset restart at 0 at each hierarchy level
428       if(!member && ((_class.type == normalClass || _class.type == noHeadClass) || (_class.type == structClass && _class.memberOffset && _class.memberOffset > _class.base.structSize)))
429          _class.memberOffset = (_class.base && _class.type == structClass) ? _class.base.structSize : 0;
430
431       if(!member && _class.destructionWatchOffset)
432          _class.memberOffset += sizeof(OldList);
433
434       // To avoid reentrancy...
435       //_class.structSize = -1;
436
437       {
438          DataMember dataMember;
439          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
440          {
441             if(!dataMember.isProperty)
442             {
443                if(dataMember.type == normalMember && dataMember.dataTypeString && !dataMember.dataType)
444                {
445                   dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
446                   /*if(!dataMember.dataType)
447                      dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
448                      */
449                }
450             }
451          }
452       }
453
454       {
455          DataMember dataMember;
456          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
457          {
458             if(!dataMember.isProperty && (dataMember.type != normalMember || dataMember.dataTypeString))
459             {
460                if(!isMember && _class.type == bitClass && dataMember.dataType)
461                {
462                   BitMember bitMember = (BitMember) dataMember;
463                   uint64 mask = 0;
464                   int d;
465
466                   ComputeTypeSize(dataMember.dataType);
467
468                   if(bitMember.pos == -1) bitMember.pos = _class.memberOffset;
469                   if(!bitMember.size) bitMember.size = dataMember.dataType.size * 8;
470
471                   _class.memberOffset = bitMember.pos + bitMember.size;
472                   for(d = 0; d<bitMember.size; d++)
473                   {
474                      if(d)
475                         mask <<= 1;
476                      mask |= 1;
477                   }
478                   bitMember.mask = mask << bitMember.pos;
479                }
480                else if(dataMember.type == normalMember && dataMember.dataType)
481                {
482                   int size;
483                   int alignment = 0;
484
485                   // Prevent infinite recursion
486                   if(dataMember.dataType.kind != classType ||
487                      ((!dataMember.dataType._class || !dataMember.dataType._class.registered || dataMember.dataType._class.registered != _class ||
488                      _class.type != structClass)))
489                      ComputeTypeSize(dataMember.dataType);
490
491                   if(dataMember.dataType.bitFieldCount)
492                   {
493                      bitFields += dataMember.dataType.bitFieldCount;
494                      size = 0;
495                   }
496                   else
497                   {
498                      if(bitFields)
499                      {
500                         int size = (bitFields + 7) / 8;
501
502                         if(isMember)
503                         {
504                            // TESTING THIS PADDING CODE
505                            if(alignment)
506                            {
507                               member.structAlignment = Max(member.structAlignment, alignment);
508
509                               if(member.memberOffset % alignment)
510                                  member.memberOffset += alignment - (member.memberOffset % alignment);
511                            }
512
513                            dataMember.offset = member.memberOffset;
514                            if(member.type == unionMember)
515                               unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
516                            else
517                            {
518                               member.memberOffset += size;
519                            }
520                         }
521                         else
522                         {
523                            // TESTING THIS PADDING CODE
524                            if(alignment)
525                            {
526                               _class.structAlignment = Max(_class.structAlignment, alignment);
527
528                               if(_class.memberOffset % alignment)
529                                  _class.memberOffset += alignment - (_class.memberOffset % alignment);
530                            }
531
532                            dataMember.offset = _class.memberOffset;
533                            _class.memberOffset += size;
534                         }
535                         bitFields = 0;
536                      }
537                      size = dataMember.dataType.size;
538                      alignment = dataMember.dataType.alignment;
539                   }
540
541                   if(isMember)
542                   {
543                      // TESTING THIS PADDING CODE
544                      if(alignment)
545                      {
546                         member.structAlignment = Max(member.structAlignment, alignment);
547
548                         if(member.memberOffset % alignment)
549                            member.memberOffset += alignment - (member.memberOffset % alignment);
550                      }
551
552                      dataMember.offset = member.memberOffset;
553                      if(member.type == unionMember)
554                         unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
555                      else
556                      {
557                         member.memberOffset += size;
558                      }
559                   }
560                   else
561                   {
562                      // TESTING THIS PADDING CODE
563                      if(alignment)
564                      {
565                         _class.structAlignment = Max(_class.structAlignment, alignment);
566
567                         if(_class.memberOffset % alignment)
568                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
569                      }
570
571                      dataMember.offset = _class.memberOffset;
572                      _class.memberOffset += size;
573                   }
574                }
575                else
576                {
577                   int alignment;
578
579                   ComputeClassMembers((Class)dataMember, true);
580                   alignment = dataMember.structAlignment;
581
582                   if(isMember)
583                   {
584                      if(alignment)
585                      {
586                         if(member.memberOffset % alignment)
587                            member.memberOffset += alignment - (member.memberOffset % alignment);
588
589                         member.structAlignment = Max(member.structAlignment, alignment);
590                      }
591                      dataMember.offset = member.memberOffset;
592                      if(member.type == unionMember)
593                         unionMemberOffset = Max(unionMemberOffset, dataMember.memberOffset);
594                      else
595                         member.memberOffset += dataMember.memberOffset;
596                   }
597                   else
598                   {
599                      if(alignment)
600                      {
601                         if(_class.memberOffset % alignment)
602                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
603                         _class.structAlignment = Max(_class.structAlignment, alignment);
604                      }
605                      dataMember.offset = _class.memberOffset;
606                      _class.memberOffset += dataMember.memberOffset;
607                   }
608                }
609             }
610          }
611          if(bitFields)
612          {
613             int alignment = 0;
614             int size = (bitFields + 7) / 8;
615
616             if(isMember)
617             {
618                // TESTING THIS PADDING CODE
619                if(alignment)
620                {
621                   member.structAlignment = Max(member.structAlignment, alignment);
622
623                   if(member.memberOffset % alignment)
624                      member.memberOffset += alignment - (member.memberOffset % alignment);
625                }
626
627                if(member.type == unionMember)
628                   unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
629                else
630                {
631                   member.memberOffset += size;
632                }
633             }
634             else
635             {
636                // TESTING THIS PADDING CODE
637                if(alignment)
638                {
639                   _class.structAlignment = Max(_class.structAlignment, alignment);
640
641                   if(_class.memberOffset % alignment)
642                      _class.memberOffset += alignment - (_class.memberOffset % alignment);
643                }
644                _class.memberOffset += size;
645             }
646             bitFields = 0;
647          }
648       }
649       if(member && member.type == unionMember)
650       {
651          member.memberOffset = unionMemberOffset;
652       }
653
654       if(!isMember)
655       {
656          /*if(_class.type == structClass)
657             _class.size = _class.memberOffset;
658          else
659          */
660
661          if(_class.type != bitClass)
662          {
663             int extra = 0;
664             if(_class.structAlignment)
665             {
666                if(_class.memberOffset % _class.structAlignment)
667                   extra += _class.structAlignment - (_class.memberOffset % _class.structAlignment);
668             }
669             _class.structSize = (_class.base ? (_class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize) : 0) + _class.memberOffset + extra;
670             if(!member)
671             {
672                Property prop;
673                for(prop = _class.membersAndProperties.first; prop; prop = prop.next)
674                {
675                   if(prop.isProperty && prop.isWatchable)
676                   {
677                      prop.watcherOffset = _class.structSize;
678                      _class.structSize += sizeof(OldList);
679                   }
680                }
681             }
682
683             // Fix Derivatives
684             {
685                OldLink derivative;
686                for(derivative = _class.derivatives.first; derivative; derivative = derivative.next)
687                {
688                   Class deriv = derivative.data;
689
690                   if(deriv.computeSize)
691                   {
692                      // TESTING THIS NEW CODE HERE... TRYING TO FIX ScrollBar MEMBERS DEBUGGING
693                      deriv.offset = /*_class.offset + */_class.structSize;
694                      deriv.memberOffset = 0;
695                      // ----------------------
696
697                      deriv.structSize = deriv.offset;
698
699                      ComputeClassMembers(deriv, false);
700                   }
701                }
702             }
703          }
704       }
705    }
706    if(context)
707       FinishTemplatesContext(context);
708 }
709
710 public void ComputeModuleClasses(Module module)
711 {
712    Class _class;
713    OldLink subModule;
714
715    for(subModule = module.modules.first; subModule; subModule = subModule.next)
716       ComputeModuleClasses(subModule.data);
717    for(_class = module.classes.first; _class; _class = _class.next)
718       ComputeClassMembers(_class, false);
719 }
720
721
722 public int ComputeTypeSize(Type type)
723 {
724    uint size = type ? type.size : 0;
725    if(!size && type && !type.computing)
726    {
727       type.computing = true;
728       switch(type.kind)
729       {
730          case _BoolType: type.alignment = size = sizeof(char); break;   // Assuming 1 byte _Bool
731          case charType: type.alignment = size = sizeof(char); break;
732          case intType: type.alignment = size = sizeof(int); break;
733          case int64Type: type.alignment = size = sizeof(int64); break;
734          case intPtrType: type.alignment = size = targetBits / 8; type.pointerAlignment = true; break;
735          case intSizeType: type.alignment = size = targetBits / 8; type.pointerAlignment = true; break;
736          case longType: type.alignment = size = sizeof(long); break;
737          case shortType: type.alignment = size = sizeof(short); break;
738          case floatType: type.alignment = size = sizeof(float); break;
739          case doubleType: type.alignment = size = sizeof(double); break;
740          case classType:
741          {
742             Class _class = type._class ? type._class.registered : null;
743
744             if(_class && _class.type == structClass)
745             {
746                // Ensure all members are properly registered
747                ComputeClassMembers(_class, false);
748                type.alignment = _class.structAlignment;
749                type.pointerAlignment = (bool)_class.pointerAlignment;
750                size = _class.structSize;
751                if(type.alignment && size % type.alignment)
752                   size += type.alignment - (size % type.alignment);
753
754             }
755             else if(_class && (_class.type == unitClass ||
756                    _class.type == enumClass ||
757                    _class.type == bitClass))
758             {
759                if(!_class.dataType)
760                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
761                size = type.alignment = ComputeTypeSize(_class.dataType);
762             }
763             else
764             {
765                size = type.alignment = targetBits / 8; // sizeof(Instance *);
766                type.pointerAlignment = true;
767             }
768             break;
769          }
770          case pointerType: case subClassType: size = type.alignment = targetBits / 8; /*sizeof(void *); */ type.pointerAlignment = true; break;
771          case arrayType:
772             if(type.arraySizeExp)
773             {
774                ProcessExpressionType(type.arraySizeExp);
775                ComputeExpression(type.arraySizeExp);
776                if(!type.arraySizeExp.isConstant || (type.arraySizeExp.expType.kind != intType &&
777                   type.arraySizeExp.expType.kind != shortType &&
778                   type.arraySizeExp.expType.kind != charType &&
779                   type.arraySizeExp.expType.kind != longType &&
780                   type.arraySizeExp.expType.kind != int64Type &&
781                   type.arraySizeExp.expType.kind != intSizeType &&
782                   type.arraySizeExp.expType.kind != intPtrType &&
783                   type.arraySizeExp.expType.kind != enumType &&
784                   (type.arraySizeExp.expType.kind != classType || !type.arraySizeExp.expType._class.registered || type.arraySizeExp.expType._class.registered.type != enumClass)))
785                {
786                   Location oldLoc = yylloc;
787                   // bool isConstant = type.arraySizeExp.isConstant;
788                   char expression[10240];
789                   expression[0] = '\0';
790                   type.arraySizeExp.expType = null;
791                   yylloc = type.arraySizeExp.loc;
792                   if(inCompiler)
793                      PrintExpression(type.arraySizeExp, expression);
794                   Compiler_Error($"Array size not constant int (%s)\n", expression);
795                   yylloc = oldLoc;
796                }
797                GetInt(type.arraySizeExp, &type.arraySize);
798             }
799             else if(type.enumClass)
800             {
801                if(type.enumClass && type.enumClass.registered && type.enumClass.registered.type == enumClass)
802                {
803                   type.arraySize = (int)eClass_GetProperty(type.enumClass.registered, "enumSize");
804                }
805                else
806                   type.arraySize = 0;
807             }
808             else
809             {
810                // Unimplemented auto size
811                type.arraySize = 0;
812             }
813
814             size = ComputeTypeSize(type.type) * type.arraySize;
815             if(type.type)
816             {
817                type.alignment = type.type.alignment;
818                type.pointerAlignment = type.type.pointerAlignment;
819             }
820
821             break;
822          case structType:
823          {
824             if(!type.members.first && type.enumName)
825             {
826                Symbol symbol = FindStruct(curContext, type.enumName);
827                if(symbol && symbol.type)
828                {
829                   ComputeTypeSize(symbol.type);
830                   size = symbol.type.size;
831                }
832             }
833             else
834             {
835                Type member;
836                for(member = type.members.first; member; member = member.next)
837                {
838                   uint addSize = ComputeTypeSize(member);
839
840                   member.offset = size;
841                   if(member.alignment && size % member.alignment)
842                      member.offset += member.alignment - (size % member.alignment);
843                   size = member.offset;
844
845                   if(member.pointerAlignment && type.size <= 4)
846                      type.pointerAlignment = true;
847                   else if(!member.pointerAlignment && member.alignment >= 8)
848                      type.pointerAlignment = false;
849
850                   type.alignment = Max(type.alignment, member.alignment);
851                   size += addSize;
852                }
853                if(type.alignment && size % type.alignment)
854                   size += type.alignment - (size % type.alignment);
855             }
856             break;
857          }
858          case unionType:
859          {
860             if(!type.members.first && type.enumName)
861             {
862                Symbol symbol = FindStruct(curContext, type.enumName);
863                if(symbol && symbol.type)
864                {
865                   ComputeTypeSize(symbol.type);
866                   size = symbol.type.size;
867                   type.alignment = symbol.type.alignment;
868                }
869             }
870             else
871             {
872                Type member;
873                for(member = type.members.first; member; member = member.next)
874                {
875                   uint addSize = ComputeTypeSize(member);
876
877                   member.offset = size;
878                   if(member.alignment && size % member.alignment)
879                      member.offset += member.alignment - (size % member.alignment);
880                   size = member.offset;
881
882                   if(member.pointerAlignment && type.size <= 4)
883                      type.pointerAlignment = true;
884                   else if(!member.pointerAlignment && member.alignment >= 8)
885                      type.pointerAlignment = false;
886
887                   type.alignment = Max(type.alignment, member.alignment);
888
889                   size = Max(size, addSize);
890                }
891                if(type.alignment && size % type.alignment)
892                   size += type.alignment - (size % type.alignment);
893             }
894             break;
895          }
896          case templateType:
897          {
898             TemplateParameter param = type.templateParameter;
899             Type baseType = ProcessTemplateParameterType(param);
900             if(baseType)
901             {
902                size = ComputeTypeSize(baseType);
903                type.alignment = baseType.alignment;
904                type.pointerAlignment = baseType.pointerAlignment;
905             }
906             else
907                type.alignment = size = sizeof(uint64);
908             break;
909          }
910          case enumType:
911          {
912             type.alignment = size = sizeof(enum { test });
913             break;
914          }
915          case thisClassType:
916          {
917             type.alignment = size = targetBits / 8; //sizeof(void *);
918             type.pointerAlignment = true;
919             break;
920          }
921       }
922       type.size = size;
923       type.computing = false;
924    }
925    return size;
926 }
927
928
929 /*static */int AddMembers(External neededBy, OldList * declarations, Class _class, bool isMember, uint * retSize, Class topClass, bool *addedPadding)
930 {
931    // This function is in need of a major review when implementing private members etc.
932    DataMember topMember = isMember ? (DataMember) _class : null;
933    uint totalSize = 0;
934    uint maxSize = 0;
935    int alignment;
936    uint size;
937    DataMember member;
938    int anonID = 1;
939    Context context = isMember ? null : SetupTemplatesContext(_class);
940    if(addedPadding)
941       *addedPadding = false;
942
943    if(!isMember && _class.base)
944    {
945       maxSize = _class.structSize;
946       //if(_class.base.type != systemClass) // Commented out with new Instance _class
947       {
948          // DANGER: Testing this noHeadClass here...
949          if(_class.type == structClass || _class.type == noHeadClass)
950             /*totalSize = */AddMembers(neededBy, declarations, _class.base, false, &totalSize, topClass, null);
951          else
952          {
953             uint baseSize = _class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize;
954             if(maxSize > baseSize)
955                maxSize -= baseSize;
956             else
957                maxSize = 0;
958          }
959       }
960    }
961
962    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
963    {
964       if(!member.isProperty)
965       {
966          switch(member.type)
967          {
968             case normalMember:
969             {
970                if(member.dataTypeString)
971                {
972                   OldList * specs = MkList(), * decls = MkList();
973                   Declarator decl;
974
975                   decl = SpecDeclFromString(member.dataTypeString, specs,
976                      MkDeclaratorIdentifier(MkIdentifier(member.name)));
977                   ListAdd(decls, MkStructDeclarator(decl, null));
978                   ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, decls, null)));
979
980                   if(!member.dataType)
981                      member.dataType = ProcessType(specs, decl);
982
983                   ReplaceThisClassSpecifiers(specs, topClass /*member._class*/);
984
985                   {
986                      Type type = ProcessType(specs, decl);
987                      DeclareType(neededBy, member.dataType, true, false);
988                      FreeType(type);
989                   }
990                   /*
991                   if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
992                      member.dataType._class.registered && member.dataType._class.registered.type == structClass)
993                      DeclareStruct(member.dataType._class.string, false);
994                   */
995
996                   ComputeTypeSize(member.dataType);
997                   size = member.dataType.size;
998                   alignment = member.dataType.alignment;
999
1000                   if(alignment)
1001                   {
1002                      if(totalSize % alignment)
1003                         totalSize += alignment - (totalSize % alignment);
1004                   }
1005                   totalSize += size;
1006                }
1007                break;
1008             }
1009             case unionMember:
1010             case structMember:
1011             {
1012                OldList * specs = MkList(), * list = MkList();
1013                char id[100];
1014                sprintf(id, "__anon%d", anonID++);
1015
1016                size = 0;
1017                AddMembers(neededBy, list, (Class)member, true, &size, topClass, null);
1018                ListAdd(specs,
1019                   MkStructOrUnion((member.type == unionMember)?unionSpecifier:structSpecifier, null, list));
1020                ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, MkListOne(MkDeclaratorIdentifier(MkIdentifier(id))),null)));
1021                alignment = member.structAlignment;
1022
1023                if(alignment)
1024                {
1025                   if(totalSize % alignment)
1026                      totalSize += alignment - (totalSize % alignment);
1027                }
1028                totalSize += size;
1029                break;
1030             }
1031          }
1032       }
1033    }
1034    if(retSize)
1035    {
1036       if(topMember && topMember.type == unionMember)
1037          *retSize = Max(*retSize, totalSize);
1038       else
1039          *retSize += totalSize;
1040    }
1041    else if(totalSize < maxSize && _class.type != systemClass)
1042    {
1043       int autoPadding = 0;
1044       if(!isMember && _class.structAlignment && totalSize % _class.structAlignment)
1045          autoPadding = _class.structAlignment - (totalSize % _class.structAlignment);
1046       if(totalSize + autoPadding < maxSize)
1047       {
1048          char sizeString[50];
1049          sprintf(sizeString, "%d", maxSize - totalSize);
1050          ListAdd(declarations,
1051             MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(CHAR)),
1052             MkListOne(MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__ecere_padding")), MkExpConstant(sizeString))), null)));
1053          if(addedPadding)
1054             *addedPadding = true;
1055       }
1056    }
1057    if(context)
1058       FinishTemplatesContext(context);
1059    return topMember ? topMember.memberID : _class.memberID;
1060 }
1061
1062 static int DeclareMembers(External neededBy, Class _class, bool isMember)
1063 {
1064    DataMember topMember = isMember ? (DataMember) _class : null;
1065    DataMember member;
1066    Context context = isMember ? null : SetupTemplatesContext(_class);
1067
1068    if(!isMember && (_class.type == structClass || _class.type == noHeadClass) && _class.base.type != systemClass)
1069       DeclareMembers(neededBy, _class.base, false);
1070
1071    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
1072    {
1073       if(!member.isProperty)
1074       {
1075          switch(member.type)
1076          {
1077             case normalMember:
1078             {
1079                if(!member.dataType && member.dataTypeString)
1080                   member.dataType = ProcessTypeString(member.dataTypeString, false);
1081                if(member.dataType)
1082                   DeclareType(neededBy, member.dataType, true, false);
1083                break;
1084             }
1085             case unionMember:
1086             case structMember:
1087             {
1088                DeclareMembers(neededBy, (Class)member, true);
1089                break;
1090             }
1091          }
1092       }
1093    }
1094    if(context)
1095       FinishTemplatesContext(context);
1096
1097    return topMember ? topMember.memberID : _class.memberID;
1098 }
1099
1100 static void IdentifyAnonStructs(OldList/*<ClassDef>*/ *  definitions)
1101 {
1102    ClassDef def;
1103    int anonID = 1;
1104    for(def = definitions->first; def; def = def.next)
1105    {
1106       if(def.type == declarationClassDef)
1107       {
1108          Declaration decl = def.decl;
1109          if(decl && decl.specifiers)
1110          {
1111             Specifier spec;
1112             bool isStruct = false;
1113             for(spec = decl.specifiers->first; spec; spec = spec.next)
1114             {
1115                if(spec.type == structSpecifier || spec.type == unionSpecifier)
1116                {
1117                   if(spec.definitions)
1118                      IdentifyAnonStructs(spec.definitions);
1119                   isStruct = true;
1120                }
1121             }
1122             if(isStruct)
1123             {
1124                Declarator d = null;
1125                if(decl.declarators)
1126                {
1127                   for(d = decl.declarators->first; d; d = d.next)
1128                   {
1129                      Identifier idDecl = GetDeclId(d);
1130                      if(idDecl)
1131                         break;
1132                   }
1133                }
1134                if(!d)
1135                {
1136                   char id[100];
1137                   sprintf(id, "__anon%d", anonID++);
1138                   if(!decl.declarators)
1139                      decl.declarators = MkList();
1140                   ListAdd(decl.declarators, MkDeclaratorIdentifier(MkIdentifier(id)));
1141                }
1142             }
1143          }
1144       }
1145    }
1146 }
1147
1148 External DeclareStruct(External neededBy, const char * name, bool skipNoHead, bool needDereference)
1149 {
1150    return _DeclareStruct(neededBy, name, skipNoHead, needDereference, false);
1151 }
1152
1153 External _DeclareStruct(External neededBy, const char * name, bool skipNoHead, bool needDereference, bool fwdDecl)
1154 {
1155    External external = null;
1156    Symbol classSym = FindClass(name);
1157    OldList * curDeclarations = null;
1158    Specifier curSpec = null;
1159
1160    if(!inCompiler || !classSym) return null;
1161
1162    // We don't need any declaration for bit classes...
1163    if(classSym.registered &&
1164       (classSym.registered.type == bitClass || classSym.registered.type == unitClass || classSym.registered.type == enumClass))
1165       return null;
1166
1167    if(!classSym.registered || (classSym.registered.type == normalClass && classSym.registered.structSize && classSym.registered.base && classSym.registered.base.base))
1168       _DeclareStruct(neededBy, "ecere::com::Instance", false, true, fwdDecl);
1169
1170    external = classSym.structExternal;
1171
1172    if(external && external.declaration)
1173    {
1174       Specifier spec;
1175       for(spec = external.declaration.specifiers ? external.declaration.specifiers->first : null; spec; spec = spec.next)
1176          if(spec.type == structSpecifier || spec.type == unionSpecifier)
1177          {
1178             curSpec = spec;
1179             curDeclarations = spec.definitions;
1180             break;
1181          }
1182    }
1183
1184    if(classSym.registered && !classSym.declaring && classSym.imported && (!classSym.declaredStructSym || (classSym.registered.type == noHeadClass && !skipNoHead && external && !curDeclarations)))
1185    {
1186       OldList * specifiers, * declarators;
1187       OldList * declarations = null;
1188       char structName[1024];
1189       bool addedPadding = false;
1190
1191       classSym.declaring++;
1192
1193       if(strchr(classSym.string, '<'))
1194       {
1195          if(classSym.registered.templateClass)
1196          {
1197             external = _DeclareStruct(neededBy, classSym.registered.templateClass.fullName, skipNoHead, needDereference, fwdDecl);
1198             classSym.declaring--;
1199          }
1200          return external;
1201       }
1202
1203       structName[0] = 0;
1204       FullClassNameCat(structName, name, false);
1205
1206       classSym.declaredStructSym = true;
1207       if(!external || (classSym.registered.type == noHeadClass && !skipNoHead && !curDeclarations))
1208       {
1209          bool add = false;
1210          if(!external)
1211          {
1212             external = MkExternalDeclaration(null);
1213             classSym.structExternal = external;
1214             external.symbol = classSym;
1215
1216             add = true;
1217          }
1218
1219          if(!skipNoHead)
1220          {
1221             declarations = MkList();
1222             AddMembers(external, declarations, classSym.registered, false, null, classSym.registered, &addedPadding);
1223          }
1224
1225          if(declarations && (!declarations->count || (declarations->count == 1 && addedPadding)))
1226          {
1227             FreeList(declarations, FreeClassDef);
1228             declarations = null;
1229          }
1230
1231          if(classSym.registered.type != noHeadClass && !declarations)
1232          {
1233             FreeExternal(external);
1234             external = null;
1235             classSym.structExternal = null;
1236          }
1237          else
1238          {
1239             if(curSpec)
1240                curSpec.definitions = declarations;
1241             else
1242             {
1243                specifiers = MkList();
1244                declarators = MkList();
1245                ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), declarations));
1246                external.declaration = MkDeclaration(specifiers, declarators);
1247             }
1248             if(add)
1249                ast->Add(external);
1250          }
1251       }
1252       classSym.declaring--;
1253    }
1254    else if(!classSym.declaredStructSym && classSym.structExternal)
1255    {
1256       classSym.declaredStructSym = true;
1257
1258       if(classSym.registered)
1259          DeclareMembers(classSym.structExternal, classSym.registered, false);
1260
1261       if(classSym.structExternal.declaration && classSym.structExternal.declaration.specifiers)
1262       {
1263          Specifier spec;
1264          for(spec = classSym.structExternal.declaration.specifiers->first; spec; spec = spec.next)
1265          {
1266             if(spec.definitions)
1267                IdentifyAnonStructs(spec.definitions);
1268          }
1269       }
1270    }
1271    if(inCompiler && neededBy && (external || !classSym.imported))
1272    {
1273       if(!external)
1274       {
1275          classSym.structExternal = external = MkExternalDeclaration(null);
1276          external.symbol = classSym;
1277          ast->Add(external);
1278       }
1279       if(reachedPass15 && !external.declaration && classSym.registered && classSym.registered.type == noHeadClass)
1280       {
1281          // Declare nohead classes without definitions here (e.g. IteratorPointer)
1282          char structName[1024];
1283          OldList * specifiers, * declarators;
1284          structName[0] = 0;
1285          FullClassNameCat(structName, name, false);
1286          specifiers = MkList();
1287          declarators = MkList();
1288          ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), null));
1289          external.declaration = MkDeclaration(specifiers, declarators);
1290       }
1291       if(fwdDecl)
1292       {
1293          External e = external.fwdDecl ? external.fwdDecl : external;
1294          if(e.incoming.count)
1295             neededBy.CreateUniqueEdge(e, !needDereference && !external.fwdDecl);
1296       }
1297       else
1298          neededBy.CreateUniqueEdge(external, !needDereference);
1299    }
1300    return external;
1301 }
1302
1303 void DeclareProperty(External neededBy, Property prop, char * setName, char * getName)
1304 {
1305    Symbol symbol = prop.symbol;
1306    bool imported = false;
1307    bool dllImport = false;
1308    External structExternal = null;
1309    External instExternal = null;
1310
1311    strcpy(setName, "__ecereProp_");
1312    FullClassNameCat(setName, prop._class.fullName, false);
1313    strcat(setName, "_Set_");
1314    FullClassNameCat(setName, prop.name, true);
1315
1316    strcpy(getName, "__ecereProp_");
1317    FullClassNameCat(getName, prop._class.fullName, false);
1318    strcat(getName, "_Get_");
1319    FullClassNameCat(getName, prop.name, true);
1320
1321    if(!symbol || symbol._import)
1322    {
1323       if(!symbol)
1324       {
1325          Symbol classSym;
1326
1327          if(!prop._class.symbol)
1328             prop._class.symbol = FindClass(prop._class.fullName);
1329          classSym = prop._class.symbol;
1330          if(classSym && !classSym._import)
1331          {
1332             ModuleImport module;
1333
1334             if(prop._class.module)
1335                module = FindModule(prop._class.module);
1336             else
1337                module = mainModule;
1338
1339             classSym._import = ClassImport
1340             {
1341                name = CopyString(prop._class.fullName);
1342                isRemote = prop._class.isRemote;
1343             };
1344             module.classes.Add(classSym._import);
1345          }
1346          symbol = prop.symbol = Symbol { };
1347          symbol._import = (ClassImport)PropertyImport
1348          {
1349             name = CopyString(prop.name);
1350             isVirtual = false; //prop.isVirtual;
1351             hasSet = prop.Set ? true : false;
1352             hasGet = prop.Get ? true : false;
1353          };
1354          if(classSym)
1355             classSym._import.properties.Add(symbol._import);
1356       }
1357       imported = true;
1358       // Ugly work around for isNan properties declared within float/double classes which are initialized with ecereCOM
1359       if((prop._class.module != privateModule || !strcmp(prop._class.name, "float") || !strcmp(prop._class.name, "double")) &&
1360          prop._class.module.importType != staticImport)
1361          dllImport = true;
1362    }
1363
1364    if(!symbol.type)
1365    {
1366       Context context = SetupTemplatesContext(prop._class);
1367       symbol.type = ProcessTypeString(prop.dataTypeString, false);
1368       FinishTemplatesContext(context);
1369    }
1370
1371    if((prop.Get && !symbol.externalGet) || (prop.Set && !symbol.externalSet))
1372    {
1373       if(prop._class.type == normalClass && prop._class.structSize)
1374          instExternal = DeclareStruct(null, "ecere::com::Instance", false, true);
1375       structExternal = DeclareStruct(null, prop._class.fullName, prop._class.type != structClass /*true*/, false);
1376    }
1377
1378    // Get
1379    if(prop.Get && !symbol.externalGet)
1380    {
1381       Declaration decl;
1382       OldList * specifiers, * declarators;
1383       Declarator d;
1384       OldList * params;
1385       Specifier spec = null;
1386       External external;
1387       Declarator typeDecl;
1388       bool simple = false;
1389       bool needReference;
1390
1391       specifiers = MkList();
1392       declarators = MkList();
1393       params = MkList();
1394
1395       ListAdd(params, MkTypeName(MkListOne(MkSpecifierName(prop._class.fullName)),
1396          MkDeclaratorIdentifier(MkIdentifier("this"))));
1397
1398       d = MkDeclaratorIdentifier(MkIdentifier(getName));
1399       //if(imported)
1400       if(dllImport)
1401          d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1402
1403       {
1404          Context context = SetupTemplatesContext(prop._class);
1405          typeDecl = SpecDeclFromString(prop.dataTypeString, specifiers, null);
1406          FinishTemplatesContext(context);
1407       }
1408
1409       // Make sure the simple _class's type is declared
1410       needReference = !typeDecl || typeDecl.type == identifierDeclarator;
1411       for(spec = specifiers->first; spec; spec = spec.next)
1412       {
1413          if(spec.type == nameSpecifier)
1414          {
1415             Symbol classSym = spec.symbol;
1416             if(needReference)
1417             {
1418                symbol._class = classSym.registered;
1419                if(classSym.registered && classSym.registered.type == structClass)
1420                   simple = true;
1421             }
1422             break;
1423          }
1424       }
1425
1426       if(!simple)
1427          d = PlugDeclarator(typeDecl, d);
1428       else
1429       {
1430          ListAdd(params, MkTypeName(specifiers,
1431             PlugDeclarator(typeDecl, MkDeclaratorIdentifier(MkIdentifier("value")))));
1432          specifiers = MkList();
1433       }
1434
1435       d = MkDeclaratorFunction(d, params);
1436
1437       //if(imported)
1438       if(dllImport)
1439          specifiers->Insert(null, MkSpecifier(EXTERN));
1440       else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1441          specifiers->Insert(null, MkSpecifier(STATIC));
1442       if(simple)
1443          ListAdd(specifiers, MkSpecifier(VOID));
1444
1445       ListAdd(declarators, MkInitDeclarator(d, null));
1446
1447       decl = MkDeclaration(specifiers, declarators);
1448
1449       external = MkExternalDeclaration(decl);
1450
1451       if(structExternal)
1452          external.CreateEdge(structExternal, false);
1453       if(instExternal)
1454          external.CreateEdge(instExternal, false);
1455
1456       if(spec)
1457          DeclareStruct(external, spec.name, false, needReference);
1458
1459       ast->Add(external);
1460       external.symbol = symbol;
1461       symbol.externalGet = external;
1462
1463       ReplaceThisClassSpecifiers(specifiers, prop._class);
1464
1465       if(typeDecl)
1466          FreeDeclarator(typeDecl);
1467    }
1468
1469    // Set
1470    if(prop.Set && !symbol.externalSet)
1471    {
1472       Declaration decl;
1473       OldList * specifiers, * declarators;
1474       Declarator d;
1475       OldList * params;
1476       Specifier spec = null;
1477       External external;
1478       Declarator typeDecl;
1479       bool needReference;
1480
1481       declarators = MkList();
1482       params = MkList();
1483
1484       if(!prop.conversion || prop._class.type == structClass)
1485       {
1486          ListAdd(params, MkTypeName(MkListOne(MkSpecifierName(prop._class.fullName)),
1487             MkDeclaratorIdentifier(MkIdentifier("this"))));
1488       }
1489
1490       specifiers = MkList();
1491
1492       {
1493          Context context = SetupTemplatesContext(prop._class);
1494          typeDecl = d = SpecDeclFromString(prop.dataTypeString, specifiers,
1495             MkDeclaratorIdentifier(MkIdentifier("value")));
1496          FinishTemplatesContext(context);
1497       }
1498       if(!strcmp(prop._class.base.fullName, "eda::Row") || !strcmp(prop._class.base.fullName, "eda::Id"))
1499          specifiers->Insert(null, MkSpecifier(CONST));
1500
1501       ListAdd(params, MkTypeName(specifiers, d));
1502
1503       d = MkDeclaratorIdentifier(MkIdentifier(setName));
1504       if(dllImport)
1505          d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1506       d = MkDeclaratorFunction(d, params);
1507
1508       // Make sure the simple _class's type is declared
1509       needReference = !typeDecl || typeDecl.type == identifierDeclarator;
1510       for(spec = specifiers->first; spec; spec = spec.next)
1511       {
1512          if(spec.type == nameSpecifier)
1513          {
1514             Symbol classSym = spec.symbol;
1515             if(needReference)
1516                symbol._class = classSym.registered;
1517             break;
1518          }
1519       }
1520
1521       ListAdd(declarators, MkInitDeclarator(d, null));
1522
1523       specifiers = MkList();
1524       if(dllImport)
1525          specifiers->Insert(null, MkSpecifier(EXTERN));
1526       else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1527          specifiers->Insert(null, MkSpecifier(STATIC));
1528
1529       if(!prop.conversion || prop._class.type == structClass)
1530          ListAdd(specifiers, MkSpecifier(VOID));
1531       else
1532          ListAdd(specifiers, MkSpecifierName(prop._class.fullName));
1533
1534       decl = MkDeclaration(specifiers, declarators);
1535
1536       external = MkExternalDeclaration(decl);
1537
1538       if(structExternal)
1539          external.CreateEdge(structExternal, false);
1540       if(instExternal)
1541          external.CreateEdge(instExternal, false);
1542
1543       if(spec)
1544          DeclareStruct(external, spec.name, false, needReference);
1545
1546       ast->Add(external);
1547       external.symbol = symbol;
1548       symbol.externalSet = external;
1549
1550       ReplaceThisClassSpecifiers(specifiers, prop._class);
1551    }
1552
1553    // Property (for Watchers)
1554    if(!symbol.externalPtr)
1555    {
1556       Declaration decl;
1557       External external;
1558       OldList * specifiers = MkList();
1559       char propName[1024];
1560
1561       if(imported)
1562          specifiers->Insert(null, MkSpecifier(EXTERN));
1563       else
1564       {
1565          specifiers->Insert(null, MkSpecifier(STATIC));
1566          specifiers->Add(MkSpecifierExtended(MkExtDeclAttrib(MkAttrib(ATTRIB, MkListOne(MkAttribute(CopyString("unused"), null))))));
1567       }
1568
1569       ListAdd(specifiers, MkSpecifierName("Property"));
1570
1571       strcpy(propName, "__ecereProp_");
1572       FullClassNameCat(propName, prop._class.fullName, false);
1573       strcat(propName, "_");
1574       FullClassNameCat(propName, prop.name, true);
1575
1576       {
1577          OldList * list = MkList();
1578          ListAdd(list, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(propName)), null));
1579
1580          if(!imported)
1581          {
1582             strcpy(propName, "__ecerePropM_");
1583             FullClassNameCat(propName, prop._class.fullName, false);
1584             strcat(propName, "_");
1585             FullClassNameCat(propName, prop.name, true);
1586
1587             ListAdd(list, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(propName)), null));
1588          }
1589          decl = MkDeclaration(specifiers, list);
1590       }
1591
1592       external = MkExternalDeclaration(decl);
1593       ast->Insert(curExternal.prev, external);
1594       external.symbol = symbol;
1595       symbol.externalPtr = external;
1596    }
1597
1598    if(inCompiler && neededBy)
1599    {
1600       // Could improve this to create edge on only what is needed...
1601       if(symbol.externalPtr)
1602          neededBy.CreateUniqueEdge(symbol.externalPtr, false);
1603
1604       if(symbol.externalGet)
1605          neededBy.CreateUniqueEdge(symbol.externalGet, symbol.externalGet.type == functionExternal);
1606
1607       if(symbol.externalSet)
1608          neededBy.CreateUniqueEdge(symbol.externalSet, symbol.externalSet.type == functionExternal);
1609
1610       // IsSet ?
1611    }
1612 }
1613
1614 // ***************** EXPRESSION PROCESSING ***************************
1615 public Type Dereference(Type source)
1616 {
1617    Type type = null;
1618    if(source)
1619    {
1620       if(source.kind == pointerType || source.kind == arrayType)
1621       {
1622          type = source.type;
1623          source.type.refCount++;
1624       }
1625       else if(source.kind == classType && !strcmp(source._class.string, "String"))
1626       {
1627          type = Type
1628          {
1629             kind = charType;
1630             refCount = 1;
1631          };
1632       }
1633       // Support dereferencing of no head classes for now...
1634       else if(source.kind == classType && source._class && source._class.registered && source._class.registered.type == noHeadClass)
1635       {
1636          type = source;
1637          source.refCount++;
1638       }
1639       else
1640          Compiler_Error($"cannot dereference type\n");
1641    }
1642    return type;
1643 }
1644
1645 static Type Reference(Type source)
1646 {
1647    Type type = null;
1648    if(source)
1649    {
1650       type = Type
1651       {
1652          kind = pointerType;
1653          type = source;
1654          refCount = 1;
1655       };
1656       source.refCount++;
1657    }
1658    return type;
1659 }
1660
1661 void ProcessMemberInitData(MemberInit member, Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
1662 {
1663    Identifier ident = member.identifiers ? member.identifiers->first : null;
1664    bool found = false;
1665    DataMember dataMember = null;
1666    Method method = null;
1667    bool freeType = false;
1668
1669    yylloc = member.loc;
1670
1671    if(!ident)
1672    {
1673       if(curMember)
1674       {
1675          eClass_FindNextMember(_class, curClass, curMember, subMemberStack, subMemberStackPos);
1676          if(*curMember)
1677          {
1678             found = true;
1679             dataMember = *curMember;
1680          }
1681       }
1682    }
1683    else
1684    {
1685       DataMember thisMember = (DataMember)eClass_FindProperty(_class, ident.string, privateModule);
1686       DataMember _subMemberStack[256];
1687       int _subMemberStackPos = 0;
1688
1689       // FILL MEMBER STACK
1690       if(!thisMember)
1691          thisMember = eClass_FindDataMember(_class, ident.string, privateModule, _subMemberStack, &_subMemberStackPos);
1692       if(thisMember)
1693       {
1694          dataMember = thisMember;
1695          if(curMember && thisMember.memberAccess == publicAccess)
1696          {
1697             *curMember = thisMember;
1698             *curClass = thisMember._class;
1699             memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
1700             *subMemberStackPos = _subMemberStackPos;
1701          }
1702          found = true;
1703       }
1704       else
1705       {
1706          // Setting a method
1707          method = eClass_FindMethod(_class, ident.string, privateModule);
1708          if(method && method.type == virtualMethod)
1709             found = true;
1710          else
1711             method = null;
1712       }
1713    }
1714
1715    if(found)
1716    {
1717       Type type = null;
1718       if(dataMember)
1719       {
1720          if(!dataMember.dataType && dataMember.dataTypeString)
1721          {
1722             //Context context = SetupTemplatesContext(dataMember._class);
1723             Context context = SetupTemplatesContext(_class);
1724             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
1725             FinishTemplatesContext(context);
1726          }
1727          type = dataMember.dataType;
1728       }
1729       else if(method)
1730       {
1731          // This is for destination type...
1732          if(!method.dataType)
1733             ProcessMethodType(method);
1734          //DeclareMethod(method);
1735          // method.dataType = ((Symbol)method.symbol)->type;
1736          type = method.dataType;
1737       }
1738
1739       if(ident && ident.next)
1740       {
1741          for(ident = ident.next; ident && type; ident = ident.next)
1742          {
1743             if(type.kind == classType)
1744             {
1745                dataMember = (DataMember)eClass_FindProperty(type._class.registered, ident.string, privateModule);
1746                if(!dataMember)
1747                   dataMember = eClass_FindDataMember(type._class.registered, ident.string, privateModule, null, null);
1748                if(dataMember)
1749                   type = dataMember.dataType;
1750             }
1751             else if(type.kind == structType || type.kind == unionType)
1752             {
1753                Type memberType;
1754                for(memberType = type.members.first; memberType; memberType = memberType.next)
1755                {
1756                   if(!strcmp(memberType.name, ident.string))
1757                   {
1758                      type = memberType;
1759                      break;
1760                   }
1761                }
1762             }
1763          }
1764       }
1765
1766       // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
1767       if(type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type && _class.templateArgs /* TODO: Watch out for these _class.templateClass*/)
1768       {
1769          int id = 0;
1770          ClassTemplateParameter curParam = null;
1771          Class sClass;
1772          for(sClass = _class; sClass; sClass = sClass.base)
1773          {
1774             id = 0;
1775             if(sClass.templateClass) sClass = sClass.templateClass;
1776             for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
1777             {
1778                if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
1779                {
1780                   for(sClass = sClass.base; sClass; sClass = sClass.base)
1781                   {
1782                      if(sClass.templateClass) sClass = sClass.templateClass;
1783                      id += sClass.templateParams.count;
1784                   }
1785                   break;
1786                }
1787                id++;
1788             }
1789             if(curParam) break;
1790          }
1791
1792          if(curParam)
1793          {
1794             ClassTemplateArgument arg = _class.templateArgs[id];
1795             if(arg.dataTypeString)
1796             {
1797                bool constant = type.constant;
1798                // FreeType(type);
1799                type = ProcessTypeString(arg.dataTypeString, false);
1800                if(type.kind == classType && constant) type.constant = true;
1801                else if(type.kind == pointerType)
1802                {
1803                   Type t = type.type;
1804                   while(t.kind == pointerType) t = t.type;
1805                   if(constant) t.constant = constant;
1806                }
1807                freeType = true;
1808                if(type && _class.templateClass)
1809                   type.passAsTemplate = true;
1810                if(type)
1811                {
1812                   // type.refCount++;
1813                   /*if(!exp.destType)
1814                   {
1815                      exp.destType = ProcessTypeString(arg.dataTypeString, false);
1816                      exp.destType.refCount++;
1817                   }*/
1818                }
1819             }
1820          }
1821       }
1822       if(type && type.kind == classType && type._class && type._class.registered && strchr(type._class.registered.fullName, '<'))
1823       {
1824          Class expClass = type._class.registered;
1825          Class cClass = null;
1826          int paramCount = 0;
1827          int lastParam = -1;
1828
1829          char templateString[1024];
1830          ClassTemplateParameter param;
1831          sprintf(templateString, "%s<", expClass.templateClass.fullName);
1832          for(cClass = expClass; cClass; cClass = cClass.base)
1833          {
1834             int p = 0;
1835             if(cClass.templateClass) cClass = cClass.templateClass;
1836             for(param = cClass.templateParams.first; param; param = param.next)
1837             {
1838                int id = p;
1839                Class sClass;
1840                ClassTemplateArgument arg;
1841                for(sClass = cClass.base; sClass; sClass = sClass.base)
1842                {
1843                   if(sClass.templateClass) sClass = sClass.templateClass;
1844                   id += sClass.templateParams.count;
1845                }
1846                arg = expClass.templateArgs[id];
1847
1848                for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
1849                {
1850                   ClassTemplateParameter cParam;
1851                   //int p = numParams - sClass.templateParams.count;
1852                   int p = 0;
1853                   Class nextClass;
1854                   if(sClass.templateClass) sClass = sClass.templateClass;
1855
1856                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
1857                   {
1858                      if(nextClass.templateClass) nextClass = nextClass.templateClass;
1859                      p += nextClass.templateParams.count;
1860                   }
1861
1862                   for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
1863                   {
1864                      if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
1865                      {
1866                         if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1867                         {
1868                            arg.dataTypeString = _class.templateArgs[p].dataTypeString;
1869                            arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
1870                            break;
1871                         }
1872                      }
1873                   }
1874                }
1875
1876                {
1877                   char argument[256];
1878                   argument[0] = '\0';
1879                   /*if(arg.name)
1880                   {
1881                      strcat(argument, arg.name.string);
1882                      strcat(argument, " = ");
1883                   }*/
1884                   switch(param.type)
1885                   {
1886                      case expression:
1887                      {
1888                         // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
1889                         char expString[1024];
1890                         OldList * specs = MkList();
1891                         Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
1892                         Expression exp;
1893                         char * string = PrintHexUInt64(arg.expression.ui64);
1894                         exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
1895                         delete string;
1896
1897                         ProcessExpressionType(exp);
1898                         ComputeExpression(exp);
1899                         expString[0] = '\0';
1900                         PrintExpression(exp, expString);
1901                         strcat(argument, expString);
1902                         //delete exp;
1903                         FreeExpression(exp);
1904                         break;
1905                      }
1906                      case identifier:
1907                      {
1908                         strcat(argument, arg.member.name);
1909                         break;
1910                      }
1911                      case TemplateParameterType::type:
1912                      {
1913                         if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1914                            strcat(argument, arg.dataTypeString);
1915                         break;
1916                      }
1917                   }
1918                   if(argument[0])
1919                   {
1920                      if(paramCount) strcat(templateString, ", ");
1921                      if(lastParam != p - 1)
1922                      {
1923                         strcat(templateString, param.name);
1924                         strcat(templateString, " = ");
1925                      }
1926                      strcat(templateString, argument);
1927                      paramCount++;
1928                      lastParam = p;
1929                   }
1930                   p++;
1931                }
1932             }
1933          }
1934          {
1935             int len = strlen(templateString);
1936             if(templateString[len-1] == '<')
1937                len--;
1938             else
1939             {
1940                if(templateString[len-1] == '>')
1941                   templateString[len++] = ' ';
1942                templateString[len++] = '>';
1943             }
1944             templateString[len++] = '\0';
1945          }
1946          {
1947             Context context = SetupTemplatesContext(_class);
1948             if(freeType) FreeType(type);
1949             type = ProcessTypeString(templateString, false);
1950             freeType = true;
1951             FinishTemplatesContext(context);
1952          }
1953       }
1954
1955       if(method && member.initializer && member.initializer.type == expInitializer && member.initializer.exp)
1956       {
1957          ProcessExpressionType(member.initializer.exp);
1958          if(!member.initializer.exp.expType)
1959          {
1960             if(inCompiler)
1961             {
1962                char expString[10240];
1963                expString[0] = '\0';
1964                PrintExpression(member.initializer.exp, expString);
1965                ChangeCh(expString, '\n', ' ');
1966                Compiler_Error($"unresolved symbol used as an instance method %s\n", expString);
1967             }
1968          }
1969          //else if(!MatchTypes(member.exp.expType, type, null, _class, null, true, true, false, false))
1970          else if(!MatchTypes(member.initializer.exp.expType, type, null, null, _class, true, true, false, false, true))
1971          {
1972             Compiler_Error($"incompatible instance method %s\n", ident.string);
1973          }
1974       }
1975       else if(member.initializer)
1976       {
1977          /*
1978          FreeType(member.exp.destType);
1979          member.exp.destType = type;
1980          if(member.exp.destType)
1981             member.exp.destType.refCount++;
1982          ProcessExpressionType(member.exp);
1983          */
1984
1985          ProcessInitializer(member.initializer, type);
1986       }
1987       if(freeType) FreeType(type);
1988    }
1989    else
1990    {
1991       if(_class && _class.type == unitClass)
1992       {
1993          if(member.initializer)
1994          {
1995             /*
1996             FreeType(member.exp.destType);
1997             member.exp.destType = MkClassType(_class.fullName);
1998             ProcessExpressionType(member.initializer, type);
1999             */
2000             Type type = MkClassType(_class.fullName);
2001             ProcessInitializer(member.initializer, type);
2002             FreeType(type);
2003          }
2004       }
2005       else
2006       {
2007          if(member.initializer)
2008          {
2009             //ProcessExpressionType(member.exp);
2010             ProcessInitializer(member.initializer, null);
2011          }
2012          if(ident)
2013          {
2014             if(method)
2015             {
2016                Compiler_Error($"couldn't find virtual method %s in class %s\n", ident.string, _class.fullName);
2017             }
2018             else if(_class)
2019             {
2020                Compiler_Error($"couldn't find member %s in class %s\n", ident.string, _class.fullName);
2021                if(inCompiler)
2022                   eClass_AddDataMember(_class, ident.string, "int", 0, 0, publicAccess);
2023             }
2024          }
2025          else if(_class)
2026             Compiler_Error($"too many initializers for instantiation of class %s\n", _class.fullName);
2027       }
2028    }
2029 }
2030
2031 void ProcessInstantiationType(Instantiation inst)
2032 {
2033    yylloc = inst.loc;
2034    if(inst._class)
2035    {
2036       MembersInit members;
2037       Symbol classSym;
2038       Class _class;
2039
2040       classSym = inst._class.symbol;
2041       _class = classSym ? classSym.registered : null;
2042
2043       if(!_class || _class.type != noHeadClass)
2044          DeclareStruct(curExternal, inst._class.name, false, true);
2045
2046       afterExternal = afterExternal ? afterExternal : curExternal;
2047
2048       if(inst.exp)
2049          ProcessExpressionType(inst.exp);
2050
2051       inst.isConstant = true;
2052       if(inst.members)
2053       {
2054          DataMember curMember = null;
2055          Class curClass = null;
2056          DataMember subMemberStack[256];
2057          int subMemberStackPos = 0;
2058
2059          for(members = inst.members->first; members; members = members.next)
2060          {
2061             switch(members.type)
2062             {
2063                case methodMembersInit:
2064                {
2065                   char name[1024];
2066                   static uint instMethodID = 0;
2067                   External external = curExternal;
2068                   Context context = curContext;
2069                   Declarator declarator = members.function.declarator;
2070                   Identifier nameID = GetDeclId(declarator);
2071                   char * unmangled = nameID ? nameID.string : null;
2072                   Expression exp;
2073                   External createdExternal = null;
2074
2075                   if(inCompiler)
2076                   {
2077                      char number[16];
2078                      strcpy(name, "__ecereInstMeth_");
2079                      FullClassNameCat(name, _class ? _class.fullName : "_UNKNOWNCLASS", false);
2080                      strcat(name, "_");
2081                      strcat(name, nameID.string);
2082                      strcat(name, "_");
2083                      sprintf(number, "_%08d", instMethodID++);
2084                      strcat(name, number);
2085                      nameID.string = CopyString(name);
2086                   }
2087
2088                   // Do modifications here...
2089                   if(declarator)
2090                   {
2091                      Symbol symbol = declarator.symbol;
2092                      Method method = eClass_FindMethod(_class, unmangled, privateModule);
2093
2094                      if(method && method.type == virtualMethod)
2095                      {
2096                         symbol.method = method;
2097                         ProcessMethodType(method);
2098
2099                         if(!symbol.type.thisClass)
2100                         {
2101                            if(method.dataType.thisClass && currentClass &&
2102                               eClass_IsDerived(currentClass, method.dataType.thisClass.registered))
2103                            {
2104                               if(!currentClass.symbol)
2105                                  currentClass.symbol = FindClass(currentClass.fullName);
2106                               symbol.type.thisClass = currentClass.symbol;
2107                            }
2108                            else
2109                            {
2110                               if(!_class.symbol)
2111                                  _class.symbol = FindClass(_class.fullName);
2112                               symbol.type.thisClass = _class.symbol;
2113                            }
2114                         }
2115                         DeclareType(curExternal, symbol.type, true, true);
2116
2117                      }
2118                      else if(classSym)
2119                      {
2120                         Compiler_Error($"couldn't find virtual method %s in class %s\n",
2121                            unmangled, classSym.string);
2122                      }
2123                   }
2124
2125                   createdExternal = ProcessClassFunction(classSym ? classSym.registered : null, members.function, ast, afterExternal, true);
2126
2127                   if(nameID)
2128                   {
2129                      FreeSpecifier(nameID._class);
2130                      nameID._class = null;
2131                   }
2132
2133                   curExternal = createdExternal;
2134                   if(inCompiler)
2135                   {
2136                      if(createdExternal.function)
2137                         ProcessFunction(createdExternal.function);
2138                   }
2139                   else if(declarator)
2140                   {
2141                      curExternal = declarator.symbol.pointerExternal;
2142                      ProcessFunction((FunctionDefinition)members.function);
2143                   }
2144                   curExternal = external;
2145                   curContext = context;
2146
2147                   if(inCompiler)
2148                   {
2149                      FreeClassFunction(members.function);
2150
2151                      // In this pass, turn this into a MemberInitData
2152                      exp = QMkExpId(name);
2153                      members.type = dataMembersInit;
2154                      members.dataMembers = MkListOne(MkMemberInit(MkListOne(MkIdentifier(unmangled)), MkInitializerAssignment(exp)));
2155
2156                      delete unmangled;
2157                   }
2158                   break;
2159                }
2160                case dataMembersInit:
2161                {
2162                   if(members.dataMembers && classSym)
2163                   {
2164                      MemberInit member;
2165                      Location oldyyloc = yylloc;
2166                      for(member = members.dataMembers->first; member; member = member.next)
2167                      {
2168                         ProcessMemberInitData(member, classSym.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
2169                         if(member.initializer && !member.initializer.isConstant)
2170                            inst.isConstant = false;
2171                      }
2172                      yylloc = oldyyloc;
2173                   }
2174                   break;
2175                }
2176             }
2177          }
2178       }
2179    }
2180 }
2181
2182 void DeclareType(External neededFor, Type type, bool needDereference, bool forFunctionDef)
2183 {
2184    _DeclareType(neededFor, type, needDereference, forFunctionDef, false);
2185 }
2186
2187 void DeclareTypeForwardDeclare(External neededFor, Type type, bool needDereference, bool forFunctionDef)
2188 {
2189    _DeclareType(neededFor, type, needDereference, forFunctionDef, true);
2190 }
2191
2192 static void _DeclareType(External neededFor, Type type, bool needDereference, bool forFunctionDef, bool fwdDecl)
2193 {
2194    if(inCompiler)
2195    {
2196       if(type.kind == functionType)
2197       {
2198          Type param;
2199          for(param = type.params.first; param; param = param.next)
2200             _DeclareType(neededFor, param, forFunctionDef, false, fwdDecl);
2201          _DeclareType(neededFor, type.returnType, forFunctionDef, false, fwdDecl);
2202       }
2203       else if(type.kind == pointerType)
2204          _DeclareType(neededFor, type.type, false, false, fwdDecl);
2205       else if(type.kind == classType)
2206       {
2207          Class c = type._class.registered;
2208          _DeclareStruct(neededFor, c ? c.fullName : "ecere::com::Instance", c ? c.type == noHeadClass : false, needDereference && c && c.type == structClass, fwdDecl);
2209       }
2210       else if(type.kind == structType || type.kind == unionType)
2211       {
2212          Type member;
2213          for(member = type.members.first; member; member = member.next)
2214             _DeclareType(neededFor, member, needDereference, forFunctionDef, fwdDecl);
2215       }
2216       else if(type.kind == arrayType)
2217          _DeclareType(neededFor, type.arrayType, true, false, fwdDecl);
2218    }
2219 }
2220
2221 ClassTemplateArgument * FindTemplateArg(Class _class, TemplateParameter param)
2222 {
2223    ClassTemplateArgument * arg = null;
2224    int id = 0;
2225    ClassTemplateParameter curParam = null;
2226    Class sClass;
2227    for(sClass = _class; sClass; sClass = sClass.base)
2228    {
2229       id = 0;
2230       if(sClass.templateClass) sClass = sClass.templateClass;
2231       for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
2232       {
2233          if(curParam.type == TemplateParameterType::type && !strcmp(param.identifier.string, curParam.name))
2234          {
2235             for(sClass = sClass.base; sClass; sClass = sClass.base)
2236             {
2237                if(sClass.templateClass) sClass = sClass.templateClass;
2238                id += sClass.templateParams.count;
2239             }
2240             break;
2241          }
2242          id++;
2243       }
2244       if(curParam) break;
2245    }
2246    if(curParam)
2247    {
2248       arg = &_class.templateArgs[id];
2249       if(arg && param.type == type)
2250          arg->dataTypeClass = eSystem_FindClass(_class.module, arg->dataTypeString);
2251    }
2252    return arg;
2253 }
2254
2255 public Context SetupTemplatesContext(Class _class)
2256 {
2257    Context context = PushContext();
2258    context.templateTypesOnly = true;
2259    if(_class.symbol && ((Symbol)_class.symbol).templateParams)
2260    {
2261       TemplateParameter param = ((Symbol)_class.symbol).templateParams->first;
2262       for(; param; param = param.next)
2263       {
2264          if(param.type == type && param.identifier)
2265          {
2266             TemplatedType type { key = (uintptr)param.identifier.string, param = param };
2267             curContext.templateTypes.Add((BTNode)type);
2268          }
2269       }
2270    }
2271    else if(_class)
2272    {
2273       Class sClass;
2274       for(sClass = _class; sClass; sClass = sClass.base)
2275       {
2276          ClassTemplateParameter p;
2277          for(p = sClass.templateParams.first; p; p = p.next)
2278          {
2279             //OldList * specs = MkList();
2280             //Declarator decl = null;
2281             //decl = SpecDeclFromString(p.dataTypeString, specs, null);
2282             if(p.type == type)
2283             {
2284                TemplateParameter param = p.param;
2285                TemplatedType type;
2286                if(!param)
2287                {
2288                   // ADD DATA TYPE HERE...
2289                   p.param = param = TemplateParameter
2290                   {
2291                      identifier = MkIdentifier(p.name), type = p.type,
2292                      dataTypeString = p.dataTypeString /*, dataType = { specs, decl }*/
2293                   };
2294                }
2295                type = TemplatedType { key = (uintptr)p.name, param = param };
2296                curContext.templateTypes.Add((BTNode)type);
2297             }
2298          }
2299       }
2300    }
2301    return context;
2302 }
2303
2304 public void FinishTemplatesContext(Context context)
2305 {
2306    PopContext(context);
2307    FreeContext(context);
2308    delete context;
2309 }
2310
2311 public void ProcessMethodType(Method method)
2312 {
2313    if(!method.dataType)
2314    {
2315       Context context = SetupTemplatesContext(method._class);
2316
2317       method.dataType = ProcessTypeString(method.dataTypeString, false);
2318
2319       FinishTemplatesContext(context);
2320
2321       if(method.type != virtualMethod && method.dataType)
2322       {
2323          if(!method.dataType.thisClass && !method.dataType.staticMethod)
2324          {
2325             if(!method._class.symbol)
2326                method._class.symbol = FindClass(method._class.fullName);
2327             method.dataType.thisClass = method._class.symbol;
2328          }
2329       }
2330
2331       // Why was this commented out? Working fine without now...
2332
2333       /*
2334       if(method.dataType.kind == functionType && !method.dataType.staticMethod && !method.dataType.thisClass)
2335          method.dataType.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2336          */
2337    }
2338
2339    /*
2340    if(type)
2341    {
2342       char * par = strstr(type, "(");
2343       char * classOp = null;
2344       int classOpLen = 0;
2345       if(par)
2346       {
2347          int c;
2348          for(c = par-type-1; c >= 0; c++)
2349          {
2350             if(type[c] == ':' && type[c+1] == ':')
2351             {
2352                classOp = type + c - 1;
2353                for(c = c-1; c >=0 && !isspace(type[c]); c--)
2354                {
2355                   classOp--;
2356                   classOpLen++;
2357                }
2358                break;
2359             }
2360             else if(!isspace(type[c]))
2361                break;
2362          }
2363       }
2364       if(classOp)
2365       {
2366          char temp[1024];
2367          int typeLen = strlen(type);
2368          memcpy(temp, classOp, classOpLen);
2369          temp[classOpLen] = '\0';
2370          if(temp[0])
2371             _class = eSystem_FindClass(module, temp);
2372          else
2373             _class = null;
2374          method.dataTypeString = new char[typeLen - classOpLen + 1];
2375          memcpy(method.dataTypeString, type, classOp - type);
2376          memcpy(method.dataTypeString + (classOp - type), classOp + classOpLen, typeLen - (classOp - type + classOpLen));
2377       }
2378       else
2379          method.dataTypeString = type;
2380    }
2381    */
2382 }
2383
2384
2385 public void ProcessPropertyType(Property prop)
2386 {
2387    if(!prop.dataType)
2388    {
2389       Context context = SetupTemplatesContext(prop._class);
2390       prop.dataType = ProcessTypeString(prop.dataTypeString, false);
2391       FinishTemplatesContext(context);
2392    }
2393 }
2394
2395 public void DeclareMethod(External neededFor, Method method, const char * name)
2396 {
2397    Symbol symbol = method.symbol;
2398    if(!symbol || (!symbol.pointerExternal && (!symbol.methodCodeExternal || method.type == virtualMethod)))
2399    {
2400       bool dllImport = false;
2401
2402       if(!method.dataType)
2403          method.dataType = ProcessTypeString(method.dataTypeString, false);
2404
2405       //if(!symbol || symbol._import || method.type == virtualMethod)
2406       {
2407          if(!symbol || method.type == virtualMethod)
2408          {
2409             Symbol classSym;
2410             if(!method._class.symbol)
2411                method._class.symbol = FindClass(method._class.fullName);
2412             classSym = method._class.symbol;
2413             if(!classSym._import)
2414             {
2415                ModuleImport module;
2416
2417                if(method._class.module && method._class.module.name)
2418                   module = FindModule(method._class.module);
2419                else
2420                   module = mainModule;
2421                classSym._import = ClassImport
2422                {
2423                   name = CopyString(method._class.fullName);
2424                   isRemote = method._class.isRemote;
2425                };
2426                module.classes.Add(classSym._import);
2427             }
2428             if(!symbol)
2429             {
2430                symbol = method.symbol = Symbol { };
2431             }
2432             if(!symbol._import)
2433             {
2434                symbol._import = (ClassImport)MethodImport
2435                {
2436                   name = CopyString(method.name);
2437                   isVirtual = method.type == virtualMethod;
2438                };
2439                classSym._import.methods.Add(symbol._import);
2440             }
2441             if(!symbol)
2442             {
2443                symbol.type = method.dataType;
2444                if(symbol.type) symbol.type.refCount++;
2445             }
2446          }
2447          if(!method.dataType.dllExport)
2448          {
2449             if((method._class.module != privateModule || !strcmp(method._class.name, "float") || !strcmp(method._class.name, "double")) && method._class.module.importType != staticImport)
2450                dllImport = true;
2451          }
2452       }
2453
2454       if(inCompiler)
2455       {
2456          // We need a declaration here :)
2457          Declaration decl;
2458          OldList * specifiers, * declarators;
2459          Declarator d;
2460          Declarator funcDecl;
2461          External external;
2462
2463          specifiers = MkList();
2464          declarators = MkList();
2465
2466          if(dllImport)
2467             ListAdd(specifiers, MkSpecifier(EXTERN));
2468          else if(method._class.symbol && ((Symbol)method._class.symbol).isStatic)
2469             ListAdd(specifiers, MkSpecifier(STATIC));
2470
2471          if(method.type == virtualMethod)
2472          {
2473             ListAdd(specifiers, MkSpecifier(INT));
2474             d = MkDeclaratorIdentifier(MkIdentifier(name));
2475          }
2476          else
2477          {
2478             d = MkDeclaratorIdentifier(MkIdentifier(name));
2479             if(dllImport)
2480                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2481             {
2482                Context context = SetupTemplatesContext(method._class);
2483                d = SpecDeclFromString(method.dataTypeString, specifiers, d);
2484                FinishTemplatesContext(context);
2485             }
2486             funcDecl = GetFuncDecl(d);
2487
2488             if(dllImport)
2489             {
2490                Specifier spec, next;
2491                for(spec = specifiers->first; spec; spec = next)
2492                {
2493                   next = spec.next;
2494                   if(spec.type == extendedSpecifier)
2495                   {
2496                      specifiers->Remove(spec);
2497                      FreeSpecifier(spec);
2498                   }
2499                }
2500             }
2501
2502             // Add this parameter if not a static method
2503             if(method.dataType && !method.dataType.staticMethod)
2504             {
2505                if(funcDecl && funcDecl.function.parameters && funcDecl.function.parameters->count)
2506                {
2507                   Class _class = method.dataType.thisClass ? method.dataType.thisClass.registered : method._class;
2508                   TypeName thisParam = MkTypeName(MkListOne(
2509                      MkSpecifierName(method.dataType.thisClass ? method.dataType.thisClass.string : method._class.fullName)),
2510                      (_class && _class.type == systemClass) ? MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("this"))) : MkDeclaratorIdentifier(MkIdentifier("this")));
2511                   TypeName firstParam = ((TypeName)funcDecl.function.parameters->first);
2512                   Specifier firstSpec = firstParam.qualifiers ? firstParam.qualifiers->first : null;
2513
2514                   if(firstSpec && firstSpec.type == baseSpecifier && firstSpec.specifier == VOID && !firstParam.declarator)
2515                   {
2516                      TypeName param = funcDecl.function.parameters->first;
2517                      funcDecl.function.parameters->Remove(param);
2518                      FreeTypeName(param);
2519                   }
2520
2521                   if(!funcDecl.function.parameters)
2522                      funcDecl.function.parameters = MkList();
2523                   funcDecl.function.parameters->Insert(null, thisParam);
2524                }
2525             }
2526          }
2527          ProcessDeclarator(d, true);
2528
2529          ListAdd(declarators, MkInitDeclarator(d, null));
2530
2531          decl = MkDeclaration(specifiers, declarators);
2532
2533          ReplaceThisClassSpecifiers(specifiers, method._class);
2534
2535          external = MkExternalDeclaration(decl);
2536          external.symbol = symbol;
2537          symbol.pointerExternal = external;
2538          ast->Add(external);
2539          DeclareStruct(external, method._class.fullName, true, true);
2540          if(method.dataType)
2541             DeclareType(external, method.dataType, true, true);
2542       }
2543    }
2544    if(inCompiler && neededFor)
2545    {
2546       External external = symbol.pointerExternal ? symbol.pointerExternal : symbol.methodCodeExternal;
2547       neededFor.CreateUniqueEdge(external, external.type == functionExternal);
2548    }
2549 }
2550
2551 char * ReplaceThisClass(Class _class)
2552 {
2553    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2554    {
2555       bool first = true;
2556       int p = 0;
2557       ClassTemplateParameter param;
2558       int lastParam = -1;
2559
2560       char className[1024];
2561       strcpy(className, _class.fullName);
2562       for(param = _class.templateParams.first; param; param = param.next)
2563       {
2564          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2565          {
2566             if(first) strcat(className, "<");
2567             if(!first) strcat(className, ", ");
2568             if(lastParam + 1 != p)
2569             {
2570                strcat(className, param.name);
2571                strcat(className, " = ");
2572             }
2573             strcat(className, param.name);
2574             first = false;
2575             lastParam = p;
2576          }
2577          p++;
2578       }
2579       if(!first)
2580       {
2581          int len = strlen(className);
2582          if(className[len-1] == '>') className[len++] = ' ';
2583          className[len++] = '>';
2584          className[len++] = '\0';
2585       }
2586       return CopyString(className);
2587    }
2588    else
2589       return CopyString(_class.fullName);
2590 }
2591
2592 Type ReplaceThisClassType(Class _class)
2593 {
2594    Type type;
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       char className[1024];
2602       strcpy(className, _class.fullName);
2603
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       type = MkClassType(className);
2629       //type = ProcessTypeString(className, false);
2630    }
2631    else
2632    {
2633       type = MkClassType(_class.fullName);
2634       //type = ProcessTypeString(_class.fullName, false);
2635    }
2636    //type.wasThisClass = true;
2637    return type;
2638 }
2639
2640 void ReplaceThisClassSpecifiers(OldList specs, Class _class)
2641 {
2642    if(specs != null && _class)
2643    {
2644       Specifier spec;
2645       for(spec = specs.first; spec; spec = spec.next)
2646       {
2647          if(spec.type == baseSpecifier && spec.specifier == THISCLASS)
2648          {
2649             spec.type = nameSpecifier;
2650             spec.name = ReplaceThisClass(_class);
2651             spec.symbol = FindClass(spec.name); //_class.symbol;
2652          }
2653       }
2654    }
2655 }
2656
2657 // Returns imported or not
2658 bool DeclareFunction(External neededFor, GlobalFunction function, char * name)
2659 {
2660    Symbol symbol = function.symbol;
2661    // TOCHECK: Might get rid of the pointerExternal check in favor of marking the edge as breakable
2662    if(!symbol || !symbol.pointerExternal)
2663    {
2664       bool imported = false;
2665       bool dllImport = false;
2666
2667       if(!function.dataType)
2668       {
2669          function.dataType = ProcessTypeString(function.dataTypeString, false);
2670          if(!function.dataType.thisClass)
2671             function.dataType.staticMethod = true;
2672       }
2673
2674       if(inCompiler)
2675       {
2676          if(!symbol)
2677          {
2678             ModuleImport module = FindModule(function.module);
2679             // WARNING: This is not added anywhere...
2680             symbol = function.symbol = Symbol {  };
2681
2682             if(module.name)
2683             {
2684                if(!function.dataType.dllExport)
2685                {
2686                   symbol._import = (ClassImport)FunctionImport { name = CopyString(function.name) };
2687                   module.functions.Add(symbol._import);
2688                }
2689             }
2690             // Set the symbol type
2691             {
2692                symbol.type = ProcessTypeString(function.dataTypeString, false);
2693                if(!symbol.type.thisClass)
2694                   symbol.type.staticMethod = true;
2695             }
2696          }
2697          imported = symbol._import ? true : false;
2698          if(imported && function.module != privateModule && function.module.importType != staticImport)
2699             dllImport = true;
2700       }
2701
2702       if(inCompiler)
2703       {
2704          // TOCHECK: What's with the functionExternal check here? Is it Edge breaking / forward declaration?
2705          //if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2706          {
2707             // We need a declaration here :)
2708             Declaration decl;
2709             OldList * specifiers, * declarators;
2710             Declarator d;
2711             Declarator funcDecl;
2712             External external;
2713
2714             specifiers = MkList();
2715             declarators = MkList();
2716
2717             ListAdd(specifiers, MkSpecifier(EXTERN));
2718
2719             d = MkDeclaratorIdentifier(MkIdentifier(imported ? name : function.name));
2720             if(dllImport)
2721                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2722
2723             d = SpecDeclFromString(function.dataTypeString, specifiers, d);
2724             // TAKE OUT THE DLL EXPORT IF STATICALLY IMPORTED:
2725             if(function.module.importType == staticImport)
2726             {
2727                Specifier spec;
2728                for(spec = specifiers->first; spec; spec = spec.next)
2729                   if(spec.type == extendedSpecifier && spec.extDecl && spec.extDecl.type == extDeclString && !strcmp(spec.extDecl.s, "dllexport"))
2730                   {
2731                      specifiers->Remove(spec);
2732                      FreeSpecifier(spec);
2733                      break;
2734                   }
2735             }
2736
2737             funcDecl = GetFuncDecl(d);
2738
2739             // Make sure we don't have empty parameter declarations for static methods...
2740             if(funcDecl && !funcDecl.function.parameters)
2741             {
2742                funcDecl.function.parameters = MkList();
2743                funcDecl.function.parameters->Insert(null,
2744                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2745             }
2746
2747             ListAdd(declarators, MkInitDeclarator(d, null));
2748
2749             {
2750                Context oldCtx = curContext;
2751                curContext = globalContext;
2752                decl = MkDeclaration(specifiers, declarators);
2753                curContext = oldCtx;
2754             }
2755
2756             // Keep a different symbol for the function definition than the declaration...
2757             /* Note: This should be handled by the edge breaking...
2758             if(symbol.pointerExternal && symbol.pointerExternal.type == functionExternal)
2759             {
2760                Symbol functionSymbol { };
2761                // Copy symbol
2762                {
2763                   *functionSymbol = *symbol;
2764                   functionSymbol.string = CopyString(symbol.string);
2765                   if(functionSymbol.type)
2766                      functionSymbol.type.refCount++;
2767                }
2768
2769                excludedSymbols->Add(functionSymbol);
2770
2771                symbol.pointerExternal.symbol = functionSymbol;
2772             }
2773             */
2774             external = MkExternalDeclaration(decl);
2775             ast->Add(external);
2776             external.symbol = symbol;
2777             symbol.pointerExternal = external;
2778
2779             DeclareType(external, function.dataType, true, true);
2780          }
2781       }
2782    }
2783    if(inCompiler && neededFor && symbol && symbol.pointerExternal)
2784       neededFor.CreateUniqueEdge(symbol.pointerExternal, symbol.pointerExternal.type == functionExternal);
2785    return (symbol && symbol._import && function.module != privateModule && function.module.importType != staticImport) ? true : false;
2786 }
2787
2788 void DeclareGlobalData(External neededFor, GlobalData data)
2789 {
2790    Symbol symbol = data.symbol;
2791    // TOCHECK: Might get rid of the pointerExternal check in favor of marking the edge as breakable
2792    if(!symbol || !symbol.pointerExternal)
2793    {
2794       if(inCompiler)
2795       {
2796          if(!symbol)
2797             symbol = data.symbol = Symbol { };
2798       }
2799       if(!data.dataType)
2800          data.dataType = ProcessTypeString(data.dataTypeString, false);
2801
2802       if(inCompiler)
2803       {
2804          // We need a declaration here :)
2805          Declaration decl;
2806          OldList * specifiers, * declarators;
2807          Declarator d;
2808          External external;
2809
2810          specifiers = MkList();
2811          declarators = MkList();
2812
2813          ListAdd(specifiers, MkSpecifier(EXTERN));
2814          d = MkDeclaratorIdentifier(MkIdentifier(data.fullName));
2815          d = SpecDeclFromString(data.dataTypeString, specifiers, d);
2816
2817          ListAdd(declarators, MkInitDeclarator(d, null));
2818
2819          decl = MkDeclaration(specifiers, declarators);
2820          external = MkExternalDeclaration(decl);
2821          if(curExternal)
2822             ast->Insert(curExternal.prev, external);
2823          external.symbol = symbol;
2824          symbol.pointerExternal = external;
2825
2826          DeclareType(external, data.dataType, true, true);
2827       }
2828    }
2829    if(inCompiler && neededFor && symbol && symbol.pointerExternal)
2830       neededFor.CreateUniqueEdge(symbol.pointerExternal, false);
2831 }
2832
2833 class Conversion : struct
2834 {
2835    Conversion prev, next;
2836    Property convert;
2837    bool isGet;
2838    Type resultType;
2839 };
2840
2841 static bool CheckConstCompatibility(Type source, Type dest, bool warn)
2842 {
2843    bool status = true;
2844    if(((source.kind == classType && source._class && source._class.registered) || source.kind == arrayType || source.kind == pointerType) &&
2845       ((dest.kind == classType && dest._class && dest._class.registered) || /*dest.kind == arrayType || */dest.kind == pointerType))
2846    {
2847       Class sourceClass = source.kind == classType ? source._class.registered : null;
2848       Class destClass = dest.kind == classType ? dest._class.registered : null;
2849       if((!sourceClass || (sourceClass && sourceClass.type == normalClass && !sourceClass.structSize)) &&
2850          (!destClass || (destClass && destClass.type == normalClass && !destClass.structSize)))
2851       {
2852          Type sourceType = source, destType = dest;
2853          while((sourceType.kind == pointerType || sourceType.kind == arrayType) && sourceType.type) sourceType = sourceType.type;
2854          while((destType.kind == pointerType || destType.kind == arrayType) && destType.type) destType = destType.type;
2855          if(!destType.constant && sourceType.constant)
2856          {
2857             status = false;
2858             if(warn)
2859                Compiler_Warning($"discarding const qualifier\n");
2860          }
2861       }
2862    }
2863    return status;
2864 }
2865
2866 public bool MatchTypes(Type source, Type dest, OldList conversions, Class owningClassSource, Class owningClassDest, bool doConversion, bool enumBaseType, bool acceptReversedParams,
2867                        bool isConversionExploration, bool warnConst)
2868 {
2869    if(source && dest)
2870    {
2871       if(warnConst)
2872          CheckConstCompatibility(source, dest, true);
2873       // Property convert;
2874
2875       if(source.kind == templateType && dest.kind != templateType)
2876       {
2877          Type type = ProcessTemplateParameterType(source.templateParameter);
2878          if(type) source = type;
2879       }
2880
2881       if(dest.kind == templateType && source.kind != templateType)
2882       {
2883          Type type = ProcessTemplateParameterType(dest.templateParameter);
2884          if(type) dest = type;
2885       }
2886
2887       if(dest.classObjectType == typedObject && dest.kind != functionType)
2888       {
2889          if(source.classObjectType != anyObject)
2890             return true;
2891          else
2892          {
2893             // If either the source or the destination defines the class, accepts any_object as compatible for a typed_object
2894             if((dest._class && strcmp(dest._class.string, "class")) || (source._class && strcmp(source._class.string, "class")))
2895             {
2896                return true;
2897             }
2898          }
2899       }
2900       else
2901       {
2902          if(source.kind != functionType && source.classObjectType == anyObject)
2903             return true;
2904          if(dest.kind != functionType && dest.classObjectType == anyObject && source.classObjectType != typedObject)
2905             return true;
2906       }
2907
2908       if((dest.kind == structType && source.kind == structType) ||
2909          (dest.kind == unionType && source.kind == unionType))
2910       {
2911          if((dest.enumName && source.enumName && !strcmp(dest.enumName, source.enumName)) ||
2912              (source.members.first && source.members.first == dest.members.first))
2913             return true;
2914       }
2915
2916       if(dest.kind == ellipsisType && source.kind != voidType)
2917          return true;
2918
2919       if(dest.kind == pointerType && dest.type.kind == voidType &&
2920          ((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))
2921          || source.kind == subClassType || source.kind == pointerType || source.kind == arrayType || source.kind == functionType || source.kind == thisClassType)
2922
2923          /*source.kind != voidType && source.kind != structType && source.kind != unionType  */
2924
2925          /*&& (source.kind != classType /-*|| source._class.registered.type != structClass)*/)
2926          return true;
2927       if(!isConversionExploration && source.kind == pointerType && source.type.kind == voidType &&
2928          ((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))
2929          || dest.kind == subClassType || dest.kind == pointerType || dest.kind == arrayType || dest.kind == functionType || dest.kind == thisClassType)
2930          /* dest.kind != voidType && dest.kind != structType && dest.kind != unionType  */
2931
2932          /*&& (dest.kind != classType || dest._class.registered.type != structClass)*/)
2933          return true;
2934
2935       if(((source.kind == classType && dest.kind == classType) || (source.kind == subClassType && dest.kind == subClassType)) && source._class)
2936       {
2937          if(source._class.registered && source._class.registered.type == unitClass)
2938          {
2939             if(conversions != null)
2940             {
2941                if(source._class.registered == dest._class.registered)
2942                   return true;
2943             }
2944             else
2945             {
2946                Class sourceBase, destBase;
2947                for(sourceBase = source._class.registered; sourceBase && sourceBase.base.type != systemClass; sourceBase = sourceBase.base);
2948                for(destBase = dest._class.registered; destBase && destBase.base.type != systemClass; destBase = destBase.base);
2949                if(sourceBase == destBase)
2950                   return true;
2951             }
2952          }
2953          // Don't match enum inheriting from other enum if resolving enumeration values
2954          // TESTING: !dest.classObjectType
2955          else if(source._class && dest._class && (dest.classObjectType == source.classObjectType || !dest.classObjectType) &&
2956             (enumBaseType ||
2957                (!source._class.registered || source._class.registered.type != enumClass) ||
2958                (!dest._class.registered || dest._class.registered.type != enumClass)) && eClass_IsDerived(source._class.registered, dest._class.registered))
2959             return true;
2960          else
2961          {
2962             // Added this so that DefinedColor = Color doesn't go through ColorRGB property
2963             if(enumBaseType &&
2964                dest._class && dest._class.registered && dest._class.registered.type == enumClass &&
2965                ((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)
2966             {
2967                if(eClass_IsDerived(dest._class.registered, source._class.registered))
2968                {
2969                   return true;
2970                }
2971             }
2972          }
2973       }
2974
2975       // JUST ADDED THIS...
2976       if(source.kind == subClassType && dest.kind == classType && dest._class && !strcmp(dest._class.string, "ecere::com::Class"))
2977          return true;
2978
2979       if(doConversion)
2980       {
2981          // Just added this for Straight conversion of ColorAlpha => Color
2982          if(source.kind == classType)
2983          {
2984             Class _class;
2985             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
2986             {
2987                Property convert;
2988                for(convert = _class.conversions.first; convert; convert = convert.next)
2989                {
2990                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
2991                   {
2992                      Conversion after = (conversions != null) ? conversions.last : null;
2993
2994                      if(!convert.dataType)
2995                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
2996                      // Only go ahead with this conversion flow while processing an existing conversion if the conversion data type is a class
2997                      if((!isConversionExploration || convert.dataType.kind == classType || !strcmp(_class.name, "String")) &&
2998                         MatchTypes(convert.dataType, dest, conversions, null, null,
2999                            (convert.dataType.kind == classType && !strcmp(convert.dataTypeString, "String")) ? true : false,
3000                               convert.dataType.kind == classType, false, true, warnConst))
3001                      {
3002                         if(!conversions && !convert.Get)
3003                            return true;
3004                         else if(conversions != null)
3005                         {
3006                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3007                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3008                               (dest.kind != classType || dest._class.registered != _class.base))
3009                               return true;
3010                            else
3011                            {
3012                               Conversion conv { convert = convert, isGet = true };
3013                               // conversions.Add(conv);
3014                               conversions.Insert(after, conv);
3015
3016                               return true;
3017                            }
3018                         }
3019                      }
3020                   }
3021                }
3022             }
3023          }
3024
3025          // MOVING THIS??
3026
3027          if(dest.kind == classType)
3028          {
3029             Class _class;
3030             for(_class = dest._class ? dest._class.registered : null; _class; _class = _class.base)
3031             {
3032                Property convert;
3033                for(convert = _class.conversions.first; convert; convert = convert.next)
3034                {
3035                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3036                   {
3037                      Type constType = null;
3038                      bool success = false;
3039                      // Conversion after = (conversions != null) ? conversions.last : null;
3040
3041                      if(!convert.dataType)
3042                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3043
3044                      if(warnConst && convert.dataType.kind == pointerType && convert.dataType.type && dest.constant)
3045                      {
3046                         Type ptrType { };
3047                         constType = { kind = pointerType, refCount = 1, type = ptrType };
3048                         CopyTypeInto(ptrType, convert.dataType.type);
3049                         ptrType.constant = true;
3050                      }
3051
3052                      // Just added this equality check to prevent recursion.... Make it safer?
3053                      // Changed enumBaseType to false here to prevent all int-compatible enums to show up in AnchorValues
3054                      if((constType || convert.dataType != dest) && MatchTypes(source, constType ? constType : convert.dataType, conversions, null, null, true, false /*true*/, false, true, warnConst))
3055                      {
3056                         if(!conversions && !convert.Set)
3057                            success = true;
3058                         else if(conversions != null)
3059                         {
3060                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3061                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3062                               (source.kind != classType || source._class.registered != _class.base))
3063                               success = true;
3064                            else
3065                            {
3066                               // *** Testing this! ***
3067                               Conversion conv { convert = convert };
3068                               conversions.Add(conv);
3069                               //conversions.Insert(after, conv);
3070                               success = true;
3071                            }
3072                         }
3073                      }
3074                      if(constType)
3075                         FreeType(constType);
3076                      if(success)
3077                         return true;
3078                   }
3079                }
3080             }
3081             /*if(dest._class.registered && !strcmp(dest._class.registered.name, "bool"))
3082             {
3083                if(source.kind != voidType && source.kind != structType && source.kind != unionType &&
3084                   (source.kind != classType || source._class.registered.type != structClass))
3085                   return true;
3086             }*/
3087
3088             // TESTING THIS... IS THIS OK??
3089             if(enumBaseType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3090             {
3091                if(!dest._class.registered.dataType)
3092                   dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3093                // Only support this for classes...
3094                if(dest._class.registered.dataType.kind == classType || source.truth || dest.truth/* ||
3095                   !strcmp(dest._class.registered.name, "bool") || (source.kind == classType && !strcmp(source._class.string, "bool"))*/)
3096                {
3097                   if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, dest._class.registered.dataType.kind == classType, false, false, warnConst))
3098                   {
3099                      return true;
3100                   }
3101                }
3102             }
3103          }
3104
3105          // Moved this lower
3106          if(source.kind == classType)
3107          {
3108             Class _class;
3109             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3110             {
3111                Property convert;
3112                for(convert = _class.conversions.first; convert; convert = convert.next)
3113                {
3114                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3115                   {
3116                      Conversion after = (conversions != null) ? conversions.last : null;
3117
3118                      if(!convert.dataType)
3119                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3120                      if(convert.dataType != source &&
3121                         (!isConversionExploration || convert.dataType.kind == classType || !strcmp(_class.name, "String")) &&
3122                         MatchTypes(convert.dataType, dest, conversions, null, null, convert.dataType.kind == classType, convert.dataType.kind == classType, false, true, warnConst))
3123                      {
3124                         if(!conversions && !convert.Get)
3125                            return true;
3126                         else if(conversions != null)
3127                         {
3128                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3129                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3130                               (dest.kind != classType || dest._class.registered != _class.base))
3131                               return true;
3132                            else
3133                            {
3134                               Conversion conv { convert = convert, isGet = true };
3135
3136                               // conversions.Add(conv);
3137                               conversions.Insert(after, conv);
3138                               return true;
3139                            }
3140                         }
3141                      }
3142                   }
3143                }
3144             }
3145
3146             // TESTING THIS... IS THIS OK??
3147             if(enumBaseType && source._class && source._class.registered && source._class.registered.type == enumClass)
3148             {
3149                if(!source._class.registered.dataType)
3150                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3151                if(!isConversionExploration || source._class.registered.dataType.kind == classType || !strcmp(source._class.registered.name, "String"))
3152                {
3153                   if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, source._class.registered.dataType.kind == classType, source._class.registered.dataType.kind == classType, false, false, warnConst))
3154                      return true;
3155                   // For bool to be accepted by byte, short, etc.
3156                   else if(MatchTypes(dest, source._class.registered.dataType, null, null, null, false, false, false, false, warnConst))
3157                      return true;
3158                }
3159             }
3160          }
3161       }
3162
3163       if(source.kind == classType || source.kind == subClassType)
3164          ;
3165       else if(dest.kind == source.kind &&
3166          (dest.kind != structType && dest.kind != unionType &&
3167           dest.kind != functionType && dest.kind != arrayType && dest.kind != pointerType && dest.kind != methodType))
3168           return true;
3169       // RECENTLY ADDED THESE
3170       else if(dest.kind == doubleType && source.kind == floatType)
3171          return true;
3172       else if(dest.kind == shortType && (source.kind == charType || source.kind == _BoolType))
3173          return true;
3174       else if(dest.kind == intType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intSizeType /* Exception here for size_t */))
3175          return true;
3176       else if(dest.kind == int64Type && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intPtrType || source.kind == intSizeType))
3177          return true;
3178       else if(dest.kind == intPtrType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intSizeType || source.kind == int64Type))
3179          return true;
3180       else if(dest.kind == intSizeType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == int64Type || source.kind == intPtrType))
3181          return true;
3182       else if(source.kind == enumType &&
3183          (dest.kind == intType || dest.kind == shortType || dest.kind == charType || source.kind == _BoolType || dest.kind == longType || dest.kind == int64Type || dest.kind == intPtrType || dest.kind == intSizeType))
3184           return true;
3185       else if(dest.kind == enumType && !isConversionExploration &&
3186          (source.kind == intType || source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == longType || source.kind == int64Type || source.kind == intPtrType || source.kind == intSizeType))
3187           return true;
3188       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) &&
3189               ((source.kind == functionType || (source.kind == pointerType && source.type.kind == functionType) || source.kind == methodType)))
3190       {
3191          Type paramSource, paramDest;
3192
3193          if(dest.kind == methodType)
3194             owningClassDest = dest.methodClass ? dest.methodClass : dest.method._class;
3195          if(source.kind == methodType)
3196             owningClassSource = source.methodClass ? source.methodClass : source.method._class;
3197
3198          if(dest.kind == pointerType && dest.type.kind == functionType) dest = dest.type;
3199          if(source.kind == pointerType && source.type.kind == functionType) source = source.type;
3200          if(dest.kind == methodType)
3201             dest = dest.method.dataType;
3202          if(source.kind == methodType)
3203             source = source.method.dataType;
3204
3205          paramSource = source.params.first;
3206          if(paramSource && paramSource.kind == voidType) paramSource = null;
3207          paramDest = dest.params.first;
3208          if(paramDest && paramDest.kind == voidType) paramDest = null;
3209
3210
3211          if((dest.staticMethod || (!dest.thisClass && !owningClassDest)) &&
3212             !(source.staticMethod || (!source.thisClass && !owningClassSource)))
3213          {
3214             // Source thisClass must be derived from destination thisClass
3215             if(!paramDest || (!(paramDest.kind == pointerType && paramDest.type && paramDest.type.kind == voidType) && (paramDest.kind != classType ||
3216                !eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource,paramDest._class.registered))))
3217             {
3218                if(paramDest && paramDest.kind == classType)
3219                   Compiler_Error($"method class must be derived from %s\n", paramDest._class.string);
3220                else
3221                   Compiler_Error($"method class should not take an object\n");
3222                return false;
3223             }
3224             paramDest = paramDest.next;
3225          }
3226          else if(!dest.staticMethod && (dest.thisClass || owningClassDest))
3227          {
3228             if((source.staticMethod || (!source.thisClass && !owningClassSource)))
3229             {
3230                if(dest.thisClass)
3231                {
3232                   if(!paramSource || paramSource.kind != classType || !eClass_IsDerived(paramSource._class.registered,dest.thisClass.registered))
3233                   {
3234                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3235                      return false;
3236                   }
3237                }
3238                else
3239                {
3240                   // THIS WAS BACKWARDS:
3241                   // if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(owningClassDest, paramSource._class.registered)))
3242                   if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(paramSource._class.registered, owningClassDest)))
3243                   {
3244                      if(owningClassDest)
3245                        Compiler_Error($"%s expected to be derived from method class\n", owningClassDest.fullName);
3246                      else
3247                         Compiler_Error($"overriding class expected to be derived from method class\n");
3248                      return false;
3249                   }
3250                }
3251                paramSource = paramSource.next;
3252             }
3253             else
3254             {
3255                if(dest.thisClass)
3256                {
3257                   // Source thisClass must be derived from destination thisClass
3258                   if(!eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource, dest.thisClass.registered))
3259                   {
3260                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3261                      return false;
3262                   }
3263                }
3264                else
3265                {
3266                   // THIS WAS BACKWARDS TOO??
3267                   // if(source.thisClass && owningClassDest && !eClass_IsDerived(owningClassDest, source.thisClass.registered))
3268                   if(source.thisClass && source.thisClass.registered && owningClassDest && !eClass_IsDerived(source.thisClass.registered, owningClassDest))
3269                   {
3270                      //if(owningClass)
3271                         Compiler_Error($"%s expected to be derived from method class\n", /*owningClass.name*/ source.thisClass.registered.fullName);
3272                      //else
3273                         //Compiler_Error($"overriding class expected to be derived from method class\n");
3274                      return false;
3275                   }
3276                }
3277             }
3278          }
3279
3280
3281          // Source return type must be derived from destination return type
3282          if(!MatchTypes(source.returnType, dest.returnType, null, null, null, true, true, false, false, warnConst))
3283          {
3284             Compiler_Warning($"incompatible return type for function\n");
3285             return false;
3286          }
3287          // The const check is backwards from the MatchTypes above (for derivative classes checks)
3288          else
3289             CheckConstCompatibility(dest.returnType, source.returnType, true);
3290
3291          // Check parameters
3292
3293          for(; paramDest; paramDest = paramDest.next)
3294          {
3295             if(!paramSource)
3296             {
3297                //Compiler_Warning($"not enough parameters\n");
3298                Compiler_Error($"not enough parameters\n");
3299                return false;
3300             }
3301             {
3302                Type paramDestType = paramDest;
3303                Type paramSourceType = paramSource;
3304                Type type = paramDestType;
3305
3306                // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
3307                if(paramDest.kind == templateType && paramDest.templateParameter.type == TemplateParameterType::type && owningClassSource &&
3308                   paramSource.kind != templateType)
3309                {
3310                   int id = 0;
3311                   ClassTemplateParameter curParam = null;
3312                   Class sClass;
3313                   for(sClass = owningClassSource; sClass; sClass = sClass.base)
3314                   {
3315                      id = 0;
3316                      if(sClass.templateClass) sClass = sClass.templateClass;
3317                      for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
3318                      {
3319                         if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
3320                         {
3321                            for(sClass = sClass.base; sClass; sClass = sClass.base)
3322                            {
3323                               if(sClass.templateClass) sClass = sClass.templateClass;
3324                               id += sClass.templateParams.count;
3325                            }
3326                            break;
3327                         }
3328                         id++;
3329                      }
3330                      if(curParam) break;
3331                   }
3332
3333                   if(curParam)
3334                   {
3335                      ClassTemplateArgument arg = owningClassSource.templateArgs[id];
3336                      paramDestType = type = ProcessTypeString(arg.dataTypeString, false);
3337                   }
3338                }
3339
3340                // paramDest must be derived from paramSource
3341                if(!MatchTypes(paramDestType, paramSourceType, null, null, null, true, true, false, false, warnConst) &&
3342                   (!acceptReversedParams || !MatchTypes(paramSourceType, paramDestType, null, null, null, true, true, false, false, warnConst)))
3343                {
3344                   char type[1024];
3345                   type[0] = 0;
3346                   PrintType(paramDest, type, false, true);
3347                   Compiler_Warning($"incompatible parameter %s (expected %s)\n", paramSource.name, type);
3348
3349                   if(paramDestType != paramDest)
3350                      FreeType(paramDestType);
3351                   return false;
3352                }
3353                if(paramDestType != paramDest)
3354                   FreeType(paramDestType);
3355             }
3356
3357             paramSource = paramSource.next;
3358          }
3359          if(paramSource)
3360          {
3361             Compiler_Error($"too many parameters\n");
3362             return false;
3363          }
3364          return true;
3365       }
3366       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) && (source.kind == pointerType && source.type.kind == voidType))
3367       {
3368          return true;
3369       }
3370       else if((dest.kind == pointerType || dest.kind == arrayType) &&
3371          (source.kind == arrayType || source.kind == pointerType))
3372       {
3373          // Pointers to pointer is incompatible with non normal/nohead classes
3374          if(!(dest.type && dest.type.kind == pointerType && source.type.kind == classType && source.type._class &&
3375             source.type._class.registered && (source.type._class.registered.type != normalClass && source.type._class.registered.type != noHeadClass) && !source.type.byReference))
3376          {
3377             ComputeTypeSize(source.type);
3378             ComputeTypeSize(dest.type);
3379             if(source.type.size == dest.type.size && MatchTypes(source.type, dest.type, null, null, null, true, true, false, false, warnConst))
3380                return true;
3381          }
3382       }
3383    }
3384    return false;
3385 }
3386
3387 static void FreeConvert(Conversion convert)
3388 {
3389    if(convert.resultType)
3390       FreeType(convert.resultType);
3391 }
3392
3393 bool MatchWithEnums_NameSpace(NameSpace nameSpace, Expression sourceExp, Type dest,
3394                               char * string, OldList conversions)
3395 {
3396    BTNamedLink link;
3397
3398    for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
3399    {
3400       Class _class = link.data;
3401       if(_class.type == enumClass)
3402       {
3403          OldList converts { };
3404          Type type { };
3405          type.kind = classType;
3406
3407          if(!_class.symbol)
3408             _class.symbol = FindClass(_class.fullName);
3409          type._class = _class.symbol;
3410
3411          if(MatchTypes(type, dest, &converts, null, null, dest.kind != classType || !dest._class || strcmp(dest._class.string, "bool"),
3412                false, false, false, false))
3413          {
3414             NamedLink64 value;
3415             Class enumClass = eSystem_FindClass(privateModule, "enum");
3416             if(enumClass)
3417             {
3418                Class baseClass;
3419                for(baseClass = _class ; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
3420                {
3421                   EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
3422                   for(value = e.values.first; value; value = value.next)
3423                   {
3424                      if(!strcmp(value.name, string))
3425                         break;
3426                   }
3427                   if(value)
3428                   {
3429                      FreeType(sourceExp.expType);
3430
3431                      sourceExp.isConstant = true;
3432                      sourceExp.expType = MkClassType(baseClass.fullName);
3433                      if(inCompiler || inPreCompiler || inDebugger)
3434                      {
3435                         char constant[256];
3436                         FreeExpContents(sourceExp);
3437
3438                         sourceExp.type = constantExp;
3439                         if(!strcmp(baseClass.dataTypeString, "int") || !strcmp(baseClass.dataTypeString, "int64") || !strcmp(baseClass.dataTypeString, "short") || !strcmp(baseClass.dataTypeString, "char"))
3440                            sprintf(constant, FORMAT64D, value.data);
3441                         else
3442                            sprintf(constant, FORMAT64HEXLL, value.data);
3443                         sourceExp.constant = CopyString(constant);
3444                         //for(;baseClass.base && baseClass.base.type != systemClass; baseClass = baseClass.base);
3445                      }
3446
3447                      while(converts.first)
3448                      {
3449                         Conversion convert = converts.first;
3450                         converts.Remove(convert);
3451                         conversions.Add(convert);
3452                      }
3453                      delete type;
3454                      return true;
3455                   }
3456                }
3457             }
3458          }
3459          if(converts.first)
3460             converts.Free(FreeConvert);
3461          delete type;
3462       }
3463    }
3464    for(nameSpace = (NameSpace *)nameSpace.nameSpaces.first; nameSpace != null; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
3465       if(MatchWithEnums_NameSpace(nameSpace, sourceExp, dest, string, conversions))
3466          return true;
3467    return false;
3468 }
3469
3470 public bool ModuleVisibility(Module searchIn, Module searchFor)
3471 {
3472    SubModule subModule;
3473
3474    if(searchFor == searchIn)
3475       return true;
3476
3477    for(subModule = searchIn.modules.first; subModule; subModule = subModule.next)
3478    {
3479       if(subModule.importMode == publicAccess || searchIn == searchIn.application)
3480       {
3481          if(ModuleVisibility(subModule.module, searchFor))
3482             return true;
3483       }
3484    }
3485    return false;
3486 }
3487
3488 bool MatchWithEnums_Module(Module mainModule, Expression sourceExp, Type dest, char * string, OldList conversions)
3489 {
3490    Module module;
3491
3492    if(MatchWithEnums_NameSpace(mainModule.application.systemNameSpace, sourceExp, dest, string, conversions))
3493       return true;
3494    if(MatchWithEnums_NameSpace(mainModule.application.privateNameSpace, sourceExp, dest, string, conversions))
3495       return true;
3496    if(MatchWithEnums_NameSpace(mainModule.application.publicNameSpace, sourceExp, dest, string, conversions))
3497       return true;
3498
3499    for(module = mainModule.application.allModules.first; module; module = module.next)
3500    {
3501       if(ModuleVisibility(mainModule, module) && MatchWithEnums_NameSpace(module.publicNameSpace, sourceExp, dest, string, conversions))
3502          return true;
3503    }
3504    return false;
3505 }
3506
3507 bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, bool skipUnitBla, bool warnConst)
3508 {
3509    Type source;
3510    Type realDest = dest;
3511    Type backupSourceExpType = null;
3512    Expression nbExp = GetNonBracketsExp(sourceExp);
3513    Expression computedExp = nbExp;
3514    dest.refCount++;
3515
3516    if(sourceExp.isConstant && sourceExp.type != constantExp && sourceExp.type != identifierExp && sourceExp.type != castExp &&
3517       dest.kind == classType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3518    {
3519       computedExp = CopyExpression(nbExp);        // Keep the original expression, but compute for checking enum ranges
3520       ComputeExpression(computedExp /*sourceExp*/);
3521    }
3522
3523    source = sourceExp.expType;
3524
3525    if(dest.kind == pointerType && sourceExp.type == constantExp && !strtoul(sourceExp.constant, null, 0))
3526    {
3527       if(computedExp != nbExp)
3528       {
3529          FreeExpression(computedExp);
3530          computedExp = nbExp;
3531       }
3532       FreeType(dest);
3533       return true;
3534    }
3535
3536    if(!skipUnitBla && source && dest && source.kind == classType && dest.kind == classType)
3537    {
3538        if(source._class && source._class.registered && source._class.registered.type == unitClass)
3539        {
3540           Class sourceBase, destBase;
3541           for(sourceBase = source._class.registered;
3542               sourceBase && sourceBase.base && sourceBase.base.type != systemClass;
3543               sourceBase = sourceBase.base);
3544           for(destBase = dest._class.registered;
3545               destBase && destBase.base && destBase.base.type != systemClass;
3546               destBase = destBase.base);
3547           //if(source._class.registered == dest._class.registered)
3548           if(sourceBase == destBase)
3549           {
3550             if(computedExp != nbExp)
3551             {
3552                FreeExpression(computedExp);
3553                computedExp = nbExp;
3554             }
3555             FreeType(dest);
3556             return true;
3557          }
3558       }
3559    }
3560
3561    if(source)
3562    {
3563       OldList * specs;
3564       bool flag = false;
3565       int64 value = MAXINT;
3566
3567       source.refCount++;
3568
3569       if(computedExp.type == constantExp)
3570       {
3571          if(source.isSigned)
3572             value = strtoll(computedExp.constant, null, 0);
3573          else
3574             value = strtoull(computedExp.constant, null, 0);
3575       }
3576       else if(computedExp.type == opExp && sourceExp.op.op == '-' && !computedExp.op.exp1 && computedExp.op.exp2 && computedExp.op.exp2.type == constantExp)
3577       {
3578          if(source.isSigned)
3579             value = -strtoll(computedExp.op.exp2.constant, null, 0);
3580          else
3581             value = -strtoull(computedExp.op.exp2.constant, null, 0);
3582       }
3583       if(computedExp != nbExp)
3584       {
3585          FreeExpression(computedExp);
3586          computedExp = nbExp;
3587       }
3588
3589       if(dest.kind != classType && source.kind == classType && source._class && source._class.registered &&
3590          !strcmp(source._class.registered.fullName, "unichar" /*"ecere::com::unichar"*/))
3591       {
3592          FreeType(source);
3593          source = Type { kind = intType, isSigned = false, refCount = 1 };
3594       }
3595
3596       if(dest.kind == classType)
3597       {
3598          Class _class = dest._class ? dest._class.registered : null;
3599
3600          if(_class && _class.type == unitClass)
3601          {
3602             if(source.kind != classType)
3603             {
3604                Type tempType { };
3605                Type tempDest, tempSource;
3606
3607                for(; _class.base.type != systemClass; _class = _class.base);
3608                tempSource = dest;
3609                tempDest = tempType;
3610
3611                tempType.kind = classType;
3612                if(!_class.symbol)
3613                   _class.symbol = FindClass(_class.fullName);
3614
3615                tempType._class = _class.symbol;
3616                tempType.truth = dest.truth;
3617                if(tempType._class)
3618                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false, warnConst);
3619
3620                // NOTE: To handle bad warnings on int64 vs 32 bit eda::Id incompatibilities
3621                backupSourceExpType = sourceExp.expType;
3622                if(dest.passAsTemplate)
3623                {
3624                   // Don't carry passAsTemplate
3625                   sourceExp.expType = { };
3626                   CopyTypeInto(sourceExp.expType, dest);
3627                   sourceExp.expType.passAsTemplate = false;
3628                }
3629                else
3630                {
3631                   sourceExp.expType = dest;
3632                   dest.refCount++;
3633                }
3634                //sourceExp.expType = MkClassType(_class.fullName);
3635                flag = true;
3636
3637                delete tempType;
3638             }
3639          }
3640
3641
3642          // Why wasn't there something like this?
3643          if(_class && _class.type == bitClass && source.kind != classType)
3644          {
3645             if(!dest._class.registered.dataType)
3646                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3647             if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false, warnConst))
3648             {
3649                FreeType(source);
3650                FreeType(sourceExp.expType);
3651                source = sourceExp.expType = MkClassType(dest._class.string);
3652                source.refCount++;
3653
3654                //source.kind = classType;
3655                //source._class = dest._class;
3656             }
3657          }
3658
3659          // Adding two enumerations
3660          /*
3661          if(_class && _class.type == enumClass && source.kind == classType && source._class && source._class.registered && source._class.registered.type == enumClass)
3662          {
3663             if(!source._class.registered.dataType)
3664                source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3665             if(!dest._class.registered.dataType)
3666                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3667
3668             if(MatchTypes(source._class.registered.dataType, dest._class.registered.dataType, conversions, null, null, true, false, false))
3669             {
3670                FreeType(source);
3671                source = sourceExp.expType = MkClassType(dest._class.string);
3672                source.refCount++;
3673
3674                //source.kind = classType;
3675                //source._class = dest._class;
3676             }
3677          }*/
3678
3679          if(_class && !strcmp(_class.fullName, "ecere::com::Class") && source.kind == pointerType && source.type && source.type.kind == charType && sourceExp.type == stringExp)
3680          {
3681             OldList * specs = MkList();
3682             Declarator decl;
3683             char string[1024];
3684
3685             ReadString(string, sourceExp.string);
3686             decl = SpecDeclFromString(string, specs, null);
3687
3688             FreeExpContents(sourceExp);
3689             FreeType(sourceExp.expType);
3690
3691             sourceExp.type = classExp;
3692             sourceExp._classExp.specifiers = specs;
3693             sourceExp._classExp.decl = decl;
3694             sourceExp.expType = dest;
3695             dest.refCount++;
3696
3697             FreeType(source);
3698             FreeType(dest);
3699             if(backupSourceExpType) FreeType(backupSourceExpType);
3700             return true;
3701          }
3702       }
3703       else if(source.kind == classType)
3704       {
3705          Class _class = source._class ? source._class.registered : null;
3706
3707          if(_class && (_class.type == unitClass || /*!strcmp(_class.fullName, "bool") || _class.type == enumClass || */_class.type == bitClass ))  // TOCHECK: enumClass, bitClass is new here...
3708          {
3709             /*
3710             if(dest.kind != classType)
3711             {
3712                // Testing this simpler piece of code... (Broke Units Conversion to no unit Logic)
3713                if(!source._class.registered.dataType)
3714                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3715
3716                FreeType(dest);
3717                dest = MkClassType(source._class.string);
3718                //if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, false, false))
3719                //   dest = MkClassType(source._class.string);
3720             }
3721             */
3722
3723             if(dest.kind != classType)
3724             {
3725                Type tempType { };
3726                Type tempDest, tempSource;
3727
3728                if(!source._class.registered.dataType)
3729                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3730
3731                for(; _class.base.type != systemClass; _class = _class.base);
3732                tempDest = source;
3733                tempSource = tempType;
3734                tempType.kind = classType;
3735                tempType._class = FindClass(_class.fullName);
3736                tempType.truth = source.truth;
3737                tempType.classObjectType = source.classObjectType;
3738
3739                if(tempType._class)
3740                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false, warnConst);
3741
3742                // PUT THIS BACK TESTING UNITS?
3743                if(conversions && conversions.last)
3744                {
3745                   ((Conversion)(conversions.last)).resultType = dest;
3746                   dest.refCount++;
3747                }
3748
3749                FreeType(sourceExp.expType);
3750                sourceExp.expType = MkClassType(_class.fullName);
3751                sourceExp.expType.truth = source.truth;
3752                sourceExp.expType.classObjectType = source.classObjectType;
3753
3754                // *** This if was commented out, put it back because "int a =^ Destroy()" shows up bool enum values in autocomplete ***
3755
3756                if(!sourceExp.destType)
3757                {
3758                   FreeType(sourceExp.destType);
3759                   sourceExp.destType = sourceExp.expType;
3760                   if(sourceExp.expType)
3761                      sourceExp.expType.refCount++;
3762                }
3763                //flag = true;
3764                //source = _class.dataType;
3765
3766
3767                // TOCHECK: TESTING THIS NEW CODE
3768                if(!_class.dataType)
3769                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3770                FreeType(dest);
3771                dest = MkClassType(source._class.string);
3772                dest.truth = source.truth;
3773                dest.classObjectType = source.classObjectType;
3774
3775                FreeType(source);
3776                source = _class.dataType;
3777                source.refCount++;
3778
3779                delete tempType;
3780             }
3781          }
3782       }
3783
3784       if(!flag)
3785       {
3786          if(MatchTypes(source, dest, conversions, null, null, true, true, false, false, warnConst))
3787          {
3788             FreeType(source);
3789             FreeType(dest);
3790             return true;
3791          }
3792       }
3793
3794       // Implicit Casts
3795       /*
3796       if(source.kind == classType)
3797       {
3798          Class _class = source._class.registered;
3799          if(_class.type == unitClass)
3800          {
3801             if(!_class.dataType)
3802                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3803             source = _class.dataType;
3804          }
3805       }*/
3806
3807       if(dest.kind == classType)
3808       {
3809          Class _class = dest._class ? dest._class.registered : null;
3810          bool fittingValue = false;
3811          if(_class && _class.type == enumClass)
3812          {
3813             Class enumClass = eSystem_FindClass(privateModule, "enum");
3814             EnumClassData c = ACCESS_CLASSDATA(_class, enumClass);
3815             if(c && value >= 0 && value <= c.largest)
3816                fittingValue = true;
3817          }
3818
3819          if(_class && !dest.truth && (_class.type == unitClass || fittingValue ||
3820             (/*_class.type == enumClass*/_class.type != structClass && !value && source.kind == intType) || _class.type == bitClass))   // TOCHECK: enumClass, bitClass is new here...
3821          {
3822             if(_class.type == normalClass || _class.type == noHeadClass)
3823             {
3824                Expression newExp { };
3825                *newExp = *sourceExp;
3826                if(sourceExp.destType) sourceExp.destType.refCount++;
3827                if(sourceExp.expType)  sourceExp.expType.refCount++;
3828                sourceExp.type = castExp;
3829                sourceExp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
3830                sourceExp.cast.exp = newExp;
3831                FreeType(sourceExp.expType);
3832                sourceExp.expType = null;
3833                ProcessExpressionType(sourceExp);
3834
3835                // In Debugger, this helps with addresses (e.g. null pointers) that end up casted to a void *: keeps a classType instead of a pointerType
3836                if(!inCompiler)
3837                {
3838                   FreeType(sourceExp.expType);
3839                   sourceExp.expType = dest;
3840                }
3841
3842                FreeType(source);
3843                if(inCompiler) FreeType(dest);
3844
3845                if(backupSourceExpType) FreeType(backupSourceExpType);
3846                return true;
3847             }
3848
3849             if(!_class.dataType)
3850                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3851             FreeType(dest);
3852             dest = _class.dataType;
3853             dest.refCount++;
3854          }
3855
3856          // Accept lower precision types for units, since we want to keep the unit type
3857          if(dest.kind == doubleType &&
3858             (source.kind == doubleType || source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType ||
3859              source.kind == charType || source.kind == _BoolType))
3860          {
3861             specs = MkListOne(MkSpecifier(DOUBLE));
3862          }
3863          else if(dest.kind == floatType &&
3864             (source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3865             source.kind == _BoolType || source.kind == doubleType))
3866          {
3867             specs = MkListOne(MkSpecifier(FLOAT));
3868          }
3869          else if(dest.kind == int64Type && (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3870             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3871          {
3872             specs = MkList();
3873             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3874             ListAdd(specs, MkSpecifier(INT64));
3875          }
3876          else if(dest.kind == intType && (source.kind == intType || source.kind == shortType || source.kind == charType ||
3877             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3878          {
3879             specs = MkList();
3880             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3881             ListAdd(specs, MkSpecifier(INT));
3882          }
3883          else if(dest.kind == shortType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType ||
3884             source.kind == floatType || source.kind == doubleType))
3885          {
3886             specs = MkList();
3887             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3888             ListAdd(specs, MkSpecifier(SHORT));
3889          }
3890          else if(dest.kind == charType && (source.kind == charType || source.kind == _BoolType || source.kind == shortType || source.kind == intType ||
3891             source.kind == floatType || source.kind == doubleType))
3892          {
3893             specs = MkList();
3894             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3895             ListAdd(specs, MkSpecifier(CHAR));
3896          }
3897          else
3898          {
3899             FreeType(source);
3900             FreeType(dest);
3901             if(backupSourceExpType)
3902             {
3903                // Failed to convert: revert previous exp type
3904                if(sourceExp.expType) FreeType(sourceExp.expType);
3905                sourceExp.expType = backupSourceExpType;
3906             }
3907             return false;
3908          }
3909       }
3910       else if(dest.kind == doubleType &&
3911          (source.kind == doubleType || source.kind == floatType || source.kind == int64Type || source.kind == intType || source.kind == enumType || source.kind == shortType ||
3912           source.kind == _BoolType || source.kind == charType))
3913       {
3914          specs = MkListOne(MkSpecifier(DOUBLE));
3915       }
3916       else if(dest.kind == floatType &&
3917          (source.kind == floatType || source.kind == enumType || source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3918       {
3919          specs = MkListOne(MkSpecifier(FLOAT));
3920       }
3921       else if(dest.kind == _BoolType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3922          (value == 1 || value == 0))
3923       {
3924          specs = MkList();
3925          ListAdd(specs, MkSpecifier(BOOL));
3926       }
3927       else if(dest.kind == charType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3928          (dest.isSigned ? (value >= -128 && value <= 127) : (value >= 0 && value <= 255)))
3929       {
3930          if(source.kind == intType)
3931             return true;
3932          else
3933          {
3934             specs = MkList();
3935             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3936             ListAdd(specs, MkSpecifier(CHAR));
3937          }
3938       }
3939       else if(dest.kind == shortType && (source.kind == enumType || source.kind == _BoolType || source.kind == charType || source.kind == shortType ||
3940          (source.kind == intType && (dest.isSigned ? (value >= -32768 && value <= 32767) : (value >= 0 && value <= 65535)))))
3941       {
3942          if(source.kind == intType)
3943             return true;
3944          else
3945          {
3946             specs = MkList();
3947             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3948             ListAdd(specs, MkSpecifier(SHORT));
3949          }
3950       }
3951       else if(dest.kind == intType && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType))
3952       {
3953          specs = MkList();
3954          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3955          ListAdd(specs, MkSpecifier(INT));
3956       }
3957       else if(dest.kind == int64Type && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType || source.kind == int64Type))
3958       {
3959          specs = MkList();
3960          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3961          ListAdd(specs, MkSpecifier(INT64));
3962       }
3963       else if(dest.kind == enumType &&
3964          (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3965       {
3966          specs = MkListOne(MkEnum(MkIdentifier(dest.enumName), null));
3967       }
3968       else
3969       {
3970          FreeType(source);
3971          FreeType(dest);
3972          if(backupSourceExpType)
3973          {
3974             // Failed to convert: revert previous exp type
3975             if(sourceExp.expType) FreeType(sourceExp.expType);
3976             sourceExp.expType = backupSourceExpType;
3977          }
3978          return false;
3979       }
3980
3981       if(!flag && !sourceExp.opDestType)
3982       {
3983          Expression newExp { };
3984          *newExp = *sourceExp;
3985          newExp.prev = null;
3986          newExp.next = null;
3987          if(sourceExp.destType) sourceExp.destType.refCount++;
3988          if(sourceExp.expType)  sourceExp.expType.refCount++;
3989
3990          sourceExp.type = castExp;
3991          if(realDest.kind == classType)
3992          {
3993             sourceExp.cast.typeName = QMkClass(realDest._class.string, null);
3994             FreeList(specs, FreeSpecifier);
3995          }
3996          else
3997             sourceExp.cast.typeName = MkTypeName(specs, null);
3998          if(newExp.type == opExp)
3999          {
4000             sourceExp.cast.exp = MkExpBrackets(MkListOne(newExp));
4001          }
4002          else
4003             sourceExp.cast.exp = newExp;
4004
4005          FreeType(sourceExp.expType);
4006          sourceExp.expType = null;
4007          ProcessExpressionType(sourceExp);
4008       }
4009       else
4010          FreeList(specs, FreeSpecifier);
4011
4012       FreeType(dest);
4013       FreeType(source);
4014       if(backupSourceExpType) FreeType(backupSourceExpType);
4015
4016       return true;
4017    }
4018    else
4019    {
4020       if(computedExp != nbExp)
4021       {
4022          FreeExpression(computedExp);
4023          computedExp = nbExp;
4024       }
4025
4026       while((sourceExp.type == bracketsExp || sourceExp.type == extensionExpressionExp) && sourceExp.list) sourceExp = sourceExp.list->last;
4027       if(sourceExp.type == identifierExp)
4028       {
4029          Identifier id = sourceExp.identifier;
4030          if(dest.kind == classType)
4031          {
4032             if(dest._class && dest._class.registered && dest._class.registered.type == enumClass)
4033             {
4034                Class _class = dest._class.registered;
4035                Class enumClass = eSystem_FindClass(privateModule, "enum");
4036                if(enumClass)
4037                {
4038                   for( ; _class && _class.type == ClassType::enumClass; _class = _class.base)
4039                   {
4040                      NamedLink64 value;
4041                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4042                      for(value = e.values.first; value; value = value.next)
4043                      {
4044                         if(!strcmp(value.name, id.string))
4045                            break;
4046                      }
4047                      if(value)
4048                      {
4049                         FreeType(sourceExp.expType);
4050
4051                         sourceExp.isConstant = true;
4052                         sourceExp.expType = MkClassType(_class.fullName);
4053                         if(inCompiler || inPreCompiler || inDebugger)
4054                         {
4055                            FreeExpContents(sourceExp);
4056
4057                            sourceExp.type = constantExp;
4058                            if(_class.dataTypeString && (!strcmp(_class.dataTypeString, "int") || !strcmp(_class.dataTypeString, "int64") || !strcmp(_class.dataTypeString, "short") || !strcmp(_class.dataTypeString, "char"))) // _class cannot be null here!
4059                               sourceExp.constant = PrintInt64(value.data);
4060                            else
4061                               sourceExp.constant = PrintUInt64(value.data);
4062                            //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
4063                         }
4064                         FreeType(dest);
4065                         return true;
4066                      }
4067                   }
4068                }
4069             }
4070          }
4071
4072          // Loop through all enum classes
4073          if(dest.classObjectType != typedObject && dest.kind == classType /*!= ellipsisType */&& MatchWithEnums_Module(privateModule, sourceExp, dest, id.string, conversions))
4074          {
4075             FreeType(dest);
4076             return true;
4077          }
4078       }
4079       FreeType(dest);
4080    }
4081    return false;
4082 }
4083
4084 #define TERTIARY(o, name, m, t, p) \
4085    static bool name(Expression exp, Operand op1, Operand op2, Operand op3)   \
4086    {                                                              \
4087       exp.type = constantExp;                                    \
4088       exp.string = p(op1.m ? op2.m : op3.m);                     \
4089       if(!exp.expType) \
4090          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4091       return true;                                                \
4092    }
4093
4094 #define BINARY(o, name, m, t, p) \
4095    static bool name(Expression exp, Operand op1, Operand op2)   \
4096    {                                                              \
4097       t value2 = op2.m;                                           \
4098       exp.type = constantExp;                                    \
4099       exp.string = p((t)(op1.m o value2));                     \
4100       if(!exp.expType) \
4101          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4102       return true;                                                \
4103    }
4104
4105 #define BINARY_DIVIDEINT(o, name, m, t, p) \
4106    static bool name(Expression exp, Operand op1, Operand op2)   \
4107    {                                                              \
4108       t value2 = op2.m;                                           \
4109       exp.type = constantExp;                                    \
4110       exp.string = p(value2 ? ((t)(op1.m o value2)) : 0);             \
4111       if(!exp.expType) \
4112          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4113       return true;                                                \
4114    }
4115
4116 #define BINARY_DIVIDEREAL(o, name, m, t, p) \
4117    static bool name(Expression exp, Operand op1, Operand op2)   \
4118    {                                                              \
4119       t value2 = op2.m;                                           \
4120       exp.type = constantExp;                                    \
4121       exp.string = p((t)(op1.m o value2));             \
4122       if(!exp.expType) \
4123          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4124       return true;                                                \
4125    }
4126
4127 #define UNARY(o, name, m, t, p) \
4128    static bool name(Expression exp, Operand op1)                \
4129    {                                                              \
4130       exp.type = constantExp;                                    \
4131       exp.string = p((t)(o op1.m));                                   \
4132       if(!exp.expType) \
4133          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4134       return true;                                                \
4135    }
4136
4137 #define OPERATOR_ALL(macro, o, name) \
4138    macro(o, Int##name, i, int, PrintInt) \
4139    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4140    macro(o, Int64##name, i64, int64, PrintInt64) \
4141    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4142    macro(o, Short##name, s, short, PrintShort) \
4143    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4144    macro(o, Char##name, c, char, PrintChar) \
4145    macro(o, UChar##name, uc, unsigned char, PrintUChar) \
4146    macro(o, Float##name, f, float, PrintFloat) \
4147    macro(o, Double##name, d, double, PrintDouble)
4148
4149 #define OPERATOR_INTTYPES(macro, o, name) \
4150    macro(o, Int##name, i, int, PrintInt) \
4151    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4152    macro(o, Int64##name, i64, int64, PrintInt64) \
4153    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4154    macro(o, Short##name, s, short, PrintShort) \
4155    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4156    macro(o, Char##name, c, char, PrintChar) \
4157    macro(o, UChar##name, uc, unsigned char, PrintUChar)
4158
4159 #define OPERATOR_REALTYPES(macro, o, name) \
4160    macro(o, Float##name, f, float, PrintFloat) \
4161    macro(o, Double##name, d, double, PrintDouble)
4162
4163 // binary arithmetic
4164 OPERATOR_ALL(BINARY, +, Add)
4165 OPERATOR_ALL(BINARY, -, Sub)
4166 OPERATOR_ALL(BINARY, *, Mul)
4167 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /, Div)
4168 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /, Div)
4169 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %, Mod)
4170
4171 // unary arithmetic
4172 OPERATOR_ALL(UNARY, -, Neg)
4173
4174 // unary arithmetic increment and decrement
4175 OPERATOR_ALL(UNARY, ++, Inc)
4176 OPERATOR_ALL(UNARY, --, Dec)
4177
4178 // binary arithmetic assignment
4179 OPERATOR_ALL(BINARY, =, Asign)
4180 OPERATOR_ALL(BINARY, +=, AddAsign)
4181 OPERATOR_ALL(BINARY, -=, SubAsign)
4182 OPERATOR_ALL(BINARY, *=, MulAsign)
4183 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /=, DivAsign)
4184 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /=, DivAsign)
4185 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %=, ModAsign)
4186
4187 // binary bitwise
4188 OPERATOR_INTTYPES(BINARY, &, BitAnd)
4189 OPERATOR_INTTYPES(BINARY, |, BitOr)
4190 OPERATOR_INTTYPES(BINARY, ^, BitXor)
4191 OPERATOR_INTTYPES(BINARY, <<, LShift)
4192 OPERATOR_INTTYPES(BINARY, >>, RShift)
4193
4194 // unary bitwise
4195 OPERATOR_INTTYPES(UNARY, ~, BitNot)
4196
4197 // binary bitwise assignment
4198 OPERATOR_INTTYPES(BINARY, &=, AndAsign)
4199 OPERATOR_INTTYPES(BINARY, |=, OrAsign)
4200 OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
4201 OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
4202 OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
4203
4204 // unary logical negation
4205 OPERATOR_INTTYPES(UNARY, !, Not)
4206
4207 // binary logical equality
4208 OPERATOR_ALL(BINARY, ==, Equ)
4209 OPERATOR_ALL(BINARY, !=, Nqu)
4210
4211 // binary logical
4212 OPERATOR_ALL(BINARY, &&, And)
4213 OPERATOR_ALL(BINARY, ||, Or)
4214
4215 // binary logical relational
4216 OPERATOR_ALL(BINARY, >, Grt)
4217 OPERATOR_ALL(BINARY, <, Sma)
4218 OPERATOR_ALL(BINARY, >=, GrtEqu)
4219 OPERATOR_ALL(BINARY, <=, SmaEqu)
4220
4221 // tertiary condition operator
4222 OPERATOR_INTTYPES(TERTIARY, ?, Cond)
4223
4224 //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
4225 #define OPERATOR_TABLE_ALL(name, type) \
4226     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, type##Mod, \
4227                           type##Neg, \
4228                           type##Inc, type##Dec, \
4229                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, type##ModAsign, \
4230                           type##BitAnd, type##BitOr, type##BitXor, type##LShift, type##RShift, \
4231                           type##BitNot, \
4232                           type##AndAsign, type##OrAsign, type##XorAsign, type##LShiftAsign, type##RShiftAsign, \
4233                           type##Not, \
4234                           type##Equ, type##Nqu, \
4235                           type##And, type##Or, \
4236                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu, type##Cond \
4237                         }; \
4238
4239 #define OPERATOR_TABLE_INTTYPES(name, type) \
4240     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, null, \
4241                           type##Neg, \
4242                           type##Inc, type##Dec, \
4243                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, null, \
4244                           null, null, null, null, null, \
4245                           null, \
4246                           null, null, null, null, null, \
4247                           null, \
4248                           type##Equ, type##Nqu, \
4249                           type##And, type##Or, \
4250                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu \
4251                         }; \
4252
4253 OPERATOR_TABLE_ALL(int, Int)
4254 OPERATOR_TABLE_ALL(uint, UInt)
4255 OPERATOR_TABLE_ALL(int64, Int64)
4256 OPERATOR_TABLE_ALL(uint64, UInt64)
4257 OPERATOR_TABLE_ALL(short, Short)
4258 OPERATOR_TABLE_ALL(ushort, UShort)
4259 OPERATOR_TABLE_INTTYPES(float, Float)
4260 OPERATOR_TABLE_INTTYPES(double, Double)
4261 OPERATOR_TABLE_ALL(char, Char)
4262 OPERATOR_TABLE_ALL(uchar, UChar)
4263
4264 //OpTable intOps =    {    IntAdd,    IntSub,    IntMul,    IntDiv,    IntMod,    IntExp,    IntNot,    IntBwn,    IntOr,    IntAnd,    IntEqu,    IntNqu,    IntGrt,    IntSma,    IntGrtEqu,    IntSmaEqu,    IntNeg,    IntLBitSft,    IntRBitSft };
4265 //OpTable uintOps =   {   UIntAdd,   UIntSub,   UIntMul,   UIntDiv,   UIntMod,   UIntExp,   UIntNot,   UIntBwn,   UIntOr,   UIntAnd,   UIntEqu,   UIntNqu,   UIntGrt,   UIntSma,   UIntGrtEqu,   UIntSmaEqu,   UIntNeg,   UIntLBitSft,   UIntRBitSft };
4266 //OpTable shortOps =  {  ShortAdd,  ShortSub,  ShortMul,  ShortDiv,  ShortMod,  ShortExp,  ShortNot,  ShortBwn,  ShortOr,  ShortAnd,  ShortEqu,  ShortNqu,  ShortGrt,  ShortSma,  ShortGrtEqu,  ShortSmaEqu,  ShortNeg,  ShortLBitSft,  ShortRBitSft };
4267 //OpTable ushortOps = { UShortAdd, UShortSub, UShortMul, UShortDiv, UShortMod, UShortExp, UShortNot, UShortBwn, UShortOr, UShortAnd, UShortEqu, UShortNqu, UShortGrt, UShortSma, UShortGrtEqu, UShortSmaEqu, UShortNeg, UShortLBitSft, UShortRBitSft };
4268 //OpTable floatOps =  {  FloatAdd,  FloatSub,  FloatMul,  FloatDiv,      null,      null,      null,      null,     null,      null,  FloatEqu,  FloatNqu,  FloatGrt,  FloatSma,  FloatGrtEqu,  FloatSmaEqu,  FloatNeg,          null,          null };
4269 //OpTable doubleOps = { DoubleAdd, DoubleSub, DoubleMul, DoubleDiv,      null,      null,      null,      null,     null,      null, DoubleEqu, DoubleNqu, DoubleGrt, DoubleSma, DoubleGrtEqu, DoubleSmaEqu, DoubleNeg,          null,          null };
4270 //OpTable charOps =   {   CharAdd,   CharSub,   CharMul,   CharDiv,   CharMod,   CharExp,   CharNot,   CharBwn,   CharOr,   CharAnd,   CharEqu,   CharNqu,   CharGrt,   CharSma,   CharGrtEqu,   CharSmaEqu,   CharNeg,   CharLBitSft,   CharRBitSft };
4271 //OpTable ucharOps =  {  UCharAdd,  UCharSub,  UCharMul,  UCharDiv,  UCharMod,  UCharExp,  UCharNot,  UCharBwn,  UCharOr,  UCharAnd,  UCharEqu,  UCharNqu,  UCharGrt,  UCharSma,  UCharGrtEqu,  UCharSmaEqu,  UCharNeg,  UCharLBitSft,  UCharRBitSft };
4272
4273 public void ReadString(char * output,  char * string)
4274 {
4275    int len = strlen(string);
4276    int c,d = 0;
4277    bool quoted = false, escaped = false;
4278    for(c = 0; c<len; c++)
4279    {
4280       char ch = string[c];
4281       if(escaped)
4282       {
4283          switch(ch)
4284          {
4285             case 'n': output[d] = '\n'; break;
4286             case 't': output[d] = '\t'; break;
4287             case 'a': output[d] = '\a'; break;
4288             case 'b': output[d] = '\b'; break;
4289             case 'f': output[d] = '\f'; break;
4290             case 'r': output[d] = '\r'; break;
4291             case 'v': output[d] = '\v'; break;
4292             case '\\': output[d] = '\\'; break;
4293             case '\"': output[d] = '\"'; break;
4294             case '\'': output[d] = '\''; break;
4295             default: output[d] = ch;
4296          }
4297          d++;
4298          escaped = false;
4299       }
4300       else
4301       {
4302          if(ch == '\"')
4303             quoted ^= true;
4304          else if(quoted)
4305          {
4306             if(ch == '\\')
4307                escaped = true;
4308             else
4309                output[d++] = ch;
4310          }
4311       }
4312    }
4313    output[d] = '\0';
4314 }
4315
4316 // String Unescape Copy
4317
4318 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
4319 // This is the same as ReadString above (which also misses numeric escape codes) except it doesn't handle external quotes
4320 public int UnescapeString(char * d, char * s, int len)
4321 {
4322    int j = 0, k = 0;
4323    char ch;
4324    while(j < len && (ch = s[j]))
4325    {
4326       switch(ch)
4327       {
4328          case '\\':
4329             switch((ch = s[++j]))
4330             {
4331                case 'n': d[k] = '\n'; break;
4332                case 't': d[k] = '\t'; break;
4333                case 'a': d[k] = '\a'; break;
4334                case 'b': d[k] = '\b'; break;
4335                case 'f': d[k] = '\f'; break;
4336                case 'r': d[k] = '\r'; break;
4337                case 'v': d[k] = '\v'; break;
4338                case '\\': d[k] = '\\'; break;
4339                case '\"': d[k] = '\"'; break;
4340                case '\'': d[k] = '\''; break;
4341                default: d[k] = '\\'; d[k] = ch;
4342             }
4343             break;
4344          default:
4345             d[k] = ch;
4346       }
4347       j++, k++;
4348    }
4349    d[k] = '\0';
4350    return k;
4351 }
4352
4353 public char * OffsetEscapedString(char * s, int len, int offset)
4354 {
4355    char ch;
4356    int j = 0, k = 0;
4357    while(j < len && k < offset && (ch = s[j]))
4358    {
4359       if(ch == '\\') ++j;
4360       j++, k++;
4361    }
4362    return (k == offset) ? s + j : null;
4363 }
4364
4365 public Operand GetOperand(Expression exp)
4366 {
4367    Operand op { };
4368    Type type = exp.expType;
4369    if(type)
4370    {
4371       while(type.kind == classType &&
4372          type._class.registered && (type._class.registered.type == bitClass || type._class.registered.type == unitClass || type._class.registered.type == enumClass))
4373       {
4374          if(!type._class.registered.dataType)
4375             type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
4376          type = type._class.registered.dataType;
4377
4378       }
4379       if(exp.type == stringExp && op.kind == pointerType)
4380       {
4381          op.ui64 = (uint64)(uintptr)exp.string;
4382          op.kind = pointerType;
4383          op.ops = uint64Ops;
4384       }
4385       else if(exp.isConstant && exp.type == constantExp)
4386       {
4387          op.kind = type.kind;
4388          op.type = type;
4389
4390          switch(op.kind)
4391          {
4392             case _BoolType:
4393             case charType:
4394             {
4395                if(exp.constant[0] == '\'')
4396                {
4397                   op.c = exp.constant[1];
4398                   op.ops = charOps;
4399                }
4400                else if(type.isSigned)
4401                {
4402                   op.c = (char)strtol(exp.constant, null, 0);
4403                   op.ops = charOps;
4404                }
4405                else
4406                {
4407                   op.uc = (unsigned char)strtoul(exp.constant, null, 0);
4408                   op.ops = ucharOps;
4409                }
4410                break;
4411             }
4412             case shortType:
4413                if(exp.constant[0] == '\'')
4414                {
4415                   op.s = exp.constant[1];
4416                   op.ops = shortOps;
4417                }
4418                else if(type.isSigned)
4419                {
4420                   op.s = (short)strtol(exp.constant, null, 0);
4421                   op.ops = shortOps;
4422                }
4423                else
4424                {
4425                   op.us = (unsigned short)strtoul(exp.constant, null, 0);
4426                   op.ops = ushortOps;
4427                }
4428                break;
4429             case intType:
4430             case longType:
4431                if(exp.constant[0] == '\'')
4432                {
4433                   op.i = exp.constant[1];
4434                   op.ops = intOps;
4435                }
4436                else if(type.isSigned)
4437                {
4438                   op.i = (int)strtol(exp.constant, null, 0);
4439                   op.ops = intOps;
4440                }
4441                else
4442                {
4443                   op.ui = (unsigned int)strtoul(exp.constant, null, 0);
4444                   op.ops = uintOps;
4445                }
4446                op.kind = intType;
4447                break;
4448             case int64Type:
4449                if(type.isSigned)
4450                {
4451                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4452                   op.ops = int64Ops;
4453                }
4454                else
4455                {
4456                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4457                   op.ops = uint64Ops;
4458                }
4459                op.kind = int64Type;
4460                break;
4461             case intPtrType:
4462                if(type.isSigned)
4463                {
4464                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4465                   op.ops = int64Ops;
4466                }
4467                else
4468                {
4469                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4470                   op.ops = uint64Ops;
4471                }
4472                op.kind = int64Type;
4473                break;
4474             case intSizeType:
4475                if(type.isSigned)
4476                {
4477                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4478                   op.ops = int64Ops;
4479                }
4480                else
4481                {
4482                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4483                   op.ops = uint64Ops;
4484                }
4485                op.kind = int64Type;
4486                break;
4487             case floatType:
4488                if(!strcmp(exp.constant, "inf")) op.f = float::inf();
4489                else if(!strcmp(exp.constant, "-inf")) op.f = -float::inf();
4490                else if(!strcmp(exp.constant, "nan")) op.f = float::nan();
4491                else if(!strcmp(exp.constant, "-nan")) op.f = -float::nan();
4492                else
4493                   op.f = (float)strtod(exp.constant, null);
4494                op.ops = floatOps;
4495                break;
4496             case doubleType:
4497                if(!strcmp(exp.constant, "inf")) op.d = double::inf();
4498                else if(!strcmp(exp.constant, "-inf")) op.d = -double::inf();
4499                else if(!strcmp(exp.constant, "nan")) op.d = double::nan();
4500                else if(!strcmp(exp.constant, "-nan")) op.d = -double::nan();
4501                else
4502                   op.d = (double)strtod(exp.constant, null);
4503                op.ops = doubleOps;
4504                break;
4505             //case classType:    For when we have operator overloading...
4506             // Pointer additions
4507             //case functionType:
4508             case arrayType:
4509             case pointerType:
4510             case classType:
4511                op.ui64 = _strtoui64(exp.constant, null, 0);
4512                op.kind = pointerType;
4513                op.ops = uint64Ops;
4514                // op.ptrSize =
4515                break;
4516          }
4517       }
4518    }
4519    return op;
4520 }
4521
4522 static int64 GetEnumValue(Class _class, void * ptr)
4523 {
4524    int64 v = 0;
4525    switch(_class.typeSize)
4526    {
4527       case 8:
4528          if(!strcmp(_class.dataTypeString, "uint64"))
4529             v = (int64)*(uint64 *)ptr;
4530          else
4531             v = (int64)*(int64 *)ptr;
4532          break;
4533       case 4:
4534          if(!strcmp(_class.dataTypeString, "uint"))
4535             v = (int64)*(uint *)ptr;
4536          else
4537             v = (int64)*(int *)ptr;
4538          break;
4539       case 2:
4540          if(!strcmp(_class.dataTypeString, "uint16"))
4541             v = (int64)*(uint16 *)ptr;
4542          else
4543             v = (int64)*(short *)ptr;
4544          break;
4545       case 1:
4546          if(!strcmp(_class.dataTypeString, "byte"))
4547             v = (int64)*(byte *)ptr;
4548          else
4549             v = (int64)*(char *)ptr;
4550          break;
4551    }
4552    return v;
4553 }
4554
4555 static __attribute__((unused)) void UnusedFunction()
4556 {
4557    int a;
4558    a.OnGetString(0,0,0);
4559 }
4560 default:
4561 extern int __ecereVMethodID_class_OnGetString;
4562 public:
4563
4564 static void PopulateInstanceProcessMember(Instantiation inst, OldList * memberList, DataMember parentDataMember, uint offset)
4565 {
4566    DataMember dataMember;
4567    for(dataMember = parentDataMember.members.first; dataMember; dataMember = dataMember.next)
4568    {
4569       if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4570          PopulateInstanceProcessMember(inst, memberList, dataMember, offset + dataMember.offset);
4571       else
4572       {
4573          Expression exp { };
4574          MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4575          Type type;
4576          void * ptr = inst.data + dataMember.offset + offset;
4577          char * result = null;
4578          exp.loc = member.loc = inst.loc;
4579          ((Identifier)member.identifiers->first).loc = inst.loc;
4580
4581          if(!dataMember.dataType)
4582             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4583          type = dataMember.dataType;
4584          if(type.kind == classType)
4585          {
4586             Class _class = type._class.registered;
4587             if(_class.type == enumClass)
4588             {
4589                Class enumClass = eSystem_FindClass(privateModule, "enum");
4590                if(enumClass)
4591                {
4592                   EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4593                   NamedLink64 item;
4594                   for(item = e.values.first; item; item = item.next)
4595                   {
4596                      if(item.data == GetEnumValue(_class, ptr))
4597                      {
4598                         result = item.name;
4599                         break;
4600                      }
4601                   }
4602                   if(result)
4603                   {
4604                      exp.identifier = MkIdentifier(result);
4605                      exp.type = identifierExp;
4606                      exp.destType = MkClassType(_class.fullName);
4607                      ProcessExpressionType(exp);
4608                   }
4609                }
4610             }
4611             if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4612             {
4613                if(!_class.dataType)
4614                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4615                type = _class.dataType;
4616             }
4617          }
4618          if(!result)
4619          {
4620             switch(type.kind)
4621             {
4622                case floatType:
4623                {
4624                   FreeExpContents(exp);
4625
4626                   exp.constant = PrintFloat(*(float*)ptr);
4627                   exp.type = constantExp;
4628                   break;
4629                }
4630                case doubleType:
4631                {
4632                   FreeExpContents(exp);
4633
4634                   exp.constant = PrintDouble(*(double*)ptr);
4635                   exp.type = constantExp;
4636                   break;
4637                }
4638                case intType:
4639                {
4640                   FreeExpContents(exp);
4641
4642                   exp.constant = PrintInt(*(int*)ptr);
4643                   exp.type = constantExp;
4644                   break;
4645                }
4646                case int64Type:
4647                {
4648                   FreeExpContents(exp);
4649
4650                   exp.constant = PrintInt64(*(int64*)ptr);
4651                   exp.type = constantExp;
4652                   break;
4653                }
4654                case intPtrType:
4655                {
4656                   FreeExpContents(exp);
4657                   // TODO: This should probably use proper type
4658                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4659                   exp.type = constantExp;
4660                   break;
4661                }
4662                case intSizeType:
4663                {
4664                   FreeExpContents(exp);
4665                   // TODO: This should probably use proper type
4666                   exp.constant = PrintInt64((int64)*(intsize*)ptr);
4667                   exp.type = constantExp;
4668                   break;
4669                }
4670                default:
4671                   Compiler_Error($"Unhandled type populating instance\n");
4672             }
4673          }
4674          ListAdd(memberList, member);
4675       }
4676
4677       if(parentDataMember.type == unionMember)
4678          break;
4679    }
4680 }
4681
4682 void PopulateInstance(Instantiation inst)
4683 {
4684    Symbol classSym = inst._class.symbol; // FindClass(inst._class.name);
4685    Class _class = classSym.registered;
4686    DataMember dataMember;
4687    OldList * memberList = MkList();
4688    // Added this check and ->Add to prevent memory leaks on bad code
4689    if(!inst.members)
4690       inst.members = MkListOne(MkMembersInitList(memberList));
4691    else
4692       inst.members->Add(MkMembersInitList(memberList));
4693    for(dataMember = _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
4694    {
4695       if(!dataMember.isProperty)
4696       {
4697          if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4698             PopulateInstanceProcessMember(inst, memberList, dataMember, dataMember.offset);
4699          else
4700          {
4701             Expression exp { };
4702             MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4703             Type type;
4704             void * ptr = inst.data + dataMember.offset;
4705             char * result = null;
4706
4707             exp.loc = member.loc = inst.loc;
4708             ((Identifier)member.identifiers->first).loc = inst.loc;
4709
4710             if(!dataMember.dataType)
4711                dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4712             type = dataMember.dataType;
4713             if(type.kind == classType)
4714             {
4715                Class _class = type._class.registered;
4716                if(_class.type == enumClass)
4717                {
4718                   Class enumClass = eSystem_FindClass(privateModule, "enum");
4719                   if(enumClass)
4720                   {
4721                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4722                      NamedLink64 item;
4723                      for(item = e.values.first; item; item = item.next)
4724                      {
4725                         if(item.data == GetEnumValue(_class, ptr))
4726                         {
4727                            result = item.name;
4728                            break;
4729                         }
4730                      }
4731                   }
4732                   if(result)
4733                   {
4734                      exp.identifier = MkIdentifier(result);
4735                      exp.type = identifierExp;
4736                      exp.destType = MkClassType(_class.fullName);
4737                      ProcessExpressionType(exp);
4738                   }
4739                }
4740                if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4741                {
4742                   if(!_class.dataType)
4743                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4744                   type = _class.dataType;
4745                }
4746             }
4747             if(!result)
4748             {
4749                switch(type.kind)
4750                {
4751                   case floatType:
4752                   {
4753                      exp.constant = PrintFloat(*(float*)ptr);
4754                      exp.type = constantExp;
4755                      break;
4756                   }
4757                   case doubleType:
4758                   {
4759                      exp.constant = PrintDouble(*(double*)ptr);
4760                      exp.type = constantExp;
4761                      break;
4762                   }
4763                   case intType:
4764                   {
4765                      exp.constant = PrintInt(*(int*)ptr);
4766                      exp.type = constantExp;
4767                      break;
4768                   }
4769                   case int64Type:
4770                   {
4771                      exp.constant = PrintInt64(*(int64*)ptr);
4772                      exp.type = constantExp;
4773                      break;
4774                   }
4775                   case intPtrType:
4776                   {
4777                      exp.constant = PrintInt64((int64)*(intptr*)ptr);
4778                      exp.type = constantExp;
4779                      break;
4780                   }
4781                   default:
4782                      Compiler_Error($"Unhandled type populating instance\n");
4783                }
4784             }
4785             ListAdd(memberList, member);
4786          }
4787       }
4788    }
4789 }
4790
4791 void ComputeInstantiation(Expression exp)
4792 {
4793    Instantiation inst = exp.instance;
4794    MembersInit members;
4795    Symbol classSym = inst._class ? inst._class.symbol : null; // FindClass(inst._class.name);
4796    Class _class = classSym ? classSym.registered : null;
4797    DataMember curMember = null;
4798    Class curClass = null;
4799    DataMember subMemberStack[256];
4800    int subMemberStackPos = 0;
4801    uint64 bits = 0;
4802
4803    if(_class && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass ))
4804    {
4805       // Don't recompute the instantiation...
4806       // Non Simple classes will have become constants by now
4807       if(inst.data)
4808          return;
4809
4810       if(_class.type == normalClass || _class.type == noHeadClass)
4811       {
4812          inst.data = (byte *)eInstance_New(_class);
4813          if(_class.type == normalClass)
4814             ((Instance)inst.data)._refCount++;
4815       }
4816       else
4817          inst.data = new0 byte[_class.structSize];
4818    }
4819
4820    if(inst.members)
4821    {
4822       for(members = inst.members->first; members; members = members.next)
4823       {
4824          switch(members.type)
4825          {
4826             case dataMembersInit:
4827             {
4828                if(members.dataMembers)
4829                {
4830                   MemberInit member;
4831                   for(member = members.dataMembers->first; member; member = member.next)
4832                   {
4833                      Identifier ident = member.identifiers ? member.identifiers->first : null;
4834                      bool found = false;
4835
4836                      Property prop = null;
4837                      DataMember dataMember = null;
4838                      uint dataMemberOffset;
4839
4840                      if(!ident)
4841                      {
4842                         eClass_FindNextMember(_class, &curClass, &curMember, subMemberStack, &subMemberStackPos);
4843                         if(curMember)
4844                         {
4845                            if(curMember.isProperty)
4846                               prop = (Property)curMember;
4847                            else
4848                            {
4849                               dataMember = curMember;
4850
4851                               // CHANGED THIS HERE
4852                               eClass_FindDataMemberAndOffset(_class, dataMember.name, &dataMemberOffset, privateModule, null, null);
4853
4854                               // 2013/17/29 -- It seems that this was missing here!
4855                               if(_class.type == normalClass)
4856                                  dataMemberOffset += _class.base.structSize;
4857                               // dataMemberOffset = dataMember.offset;
4858                            }
4859                            found = true;
4860                         }
4861                      }
4862                      else
4863                      {
4864                         prop = eClass_FindProperty(_class, ident.string, privateModule);
4865                         if(prop)
4866                         {
4867                            found = true;
4868                            if(prop.memberAccess == publicAccess)
4869                            {
4870                               curMember = (DataMember)prop;
4871                               curClass = prop._class;
4872                            }
4873                         }
4874                         else
4875                         {
4876                            DataMember _subMemberStack[256];
4877                            int _subMemberStackPos = 0;
4878
4879                            // FILL MEMBER STACK
4880                            dataMember = eClass_FindDataMemberAndOffset(_class, ident.string, &dataMemberOffset, privateModule, _subMemberStack, &_subMemberStackPos);
4881
4882                            if(dataMember)
4883                            {
4884                               found = true;
4885                               if(dataMember.memberAccess == publicAccess)
4886                               {
4887                                  curMember = dataMember;
4888                                  curClass = dataMember._class;
4889                                  memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
4890                                  subMemberStackPos = _subMemberStackPos;
4891                               }
4892                            }
4893                         }
4894                      }
4895
4896                      if(found && member.initializer && member.initializer.type == expInitializer)
4897                      {
4898                         Expression value = member.initializer.exp;
4899                         Type type = null;
4900                         bool deepMember = false;
4901                         if(prop)
4902                         {
4903                            type = prop.dataType;
4904                         }
4905                         else if(dataMember)
4906                         {
4907                            if(!dataMember.dataType)
4908                               dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4909
4910                            type = dataMember.dataType;
4911                         }
4912
4913                         if(ident && ident.next)
4914                         {
4915                            deepMember = true;
4916
4917                            // for(; ident && type; ident = ident.next)
4918                            for(ident = ident.next; ident && type; ident = ident.next)
4919                            {
4920                               if(type.kind == classType)
4921                               {
4922                                  prop = eClass_FindProperty(type._class.registered,
4923                                     ident.string, privateModule);
4924                                  if(prop)
4925                                     type = prop.dataType;
4926                                  else
4927                                  {
4928                                     dataMember = eClass_FindDataMemberAndOffset(type._class.registered,
4929                                        ident.string, &dataMemberOffset, privateModule, null, null);
4930                                     if(dataMember)
4931                                        type = dataMember.dataType;
4932                                  }
4933                               }
4934                               else if(type.kind == structType || type.kind == unionType)
4935                               {
4936                                  Type memberType;
4937                                  for(memberType = type.members.first; memberType; memberType = memberType.next)
4938                                  {
4939                                     if(!strcmp(memberType.name, ident.string))
4940                                     {
4941                                        type = memberType;
4942                                        break;
4943                                     }
4944                                  }
4945                               }
4946                            }
4947                         }
4948                         if(value)
4949                         {
4950                            FreeType(value.destType);
4951                            value.destType = type;
4952                            if(type) type.refCount++;
4953                            ComputeExpression(value);
4954                         }
4955                         if(!deepMember && type && value && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass /*&& value.expType.kind == type.kind*/))
4956                         {
4957                            if(type.kind == classType)
4958                            {
4959                               Class _class = type._class.registered;
4960                               if(_class && (_class.type == bitClass || _class.type == unitClass || _class.type == enumClass))
4961                               {
4962                                  if(!_class.dataType)
4963                                     _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4964                                  type = _class.dataType;
4965                               }
4966                            }
4967
4968                            if(dataMember)
4969                            {
4970                               void * ptr = inst.data + dataMemberOffset;
4971
4972                               if(value.type == constantExp)
4973                               {
4974                                  switch(type.kind)
4975                                  {
4976                                     case intType:
4977                                     {
4978                                        GetInt(value, (int*)ptr);
4979                                        break;
4980                                     }
4981                                     case int64Type:
4982                                     {
4983                                        GetInt64(value, (int64*)ptr);
4984                                        break;
4985                                     }
4986                                     case intPtrType:
4987                                     {
4988                                        GetIntPtr(value, (intptr*)ptr);
4989                                        break;
4990                                     }
4991                                     case intSizeType:
4992                                     {
4993                                        GetIntSize(value, (intsize*)ptr);
4994                                        break;
4995                                     }
4996                                     case floatType:
4997                                     {
4998                                        GetFloat(value, (float*)ptr);
4999                                        break;
5000                                     }
5001                                     case doubleType:
5002                                     {
5003                                        GetDouble(value, (double *)ptr);
5004                                        break;
5005                                     }
5006                                  }
5007                               }
5008                               else if(value.type == instanceExp)
5009                               {
5010                                  if(type.kind == classType)
5011                                  {
5012                                     Class _class = type._class.registered;
5013                                     if(_class.type == structClass)
5014                                     {
5015                                        ComputeTypeSize(type);
5016                                        if(value.instance.data)
5017                                           memcpy(ptr, value.instance.data, type.size);
5018                                     }
5019                                  }
5020                               }
5021                            }
5022                            else if(prop && prop.Set != (void *)(intptr)1)
5023                            {
5024                               if(value.type == instanceExp && value.instance.data)
5025                               {
5026                                  if(type.kind == classType)
5027                                  {
5028                                     Class _class = type._class.registered;
5029                                     if(_class && (_class.type != normalClass || eClass_IsDerived(((Instance)value.instance.data)._class, _class)))
5030                                     {
5031                                        void (*Set)(void *, void *) = (void *)prop.Set;
5032                                        Set(inst.data, value.instance.data);
5033                                        PopulateInstance(inst);
5034                                     }
5035                                  }
5036                               }
5037                               else if(value.type == constantExp)
5038                               {
5039                                  switch(type.kind)
5040                                  {
5041                                     case doubleType:
5042                                     {
5043                                        void (*Set)(void *, double) = (void *)prop.Set;
5044                                        Set(inst.data, strtod(value.constant, null) );
5045                                        break;
5046                                     }
5047                                     case floatType:
5048                                     {
5049                                        void (*Set)(void *, float) = (void *)prop.Set;
5050                                        Set(inst.data, (float)(strtod(value.constant, null)));
5051                                        break;
5052                                     }
5053                                     case intType:
5054                                     {
5055                                        void (*Set)(void *, int) = (void *)prop.Set;
5056                                        Set(inst.data, (int)strtol(value.constant, null, 0));
5057                                        break;
5058                                     }
5059                                     case int64Type:
5060                                     {
5061                                        void (*Set)(void *, int64) = (void *)prop.Set;
5062                                        Set(inst.data, _strtoi64(value.constant, null, 0));
5063                                        break;
5064                                     }
5065                                     case intPtrType:
5066                                     {
5067                                        void (*Set)(void *, intptr) = (void *)prop.Set;
5068                                        Set(inst.data, (intptr)_strtoi64(value.constant, null, 0));
5069                                        break;
5070                                     }
5071                                     case intSizeType:
5072                                     {
5073                                        void (*Set)(void *, intsize) = (void *)prop.Set;
5074                                        Set(inst.data, (intsize)_strtoi64(value.constant, null, 0));
5075                                        break;
5076                                     }
5077                                  }
5078                               }
5079                               else if(value.type == stringExp)
5080                               {
5081                                  char temp[1024];
5082                                  ReadString(temp, value.string);
5083                                  ((void (*)(void *, void *))(void *)prop.Set)(inst.data, temp);
5084                               }
5085                            }
5086                         }
5087                         else if(!deepMember && type && _class.type == unitClass)
5088                         {
5089                            if(prop)
5090                            {
5091                               // Only support converting units to units for now...
5092                               if(value.type == constantExp)
5093                               {
5094                                  if(type.kind == classType)
5095                                  {
5096                                     Class _class = type._class.registered;
5097                                     if(_class.type == unitClass)
5098                                     {
5099                                        if(!_class.dataType)
5100                                           _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5101                                        type = _class.dataType;
5102                                     }
5103                                  }
5104                                  // TODO: Assuming same base type for units...
5105                                  switch(type.kind)
5106                                  {
5107                                     case floatType:
5108                                     {
5109                                        float fValue;
5110                                        float (*Set)(float) = (void *)prop.Set;
5111                                        GetFloat(member.initializer.exp, &fValue);
5112                                        exp.constant = PrintFloat(Set(fValue));
5113                                        exp.type = constantExp;
5114                                        break;
5115                                     }
5116                                     case doubleType:
5117                                     {
5118                                        double dValue;
5119                                        double (*Set)(double) = (void *)prop.Set;
5120                                        GetDouble(member.initializer.exp, &dValue);
5121                                        exp.constant = PrintDouble(Set(dValue));
5122                                        exp.type = constantExp;
5123                                        break;
5124                                     }
5125                                  }
5126                               }
5127                            }
5128                         }
5129                         else if(!deepMember && type && _class.type == bitClass)
5130                         {
5131                            if(prop)
5132                            {
5133                               if(value.type == instanceExp && value.instance.data)
5134                               {
5135                                  unsigned int (*Set)(void *) = (void *)prop.Set;
5136                                  bits = Set(value.instance.data);
5137                               }
5138                               else if(value.type == constantExp)
5139                               {
5140                               }
5141                            }
5142                            else if(dataMember)
5143                            {
5144                               BitMember bitMember = (BitMember) dataMember;
5145                               Type type;
5146                               uint64 part = 0;
5147                               bits = (bits & ~bitMember.mask);
5148                               if(!bitMember.dataType)
5149                                  bitMember.dataType = ProcessTypeString(bitMember.dataTypeString, false);
5150                               type = bitMember.dataType;
5151                               if(type.kind == classType && type._class && type._class.registered)
5152                               {
5153                                  if(!type._class.registered.dataType)
5154                                     type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
5155                                  type = type._class.registered.dataType;
5156                               }
5157                               switch(type.kind)
5158                               {
5159                                  case _BoolType:
5160                                  case charType:       { byte v; type.isSigned ? GetChar(value, (char *)&v) : GetUChar(value, &v); part = (uint64)v; break; }
5161                                  case shortType:      { uint16 v; type.isSigned ? GetShort(value, (short *)&v) : GetUShort(value, &v); part = (uint64)v; break; }
5162                                  case intType:
5163                                  case longType:       { uint v; type.isSigned ? GetInt(value, (int *)&v) : GetUInt(value, &v); part = (uint64)v; break; }
5164                                  case int64Type:      { uint64 v; type.isSigned ? GetInt64(value, (int64 *)&v) : GetUInt64(value, &v); part = (uint64)v; break; }
5165                                  case intPtrType:     { uintptr v; type.isSigned ? GetIntPtr(value, (intptr *)&v) : GetUIntPtr(value, &v); part = (uint64)v; break; }
5166                                  case intSizeType:    { uintsize v; type.isSigned ? GetIntSize(value, (intsize *)&v) : GetUIntSize(value, &v); part = (uint64)v; break; }
5167                               }
5168                               bits |= part << bitMember.pos;
5169                            }
5170                         }
5171                      }
5172                      else
5173                      {
5174                         if(_class && _class.type == unitClass)
5175                         {
5176                            ComputeExpression(member.initializer.exp);
5177                            exp.constant = member.initializer.exp.constant;
5178                            exp.type = constantExp;
5179
5180                            member.initializer.exp.constant = null;
5181                         }
5182                      }
5183                   }
5184                }
5185                break;
5186             }
5187          }
5188       }
5189    }
5190    if(_class && _class.type == bitClass)
5191    {
5192       exp.constant = PrintHexUInt(bits);
5193       exp.type = constantExp;
5194    }
5195    if(exp.type != instanceExp)
5196    {
5197       FreeInstance(inst);
5198    }
5199 }
5200
5201 static bool Promote(Operand op, TypeKind kind, bool isSigned)
5202 {
5203    bool result = false;
5204    switch(kind)
5205    {
5206       case shortType:
5207          if(op.kind == charType || op.kind == enumType || op.kind == _BoolType)
5208             result = isSigned ? GetOpShort(op, &op.s) : GetOpUShort(op, &op.us);
5209          break;
5210       case intType:
5211       case longType:
5212          if(op.kind == charType || op.kind == shortType || op.kind == enumType || op.kind == _BoolType)
5213             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5214          break;
5215       case int64Type:
5216          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5217             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5218             result = isSigned ? GetOpInt64(op, &op.i64) : GetOpUInt64(op, &op.ui64);
5219          break;
5220       case floatType:
5221          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType ||
5222             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5223             result = GetOpFloat(op, &op.f);
5224          break;
5225       case doubleType:
5226          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType ||
5227             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5228             result = GetOpDouble(op, &op.d);
5229          break;
5230       case pointerType:
5231          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5232             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5233             result = GetOpUInt64 /*GetOpUIntPtr*/(op, &op.ui64);
5234          break;
5235       case enumType:
5236          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5237             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5238             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5239          break;
5240       case intPtrType:
5241          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5242             result = isSigned ? GetOpInt64 /*GetOpIntPtr*/(op, &op.i64) : GetOpUInt64 /*GetOpUIntPtr*/(op, &op.ui64);
5243          break;
5244       case intSizeType:
5245          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5246             result = isSigned ? GetOpInt64 /*GetOpIntSize*/(op, &op.i64) : GetOpUInt64 /*GetOpUIntSize*/(op, &op.ui64);
5247          break;
5248    }
5249    return result;
5250 }
5251
5252 void CallOperator(Expression exp, Expression exp1, Expression exp2, Operand op1, Operand op2)
5253 {
5254    if(exp.op.op == SIZEOF)
5255    {
5256       FreeExpContents(exp);
5257       exp.type = constantExp;
5258       exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5259    }
5260    else
5261    {
5262       if(!exp.op.exp1)
5263       {
5264          switch(exp.op.op)
5265          {
5266             // unary arithmetic
5267             case '+':
5268             {
5269                // Provide default unary +
5270                Expression exp2 = exp.op.exp2;
5271                exp.op.exp2 = null;
5272                FreeExpContents(exp);
5273                FreeType(exp.expType);
5274                FreeType(exp.destType);
5275                *exp = *exp2;
5276                delete exp2;
5277                break;
5278             }
5279             case '-':
5280                if(op1.ops.Neg) { FreeExpContents(exp); op1.ops.Neg(exp, op1); }
5281                break;
5282             // unary arithmetic increment and decrement
5283                   //OPERATOR_ALL(UNARY, ++, Inc)
5284                   //OPERATOR_ALL(UNARY, --, Dec)
5285             // unary bitwise
5286             case '~':
5287                if(op1.ops.BitNot) { FreeExpContents(exp); op1.ops.BitNot(exp, op1); }
5288                break;
5289             // unary logical negation
5290             case '!':
5291                if(op1.ops.Not) { FreeExpContents(exp); op1.ops.Not(exp, op1); }
5292                break;
5293          }
5294       }
5295       else
5296       {
5297          if(op1 && op2 && op1.type && op2.type && op1.kind != op2.kind)
5298          {
5299             if(Promote(op2, op1.kind, op1.type.isSigned))
5300                op2.kind = op1.kind, op2.ops = op1.ops;
5301             else if(Promote(op1, op2.kind, op2.type.isSigned))
5302                op1.kind = op2.kind, op1.ops = op2.ops;
5303          }
5304          switch(exp.op.op)
5305          {
5306             // binary arithmetic
5307             case '+':
5308                if(op1.ops.Add) { FreeExpContents(exp); op1.ops.Add(exp, op1, op2); }
5309                break;
5310             case '-':
5311                if(op1.ops.Sub) { FreeExpContents(exp); op1.ops.Sub(exp, op1, op2); }
5312                break;
5313             case '*':
5314                if(op1.ops.Mul) { FreeExpContents(exp); op1.ops.Mul(exp, op1, op2); }
5315                break;
5316             case '/':
5317                if(op1.ops.Div) { FreeExpContents(exp); op1.ops.Div(exp, op1, op2); }
5318                break;
5319             case '%':
5320                if(op1.ops.Mod) { FreeExpContents(exp); op1.ops.Mod(exp, op1, op2); }
5321                break;
5322             // binary arithmetic assignment
5323                   //OPERATOR_ALL(BINARY, =, Asign)
5324                   //OPERATOR_ALL(BINARY, +=, AddAsign)
5325                   //OPERATOR_ALL(BINARY, -=, SubAsign)
5326                   //OPERATOR_ALL(BINARY, *=, MulAsign)
5327                   //OPERATOR_ALL(BINARY, /=, DivAsign)
5328                   //OPERATOR_ALL(BINARY, %=, ModAsign)
5329             // binary bitwise
5330             case '&':
5331                if(exp.op.exp2)
5332                {
5333                   if(op1.ops.BitAnd) { FreeExpContents(exp); op1.ops.BitAnd(exp, op1, op2); }
5334                }
5335                break;
5336             case '|':
5337                if(op1.ops.BitOr) { FreeExpContents(exp); op1.ops.BitOr(exp, op1, op2); }
5338                break;
5339             case '^':
5340                if(op1.ops.BitXor) { FreeExpContents(exp); op1.ops.BitXor(exp, op1, op2); }
5341                break;
5342             case LEFT_OP:
5343                if(op1.ops.LShift) { FreeExpContents(exp); op1.ops.LShift(exp, op1, op2); }
5344                break;
5345             case RIGHT_OP:
5346                if(op1.ops.RShift) { FreeExpContents(exp); op1.ops.RShift(exp, op1, op2); }
5347                break;
5348             // binary bitwise assignment
5349                   //OPERATOR_INTTYPES(BINARY, &=, AndAsign)
5350                   //OPERATOR_INTTYPES(BINARY, |=, OrAsign)
5351                   //OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
5352                   //OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
5353                   //OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
5354             // binary logical equality
5355             case EQ_OP:
5356                if(op1.ops.Equ) { FreeExpContents(exp); op1.ops.Equ(exp, op1, op2); }
5357                break;
5358             case NE_OP:
5359                if(op1.ops.Nqu) { FreeExpContents(exp); op1.ops.Nqu(exp, op1, op2); }
5360                break;
5361             // binary logical
5362             case AND_OP:
5363                if(op1.ops.And) { FreeExpContents(exp); op1.ops.And(exp, op1, op2); }
5364                break;
5365             case OR_OP:
5366                if(op1.ops.Or) { FreeExpContents(exp); op1.ops.Or(exp, op1, op2); }
5367                break;
5368             // binary logical relational
5369             case '>':
5370                if(op1.ops.Grt) { FreeExpContents(exp); op1.ops.Grt(exp, op1, op2); }
5371                break;
5372             case '<':
5373                if(op1.ops.Sma) { FreeExpContents(exp); op1.ops.Sma(exp, op1, op2); }
5374                break;
5375             case GE_OP:
5376                if(op1.ops.GrtEqu) { FreeExpContents(exp); op1.ops.GrtEqu(exp, op1, op2); }
5377                break;
5378             case LE_OP:
5379                if(op1.ops.SmaEqu) { FreeExpContents(exp); op1.ops.SmaEqu(exp, op1, op2); }
5380                break;
5381          }
5382       }
5383    }
5384 }
5385
5386 void ComputeExpression(Expression exp)
5387 {
5388 #ifdef _DEBUG
5389    char expString[10240];
5390    expString[0] = '\0';
5391    PrintExpression(exp, expString);
5392 #endif
5393
5394    switch(exp.type)
5395    {
5396       case identifierExp:
5397       {
5398          Identifier id = exp.identifier;
5399          if(id && exp.isConstant && !inCompiler && !inPreCompiler && !inDebugger)
5400          {
5401             Class c = (exp.expType && exp.expType.kind == classType && exp.expType._class) ? exp.expType._class.registered : null;
5402             if(c && c.type == enumClass)
5403             {
5404                Class enumClass = eSystem_FindClass(privateModule, "enum");
5405                if(enumClass)
5406                {
5407                   NamedLink64 value;
5408                   EnumClassData e = ACCESS_CLASSDATA(c, enumClass);
5409                   for(value = e.values.first; value; value = value.next)
5410                   {
5411                      if(!strcmp(value.name, id.string))
5412                         break;
5413                   }
5414                   if(value)
5415                   {
5416                      const String dts = c.dataTypeString;
5417                      FreeExpContents(exp);
5418                      exp.type = constantExp;
5419                      exp.constant = (dts && (!strcmp(dts, "int") || !strcmp(dts, "int64") || !strcmp(dts, "short") || !strcmp(dts, "char"))) ? PrintInt64(value.data) : PrintUInt64(value.data);
5420                   }
5421                }
5422             }
5423          }
5424          break;
5425       }
5426       case instanceExp:
5427       {
5428          ComputeInstantiation(exp);
5429          break;
5430       }
5431       /*
5432       case constantExp:
5433          break;
5434       */
5435       case opExp:
5436       {
5437          Expression exp1, exp2 = null;
5438          Operand op1 { };
5439          Operand op2 { };
5440
5441          // We don't care about operations with only exp2 (INC_OP, DEC_OP...)
5442          if(exp.op.exp2)
5443          {
5444             Expression e = exp.op.exp2;
5445
5446             while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
5447             {
5448                if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
5449                {
5450                   if(e.type == extensionCompoundExp)
5451                      e = ((Statement)e.compound.compound.statements->last).expressions->last;
5452                   else
5453                      e = e.list->last;
5454                }
5455             }
5456             if(exp.op.op == TokenType::sizeOf && e && e.expType)
5457             {
5458                if(e.type == stringExp && e.string)
5459                {
5460                   char * string = e.string;
5461                   int len = strlen(string);
5462                   char * tmp = new char[len-2+1];
5463                   len = UnescapeString(tmp, string + 1, len - 2);
5464                   delete tmp;
5465                   FreeExpContents(exp);
5466                   exp.type = constantExp;
5467                   exp.constant = PrintUInt(len + 1);
5468                }
5469                else
5470                {
5471                   Type type = e.expType;
5472                   type.refCount++;
5473                   FreeExpContents(exp);
5474                   exp.type = constantExp;
5475                   exp.constant = PrintUInt(ComputeTypeSize(type));
5476                   FreeType(type);
5477                }
5478                break;
5479             }
5480             else
5481                ComputeExpression(exp.op.exp2);
5482          }
5483          if(exp.op.exp1)
5484          {
5485             ComputeExpression(exp.op.exp1);
5486             exp1 = exp.op.exp1;
5487             exp2 = exp.op.exp2;
5488             op1 = GetOperand(exp1);
5489             if(op1.type) op1.type.refCount++;
5490             if(exp2)
5491             {
5492                op2 = GetOperand(exp2);
5493                if(op2.type) op2.type.refCount++;
5494             }
5495          }
5496          else
5497          {
5498             exp1 = exp.op.exp2;
5499             op1 = GetOperand(exp1);
5500             if(op1.type) op1.type.refCount++;
5501          }
5502
5503          CallOperator(exp, exp1, exp2, op1, op2);
5504          /*
5505          switch(exp.op.op)
5506          {
5507             // Unary operators
5508             case '&':
5509                // Also binary
5510                if(exp.op.exp1 && exp.op.exp2)
5511                {
5512                   // Binary And
5513                   if(op1.ops.BitAnd)
5514                   {
5515                      FreeExpContents(exp);
5516                      op1.ops.BitAnd(exp, op1, op2);
5517                   }
5518                }
5519                break;
5520             case '*':
5521                if(exp.op.exp1)
5522                {
5523                   if(op1.ops.Mul)
5524                   {
5525                      FreeExpContents(exp);
5526                      op1.ops.Mul(exp, op1, op2);
5527                   }
5528                }
5529                break;
5530             case '+':
5531                if(exp.op.exp1)
5532                {
5533                   if(op1.ops.Add)
5534                   {
5535                      FreeExpContents(exp);
5536                      op1.ops.Add(exp, op1, op2);
5537                   }
5538                }
5539                else
5540                {
5541                   // Provide default unary +
5542                   Expression exp2 = exp.op.exp2;
5543                   exp.op.exp2 = null;
5544                   FreeExpContents(exp);
5545                   FreeType(exp.expType);
5546                   FreeType(exp.destType);
5547
5548                   *exp = *exp2;
5549                   delete exp2;
5550                }
5551                break;
5552             case '-':
5553                if(exp.op.exp1)
5554                {
5555                   if(op1.ops.Sub)
5556                   {
5557                      FreeExpContents(exp);
5558                      op1.ops.Sub(exp, op1, op2);
5559                   }
5560                }
5561                else
5562                {
5563                   if(op1.ops.Neg)
5564                   {
5565                      FreeExpContents(exp);
5566                      op1.ops.Neg(exp, op1);
5567                   }
5568                }
5569                break;
5570             case '~':
5571                if(op1.ops.BitNot)
5572                {
5573                   FreeExpContents(exp);
5574                   op1.ops.BitNot(exp, op1);
5575                }
5576                break;
5577             case '!':
5578                if(op1.ops.Not)
5579                {
5580                   FreeExpContents(exp);
5581                   op1.ops.Not(exp, op1);
5582                }
5583                break;
5584             // Binary only operators
5585             case '/':
5586                if(op1.ops.Div)
5587                {
5588                   FreeExpContents(exp);
5589                   op1.ops.Div(exp, op1, op2);
5590                }
5591                break;
5592             case '%':
5593                if(op1.ops.Mod)
5594                {
5595                   FreeExpContents(exp);
5596                   op1.ops.Mod(exp, op1, op2);
5597                }
5598                break;
5599             case LEFT_OP:
5600                break;
5601             case RIGHT_OP:
5602                break;
5603             case '<':
5604                if(exp.op.exp1)
5605                {
5606                   if(op1.ops.Sma)
5607                   {
5608                      FreeExpContents(exp);
5609                      op1.ops.Sma(exp, op1, op2);
5610                   }
5611                }
5612                break;
5613             case '>':
5614                if(exp.op.exp1)
5615                {
5616                   if(op1.ops.Grt)
5617                   {
5618                      FreeExpContents(exp);
5619                      op1.ops.Grt(exp, op1, op2);
5620                   }
5621                }
5622                break;
5623             case LE_OP:
5624                if(exp.op.exp1)
5625                {
5626                   if(op1.ops.SmaEqu)
5627                   {
5628                      FreeExpContents(exp);
5629                      op1.ops.SmaEqu(exp, op1, op2);
5630                   }
5631                }
5632                break;
5633             case GE_OP:
5634                if(exp.op.exp1)
5635                {
5636                   if(op1.ops.GrtEqu)
5637                   {
5638                      FreeExpContents(exp);
5639                      op1.ops.GrtEqu(exp, op1, op2);
5640                   }
5641                }
5642                break;
5643             case EQ_OP:
5644                if(exp.op.exp1)
5645                {
5646                   if(op1.ops.Equ)
5647                   {
5648                      FreeExpContents(exp);
5649                      op1.ops.Equ(exp, op1, op2);
5650                   }
5651                }
5652                break;
5653             case NE_OP:
5654                if(exp.op.exp1)
5655                {
5656                   if(op1.ops.Nqu)
5657                   {
5658                      FreeExpContents(exp);
5659                      op1.ops.Nqu(exp, op1, op2);
5660                   }
5661                }
5662                break;
5663             case '|':
5664                if(op1.ops.BitOr)
5665                {
5666                   FreeExpContents(exp);
5667                   op1.ops.BitOr(exp, op1, op2);
5668                }
5669                break;
5670             case '^':
5671                if(op1.ops.BitXor)
5672                {
5673                   FreeExpContents(exp);
5674                   op1.ops.BitXor(exp, op1, op2);
5675                }
5676                break;
5677             case AND_OP:
5678                break;
5679             case OR_OP:
5680                break;
5681             case SIZEOF:
5682                FreeExpContents(exp);
5683                exp.type = constantExp;
5684                exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5685                break;
5686          }
5687          */
5688          if(op1.type) FreeType(op1.type);
5689          if(op2.type) FreeType(op2.type);
5690          break;
5691       }
5692       case bracketsExp:
5693       case extensionExpressionExp:
5694       {
5695          Expression e, n;
5696          for(e = exp.list->first; e; e = n)
5697          {
5698             n = e.next;
5699             if(!n)
5700             {
5701                OldList * list = exp.list;
5702                Expression prev = exp.prev;
5703                Expression next = exp.next;
5704                ComputeExpression(e);
5705                //FreeExpContents(exp);
5706                FreeType(exp.expType);
5707                FreeType(exp.destType);
5708                *exp = *e;
5709                exp.prev = prev;
5710                exp.next = next;
5711                delete e;
5712                delete list;
5713             }
5714             else
5715             {
5716                FreeExpression(e);
5717             }
5718          }
5719          break;
5720       }
5721       /*
5722
5723       case ExpIndex:
5724       {
5725          Expression e;
5726          exp.isConstant = true;
5727
5728          ComputeExpression(exp.index.exp);
5729          if(!exp.index.exp.isConstant)
5730             exp.isConstant = false;
5731
5732          for(e = exp.index.index->first; e; e = e.next)
5733          {
5734             ComputeExpression(e);
5735             if(!e.next)
5736             {
5737                // Check if this type is int
5738             }
5739             if(!e.isConstant)
5740                exp.isConstant = false;
5741          }
5742          exp.expType = Dereference(exp.index.exp.expType);
5743          break;
5744       }
5745       */
5746       case memberExp:
5747       {
5748          Expression memberExp = exp.member.exp;
5749          Identifier memberID = exp.member.member;
5750
5751          Type type;
5752          ComputeExpression(exp.member.exp);
5753          type = exp.member.exp.expType;
5754          if(type)
5755          {
5756             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);
5757             Property prop = null;
5758             DataMember member = null;
5759             Class convertTo = null;
5760             if(type.kind == subClassType && exp.member.exp.type == classExp)
5761                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
5762
5763             if(!_class)
5764             {
5765                char string[256];
5766                Symbol classSym;
5767                string[0] = '\0';
5768                PrintTypeNoConst(type, string, false, true);
5769                classSym = FindClass(string);
5770                _class = classSym ? classSym.registered : null;
5771             }
5772
5773             if(exp.member.member)
5774             {
5775                prop = eClass_FindProperty(_class, exp.member.member.string, privateModule);
5776                if(!prop)
5777                   member = eClass_FindDataMember(_class, exp.member.member.string, privateModule, null, null);
5778             }
5779             if(!prop && !member && _class && exp.member.member)
5780             {
5781                Symbol classSym = FindClass(exp.member.member.string);
5782                convertTo = _class;
5783                _class = classSym ? classSym.registered : null;
5784                prop = eClass_FindProperty(_class, convertTo.fullName, privateModule);
5785             }
5786
5787             if(prop)
5788             {
5789                if(prop.compiled)
5790                {
5791                   Type type = prop.dataType;
5792                   // TODO: Assuming same base type for units...
5793                   if(_class.type == unitClass)
5794                   {
5795                      if(type.kind == classType)
5796                      {
5797                         Class _class = type._class.registered;
5798                         if(_class.type == unitClass)
5799                         {
5800                            if(!_class.dataType)
5801                               _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5802                            type = _class.dataType;
5803                         }
5804                      }
5805                      switch(type.kind)
5806                      {
5807                         case floatType:
5808                         {
5809                            float value;
5810                            float (*Get)(float) = (void *)prop.Get;
5811                            GetFloat(exp.member.exp, &value);
5812                            exp.constant = PrintFloat(Get ? Get(value) : value);
5813                            exp.type = constantExp;
5814                            break;
5815                         }
5816                         case doubleType:
5817                         {
5818                            double value;
5819                            double (*Get)(double);
5820                            GetDouble(exp.member.exp, &value);
5821
5822                            if(convertTo)
5823                               Get = (void *)prop.Set;
5824                            else
5825                               Get = (void *)prop.Get;
5826                            exp.constant = PrintDouble(Get ? Get(value) : value);
5827                            exp.type = constantExp;
5828                            break;
5829                         }
5830                      }
5831                   }
5832                   else
5833                   {
5834                      if(convertTo)
5835                      {
5836                         Expression value = exp.member.exp;
5837                         Type type;
5838                         if(!prop.dataType)
5839                            ProcessPropertyType(prop);
5840
5841                         type = prop.dataType;
5842                         if(!type)
5843                         {
5844                             // printf("Investigate this\n");
5845                         }
5846                         else if(_class.type == structClass)
5847                         {
5848                            switch(type.kind)
5849                            {
5850                               case classType:
5851                               {
5852                                  Class propertyClass = type._class.registered;
5853                                  if(propertyClass.type == structClass && value.type == instanceExp)
5854                                  {
5855                                     void (*Set)(void *, void *) = (void *)prop.Set;
5856                                     exp.instance = Instantiation { };
5857                                     exp.instance.data = new0 byte[_class.structSize];
5858                                     exp.instance._class = MkSpecifierName(_class.fullName);
5859                                     exp.instance.loc = exp.loc;
5860                                     exp.type = instanceExp;
5861                                     Set(exp.instance.data, value.instance.data);
5862                                     PopulateInstance(exp.instance);
5863                                  }
5864                                  break;
5865                               }
5866                               case intType:
5867                               {
5868                                  int intValue;
5869                                  void (*Set)(void *, int) = (void *)prop.Set;
5870
5871                                  exp.instance = Instantiation { };
5872                                  exp.instance.data = new0 byte[_class.structSize];
5873                                  exp.instance._class = MkSpecifierName(_class.fullName);
5874                                  exp.instance.loc = exp.loc;
5875                                  exp.type = instanceExp;
5876
5877                                  GetInt(value, &intValue);
5878
5879                                  Set(exp.instance.data, intValue);
5880                                  PopulateInstance(exp.instance);
5881                                  break;
5882                               }
5883                               case int64Type:
5884                               {
5885                                  int64 intValue;
5886                                  void (*Set)(void *, int64) = (void *)prop.Set;
5887
5888                                  exp.instance = Instantiation { };
5889                                  exp.instance.data = new0 byte[_class.structSize];
5890                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5891                                  exp.instance.loc = exp.loc;
5892                                  exp.type = instanceExp;
5893
5894                                  GetInt64(value, &intValue);
5895
5896                                  Set(exp.instance.data, intValue);
5897                                  PopulateInstance(exp.instance);
5898                                  break;
5899                               }
5900                               case intPtrType:
5901                               {
5902                                  // TOFIX:
5903                                  intptr intValue;
5904                                  void (*Set)(void *, intptr) = (void *)prop.Set;
5905
5906                                  exp.instance = Instantiation { };
5907                                  exp.instance.data = new0 byte[_class.structSize];
5908                                  exp.instance._class = MkSpecifierName(_class.fullName);
5909                                  exp.instance.loc = exp.loc;
5910                                  exp.type = instanceExp;
5911
5912                                  GetIntPtr(value, &intValue);
5913
5914                                  Set(exp.instance.data, intValue);
5915                                  PopulateInstance(exp.instance);
5916                                  break;
5917                               }
5918                               case intSizeType:
5919                               {
5920                                  // TOFIX:
5921                                  intsize intValue;
5922                                  void (*Set)(void *, intsize) = (void *)prop.Set;
5923
5924                                  exp.instance = Instantiation { };
5925                                  exp.instance.data = new0 byte[_class.structSize];
5926                                  exp.instance._class = MkSpecifierName(_class.fullName);
5927                                  exp.instance.loc = exp.loc;
5928                                  exp.type = instanceExp;
5929
5930                                  GetIntSize(value, &intValue);
5931
5932                                  Set(exp.instance.data, intValue);
5933                                  PopulateInstance(exp.instance);
5934                                  break;
5935                               }
5936                               case floatType:
5937                               {
5938                                  float floatValue;
5939                                  void (*Set)(void *, float) = (void *)prop.Set;
5940
5941                                  exp.instance = Instantiation { };
5942                                  exp.instance.data = new0 byte[_class.structSize];
5943                                  exp.instance._class = MkSpecifierName(_class.fullName);
5944                                  exp.instance.loc = exp.loc;
5945                                  exp.type = instanceExp;
5946
5947                                  GetFloat(value, &floatValue);
5948
5949                                  Set(exp.instance.data, floatValue);
5950                                  PopulateInstance(exp.instance);
5951                                  break;
5952                               }
5953                               case doubleType:
5954                               {
5955                                  double doubleValue;
5956                                  void (*Set)(void *, double) = (void *)prop.Set;
5957
5958                                  exp.instance = Instantiation { };
5959                                  exp.instance.data = new0 byte[_class.structSize];
5960                                  exp.instance._class = MkSpecifierName(_class.fullName);
5961                                  exp.instance.loc = exp.loc;
5962                                  exp.type = instanceExp;
5963
5964                                  GetDouble(value, &doubleValue);
5965
5966                                  Set(exp.instance.data, doubleValue);
5967                                  PopulateInstance(exp.instance);
5968                                  break;
5969                               }
5970                            }
5971                         }
5972                         else if(_class.type == bitClass)
5973                         {
5974                            switch(type.kind)
5975                            {
5976                               case classType:
5977                               {
5978                                  Class propertyClass = type._class.registered;
5979                                  if(propertyClass.type == structClass && value.instance.data)
5980                                  {
5981                                     unsigned int (*Set)(void *) = (void *)prop.Set;
5982                                     unsigned int bits = Set(value.instance.data);
5983                                     exp.constant = PrintHexUInt(bits);
5984                                     exp.type = constantExp;
5985                                     break;
5986                                  }
5987                                  else if(_class.type == bitClass)
5988                                  {
5989                                     unsigned int value;
5990                                     unsigned int (*Set)(unsigned int) = (void *)prop.Set;
5991                                     unsigned int bits;
5992
5993                                     GetUInt(exp.member.exp, &value);
5994                                     bits = Set(value);
5995                                     exp.constant = PrintHexUInt(bits);
5996                                     exp.type = constantExp;
5997                                  }
5998                               }
5999                            }
6000                         }
6001                      }
6002                      else
6003                      {
6004                         if(_class.type == bitClass)
6005                         {
6006                            unsigned int value;
6007                            GetUInt(exp.member.exp, &value);
6008
6009                            switch(type.kind)
6010                            {
6011                               case classType:
6012                               {
6013                                  Class _class = type._class.registered;
6014                                  if(_class.type == structClass)
6015                                  {
6016                                     void (*Get)(unsigned int, void *) = (void *)prop.Get;
6017
6018                                     exp.instance = Instantiation { };
6019                                     exp.instance.data = new0 byte[_class.structSize];
6020                                     exp.instance._class = MkSpecifierName(_class.fullName);
6021                                     exp.instance.loc = exp.loc;
6022                                     //exp.instance.fullSet = true;
6023                                     exp.type = instanceExp;
6024                                     Get(value, exp.instance.data);
6025                                     PopulateInstance(exp.instance);
6026                                  }
6027                                  else if(_class.type == bitClass)
6028                                  {
6029                                     unsigned int (*Get)(unsigned int) = (void *)prop.Get;
6030                                     uint64 bits = Get(value);
6031                                     exp.constant = PrintHexUInt64(bits);
6032                                     exp.type = constantExp;
6033                                  }
6034                                  break;
6035                               }
6036                            }
6037                         }
6038                         else if(_class.type == structClass)
6039                         {
6040                            byte * value = (exp.member.exp.type == instanceExp ) ? exp.member.exp.instance.data : null;
6041                            switch(type.kind)
6042                            {
6043                               case classType:
6044                               {
6045                                  Class _class = type._class.registered;
6046                                  if(_class.type == structClass && value)
6047                                  {
6048                                     void (*Get)(void *, void *) = (void *)prop.Get;
6049
6050                                     exp.instance = Instantiation { };
6051                                     exp.instance.data = new0 byte[_class.structSize];
6052                                     exp.instance._class = MkSpecifierName(_class.fullName);
6053                                     exp.instance.loc = exp.loc;
6054                                     //exp.instance.fullSet = true;
6055                                     exp.type = instanceExp;
6056                                     Get(value, exp.instance.data);
6057                                     PopulateInstance(exp.instance);
6058                                  }
6059                                  break;
6060                               }
6061                            }
6062                         }
6063                         /*else
6064                         {
6065                            char * value = exp.member.exp.instance.data;
6066                            switch(type.kind)
6067                            {
6068                               case classType:
6069                               {
6070                                  Class _class = type._class.registered;
6071                                  if(_class.type == normalClass)
6072                                  {
6073                                     void *(*Get)(void *) = (void *)prop.Get;
6074
6075                                     exp.instance = Instantiation { };
6076                                     exp.instance._class = MkSpecifierName(_class.fullName); //MkClassName(_class.fullName);
6077                                     exp.type = instanceExp;
6078                                     exp.instance.data = Get(value, exp.instance.data);
6079                                  }
6080                                  break;
6081                               }
6082                            }
6083                         }
6084                         */
6085                      }
6086                   }
6087                }
6088                else
6089                {
6090                   exp.isConstant = false;
6091                }
6092             }
6093             else if(member)
6094             {
6095             }
6096          }
6097
6098          if(exp.type != ExpressionType::memberExp)
6099          {
6100             FreeExpression(memberExp);
6101             FreeIdentifier(memberID);
6102          }
6103          break;
6104       }
6105       case typeSizeExp:
6106       {
6107          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
6108          FreeExpContents(exp);
6109          exp.constant = PrintUInt(ComputeTypeSize(type));
6110          exp.type = constantExp;
6111          FreeType(type);
6112          break;
6113       }
6114       case classSizeExp:
6115       {
6116          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
6117          if(classSym && classSym.registered)
6118          {
6119             if(classSym.registered.fixed)
6120             {
6121                FreeSpecifier(exp._class);
6122                exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
6123                exp.type = constantExp;
6124             }
6125             else
6126             {
6127                char className[1024];
6128                strcpy(className, "__ecereClass_");
6129                FullClassNameCat(className, classSym.string, true);
6130
6131                DeclareClass(curExternal, classSym, className);
6132
6133                FreeExpContents(exp);
6134                exp.type = pointerExp;
6135                exp.member.exp = MkExpIdentifier(MkIdentifier(className));
6136                exp.member.member = MkIdentifier("structSize");
6137             }
6138          }
6139          break;
6140       }
6141       case castExp:
6142       //case constantExp:
6143       {
6144          Type type;
6145          Expression e = exp;
6146          if(exp.type == castExp)
6147          {
6148             if(exp.cast.exp)
6149                ComputeExpression(exp.cast.exp);
6150             e = exp.cast.exp;
6151          }
6152          if(e && exp.expType)
6153          {
6154             /*if(exp.destType)
6155                type = exp.destType;
6156             else*/
6157                type = exp.expType;
6158             if(type.kind == classType)
6159             {
6160                Class _class = type._class.registered;
6161                if(_class && (_class.type == unitClass || _class.type == bitClass))
6162                {
6163                   if(!_class.dataType)
6164                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
6165                   type = _class.dataType;
6166                }
6167             }
6168
6169             switch(type.kind)
6170             {
6171                case _BoolType:
6172                case charType:
6173                   if(type.isSigned)
6174                   {
6175                      char value = 0;
6176                      if(GetChar(e, &value))
6177                      {
6178                         FreeExpContents(exp);
6179                         exp.constant = PrintChar(value);
6180                         exp.type = constantExp;
6181                      }
6182                   }
6183                   else
6184                   {
6185                      unsigned char value = 0;
6186                      if(GetUChar(e, &value))
6187                      {
6188                         FreeExpContents(exp);
6189                         exp.constant = PrintUChar(value);
6190                         exp.type = constantExp;
6191                      }
6192                   }
6193                   break;
6194                case shortType:
6195                   if(type.isSigned)
6196                   {
6197                      short value = 0;
6198                      if(GetShort(e, &value))
6199                      {
6200                         FreeExpContents(exp);
6201                         exp.constant = PrintShort(value);
6202                         exp.type = constantExp;
6203                      }
6204                   }
6205                   else
6206                   {
6207                      unsigned short value = 0;
6208                      if(GetUShort(e, &value))
6209                      {
6210                         FreeExpContents(exp);
6211                         exp.constant = PrintUShort(value);
6212                         exp.type = constantExp;
6213                      }
6214                   }
6215                   break;
6216                case intType:
6217                   if(type.isSigned)
6218                   {
6219                      int value = 0;
6220                      if(GetInt(e, &value))
6221                      {
6222                         FreeExpContents(exp);
6223                         exp.constant = PrintInt(value);
6224                         exp.type = constantExp;
6225                      }
6226                   }
6227                   else
6228                   {
6229                      unsigned int value = 0;
6230                      if(GetUInt(e, &value))
6231                      {
6232                         FreeExpContents(exp);
6233                         exp.constant = PrintUInt(value);
6234                         exp.type = constantExp;
6235                      }
6236                   }
6237                   break;
6238                case int64Type:
6239                   if(type.isSigned)
6240                   {
6241                      int64 value = 0;
6242                      if(GetInt64(e, &value))
6243                      {
6244                         FreeExpContents(exp);
6245                         exp.constant = PrintInt64(value);
6246                         exp.type = constantExp;
6247                      }
6248                   }
6249                   else
6250                   {
6251                      uint64 value = 0;
6252                      if(GetUInt64(e, &value))
6253                      {
6254                         FreeExpContents(exp);
6255                         exp.constant = PrintUInt64(value);
6256                         exp.type = constantExp;
6257                      }
6258                   }
6259                   break;
6260                case intPtrType:
6261                   if(type.isSigned)
6262                   {
6263                      intptr value = 0;
6264                      if(GetIntPtr(e, &value))
6265                      {
6266                         FreeExpContents(exp);
6267                         exp.constant = PrintInt64((int64)value);
6268                         exp.type = constantExp;
6269                      }
6270                   }
6271                   else
6272                   {
6273                      uintptr value = 0;
6274                      if(GetUIntPtr(e, &value))
6275                      {
6276                         FreeExpContents(exp);
6277                         exp.constant = PrintUInt64((uint64)value);
6278                         exp.type = constantExp;
6279                      }
6280                   }
6281                   break;
6282                case intSizeType:
6283                   if(type.isSigned)
6284                   {
6285                      intsize value = 0;
6286                      if(GetIntSize(e, &value))
6287                      {
6288                         FreeExpContents(exp);
6289                         exp.constant = PrintInt64((int64)value);
6290                         exp.type = constantExp;
6291                      }
6292                   }
6293                   else
6294                   {
6295                      uintsize value = 0;
6296                      if(GetUIntSize(e, &value))
6297                      {
6298                         FreeExpContents(exp);
6299                         exp.constant = PrintUInt64((uint64)value);
6300                         exp.type = constantExp;
6301                      }
6302                   }
6303                   break;
6304                case floatType:
6305                {
6306                   float value = 0;
6307                   if(GetFloat(e, &value))
6308                   {
6309                      FreeExpContents(exp);
6310                      exp.constant = PrintFloat(value);
6311                      exp.type = constantExp;
6312                   }
6313                   break;
6314                }
6315                case doubleType:
6316                {
6317                   double value = 0;
6318                   if(GetDouble(e, &value))
6319                   {
6320                      FreeExpContents(exp);
6321                      exp.constant = PrintDouble(value);
6322                      exp.type = constantExp;
6323                   }
6324                   break;
6325                }
6326             }
6327          }
6328          break;
6329       }
6330       case conditionExp:
6331       {
6332          Operand op1 { };
6333          Operand op2 { };
6334          Operand op3 { };
6335
6336          if(exp.cond.exp)
6337             // Caring only about last expression for now...
6338             ComputeExpression(exp.cond.exp->last);
6339          if(exp.cond.elseExp)
6340             ComputeExpression(exp.cond.elseExp);
6341          if(exp.cond.cond)
6342             ComputeExpression(exp.cond.cond);
6343
6344          op1 = GetOperand(exp.cond.cond);
6345          if(op1.type) op1.type.refCount++;
6346          op2 = GetOperand(exp.cond.exp->last);
6347          if(op2.type) op2.type.refCount++;
6348          op3 = GetOperand(exp.cond.elseExp);
6349          if(op3.type) op3.type.refCount++;
6350
6351          if(op1.ops.Cond) { FreeExpContents(exp); op1.ops.Cond(exp, op1, op2, op3); }
6352          if(op1.type) FreeType(op1.type);
6353          if(op2.type) FreeType(op2.type);
6354          if(op3.type) FreeType(op3.type);
6355          break;
6356       }
6357    }
6358 }
6359
6360 static bool CheckExpressionType(Expression exp, Type destType, bool skipUnitBla, bool warnConst)
6361 {
6362    bool result = true;
6363    if(destType)
6364    {
6365       OldList converts { };
6366       Conversion convert;
6367
6368       if(destType.kind == voidType)
6369          return false;
6370
6371       if(!MatchTypeExpression(exp, destType, &converts, skipUnitBla, warnConst))
6372          result = false;
6373       if(converts.count)
6374       {
6375          // for(convert = converts.last; convert; convert = convert.prev)
6376          for(convert = converts.first; convert; convert = convert.next)
6377          {
6378             bool empty = !(convert.isGet ? (void *)convert.convert.Get : (void *)convert.convert.Set);
6379             if(!empty)
6380             {
6381                Expression newExp { };
6382                ClassObjectType objectType = exp.expType ? exp.expType.classObjectType : none;
6383
6384                // TODO: Check this...
6385                *newExp = *exp;
6386                newExp.prev = null;
6387                newExp.next = null;
6388                newExp.destType = null;
6389
6390                if(convert.isGet)
6391                {
6392                   // [exp].ColorRGB
6393                   exp.type = memberExp;
6394                   exp.addedThis = true;
6395                   exp.member.exp = newExp;
6396                   FreeType(exp.member.exp.expType);
6397
6398                   exp.member.exp.expType = MkClassType(convert.convert._class.fullName);
6399                   exp.member.exp.expType.classObjectType = objectType;
6400                   exp.member.member = MkIdentifier(convert.convert.dataTypeString);
6401                   exp.member.memberType = propertyMember;
6402                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6403                   // TESTING THIS... for (int)degrees
6404                   exp.needCast = true;
6405                   if(exp.expType) exp.expType.refCount++;
6406                   ApplyAnyObjectLogic(exp.member.exp);
6407                }
6408                else
6409                {
6410
6411                   /*if(exp.isConstant)
6412                   {
6413                      // Color { ColorRGB = [exp] };
6414                      exp.type = instanceExp;
6415                      exp.instance = MkInstantiation(MkSpecifierName((convert.convert._class.fullName), //MkClassName(convert.convert._class.fullName),
6416                         null, MkListOne(MkMembersInitList(MkListOne(MkMemberInit(
6417                         MkListOne(MkIdentifier(convert.convert.dataTypeString)), newExp)))));
6418                   }
6419                   else*/
6420                   {
6421                      // If not constant, don't turn it yet into an instantiation
6422                      // (Go through the deep members system first)
6423                      exp.type = memberExp;
6424                      exp.addedThis = true;
6425                      exp.member.exp = newExp;
6426
6427                      // ADDED THIS HERE TO SOLVE PROPERTY ISSUES WITH NOHEAD CLASSES
6428                      if(/*!notByReference && */newExp.expType && newExp.expType.kind == classType && newExp.expType._class && newExp.expType._class.registered &&
6429                         newExp.expType._class.registered.type == noHeadClass)
6430                      {
6431                         newExp.byReference = true;
6432                      }
6433
6434                      FreeType(exp.member.exp.expType);
6435                      /*exp.member.exp.expType = convert.convert.dataType;
6436                      if(convert.convert.dataType) convert.convert.dataType.refCount++;*/
6437                      exp.member.exp.expType = null;
6438                      if(convert.convert.dataType)
6439                      {
6440                         exp.member.exp.expType = { };
6441                         CopyTypeInto(exp.member.exp.expType, convert.convert.dataType);
6442                         exp.member.exp.expType.refCount = 1;
6443                         exp.member.exp.expType.classObjectType = objectType;
6444                         ApplyAnyObjectLogic(exp.member.exp);
6445                      }
6446
6447                      exp.member.member = MkIdentifier(convert.convert._class.fullName);
6448                      exp.member.memberType = reverseConversionMember;
6449                      exp.expType = convert.resultType ? convert.resultType :
6450                         MkClassType(convert.convert._class.fullName);
6451                      exp.needCast = true;
6452                      if(convert.resultType) convert.resultType.refCount++;
6453                   }
6454                }
6455             }
6456             else
6457             {
6458                FreeType(exp.expType);
6459                if(convert.isGet)
6460                {
6461                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6462                   if(exp.destType.casted)
6463                      exp.needCast = true;
6464                   if(exp.expType) exp.expType.refCount++;
6465                }
6466                else
6467                {
6468                   exp.expType = convert.resultType ? convert.resultType : MkClassType(convert.convert._class.fullName);
6469                   if(exp.destType.casted)
6470                      exp.needCast = true;
6471                   if(convert.resultType)
6472                      convert.resultType.refCount++;
6473                }
6474             }
6475          }
6476          if(exp.isConstant && inCompiler)
6477             ComputeExpression(exp);
6478
6479          converts.Free(FreeConvert);
6480       }
6481
6482       if(!result && exp.expType && converts.count)      // TO TEST: Added converts.count here to avoid a double warning with function type
6483       {
6484          result = MatchTypes(exp.expType, exp.destType, null, null, null, true, true, false, false, warnConst);
6485       }
6486       if(!result && exp.expType && exp.destType)
6487       {
6488          if((exp.destType.kind == classType && exp.expType.kind == pointerType &&
6489              exp.expType.type.kind == classType && exp.expType.type._class == exp.destType._class && exp.destType._class.registered && exp.destType._class.registered.type == structClass) ||
6490             (exp.expType.kind == classType && exp.destType.kind == pointerType &&
6491             exp.destType.type.kind == classType && exp.destType.type._class == exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass))
6492             result = true;
6493       }
6494    }
6495    // if(result) CheckTemplateTypes(exp);
6496    return result;
6497 }
6498
6499 void CheckTemplateTypes(Expression exp)
6500 {
6501    /*
6502    bool et = exp.expType ? exp.expType.passAsTemplate : false;
6503    bool dt = exp.destType ? exp.destType.passAsTemplate : false;
6504    */
6505    Expression nbExp = GetNonBracketsExp(exp);
6506    if(exp.destType && exp.destType.passAsTemplate && exp.expType && exp.expType.kind != templateType && !exp.expType.passAsTemplate &&
6507       (nbExp == exp || nbExp.type != castExp))
6508    {
6509       Expression newExp { };
6510       Context context;
6511       TypeKind kind = exp.expType.kind;
6512       *newExp = *exp;
6513       if(exp.destType) exp.destType.refCount++;
6514       if(exp.expType)  exp.expType.refCount++;
6515       newExp.prev = null;
6516       newExp.next = null;
6517
6518       if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered)
6519       {
6520          Class c = exp.expType._class.registered;
6521          if(c.type == bitClass || c.type == enumClass || c.type == unitClass)
6522          {
6523             if(!c.dataType)
6524                c.dataType = ProcessTypeString(c.dataTypeString, false);
6525             kind = c.dataType.kind;
6526          }
6527       }
6528
6529       switch(kind)
6530       {
6531          case doubleType:
6532             if(exp.destType.classObjectType)
6533             {
6534                // We need to pass the address, just pass it along (Undo what was done above)
6535                if(exp.destType) exp.destType.refCount--;
6536                if(exp.expType)  exp.expType.refCount--;
6537                delete newExp;
6538             }
6539             else
6540             {
6541                // If we're looking for value:
6542                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6543                OldList * specs;
6544                OldList * unionDefs = MkList();
6545                OldList * statements = MkList();
6546                context = PushContext();
6547                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6548                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6549                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6550                exp.type = extensionCompoundExp;
6551                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6552                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")), '=', newExp))));
6553                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
6554                exp.compound.compound.context = context;
6555                PopContext(context);
6556             }
6557             break;
6558          default:
6559             exp.type = castExp;
6560             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6561             if((exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass) || exp.expType.isPointerType)
6562                exp.cast.exp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), MkExpBrackets(MkListOne(newExp)));
6563             else
6564                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6565             exp.needCast = true;
6566             break;
6567       }
6568    }
6569    else if(exp.expType && exp.expType.passAsTemplate && exp.destType && exp.usage.usageGet && exp.destType.kind != templateType && !exp.destType.passAsTemplate)
6570    {
6571       Expression newExp { };
6572       Context context;
6573       TypeKind kind = exp.expType.kind;
6574       *newExp = *exp;
6575       if(exp.destType) exp.destType.refCount++;
6576       if(exp.expType)  exp.expType.refCount++;
6577       newExp.prev = null;
6578       newExp.next = null;
6579
6580       if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered)
6581       {
6582          Class c = exp.expType._class.registered;
6583          if(c.type == bitClass || c.type == enumClass || c.type == unitClass)
6584          {
6585             if(!c.dataType)
6586                c.dataType = ProcessTypeString(c.dataTypeString, false);
6587             kind = c.dataType.kind;
6588          }
6589       }
6590
6591       switch(kind)
6592       {
6593          case doubleType:
6594             if(exp.destType.classObjectType)
6595             {
6596                // We need to pass the address, just pass it along (Undo what was done above)
6597                if(exp.destType) exp.destType.refCount--;
6598                if(exp.expType)  exp.expType.refCount--;
6599                delete newExp;
6600             }
6601             else
6602             {
6603                // If we're looking for value:
6604                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6605                OldList * specs;
6606                OldList * unionDefs = MkList();
6607                OldList * statements = MkList();
6608                context = PushContext();
6609                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6610                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6611                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6612                exp.type = extensionCompoundExp;
6613                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6614                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
6615                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")))));
6616                exp.compound.compound.context = context;
6617                PopContext(context);
6618             }
6619             break;
6620          case classType:
6621          {
6622             if(exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass)
6623             {
6624                exp.type = bracketsExp;
6625
6626                newExp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), newExp);
6627                exp.list = MkListOne(MkExpOp(null, '*', MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)),
6628                   MkDeclaratorPointer(MkPointer(null, null), null)), newExp)));
6629                ProcessExpressionType(exp.list->first);
6630                break;
6631             }
6632             else
6633             {
6634                exp.type = bracketsExp;
6635                if(exp.expType.isPointerType)
6636                {
6637                   exp.needTemplateCast = 2;
6638                   newExp.needCast = true;
6639                   newExp.needTemplateCast = 2;
6640                   newExp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), newExp);
6641                }
6642
6643                exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)), null), newExp));
6644                exp.needTemplateCast = 2;
6645                newExp.needCast = true;
6646                newExp.needTemplateCast = 2;
6647                ProcessExpressionType(exp.list->first);
6648                break;
6649             }
6650          }
6651          default:
6652          {
6653             if(exp.expType.kind == templateType)
6654             {
6655                Type type = ProcessTemplateParameterType(exp.expType.templateParameter);
6656                if(type)
6657                {
6658                   FreeType(exp.destType);
6659                   FreeType(exp.expType);
6660                   delete newExp;
6661                   break;
6662                }
6663             }
6664             /*if(newExp.type == memberExp && newExp.member.memberType == dataMember)
6665             {
6666                // When was this required?    Removed to address using templated values to pass to printf()
6667                exp.type = opExp;
6668                exp.op.op = '*';
6669                exp.op.exp1 = null;
6670                exp.op.exp2 = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uint64")), MkDeclaratorPointer(MkPointer(null, null), null)),
6671                   MkExpBrackets(MkListOne(MkExpOp(null, '&', newExp))));
6672             }
6673             else*/
6674             {
6675                char typeString[1024];
6676                Declarator decl;
6677                OldList * specs = MkList();
6678                typeString[0] = '\0';
6679                PrintType(exp.expType, typeString, false, false);
6680                decl = SpecDeclFromString(typeString, specs, null);
6681
6682                exp.type = castExp;
6683                //exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6684                exp.cast.typeName = MkTypeName(specs, decl);
6685                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6686                exp.cast.exp.needCast = true;
6687                exp.needTemplateCast = 2;
6688                newExp.needTemplateCast = 2;
6689             }
6690             break;
6691          }
6692       }
6693    }
6694 }
6695 // TODO: The Symbol tree should be reorganized by namespaces
6696 // Name Space:
6697 //    - Tree of all symbols within (stored without namespace)
6698 //    - Tree of sub-namespaces
6699
6700 static Symbol ScanWithNameSpace(BinaryTree tree, const char * nameSpace, const char * name)
6701 {
6702    int nsLen = strlen(nameSpace);
6703    Symbol symbol;
6704    // Start at the name space prefix
6705    for(symbol = (Symbol)tree.FindPrefix(nameSpace); symbol; symbol = (Symbol)((BTNode)symbol).next)
6706    {
6707       char * s = symbol.string;
6708       if(!strncmp(s, nameSpace, nsLen))
6709       {
6710          // This supports e.g. matching ecere::Socket to ecere::net::Socket
6711          int c;
6712          char * namePart;
6713          for(c = strlen(s)-1; c >= 0; c--)
6714             if(s[c] == ':')
6715                break;
6716
6717          namePart = s+c+1;
6718          if(!strcmp(namePart, name))
6719          {
6720             // TODO: Error on ambiguity
6721             return symbol;
6722          }
6723       }
6724       else
6725          break;
6726    }
6727    return null;
6728 }
6729
6730 static Symbol FindWithNameSpace(BinaryTree tree, const char * name)
6731 {
6732    int c;
6733    char nameSpace[1024];
6734    const char * namePart;
6735    bool gotColon = false;
6736
6737    nameSpace[0] = '\0';
6738    for(c = strlen(name)-1; c >= 0; c--)
6739       if(name[c] == ':')
6740       {
6741          gotColon = true;
6742          break;
6743       }
6744
6745    namePart = name+c+1;
6746    while(c >= 0 && name[c] == ':') c--;
6747    if(c >= 0)
6748    {
6749       // Try an exact match first
6750       Symbol symbol = (Symbol)tree.FindString(name);
6751       if(symbol)
6752          return symbol;
6753
6754       // Namespace specified
6755       memcpy(nameSpace, name, c + 1);
6756       nameSpace[c+1] = 0;
6757
6758       return ScanWithNameSpace(tree, nameSpace, namePart);
6759    }
6760    else if(gotColon)
6761    {
6762       // Looking for a global symbol, e.g. ::Sleep()
6763       Symbol symbol = (Symbol)tree.FindString(namePart);
6764       return symbol;
6765    }
6766    else
6767    {
6768       // Name only (no namespace specified)
6769       Symbol symbol = (Symbol)tree.FindString(namePart);
6770       if(symbol)
6771          return symbol;
6772       return ScanWithNameSpace(tree, "", namePart);
6773    }
6774    return null;
6775 }
6776
6777 /*static */Symbol FindSymbol(const char * name, Context startContext, Context endContext, bool isStruct, bool globalNameSpace)
6778 {
6779 #ifdef _DEBUG
6780    //Time startTime = GetTime();
6781 #endif
6782    // Optimize this later? Do this before/less?
6783    Context ctx;
6784    Symbol symbol = null;
6785
6786    // First, check if the identifier is declared inside the function
6787    //for(ctx = curContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6788
6789    for(ctx = startContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6790    {
6791       if(ctx == globalContext && !globalNameSpace && ctx.hasNameSpace)
6792       {
6793          symbol = null;
6794          if(thisNameSpace)
6795          {
6796             char curName[1024];
6797             strcpy(curName, thisNameSpace);
6798             strcat(curName, "::");
6799             strcat(curName, name);
6800             // Try to resolve in current namespace first
6801             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, curName);
6802          }
6803          if(!symbol)
6804             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, name);
6805       }
6806       else
6807          symbol = (Symbol)(isStruct ? ctx.structSymbols : ctx.symbols).FindString(name);
6808
6809       if(symbol || ctx == endContext) break;
6810    }
6811    if(inCompiler && symbol && ctx == globalContext && symbol.pointerExternal && curExternal && symbol.pointerExternal != curExternal)
6812       curExternal.CreateUniqueEdge(symbol.pointerExternal, symbol.pointerExternal.type == functionExternal);
6813 #ifdef _DEBUG
6814    //findSymbolTotalTime += GetTime() - startTime;
6815 #endif
6816    return symbol;
6817 }
6818
6819 static void GetTypeSpecs(Type type, OldList * specs)
6820 {
6821    if(!type.isSigned && type.kind != intPtrType && type.kind != intSizeType) ListAdd(specs, MkSpecifier(UNSIGNED));
6822    switch(type.kind)
6823    {
6824       case classType:
6825       {
6826          if(type._class.registered)
6827          {
6828             if(!type._class.registered.dataType)
6829                type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
6830             GetTypeSpecs(type._class.registered.dataType, specs);
6831          }
6832          break;
6833       }
6834       case doubleType: ListAdd(specs, MkSpecifier(DOUBLE)); break;
6835       case floatType: ListAdd(specs, MkSpecifier(FLOAT)); break;
6836       case charType: ListAdd(specs, MkSpecifier(CHAR)); break;
6837       case _BoolType: ListAdd(specs, MkSpecifier(_BOOL)); break;
6838       case shortType: ListAdd(specs, MkSpecifier(SHORT)); break;
6839       case int64Type: ListAdd(specs, MkSpecifier(INT64)); break;
6840       case intPtrType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intptr" : "uintptr")); break;
6841       case intSizeType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intsize" : "uintsize")); break;
6842       case intType:
6843       default:
6844          ListAdd(specs, MkSpecifier(INT)); break;
6845    }
6846 }
6847
6848 static void PrintArraySize(Type arrayType, char * string)
6849 {
6850    char size[256];
6851    size[0] = '\0';
6852    strcat(size, "[");
6853    if(arrayType.enumClass)
6854       strcat(size, arrayType.enumClass.string);
6855    else if(arrayType.arraySizeExp)
6856       PrintExpression(arrayType.arraySizeExp, size);
6857    strcat(size, "]");
6858    strcat(string, size);
6859 }
6860
6861 // WARNING : This function expects a null terminated string since it recursively concatenate...
6862 static void PrintTypeSpecs(Type type, char * string, bool fullName, bool printConst)
6863 {
6864    if(type)
6865    {
6866       if(printConst && type.constant)
6867          strcat(string, "const ");
6868       switch(type.kind)
6869       {
6870          case classType:
6871          {
6872             Symbol c = type._class;
6873             bool isObjectBaseClass = !c || !c.string || !strcmp(c.string, "class");
6874             // TODO: typed_object does not fully qualify the type, as it may have taken up an actual class (Stored in _class) from overriding
6875             //       look into merging with thisclass ?
6876             if(type.classObjectType == typedObject && isObjectBaseClass)
6877                strcat(string, "typed_object");
6878             else if(type.classObjectType == anyObject && isObjectBaseClass)
6879                strcat(string, "any_object");
6880             else
6881             {
6882                if(c && c.string)
6883                   strcat(string, (fullName || !c.registered) ? c.string : c.registered.name);
6884             }
6885             if(type.byReference)
6886                strcat(string, " &");
6887             break;
6888          }
6889          case voidType: strcat(string, "void"); break;
6890          case intType:  strcat(string, type.isSigned ? "int" : "uint"); break;
6891          case int64Type:  strcat(string, type.isSigned ? "int64" : "uint64"); break;
6892          case intPtrType:  strcat(string, type.isSigned ? "intptr" : "uintptr"); break;
6893          case intSizeType:  strcat(string, type.isSigned ? "intsize" : "uintsize"); break;
6894          case charType: strcat(string, type.isSigned ? "char" : "byte"); break;
6895          case _BoolType: strcat(string, "_Bool"); break;
6896          case shortType: strcat(string, type.isSigned ? "short" : "uint16"); break;
6897          case floatType: strcat(string, "float"); break;
6898          case doubleType: strcat(string, "double"); break;
6899          case structType:
6900             if(type.enumName)
6901             {
6902                strcat(string, "struct ");
6903                strcat(string, type.enumName);
6904             }
6905             else if(type.typeName)
6906                strcat(string, type.typeName);
6907             else
6908             {
6909                Type member;
6910                strcat(string, "struct { ");
6911                for(member = type.members.first; member; member = member.next)
6912                {
6913                   PrintType(member, string, true, fullName);
6914                   strcat(string,"; ");
6915                }
6916                strcat(string,"}");
6917             }
6918             break;
6919          case unionType:
6920             if(type.enumName)
6921             {
6922                strcat(string, "union ");
6923                strcat(string, type.enumName);
6924             }
6925             else if(type.typeName)
6926                strcat(string, type.typeName);
6927             else
6928             {
6929                strcat(string, "union ");
6930                strcat(string,"(unnamed)");
6931             }
6932             break;
6933          case enumType:
6934             if(type.enumName)
6935             {
6936                strcat(string, "enum ");
6937                strcat(string, type.enumName);
6938             }
6939             else if(type.typeName)
6940                strcat(string, type.typeName);
6941             else
6942                strcat(string, "int"); // "enum");
6943             break;
6944          case ellipsisType:
6945             strcat(string, "...");
6946             break;
6947          case subClassType:
6948             strcat(string, "subclass(");
6949             strcat(string, type._class ? type._class.string : "int");
6950             strcat(string, ")");
6951             break;
6952          case templateType:
6953             strcat(string, type.templateParameter.identifier.string);
6954             break;
6955          case thisClassType:
6956             strcat(string, "thisclass");
6957             break;
6958          case vaListType:
6959             strcat(string, "__builtin_va_list");
6960             break;
6961       }
6962    }
6963 }
6964
6965 static void PrintName(Type type, char * string, bool fullName)
6966 {
6967    if(type.name && type.name[0])
6968    {
6969       if(fullName)
6970          strcat(string, type.name);
6971       else
6972       {
6973          char * name = RSearchString(type.name, "::", strlen(type.name), true, false);
6974          if(name) name += 2; else name = type.name;
6975          strcat(string, name);
6976       }
6977    }
6978 }
6979
6980 static void PrintAttribs(Type type, char * string)
6981 {
6982    if(type)
6983    {
6984       if(type.dllExport)   strcat(string, "dllexport ");
6985       if(type.attrStdcall) strcat(string, "stdcall ");
6986    }
6987 }
6988
6989 static void PrePrintType(Type type, char * string, bool fullName, Type parentType, bool printConst)
6990 {
6991    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
6992    {
6993       if((type.kind == functionType || type.kind == methodType) && (!parentType || parentType.kind != pointerType))
6994          PrintAttribs(type, string);
6995       if(printConst && type.constant && (type.kind == functionType || type.kind == methodType))
6996          strcat(string, " const");
6997       PrePrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName, type, printConst);
6998       if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
6999          strcat(string, " (");
7000       if(type.kind == pointerType)
7001       {
7002          if(type.type.kind == functionType || type.type.kind == methodType)
7003             PrintAttribs(type.type, string);
7004       }
7005       if(type.kind == pointerType)
7006       {
7007          if(type.type.kind == functionType || type.type.kind == methodType || type.type.kind == arrayType)
7008             strcat(string, "*");
7009          else
7010             strcat(string, " *");
7011       }
7012       if(printConst && type.constant && type.kind == pointerType)
7013          strcat(string, " const");
7014    }
7015    else
7016       PrintTypeSpecs(type, string, fullName, printConst);
7017 }
7018
7019 static void PostPrintType(Type type, char * string, bool fullName)
7020 {
7021    if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
7022       strcat(string, ")");
7023    if(type.kind == arrayType)
7024       PrintArraySize(type, string);
7025    else if(type.kind == functionType)
7026    {
7027       Type param;
7028       strcat(string, "(");
7029       for(param = type.params.first; param; param = param.next)
7030       {
7031          PrintType(param, string, true, fullName);
7032          if(param.next) strcat(string, ", ");
7033       }
7034       strcat(string, ")");
7035    }
7036    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
7037       PostPrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName);
7038 }
7039
7040 // *****
7041 // TODO: Add a max buffer size to avoid overflows. This function is used with static size char arrays.
7042 // *****
7043 static void _PrintType(Type type, char * string, bool printName, bool fullName, bool printConst)
7044 {
7045    PrePrintType(type, string, fullName, null, printConst);
7046
7047    if(type.thisClass || (printName && type.name && type.name[0]))
7048       strcat(string, " ");
7049    if(/*(type.kind == methodType || type.kind == functionType) && */(type.thisClass || type.staticMethod))
7050    {
7051       Symbol _class = type.thisClass;
7052       if((type.classObjectType == typedObject || type.classObjectType == classPointer) || (_class && !strcmp(_class.string, "class")))
7053       {
7054          if(type.classObjectType == classPointer)
7055             strcat(string, "class");
7056          else
7057             strcat(string, type.byReference ? "typed_object&" : "typed_object");
7058       }
7059       else if(_class && _class.string)
7060       {
7061          String s = _class.string;
7062          if(fullName)
7063             strcat(string, s);
7064          else
7065          {
7066             char * name = RSearchString(s, "::", strlen(s), true, false);
7067             if(name) name += 2; else name = s;
7068             strcat(string, name);
7069          }
7070       }
7071       strcat(string, "::");
7072    }
7073
7074    if(printName && type.name)
7075       PrintName(type, string, fullName);
7076    PostPrintType(type, string, fullName);
7077    if(type.bitFieldCount)
7078    {
7079       char count[100];
7080       sprintf(count, ":%d", type.bitFieldCount);
7081       strcat(string, count);
7082    }
7083 }
7084
7085 void PrintType(Type type, char * string, bool printName, bool fullName)
7086 {
7087    _PrintType(type, string, printName, fullName, true);
7088 }
7089
7090 void PrintTypeNoConst(Type type, char * string, bool printName, bool fullName)
7091 {
7092    _PrintType(type, string, printName, fullName, false);
7093 }
7094
7095 static Type FindMember(Type type, char * string)
7096 {
7097    Type memberType;
7098    for(memberType = type.members.first; memberType; memberType = memberType.next)
7099    {
7100       if(!memberType.name)
7101       {
7102          Type subType = FindMember(memberType, string);
7103          if(subType)
7104             return subType;
7105       }
7106       else if(!strcmp(memberType.name, string))
7107          return memberType;
7108    }
7109    return null;
7110 }
7111
7112 Type FindMemberAndOffset(Type type, char * string, uint * offset)
7113 {
7114    Type memberType;
7115    for(memberType = type.members.first; memberType; memberType = memberType.next)
7116    {
7117       if(!memberType.name)
7118       {
7119          Type subType = FindMember(memberType, string);
7120          if(subType)
7121          {
7122             *offset += memberType.offset;
7123             return subType;
7124          }
7125       }
7126       else if(!strcmp(memberType.name, string))
7127       {
7128          *offset += memberType.offset;
7129          return memberType;
7130       }
7131    }
7132    return null;
7133 }
7134
7135 public bool GetParseError() { return parseError; }
7136
7137 Expression ParseExpressionString(char * expression)
7138 {
7139    parseError = false;
7140
7141    fileInput = TempFile { };
7142    fileInput.Write(expression, 1, strlen(expression));
7143    fileInput.Seek(0, start);
7144
7145    echoOn = false;
7146    parsedExpression = null;
7147    resetScanner();
7148    expression_yyparse();
7149    delete fileInput;
7150
7151    return parsedExpression;
7152 }
7153
7154 static bool ResolveIdWithClass(Expression exp, Class _class, bool skipIDClassCheck)
7155 {
7156    Identifier id = exp.identifier;
7157    Method method = null;
7158    Property prop = null;
7159    DataMember member = null;
7160    ClassProperty classProp = null;
7161
7162    if(_class && _class.type == enumClass)
7163    {
7164       NamedLink64 value = null;
7165       Class enumClass = eSystem_FindClass(privateModule, "enum");
7166       if(enumClass)
7167       {
7168          Class baseClass;
7169          for(baseClass = _class; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
7170          {
7171             EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
7172             for(value = e.values.first; value; value = value.next)
7173             {
7174                if(!strcmp(value.name, id.string))
7175                   break;
7176             }
7177             if(value)
7178             {
7179                exp.isConstant = true;
7180                if(inCompiler || inPreCompiler || inDebugger)
7181                {
7182                   char constant[256];
7183                   FreeExpContents(exp);
7184
7185                   exp.type = constantExp;
7186                   if(!strcmp(baseClass.dataTypeString, "int") || !strcmp(baseClass.dataTypeString, "int64") || !strcmp(baseClass.dataTypeString, "char") || !strcmp(baseClass.dataTypeString, "short"))
7187                      sprintf(constant, FORMAT64D, value.data);
7188                   else
7189                      sprintf(constant, FORMAT64HEX, value.data);
7190                   exp.constant = CopyString(constant);
7191                }
7192                //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
7193                exp.expType = MkClassType(baseClass.fullName);
7194                break;
7195             }
7196          }
7197       }
7198       if(value)
7199          return true;
7200    }
7201    if((method = eClass_FindMethod(_class, id.string, privateModule)))
7202    {
7203       ProcessMethodType(method);
7204       exp.expType = Type
7205       {
7206          refCount = 1;
7207          kind = methodType;
7208          method = method;
7209          // Crash here?
7210          // TOCHECK: Put it back to what it was...
7211          // methodClass = _class;
7212          methodClass = (skipIDClassCheck || (id && id._class)) ? _class : null;
7213       };
7214       //id._class = null;
7215       return true;
7216    }
7217    else if((prop = eClass_FindProperty(_class, id.string, privateModule)))
7218    {
7219       if(!prop.dataType)
7220          ProcessPropertyType(prop);
7221       exp.expType = prop.dataType;
7222       if(prop.dataType) prop.dataType.refCount++;
7223       return true;
7224    }
7225    else if((member = eClass_FindDataMember(_class, id.string, privateModule, null, null)))
7226    {
7227       if(!member.dataType)
7228          member.dataType = ProcessTypeString(member.dataTypeString, false);
7229       exp.expType = member.dataType;
7230       if(member.dataType) member.dataType.refCount++;
7231       return true;
7232    }
7233    else if((classProp = eClass_FindClassProperty(_class, id.string)))
7234    {
7235       if(!classProp.dataType)
7236          classProp.dataType = ProcessTypeString(classProp.dataTypeString, false);
7237
7238       if(classProp.constant)
7239       {
7240          FreeExpContents(exp);
7241
7242          exp.isConstant = true;
7243          if(classProp.dataType.kind == pointerType && classProp.dataType.type.kind == charType)
7244          {
7245             //char constant[256];
7246             exp.type = stringExp;
7247             exp.constant = QMkString((char *)(uintptr)classProp.Get(_class));
7248          }
7249          else
7250          {
7251             char constant[256];
7252             exp.type = constantExp;
7253             sprintf(constant, "%d", (int)classProp.Get(_class));
7254             exp.constant = CopyString(constant);
7255          }
7256       }
7257       else
7258       {
7259          // TO IMPLEMENT...
7260       }
7261
7262       exp.expType = classProp.dataType;
7263       if(classProp.dataType) classProp.dataType.refCount++;
7264       return true;
7265    }
7266    return false;
7267 }
7268
7269 static GlobalData ScanGlobalData(NameSpace nameSpace, char * name)
7270 {
7271    BinaryTree * tree = &nameSpace.functions;
7272    GlobalData data = (GlobalData)tree->FindString(name);
7273    NameSpace * child;
7274    if(!data)
7275    {
7276       for(child = (NameSpace *)nameSpace.nameSpaces.first; child; child = (NameSpace *)((BTNode)child).next)
7277       {
7278          data = ScanGlobalData(child, name);
7279          if(data)
7280             break;
7281       }
7282    }
7283    return data;
7284 }
7285
7286 static GlobalData FindGlobalData(char * name)
7287 {
7288    int start = 0, c;
7289    NameSpace * nameSpace;
7290    nameSpace = globalData;
7291    for(c = 0; name[c]; c++)
7292    {
7293       if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
7294       {
7295          NameSpace * newSpace;
7296          char * spaceName = new char[c - start + 1];
7297          strncpy(spaceName, name + start, c - start);
7298          spaceName[c-start] = '\0';
7299          newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
7300          delete spaceName;
7301          if(!newSpace)
7302             return null;
7303          nameSpace = newSpace;
7304          if(name[c] == ':') c++;
7305          start = c+1;
7306       }
7307    }
7308    if(c - start)
7309    {
7310       return ScanGlobalData(nameSpace, name + start);
7311    }
7312    return null;
7313 }
7314
7315 static int definedExpStackPos;
7316 static void * definedExpStack[512];
7317
7318 // This function makes checkedExp equivalent to newExp, ending up freeing newExp
7319 void ReplaceExpContents(Expression checkedExp, Expression newExp)
7320 {
7321    Expression prev = checkedExp.prev, next = checkedExp.next;
7322
7323    FreeExpContents(checkedExp);
7324    FreeType(checkedExp.expType);
7325    FreeType(checkedExp.destType);
7326
7327    *checkedExp = *newExp;
7328
7329    delete newExp;
7330
7331    checkedExp.prev = prev;
7332    checkedExp.next = next;
7333 }
7334
7335 void ApplyAnyObjectLogic(Expression e)
7336 {
7337    Type destType = /*(e.destType && e.destType.kind == ellipsisType) ? ellipsisDestType : */e.destType;
7338 #ifdef _DEBUG
7339    char debugExpString[4096];
7340    debugExpString[0] = '\0';
7341    PrintExpression(e, debugExpString);
7342 #endif
7343
7344    if(destType && (/*destType.classObjectType == ClassObjectType::typedObject || */destType.classObjectType == anyObject))
7345    {
7346       //if(e.destType && e.destType.kind == ellipsisType) usedEllipsis = true;
7347       //ellipsisDestType = destType;
7348       if(e && e.expType)
7349       {
7350          Type type = e.expType;
7351          Class _class = null;
7352          //Type destType = e.destType;
7353
7354          if(type.kind == classType && type._class && type._class.registered)
7355          {
7356             _class = type._class.registered;
7357          }
7358          else if(type.kind == subClassType)
7359          {
7360             _class = FindClass("ecere::com::Class").registered;
7361          }
7362          else
7363          {
7364             char string[1024] = "";
7365             Symbol classSym;
7366
7367             PrintTypeNoConst(type, string, false, true);
7368             classSym = FindClass(string);
7369             if(classSym) _class = classSym.registered;
7370          }
7371
7372          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...
7373             (!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))) ||
7374             destType.byReference)))
7375          {
7376             if(!_class || strcmp(_class.fullName, "char *"))     // TESTING THIS WITH NEW String class...
7377             {
7378                Expression checkedExp = e, newExp;
7379
7380                while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7381                {
7382                   if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7383                   {
7384                      if(checkedExp.type == extensionCompoundExp)
7385                      {
7386                         checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7387                      }
7388                      else
7389                         checkedExp = checkedExp.list->last;
7390                   }
7391                   else if(checkedExp.type == castExp)
7392                      checkedExp = checkedExp.cast.exp;
7393                }
7394
7395                if(checkedExp && checkedExp.type == opExp && checkedExp.op.op == '*' && !checkedExp.op.exp1)
7396                {
7397                   newExp = checkedExp.op.exp2;
7398                   checkedExp.op.exp2 = null;
7399                   FreeExpContents(checkedExp);
7400
7401                   if(e.expType && e.expType.passAsTemplate)
7402                   {
7403                      char size[100];
7404                      ComputeTypeSize(e.expType);
7405                      sprintf(size, "%d", e.expType.size);   // Potential 32/64 Bootstrap issue
7406                      newExp = MkExpBrackets(MkListOne(MkExpOp(MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)),
7407                         MkDeclaratorPointer(MkPointer(null, null), null)), newExp), '+',
7408                            MkExpCall(MkExpIdentifier(MkIdentifier("__ENDIAN_PAD")), MkListOne(MkExpConstant(size))))));
7409                   }
7410
7411                   ReplaceExpContents(checkedExp, newExp);
7412                   e.byReference = true;
7413                }
7414                else if(!e.byReference || (_class && _class.type == noHeadClass))     // TESTING THIS HERE...
7415                {
7416                   Expression checkedExp; //, newExp;
7417
7418                   {
7419                      // TODO: Move code from debugTools.ec for hasAddress flag, this is just temporary
7420                      bool hasAddress =
7421                         e.type == identifierExp ||
7422                         (e.type == ExpressionType::memberExp && e.member.memberType == dataMember) ||
7423                         (e.type == ExpressionType::pointerExp && e.member.memberType == dataMember) ||
7424                         (e.type == opExp && !e.op.exp1 && e.op.op == '*') ||
7425                         e.type == indexExp;
7426
7427                      if(_class && _class.type != noHeadClass && _class.type != normalClass && _class.type != structClass && !hasAddress)
7428                      {
7429                         Context context = PushContext();
7430                         Declarator decl;
7431                         OldList * specs = MkList();
7432                         char typeString[1024];
7433                         Expression newExp { };
7434
7435                         typeString[0] = '\0';
7436                         *newExp = *e;
7437
7438                         //if(e.destType) e.destType.refCount++;
7439                         // if(exp.expType) exp.expType.refCount++;
7440                         newExp.prev = null;
7441                         newExp.next = null;
7442                         newExp.expType = null;
7443
7444                         PrintTypeNoConst(e.expType, typeString, false, true);
7445                         decl = SpecDeclFromString(typeString, specs, null);
7446                         newExp.destType = ProcessType(specs, decl);
7447
7448                         curContext = context;
7449
7450                         // We need a current compound for this
7451                         if(curCompound)
7452                         {
7453                            char name[100];
7454                            OldList * stmts = MkList();
7455                            e.type = extensionCompoundExp;
7456                            sprintf(name, "__internalValue%03X", internalValueCounter++);
7457                            if(!curCompound.compound.declarations)
7458                               curCompound.compound.declarations = MkList();
7459                            curCompound.compound.declarations->Insert(null, MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(name)), null))));
7460                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(name)), '=', newExp))));
7461                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier(name)))));
7462                            e.compound = MkCompoundStmt(null, stmts);
7463                         }
7464                         else
7465                            printf("libec: compiler error, curCompound is null in ApplyAnyObjectLogic\n");
7466
7467                         /*
7468                         e.compound = MkCompoundStmt(
7469                            MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(
7470                               MkDeclaratorIdentifier(MkIdentifier("__internalValue")), MkInitializerAssignment(newExp))))),
7471
7472                            MkListOne(MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier("__internalValue"))))));
7473                         */
7474
7475                         {
7476                            Type type = e.destType;
7477                            e.destType = { };
7478                            CopyTypeInto(e.destType, type);
7479                            e.destType.refCount = 1;
7480                            e.destType.classObjectType = none;
7481                            FreeType(type);
7482                         }
7483
7484                         e.compound.compound.context = context;
7485                         PopContext(context);
7486                         curContext = context.parent;
7487                      }
7488                   }
7489
7490                   // TODO: INTEGRATE THIS WITH VERSION ABOVE WHICH WAS ADDED TO ENCOMPASS OTHER CASE (*pointer)
7491                   checkedExp = e;
7492                   while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7493                   {
7494                      if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7495                      {
7496                         if(checkedExp.type == extensionCompoundExp)
7497                         {
7498                            checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7499                         }
7500                         else
7501                            checkedExp = checkedExp.list->last;
7502                      }
7503                      else if(checkedExp.type == castExp)
7504                         checkedExp = checkedExp.cast.exp;
7505                   }
7506                   {
7507                      Expression operand { };
7508                      operand = *checkedExp;
7509                      checkedExp.Clear();
7510                      checkedExp.destType = ProcessTypeString("void *", false);
7511                      checkedExp.expType = checkedExp.destType;
7512                      checkedExp.destType.refCount++;
7513
7514                      checkedExp.type = opExp;
7515                      checkedExp.op.op = '&';
7516                      checkedExp.op.exp1 = null;
7517                      checkedExp.op.exp2 = operand;
7518
7519                      //newExp = MkExpOp(null, '&', checkedExp);
7520                   }
7521                   //ReplaceExpContents(checkedExp, newExp);
7522                }
7523             }
7524          }
7525       }
7526    }
7527    {
7528       // If expression type is a simple class, make it an address
7529       // FixReference(e, true);
7530    }
7531 //#if 0
7532    if((!destType || destType.kind == ellipsisType || destType.kind == voidType) && e.expType && (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7533       (e.expType.byReference || (e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7534          (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass ) )))
7535    {
7536       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"))
7537       {
7538          return;  // LEAVE THIS CASE (typed_object & :: methods 's this) TO PASS 2 FOR NOW
7539       }
7540       else
7541       {
7542          Expression thisExp { };
7543
7544          *thisExp = *e;
7545          thisExp.prev = null;
7546          thisExp.next = null;
7547          e.Clear();
7548
7549          e.type = bracketsExp;
7550          e.list = MkListOne(MkExpOp(null, '*', thisExp.type == identifierExp ? thisExp : MkExpBrackets(MkListOne(thisExp))));
7551          if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && thisExp.expType._class.registered.type == noHeadClass)
7552             ((Expression)e.list->first).byReference = true;
7553
7554          /*if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && !strcmp(thisExp.expType._class.registered.name, "class"))
7555          {
7556             e.expType = thisExp.expType;
7557             e.expType.refCount++;
7558          }
7559          else*/
7560          {
7561             e.expType = { };
7562             CopyTypeInto(e.expType, thisExp.expType);
7563             e.expType.byReference = false;
7564             e.expType.refCount = 1;
7565
7566             if(e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7567                (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass))
7568             {
7569                e.expType.classObjectType = none;
7570             }
7571          }
7572       }
7573    }
7574 // TOFIX: Try this for a nice IDE crash!
7575 //#endif
7576    // The other way around
7577    else
7578 //#endif
7579    if(destType && e.expType &&
7580          //e.expType.kind == classType && e.expType._class && e.expType._class.registered && !strcmp(e.expType._class.registered.name, "class") &&
7581          (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7582          !destType.classObjectType && /*(destType.kind != pointerType || !destType.type || destType.type.kind != voidType) &&*/ destType.kind != voidType)
7583    {
7584       if(destType.kind == ellipsisType)
7585       {
7586          Compiler_Error($"Unspecified type\n");
7587       }
7588       else if(!(destType.truth && e.expType.kind == classType && e.expType._class && e.expType._class.registered && e.expType._class.registered.type == structClass))
7589       {
7590          bool byReference = e.expType.byReference;
7591          Expression thisExp { };
7592          Declarator decl;
7593          OldList * specs = MkList();
7594          char typeString[1024]; // Watch buffer overruns
7595          Type type;
7596          ClassObjectType backupClassObjectType;
7597          bool backupByReference;
7598
7599          if(e.expType.kind == classType && e.expType._class && e.expType._class.registered && strcmp(e.expType._class.registered.name, "class"))
7600             type = e.expType;
7601          else
7602             type = destType;
7603
7604          backupClassObjectType = type.classObjectType;
7605          backupByReference = type.byReference;
7606
7607          type.classObjectType = none;
7608          type.byReference = false;
7609
7610          typeString[0] = '\0';
7611          PrintType(type, typeString, false, true);
7612          decl = SpecDeclFromString(typeString, specs, null);
7613
7614          type.classObjectType = backupClassObjectType;
7615          type.byReference = backupByReference;
7616
7617          *thisExp = *e;
7618          thisExp.prev = null;
7619          thisExp.next = null;
7620          e.Clear();
7621
7622          if( ( type.kind == classType && type._class && type._class.registered &&
7623                    (type._class.registered.type == systemClass || type._class.registered.type == bitClass ||
7624                     type._class.registered.type == enumClass || type._class.registered.type == unitClass) ) ||
7625              (type.kind != pointerType && type.kind != intPtrType && type.kind != arrayType && type.kind != classType) ||
7626              (!destType.byReference && byReference && (destType.kind != pointerType || type.kind != pointerType)))
7627          {
7628             bool passAsTemplate = thisExp.destType.passAsTemplate;
7629             Type t;
7630
7631             destType.refCount++;
7632
7633             e.type = opExp;
7634             e.op.op = '*';
7635             e.op.exp1 = null;
7636             e.op.exp2 = MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), thisExp);
7637
7638             t = { };
7639             CopyTypeInto(t, thisExp.destType);
7640             t.passAsTemplate = false;
7641             FreeType(thisExp.destType);
7642             thisExp.destType = t;
7643
7644             t = { };
7645             CopyTypeInto(t, destType);
7646             t.passAsTemplate = passAsTemplate;
7647             FreeType(destType);
7648             destType = t;
7649             destType.refCount = 0;
7650
7651             e.expType = { };
7652             CopyTypeInto(e.expType, type);
7653             if(type.passAsTemplate)
7654             {
7655                e.expType.classObjectType = none;
7656                e.expType.passAsTemplate = false;
7657             }
7658             e.expType.byReference = false;
7659             e.expType.refCount = 1;
7660          }
7661          else
7662          {
7663             e.type = castExp;
7664             e.cast.typeName = MkTypeName(specs, decl);
7665             e.cast.exp = thisExp;
7666             e.byReference = true;
7667             e.expType = type;
7668             type.refCount++;
7669          }
7670
7671          if(e.destType)
7672             FreeType(e.destType);
7673
7674          e.destType = destType;
7675          destType.refCount++;
7676       }
7677    }
7678 }
7679
7680 void ApplyLocation(Expression exp, Location loc)
7681 {
7682    exp.loc = loc;
7683    switch(exp.type)
7684    {
7685       case opExp:
7686          if(exp.op.exp1) ApplyLocation(exp.op.exp1, loc);
7687          if(exp.op.exp2) ApplyLocation(exp.op.exp2, loc);
7688          break;
7689       case bracketsExp:
7690          if(exp.list)
7691          {
7692             Expression e;
7693             for(e = exp.list->first; e; e = e.next)
7694                ApplyLocation(e, loc);
7695          }
7696          break;
7697       case indexExp:
7698          if(exp.index.index)
7699          {
7700             Expression e;
7701             for(e = exp.index.index->first; e; e = e.next)
7702                ApplyLocation(e, loc);
7703          }
7704          if(exp.index.exp)
7705             ApplyLocation(exp.index.exp, loc);
7706          break;
7707       case callExp:
7708          if(exp.call.arguments)
7709          {
7710             Expression arg;
7711             for(arg = exp.call.arguments->first; arg; arg = arg.next)
7712                ApplyLocation(arg, loc);
7713          }
7714          if(exp.call.exp)
7715             ApplyLocation(exp.call.exp, loc);
7716          break;
7717       case memberExp:
7718       case pointerExp:
7719          if(exp.member.exp)
7720             ApplyLocation(exp.member.exp, loc);
7721          break;
7722       case castExp:
7723          if(exp.cast.exp)
7724             ApplyLocation(exp.cast.exp, loc);
7725          break;
7726       case conditionExp:
7727          if(exp.cond.exp)
7728          {
7729             Expression e;
7730             for(e = exp.cond.exp->first; e; e = e.next)
7731                ApplyLocation(e, loc);
7732          }
7733          if(exp.cond.cond)
7734             ApplyLocation(exp.cond.cond, loc);
7735          if(exp.cond.elseExp)
7736             ApplyLocation(exp.cond.elseExp, loc);
7737          break;
7738       case vaArgExp:
7739          if(exp.vaArg.exp)
7740             ApplyLocation(exp.vaArg.exp, loc);
7741          break;
7742       default:
7743          break;
7744    }
7745 }
7746
7747 void ProcessExpressionType(Expression exp)
7748 {
7749    bool unresolved = false;
7750    Location oldyylloc = yylloc;
7751    bool notByReference = false;
7752 #ifdef _DEBUG
7753    char debugExpString[4096];
7754    debugExpString[0] = '\0';
7755    PrintExpression(exp, debugExpString);
7756 #endif
7757    if(!exp || exp.expType)
7758       return;
7759
7760    //eSystem_Logf("%s\n", expString);
7761
7762    // Testing this here
7763    yylloc = exp.loc;
7764    switch(exp.type)
7765    {
7766       case identifierExp:
7767       {
7768          Identifier id = exp.identifier;
7769          if(!id || !topContext) return;
7770
7771          // DOING THIS LATER NOW...
7772          if(id._class && id._class.name)
7773          {
7774             id.classSym = id._class.symbol; // FindClass(id._class.name);
7775             /* TODO: Name Space Fix ups
7776             if(!id.classSym)
7777                id.nameSpace = eSystem_FindNameSpace(privateModule, id._class.name);
7778             */
7779          }
7780
7781          /* WHY WAS THIS COMMENTED OUT? if(!strcmp(id.string, "__thisModule"))
7782          {
7783             exp.expType = ProcessTypeString("Module", true);
7784             break;
7785          }
7786          else */
7787          if(!strcmp(id.string, "__runtimePlatform"))
7788          {
7789             exp.expType = ProcessTypeString("ecere::com::Platform", true);
7790             break;
7791          }
7792          else if(strstr(id.string, "__ecereClass") == id.string)
7793          {
7794             exp.expType = ProcessTypeString("ecere::com::Class", true);
7795             break;
7796          }
7797          else if(id._class && (id.classSym || (id._class.name && !strcmp(id._class.name, "property"))))
7798          {
7799             // Added this here as well
7800             ReplaceClassMembers(exp, thisClass);
7801             if(exp.type != identifierExp)
7802             {
7803                ProcessExpressionType(exp);
7804                break;
7805             }
7806
7807             if(id.classSym && ResolveIdWithClass(exp, id.classSym.registered, false))
7808                break;
7809          }
7810          else
7811          {
7812             Symbol symbol = FindSymbol(id.string, curContext, topContext /*exp.destType ? topContext : globalContext*/, false, id._class && id._class.name == null);
7813             // Enums should be resolved here (Special pass in opExp to fix identifiers not seen as enum on the first pass)
7814             if(!symbol/* && exp.destType*/)
7815             {
7816                if(exp.destType && CheckExpressionType(exp, exp.destType, false, false))
7817                   break;
7818                else
7819                {
7820                   if(thisClass)
7821                   {
7822                      ReplaceClassMembers(exp, thisClass ? thisClass : currentClass);
7823                      if(exp.type != identifierExp)
7824                      {
7825                         ProcessExpressionType(exp);
7826                         break;
7827                      }
7828                   }
7829                   // Static methods called from inside the _class
7830                   else if(currentClass && !id._class)
7831                   {
7832                      if(ResolveIdWithClass(exp, currentClass, true))
7833                         break;
7834                   }
7835                   symbol = FindSymbol(id.string, topContext.parent, globalContext, false, id._class && id._class.name == null);
7836                }
7837             }
7838
7839             // If we manage to resolve this symbol
7840             if(symbol)
7841             {
7842                Type type = symbol.type;
7843                Class _class = (type && type.kind == classType && type._class) ? type._class.registered : null;
7844
7845                if(_class && !strcmp(id.string, "this") && !type.classObjectType)
7846                {
7847                   Context context = SetupTemplatesContext(_class);
7848                   type = ReplaceThisClassType(_class);
7849                   FinishTemplatesContext(context);
7850                   if(type) type.refCount = 0;   // We'll be incrementing it right below...
7851                }
7852
7853                FreeSpecifier(id._class);
7854                id._class = null;
7855                delete id.string;
7856                id.string = CopyString(symbol.string);
7857
7858                id.classSym = null;
7859                exp.expType = type;
7860                if(type)
7861                   type.refCount++;
7862
7863                                                 // Commented this out, it was making non-constant enum parameters seen as constant
7864                                                 // enums should have been resolved by ResolveIdWithClass, changed to constantExp and marked as constant
7865                if(type && (type.kind == enumType /*|| (_class && _class.type == enumClass)*/))
7866                   // Add missing cases here... enum Classes...
7867                   exp.isConstant = true;
7868
7869                // TOCHECK: Why was !strcmp(id.string, "this") commented out?
7870                if(symbol.isParam || !strcmp(id.string, "this"))
7871                {
7872                   if(_class && _class.type == structClass && !type.declaredWithStruct)
7873                      exp.byReference = true;
7874
7875                   //TESTING COMMENTING THIS OUT IN FAVOR OF ApplyAnyObjectLogic
7876                   /*if(type && _class && (type.classObjectType == typedObject || type.classObjectType == anyObject) &&
7877                      ((_class.type == unitClass || _class.type == enumClass || _class.type == bitClass) ||
7878                      (type.byReference && (_class.type == normalClass || _class.type == noHeadClass))))
7879                   {
7880                      Identifier id = exp.identifier;
7881                      exp.type = bracketsExp;
7882                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(id)));
7883                   }*/
7884                }
7885
7886                if(symbol.isIterator)
7887                {
7888                   if(symbol.isIterator == 3)
7889                   {
7890                      exp.type = bracketsExp;
7891                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(exp.identifier)));
7892                      ((Expression)exp.list->first).op.exp2.expType = exp.expType;
7893                      exp.expType = null;
7894                      ProcessExpressionType(exp);
7895                   }
7896                   else if(symbol.isIterator != 4)
7897                   {
7898                      exp.type = memberExp;
7899                      exp.member.exp = MkExpIdentifier(exp.identifier);
7900                      exp.member.exp.expType = exp.expType;
7901                      /*if(symbol.isIterator == 6)
7902                         exp.member.member = MkIdentifier("key");
7903                      else*/
7904                         exp.member.member = MkIdentifier("data");
7905                      exp.expType = null;
7906                      ProcessExpressionType(exp);
7907                   }
7908                }
7909                break;
7910             }
7911             else
7912             {
7913                DefinedExpression definedExp = null;
7914                if(thisNameSpace && !(id._class && !id._class.name))
7915                {
7916                   char name[1024];
7917                   strcpy(name, thisNameSpace);
7918                   strcat(name, "::");
7919                   strcat(name, id.string);
7920                   definedExp = eSystem_FindDefine(privateModule, name);
7921                }
7922                if(!definedExp)
7923                   definedExp = eSystem_FindDefine(privateModule, id.string);
7924                if(definedExp)
7925                {
7926                   int c;
7927                   for(c = 0; c<definedExpStackPos; c++)
7928                      if(definedExpStack[c] == definedExp)
7929                         break;
7930                   if(c == definedExpStackPos && c < sizeof(definedExpStack) / sizeof(void *))
7931                   {
7932                      Location backupYylloc = yylloc;
7933                      File backInput = fileInput;
7934                      definedExpStack[definedExpStackPos++] = definedExp;
7935
7936                      fileInput = TempFile { };
7937                      fileInput.Write(definedExp.value, 1, strlen(definedExp.value));
7938                      fileInput.Seek(0, start);
7939
7940                      echoOn = false;
7941                      parsedExpression = null;
7942                      resetScanner();
7943                      expression_yyparse();
7944                      delete fileInput;
7945                      if(backInput)
7946                         fileInput = backInput;
7947
7948                      yylloc = backupYylloc;
7949
7950                      if(parsedExpression)
7951                      {
7952                         FreeIdentifier(id);
7953                         exp.type = bracketsExp;
7954                         exp.list = MkListOne(parsedExpression);
7955                         ApplyLocation(parsedExpression, yylloc);
7956                         ProcessExpressionType(exp);
7957                         definedExpStackPos--;
7958                         return;
7959                      }
7960                      definedExpStackPos--;
7961                   }
7962                   else
7963                   {
7964                      if(inCompiler)
7965                      {
7966                         Compiler_Error($"Recursion in defined expression %s\n", id.string);
7967                      }
7968                   }
7969                }
7970                else
7971                {
7972                   GlobalData data = null;
7973                   if(thisNameSpace && !(id._class && !id._class.name))
7974                   {
7975                      char name[1024];
7976                      strcpy(name, thisNameSpace);
7977                      strcat(name, "::");
7978                      strcat(name, id.string);
7979                      data = FindGlobalData(name);
7980                   }
7981                   if(!data)
7982                      data = FindGlobalData(id.string);
7983                   if(data)
7984                   {
7985                      DeclareGlobalData(curExternal, data);
7986                      exp.expType = data.dataType;
7987                      if(data.dataType) data.dataType.refCount++;
7988
7989                      delete id.string;
7990                      id.string = CopyString(data.fullName);
7991                      FreeSpecifier(id._class);
7992                      id._class = null;
7993
7994                      break;
7995                   }
7996                   else
7997                   {
7998                      GlobalFunction function = null;
7999                      if(thisNameSpace && !(id._class && !id._class.name))
8000                      {
8001                         char name[1024];
8002                         strcpy(name, thisNameSpace);
8003                         strcat(name, "::");
8004                         strcat(name, id.string);
8005                         function = eSystem_FindFunction(privateModule, name);
8006                      }
8007                      if(!function)
8008                         function = eSystem_FindFunction(privateModule, id.string);
8009                      if(function)
8010                      {
8011                         char name[1024];
8012                         delete id.string;
8013                         id.string = CopyString(function.name);
8014                         name[0] = 0;
8015
8016                         if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
8017                            strcpy(name, "__ecereFunction_");
8018                         FullClassNameCat(name, id.string, false); // Why is this using FullClassNameCat ?
8019                         if(DeclareFunction(curExternal, function, name))
8020                         {
8021                            delete id.string;
8022                            id.string = CopyString(name);
8023                         }
8024                         exp.expType = function.dataType;
8025                         if(function.dataType) function.dataType.refCount++;
8026
8027                         FreeSpecifier(id._class);
8028                         id._class = null;
8029
8030                         break;
8031                      }
8032                   }
8033                }
8034             }
8035          }
8036          unresolved = true;
8037          break;
8038       }
8039       case instanceExp:
8040       {
8041          // Class _class;
8042          // Symbol classSym;
8043
8044          if(!exp.instance._class)
8045          {
8046             if(exp.destType && exp.destType.kind == classType && exp.destType._class)
8047             {
8048                exp.instance._class = MkSpecifierName(exp.destType._class.string);
8049             }
8050          }
8051
8052          //classSym = FindClass(exp.instance._class.fullName);
8053          //_class = classSym ? classSym.registered : null;
8054
8055          ProcessInstantiationType(exp.instance);
8056
8057          exp.isConstant = exp.instance.isConstant;
8058
8059          /*
8060          if(_class.type == unitClass && _class.base.type != systemClass)
8061          {
8062             {
8063                Type destType = exp.destType;
8064
8065                exp.destType = MkClassType(_class.base.fullName);
8066                exp.expType = MkClassType(_class.fullName);
8067                CheckExpressionType(exp, exp.destType, true);
8068
8069                exp.destType = destType;
8070             }
8071             exp.expType = MkClassType(_class.fullName);
8072          }
8073          else*/
8074          if(exp.instance._class)
8075          {
8076             exp.expType = MkClassType(exp.instance._class.name);
8077             /*if(exp.expType._class && exp.expType._class.registered &&
8078                (exp.expType._class.registered.type == normalClass || exp.expType._class.registered.type == noHeadClass))
8079                exp.expType.byReference = true;*/
8080          }
8081          break;
8082       }
8083       case constantExp:
8084       {
8085          if(!exp.expType)
8086          {
8087             char * constant = exp.constant;
8088             Type type
8089             {
8090                refCount = 1;
8091                constant = true;
8092             };
8093             exp.expType = type;
8094
8095             if(constant[0] == '\'')
8096             {
8097                if((int)((byte *)constant)[1] > 127)
8098                {
8099                   int nb;
8100                   unichar ch = UTF8GetChar(constant + 1, &nb);
8101                   if(nb < 2) ch = constant[1];
8102                   delete constant;
8103                   exp.constant = PrintUInt(ch);
8104                   // type.kind = (ch > 0xFFFF) ? intType : shortType;
8105                   type.kind = classType; //(ch > 0xFFFF) ? intType : shortType;
8106                   type._class = FindClass("unichar");
8107
8108                   type.isSigned = false;
8109                }
8110                else
8111                {
8112                   type.kind = charType;
8113                   type.isSigned = true;
8114                }
8115             }
8116             else
8117             {
8118                char * dot = strchr(constant, '.');
8119                bool isHex = (constant[0] == '0' && (constant[1] == 'x' || constant[1] == 'X'));
8120                char * exponent;
8121                if(isHex)
8122                {
8123                   exponent = strchr(constant, 'p');
8124                   if(!exponent) exponent = strchr(constant, 'P');
8125                }
8126                else
8127                {
8128                   exponent = strchr(constant, 'e');
8129                   if(!exponent) exponent = strchr(constant, 'E');
8130                }
8131
8132                if(dot || exponent)
8133                {
8134                   if(strchr(constant, 'f') || strchr(constant, 'F'))
8135                      type.kind = floatType;
8136                   else
8137                      type.kind = doubleType;
8138                   type.isSigned = true;
8139                }
8140                else
8141                {
8142                   bool isSigned = constant[0] == '-';
8143                   char * endP = null;
8144                   int64 i64 = strtoll(constant, &endP, 0);
8145                   uint64 ui64 = strtoull(constant, &endP, 0);
8146                   bool is64Bit = endP && (!strcmp(endP, "LL") || !strcmp(endP, "ll") || !strcmp(endP, "LLU") || !strcmp(endP, "llu") || !strcmp(endP, "ull") || !strcmp(endP, "ULL"));
8147                   bool forceUnsigned = endP && (!strcmp(endP, "U") || !strcmp(endP, "u") || !strcmp(endP, "LLU") || !strcmp(endP, "llu") || !strcmp(endP, "ull") || !strcmp(endP, "ULL"));
8148                   if(isSigned)
8149                   {
8150                      if(i64 < MININT)
8151                         is64Bit = true;
8152                   }
8153                   else
8154                   {
8155                      if(ui64 > MAXINT)
8156                      {
8157                         if(ui64 > MAXDWORD)
8158                         {
8159                            is64Bit = true;
8160                            if(ui64 <= MAXINT64 && (constant[0] != '0' || !constant[1]))
8161                               isSigned = true;
8162                         }
8163                      }
8164                      else if(constant[0] != '0' || !constant[1])
8165                         isSigned = true;
8166                   }
8167                   if(forceUnsigned)
8168                      isSigned = false;
8169                   type.kind = is64Bit ? int64Type : intType;
8170                   type.isSigned = isSigned;
8171                }
8172             }
8173             exp.isConstant = true;
8174             if(exp.destType && exp.destType.kind == doubleType)
8175                type.kind = doubleType;
8176             else if(exp.destType && exp.destType.kind == floatType)
8177                type.kind = floatType;
8178             else if(exp.destType && exp.destType.kind == int64Type)
8179                type.kind = int64Type;
8180          }
8181          break;
8182       }
8183       case stringExp:
8184       {
8185          exp.isConstant = true;      // Why wasn't this constant?
8186          exp.expType = Type
8187          {
8188             refCount = 1;
8189             kind = pointerType;
8190             type = Type
8191             {
8192                refCount = 1;
8193                kind = exp.wideString ? shortType : charType;
8194                constant = true;
8195                isSigned = exp.wideString ? false : true;
8196             }
8197          };
8198          break;
8199       }
8200       case newExp:
8201       case new0Exp:
8202          ProcessExpressionType(exp._new.size);
8203          exp.expType = Type
8204          {
8205             refCount = 1;
8206             kind = pointerType;
8207             type = ProcessType(exp._new.typeName.qualifiers, exp._new.typeName.declarator);
8208          };
8209          DeclareType(curExternal, exp.expType.type, true, false);
8210          break;
8211       case renewExp:
8212       case renew0Exp:
8213          ProcessExpressionType(exp._renew.size);
8214          ProcessExpressionType(exp._renew.exp);
8215          exp.expType = Type
8216          {
8217             refCount = 1;
8218             kind = pointerType;
8219             type = ProcessType(exp._renew.typeName.qualifiers, exp._renew.typeName.declarator);
8220          };
8221          DeclareType(curExternal, exp.expType.type, true, false);
8222          break;
8223       case opExp:
8224       {
8225          bool assign = false, boolResult = false, boolOps = false;
8226          Type type1 = null, type2 = null;
8227          bool useDestType = false, useSideType = false;
8228          Location oldyylloc = yylloc;
8229          bool useSideUnit = false;
8230          Class destClass = (exp.destType && exp.destType.kind == classType && exp.destType._class) ? exp.destType._class.registered : null;
8231
8232          // Dummy type to prevent ProcessExpression of operands to say unresolved identifiers yet
8233          Type dummy
8234          {
8235             count = 1;
8236             refCount = 1;
8237          };
8238
8239          switch(exp.op.op)
8240          {
8241             // Assignment Operators
8242             case '=':
8243             case MUL_ASSIGN:
8244             case DIV_ASSIGN:
8245             case MOD_ASSIGN:
8246             case ADD_ASSIGN:
8247             case SUB_ASSIGN:
8248             case LEFT_ASSIGN:
8249             case RIGHT_ASSIGN:
8250             case AND_ASSIGN:
8251             case XOR_ASSIGN:
8252             case OR_ASSIGN:
8253                assign = true;
8254                break;
8255             // boolean Operators
8256             case '!':
8257                // Expect boolean operators
8258                //boolOps = true;
8259                //boolResult = true;
8260                break;
8261             case AND_OP:
8262             case OR_OP:
8263                // Expect boolean operands
8264                boolOps = true;
8265                boolResult = true;
8266                break;
8267             // Comparisons
8268             case EQ_OP:
8269             case '<':
8270             case '>':
8271             case LE_OP:
8272             case GE_OP:
8273             case NE_OP:
8274                // Gives boolean result
8275                boolResult = true;
8276                useSideType = true;
8277                break;
8278             case '+':
8279             case '-':
8280                useSideUnit = true;
8281                useSideType = true;
8282                useDestType = true;
8283                break;
8284
8285             case LEFT_OP:
8286             case RIGHT_OP:
8287                // useSideType = true;
8288                // useDestType = true;
8289                break;
8290
8291             case '|':
8292             case '^':
8293                useSideType = true;
8294                useDestType = true;
8295                break;
8296
8297             case '/':
8298             case '%':
8299                useSideType = true;
8300                useDestType = true;
8301                break;
8302             case '&':
8303             case '*':
8304                if(exp.op.exp1)
8305                {
8306                   // For & operator, useDestType nicely ensures the result will fit in a bool (TODO: Fix for generic enum)
8307                   useSideType = true;
8308                   useDestType = true;
8309                }
8310                break;
8311
8312             /*// Implement speed etc.
8313             case '*':
8314             case '/':
8315                break;
8316             */
8317          }
8318          if(exp.op.op == '&')
8319          {
8320             // Added this here earlier for Iterator address as key
8321             if(!exp.op.exp1 && exp.op.exp2 && exp.op.exp2.type == identifierExp && exp.op.exp2.identifier)
8322             {
8323                Identifier id = exp.op.exp2.identifier;
8324                Symbol symbol = FindSymbol(id.string, curContext, topContext, false, id._class && id._class.name == null);
8325                if(symbol && symbol.isIterator == 2)
8326                {
8327                   exp.type = memberExp;
8328                   exp.member.exp = exp.op.exp2;
8329                   exp.member.member = MkIdentifier("key");
8330                   exp.expType = null;
8331                   exp.op.exp2.expType = symbol.type;
8332                   symbol.type.refCount++;
8333                   ProcessExpressionType(exp);
8334                   FreeType(dummy);
8335                   break;
8336                }
8337                // exp.op.exp2.usage.usageRef = true;
8338             }
8339          }
8340
8341          //dummy.kind = TypeDummy;
8342          if(exp.op.exp1)
8343          {
8344             // Added this check here to use the dest type only for units derived from the base unit
8345             // So that untyped units will use the side unit as opposed to the untyped destination unit
8346             // This fixes (#771) sin(Degrees { 5 } + 5) to be equivalent to sin(Degrees { 10 }), since sin expects a generic Angle
8347             if(exp.op.exp2 && useSideUnit && useDestType && destClass && destClass.type == unitClass && destClass.base.type != unitClass)
8348                useDestType = false;
8349
8350             if(destClass && useDestType &&
8351               ((destClass.type == unitClass && useSideUnit) || destClass.type == enumClass || destClass.type == bitClass))
8352
8353               //(exp.destType._class.registered.type == unitClass || exp.destType._class.registered.type == enumClass) && useDestType)
8354             {
8355                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8356                exp.op.exp1.destType = exp.destType;
8357                exp.op.exp1.opDestType = true;
8358                if(exp.destType)
8359                   exp.destType.refCount++;
8360             }
8361             else if(!assign)
8362             {
8363                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8364                exp.op.exp1.destType = dummy;
8365                dummy.refCount++;
8366             }
8367
8368             // TESTING THIS HERE...
8369             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count++;
8370                ProcessExpressionType(exp.op.exp1);
8371             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count--;
8372
8373             exp.op.exp1.opDestType = false;
8374
8375             // Fix for unit and ++ / --
8376             if(!exp.op.exp2 && (exp.op.op == INC_OP || exp.op.op == DEC_OP) && exp.op.exp1.expType && exp.op.exp1.expType.kind == classType &&
8377                exp.op.exp1.expType._class && exp.op.exp1.expType._class.registered && exp.op.exp1.expType._class.registered.type == unitClass)
8378             {
8379                exp.op.exp2 = MkExpConstant("1");
8380                exp.op.op = exp.op.op == INC_OP ? ADD_ASSIGN : SUB_ASSIGN;
8381                assign = true;
8382             }
8383
8384             if(exp.op.exp1.destType == dummy)
8385             {
8386                FreeType(dummy);
8387                exp.op.exp1.destType = null;
8388             }
8389
8390             if(exp.op.exp2)
8391             {
8392                if(!assign && exp.op.exp1.expType && (exp.op.exp1.expType.kind == charType || exp.op.exp1.expType.kind == shortType))
8393                {
8394                   Type type { kind = intType, isSigned = true, refCount = 1, signedBeforePromotion = exp.op.exp1.expType.isSigned, bitMemberSize = exp.op.exp1.expType.bitMemberSize, promotedFrom = exp.op.exp1.expType.kind };
8395                   FreeType(exp.op.exp1.expType);
8396                   exp.op.exp1.expType = type;
8397                }
8398             }
8399
8400             type1 = exp.op.exp1.expType;
8401          }
8402
8403          if(exp.op.exp2)
8404          {
8405             char expString[10240];
8406             expString[0] = '\0';
8407             if(exp.op.exp2.type == instanceExp && !exp.op.exp2.instance._class)
8408             {
8409                if(exp.op.exp1)
8410                {
8411                   exp.op.exp2.destType = exp.op.exp1.expType;
8412                   if(exp.op.exp1.expType)
8413                      exp.op.exp1.expType.refCount++;
8414                }
8415                else
8416                {
8417                   exp.op.exp2.destType = exp.destType;
8418                   if(!exp.op.exp1 || (exp.op.op != '&' && exp.op.op != '^'))
8419                      exp.op.exp2.opDestType = true;
8420                   if(exp.destType)
8421                      exp.destType.refCount++;
8422                }
8423
8424                if(type1) type1.refCount++;
8425                exp.expType = type1;
8426             }
8427             else if(assign)
8428             {
8429                if(inCompiler)
8430                   PrintExpression(exp.op.exp2, expString);
8431
8432                if(type1 && type1.kind == pointerType)
8433                {
8434                   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 ||
8435                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN)
8436                      Compiler_Error($"operator %s illegal on pointer\n", exp.op.op);
8437                   else if(exp.op.op == '=')
8438                   {
8439                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8440                      exp.op.exp2.destType = type1;
8441                      if(type1)
8442                         type1.refCount++;
8443                   }
8444                }
8445                else
8446                {
8447                   // Don't convert to the type for those... (e.g.: Degrees a; a /= 2;)
8448                   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/* ||
8449                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN*/);
8450                   else
8451                   {
8452                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8453                      exp.op.exp2.destType = type1;
8454                      if(type1)
8455                         type1.refCount++;
8456                   }
8457                }
8458                if(type1) type1.refCount++;
8459                exp.expType = type1;
8460             }
8461             else if(destClass &&
8462                   ((destClass.type == unitClass && useDestType && useSideUnit) ||
8463                   (destClass.type == enumClass && useDestType)))
8464             {
8465                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8466                exp.op.exp2.destType = exp.destType;
8467                if(exp.op.op != '&' && exp.op.op != '^')
8468                   exp.op.exp2.opDestType = true;
8469                if(exp.destType)
8470                   exp.destType.refCount++;
8471             }
8472             else
8473             {
8474                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8475                exp.op.exp2.destType = dummy;
8476                dummy.refCount++;
8477             }
8478
8479             // TESTING THIS HERE... (DANGEROUS)
8480             if(type1 && boolResult && useSideType && type1.kind == classType && type1._class && type1._class.registered &&
8481                (type1._class.registered.type == bitClass || type1._class.registered.type == enumClass))
8482             {
8483                FreeType(exp.op.exp2.destType);
8484                exp.op.exp2.destType = type1;
8485                type1.refCount++;
8486             }
8487             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count++;
8488             // Cannot lose the cast on a sizeof
8489             if(exp.op.op == SIZEOF)
8490             {
8491                Expression e = exp.op.exp2;
8492                while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
8493                {
8494                   if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
8495                   {
8496                      if(e.type == extensionCompoundExp)
8497                         e = ((Statement)e.compound.compound.statements->last).expressions->last;
8498                      else
8499                         e = e.list->last;
8500                   }
8501                }
8502                if(e.type == castExp && e.cast.exp)
8503                   e.cast.exp.needCast = true;
8504             }
8505             ProcessExpressionType(exp.op.exp2);
8506             exp.op.exp2.opDestType = false;
8507             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count--;
8508
8509             if(!assign && (exp.op.exp1 || exp.op.op == '~'))
8510             {
8511                if(exp.op.exp2.expType && (exp.op.exp2.expType.kind == charType || exp.op.exp2.expType.kind == shortType))
8512                {
8513                   Type type { kind = intType, isSigned = true, refCount = 1, signedBeforePromotion = exp.op.exp2.expType.isSigned, bitMemberSize = exp.op.exp2.expType.bitMemberSize, promotedFrom = exp.op.exp2.expType.kind };
8514                   FreeType(exp.op.exp2.expType);
8515                   exp.op.exp2.expType = type;
8516                }
8517             }
8518
8519             if(assign && type1 && type1.kind == pointerType && exp.op.exp2.expType)
8520             {
8521                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)
8522                {
8523                   if(exp.op.op != '=' && type1.type.kind == voidType)
8524                      Compiler_Error($"void *: unknown size\n");
8525                }
8526                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||
8527                            (type1.type.kind == voidType && exp.op.exp2.expType.kind == classType && exp.op.exp2.expType._class.registered &&
8528                               (exp.op.exp2.expType._class.registered.type == normalClass ||
8529                               exp.op.exp2.expType._class.registered.type == structClass ||
8530                               exp.op.exp2.expType._class.registered.type == noHeadClass)))
8531                {
8532                   if(exp.op.op == ADD_ASSIGN)
8533                      Compiler_Error($"cannot add two pointers\n");
8534                }
8535                else if((exp.op.exp2.expType.kind == classType && type1.kind == pointerType && type1.type.kind == classType &&
8536                   type1.type._class == exp.op.exp2.expType._class && exp.op.exp2.expType._class.registered && exp.op.exp2.expType._class.registered.type == structClass))
8537                {
8538                   if(exp.op.op == ADD_ASSIGN)
8539                      Compiler_Error($"cannot add two pointers\n");
8540                }
8541                else if(inCompiler)
8542                {
8543                   char type1String[1024];
8544                   char type2String[1024];
8545                   type1String[0] = '\0';
8546                   type2String[0] = '\0';
8547
8548                   PrintType(exp.op.exp2.expType, type1String, false, true);
8549                   PrintType(type1, type2String, false, true);
8550                   ChangeCh(expString, '\n', ' ');
8551                   Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1String, type2String);
8552                }
8553             }
8554
8555             if(exp.op.exp2.destType == dummy)
8556             {
8557                FreeType(dummy);
8558                exp.op.exp2.destType = null;
8559             }
8560
8561             if(exp.op.op == '-' && !exp.op.exp1 && exp.op.exp2.expType && !exp.op.exp2.expType.isSigned)
8562             {
8563                type2 = { };
8564                type2.refCount = 1;
8565                CopyTypeInto(type2, exp.op.exp2.expType);
8566                type2.isSigned = true;
8567             }
8568             else if(exp.op.op == '~' && !exp.op.exp1 && exp.op.exp2.expType && (!exp.op.exp2.expType.isSigned || exp.op.exp2.expType.kind != intType))
8569             {
8570                type2 = { kind = intType };
8571                type2.refCount = 1;
8572                type2.isSigned = true;
8573             }
8574             else
8575             {
8576                type2 = exp.op.exp2.expType;
8577                if(type2) type2.refCount++;
8578             }
8579          }
8580
8581          dummy.kind = voidType;
8582
8583          if(exp.op.op == SIZEOF)
8584          {
8585             exp.expType = Type
8586             {
8587                refCount = 1;
8588                kind = intSizeType;
8589             };
8590             exp.isConstant = true;
8591          }
8592          // Get type of dereferenced pointer
8593          else if(exp.op.op == '*' && !exp.op.exp1)
8594          {
8595             exp.expType = Dereference(type2);
8596             if(type2 && type2.kind == classType)
8597                notByReference = true;
8598          }
8599          else if(exp.op.op == '&' && !exp.op.exp1)
8600             exp.expType = Reference(type2);
8601          else if(exp.op.op == LEFT_OP || exp.op.op == RIGHT_OP)
8602          {
8603             if(exp.op.exp1.expType)
8604             {
8605                exp.expType = exp.op.exp1.expType;
8606                exp.expType.refCount++;
8607             }
8608          }
8609          else if(!assign)
8610          {
8611             if(boolOps)
8612             {
8613                if(exp.op.exp1)
8614                {
8615                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8616                   exp.op.exp1.destType = MkClassType("bool");
8617                   exp.op.exp1.destType.truth = true;
8618                   if(!exp.op.exp1.expType)
8619                      ProcessExpressionType(exp.op.exp1);
8620                   else
8621                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8622                   FreeType(exp.op.exp1.expType);
8623                   exp.op.exp1.expType = MkClassType("bool");
8624                   exp.op.exp1.expType.truth = true;
8625                }
8626                if(exp.op.exp2)
8627                {
8628                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8629                   exp.op.exp2.destType = MkClassType("bool");
8630                   exp.op.exp2.destType.truth = true;
8631                   if(!exp.op.exp2.expType)
8632                      ProcessExpressionType(exp.op.exp2);
8633                   else
8634                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8635                   FreeType(exp.op.exp2.expType);
8636                   exp.op.exp2.expType = MkClassType("bool");
8637                   exp.op.exp2.expType.truth = true;
8638                }
8639             }
8640             else if(exp.op.exp1 && exp.op.exp2 &&
8641                ((useSideType /*&&
8642                      (useSideUnit ||
8643                         ((!type1 || type1.kind != classType || type1._class.registered.type != unitClass) &&
8644                          (!type2 || type2.kind != classType || type2._class.registered.type != unitClass)))*/) ||
8645                   ((!type1 || type1.kind != classType || !strcmp(type1._class.string, "String")) &&
8646                   (!type2 || type2.kind != classType || !strcmp(type2._class.string, "String")))))
8647             {
8648                if(type1 && type2 &&
8649                   // If either both are class or both are not class
8650                   ((type1.kind == classType && type1._class && strcmp(type1._class.string, "String")) == (type2.kind == classType && type2._class && strcmp(type2._class.string, "String"))))
8651                {
8652                   // Added this check for enum subtraction to result in an int type:
8653                   if(exp.op.op == '-' &&
8654                      ((type1.kind == classType && type1._class.registered && type1._class.registered.type == enumClass) ||
8655                       (type2.kind == classType && type2._class.registered && type2._class.registered.type == enumClass)) )
8656                   {
8657                      Type intType;
8658                      if(!type1._class.registered.dataType)
8659                         type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
8660                      if(!type2._class.registered.dataType)
8661                         type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
8662
8663                      intType = ProcessTypeString(
8664                         (type1._class.registered.dataType.kind == int64Type || type2._class.registered.dataType.kind == int64Type) ? "int64" : "int", false);
8665
8666                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8667                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8668                      exp.op.exp1.destType = intType;
8669                      exp.op.exp2.destType = intType;
8670                      intType.refCount++;
8671                   }
8672                   else
8673                   {
8674                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8675                      exp.op.exp2.destType = type1;
8676                      type1.refCount++;
8677                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8678                      exp.op.exp1.destType = type2;
8679                      type2.refCount++;
8680                   }
8681
8682                   // Warning here for adding Radians + Degrees with no destination type
8683                   if(!boolResult && type1.kind == classType && (!exp.destType || exp.destType.kind != classType) &&
8684                      type1._class.registered && type1._class.registered.type == unitClass &&
8685                      type2._class.registered && type2._class.registered.type == unitClass &&
8686                      type1._class.registered != type2._class.registered)
8687                      Compiler_Warning($"operating on %s and %s with an untyped result, assuming %s\n",
8688                         type1._class.string, type2._class.string, type1._class.string);
8689
8690                   if(type1.kind == pointerType && type1.type.kind == templateType && type2.kind != pointerType)
8691                   {
8692                      Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8693                      if(argExp)
8694                      {
8695                         Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8696
8697                         exp.op.exp1 = MkExpBrackets(MkListOne(MkExpCast(
8698                            MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
8699                            exp.op.exp1)));
8700
8701                         ProcessExpressionType(exp.op.exp1);
8702
8703                         if(type2.kind != pointerType)
8704                         {
8705                            ProcessExpressionType(classExp);
8706
8707                            exp.op.exp2 = MkExpBrackets(MkListOne(MkExpOp(exp.op.exp2, '*', MkExpMember(classExp, MkIdentifier("typeSize")) )));
8708
8709                            if(!exp.op.exp2.expType)
8710                            {
8711                               if(type2)
8712                                  FreeType(type2);
8713                               type2 = exp.op.exp2.expType = ProcessTypeString("int", false);
8714                               type2.refCount++;
8715                            }
8716
8717                            ProcessExpressionType(exp.op.exp2);
8718                         }
8719                      }
8720                   }
8721
8722                   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)))
8723                   {
8724                      if(type1.kind != classType && type1.type.kind == voidType)
8725                         Compiler_Error($"void *: unknown size\n");
8726                      exp.expType = type1;
8727                      if(type1) type1.refCount++;
8728                   }
8729                   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)))
8730                   {
8731                      if(type2.kind != classType && type2.type.kind == voidType)
8732                         Compiler_Error($"void *: unknown size\n");
8733                      exp.expType = type2;
8734                      if(type2) type2.refCount++;
8735                   }
8736                   else if((type1.kind == pointerType && type2.kind != pointerType && type2.kind != arrayType && type2.kind != functionType && type2.kind != methodType && type2.kind != classType && type2.kind != subClassType) ||
8737                           (type2.kind == pointerType && type1.kind != pointerType && type1.kind != arrayType && type1.kind != functionType && type1.kind != methodType && type1.kind != classType && type1.kind != subClassType))
8738                   {
8739                      Compiler_Warning($"different levels of indirection\n");
8740                   }
8741                   else
8742                   {
8743                      bool success = false;
8744                      if(type1.kind == pointerType && type2.kind == pointerType)
8745                      {
8746                         if(exp.op.op == '+')
8747                            Compiler_Error($"cannot add two pointers\n");
8748                         else if(exp.op.op == '-')
8749                         {
8750                            // Pointer Subtraction gives integer
8751                            if(MatchTypes(type1.type, type2.type, null, null, null, false, false, false, false, false))
8752                            {
8753                               exp.expType = Type
8754                               {
8755                                  kind = intType;
8756                                  refCount = 1;
8757                               };
8758                               success = true;
8759
8760                               if(type1.type.kind == templateType)
8761                               {
8762                                  Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8763                                  if(argExp)
8764                                  {
8765                                     Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8766
8767                                     ProcessExpressionType(classExp);
8768
8769                                     exp.type = bracketsExp;
8770                                     exp.list = MkListOne(MkExpOp(
8771                                        MkExpBrackets(MkListOne(MkExpOp(
8772                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp1)))
8773                                              , exp.op.op,
8774                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp2)))))), '/',
8775                                              MkExpMember(classExp, MkIdentifier("typeSize"))));
8776
8777                                     ProcessExpressionType(((Expression)exp.list->first).op.exp2);
8778                                     FreeType(dummy);
8779                                     return;
8780                                  }
8781                               }
8782                            }
8783                         }
8784                      }
8785
8786                      if(!success && exp.op.exp1.type == constantExp)
8787                      {
8788                         // If first expression is constant, try to match that first
8789                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8790                         {
8791                            if(exp.expType) FreeType(exp.expType);
8792                            exp.expType = exp.op.exp1.destType;
8793                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8794                            success = true;
8795                         }
8796                         else if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
8797                         {
8798                            if(exp.expType) FreeType(exp.expType);
8799                            exp.expType = exp.op.exp2.destType;
8800                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8801                            success = true;
8802                         }
8803                      }
8804                      else if(!success)
8805                      {
8806                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
8807                         {
8808                            if(exp.expType) FreeType(exp.expType);
8809                            exp.expType = exp.op.exp2.destType;
8810                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8811                            success = true;
8812                         }
8813                         else if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8814                         {
8815                            if(exp.expType) FreeType(exp.expType);
8816                            exp.expType = exp.op.exp1.destType;
8817                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8818                            success = true;
8819                         }
8820                      }
8821                      if(!success)
8822                      {
8823                         char expString1[10240];
8824                         char expString2[10240];
8825                         char type1[1024];
8826                         char type2[1024];
8827                         expString1[0] = '\0';
8828                         expString2[0] = '\0';
8829                         type1[0] = '\0';
8830                         type2[0] = '\0';
8831                         if(inCompiler)
8832                         {
8833                            PrintExpression(exp.op.exp1, expString1);
8834                            ChangeCh(expString1, '\n', ' ');
8835                            PrintExpression(exp.op.exp2, expString2);
8836                            ChangeCh(expString2, '\n', ' ');
8837                            PrintType(exp.op.exp1.expType, type1, false, true);
8838                            PrintType(exp.op.exp2.expType, type2, false, true);
8839                         }
8840
8841                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1, expString2, type2);
8842                      }
8843                   }
8844                }
8845                // ADDED THESE TWO FROM OUTSIDE useSideType CHECK
8846                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type2 && type1 && type2.kind == classType && type1.kind != classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
8847                {
8848                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8849                   // Convert e.g. / 4 into / 4.0
8850                   exp.op.exp1.destType = type2._class.registered.dataType;
8851                   if(type2._class.registered.dataType)
8852                      type2._class.registered.dataType.refCount++;
8853                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8854                   exp.expType = type2;
8855                   if(type2) type2.refCount++;
8856                }
8857                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type1 && type2 && type1.kind == classType && type2.kind != classType && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
8858                {
8859                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8860                   // Convert e.g. / 4 into / 4.0
8861                   exp.op.exp2.destType = type1._class.registered.dataType;
8862                   if(type1._class.registered.dataType)
8863                      type1._class.registered.dataType.refCount++;
8864                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8865                   exp.expType = type1;
8866                   if(type1) type1.refCount++;
8867                }
8868                else if(type1)
8869                {
8870                   bool valid = false;
8871
8872                   if(!boolResult && useSideUnit && type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8873                   {
8874                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8875
8876                      if(!type1._class.registered.dataType)
8877                         type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
8878                      exp.op.exp2.destType = type1._class.registered.dataType;
8879                      exp.op.exp2.destType.refCount++;
8880
8881                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8882                      if(type2)
8883                         FreeType(type2);
8884                      type2 = exp.op.exp2.destType;
8885                      if(type2) type2.refCount++;
8886
8887                      exp.expType = type2;
8888                      type2.refCount++;
8889                   }
8890
8891                   if(!boolResult && useSideUnit && type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8892                   {
8893                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8894
8895                      if(!type2._class.registered.dataType)
8896                         type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
8897                      exp.op.exp1.destType = type2._class.registered.dataType;
8898                      exp.op.exp1.destType.refCount++;
8899
8900                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8901                      type1 = exp.op.exp1.destType;
8902                      exp.expType = type1;
8903                      type1.refCount++;
8904                   }
8905
8906                   // TESTING THIS NEW CODE
8907                   if(!boolResult || exp.op.op == '>' || exp.op.op == '<' || exp.op.op == GE_OP || exp.op.op == LE_OP)
8908                   {
8909                      bool op1IsEnum = type1 && type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass;
8910                      bool op2IsEnum = type2 && type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass;
8911                      if(exp.op.op == '*' || exp.op.op == '/' || exp.op.op == '-' || exp.op.op == '|' || exp.op.op == '^')
8912                      {
8913                         // Convert the enum to an int instead for these operators
8914                         if(op1IsEnum && exp.op.exp2.expType)
8915                         {
8916                            if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false, false))
8917                            {
8918                               if(exp.expType) FreeType(exp.expType);
8919                               exp.expType = exp.op.exp2.expType;
8920                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8921                               valid = true;
8922                            }
8923                         }
8924                         else if(op2IsEnum && exp.op.exp1.expType)
8925                         {
8926                            if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false, false))
8927                            {
8928                               if(exp.expType) FreeType(exp.expType);
8929                               exp.expType = exp.op.exp1.expType;
8930                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8931                               valid = true;
8932                            }
8933                         }
8934                      }
8935                      else
8936                      {
8937                         if(op1IsEnum && exp.op.exp2.expType)
8938                         {
8939                            if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false, false))
8940                            {
8941                               if(exp.expType) FreeType(exp.expType);
8942                               exp.expType = exp.op.exp1.expType;
8943                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8944                               valid = true;
8945                            }
8946                         }
8947                         else if(op2IsEnum && exp.op.exp1.expType)
8948                         {
8949                            if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false, false))
8950                            {
8951                               if(exp.expType) FreeType(exp.expType);
8952                               exp.expType = exp.op.exp2.expType;
8953                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8954                               valid = true;
8955                            }
8956                         }
8957                      }
8958                   }
8959
8960                   if(!valid)
8961                   {
8962                      // Added this first part of the if here to handle  5 + Degrees { 5 } with either a base unit dest or not a unit dest type
8963                      if(type2 && type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass &&
8964                         (type1.kind != classType || !type1._class || !type1._class.registered || type1._class.registered.type != unitClass))
8965                      {
8966                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8967                         exp.op.exp1.destType = type2;
8968                         type2.refCount++;
8969
8970                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8971                         {
8972                            if(exp.expType) FreeType(exp.expType);
8973                            exp.expType = exp.op.exp1.destType;
8974                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8975                         }
8976                      }
8977                      else
8978                      {
8979                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8980                         exp.op.exp2.destType = type1;
8981                         type1.refCount++;
8982
8983                      /*
8984                      // Maybe this was meant to be an enum...
8985                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
8986                      {
8987                         Type oldType = exp.op.exp2.expType;
8988                         exp.op.exp2.expType = null;
8989                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8990                            FreeType(oldType);
8991                         else
8992                            exp.op.exp2.expType = oldType;
8993                      }
8994                      */
8995
8996                      /*
8997                      // TESTING THIS HERE... LATEST ADDITION
8998                      if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8999                      {
9000                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9001                         exp.op.exp2.destType = type2._class.registered.dataType;
9002                         if(type2._class.registered.dataType)
9003                            type2._class.registered.dataType.refCount++;
9004                         CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
9005
9006                         //exp.expType = type2._class.registered.dataType; //type2;
9007                         //if(type2) type2.refCount++;
9008                      }
9009
9010                      // TESTING THIS HERE... LATEST ADDITION
9011                      if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
9012                      {
9013                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9014                         exp.op.exp1.destType = type1._class.registered.dataType;
9015                         if(type1._class.registered.dataType)
9016                            type1._class.registered.dataType.refCount++;
9017                         CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
9018                         exp.expType = type1._class.registered.dataType; //type1;
9019                         if(type1) type1.refCount++;
9020                      }
9021                      */
9022
9023                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
9024                         {
9025                            if(exp.expType) FreeType(exp.expType);
9026                            exp.expType = exp.op.exp2.destType;
9027                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
9028                         }
9029                         else if(type1 && type2)
9030                         {
9031                            char expString1[10240];
9032                            char expString2[10240];
9033                            char type1String[1024];
9034                            char type2String[1024];
9035                            expString1[0] = '\0';
9036                            expString2[0] = '\0';
9037                            type1String[0] = '\0';
9038                            type2String[0] = '\0';
9039                            if(inCompiler)
9040                            {
9041                               PrintExpression(exp.op.exp1, expString1);
9042                               ChangeCh(expString1, '\n', ' ');
9043                               PrintExpression(exp.op.exp2, expString2);
9044                               ChangeCh(expString2, '\n', ' ');
9045                               PrintType(exp.op.exp1.expType, type1String, false, true);
9046                               PrintType(exp.op.exp2.expType, type2String, false, true);
9047                            }
9048
9049                            Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1String, expString2, type2String);
9050
9051                            if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
9052                            {
9053                               exp.expType = exp.op.exp1.expType;
9054                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
9055                            }
9056                            else if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
9057                            {
9058                               exp.expType = exp.op.exp2.expType;
9059                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
9060                            }
9061                         }
9062                      }
9063                   }
9064                }
9065                else if(type2)
9066                {
9067                   // Maybe this was meant to be an enum...
9068                   if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
9069                   {
9070                      Type oldType = exp.op.exp1.expType;
9071                      exp.op.exp1.expType = null;
9072                      if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
9073                         FreeType(oldType);
9074                      else
9075                         exp.op.exp1.expType = oldType;
9076                   }
9077
9078                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9079                   exp.op.exp1.destType = type2;
9080                   type2.refCount++;
9081                   /*
9082                   // TESTING THIS HERE... LATEST ADDITION
9083                   if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
9084                   {
9085                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9086                      exp.op.exp1.destType = type1._class.registered.dataType;
9087                      if(type1._class.registered.dataType)
9088                         type1._class.registered.dataType.refCount++;
9089                   }
9090
9091                   // TESTING THIS HERE... LATEST ADDITION
9092                   if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
9093                   {
9094                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9095                      exp.op.exp2.destType = type2._class.registered.dataType;
9096                      if(type2._class.registered.dataType)
9097                         type2._class.registered.dataType.refCount++;
9098                   }
9099                   */
9100
9101                   if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
9102                   {
9103                      if(exp.expType) FreeType(exp.expType);
9104                      exp.expType = exp.op.exp1.destType;
9105                      if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
9106                   }
9107                }
9108             }
9109             else if(type2 && (!type1 || (type2.kind == classType && type1.kind != classType)))
9110             {
9111                if(type1 && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
9112                {
9113                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9114                   // Convert e.g. / 4 into / 4.0
9115                   exp.op.exp1.destType = type2._class.registered.dataType;
9116                   if(type2._class.registered.dataType)
9117                      type2._class.registered.dataType.refCount++;
9118                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
9119                }
9120                if(exp.op.op == '!')
9121                {
9122                   exp.expType = MkClassType("bool");
9123                   exp.expType.truth = true;
9124                }
9125                else
9126                {
9127                   exp.expType = type2;
9128                   if(type2) type2.refCount++;
9129                }
9130             }
9131             else if(type1 && (!type2 || (type1.kind == classType && type2.kind != classType)))
9132             {
9133                if(type2 && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
9134                {
9135                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9136                   // Convert e.g. / 4 into / 4.0
9137                   exp.op.exp2.destType = type1._class.registered.dataType;
9138                   if(type1._class.registered.dataType)
9139                      type1._class.registered.dataType.refCount++;
9140                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
9141                }
9142                exp.expType = type1;
9143                if(type1) type1.refCount++;
9144             }
9145          }
9146
9147          yylloc = exp.loc;
9148          if(exp.op.exp1 && !exp.op.exp1.expType)
9149          {
9150             char expString[10000];
9151             expString[0] = '\0';
9152             if(inCompiler)
9153             {
9154                PrintExpression(exp.op.exp1, expString);
9155                ChangeCh(expString, '\n', ' ');
9156             }
9157             if(expString[0])
9158                Compiler_Error($"couldn't determine type of %s\n", expString);
9159          }
9160          if(exp.op.exp2 && !exp.op.exp2.expType)
9161          {
9162             char expString[10240];
9163             expString[0] = '\0';
9164             if(inCompiler)
9165             {
9166                PrintExpression(exp.op.exp2, expString);
9167                ChangeCh(expString, '\n', ' ');
9168             }
9169             if(expString[0])
9170                Compiler_Error($"couldn't determine type of %s\n", expString);
9171          }
9172
9173          if(boolResult)
9174          {
9175             FreeType(exp.expType);
9176             exp.expType = MkClassType("bool");
9177             exp.expType.truth = true;
9178          }
9179
9180          if(exp.op.op != SIZEOF)
9181             exp.isConstant = (!exp.op.exp1 || exp.op.exp1.isConstant) &&
9182                (!exp.op.exp2 || exp.op.exp2.isConstant);
9183
9184          if(exp.op.op == SIZEOF && exp.op.exp2.expType)
9185          {
9186             DeclareType(curExternal, exp.op.exp2.expType, true, false);
9187          }
9188
9189          if(exp.op.op == DELETE && exp.op.exp2 && exp.op.exp2.expType && exp.op.exp2.expType.specConst)
9190             Compiler_Warning($"deleting const qualified object\n");
9191
9192          yylloc = oldyylloc;
9193
9194          FreeType(dummy);
9195          if(type2)
9196             FreeType(type2);
9197          break;
9198       }
9199       case bracketsExp:
9200       case extensionExpressionExp:
9201       {
9202          Expression e;
9203          exp.isConstant = true;
9204          for(e = exp.list->first; e; e = e.next)
9205          {
9206             //bool inced = false;
9207             if(!e.next)
9208             {
9209                FreeType(e.destType);
9210                e.opDestType = exp.opDestType;
9211                e.destType = exp.destType;
9212                if(e.destType) { exp.destType.refCount++; /*e.destType.count++; inced = true;*/ }
9213             }
9214             ProcessExpressionType(e);
9215             /*if(inced)
9216                exp.destType.count--;*/
9217             if(!exp.expType && !e.next)
9218             {
9219                exp.expType = e.expType;
9220                if(e.expType) e.expType.refCount++;
9221             }
9222             if(!e.isConstant)
9223                exp.isConstant = false;
9224          }
9225
9226          // In case a cast became a member...
9227          e = exp.list->first;
9228          if(!e.next && e.type == memberExp)
9229          {
9230             // Preserve prev, next
9231             Expression next = exp.next, prev = exp.prev;
9232
9233
9234             FreeType(exp.expType);
9235             FreeType(exp.destType);
9236             delete exp.list;
9237
9238             *exp = *e;
9239
9240             exp.prev = prev;
9241             exp.next = next;
9242
9243             delete e;
9244
9245             ProcessExpressionType(exp);
9246          }
9247          break;
9248       }
9249       case indexExp:
9250       {
9251          Expression e;
9252          exp.isConstant = true;
9253
9254          ProcessExpressionType(exp.index.exp);
9255          if(!exp.index.exp.isConstant)
9256             exp.isConstant = false;
9257
9258          if(exp.index.exp.expType)
9259          {
9260             Type source = exp.index.exp.expType;
9261             if(source.kind == classType && source._class && source._class.registered)
9262             {
9263                Class _class = source._class.registered;
9264                Class c = _class.templateClass ? _class.templateClass : _class;
9265                if(_class != containerClass && eClass_IsDerived(c, containerClass) && _class.templateArgs)
9266                {
9267                   exp.expType = ProcessTypeString(_class.templateArgs[2].dataTypeString, false);
9268
9269                   if(exp.index.index && exp.index.index->last)
9270                   {
9271                      Type type = ProcessTypeString(_class.templateArgs[1].dataTypeString, false);
9272
9273                      if(type.kind == classType) type.constant = true;
9274                      else if(type.kind == pointerType)
9275                      {
9276                         Type t = type;
9277                         while(t.kind == pointerType) t = t.type;
9278                         t.constant = true;
9279                      }
9280
9281                      ((Expression)exp.index.index->last).destType = type;
9282                   }
9283                }
9284             }
9285          }
9286
9287          for(e = exp.index.index->first; e; e = e.next)
9288          {
9289             if(!e.next && exp.index.exp.expType && exp.index.exp.expType.kind == arrayType && exp.index.exp.expType.enumClass)
9290             {
9291                if(e.destType) FreeType(e.destType);
9292                e.destType = MkClassType(exp.index.exp.expType.enumClass.string);
9293             }
9294             ProcessExpressionType(e);
9295             if(!e.next)
9296             {
9297                // Check if this type is int
9298             }
9299             if(!e.isConstant)
9300                exp.isConstant = false;
9301          }
9302
9303          if(!exp.expType)
9304             exp.expType = Dereference(exp.index.exp.expType);
9305          if(exp.expType)
9306             DeclareType(curExternal, exp.expType, true, false);
9307          break;
9308       }
9309       case callExp:
9310       {
9311          Expression e;
9312          Type functionType;
9313          Type methodType = null;
9314          char name[1024];
9315          name[0] = '\0';
9316
9317          if(inCompiler)
9318          {
9319             PrintExpression(exp.call.exp,  name);
9320             if(exp.call.exp.expType && !exp.call.exp.expType.returnType)
9321             {
9322                //exp.call.exp.expType = null;
9323                PrintExpression(exp.call.exp,  name);
9324             }
9325          }
9326          if(exp.call.exp.type == identifierExp)
9327          {
9328             Expression idExp = exp.call.exp;
9329             Identifier id = idExp.identifier;
9330             if(!strcmp(id.string, "__builtin_frame_address"))
9331             {
9332                exp.expType = ProcessTypeString("void *", true);
9333                if(exp.call.arguments && exp.call.arguments->first)
9334                   ProcessExpressionType(exp.call.arguments->first);
9335                break;
9336             }
9337             else if(!strcmp(id.string, "__ENDIAN_PAD"))
9338             {
9339                exp.expType = ProcessTypeString("int", true);
9340                if(exp.call.arguments && exp.call.arguments->first)
9341                   ProcessExpressionType(exp.call.arguments->first);
9342                break;
9343             }
9344             else if(!strcmp(id.string, "Max") ||
9345                !strcmp(id.string, "Min") ||
9346                !strcmp(id.string, "Sgn") ||
9347                !strcmp(id.string, "Abs"))
9348             {
9349                Expression a = null;
9350                Expression b = null;
9351                Expression tempExp1 = null, tempExp2 = null;
9352                if((!strcmp(id.string, "Max") ||
9353                   !strcmp(id.string, "Min")) && exp.call.arguments->count == 2)
9354                {
9355                   a = exp.call.arguments->first;
9356                   b = exp.call.arguments->last;
9357                   tempExp1 = a;
9358                   tempExp2 = b;
9359                }
9360                else if(exp.call.arguments->count == 1)
9361                {
9362                   a = exp.call.arguments->first;
9363                   tempExp1 = a;
9364                }
9365
9366                if(a)
9367                {
9368                   exp.call.arguments->Clear();
9369                   idExp.identifier = null;
9370
9371                   FreeExpContents(exp);
9372
9373                   ProcessExpressionType(a);
9374                   if(b)
9375                      ProcessExpressionType(b);
9376
9377                   exp.type = bracketsExp;
9378                   exp.list = MkList();
9379
9380                   if(a.expType && (!b || b.expType))
9381                   {
9382                      if((!a.isConstant && a.type != identifierExp) || (b && !b.isConstant && b.type != identifierExp))
9383                      {
9384                         // Use the simpleStruct name/ids for now...
9385                         if(inCompiler)
9386                         {
9387                            OldList * specs = MkList();
9388                            OldList * decls = MkList();
9389                            Declaration decl;
9390                            char temp1[1024], temp2[1024];
9391
9392                            GetTypeSpecs(a.expType, specs);
9393
9394                            if(a && !a.isConstant && a.type != identifierExp)
9395                            {
9396                               sprintf(temp1, "__simpleStruct%d", curContext.simpleID++);
9397                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp1)), null));
9398                               tempExp1 = QMkExpId(temp1);
9399                               tempExp1.expType = a.expType;
9400                               if(a.expType)
9401                                  a.expType.refCount++;
9402                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp1), '=', a));
9403                            }
9404                            if(b && !b.isConstant && b.type != identifierExp)
9405                            {
9406                               sprintf(temp2, "__simpleStruct%d", curContext.simpleID++);
9407                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp2)), null));
9408                               tempExp2 = QMkExpId(temp2);
9409                               tempExp2.expType = b.expType;
9410                               if(b.expType)
9411                                  b.expType.refCount++;
9412                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp2), '=', b));
9413                            }
9414
9415                            decl = MkDeclaration(specs, decls);
9416                            if(!curCompound.compound.declarations)
9417                               curCompound.compound.declarations = MkList();
9418                            curCompound.compound.declarations->Insert(null, decl);
9419                         }
9420                      }
9421                   }
9422
9423                   if(!strcmp(id.string, "Max") || !strcmp(id.string, "Min"))
9424                   {
9425                      int op = (!strcmp(id.string, "Max")) ? '>' : '<';
9426                      ListAdd(exp.list,
9427                         MkExpCondition(MkExpBrackets(MkListOne(
9428                            MkExpOp(CopyExpression(tempExp1), op, CopyExpression(tempExp2)))),
9429                            MkListOne(CopyExpression(tempExp1)), CopyExpression(tempExp2)));
9430                      exp.expType = a.expType;
9431                      if(a.expType)
9432                         a.expType.refCount++;
9433                   }
9434                   else if(!strcmp(id.string, "Abs"))
9435                   {
9436                      ListAdd(exp.list,
9437                         MkExpCondition(MkExpBrackets(MkListOne(
9438                            MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9439                            MkListOne(MkExpOp(null, '-', CopyExpression(tempExp1))), CopyExpression(tempExp1)));
9440                      exp.expType = a.expType;
9441                      if(a.expType)
9442                         a.expType.refCount++;
9443                   }
9444                   else if(!strcmp(id.string, "Sgn"))
9445                   {
9446                      // ((!(a))?(0):(((a)<0)?(-1):(1)))
9447                      ListAdd(exp.list,
9448                         MkExpCondition(MkExpBrackets(MkListOne(
9449                            MkExpOp(null, '!', CopyExpression(tempExp1)))), MkListOne(MkExpConstant("0")),
9450                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(
9451                                  MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9452                                  MkListOne(MkExpConstant("-1")), MkExpConstant("1"))))));
9453                      exp.expType = ProcessTypeString("int", false);
9454                   }
9455
9456                   FreeExpression(tempExp1);
9457                   if(tempExp2) FreeExpression(tempExp2);
9458
9459                   FreeIdentifier(id);
9460                   break;
9461                }
9462             }
9463          }
9464
9465          {
9466             Type dummy
9467             {
9468                count = 1;
9469                refCount = 1;
9470             };
9471             if(!exp.call.exp.destType)
9472             {
9473                exp.call.exp.destType = dummy;
9474                dummy.refCount++;
9475             }
9476             ProcessExpressionType(exp.call.exp);
9477             if(exp.call.exp.destType == dummy)
9478             {
9479                FreeType(dummy);
9480                exp.call.exp.destType = null;
9481             }
9482             FreeType(dummy);
9483          }
9484
9485          // Check argument types against parameter types
9486          functionType = exp.call.exp.expType;
9487
9488          if(functionType && functionType.kind == TypeKind::methodType)
9489          {
9490             methodType = functionType;
9491             functionType = methodType.method.dataType;
9492
9493             //if(functionType.returnType && functionType.returnType.kind == thisClassType)
9494             // TOCHECK: Instead of doing this here could this be done per param?
9495             if(exp.call.exp.expType.usedClass)
9496             {
9497                char typeString[1024];
9498                typeString[0] = '\0';
9499                {
9500                   Symbol back = functionType.thisClass;
9501                   // Do not output class specifier here (thisclass was added to this)
9502                   functionType.thisClass = null;
9503                   PrintType(functionType, typeString, true, true);
9504                   functionType.thisClass = back;
9505                }
9506                if(strstr(typeString, "thisclass"))
9507                {
9508                   OldList * specs = MkList();
9509                   Declarator decl;
9510                   {
9511                      Context context = SetupTemplatesContext(exp.call.exp.expType.usedClass);
9512
9513                      decl = SpecDeclFromString(typeString, specs, null);
9514
9515                      // SET THIS TO FALSE WHEN PROCESSING THISCLASS OUTSIDE THE CLASS
9516                      if(thisClass != (exp.call.exp.expType.usedClass.templateClass ? exp.call.exp.expType.usedClass.templateClass :
9517                         exp.call.exp.expType.usedClass))
9518                         thisClassParams = false;
9519
9520                      ReplaceThisClassSpecifiers(specs, exp.call.exp.expType.usedClass);
9521                      {
9522                         Class backupThisClass = thisClass;
9523                         thisClass = exp.call.exp.expType.usedClass;
9524                         ProcessDeclarator(decl, true);
9525                         thisClass = backupThisClass;
9526                      }
9527
9528                      thisClassParams = true;
9529
9530                      functionType = ProcessType(specs, decl);
9531                      functionType.refCount = 0;
9532                      FinishTemplatesContext(context);
9533
9534                      // Mark parameters that were 'thisclass'
9535                      {
9536                         Type p, op;
9537                         for(p = functionType.params.first, op = methodType.method.dataType.params.first; p && op; p = p.next, op = op.next)
9538                         {
9539                            //p.wasThisClass = op.kind == thisClassType;
9540                            if(op.kind == thisClassType)
9541                               p.thisClassFrom = methodType.method._class;
9542                         }
9543                      }
9544                      if(methodType.method.dataType.returnType.kind == thisClassType)
9545                      {
9546                         // functionType.returnType.wasThisClass = true;
9547                         functionType.returnType.thisClassFrom = methodType.method._class;
9548                      }
9549                   }
9550
9551                   FreeList(specs, FreeSpecifier);
9552                   FreeDeclarator(decl);
9553                 }
9554             }
9555          }
9556          if(functionType && functionType.kind == pointerType && functionType.type && functionType.type.kind == TypeKind::functionType)
9557          {
9558             Type type = functionType.type;
9559             if(!functionType.refCount)
9560             {
9561                functionType.type = null;
9562                FreeType(functionType);
9563             }
9564             //methodType = functionType;
9565             functionType = type;
9566          }
9567          if(functionType && functionType.kind != TypeKind::functionType)
9568          {
9569             Compiler_Error($"called object %s is not a function\n", name);
9570          }
9571          else if(functionType)
9572          {
9573             bool emptyParams = false, noParams = false;
9574             Expression e = exp.call.arguments ? exp.call.arguments->first : null;
9575             Type type = functionType.params.first;
9576             Expression memberExp = (exp.call.exp.type == ExpressionType::memberExp) ? exp.call.exp : null;
9577             int extra = 0;
9578             Location oldyylloc = yylloc;
9579
9580             if(!type) emptyParams = true;
9581
9582             // WORKING ON THIS:
9583             if(functionType.extraParam && e && functionType.thisClass)
9584             {
9585                e.destType = MkClassType(functionType.thisClass.string);
9586                e = e.next;
9587             }
9588
9589             // WHY WAS THIS COMMENTED OUT ? Broke DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
9590             // Fixed #141 by adding '&& !functionType.extraParam'
9591             if(!functionType.staticMethod && !functionType.extraParam)
9592             {
9593                if(memberExp && memberExp.member.exp && memberExp.member.exp.expType && memberExp.member.exp.expType.kind == subClassType &&
9594                   memberExp.member.exp.expType._class)
9595                {
9596                   type = MkClassType(memberExp.member.exp.expType._class.string);
9597                   if(e)
9598                   {
9599                      e.destType = type;
9600                      e = e.next;
9601                      type = functionType.params.first;
9602                   }
9603                   else
9604                      type.refCount = 0;
9605                }
9606                else if(!memberExp && (functionType.thisClass || (methodType && methodType.methodClass)))
9607                {
9608                   type = MkClassType(functionType.thisClass ? functionType.thisClass.string : (methodType ? methodType.methodClass.fullName : null));
9609                   type.byReference = functionType.byReference;
9610                   type.typedByReference = functionType.typedByReference;
9611                   if(e)
9612                   {
9613                      // Allow manually passing a class for typed object
9614                      if(e.next && type.kind == classType && (functionType && functionType.thisClass) && functionType.classObjectType == typedObject)
9615                         e = e.next;
9616                      e.destType = type;
9617                      e = e.next;
9618                      type = functionType.params.first;
9619                   }
9620                   else
9621                      type.refCount = 0;
9622                   //extra = 1;
9623                }
9624             }
9625
9626             if(type && type.kind == voidType)
9627             {
9628                noParams = true;
9629                if(!type.refCount) FreeType(type);
9630                type = null;
9631             }
9632
9633             for( ; e; e = e.next)
9634             {
9635                if(!type && !emptyParams)
9636                {
9637                   yylloc = e.loc;
9638                   if(methodType && methodType.methodClass)
9639                      Compiler_Error($"too many arguments for method %s::%s (%d given, expected %d)\n",
9640                         methodType.methodClass.fullName, methodType.method.name, exp.call.arguments->count,
9641                         noParams ? 0 : functionType.params.count);
9642                   else
9643                      Compiler_Error($"too many arguments for function %s (%d given, expected %d)\n",
9644                         name /*exp.call.exp.identifier.string*/, exp.call.arguments->count,
9645                         noParams ? 0 : functionType.params.count);
9646                   break;
9647                }
9648
9649                if(methodType && type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type)
9650                {
9651                   Type templatedType = null;
9652                   Class _class = methodType.usedClass;
9653                   ClassTemplateParameter curParam = null;
9654                   int id = 0;
9655                   if(_class && _class.templateArgs /*&& _class.templateClass*/)
9656                   {
9657                      Class sClass;
9658                      for(sClass = _class; sClass; sClass = sClass.base)
9659                      {
9660                         if(sClass.templateClass) sClass = sClass.templateClass;
9661                         id = 0;
9662                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9663                         {
9664                            if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
9665                            {
9666                               Class nextClass;
9667                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
9668                               {
9669                                  if(nextClass.templateClass) nextClass = nextClass.templateClass;
9670                                  id += nextClass.templateParams.count;
9671                               }
9672                               break;
9673                            }
9674                            id++;
9675                         }
9676                         if(curParam) break;
9677                      }
9678                   }
9679                   if(curParam && _class.templateArgs[id].dataTypeString)
9680                   {
9681                      bool constant = type.constant;
9682                      ClassTemplateArgument arg = _class.templateArgs[id];
9683                      {
9684                         Context context = SetupTemplatesContext(_class);
9685
9686                         /*if(!arg.dataType)
9687                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9688                         templatedType = ProcessTypeString(arg.dataTypeString, false);
9689                         FinishTemplatesContext(context);
9690                      }
9691
9692                      if(templatedType.kind == classType && constant) templatedType.constant = true;
9693                      else if(templatedType.kind == pointerType)
9694                      {
9695                         Type t = templatedType.type;
9696                         while(t.kind == pointerType) t = t.type;
9697                         if(constant) t.constant = constant;
9698                      }
9699
9700                      e.destType = templatedType;
9701                      if(templatedType)
9702                      {
9703                         templatedType.passAsTemplate = true;
9704                         // templatedType.refCount++;
9705                      }
9706                   }
9707                   else
9708                   {
9709                      e.destType = type;
9710                      if(type) type.refCount++;
9711                   }
9712                }
9713                else
9714                {
9715                   if(type && type.kind == ellipsisType && type.prev && type.prev.kind == classType && type.prev.classObjectType)
9716                   {
9717                      e.destType = type.prev;
9718                      e.destType.refCount++;
9719                   }
9720                   else
9721                   {
9722                      e.destType = type;
9723                      if(type) type.refCount++;
9724                   }
9725                }
9726                // Don't reach the end for the ellipsis
9727                if(type && type.kind != ellipsisType)
9728                {
9729                   Type next = type.next;
9730                   if(!type.refCount) FreeType(type);
9731                   type = next;
9732                }
9733             }
9734
9735             if(type && type.kind != ellipsisType)
9736             {
9737                if(methodType && methodType.methodClass)
9738                   Compiler_Warning($"not enough arguments for method %s::%s (%d given, expected %d)\n",
9739                      methodType.methodClass.fullName, methodType.method.name, exp.call.arguments ? exp.call.arguments->count : 0,
9740                      functionType.params.count + extra);
9741                else
9742                   Compiler_Warning($"not enough arguments for function %s (%d given, expected %d)\n",
9743                      name /*exp.call.exp.identifier.string*/, exp.call.arguments ? exp.call.arguments->count : 0,
9744                      functionType.params.count + extra);
9745             }
9746             yylloc = oldyylloc;
9747             if(type && !type.refCount) FreeType(type);
9748          }
9749          else
9750          {
9751             functionType = Type
9752             {
9753                refCount = 0;
9754                kind = TypeKind::functionType;
9755             };
9756
9757             if(exp.call.exp.type == identifierExp)
9758             {
9759                char * string = exp.call.exp.identifier.string;
9760                if(inCompiler)
9761                {
9762                   Symbol symbol;
9763                   Location oldyylloc = yylloc;
9764
9765                   yylloc = exp.call.exp.identifier.loc;
9766                   if(strstr(string, "__builtin_") == string)
9767                   {
9768                      if(exp.destType)
9769                      {
9770                         functionType.returnType = exp.destType;
9771                         exp.destType.refCount++;
9772                      }
9773                   }
9774                   else
9775                      Compiler_Warning($"%s undefined; assuming extern returning int\n", string);
9776                   symbol = Symbol { string = CopyString(string), type = ProcessTypeString("int()", true) };
9777                   globalContext.symbols.Add((BTNode)symbol);
9778                   if(strstr(symbol.string, "::"))
9779                      globalContext.hasNameSpace = true;
9780
9781                   yylloc = oldyylloc;
9782                }
9783             }
9784             else if(exp.call.exp.type == memberExp)
9785             {
9786                /*Compiler_Warning($"%s undefined; assuming returning int\n",
9787                   exp.call.exp.member.member.string);*/
9788             }
9789             else
9790                Compiler_Warning($"callable object undefined; extern assuming returning int\n");
9791
9792             if(!functionType.returnType)
9793             {
9794                functionType.returnType = Type
9795                {
9796                   refCount = 1;
9797                   kind = intType;
9798                };
9799             }
9800          }
9801          if(functionType && functionType.kind == TypeKind::functionType)
9802          {
9803             exp.expType = functionType.returnType;
9804
9805             if(functionType.returnType)
9806                functionType.returnType.refCount++;
9807
9808             if(!functionType.refCount)
9809                FreeType(functionType);
9810          }
9811
9812          if(exp.call.arguments)
9813          {
9814             for(e = exp.call.arguments->first; e; e = e.next)
9815                ProcessExpressionType(e);
9816          }
9817          break;
9818       }
9819       case memberExp:
9820       {
9821          Type type;
9822          Location oldyylloc = yylloc;
9823          bool thisPtr;
9824          Expression checkExp = exp.member.exp;
9825          while(checkExp)
9826          {
9827             if(checkExp.type == castExp)
9828                checkExp = checkExp.cast.exp;
9829             else if(checkExp.type == bracketsExp)
9830                checkExp = checkExp.list ? checkExp.list->first : null;
9831             else
9832                break;
9833          }
9834
9835          thisPtr = (checkExp && checkExp.type == identifierExp && !strcmp(checkExp.identifier.string, "this"));
9836          exp.thisPtr = thisPtr;
9837
9838          // DOING THIS LATER NOW...
9839          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
9840          {
9841             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
9842             /* TODO: Name Space Fix ups
9843             if(!exp.member.member.classSym)
9844                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.fullName);
9845             */
9846          }
9847
9848          ProcessExpressionType(exp.member.exp);
9849          if(exp.member.exp.expType && exp.member.exp.expType.kind == classType && exp.member.exp.expType._class &&
9850             exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == normalClass)
9851          {
9852             exp.isConstant = false;
9853          }
9854          else
9855             exp.isConstant = exp.member.exp.isConstant;
9856          type = exp.member.exp.expType;
9857
9858          yylloc = exp.loc;
9859
9860          if(type && (type.kind == templateType))
9861          {
9862             Class _class = thisClass ? thisClass : currentClass;
9863             ClassTemplateParameter param = null;
9864             if(_class)
9865             {
9866                for(param = _class.templateParams.first; param; param = param.next)
9867                {
9868                   if(param.type == identifier && exp.member.member && exp.member.member.string && !strcmp(param.name, exp.member.member.string))
9869                      break;
9870                }
9871             }
9872             if(param && param.defaultArg.member)
9873             {
9874                Expression argExp = GetTemplateArgExpByName(param.name, thisClass, TemplateParameterType::identifier);
9875                if(argExp)
9876                {
9877                   Expression expMember = exp.member.exp;
9878                   Declarator decl;
9879                   OldList * specs = MkList();
9880                   char thisClassTypeString[1024];
9881
9882                   FreeIdentifier(exp.member.member);
9883
9884                   ProcessExpressionType(argExp);
9885
9886                   {
9887                      char * colon = strstr(param.defaultArg.memberString, "::");
9888                      if(colon)
9889                      {
9890                         memcpy(thisClassTypeString, param.defaultArg.memberString, colon - param.defaultArg.memberString);
9891                         thisClassTypeString[colon - param.defaultArg.memberString] = '\0';
9892                      }
9893                      else
9894                         strcpy(thisClassTypeString, _class.fullName);
9895                   }
9896
9897                   decl = SpecDeclFromString(param.defaultArg.member.dataTypeString, specs, null);
9898
9899                   exp.expType = ProcessType(specs, decl);
9900                   if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.templateClass)
9901                   {
9902                      Class expClass = exp.expType._class.registered;
9903                      Class cClass = null;
9904                      int paramCount = 0;
9905                      int lastParam = -1;
9906
9907                      char templateString[1024];
9908                      ClassTemplateParameter param;
9909                      sprintf(templateString, "%s<", expClass.templateClass.fullName);
9910                      for(cClass = expClass; cClass; cClass = cClass.base)
9911                      {
9912                         int p = 0;
9913                         for(param = cClass.templateParams.first; param; param = param.next)
9914                         {
9915                            int id = p;
9916                            Class sClass;
9917                            ClassTemplateArgument arg;
9918                            for(sClass = cClass.base; sClass; sClass = sClass.base) id += sClass.templateParams.count;
9919                            arg = expClass.templateArgs[id];
9920
9921                            for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
9922                            {
9923                               ClassTemplateParameter cParam;
9924                               //int p = numParams - sClass.templateParams.count;
9925                               int p = 0;
9926                               Class nextClass;
9927                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) p += nextClass.templateParams.count;
9928
9929                               for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
9930                               {
9931                                  if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
9932                                  {
9933                                     if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9934                                     {
9935                                        arg.dataTypeString = _class.templateArgs[p].dataTypeString;
9936                                        arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
9937                                        break;
9938                                     }
9939                                  }
9940                               }
9941                            }
9942
9943                            {
9944                               char argument[256];
9945                               argument[0] = '\0';
9946                               /*if(arg.name)
9947                               {
9948                                  strcat(argument, arg.name.string);
9949                                  strcat(argument, " = ");
9950                               }*/
9951                               switch(param.type)
9952                               {
9953                                  case expression:
9954                                  {
9955                                     // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
9956                                     char expString[1024];
9957                                     OldList * specs = MkList();
9958                                     Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
9959                                     Expression exp;
9960                                     char * string = PrintHexUInt64(arg.expression.ui64);
9961                                     exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
9962                                     delete string;
9963
9964                                     ProcessExpressionType(exp);
9965                                     ComputeExpression(exp);
9966                                     expString[0] = '\0';
9967                                     PrintExpression(exp, expString);
9968                                     strcat(argument, expString);
9969                                     // delete exp;
9970                                     FreeExpression(exp);
9971                                     break;
9972                                  }
9973                                  case identifier:
9974                                  {
9975                                     strcat(argument, arg.member.name);
9976                                     break;
9977                                  }
9978                                  case TemplateParameterType::type:
9979                                  {
9980                                     if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9981                                     {
9982                                        if(!strcmp(arg.dataTypeString, "thisclass"))
9983                                           strcat(argument, thisClassTypeString);
9984                                        else
9985                                           strcat(argument, arg.dataTypeString);
9986                                     }
9987                                     break;
9988                                  }
9989                               }
9990                               if(argument[0])
9991                               {
9992                                  if(paramCount) strcat(templateString, ", ");
9993                                  if(lastParam != p - 1)
9994                                  {
9995                                     strcat(templateString, param.name);
9996                                     strcat(templateString, " = ");
9997                                  }
9998                                  strcat(templateString, argument);
9999                                  paramCount++;
10000                                  lastParam = p;
10001                               }
10002                               p++;
10003                            }
10004                         }
10005                      }
10006                      {
10007                         int len = strlen(templateString);
10008                         if(templateString[len-1] == '>') templateString[len++] = ' ';
10009                         templateString[len++] = '>';
10010                         templateString[len++] = '\0';
10011                      }
10012                      {
10013                         Context context = SetupTemplatesContext(_class);
10014                         FreeType(exp.expType);
10015                         exp.expType = ProcessTypeString(templateString, false);
10016                         FinishTemplatesContext(context);
10017                      }
10018                   }
10019
10020                   if(!expMember.expType.isPointerType)
10021                      expMember = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), expMember);
10022                   // *([expType] *)(((byte *)(uintptr)[exp.member.exp]) + [argExp].member.offset)
10023                   exp.type = bracketsExp;
10024                   exp.list = MkListOne(MkExpOp(null, '*',
10025                   /*opExp;
10026                   exp.op.op = '*';
10027                   exp.op.exp1 = null;
10028                   exp.op.exp2 = */
10029                   MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpBrackets(MkListOne(MkExpOp(
10030                      MkExpBrackets(MkListOne(
10031                         MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
10032                            expMember))),
10033                               '+',
10034                               MkExpOp(MkExpMember(MkExpMember(argExp, MkIdentifier("member")), MkIdentifier("offset")),
10035                               '+',
10036                               MkExpMember(MkExpMember(MkExpMember(CopyExpression(argExp), MkIdentifier("member")), MkIdentifier("_class")), MkIdentifier("offset")))))))
10037
10038                            ));
10039                }
10040             }
10041             else if(type.templateParameter && type.templateParameter.type == TemplateParameterType::type &&
10042                (type.templateParameter.dataType || type.templateParameter.dataTypeString))
10043             {
10044                type = ProcessTemplateParameterType(type.templateParameter);
10045             }
10046          }
10047          // TODO: *** This seems to be where we should add method support for all basic types ***
10048          if(type && (type.kind == templateType));
10049          else if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType ||
10050                           type.kind == int64Type || type.kind == shortType || type.kind == longType || type.kind == charType || type.kind == _BoolType ||
10051                           type.kind == intPtrType || type.kind == intSizeType || type.kind == floatType || type.kind == doubleType ||
10052                           (type.kind == pointerType && type.type.kind == charType)))
10053          {
10054             Identifier id = exp.member.member;
10055             TypeKind typeKind = type.kind;
10056             Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10057             if(typeKind == subClassType && exp.member.exp.type == classExp)
10058             {
10059                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
10060                typeKind = classType;
10061             }
10062
10063             if(id)
10064             {
10065                if(typeKind == intType || typeKind == enumType)
10066                   _class = eSystem_FindClass(privateModule, "int");
10067                else if(!_class)
10068                {
10069                   if(type.kind == classType && type._class && type._class.registered)
10070                   {
10071                      _class = type._class.registered;
10072                   }
10073                   else if((type.kind == arrayType || type.kind == pointerType) && type.type && type.type.kind == charType)
10074                   {
10075                      _class = FindClass("char *").registered;
10076                   }
10077                   else if(type.kind == pointerType)
10078                   {
10079                      _class = eSystem_FindClass(privateModule, "uintptr");
10080                      FreeType(exp.expType);
10081                      exp.expType = ProcessTypeString("uintptr", false);
10082                      exp.byReference = true;
10083                   }
10084                   else
10085                   {
10086                      char string[1024] = "";
10087                      Symbol classSym;
10088                      PrintTypeNoConst(type, string, false, true);
10089                      classSym = FindClass(string);
10090                      if(classSym) _class = classSym.registered;
10091                   }
10092                }
10093             }
10094
10095             if(_class && id)
10096             {
10097                /*bool thisPtr =
10098                   (exp.member.exp.type == identifierExp &&
10099                   !strcmp(exp.member.exp.identifier.string, "this"));*/
10100                Property prop = null;
10101                Method method = null;
10102                DataMember member = null;
10103                Property revConvert = null;
10104                ClassProperty classProp = null;
10105
10106                if(id && id._class && id._class.name && !strcmp(id._class.name, "property"))
10107                   exp.member.memberType = propertyMember;
10108
10109                if(id && id._class && type._class && !eClass_IsDerived(type._class.registered, _class))
10110                   Compiler_Error($"invalid class specifier %s for object of class %s\n", _class.fullName, type._class.string);
10111
10112                if(typeKind != subClassType)
10113                {
10114                   // Prioritize data members over properties for "this"
10115                   if((exp.member.memberType == unresolvedMember && thisPtr) || exp.member.memberType == dataMember)
10116                   {
10117                      member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
10118                      if(member && member._class != (_class.templateClass ? _class.templateClass : _class) && exp.member.memberType != dataMember)
10119                      {
10120                         prop = eClass_FindProperty(_class, id.string, privateModule);
10121                         if(prop)
10122                            member = null;
10123                      }
10124                      if(!member && !prop)
10125                         prop = eClass_FindProperty(_class, id.string, privateModule);
10126                      if((member && member._class == (_class.templateClass ? _class.templateClass : _class)) ||
10127                         (prop && prop._class == (_class.templateClass ? _class.templateClass : _class)))
10128                         exp.member.thisPtr = true;
10129                   }
10130                   // Prioritize properties over data members otherwise
10131                   else
10132                   {
10133                      bool useMemberForNonConst = false;
10134                      // First look for Public Members (Unless class specifier is provided, which skips public priority)
10135                      if(!id.classSym)
10136                      {
10137                         prop = eClass_FindProperty(_class, id.string, null);
10138
10139                         useMemberForNonConst = prop && exp.destType &&
10140                            ( (exp.destType.kind == classType && !exp.destType.constant) || ((exp.destType.kind == pointerType || exp.destType.kind == arrayType) && exp.destType.type && !exp.destType.type.constant) ) &&
10141                               !strncmp(prop.dataTypeString, "const ", 6);
10142
10143                         if(useMemberForNonConst || !id._class || !id._class.name || strcmp(id._class.name, "property"))
10144                            member = eClass_FindDataMember(_class, id.string, null, null, null);
10145                      }
10146
10147                      if((!prop || useMemberForNonConst) && !member)
10148                      {
10149                         method = useMemberForNonConst ? null : eClass_FindMethod(_class, id.string, null);
10150                         if(!method)
10151                         {
10152                            prop = eClass_FindProperty(_class, id.string, privateModule);
10153
10154                            useMemberForNonConst |= prop && exp.destType &&
10155                               ( (exp.destType.kind == classType && !exp.destType.constant) || ((exp.destType.kind == pointerType || exp.destType.kind == arrayType) && exp.destType.type && !exp.destType.type.constant) ) &&
10156                                  !strncmp(prop.dataTypeString, "const ", 6);
10157
10158                            if(useMemberForNonConst || !id._class || !id._class.name || strcmp(id._class.name, "property"))
10159                               member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
10160                         }
10161                      }
10162
10163                      if(member && prop)
10164                      {
10165                         if(useMemberForNonConst || (member._class != prop._class && !id._class && eClass_IsDerived(member._class, prop._class)))
10166                            prop = null;
10167                         else
10168                            member = null;
10169                      }
10170                   }
10171                }
10172                if(!prop && !member && !method)     // NOTE: Recently added the !method here, causes private methods to unprioritized
10173                   method = eClass_FindMethod(_class, id.string, privateModule);
10174                if(!prop && !member && !method)
10175                {
10176                   if(typeKind == subClassType)
10177                   {
10178                      classProp = eClass_FindClassProperty(type._class.registered, exp.member.member.string);
10179                      if(classProp)
10180                      {
10181                         exp.member.memberType = classPropertyMember;
10182                         exp.expType = ProcessTypeString(classProp.dataTypeString, false);
10183                      }
10184                      else
10185                      {
10186                         // Assume this is a class_data member
10187                         char structName[1024];
10188                         Identifier id = exp.member.member;
10189                         Expression classExp = exp.member.exp;
10190                         type.refCount++;
10191
10192                         FreeType(classExp.expType);
10193                         classExp.expType = ProcessTypeString("ecere::com::Class", false);
10194
10195                         strcpy(structName, "__ecereClassData_");
10196                         FullClassNameCat(structName, type._class.string, false);
10197                         exp.type = pointerExp;
10198                         exp.member.member = id;
10199
10200                         exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10201                            MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10202                               MkExpBrackets(MkListOne(MkExpOp(
10203                                  MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10204                                     MkExpMember(classExp, MkIdentifier("data"))), '+',
10205                                        MkExpMember(MkExpClass(MkListOne(MkSpecifierName(type._class.string)), null), MkIdentifier("offsetClass")))))
10206                                  )));
10207
10208                         FreeType(type);
10209
10210                         ProcessExpressionType(exp);
10211                         return;
10212                      }
10213                   }
10214                   else
10215                   {
10216                      // Check for reverse conversion
10217                      // (Convert in an instantiation later, so that we can use
10218                      //  deep properties system)
10219                      Symbol classSym = FindClass(id.string);
10220                      if(classSym)
10221                      {
10222                         Class convertClass = classSym.registered;
10223                         if(convertClass)
10224                            revConvert = eClass_FindProperty(convertClass, _class.fullName, privateModule);
10225                      }
10226                   }
10227                }
10228
10229                //if(!exp.member.exp.destType)
10230                if(exp.member.exp.destType)
10231                   FreeType(exp.member.exp.destType);
10232                {
10233                   if(method && !method._class.symbol)
10234                      method._class.symbol = FindClass(method._class.fullName);
10235                   if(prop && !prop._class.symbol)
10236                      prop._class.symbol = FindClass(prop._class.fullName);
10237
10238                   exp.member.exp.destType = Type
10239                   {
10240                      refCount = 1;
10241                      kind = classType;
10242                      _class = prop ? prop._class.symbol : method ? method._class.symbol : _class.symbol;
10243                      // wasThisClass = type ? type.wasThisClass : false;
10244                      thisClassFrom = type ? type.thisClassFrom : null;
10245                   };
10246                }
10247
10248                if(prop)
10249                {
10250                   exp.member.memberType = propertyMember;
10251                   if(!prop.dataType)
10252                      ProcessPropertyType(prop);
10253                   exp.expType = prop.dataType;
10254                   if(!strcmp(_class.base.fullName, "eda::Row") && !exp.expType.constant && !exp.destType)
10255                   {
10256                      Type type { };
10257                      CopyTypeInto(type, exp.expType);
10258                      type.refCount = 1;
10259                      type.constant = true;
10260                      exp.expType = type;
10261                   }
10262                   else if(prop.dataType)
10263                      prop.dataType.refCount++;
10264                }
10265                else if(member)
10266                {
10267                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
10268                   {
10269                      FreeExpContents(exp);
10270                      exp.type = identifierExp;
10271                      exp.identifier = MkIdentifier("class");
10272                      ProcessExpressionType(exp);
10273                      return;
10274                   }
10275
10276                   exp.member.memberType = dataMember;
10277                   DeclareStruct(curExternal, _class.fullName, false, true);
10278                   if(member._class != _class)
10279                      DeclareStruct(curExternal, member._class.fullName, false, true);
10280
10281                   if(!member.dataType)
10282                   {
10283                      Context context = SetupTemplatesContext(_class);
10284                      member.dataType = ProcessTypeString(member.dataTypeString, false);
10285                      FinishTemplatesContext(context);
10286                   }
10287                   if(exp.member.exp.expType.kind == classType && exp.member.exp.expType._class && exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == bitClass)
10288                      member.dataType.bitMemberSize = ((BitMember)member).size;
10289                   exp.expType = member.dataType;
10290                   if(member.dataType) member.dataType.refCount++;
10291                }
10292                else if(revConvert)
10293                {
10294                   exp.member.memberType = reverseConversionMember;
10295                   exp.expType = MkClassType(revConvert._class.fullName);
10296                }
10297                else if(method)
10298                {
10299                   //if(inCompiler)
10300                   {
10301                      /*if(id._class)
10302                      {
10303                         exp.type = identifierExp;
10304                         exp.identifier = exp.member.member;
10305                      }
10306                      else*/
10307                         exp.member.memberType = methodMember;
10308                   }
10309                   if(!method.dataType)
10310                      ProcessMethodType(method);
10311                   exp.expType = Type
10312                   {
10313                      refCount = 1;
10314                      kind = methodType;
10315                      method = method;
10316                   };
10317
10318                   // Tricky spot here... To use instance versus class virtual table
10319                   // Put it back to what it was... What did we break?
10320
10321                   // Had to put it back for overriding Main of Thread global instance
10322
10323                   //exp.expType.methodClass = _class;
10324                   exp.expType.methodClass = (id && id._class) ? _class : null;
10325
10326                   // Need the actual class used for templated classes
10327                   exp.expType.usedClass = _class;
10328                }
10329                else if(!classProp)
10330                {
10331                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
10332                   {
10333                      FreeExpContents(exp);
10334                      exp.type = identifierExp;
10335                      exp.identifier = MkIdentifier("class");
10336                      FreeType(exp.expType);
10337                      exp.expType = MkClassType("ecere::com::Class");
10338                      return;
10339                   }
10340                   yylloc = exp.member.member.loc;
10341                   Compiler_Error($"couldn't find member %s in class %s\n", id.string, _class.fullName);
10342                   if(inCompiler)
10343                      eClass_AddDataMember(_class, id.string, "int", 0, 0, publicAccess);
10344                }
10345
10346                if(_class && /*(_class.templateClass || _class.templateArgs) && */exp.expType)
10347                {
10348                   Class tClass;
10349
10350                   tClass = type._class && type._class.registered ? type._class.registered : _class;
10351                   while(tClass && !tClass.templateClass) tClass = tClass.base;
10352
10353                   if(tClass && exp.expType.kind == templateType && exp.expType.templateParameter.type == TemplateParameterType::type)
10354                   {
10355                      int id = 0;
10356                      ClassTemplateParameter curParam = null;
10357                      Class sClass;
10358
10359                      for(sClass = tClass; sClass; sClass = sClass.base)
10360                      {
10361                         id = 0;
10362                         if(sClass.templateClass) sClass = sClass.templateClass;
10363                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
10364                         {
10365                            if(curParam.type == TemplateParameterType::type && !strcmp(exp.expType.templateParameter.identifier.string, curParam.name))
10366                            {
10367                               for(sClass = sClass.base; sClass; sClass = sClass.base)
10368                                  id += sClass.templateParams.count;
10369                               break;
10370                            }
10371                            id++;
10372                         }
10373                         if(curParam) break;
10374                      }
10375
10376                      if(curParam && tClass.templateArgs[id].dataTypeString)
10377                      {
10378                         ClassTemplateArgument arg = tClass.templateArgs[id];
10379                         Context context = SetupTemplatesContext(tClass);
10380                         bool constant = exp.expType.constant;
10381                         bool passAsTemplate = false;
10382                         Class thisClassFrom = null;
10383                         Type t = ProcessTypeString(exp.expType.templateParameter.dataTypeString, false);
10384                         if(t && t.kind == classType && t._class)
10385                            thisClassFrom = t._class.registered;
10386                         else
10387                            // Mark that 'thisClassFrom' was set to something
10388                            thisClassFrom = eSystem_FindClass(GetPrivateModule(), "class");
10389
10390                         FreeType(t);
10391
10392                         passAsTemplate = tClass.templateClass && (exp.expType.kind != templateType ||
10393                            (!exp.expType.templateParameter || (!exp.expType.templateParameter.dataTypeString && !exp.expType.templateParameter.dataType)));
10394
10395                         /*if(!arg.dataType)
10396                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
10397                         FreeType(exp.expType);
10398
10399                         exp.expType = ProcessTypeString(arg.dataTypeString, false);
10400                         exp.expType.thisClassFrom = thisClassFrom;
10401                         if(exp.expType.kind == classType && constant) exp.expType.constant = true;
10402                         else if(exp.expType.kind == pointerType)
10403                         {
10404                            Type t = exp.expType.type;
10405                            while(t.kind == pointerType) t = t.type;
10406                            if(constant) t.constant = constant;
10407                         }
10408                         if(exp.expType)
10409                         {
10410                            if(exp.expType.kind == thisClassType)
10411                            {
10412                               FreeType(exp.expType);
10413                               exp.expType = ReplaceThisClassType(_class);
10414                            }
10415
10416                            if(passAsTemplate)
10417                               exp.expType.passAsTemplate = true;
10418                            //exp.expType.refCount++;
10419                            if(!exp.destType)
10420                            {
10421                               exp.destType = ProcessTypeString(arg.dataTypeString, false);
10422                               if(exp.destType.kind == classType && constant) exp.destType.constant = true;
10423                               else if(exp.destType.kind == pointerType)
10424                               {
10425                                  Type t = exp.destType.type;
10426                                  while(t.kind == pointerType) t = t.type;
10427                                  if(constant) t.constant = constant;
10428                               }
10429
10430                               //exp.destType.refCount++;
10431
10432                               if(exp.destType.kind == thisClassType)
10433                               {
10434                                  FreeType(exp.destType);
10435                                  exp.destType = ReplaceThisClassType(_class);
10436                               }
10437                            }
10438                         }
10439                         FinishTemplatesContext(context);
10440                      }
10441                   }
10442                   // TODO: MORE GENERIC SUPPORT FOR DEEPER TYPES
10443                   else if(tClass && exp.expType.kind == pointerType && exp.expType.type && exp.expType.type.kind == templateType && exp.expType.type.templateParameter.type == TemplateParameterType::type)
10444                   {
10445                      int id = 0;
10446                      ClassTemplateParameter curParam = null;
10447                      Class sClass;
10448
10449                      for(sClass = tClass; sClass; sClass = sClass.base)
10450                      {
10451                         id = 0;
10452                         if(sClass.templateClass) sClass = sClass.templateClass;
10453                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
10454                         {
10455                            if(curParam.type == TemplateParameterType::type &&
10456                               !strcmp(exp.expType.type.templateParameter.identifier.string, curParam.name))
10457                            {
10458                               for(sClass = sClass.base; sClass; sClass = sClass.base)
10459                                  id += sClass.templateParams.count;
10460                               break;
10461                            }
10462                            id++;
10463                         }
10464                         if(curParam) break;
10465                      }
10466
10467                      if(curParam)
10468                      {
10469                         ClassTemplateArgument arg = tClass.templateArgs[id];
10470                         Context context = SetupTemplatesContext(tClass);
10471                         Type basicType;
10472                         /*if(!arg.dataType)
10473                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
10474
10475                         basicType = ProcessTypeString(arg.dataTypeString, false);
10476                         if(basicType)
10477                         {
10478                            if(basicType.kind == thisClassType)
10479                            {
10480                               FreeType(basicType);
10481                               basicType = ReplaceThisClassType(_class);
10482                            }
10483
10484                            /*    DO WE REALLY WANT THIS HERE? IT SEEMS TO BE ONLY USED WITH Array::array which was causing bug 135
10485                            if(tClass.templateClass)
10486                               basicType.passAsTemplate = true;
10487                            */
10488
10489                            FreeType(exp.expType);
10490
10491                            exp.expType = Type { refCount = 1, kind = pointerType, type = basicType };
10492                            //exp.expType.refCount++;
10493                            if(!exp.destType)
10494                            {
10495                               exp.destType = exp.expType;
10496                               exp.destType.refCount++;
10497                            }
10498
10499                            {
10500                               Expression newExp { };
10501                               OldList * specs = MkList();
10502                               Declarator decl;
10503                               decl = SpecDeclFromString(arg.dataTypeString, specs, null);
10504                               *newExp = *exp;
10505                               if(exp.destType) exp.destType.refCount++;
10506                               if(exp.expType)  exp.expType.refCount++;
10507                               exp.type = castExp;
10508                               exp.cast.typeName = MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl));
10509                               exp.cast.exp = newExp;
10510                               //FreeType(exp.expType);
10511                               //exp.expType = null;
10512                               //ProcessExpressionType(sourceExp);
10513                            }
10514                         }
10515                         FinishTemplatesContext(context);
10516                      }
10517                   }
10518                   else if(tClass && exp.expType.kind == classType && exp.expType._class && strchr(exp.expType._class.string, '<'))
10519                   {
10520                      Class expClass = exp.expType._class.registered;
10521                      if(expClass)
10522                      {
10523                         Class cClass = null;
10524                         int p = 0;
10525                         int paramCount = 0;
10526                         int lastParam = -1;
10527                         char templateString[1024];
10528                         ClassTemplateParameter param;
10529                         sprintf(templateString, "%s<", expClass.templateClass.fullName);
10530                         while(cClass != expClass)
10531                         {
10532                            Class sClass;
10533                            for(sClass = expClass; sClass && sClass.base != cClass; sClass = sClass.base);
10534                            cClass = sClass;
10535
10536                            for(param = cClass.templateParams.first; param; param = param.next)
10537                            {
10538                               Class cClassCur = null;
10539                               int cp = 0;
10540                               ClassTemplateParameter paramCur = null;
10541                               ClassTemplateArgument arg;
10542                               while(cClassCur != tClass && !paramCur)
10543                               {
10544                                  Class sClassCur;
10545                                  for(sClassCur = tClass; sClassCur && sClassCur.base != cClassCur; sClassCur = sClassCur.base);
10546                                  cClassCur = sClassCur;
10547
10548                                  for(paramCur = cClassCur.templateParams.first; paramCur; paramCur = paramCur.next)
10549                                  {
10550                                     if(!strcmp(paramCur.name, param.name))
10551                                     {
10552
10553                                        break;
10554                                     }
10555                                     cp++;
10556                                  }
10557                               }
10558                               if(paramCur && paramCur.type == TemplateParameterType::type)
10559                                  arg = tClass.templateArgs[cp];
10560                               else
10561                                  arg = expClass.templateArgs[p];
10562
10563                               {
10564                                  char argument[256];
10565                                  argument[0] = '\0';
10566                                  /*if(arg.name)
10567                                  {
10568                                     strcat(argument, arg.name.string);
10569                                     strcat(argument, " = ");
10570                                  }*/
10571                                  switch(param.type)
10572                                  {
10573                                     case expression:
10574                                     {
10575                                        // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
10576                                        char expString[1024];
10577                                        OldList * specs = MkList();
10578                                        Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
10579                                        Expression exp;
10580                                        char * string = PrintHexUInt64(arg.expression.ui64);
10581                                        exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
10582                                        delete string;
10583
10584                                        ProcessExpressionType(exp);
10585                                        ComputeExpression(exp);
10586                                        expString[0] = '\0';
10587                                        PrintExpression(exp, expString);
10588                                        strcat(argument, expString);
10589                                        // delete exp;
10590                                        FreeExpression(exp);
10591                                        break;
10592                                     }
10593                                     case identifier:
10594                                     {
10595                                        strcat(argument, arg.member.name);
10596                                        break;
10597                                     }
10598                                     case TemplateParameterType::type:
10599                                     {
10600                                        if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10601                                           strcat(argument, arg.dataTypeString);
10602                                        break;
10603                                     }
10604                                  }
10605                                  if(argument[0])
10606                                  {
10607                                     if(paramCount) strcat(templateString, ", ");
10608                                     if(lastParam != p - 1)
10609                                     {
10610                                        strcat(templateString, param.name);
10611                                        strcat(templateString, " = ");
10612                                     }
10613                                     strcat(templateString, argument);
10614                                     paramCount++;
10615                                     lastParam = p;
10616                                  }
10617                               }
10618                               p++;
10619                            }
10620                         }
10621                         {
10622                            int len = strlen(templateString);
10623                            if(templateString[len-1] == '>') templateString[len++] = ' ';
10624                            templateString[len++] = '>';
10625                            templateString[len++] = '\0';
10626                         }
10627
10628                         FreeType(exp.expType);
10629                         {
10630                            Context context = SetupTemplatesContext(tClass);
10631                            exp.expType = ProcessTypeString(templateString, false);
10632                            FinishTemplatesContext(context);
10633                         }
10634                      }
10635                   }
10636                }
10637             }
10638             else
10639                Compiler_Error($"undefined class %s\n", (id && (!id._class || id._class.name))? (id.classSym ? id.classSym.string : (type._class ? type._class.string : null)) : "(null)");
10640          }
10641          else if(type && (type.kind == structType || type.kind == unionType))
10642          {
10643             Type memberType = exp.member.member ? FindMember(type, exp.member.member.string) : null;
10644             if(memberType)
10645             {
10646                exp.expType = memberType;
10647                if(memberType)
10648                   memberType.refCount++;
10649             }
10650          }
10651          else
10652          {
10653             char expString[10240];
10654             expString[0] = '\0';
10655             if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10656             Compiler_Error($"member operator on non-structure type expression %s\n", expString);
10657          }
10658
10659          if(exp.expType && exp.expType.kind == thisClassType && (!exp.destType || exp.destType.kind != thisClassType))
10660          {
10661             if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType))
10662             {
10663                Identifier id = exp.member.member;
10664                Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10665                if(_class)
10666                {
10667                   FreeType(exp.expType);
10668                   exp.expType = ReplaceThisClassType(_class);
10669                }
10670             }
10671          }
10672          yylloc = oldyylloc;
10673          break;
10674       }
10675       // Convert x->y into (*x).y
10676       case pointerExp:
10677       {
10678          Type destType = exp.destType;
10679
10680          // DOING THIS LATER NOW...
10681          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
10682          {
10683             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
10684             /* TODO: Name Space Fix ups
10685             if(!exp.member.member.classSym)
10686                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.name);
10687             */
10688          }
10689
10690          exp.member.exp = MkExpBrackets(MkListOne(MkExpOp(null, '*', exp.member.exp)));
10691          exp.type = memberExp;
10692          if(destType)
10693             destType.count++;
10694          ProcessExpressionType(exp);
10695          if(destType)
10696             destType.count--;
10697          break;
10698       }
10699       case classSizeExp:
10700       {
10701          //ComputeExpression(exp);
10702
10703          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
10704          if(classSym && classSym.registered)
10705          {
10706             if(classSym.registered.type == noHeadClass || (classSym.registered.fixed && classSym.registered.structSize))
10707             {
10708                char name[1024];
10709                Class b = classSym.registered;
10710                name[0] = '\0';
10711                DeclareStruct(curExternal, classSym.string, false, true);
10712                FreeSpecifier(exp._class);
10713                FullClassNameCat(name, classSym.string, false);
10714
10715                if(b.offset == 0)
10716                {
10717                   exp.type = typeSizeExp;
10718                   exp.typeName = MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null);
10719                }
10720                else
10721                {
10722                   Expression e;
10723                   exp.type = opExp;
10724                   if(b.structSize == b.offset)
10725                      exp.op.exp1 = MkExpConstant("0");
10726                   else
10727                      exp.op.exp1 = MkExpTypeSize(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null));
10728                   exp.op.op = '+';
10729                   e = exp;
10730                   while(b.offset != 0)
10731                   {
10732                      Symbol sym;
10733                      Expression typeSize;
10734
10735                      b = b.base;
10736                      sym = FindClass(b.fullName);
10737
10738                      name[0] = '\0';
10739                      DeclareStruct(curExternal, sym.string, false, true);
10740                      FullClassNameCat(name, sym.string, false);
10741
10742                      if(b.structSize == b.offset)
10743                         typeSize = MkExpConstant("0");
10744                      else
10745                         typeSize = MkExpTypeSize(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null));
10746                      e.op.exp2 = b.offset ? MkExpOp(typeSize, '+', null) : typeSize;
10747                      e = e.op.exp2;
10748                   }
10749                }
10750             }
10751             else
10752             {
10753                if(classSym.registered.fixed && !classSym.registered.structSize)
10754                {
10755                   FreeSpecifier(exp._class);
10756                   exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
10757                   exp.type = constantExp;
10758                }
10759                else
10760                {
10761                   char className[1024];
10762                   strcpy(className, "__ecereClass_");
10763                   FullClassNameCat(className, classSym.string, true);
10764
10765                   DeclareClass(curExternal, classSym, className);
10766
10767                   FreeExpContents(exp);
10768                   exp.type = pointerExp;
10769                   exp.member.exp = MkExpIdentifier(MkIdentifier(className));
10770                   exp.member.member = MkIdentifier("structSize");
10771                }
10772             }
10773          }
10774
10775          exp.expType = Type
10776          {
10777             refCount = 1;
10778             kind = intSizeType;
10779          };
10780          // exp.isConstant = true;
10781          break;
10782       }
10783       case typeSizeExp:
10784       {
10785          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
10786
10787          exp.expType = Type
10788          {
10789             refCount = 1;
10790             kind = intSizeType;
10791          };
10792          exp.isConstant = true;
10793
10794          DeclareType(curExternal, type, true, false);
10795          FreeType(type);
10796          break;
10797       }
10798       case castExp:
10799       {
10800          Type type = ProcessType(exp.cast.typeName.qualifiers, exp.cast.typeName.declarator);
10801          type.count = 1;
10802          FreeType(exp.cast.exp.destType);
10803          exp.cast.exp.destType = type;
10804          type.refCount++;
10805          type.casted = true;
10806          ProcessExpressionType(exp.cast.exp);
10807          type.casted = false;
10808          type.count = 0;
10809          exp.expType = type;
10810          //type.refCount++;
10811
10812          // if(!NeedCast(exp.cast.exp.expType, exp.cast.exp.destType))
10813          if(!exp.cast.exp.needCast && !NeedCast(exp.cast.exp.expType, type))
10814          {
10815             void * prev = exp.prev, * next = exp.next;
10816             Type expType = exp.cast.exp.destType;
10817             Expression castExp = exp.cast.exp;
10818             Type destType = exp.destType;
10819
10820             if(expType) expType.refCount++;
10821
10822             //FreeType(exp.destType);
10823             FreeType(exp.expType);
10824             FreeTypeName(exp.cast.typeName);
10825
10826             *exp = *castExp;
10827             FreeType(exp.expType);
10828             FreeType(exp.destType);
10829
10830             exp.expType = expType;
10831             exp.destType = destType;
10832
10833             delete castExp;
10834
10835             exp.prev = prev;
10836             exp.next = next;
10837
10838          }
10839          else
10840          {
10841             exp.isConstant = exp.cast.exp.isConstant;
10842          }
10843          //FreeType(type);
10844          break;
10845       }
10846       case extensionInitializerExp:
10847       {
10848          Type type = ProcessType(exp.initializer.typeName.qualifiers, exp.initializer.typeName.declarator);
10849          // We have yet to support this... ( { } initializers are currently processed inside ProcessDeclaration()'s initDeclaration case statement
10850          // ProcessInitializer(exp.initializer.initializer, type);
10851          exp.expType = type;
10852          break;
10853       }
10854       case vaArgExp:
10855       {
10856          Type type = ProcessType(exp.vaArg.typeName.qualifiers, exp.vaArg.typeName.declarator);
10857          ProcessExpressionType(exp.vaArg.exp);
10858          exp.expType = type;
10859          break;
10860       }
10861       case conditionExp:
10862       {
10863          Expression e;
10864          Type t = exp.destType;
10865          if(t && !exp.destType.casted)
10866          {
10867             t = { };
10868             CopyTypeInto(t, exp.destType);
10869             t.count = 0;
10870          }
10871          else if(t)
10872             t.refCount++;
10873
10874          exp.isConstant = true;
10875
10876          FreeType(exp.cond.cond.destType);
10877          exp.cond.cond.destType = MkClassType("bool");
10878          exp.cond.cond.destType.truth = true;
10879          ProcessExpressionType(exp.cond.cond);
10880          if(!exp.cond.cond.isConstant)
10881             exp.isConstant = false;
10882          for(e = exp.cond.exp->first; e; e = e.next)
10883          {
10884             if(!e.next)
10885             {
10886                FreeType(e.destType);
10887                e.destType = t;
10888                if(e.destType) e.destType.refCount++;
10889             }
10890             ProcessExpressionType(e);
10891             if(!e.next)
10892             {
10893                exp.expType = e.expType;
10894                if(e.expType) e.expType.refCount++;
10895             }
10896             if(!e.isConstant)
10897                exp.isConstant = false;
10898          }
10899
10900          FreeType(exp.cond.elseExp.destType);
10901          // Added this check if we failed to find an expType
10902          // exp.cond.elseExp.destType = exp.expType ? exp.expType : exp.destType;
10903
10904          // Reversed it...
10905          exp.cond.elseExp.destType = t ? t : exp.expType;
10906
10907          if(exp.cond.elseExp.destType)
10908             exp.cond.elseExp.destType.refCount++;
10909          ProcessExpressionType(exp.cond.elseExp);
10910
10911          // FIXED THIS: Was done before calling process on elseExp
10912          if(!exp.cond.elseExp.isConstant)
10913             exp.isConstant = false;
10914
10915          FreeType(t);
10916          break;
10917       }
10918       case extensionCompoundExp:
10919       {
10920          if(exp.compound && exp.compound.compound.statements && exp.compound.compound.statements->last)
10921          {
10922             Statement last = exp.compound.compound.statements->last;
10923             if(last.type == expressionStmt && last.expressions && last.expressions->last)
10924             {
10925                ((Expression)last.expressions->last).destType = exp.destType;
10926                if(exp.destType)
10927                   exp.destType.refCount++;
10928             }
10929             ProcessStatement(exp.compound);
10930             exp.expType = (last.expressions && last.expressions->last) ? ((Expression)last.expressions->last).expType : null;
10931             if(exp.expType)
10932                exp.expType.refCount++;
10933          }
10934          break;
10935       }
10936       case classExp:
10937       {
10938          Specifier spec = exp._classExp.specifiers->first;
10939          if(spec && spec.type == nameSpecifier)
10940          {
10941             exp.expType = MkClassType(spec.name);
10942             exp.expType.kind = subClassType;
10943             exp.byReference = true;
10944          }
10945          else
10946          {
10947             exp.expType = MkClassType("ecere::com::Class");
10948             exp.byReference = true;
10949          }
10950          break;
10951       }
10952       case classDataExp:
10953       {
10954          Class _class = thisClass ? thisClass : currentClass;
10955          if(_class)
10956          {
10957             Identifier id = exp.classData.id;
10958             char structName[1024];
10959             Expression classExp;
10960             strcpy(structName, "__ecereClassData_");
10961             FullClassNameCat(structName, _class.fullName, false);
10962             exp.type = pointerExp;
10963             exp.member.member = id;
10964             if(curCompound && FindSymbol("this", curContext, curCompound.compound.context, false, false))
10965                classExp = MkExpMember(MkExpIdentifier(MkIdentifier("this")), MkIdentifier("_class"));
10966             else
10967                classExp = MkExpIdentifier(MkIdentifier("class"));
10968
10969             exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10970                MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10971                   MkExpBrackets(MkListOne(MkExpOp(
10972                      MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10973                         MkExpMember(classExp, MkIdentifier("data"))), '+',
10974                            MkExpMember(MkExpClass(MkListOne(MkSpecifierName(_class.fullName)), null), MkIdentifier("offsetClass")))))
10975                      )));
10976
10977             ProcessExpressionType(exp);
10978             return;
10979          }
10980          break;
10981       }
10982       case arrayExp:
10983       {
10984          Type type = null;
10985          const char * typeString = null;
10986          char typeStringBuf[1024];
10987          if(exp.destType && exp.destType.kind == classType && exp.destType._class && exp.destType._class.registered &&
10988             exp.destType._class.registered != containerClass && eClass_IsDerived(exp.destType._class.registered, containerClass))
10989          {
10990             Class templateClass = exp.destType._class.registered;
10991             typeString = templateClass.templateArgs[2].dataTypeString;
10992          }
10993          else if(exp.list)
10994          {
10995             // Guess type from expressions in the array
10996             Expression e;
10997             for(e = exp.list->first; e; e = e.next)
10998             {
10999                ProcessExpressionType(e);
11000                if(e.expType)
11001                {
11002                   if(!type) { type = e.expType; type.refCount++; }
11003                   else
11004                   {
11005                      // if(!MatchType(e.expType, type, null, null, null, false, false, false))
11006                      if(!MatchTypeExpression(e, type, null, false, true))
11007                      {
11008                         FreeType(type);
11009                         type = e.expType;
11010                         e.expType = null;
11011
11012                         e = exp.list->first;
11013                         ProcessExpressionType(e);
11014                         if(e.expType)
11015                         {
11016                            //if(!MatchTypes(e.expType, type, null, null, null, false, false, false))
11017                            if(!MatchTypeExpression(e, type, null, false, true))
11018                            {
11019                               FreeType(e.expType);
11020                               e.expType = null;
11021                               FreeType(type);
11022                               type = null;
11023                               break;
11024                            }
11025                         }
11026                      }
11027                   }
11028                   if(e.expType)
11029                   {
11030                      FreeType(e.expType);
11031                      e.expType = null;
11032                   }
11033                }
11034             }
11035             if(type)
11036             {
11037                typeStringBuf[0] = '\0';
11038                PrintTypeNoConst(type, typeStringBuf, false, true);
11039                typeString = typeStringBuf;
11040                FreeType(type);
11041                type = null;
11042             }
11043          }
11044          if(typeString)
11045          {
11046             /*
11047             (Container)& (struct BuiltInContainer)
11048             {
11049                ._vTbl = class(BuiltInContainer)._vTbl,
11050                ._class = class(BuiltInContainer),
11051                .refCount = 0,
11052                .data = (int[]){ 1, 7, 3, 4, 5 },
11053                .count = 5,
11054                .type = class(int),
11055             }
11056             */
11057             char templateString[1024];
11058             OldList * initializers = MkList();
11059             OldList * structInitializers = MkList();
11060             OldList * specs = MkList();
11061             Expression expExt;
11062             Declarator decl = SpecDeclFromString(typeString, specs, null);
11063             sprintf(templateString, "Container<%s>", typeString);
11064
11065             if(exp.list)
11066             {
11067                Expression e;
11068                type = ProcessTypeString(typeString, false);
11069                while((e = exp.list->first))
11070                {
11071                   exp.list->Remove(e);
11072                   e.destType = type;
11073                   type.refCount++;
11074                   ProcessExpressionType(e);
11075                   ListAdd(initializers, MkInitializerAssignment(e));
11076                }
11077                FreeType(type);
11078                delete exp.list;
11079             }
11080
11081             DeclareStruct(curExternal, "ecere::com::BuiltInContainer", false, true);
11082
11083             ListAdd(structInitializers, /*MkIdentifier("_vTbl")*/    MkInitializerAssignment(MkExpMember(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null), MkIdentifier("_vTbl"))));
11084                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11085             ListAdd(structInitializers, /*MkIdentifier("_class")*/   MkInitializerAssignment(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null)));
11086                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11087             ListAdd(structInitializers, /*MkIdentifier("_refCount")*/MkInitializerAssignment(MkExpConstant("0")));
11088                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11089             ListAdd(structInitializers, /*MkIdentifier("data")*/     MkInitializerAssignment(MkExpExtensionInitializer(
11090                MkTypeName(specs, MkDeclaratorArray(decl, null)),
11091                MkInitializerList(initializers))));
11092                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11093             ListAdd(structInitializers, /*MkIdentifier("count")*/    MkInitializerAssignment({ type = constantExp, constant = PrintString(initializers->count) }));
11094                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11095             ListAdd(structInitializers, /*MkIdentifier("type")*/     MkInitializerAssignment(MkExpClass(CopyList(specs, CopySpecifier), CopyDeclarator(decl))));
11096                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11097             exp.expType = ProcessTypeString(templateString, false);
11098             exp.type = bracketsExp;
11099             exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(templateString)), null),
11100                MkExpOp(null, '&',
11101                expExt = MkExpExtensionInitializer(MkTypeName(MkListOne(MkSpecifierName("BuiltInContainer")), null),
11102                   MkInitializerList(structInitializers)))));
11103             ProcessExpressionType(expExt);
11104          }
11105          else
11106          {
11107             exp.expType = ProcessTypeString("Container", false);
11108             Compiler_Error($"Couldn't determine type of array elements\n");
11109          }
11110          break;
11111       }
11112    }
11113
11114    if(exp.expType && exp.expType.kind == thisClassType && thisClass && (!exp.destType || exp.destType.kind != thisClassType))
11115    {
11116       FreeType(exp.expType);
11117       exp.expType = ReplaceThisClassType(thisClass);
11118    }
11119
11120    // Resolve structures here
11121    if(exp.expType && (exp.expType.kind == structType || exp.expType.kind == unionType || exp.expType.kind == enumType) && !exp.expType.members.first && exp.expType.enumName)
11122    {
11123       Symbol symbol = FindSymbol(exp.expType.enumName, curContext, globalContext, true, false);
11124       // TODO: Fix members reference...
11125       if(symbol)
11126       {
11127          if(exp.expType.kind != enumType)
11128          {
11129             Type member;
11130             String enumName = CopyString(exp.expType.enumName);
11131
11132             // Fixed a memory leak on self-referencing C structs typedefs
11133             // by instantiating a new type rather than simply copying members
11134             // into exp.expType
11135             FreeType(exp.expType);
11136             exp.expType = Type { };
11137             exp.expType.kind = symbol.type.kind;
11138             exp.expType.refCount++;
11139             exp.expType.enumName = enumName;
11140
11141             exp.expType.members = symbol.type.members;
11142             for(member = symbol.type.members.first; member; member = member.next)
11143                member.refCount++;
11144          }
11145          else
11146          {
11147             NamedLink64 member;
11148             for(member = symbol.type.members.first; member; member = member.next)
11149             {
11150                NamedLink64 value { name = CopyString(member.name) };
11151                exp.expType.members.Add(value);
11152             }
11153          }
11154       }
11155    }
11156
11157    yylloc = exp.loc;
11158    if(exp.destType && (/*exp.destType.kind == voidType || */exp.destType.kind == dummyType) );
11159    else if(exp.destType && !exp.destType.keepCast)
11160    {
11161       if(!exp.needTemplateCast && exp.expType && (exp.expType.kind == templateType || exp.expType.passAsTemplate)) // && exp.destType && !exp.destType.passAsTemplate)
11162          exp.needTemplateCast = 1;
11163
11164       if(exp.destType.kind == voidType);
11165       else if(!CheckExpressionType(exp, exp.destType, false, !exp.destType.casted))
11166       {
11167          // Warn for casting unrelated types to/from struct classes
11168          bool invalidCast = false;
11169          if(inCompiler && exp.destType.count && exp.expType)
11170          {
11171             Class c1 = (exp.expType.kind == classType && exp.expType._class) ? exp.expType._class.registered : null;
11172             Class c2 = (exp.destType.kind == classType && exp.destType._class) ? exp.destType._class.registered : null;
11173             if(c1 && c1.type != structClass) c1 = null;
11174             if(c2 && c2.type != structClass) c2 = null;
11175             if((c1 && !exp.expType.byReference && !c2 && !exp.destType.isPointerType) || (c2 && !exp.destType.byReference && !c1 && !exp.expType.isPointerType))
11176                invalidCast = true;
11177          }
11178          if(!exp.destType.count || unresolved || invalidCast)
11179          {
11180             if(!exp.expType)
11181             {
11182                yylloc = exp.loc;
11183                if(exp.destType.kind != ellipsisType)
11184                {
11185                   char type2[1024];
11186                   type2[0] = '\0';
11187                   if(inCompiler)
11188                   {
11189                      char expString[10240];
11190                      expString[0] = '\0';
11191
11192                      PrintType(exp.destType, type2, false, true);
11193
11194                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11195                      if(unresolved)
11196                         Compiler_Error($"unresolved identifier %s; expected %s\n", expString, type2);
11197                      else if(exp.type != dummyExp)
11198                         Compiler_Error($"couldn't determine type of %s; expected %s\n", expString, type2);
11199                   }
11200                }
11201                else
11202                {
11203                   char expString[10240] ;
11204                   expString[0] = '\0';
11205                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11206
11207                   if(unresolved)
11208                      Compiler_Error($"unresolved identifier %s\n", expString);
11209                   else if(exp.type != dummyExp)
11210                      Compiler_Error($"couldn't determine type of %s\n", expString);
11211                }
11212             }
11213             else
11214             {
11215                char type1[1024];
11216                char type2[1024];
11217                type1[0] = '\0';
11218                type2[0] = '\0';
11219                if(inCompiler)
11220                {
11221                   PrintType(exp.expType, type1, false, true);
11222                   PrintType(exp.destType, type2, false, true);
11223                }
11224
11225                //CheckExpressionType(exp, exp.destType, false);
11226
11227                if(exp.destType.truth && exp.destType._class && exp.destType._class.registered && !strcmp(exp.destType._class.registered.name, "bool") &&
11228                   exp.expType.kind != voidType && exp.expType.kind != structType && exp.expType.kind != unionType &&
11229                   (exp.expType.kind != classType || exp.expType.classObjectType || (exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type != structClass)));
11230                else
11231                {
11232                   Expression nbExp = GetNonBracketsExp(exp);
11233                   bool skipWarning = false;
11234                   TypeKind kind = exp.destType.kind;
11235                   if(nbExp.type == conditionExp && !nbExp.destType.casted && nbExp.destType.kind == exp.destType.kind)
11236                      // The if/else operands have already been checked / warned about
11237                      skipWarning = true;
11238                   if((kind == charType || kind == shortType) && exp.destType.isSigned == exp.expType.signedBeforePromotion && nbExp.type == opExp && nbExp.op.exp1 && nbExp.op.exp2)
11239                   {
11240                      int op = nbExp.op.op;
11241                      Expression nbExp1, nbExp2;
11242                      TypeKind from;
11243
11244                      switch(op)
11245                      {
11246                         case '%': case '/':
11247                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11248                            from = nbExp1.expType.promotedFrom;
11249                            // Division and Modulo will not take more room than type before promotion
11250                            if(from == charType || (kind == shortType && from == shortType))
11251                               skipWarning = true;
11252                            break;
11253                         // Left shift
11254                         case LEFT_OP: case RIGHT_OP:
11255                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11256                            nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11257                            from = nbExp1.expType.promotedFrom;
11258                            // Right shift will not take more room than type before promotion
11259                            if(op == RIGHT_OP && (from == charType || (kind == shortType && from == shortType)))
11260                               skipWarning = true;
11261                            else if(nbExp2.isConstant && nbExp2.type == constantExp && (nbExp.op.op == RIGHT_OP || nbExp1.expType.bitMemberSize))
11262                            {
11263                               int n = (int)strtol(nbExp2.constant, null, 0);
11264                               int s = from == charType ? 8 : 16;
11265                               // Left shifting a bit member constrained in size may still fit in type before promotion
11266                               if(nbExp1.expType.bitMemberSize && nbExp1.expType.bitMemberSize < s)
11267                                  s = nbExp1.expType.bitMemberSize;
11268
11269                               // If right shifted enough things will fit in smaller type
11270                               if(nbExp.op.op == RIGHT_OP)
11271                                  s -= n;
11272                               else
11273                                  s += n;
11274                               if(s <= (kind == charType ? 8 : 16))
11275                                  skipWarning = true;
11276                            }
11277                            break;
11278                         case '-':
11279                            if(!exp.destType.isSigned)
11280                            {
11281                               nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11282                               nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11283                               from = nbExp2.expType.promotedFrom;
11284                               // Max value of unsigned type before promotion minus the same will always fit
11285                               if((from == charType || from == shortType) && nbExp1.isConstant && nbExp1.type == constantExp)
11286                               {
11287                                  int n = (int)strtol(nbExp1.constant, null, 0);
11288                                  if(n == (from == charType ? 255 : 65535))
11289                                     skipWarning = true;
11290                               }
11291                            }
11292                            break;
11293                         case '|':
11294                         {
11295                            TypeKind kind1, kind2;
11296                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11297                            nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11298                            kind1 = nbExp1.expType.promotedFrom ? nbExp1.expType.promotedFrom : nbExp1.expType.kind;
11299                            kind2 = nbExp2.expType.promotedFrom ? nbExp2.expType.promotedFrom : nbExp2.expType.kind;
11300                            if(((kind1 == charType || (kind1 == shortType && kind == shortType)) || MatchTypeExpression(nbExp1, exp.destType, null, false, false)) &&
11301                               ((kind2 == charType || (kind2 == shortType && kind == shortType)) || MatchTypeExpression(nbExp2, exp.destType, null, false, false)))
11302                               skipWarning = true;
11303                            break;
11304                         }
11305                         case '&':
11306                         {
11307                            TypeKind kind1, kind2;
11308                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11309                            nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11310                            kind1 = nbExp1.expType.promotedFrom ? nbExp1.expType.promotedFrom : nbExp1.expType.kind;
11311                            kind2 = nbExp2.expType.promotedFrom ? nbExp2.expType.promotedFrom : nbExp2.expType.kind;
11312                            if(((kind1 == charType || (kind1 == shortType && kind == shortType)) || MatchTypeExpression(nbExp1, exp.destType, null, false, false)) ||
11313                               ((kind2 == charType || (kind2 == shortType && kind == shortType)) || MatchTypeExpression(nbExp2, exp.destType, null, false, false)))
11314                               skipWarning = true;
11315                            break;
11316                         }
11317                      }
11318                   }
11319
11320                   if(!skipWarning)
11321                   {
11322                      char expString[10240];
11323                      expString[0] = '\0';
11324                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11325
11326 #ifdef _DEBUG
11327                      CheckExpressionType(exp, exp.destType, false, true);
11328 #endif
11329
11330                      // Flex & Bison generate code that triggers this, so we ignore it for a quiet sdk build:
11331                      if(!sourceFile || (!strstr(sourceFile, "src\\lexer.ec") && !strstr(sourceFile, "src/lexer.ec") &&
11332                                         !strstr(sourceFile, "src\\grammar.ec") && !strstr(sourceFile, "src/grammar.ec") &&
11333                                         !strstr(sourceFile, "src\\type.ec") && !strstr(sourceFile, "src/type.ec") &&
11334                                         !strstr(sourceFile, "src\\expression.ec") && !strstr(sourceFile, "src/expression.ec")))
11335                      {
11336                         if(invalidCast)
11337                            Compiler_Error($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
11338                         else
11339                            Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
11340                      }
11341                   }
11342
11343                   // TO CHECK: FORCING HERE TO HELP DEBUGGER
11344                   if(!inCompiler)
11345                   {
11346                      FreeType(exp.expType);
11347                      exp.destType.refCount++;
11348                      exp.expType = exp.destType;
11349                   }
11350                }
11351             }
11352          }
11353       }
11354       // Cast function pointers to void * as eC already checked compatibility
11355       else if(exp.destType && exp.destType.kind == pointerType && exp.destType.type && exp.destType.type.kind == functionType &&
11356               exp.expType && (exp.expType.kind == functionType || exp.expType.kind == methodType))
11357       {
11358          Expression nbExp = GetNonBracketsExp(exp);
11359          if(nbExp.type != castExp || !IsVoidPtrCast(nbExp.cast.typeName))
11360          {
11361             Expression e = MoveExpContents(exp);
11362             exp.cast.exp = MkExpBrackets(MkListOne(e));
11363             exp.type = castExp;
11364             exp.cast.exp.destType = exp.destType;
11365             if(exp.destType) exp.destType.refCount++;
11366             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
11367          }
11368       }
11369    }
11370    else if(unresolved)
11371    {
11372       if(exp.identifier._class && exp.identifier._class.name)
11373          Compiler_Error($"unresolved identifier %s::%s\n", exp.identifier._class.name, exp.identifier.string);
11374       else if(exp.identifier.string && exp.identifier.string[0])
11375          Compiler_Error($"unresolved identifier %s\n", exp.identifier.string);
11376    }
11377    else if(!exp.expType && exp.type != dummyExp)
11378    {
11379       char expString[10240];
11380       expString[0] = '\0';
11381       if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11382       Compiler_Error($"couldn't determine type of %s\n", expString);
11383    }
11384
11385    // Let's try to support any_object & typed_object here:
11386    if(inCompiler)
11387       ApplyAnyObjectLogic(exp);
11388
11389    // Mark nohead classes as by reference, unless we're casting them to an integral type
11390    if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
11391       exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
11392          (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
11393           exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
11394    {
11395       exp.byReference = true;
11396    }
11397    yylloc = oldyylloc;
11398 }
11399
11400 static void FindNextDataMember(Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
11401 {
11402    // THIS CODE WILL FIND NEXT MEMBER...
11403    if(*curMember)
11404    {
11405       *curMember = (*curMember).next;
11406
11407       if(subMemberStackPos && *subMemberStackPos > 0 && subMemberStack[*subMemberStackPos-1].type == unionMember)
11408       {
11409          *curMember = subMemberStack[--(*subMemberStackPos)];
11410          *curMember = (*curMember).next;
11411       }
11412
11413       // SKIP ALL PROPERTIES HERE...
11414       while((*curMember) && (*curMember).isProperty)
11415          *curMember = (*curMember).next;
11416
11417       if(subMemberStackPos)
11418       {
11419          while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
11420          {
11421             subMemberStack[(*subMemberStackPos)++] = *curMember;
11422
11423             *curMember = (*curMember).members.first;
11424             while(*curMember && (*curMember).isProperty)
11425                *curMember = (*curMember).next;
11426          }
11427       }
11428    }
11429    while(!*curMember)
11430    {
11431       if(!*curMember)
11432       {
11433          if(subMemberStackPos && *subMemberStackPos)
11434          {
11435             *curMember = subMemberStack[--(*subMemberStackPos)];
11436             *curMember = (*curMember).next;
11437          }
11438          else
11439          {
11440             Class lastCurClass = *curClass;
11441
11442             if(*curClass == _class) break;     // REACHED THE END
11443
11444             for(*curClass = _class; (*curClass).base != lastCurClass && (*curClass).base.type != systemClass; *curClass = (*curClass).base);
11445             *curMember = (*curClass).membersAndProperties.first;
11446          }
11447
11448          while((*curMember) && (*curMember).isProperty)
11449             *curMember = (*curMember).next;
11450          if(subMemberStackPos)
11451          {
11452             while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
11453             {
11454                subMemberStack[(*subMemberStackPos)++] = *curMember;
11455
11456                *curMember = (*curMember).members.first;
11457                while(*curMember && (*curMember).isProperty)
11458                   *curMember = (*curMember).next;
11459             }
11460          }
11461       }
11462    }
11463 }
11464
11465
11466 static void ProcessInitializer(Initializer init, Type type)
11467 {
11468    switch(init.type)
11469    {
11470       case expInitializer:
11471          if(!init.exp || init.exp.type != instanceExp || !init.exp.instance || init.exp.instance._class || !type || type.kind == classType)
11472          {
11473             // TESTING THIS FOR SHUTTING = 0 WARNING
11474             if(init.exp && !init.exp.destType)
11475             {
11476                FreeType(init.exp.destType);
11477                init.exp.destType = type;
11478                if(type) type.refCount++;
11479             }
11480             if(init.exp)
11481             {
11482                ProcessExpressionType(init.exp);
11483                init.isConstant = init.exp.isConstant;
11484             }
11485             break;
11486          }
11487          else
11488          {
11489             Expression exp = init.exp;
11490             Instantiation inst = exp.instance;
11491             MembersInit members;
11492
11493             init.type = listInitializer;
11494             init.list = MkList();
11495
11496             if(inst.members)
11497             {
11498                for(members = inst.members->first; members; members = members.next)
11499                {
11500                   if(members.type == dataMembersInit)
11501                   {
11502                      MemberInit member;
11503                      for(member = members.dataMembers->first; member; member = member.next)
11504                      {
11505                         ListAdd(init.list, member.initializer);
11506                         member.initializer = null;
11507                      }
11508                   }
11509                   // Discard all MembersInitMethod
11510                }
11511             }
11512             FreeExpression(exp);
11513          }
11514       case listInitializer:
11515       {
11516          Initializer i;
11517          Type initializerType = null;
11518          Class curClass = null;
11519          DataMember curMember = null;
11520          DataMember subMemberStack[256];
11521          int subMemberStackPos = 0;
11522
11523          if(type && type.kind == arrayType)
11524             initializerType = Dereference(type);
11525          else if(type && (type.kind == structType || type.kind == unionType))
11526             initializerType = type.members.first;
11527
11528          for(i = init.list->first; i; i = i.next)
11529          {
11530             if(type && type.kind == classType && type._class && type._class.registered)
11531             {
11532                // 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)
11533                FindNextDataMember(type._class.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
11534                // TODO: Generate error on initializing a private data member this way from another module...
11535                if(curMember)
11536                {
11537                   if(!curMember.dataType)
11538                      curMember.dataType = ProcessTypeString(curMember.dataTypeString, false);
11539                   initializerType = curMember.dataType;
11540                }
11541             }
11542             ProcessInitializer(i, initializerType);
11543             if(initializerType && type && (type.kind == structType || type.kind == unionType))
11544                initializerType = initializerType.next;
11545             if(!i.isConstant)
11546                init.isConstant = false;
11547          }
11548
11549          if(type && type.kind == arrayType)
11550             FreeType(initializerType);
11551
11552          if(type && type.kind != arrayType && type.kind != structType && type.kind != unionType && (type.kind != classType || !type._class.registered || type._class.registered.type != structClass))
11553          {
11554             Compiler_Error($"Assigning list initializer to non list\n");
11555          }
11556          break;
11557       }
11558    }
11559 }
11560
11561 static void ProcessSpecifier(Specifier spec, bool declareStruct, bool warnClasses)
11562 {
11563    switch(spec.type)
11564    {
11565       case baseSpecifier:
11566       {
11567          if(spec.specifier == THISCLASS)
11568          {
11569             if(thisClass)
11570             {
11571                spec.type = nameSpecifier;
11572                spec.name = ReplaceThisClass(thisClass);
11573                spec.symbol = FindClass(spec.name);
11574                ProcessSpecifier(spec, declareStruct, false);
11575             }
11576          }
11577          break;
11578       }
11579       case nameSpecifier:
11580       {
11581          Symbol symbol = FindType(curContext, spec.name);
11582          if(symbol)
11583             DeclareType(curExternal, symbol.type, true, true);
11584          else if(spec.symbol /*&& declareStruct*/)
11585          {
11586             Class c = spec.symbol.registered;
11587             if(warnClasses && !c)
11588                Compiler_Warning("Undeclared class %s\n", spec.name);
11589             DeclareStruct(curExternal, spec.name, c && c.type == noHeadClass, declareStruct && c && c.type == structClass);
11590          }
11591          break;
11592       }
11593       case enumSpecifier:
11594       {
11595          Enumerator e;
11596          if(spec.list)
11597          {
11598             for(e = spec.list->first; e; e = e.next)
11599             {
11600                if(e.exp)
11601                   ProcessExpressionType(e.exp);
11602             }
11603          }
11604          // Fall through for IDE type processing
11605          if(inCompiler)
11606             break;
11607       }
11608       case structSpecifier:
11609       case unionSpecifier:
11610       {
11611          if(spec.definitions)
11612          {
11613             //ClassDef def;
11614             Symbol symbol = spec.id ? FindClass(spec.id.string) : null;
11615             //if(symbol)
11616                ProcessClass(spec.definitions, symbol);
11617             /*else
11618             {
11619                for(def = spec.definitions->first; def; def = def.next)
11620                {
11621                   //if(def.type == declarationClassDef && def.decl && def.decl.type == DeclarationStruct)
11622                      ProcessDeclaration(def.decl);
11623                }
11624             }*/
11625          }
11626          break;
11627       }
11628       /*
11629       case classSpecifier:
11630       {
11631          Symbol classSym = FindClass(spec.name);
11632          if(classSym && classSym.registered && classSym.registered.type == structClass)
11633             DeclareStruct(spec.name, false, true);
11634          break;
11635       }
11636       */
11637    }
11638 }
11639
11640
11641 static void ProcessDeclarator(Declarator decl, bool isFunction)
11642 {
11643    switch(decl.type)
11644    {
11645       case identifierDeclarator:
11646          if(decl.identifier.classSym /* TODO: Name Space Fix ups  || decl.identifier.nameSpace*/)
11647          {
11648             FreeSpecifier(decl.identifier._class);
11649             decl.identifier._class = null;
11650          }
11651          break;
11652       case arrayDeclarator:
11653          if(decl.array.exp)
11654             ProcessExpressionType(decl.array.exp);
11655       case structDeclarator:
11656       case bracketsDeclarator:
11657       case functionDeclarator:
11658       case pointerDeclarator:
11659       case extendedDeclarator:
11660       case extendedDeclaratorEnd:
11661       {
11662          Identifier id = null;
11663          Specifier classSpec = null;
11664          if(decl.type == functionDeclarator)
11665          {
11666             id = GetDeclId(decl);
11667             if(id && id._class)
11668             {
11669                classSpec = id._class;
11670                id._class = null;
11671             }
11672          }
11673          if(decl.declarator)
11674             ProcessDeclarator(decl.declarator, isFunction);
11675          if(decl.type == functionDeclarator)
11676          {
11677             if(classSpec)
11678             {
11679                TypeName param
11680                {
11681                   qualifiers = MkListOne(classSpec);
11682                   declarator = null;
11683                };
11684                if(!decl.function.parameters)
11685                   decl.function.parameters = MkList();
11686                decl.function.parameters->Insert(null, param);
11687             }
11688             if(decl.function.parameters)
11689             {
11690                TypeName param;
11691
11692                for(param = decl.function.parameters->first; param; param = param.next)
11693                {
11694                   if(param.qualifiers)
11695                   {
11696                      Specifier spec;
11697                      for(spec = param.qualifiers->first; spec; spec = spec.next)
11698                      {
11699                         if(spec.type == baseSpecifier)
11700                         {
11701                            if(spec.specifier == TYPED_OBJECT)
11702                            {
11703                               Declarator d = param.declarator;
11704                               TypeName newParam
11705                               {
11706                                  qualifiers = MkListOne(MkSpecifier(VOID));
11707                                  declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11708                               };
11709                               if(d.type != pointerDeclarator)
11710                                  newParam.qualifiers->Insert(null, MkSpecifier(CONST));
11711
11712                               FreeList(param.qualifiers, FreeSpecifier);
11713
11714                               param.qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
11715                               param.declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
11716
11717                               DeclareStruct(curExternal, "ecere::com::Class", false, true);
11718
11719                               decl.function.parameters->Insert(param, newParam);
11720                               param = newParam;
11721                               break;
11722                            }
11723                            else if(spec.specifier == ANY_OBJECT)
11724                            {
11725                               Declarator d = param.declarator;
11726
11727                               FreeList(param.qualifiers, FreeSpecifier);
11728
11729                               param.qualifiers = MkListOne(MkSpecifier(VOID));
11730                               if(d.type != pointerDeclarator)
11731                                  param.qualifiers->Insert(null, MkSpecifier(CONST));
11732                               param.declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11733                               break;
11734                            }
11735                            else if(spec.specifier == THISCLASS)
11736                            {
11737                               if(thisClass)
11738                               {
11739                                  spec.type = nameSpecifier;
11740                                  spec.name = ReplaceThisClass(thisClass);
11741                                  spec.symbol = FindClass(spec.name);
11742                                  ProcessSpecifier(spec, false, false);
11743                               }
11744                               break;
11745                            }
11746                         }
11747                         else if(spec.type == nameSpecifier)
11748                         {
11749                            ProcessSpecifier(spec, isFunction, true);
11750                         }
11751                      }
11752                   }
11753
11754                   if(param.declarator)
11755                      ProcessDeclarator(param.declarator, false);
11756                }
11757             }
11758          }
11759          break;
11760       }
11761    }
11762 }
11763
11764 static void ProcessDeclaration(Declaration decl, bool warnClasses)
11765 {
11766    yylloc = decl.loc;
11767    switch(decl.type)
11768    {
11769       case initDeclaration:
11770       {
11771          bool declareStruct = false;
11772          /*
11773          lineNum = decl.pos.line;
11774          column = decl.pos.col;
11775          */
11776
11777          if(decl.declarators)
11778          {
11779             InitDeclarator d;
11780
11781             for(d = decl.declarators->first; d; d = d.next)
11782             {
11783                Type type, subType;
11784                ProcessDeclarator(d.declarator, false);
11785
11786                type = ProcessType(decl.specifiers, d.declarator);
11787
11788                if(d.initializer)
11789                {
11790                   ProcessInitializer(d.initializer, type);
11791
11792                   // Change "ColorRGB a = ColorRGB { 1,2,3 } => ColorRGB a { 1,2,3 }
11793
11794                   if(decl.declarators->count == 1 && d.initializer.type == expInitializer &&
11795                      d.initializer.exp.type == instanceExp)
11796                   {
11797                      if(type.kind == classType && type._class ==
11798                         d.initializer.exp.expType._class)
11799                      {
11800                         Instantiation inst = d.initializer.exp.instance;
11801                         inst.exp = MkExpIdentifier(CopyIdentifier(GetDeclId(d.declarator)));
11802
11803                         d.initializer.exp.instance = null;
11804                         if(decl.specifiers)
11805                            FreeList(decl.specifiers, FreeSpecifier);
11806                         FreeList(decl.declarators, FreeInitDeclarator);
11807
11808                         d = null;
11809
11810                         decl.type = instDeclaration;
11811                         decl.inst = inst;
11812                      }
11813                   }
11814                }
11815                for(subType = type; subType;)
11816                {
11817                   if(subType.kind == classType)
11818                   {
11819                      declareStruct = true;
11820                      break;
11821                   }
11822                   else if(subType.kind == pointerType)
11823                      break;
11824                   else if(subType.kind == arrayType)
11825                      subType = subType.arrayType;
11826                   else
11827                      break;
11828                }
11829
11830                FreeType(type);
11831                if(!d) break;
11832             }
11833          }
11834
11835          if(decl.specifiers)
11836          {
11837             Specifier s;
11838             for(s = decl.specifiers->first; s; s = s.next)
11839             {
11840                ProcessSpecifier(s, declareStruct, true);
11841             }
11842          }
11843          break;
11844       }
11845       case instDeclaration:
11846       {
11847          ProcessInstantiationType(decl.inst);
11848          break;
11849       }
11850       case structDeclaration:
11851       {
11852          Specifier spec;
11853          Declarator d;
11854          bool declareStruct = false;
11855
11856          if(decl.declarators)
11857          {
11858             for(d = decl.declarators->first; d; d = d.next)
11859             {
11860                Type type = ProcessType(decl.specifiers, d.declarator);
11861                Type subType;
11862                ProcessDeclarator(d, false);
11863                for(subType = type; subType;)
11864                {
11865                   if(subType.kind == classType)
11866                   {
11867                      declareStruct = true;
11868                      break;
11869                   }
11870                   else if(subType.kind == pointerType)
11871                      break;
11872                   else if(subType.kind == arrayType)
11873                      subType = subType.arrayType;
11874                   else
11875                      break;
11876                }
11877                FreeType(type);
11878             }
11879          }
11880          if(decl.specifiers)
11881          {
11882             for(spec = decl.specifiers->first; spec; spec = spec.next)
11883                ProcessSpecifier(spec, declareStruct, warnClasses);
11884          }
11885          break;
11886       }
11887    }
11888 }
11889
11890 static FunctionDefinition curFunction;
11891
11892 static void CreateFireWatcher(Property prop, Expression object, Statement stmt)
11893 {
11894    char propName[1024], propNameM[1024];
11895    char getName[1024], setName[1024];
11896    OldList * args;
11897
11898    DeclareProperty(curExternal, prop, setName, getName);
11899
11900    // eInstance_FireWatchers(object, prop);
11901    strcpy(propName, "__ecereProp_");
11902    FullClassNameCat(propName, prop._class.fullName, false);
11903    strcat(propName, "_");
11904    FullClassNameCat(propName, prop.name, true);
11905
11906    strcpy(propNameM, "__ecerePropM_");
11907    FullClassNameCat(propNameM, prop._class.fullName, false);
11908    strcat(propNameM, "_");
11909    FullClassNameCat(propNameM, prop.name, true);
11910
11911    if(prop.isWatchable)
11912    {
11913       args = MkList();
11914       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11915       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11916       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11917
11918       args = MkList();
11919       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11920       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11921       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11922
11923       DeclareFunctionUtil(curExternal, "eInstance_FireWatchers");
11924    }
11925
11926    {
11927       args = MkList();
11928       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11929       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11930       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11931
11932       args = MkList();
11933       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11934       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11935       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11936
11937       DeclareFunctionUtil(curExternal, "eInstance_FireSelfWatchers");
11938    }
11939
11940    if(curFunction.propSet && !strcmp(curFunction.propSet.string, prop.name) &&
11941       (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
11942       curFunction.propSet.fireWatchersDone = true;
11943 }
11944
11945 static void ProcessStatement(Statement stmt)
11946 {
11947    yylloc = stmt.loc;
11948    /*
11949    lineNum = stmt.pos.line;
11950    column = stmt.pos.col;
11951    */
11952    switch(stmt.type)
11953    {
11954       case labeledStmt:
11955          ProcessStatement(stmt.labeled.stmt);
11956          break;
11957       case caseStmt:
11958          // This expression should be constant...
11959          if(stmt.caseStmt.exp)
11960          {
11961             FreeType(stmt.caseStmt.exp.destType);
11962             stmt.caseStmt.exp.destType = curSwitchType;
11963             if(curSwitchType) curSwitchType.refCount++;
11964             ProcessExpressionType(stmt.caseStmt.exp);
11965             ComputeExpression(stmt.caseStmt.exp);
11966          }
11967          if(stmt.caseStmt.stmt)
11968             ProcessStatement(stmt.caseStmt.stmt);
11969          break;
11970       case compoundStmt:
11971       {
11972          if(stmt.compound.context)
11973          {
11974             Declaration decl;
11975             Statement s;
11976
11977             Statement prevCompound = curCompound;
11978             Context prevContext = curContext;
11979
11980             if(!stmt.compound.isSwitch)
11981                curCompound = stmt;
11982             curContext = stmt.compound.context;
11983
11984             if(stmt.compound.declarations)
11985             {
11986                for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
11987                   ProcessDeclaration(decl, true);
11988             }
11989             if(stmt.compound.statements)
11990             {
11991                for(s = stmt.compound.statements->first; s; s = s.next)
11992                   ProcessStatement(s);
11993             }
11994
11995             curContext = prevContext;
11996             curCompound = prevCompound;
11997          }
11998          break;
11999       }
12000       case expressionStmt:
12001       {
12002          Expression exp;
12003          if(stmt.expressions)
12004          {
12005             for(exp = stmt.expressions->first; exp; exp = exp.next)
12006                ProcessExpressionType(exp);
12007          }
12008          break;
12009       }
12010       case ifStmt:
12011       {
12012          Expression exp;
12013
12014          FreeType(((Expression)stmt.ifStmt.exp->last).destType);
12015          ((Expression)stmt.ifStmt.exp->last).destType = MkClassType("bool");
12016          ((Expression)stmt.ifStmt.exp->last).destType.truth = true;
12017          for(exp = stmt.ifStmt.exp->first; exp; exp = exp.next)
12018          {
12019             ProcessExpressionType(exp);
12020          }
12021          if(stmt.ifStmt.stmt)
12022             ProcessStatement(stmt.ifStmt.stmt);
12023          if(stmt.ifStmt.elseStmt)
12024             ProcessStatement(stmt.ifStmt.elseStmt);
12025          break;
12026       }
12027       case switchStmt:
12028       {
12029          Type oldSwitchType = curSwitchType;
12030          if(stmt.switchStmt.exp)
12031          {
12032             Expression exp;
12033             for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
12034             {
12035                if(!exp.next)
12036                {
12037                   /*
12038                   Type destType
12039                   {
12040                      kind = intType;
12041                      refCount = 1;
12042                   };
12043                   e.exp.destType = destType;
12044                   */
12045
12046                   ProcessExpressionType(exp);
12047                }
12048                if(!exp.next)
12049                   curSwitchType = exp.expType;
12050             }
12051          }
12052          ProcessStatement(stmt.switchStmt.stmt);
12053          curSwitchType = oldSwitchType;
12054          break;
12055       }
12056       case whileStmt:
12057       {
12058          if(stmt.whileStmt.exp)
12059          {
12060             Expression exp;
12061
12062             FreeType(((Expression)stmt.whileStmt.exp->last).destType);
12063             ((Expression)stmt.whileStmt.exp->last).destType = MkClassType("bool");
12064             ((Expression)stmt.whileStmt.exp->last).destType.truth = true;
12065             for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
12066             {
12067                ProcessExpressionType(exp);
12068             }
12069          }
12070          if(stmt.whileStmt.stmt)
12071             ProcessStatement(stmt.whileStmt.stmt);
12072          break;
12073       }
12074       case doWhileStmt:
12075       {
12076          if(stmt.doWhile.exp)
12077          {
12078             Expression exp;
12079
12080             if(stmt.doWhile.exp->last)
12081             {
12082                FreeType(((Expression)stmt.doWhile.exp->last).destType);
12083                ((Expression)stmt.doWhile.exp->last).destType = MkClassType("bool");
12084                ((Expression)stmt.doWhile.exp->last).destType.truth = true;
12085             }
12086             for(exp = stmt.doWhile.exp->first; exp; exp = exp.next)
12087             {
12088                ProcessExpressionType(exp);
12089             }
12090          }
12091          if(stmt.doWhile.stmt)
12092             ProcessStatement(stmt.doWhile.stmt);
12093          break;
12094       }
12095       case forStmt:
12096       {
12097          Expression exp;
12098          if(stmt.forStmt.init)
12099             ProcessStatement(stmt.forStmt.init);
12100
12101          if(stmt.forStmt.check && stmt.forStmt.check.expressions)
12102          {
12103             FreeType(((Expression)stmt.forStmt.check.expressions->last).destType);
12104             ((Expression)stmt.forStmt.check.expressions->last).destType = MkClassType("bool");
12105             ((Expression)stmt.forStmt.check.expressions->last).destType.truth = true;
12106          }
12107
12108          if(stmt.forStmt.check)
12109             ProcessStatement(stmt.forStmt.check);
12110          if(stmt.forStmt.increment)
12111          {
12112             for(exp = stmt.forStmt.increment->first; exp; exp = exp.next)
12113                ProcessExpressionType(exp);
12114          }
12115
12116          if(stmt.forStmt.stmt)
12117             ProcessStatement(stmt.forStmt.stmt);
12118          break;
12119       }
12120       case forEachStmt:
12121       {
12122          Identifier id = stmt.forEachStmt.id;
12123          OldList * exp = stmt.forEachStmt.exp;
12124          OldList * filter = stmt.forEachStmt.filter;
12125          Statement block = stmt.forEachStmt.stmt;
12126          char iteratorType[1024];
12127          Type source;
12128          Expression e;
12129          bool isBuiltin = exp && exp->last &&
12130             (((Expression)exp->last).type == ExpressionType::arrayExp ||
12131               (((Expression)exp->last).type == castExp && ((Expression)exp->last).cast.exp.type == ExpressionType::arrayExp));
12132          Expression arrayExp;
12133          const char * typeString = null;
12134          int builtinCount = 0;
12135
12136          for(e = exp ? exp->first : null; e; e = e.next)
12137          {
12138             if(!e.next)
12139             {
12140                FreeType(e.destType);
12141                e.destType = ProcessTypeString("Container", false);
12142             }
12143             if(!isBuiltin || e.next)
12144                ProcessExpressionType(e);
12145          }
12146
12147          source = (exp && exp->last) ? ((Expression)exp->last).expType : null;
12148          if(isBuiltin || (source && source.kind == classType && source._class && source._class.registered && source._class.registered != containerClass &&
12149             eClass_IsDerived(source._class.registered, containerClass)))
12150          {
12151             Class _class = source ? source._class.registered : null;
12152             Symbol symbol;
12153             Expression expIt = null;
12154             bool isMap = false, isArray = false, isLinkList = false, isList = false, isCustomAVLTree = false; //, isAVLTree = false;
12155             Class arrayClass = eSystem_FindClass(privateModule, "Array");
12156             Class linkListClass = eSystem_FindClass(privateModule, "LinkList");
12157             Class customAVLTreeClass = eSystem_FindClass(privateModule, "CustomAVLTree");
12158
12159             if(inCompiler)
12160             {
12161                stmt.type = compoundStmt;
12162
12163                stmt.compound.context = Context { };
12164                stmt.compound.context.parent = curContext;
12165                curContext = stmt.compound.context;
12166             }
12167
12168             if(source && eClass_IsDerived(source._class.registered, customAVLTreeClass))
12169             {
12170                Class mapClass = eSystem_FindClass(privateModule, "Map");
12171                //Class avlTreeClass = eSystem_FindClass(privateModule, "AVLTree");
12172                isCustomAVLTree = true;
12173                /*if(eClass_IsDerived(source._class.registered, avlTreeClass))
12174                   isAVLTree = true;
12175                else */if(eClass_IsDerived(source._class.registered, mapClass))
12176                   isMap = true;
12177             }
12178             else if(source && eClass_IsDerived(source._class.registered, arrayClass)) isArray = true;
12179             else if(source && eClass_IsDerived(source._class.registered, linkListClass))
12180             {
12181                Class listClass = eSystem_FindClass(privateModule, "List");
12182                isLinkList = true;
12183                isList = eClass_IsDerived(source._class.registered, listClass);
12184             }
12185
12186             if(inCompiler && isArray)
12187             {
12188                Declarator decl;
12189                OldList * specs = MkList();
12190                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
12191                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
12192                stmt.compound.declarations = MkListOne(
12193                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12194                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12195                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalArray")),
12196                      MkInitializerAssignment(MkExpBrackets(exp))))));
12197             }
12198             else if(isBuiltin)
12199             {
12200                Type type = null;
12201                char typeStringBuf[1024];
12202
12203                // TODO: Merge this code?
12204                arrayExp = (((Expression)exp->last).type == ExpressionType::arrayExp) ? (Expression)exp->last : ((Expression)exp->last).cast.exp;
12205                if(((Expression)exp->last).type == castExp)
12206                {
12207                   TypeName typeName = ((Expression)exp->last).cast.typeName;
12208                   if(typeName)
12209                      arrayExp.destType = ProcessType(typeName.qualifiers, typeName.declarator);
12210                }
12211
12212                if(arrayExp.destType && arrayExp.destType.kind == classType && arrayExp.destType._class && arrayExp.destType._class.registered &&
12213                   arrayExp.destType._class.registered != containerClass && eClass_IsDerived(arrayExp.destType._class.registered, containerClass) &&
12214                   arrayExp.destType._class.registered.templateArgs)
12215                {
12216                   Class templateClass = arrayExp.destType._class.registered;
12217                   typeString = templateClass.templateArgs[2].dataTypeString;
12218                }
12219                else if(arrayExp.list)
12220                {
12221                   // Guess type from expressions in the array
12222                   Expression e;
12223                   for(e = arrayExp.list->first; e; e = e.next)
12224                   {
12225                      ProcessExpressionType(e);
12226                      if(e.expType)
12227                      {
12228                         if(!type) { type = e.expType; type.refCount++; }
12229                         else
12230                         {
12231                            // if(!MatchType(e.expType, type, null, null, null, false, false, false))
12232                            if(!MatchTypeExpression(e, type, null, false, true))
12233                            {
12234                               FreeType(type);
12235                               type = e.expType;
12236                               e.expType = null;
12237
12238                               e = arrayExp.list->first;
12239                               ProcessExpressionType(e);
12240                               if(e.expType)
12241                               {
12242                                  //if(!MatchTypes(e.expType, type, null, null, null, false, false, false, false))
12243                                  if(!MatchTypeExpression(e, type, null, false, true))
12244                                  {
12245                                     FreeType(e.expType);
12246                                     e.expType = null;
12247                                     FreeType(type);
12248                                     type = null;
12249                                     break;
12250                                  }
12251                               }
12252                            }
12253                         }
12254                         if(e.expType)
12255                         {
12256                            FreeType(e.expType);
12257                            e.expType = null;
12258                         }
12259                      }
12260                   }
12261                   if(type)
12262                   {
12263                      typeStringBuf[0] = '\0';
12264                      PrintType(type, typeStringBuf, false, true);
12265                      typeString = typeStringBuf;
12266                      FreeType(type);
12267                   }
12268                }
12269                if(typeString)
12270                {
12271                   if(inCompiler)
12272                   {
12273                      OldList * initializers = MkList();
12274                      Declarator decl;
12275                      OldList * specs = MkList();
12276                      if(arrayExp.list)
12277                      {
12278                         Expression e;
12279
12280                         builtinCount = arrayExp.list->count;
12281                         type = ProcessTypeString(typeString, false);
12282                         while((e = arrayExp.list->first))
12283                         {
12284                            arrayExp.list->Remove(e);
12285                            e.destType = type;
12286                            type.refCount++;
12287                            ProcessExpressionType(e);
12288                            if(inCompiler)
12289                               ListAdd(initializers, MkInitializerAssignment(e));
12290                         }
12291                         FreeType(type);
12292                         delete arrayExp.list;
12293                      }
12294                      decl = SpecDeclFromString(typeString, specs, MkDeclaratorIdentifier(id));
12295
12296                      stmt.compound.declarations = MkListOne(MkDeclaration(CopyList(specs, CopySpecifier),
12297                         MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), /*CopyDeclarator(*/decl/*)*/), null))));
12298
12299                      ListAdd(stmt.compound.declarations, MkDeclaration(specs, MkListOne(MkInitDeclarator(
12300                         PlugDeclarator(
12301                            /*CopyDeclarator(*/decl/*)*/, MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__internalArray")), null)
12302                            ), MkInitializerList(initializers)))));
12303                      FreeList(exp, FreeExpression);
12304                   }
12305                   else if(arrayExp.list)
12306                   {
12307                      Expression e;
12308                      type = ProcessTypeString(typeString, false);
12309                      for(e = arrayExp.list->first; e; e = e.next)
12310                      {
12311                         e.destType = type;
12312                         type.refCount++;
12313                         ProcessExpressionType(e);
12314                      }
12315                      FreeType(type);
12316                   }
12317                }
12318                else
12319                {
12320                   arrayExp.expType = ProcessTypeString("Container", false);
12321                   Compiler_Error($"Couldn't determine type of array elements\n");
12322                }
12323
12324                /*
12325                Declarator decl;
12326                OldList * specs = MkList();
12327
12328                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
12329                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
12330                stmt.compound.declarations = MkListOne(
12331                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12332                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName("BuiltInContainer")),
12333                   MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(MkIdentifier("__internalArray"))),
12334                      MkInitializerAssignment(MkExpBrackets(exp))))));
12335                */
12336             }
12337             else if(inCompiler && isLinkList && !isList)
12338             {
12339                Declarator decl;
12340                OldList * specs = MkList();
12341                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
12342                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12343                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12344                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalLinkList")),
12345                      MkInitializerAssignment(MkExpBrackets(exp))))));
12346             }
12347             /*else if(isCustomAVLTree)
12348             {
12349                Declarator decl;
12350                OldList * specs = MkList();
12351                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
12352                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12353                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12354                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalTree")),
12355                      MkInitializerAssignment(MkExpBrackets(exp))))));
12356             }*/
12357             else if(inCompiler && _class.templateArgs)
12358             {
12359                if(isMap)
12360                   sprintf(iteratorType, "MapIterator<%s, %s >", _class.templateArgs[5].dataTypeString, _class.templateArgs[6].dataTypeString);
12361                else
12362                   sprintf(iteratorType, "Iterator<%s, %s >", _class.templateArgs[2].dataTypeString, _class.templateArgs[1].dataTypeString);
12363
12364                stmt.compound.declarations = MkListOne(
12365                   MkDeclarationInst(MkInstantiationNamed(MkListOne(MkSpecifierName(iteratorType)),
12366                   MkExpIdentifier(id), MkListOne(MkMembersInitList(MkListOne(MkMemberInit(isMap ? MkListOne(MkIdentifier("map")) : null,
12367                   MkInitializerAssignment(MkExpBrackets(exp)))))))));
12368             }
12369             if(inCompiler)
12370             {
12371                symbol = FindSymbol(id.string, curContext, curContext, false, false);
12372
12373                if(block)
12374                {
12375                   // Reparent sub-contexts in this statement
12376                   switch(block.type)
12377                   {
12378                      case compoundStmt:
12379                         if(block.compound.context)
12380                            block.compound.context.parent = stmt.compound.context;
12381                         break;
12382                      case ifStmt:
12383                         if(block.ifStmt.stmt && block.ifStmt.stmt.type == compoundStmt && block.ifStmt.stmt.compound.context)
12384                            block.ifStmt.stmt.compound.context.parent = stmt.compound.context;
12385                         if(block.ifStmt.elseStmt && block.ifStmt.elseStmt.type == compoundStmt && block.ifStmt.elseStmt.compound.context)
12386                            block.ifStmt.elseStmt.compound.context.parent = stmt.compound.context;
12387                         break;
12388                      case switchStmt:
12389                         if(block.switchStmt.stmt && block.switchStmt.stmt.type == compoundStmt && block.switchStmt.stmt.compound.context)
12390                            block.switchStmt.stmt.compound.context.parent = stmt.compound.context;
12391                         break;
12392                      case whileStmt:
12393                         if(block.whileStmt.stmt && block.whileStmt.stmt.type == compoundStmt && block.whileStmt.stmt.compound.context)
12394                            block.whileStmt.stmt.compound.context.parent = stmt.compound.context;
12395                         break;
12396                      case doWhileStmt:
12397                         if(block.doWhile.stmt && block.doWhile.stmt.type == compoundStmt && block.doWhile.stmt.compound.context)
12398                            block.doWhile.stmt.compound.context.parent = stmt.compound.context;
12399                         break;
12400                      case forStmt:
12401                         if(block.forStmt.stmt && block.forStmt.stmt.type == compoundStmt && block.forStmt.stmt.compound.context)
12402                            block.forStmt.stmt.compound.context.parent = stmt.compound.context;
12403                         break;
12404                      case forEachStmt:
12405                         if(block.forEachStmt.stmt && block.forEachStmt.stmt.type == compoundStmt && block.forEachStmt.stmt.compound.context)
12406                            block.forEachStmt.stmt.compound.context.parent = stmt.compound.context;
12407                         break;
12408                      /* Only handle those with compound blocks for now... (Potential limitation on compound statements within expressions)
12409                      case labeledStmt:
12410                      case caseStmt
12411                      case expressionStmt:
12412                      case gotoStmt:
12413                      case continueStmt:
12414                      case breakStmt
12415                      case returnStmt:
12416                      case asmStmt:
12417                      case badDeclarationStmt:
12418                      case fireWatchersStmt:
12419                      case stopWatchingStmt:
12420                      case watchStmt:
12421                      */
12422                   }
12423                }
12424
12425                if(filter)
12426                {
12427                   block = MkIfStmt(filter, block, null);
12428                }
12429                if(isArray)
12430                {
12431                   stmt.compound.statements = MkListOne(MkForStmt(
12432                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array"))))),
12433                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12434                         MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array")), '+', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
12435                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12436                      block));
12437                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12438                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12439                  ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12440                }
12441                else if(isBuiltin)
12442                {
12443                   char count[128];
12444                   //OldList * specs = MkList();
12445                   // Declarator decl = SpecDeclFromString(typeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
12446
12447                   sprintf(count, "%d", builtinCount);
12448
12449                   stmt.compound.statements = MkListOne(MkForStmt(
12450                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpIdentifier(MkIdentifier("__internalArray"))))),
12451                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12452                         MkExpOp(MkExpIdentifier(MkIdentifier("__internalArray")), '+', MkExpConstant(count))))),
12453                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12454                      block));
12455
12456                   /*
12457                   Declarator decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
12458                   stmt.compound.statements = MkListOne(MkForStmt(
12459                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))))),
12460                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12461                         MkExpOp(MkExpCast(MkTypeName(specs, decl), MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))), '+', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
12462                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12463                      block));
12464                  */
12465                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12466                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12467                  ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12468                }
12469                else if(isLinkList && !isList)
12470                {
12471                   Class typeClass = eSystem_FindClass(_class.module, _class.templateArgs[3].dataTypeString);
12472                   Class listItemClass = eSystem_FindClass(_class.module, "ListItem");
12473                   if(typeClass && eClass_IsDerived(typeClass, listItemClass) && _class.templateArgs[5].dataTypeString &&
12474                      !strcmp(_class.templateArgs[5].dataTypeString, "LT::link"))
12475                   {
12476                      stmt.compound.statements = MkListOne(MkForStmt(
12477                         MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
12478                         MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12479                         MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
12480                         block));
12481                   }
12482                   else
12483                   {
12484                      OldList * specs = MkList();
12485                      Declarator decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, null);
12486                      stmt.compound.statements = MkListOne(MkForStmt(
12487                         MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
12488                         MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12489                         MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpCast(MkTypeName(specs, decl), MkExpCall(
12490                            MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("GetNext")),
12491                               MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName("IteratorPointer")), null), MkExpIdentifier(CopyIdentifier(id)))))))),
12492                         block));
12493                   }
12494                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12495                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12496                   ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12497                }
12498                /*else if(isCustomAVLTree)
12499                {
12500                   stmt.compound.statements = MkListOne(MkForStmt(
12501                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpMember(MkExpIdentifier(
12502                         MkIdentifier("__internalTree")), MkIdentifier("root")), MkIdentifier("minimum"))))),
12503                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12504                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
12505                      block));
12506
12507                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12508                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12509                   ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12510                }*/
12511                else
12512                {
12513                   stmt.compound.statements = MkListOne(MkWhileStmt(MkListOne(MkExpCall(MkExpMember(expIt = MkExpIdentifier(CopyIdentifier(id)),
12514                      MkIdentifier("Next")), null)), block));
12515                }
12516                ProcessExpressionType(expIt);
12517                if(stmt.compound.declarations->first)
12518                   ProcessDeclaration(stmt.compound.declarations->first, true);
12519
12520                if(symbol)
12521                   symbol.isIterator = isMap ? 2 : ((isArray || isBuiltin) ? 3 : (isLinkList ? (isList ? 5 : 4) : (isCustomAVLTree ? 6 : 1)));
12522
12523                ProcessStatement(stmt);
12524             }
12525             else
12526                ProcessStatement(stmt.forEachStmt.stmt);
12527             if(inCompiler)
12528                curContext = stmt.compound.context.parent;
12529             break;
12530          }
12531          else
12532          {
12533             Compiler_Error($"Expression is not a container\n");
12534          }
12535          break;
12536       }
12537       case gotoStmt:
12538          break;
12539       case continueStmt:
12540          break;
12541       case breakStmt:
12542          break;
12543       case returnStmt:
12544       {
12545          Expression exp;
12546          if(stmt.expressions)
12547          {
12548             for(exp = stmt.expressions->first; exp; exp = exp.next)
12549             {
12550                if(!exp.next)
12551                {
12552                   if(curFunction && !curFunction.type)
12553                      curFunction.type = ProcessType(
12554                         curFunction.specifiers, curFunction.declarator);
12555                   FreeType(exp.destType);
12556                   // TODO: current property if not compiling
12557                   exp.destType = (curFunction && curFunction.type && curFunction.type.kind == functionType) ? curFunction.type.returnType : null;
12558                   if(exp.destType) exp.destType.refCount++;
12559                }
12560                ProcessExpressionType(exp);
12561             }
12562          }
12563          break;
12564       }
12565       case badDeclarationStmt:
12566       {
12567          ProcessDeclaration(stmt.decl, true);
12568          break;
12569       }
12570       case asmStmt:
12571       {
12572          AsmField field;
12573          if(stmt.asmStmt.inputFields)
12574          {
12575             for(field = stmt.asmStmt.inputFields->first; field; field = field.next)
12576                if(field.expression)
12577                   ProcessExpressionType(field.expression);
12578          }
12579          if(stmt.asmStmt.outputFields)
12580          {
12581             for(field = stmt.asmStmt.outputFields->first; field; field = field.next)
12582                if(field.expression)
12583                   ProcessExpressionType(field.expression);
12584          }
12585          if(stmt.asmStmt.clobberedFields)
12586          {
12587             for(field = stmt.asmStmt.clobberedFields->first; field; field = field.next)
12588             {
12589                if(field.expression)
12590                   ProcessExpressionType(field.expression);
12591             }
12592          }
12593          break;
12594       }
12595       case watchStmt:
12596       {
12597          PropertyWatch propWatch;
12598          OldList * watches = stmt._watch.watches;
12599          Expression object = stmt._watch.object;
12600          Expression watcher = stmt._watch.watcher;
12601          if(watcher)
12602             ProcessExpressionType(watcher);
12603          if(object)
12604             ProcessExpressionType(object);
12605
12606          if(inCompiler)
12607          {
12608             if(watcher || thisClass)
12609             {
12610                External external = curExternal;
12611                Context context = curContext;
12612
12613                stmt.type = expressionStmt;
12614                stmt.expressions = MkList();
12615
12616                for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12617                {
12618                   ClassFunction func;
12619                   char watcherName[1024];
12620                   Class watcherClass = watcher ?
12621                      ((watcher.expType && watcher.expType.kind == classType && watcher.expType._class) ? watcher.expType._class.registered : null) : thisClass;
12622                   External createdExternal;
12623
12624                   sprintf(watcherName,"__ecerePropertyWatcher_%d", propWatcherID++);
12625                   if(propWatch.deleteWatch)
12626                      strcat(watcherName, "_delete");
12627                   else
12628                   {
12629                      Identifier propID;
12630                      for(propID = propWatch.properties->first; propID; propID = propID.next)
12631                      {
12632                         strcat(watcherName, "_");
12633                         strcat(watcherName, propID.string);
12634                      }
12635                   }
12636
12637                   if(object && object.expType && object.expType.kind == classType && object.expType._class && object.expType._class.registered)
12638                   {
12639                      func = MkClassFunction(MkListOne(MkSpecifier(VOID)), null, MkDeclaratorFunction(MkDeclaratorIdentifier(MkIdentifier(watcherName)),
12640                         MkListOne(MkTypeName(MkListOne(MkSpecifierName(object.expType._class.string)), MkDeclaratorIdentifier(MkIdentifier("value"))))), null);
12641                      ProcessClassFunctionBody(func, propWatch.compound);
12642                      propWatch.compound = null;
12643
12644                      createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal, true);
12645
12646                      FreeClassFunction(func);
12647
12648                      curExternal = createdExternal;
12649                      ProcessFunction(createdExternal.function);
12650
12651                      if(propWatch.deleteWatch)
12652                      {
12653                         OldList * args = MkList();
12654                         ListAdd(args, CopyExpression(object));
12655                         ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12656                         ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
12657                         ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_WatchDestruction")), args));
12658                      }
12659                      else
12660                      {
12661                         Class _class = object.expType._class.registered;
12662                         Identifier propID;
12663
12664                         for(propID = propWatch.properties->first; propID; propID = propID.next)
12665                         {
12666                            char propName[1024];
12667                            Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12668                            if(prop)
12669                            {
12670                               char getName[1024], setName[1024];
12671                               OldList * args = MkList();
12672
12673                               DeclareProperty(createdExternal, prop, setName, getName);
12674
12675                               // eInstance_Watch(stmt.watch.object, prop, stmt.watch.watcher, callback);
12676                               strcpy(propName, "__ecereProp_");
12677                               FullClassNameCat(propName, prop._class.fullName, false);
12678                               strcat(propName, "_");
12679                               FullClassNameCat(propName, prop.name, true);
12680
12681                               ListAdd(args, CopyExpression(object));
12682                               ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12683                               ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12684                               ListAdd(args, MkExpCast(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpIdentifier(MkIdentifier(watcherName))));
12685
12686                               ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_Watch")), args));
12687
12688                               external.CreateUniqueEdge(createdExternal, true);
12689                            }
12690                            else
12691                               Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12692                         }
12693                      }
12694                   }
12695                   else
12696                      Compiler_Error($"Invalid watched object\n");
12697                }
12698
12699                curExternal = external;
12700                curContext = context;
12701
12702                if(watcher)
12703                   FreeExpression(watcher);
12704                if(object)
12705                   FreeExpression(object);
12706                FreeList(watches, FreePropertyWatch);
12707             }
12708             else
12709                Compiler_Error($"No observer specified and not inside a class\n");
12710          }
12711          else
12712          {
12713             for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12714             {
12715                ProcessStatement(propWatch.compound);
12716             }
12717
12718          }
12719          break;
12720       }
12721       case fireWatchersStmt:
12722       {
12723          OldList * watches = stmt._watch.watches;
12724          Expression object = stmt._watch.object;
12725          Class _class;
12726          // DEBUGGER BUG: Why doesn't watches evaluate to null??
12727          // printf("%X\n", watches);
12728          // printf("%X\n", stmt._watch.watches);
12729          if(object)
12730             ProcessExpressionType(object);
12731
12732          if(inCompiler)
12733          {
12734             _class = object ?
12735                   ((object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null) : thisClass;
12736
12737             if(_class)
12738             {
12739                Identifier propID;
12740
12741                stmt.type = expressionStmt;
12742                stmt.expressions = MkList();
12743
12744                // Check if we're inside a property set
12745                if(!watches && curFunction.propSet && (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
12746                {
12747                   watches = MkListOne(MkIdentifier(curFunction.propSet.string));
12748                }
12749                else if(!watches)
12750                {
12751                   //Compiler_Error($"No property specified and not inside a property set\n");
12752                }
12753                if(watches)
12754                {
12755                   for(propID = watches->first; propID; propID = propID.next)
12756                   {
12757                      Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12758                      if(prop)
12759                      {
12760                         CreateFireWatcher(prop, object, stmt);
12761                      }
12762                      else
12763                         Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12764                   }
12765                }
12766                else
12767                {
12768                   // Fire all properties!
12769                   Property prop;
12770                   Class base;
12771                   for(base = _class; base; base = base.base)
12772                   {
12773                      for(prop = base.membersAndProperties.first; prop; prop = prop.next)
12774                      {
12775                         if(prop.isProperty && prop.isWatchable)
12776                         {
12777                            CreateFireWatcher(prop, object, stmt);
12778                         }
12779                      }
12780                   }
12781                }
12782
12783                if(object)
12784                   FreeExpression(object);
12785                FreeList(watches, FreeIdentifier);
12786             }
12787             else
12788                Compiler_Error($"Invalid object specified and not inside a class\n");
12789          }
12790          break;
12791       }
12792       case stopWatchingStmt:
12793       {
12794          OldList * watches = stmt._watch.watches;
12795          Expression object = stmt._watch.object;
12796          Expression watcher = stmt._watch.watcher;
12797          Class _class;
12798          if(object)
12799             ProcessExpressionType(object);
12800          if(watcher)
12801             ProcessExpressionType(watcher);
12802          if(inCompiler)
12803          {
12804             _class = (object && object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null;
12805
12806             if(watcher || thisClass)
12807             {
12808                if(_class)
12809                {
12810                   Identifier propID;
12811
12812                   stmt.type = expressionStmt;
12813                   stmt.expressions = MkList();
12814
12815                   if(!watches)
12816                   {
12817                      OldList * args;
12818                      // eInstance_StopWatching(object, null, watcher);
12819                      args = MkList();
12820                      ListAdd(args, CopyExpression(object));
12821                      ListAdd(args, MkExpConstant("0"));
12822                      ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12823                      ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12824                   }
12825                   else
12826                   {
12827                      for(propID = watches->first; propID; propID = propID.next)
12828                      {
12829                         char propName[1024];
12830                         Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12831                         if(prop)
12832                         {
12833                            char getName[1024], setName[1024];
12834                            OldList * args = MkList();
12835
12836                            DeclareProperty(curExternal, prop, setName, getName);
12837
12838                            // eInstance_StopWatching(object, prop, watcher);
12839                            strcpy(propName, "__ecereProp_");
12840                            FullClassNameCat(propName, prop._class.fullName, false);
12841                            strcat(propName, "_");
12842                            FullClassNameCat(propName, prop.name, true);
12843
12844                            ListAdd(args, CopyExpression(object));
12845                            ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12846                            ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12847                            ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12848                         }
12849                         else
12850                            Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12851                      }
12852                   }
12853
12854                   if(object)
12855                      FreeExpression(object);
12856                   if(watcher)
12857                      FreeExpression(watcher);
12858                   FreeList(watches, FreeIdentifier);
12859                }
12860                else
12861                   Compiler_Error($"Invalid object specified and not inside a class\n");
12862             }
12863             else
12864                Compiler_Error($"No observer specified and not inside a class\n");
12865          }
12866          break;
12867       }
12868    }
12869 }
12870
12871 static void ProcessFunction(FunctionDefinition function)
12872 {
12873    Identifier id = GetDeclId(function.declarator);
12874    Symbol symbol = function.declarator ? function.declarator.symbol : null;
12875    Type type = symbol ? symbol.type : null;
12876    Class oldThisClass = thisClass;
12877    Context oldTopContext = topContext;
12878
12879    yylloc = function.loc;
12880    // Process thisClass
12881
12882    if(type && type.thisClass)
12883    {
12884       Symbol classSym = type.thisClass;
12885       Class _class = type.thisClass.registered;
12886       char className[1024];
12887       char structName[1024];
12888       Declarator funcDecl;
12889       Symbol thisSymbol;
12890
12891       bool typedObject = false;
12892
12893       if(_class && !_class.base)
12894       {
12895          _class = currentClass;
12896          if(_class && !_class.symbol)
12897             _class.symbol = FindClass(_class.fullName);
12898          classSym = _class ? _class.symbol : null;
12899          typedObject = true;
12900       }
12901
12902       thisClass = _class;
12903
12904       if(inCompiler && _class)
12905       {
12906          if(type.kind == functionType)
12907          {
12908             if(symbol.type.params.count == 1 && ((Type)symbol.type.params.first).kind == voidType)
12909             {
12910                //TypeName param = symbol.type.params.first;
12911                Type param = symbol.type.params.first;
12912                symbol.type.params.Remove(param);
12913                //FreeTypeName(param);
12914                FreeType(param);
12915             }
12916             if(type.classObjectType != classPointer)
12917             {
12918                symbol.type.params.Insert(null, MkClassType(_class.fullName));
12919                symbol.type.staticMethod = true;
12920                symbol.type.thisClass = null;
12921
12922                // HIGH DANGER: VERIFYING THIS...
12923                symbol.type.extraParam = false;
12924             }
12925          }
12926
12927          strcpy(className, "__ecereClass_");
12928          FullClassNameCat(className, _class.fullName, true);
12929
12930          structName[0] = 0;
12931          FullClassNameCat(structName, _class.fullName, false);
12932
12933          // [class] this
12934          funcDecl = GetFuncDecl(function.declarator);
12935          if(funcDecl)
12936          {
12937             if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12938             {
12939                TypeName param = funcDecl.function.parameters->first;
12940                if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12941                {
12942                   funcDecl.function.parameters->Remove(param);
12943                   FreeTypeName(param);
12944                }
12945             }
12946
12947             if(!function.propertyNoThis)
12948             {
12949                TypeName thisParam = null;
12950
12951                if(type.classObjectType != classPointer)
12952                {
12953                   thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12954                   if(!funcDecl.function.parameters)
12955                      funcDecl.function.parameters = MkList();
12956                   funcDecl.function.parameters->Insert(null, thisParam);
12957                }
12958
12959                if(typedObject)
12960                {
12961                   if(type.classObjectType != classPointer)
12962                   {
12963                      if(type.byReference || _class.type == unitClass || _class.type == systemClass || _class.type == enumClass || _class.type == bitClass)
12964                         thisParam.declarator = MkDeclaratorPointer(MkPointer(null,null), thisParam.declarator);
12965                   }
12966
12967                   thisParam = TypeName
12968                   {
12969                      declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
12970                      qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
12971                   };
12972                   DeclareStruct(curExternal, "ecere::com::Class", false, true);
12973                   funcDecl.function.parameters->Insert(null, thisParam);
12974                }
12975             }
12976          }
12977
12978          if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
12979          {
12980             InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
12981             funcDecl = GetFuncDecl(initDecl.declarator);
12982             if(funcDecl)
12983             {
12984                if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12985                {
12986                   TypeName param = funcDecl.function.parameters->first;
12987                   if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12988                   {
12989                      funcDecl.function.parameters->Remove(param);
12990                      FreeTypeName(param);
12991                   }
12992                }
12993
12994                if(type.classObjectType != classPointer)
12995                {
12996                   if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
12997                   {
12998                      TypeName thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12999
13000                      if(!funcDecl.function.parameters)
13001                         funcDecl.function.parameters = MkList();
13002                      funcDecl.function.parameters->Insert(null, thisParam);
13003                   }
13004                }
13005             }
13006          }
13007       }
13008
13009       // Add this to the context
13010       if(function.body)
13011       {
13012          if(type.classObjectType != classPointer)
13013          {
13014             thisSymbol = Symbol
13015             {
13016                string = CopyString("this");
13017                type = classSym ? MkClassType(classSym.string) : null;
13018             };
13019             function.body.compound.context.symbols.Add((BTNode)thisSymbol);
13020
13021             if(typedObject && thisSymbol.type)
13022             {
13023                thisSymbol.type.classObjectType = ClassObjectType::typedObject;
13024                thisSymbol.type.byReference = type.byReference;
13025                thisSymbol.type.typedByReference = type.byReference;
13026             }
13027          }
13028       }
13029
13030       // Pointer to class data
13031       if(inCompiler && _class && _class.type == normalClass && type.classObjectType != classPointer)
13032       {
13033          DataMember member = null;
13034          {
13035             Class base;
13036             for(base = _class; base && base.type != systemClass; base = base.next)
13037             {
13038                for(member = base.membersAndProperties.first; member; member = member.next)
13039                   if(!member.isProperty)
13040                      break;
13041                if(member)
13042                   break;
13043             }
13044          }
13045          for(member = _class.membersAndProperties.first; member; member = member.next)
13046             if(!member.isProperty)
13047                break;
13048          if(member)
13049          {
13050             char pointerName[1024];
13051
13052             Declaration decl;
13053             Initializer initializer;
13054             Expression exp, bytePtr;
13055
13056             strcpy(pointerName, "__ecerePointer_");
13057             FullClassNameCat(pointerName, _class.fullName, false);
13058             {
13059                char className[1024];
13060                strcpy(className, "__ecereClass_");
13061                FullClassNameCat(className, classSym.string, true);
13062
13063                DeclareClass(curExternal, classSym, className);
13064             }
13065
13066             // ((byte *) this)
13067             bytePtr = QBrackets(MkExpCast(QMkType("char", QMkPtrDecl(null)), QMkExpId("this")));
13068
13069             if(_class.fixed)
13070             {
13071                Expression e;
13072                if(_class.offset && _class.offset == _class.base.structSize)
13073                {
13074                   e = MkExpClassSize(MkSpecifierName(_class.base.fullName));
13075                   ProcessExpressionType(e);
13076                }
13077                else
13078                {
13079                   char string[256];
13080                   sprintf(string, "%d", _class.offset);  // Need Bootstrap Fix
13081                   e = MkExpConstant(string);
13082                }
13083                exp = QBrackets(MkExpOp(bytePtr, '+', e));
13084             }
13085             else
13086             {
13087                // ([bytePtr] + [className]->offset)
13088                exp = QBrackets(MkExpOp(bytePtr, '+',
13089                   MkExpPointer(QMkExpId(className), MkIdentifier("offset"))));
13090             }
13091
13092             // (this ? [exp] : 0)
13093             exp = QBrackets(QMkExpCond(QMkExpId("this"), exp, MkExpConstant("0")));
13094             exp.expType = Type
13095             {
13096                refCount = 1;
13097                kind = pointerType;
13098                type = Type { refCount = 1, kind = voidType };
13099             };
13100
13101             if(function.body)
13102             {
13103                yylloc = function.body.loc;
13104                // ([structName] *) [exp]
13105                // initializer = MkInitializerAssignment(MkExpCast(QMkType(structName, QMkPtrDecl(null)), exp));
13106                initializer = MkInitializerAssignment(
13107                   MkExpCast(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)), exp));
13108
13109                // [structName] * [pointerName] = [initializer];
13110                // decl = QMkDeclaration(structName, MkInitDeclarator(QMkPtrDecl(pointerName), initializer));
13111
13112                {
13113                   Context prevContext = curContext;
13114                   OldList * list;
13115                   curContext = function.body.compound.context;
13116
13117                   decl = MkDeclaration((list = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null))),
13118                      MkListOne(MkInitDeclarator(QMkPtrDecl(pointerName), initializer)));
13119                   list->Insert(null, MkSpecifierExtended(MkExtDeclAttrib(MkAttrib(ATTRIB, MkListOne(MkAttribute(CopyString("unused"), null))))));
13120
13121                   curContext = prevContext;
13122                }
13123
13124                // WHY?
13125                decl.symbol = null;
13126
13127                if(!function.body.compound.declarations)
13128                   function.body.compound.declarations = MkList();
13129                function.body.compound.declarations->Insert(null, decl);
13130             }
13131          }
13132       }
13133
13134
13135       // Loop through the function and replace undeclared identifiers
13136       // which are a member of the class (methods, properties or data)
13137       // by "this.[member]"
13138    }
13139    else
13140       thisClass = null;
13141
13142    if(id)
13143    {
13144       FreeSpecifier(id._class);
13145       id._class = null;
13146
13147       if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
13148       {
13149          InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
13150          id = GetDeclId(initDecl.declarator);
13151
13152          FreeSpecifier(id._class);
13153          id._class = null;
13154       }
13155    }
13156    if(function.body)
13157       topContext = function.body.compound.context;
13158    {
13159       FunctionDefinition oldFunction = curFunction;
13160       curFunction = function;
13161       if(function.body)
13162          ProcessStatement(function.body);
13163
13164       // If this is a property set and no firewatchers has been done yet, add one here
13165       if(inCompiler && function.propSet && !function.propSet.fireWatchersDone)
13166       {
13167          Statement prevCompound = curCompound;
13168          Context prevContext = curContext;
13169
13170          Statement fireWatchers = MkFireWatchersStmt(null, null);
13171          if(!function.body.compound.statements) function.body.compound.statements = MkList();
13172          ListAdd(function.body.compound.statements, fireWatchers);
13173
13174          curCompound = function.body;
13175          curContext = function.body.compound.context;
13176
13177          ProcessStatement(fireWatchers);
13178
13179          curContext = prevContext;
13180          curCompound = prevCompound;
13181
13182       }
13183
13184       curFunction = oldFunction;
13185    }
13186
13187    if(function.declarator)
13188    {
13189       ProcessDeclarator(function.declarator, true);
13190    }
13191
13192    topContext = oldTopContext;
13193    thisClass = oldThisClass;
13194 }
13195
13196 /////////// INSTANTIATIONS / DATA TYPES PASS /////////////////////////////////////////////
13197 static void ProcessClass(OldList definitions, Symbol symbol)
13198 {
13199    ClassDef def;
13200    External external = curExternal;
13201    Class regClass = symbol ? symbol.registered : null;
13202
13203    // Process all functions
13204    for(def = definitions.first; def; def = def.next)
13205    {
13206       if(def.type == functionClassDef)
13207       {
13208          if(def.function.declarator)
13209             curExternal = def.function.declarator.symbol.pointerExternal;
13210          else
13211             curExternal = external;
13212
13213          ProcessFunction((FunctionDefinition)def.function);
13214       }
13215       else if(def.type == declarationClassDef)
13216       {
13217          if(def.decl.type == instDeclaration)
13218          {
13219             thisClass = regClass;
13220             ProcessInstantiationType(def.decl.inst);
13221             thisClass = null;
13222          }
13223          // Testing this
13224          else
13225          {
13226             Class backThisClass = thisClass;
13227             if(regClass) thisClass = regClass;
13228             ProcessDeclaration(def.decl, symbol ? true : false);
13229             thisClass = backThisClass;
13230          }
13231       }
13232       else if(def.type == defaultPropertiesClassDef && def.defProperties)
13233       {
13234          MemberInit defProperty;
13235
13236          // Add this to the context
13237          Symbol thisSymbol = Symbol
13238          {
13239             string = CopyString("this");
13240             type = regClass ? MkClassType(regClass.fullName) : null;
13241          };
13242          globalContext.symbols.Add((BTNode)thisSymbol);
13243
13244          for(defProperty = def.defProperties->first; defProperty; defProperty = defProperty.next)
13245          {
13246             thisClass = regClass;
13247             ProcessMemberInitData(defProperty, regClass, null, null, null, null);
13248             thisClass = null;
13249          }
13250
13251          globalContext.symbols.Remove((BTNode)thisSymbol);
13252          FreeSymbol(thisSymbol);
13253       }
13254       else if(def.type == propertyClassDef && def.propertyDef)
13255       {
13256          PropertyDef prop = def.propertyDef;
13257
13258          // Add this to the context
13259          thisClass = regClass;
13260          if(prop.setStmt)
13261          {
13262             if(regClass)
13263             {
13264                Symbol thisSymbol
13265                {
13266                   string = CopyString("this");
13267                   type = MkClassType(regClass.fullName);
13268                };
13269                prop.setStmt.compound.context.symbols.Add((BTNode)thisSymbol);
13270             }
13271
13272             curExternal = prop.symbol ? prop.symbol.externalSet : null;
13273             ProcessStatement(prop.setStmt);
13274          }
13275          if(prop.getStmt)
13276          {
13277             if(regClass)
13278             {
13279                Symbol thisSymbol
13280                {
13281                   string = CopyString("this");
13282                   type = MkClassType(regClass.fullName);
13283                };
13284                prop.getStmt.compound.context.symbols.Add((BTNode)thisSymbol);
13285             }
13286
13287             curExternal = prop.symbol ? prop.symbol.externalGet : null;
13288             ProcessStatement(prop.getStmt);
13289          }
13290          if(prop.issetStmt)
13291          {
13292             if(regClass)
13293             {
13294                Symbol thisSymbol
13295                {
13296                   string = CopyString("this");
13297                   type = MkClassType(regClass.fullName);
13298                };
13299                prop.issetStmt.compound.context.symbols.Add((BTNode)thisSymbol);
13300             }
13301
13302             curExternal = prop.symbol ? prop.symbol.externalIsSet : null;
13303             ProcessStatement(prop.issetStmt);
13304          }
13305
13306          thisClass = null;
13307       }
13308       else if(def.type == propertyWatchClassDef && def.propertyWatch)
13309       {
13310          PropertyWatch propertyWatch = def.propertyWatch;
13311
13312          thisClass = regClass;
13313          if(propertyWatch.compound)
13314          {
13315             Symbol thisSymbol
13316             {
13317                string = CopyString("this");
13318                type = regClass ? MkClassType(regClass.fullName) : null;
13319             };
13320
13321             propertyWatch.compound.compound.context.symbols.Add((BTNode)thisSymbol);
13322
13323             curExternal = null;
13324             ProcessStatement(propertyWatch.compound);
13325          }
13326          thisClass = null;
13327       }
13328    }
13329 }
13330
13331 void DeclareFunctionUtil(External neededBy, const String s)
13332 {
13333    GlobalFunction function = eSystem_FindFunction(privateModule, s);
13334    if(function)
13335    {
13336       char name[1024];
13337       name[0] = 0;
13338       if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
13339          strcpy(name, "__ecereFunction_");
13340       FullClassNameCat(name, s, false); // Why is this using FullClassNameCat ?
13341       DeclareFunction(neededBy, function, name);
13342    }
13343    else if(neededBy)
13344       FindSymbol(s, globalContext, globalContext, false, false);
13345 }
13346
13347 bool reachedPass15;
13348
13349 void ComputeDataTypes()
13350 {
13351    External external;
13352
13353    currentClass = null;
13354
13355    containerClass = eSystem_FindClass(GetPrivateModule(), "Container");
13356
13357    DeclareStruct(null, "ecere::com::Class", false, true);
13358    DeclareStruct(null, "ecere::com::Instance", false, true);
13359    DeclareStruct(null, "ecere::com::Property", false, true);
13360    DeclareStruct(null, "ecere::com::DataMember", false, true);
13361    DeclareStruct(null, "ecere::com::Method", false, true);
13362    DeclareStruct(null, "ecere::com::SerialBuffer", false, true);
13363    DeclareStruct(null, "ecere::com::ClassTemplateArgument", false, true);
13364
13365    DeclareFunctionUtil(null, "eSystem_New");
13366    DeclareFunctionUtil(null, "eSystem_New0");
13367    DeclareFunctionUtil(null, "eSystem_Renew");
13368    DeclareFunctionUtil(null, "eSystem_Renew0");
13369    DeclareFunctionUtil(null, "eSystem_Delete");
13370    DeclareFunctionUtil(null, "eClass_GetProperty");
13371    DeclareFunctionUtil(null, "eClass_SetProperty");
13372    DeclareFunctionUtil(null, "eInstance_FireSelfWatchers");
13373    DeclareFunctionUtil(null, "eInstance_SetMethod");
13374    DeclareFunctionUtil(null, "eInstance_IncRef");
13375    DeclareFunctionUtil(null, "eInstance_StopWatching");
13376    DeclareFunctionUtil(null, "eInstance_Watch");
13377    DeclareFunctionUtil(null, "eInstance_FireWatchers");
13378    reachedPass15 = true;
13379
13380    for(external = ast->first; external; external = external.next)
13381    {
13382       afterExternal = curExternal = external;
13383       if(external.type == functionExternal)
13384       {
13385          if(memoryGuard)
13386          {
13387             DeclareFunctionUtil(external, "MemoryGuard_PushLoc");
13388             DeclareFunctionUtil(external, "MemoryGuard_PopLoc");
13389          }
13390
13391          currentClass = external.function._class;
13392          ProcessFunction(external.function);
13393       }
13394       // There shouldn't be any _class member access here anyways...
13395       else if(external.type == declarationExternal)
13396       {
13397          if(memoryGuard && external.declaration && external.declaration.type == instDeclaration)
13398          {
13399             DeclareFunctionUtil(external, "MemoryGuard_PushLoc");
13400             DeclareFunctionUtil(external, "MemoryGuard_PopLoc");
13401          }
13402
13403          currentClass = null;
13404          if(external.declaration)
13405             ProcessDeclaration(external.declaration, true);
13406       }
13407       else if(external.type == classExternal)
13408       {
13409          ClassDefinition _class = external._class;
13410          currentClass = external.symbol.registered;
13411          if(memoryGuard)
13412          {
13413             DeclareFunctionUtil(external, "MemoryGuard_PushLoc");
13414             DeclareFunctionUtil(external, "MemoryGuard_PopLoc");
13415          }
13416          if(_class.definitions)
13417          {
13418             ProcessClass(_class.definitions, _class.symbol);
13419          }
13420          if(inCompiler)
13421          {
13422             // Free class data...
13423             ast->Remove(external);
13424             delete external;
13425          }
13426       }
13427       else if(external.type == nameSpaceExternal)
13428       {
13429          thisNameSpace = external.id.string;
13430       }
13431    }
13432    currentClass = null;
13433    thisNameSpace = null;
13434    curExternal = null;
13435 }