compiler/libec: Fixed new memory leaks
[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
1159    if(!inCompiler || !classSym) return null;
1160
1161    // We don't need any declaration for bit classes...
1162    if(classSym.registered &&
1163       (classSym.registered.type == bitClass || classSym.registered.type == unitClass || classSym.registered.type == enumClass))
1164       return null;
1165
1166    if(!classSym.registered || (classSym.registered.type == normalClass && classSym.registered.structSize && classSym.registered.base && classSym.registered.base.base))
1167       _DeclareStruct(neededBy, "ecere::com::Instance", false, true, fwdDecl);
1168
1169    external = classSym.structExternal;
1170
1171    if(external && external.declaration)
1172    {
1173       Specifier spec;
1174       for(spec = external.declaration.specifiers ? external.declaration.specifiers->first : null; spec; spec = spec.next)
1175          if(spec.type == structSpecifier || spec.type == unionSpecifier)
1176          {
1177             curDeclarations = spec.definitions;
1178             break;
1179          }
1180    }
1181
1182    if(classSym.registered && !classSym.declaring && classSym.imported && (!classSym.declaredStructSym || (classSym.registered.type == noHeadClass && !skipNoHead && external && !curDeclarations)))
1183    {
1184       OldList * specifiers, * declarators;
1185       OldList * declarations = null;
1186       char structName[1024];
1187       bool addedPadding = false;
1188       Specifier curSpec = null;
1189
1190       classSym.declaring++;
1191
1192       if(strchr(classSym.string, '<'))
1193       {
1194          if(classSym.registered.templateClass)
1195             external = _DeclareStruct(neededBy, classSym.registered.templateClass.fullName, skipNoHead, needDereference, fwdDecl);
1196          classSym.declaring--;
1197          return external;
1198       }
1199
1200       structName[0] = 0;
1201       FullClassNameCat(structName, name, false);
1202
1203       classSym.declaredStructSym = true;
1204       if(!external || (classSym.registered.type == noHeadClass && !skipNoHead && !curDeclarations))
1205       {
1206          bool add = false;
1207          if(!external)
1208          {
1209             external = MkExternalDeclaration(null);
1210             classSym.structExternal = external;
1211             external.symbol = classSym;
1212
1213             add = true;
1214          }
1215
1216          if(!skipNoHead)
1217          {
1218             declarations = MkList();
1219             AddMembers(external, declarations, classSym.registered, false, null, classSym.registered, &addedPadding);
1220          }
1221
1222          if(external.declaration)
1223          {
1224             Specifier spec;
1225             for(spec = external.declaration.specifiers ? external.declaration.specifiers->first : null; spec; spec = spec.next)
1226                if(spec.type == structSpecifier || spec.type == unionSpecifier)
1227                {
1228                   curSpec = spec;
1229                   curDeclarations = spec.definitions;
1230                   break;
1231                }
1232          }
1233
1234          if(declarations && (!declarations->count || (declarations->count == 1 && addedPadding)))
1235          {
1236             FreeList(declarations, FreeClassDef);
1237             declarations = null;
1238          }
1239
1240          if(classSym.registered.type != noHeadClass && !declarations)
1241          {
1242             FreeExternal(external);
1243             external = null;
1244             classSym.structExternal = null;
1245          }
1246          else
1247          {
1248             if(curSpec)
1249                curSpec.definitions = declarations;
1250             else
1251             {
1252                specifiers = MkList();
1253                declarators = MkList();
1254                ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), declarations));
1255                external.declaration = MkDeclaration(specifiers, declarators);
1256             }
1257             if(add)
1258                ast->Add(external);
1259          }
1260       }
1261       classSym.declaring--;
1262    }
1263    else if(!classSym.declaredStructSym && classSym.structExternal)
1264    {
1265       classSym.declaredStructSym = true;
1266
1267       if(classSym.registered)
1268          DeclareMembers(classSym.structExternal, classSym.registered, false);
1269
1270       if(classSym.structExternal.declaration && classSym.structExternal.declaration.specifiers)
1271       {
1272          Specifier spec;
1273          for(spec = classSym.structExternal.declaration.specifiers->first; spec; spec = spec.next)
1274          {
1275             if(spec.definitions)
1276                IdentifyAnonStructs(spec.definitions);
1277          }
1278       }
1279    }
1280    if(inCompiler && neededBy && (external || !classSym.imported))
1281    {
1282       if(!external)
1283       {
1284          classSym.structExternal = external = MkExternalDeclaration(null);
1285          external.symbol = classSym;
1286          ast->Add(external);
1287       }
1288       if(reachedPass15 && !external.declaration && classSym.registered && classSym.registered.type == noHeadClass)
1289       {
1290          // Declare nohead classes without definitions here (e.g. IteratorPointer)
1291          char structName[1024];
1292          OldList * specifiers, * declarators;
1293          structName[0] = 0;
1294          FullClassNameCat(structName, name, false);
1295          specifiers = MkList();
1296          declarators = MkList();
1297          ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), null));
1298          external.declaration = MkDeclaration(specifiers, declarators);
1299       }
1300       if(fwdDecl)
1301       {
1302          External e = external.fwdDecl ? external.fwdDecl : external;
1303          if(e.incoming.count)
1304             neededBy.CreateUniqueEdge(e, !needDereference && !external.fwdDecl);
1305       }
1306       else
1307          neededBy.CreateUniqueEdge(external, !needDereference);
1308    }
1309    return external;
1310 }
1311
1312 void DeclareProperty(External neededBy, Property prop, char * setName, char * getName)
1313 {
1314    Symbol symbol = prop.symbol;
1315    bool imported = false;
1316    bool dllImport = false;
1317    External structExternal = null;
1318    External instExternal = null;
1319
1320    strcpy(setName, "__ecereProp_");
1321    FullClassNameCat(setName, prop._class.fullName, false);
1322    strcat(setName, "_Set_");
1323    FullClassNameCat(setName, prop.name, true);
1324
1325    strcpy(getName, "__ecereProp_");
1326    FullClassNameCat(getName, prop._class.fullName, false);
1327    strcat(getName, "_Get_");
1328    FullClassNameCat(getName, prop.name, true);
1329
1330    if(!symbol || symbol._import)
1331    {
1332       if(!symbol)
1333       {
1334          Symbol classSym;
1335
1336          if(!prop._class.symbol)
1337             prop._class.symbol = FindClass(prop._class.fullName);
1338          classSym = prop._class.symbol;
1339          if(classSym && !classSym._import)
1340          {
1341             ModuleImport module;
1342
1343             if(prop._class.module)
1344                module = FindModule(prop._class.module);
1345             else
1346                module = mainModule;
1347
1348             classSym._import = ClassImport
1349             {
1350                name = CopyString(prop._class.fullName);
1351                isRemote = prop._class.isRemote;
1352             };
1353             module.classes.Add(classSym._import);
1354          }
1355          symbol = prop.symbol = Symbol { };
1356          symbol._import = (ClassImport)PropertyImport
1357          {
1358             name = CopyString(prop.name);
1359             isVirtual = false; //prop.isVirtual;
1360             hasSet = prop.Set ? true : false;
1361             hasGet = prop.Get ? true : false;
1362          };
1363          if(classSym)
1364             classSym._import.properties.Add(symbol._import);
1365       }
1366       imported = true;
1367       // Ugly work around for isNan properties declared within float/double classes which are initialized with ecereCOM
1368       if((prop._class.module != privateModule || !strcmp(prop._class.name, "float") || !strcmp(prop._class.name, "double")) &&
1369          prop._class.module.importType != staticImport)
1370          dllImport = true;
1371    }
1372
1373    if(!symbol.type)
1374    {
1375       Context context = SetupTemplatesContext(prop._class);
1376       symbol.type = ProcessTypeString(prop.dataTypeString, false);
1377       FinishTemplatesContext(context);
1378    }
1379
1380    if((prop.Get && !symbol.externalGet) || (prop.Set && !symbol.externalSet))
1381    {
1382       if(prop._class.type == normalClass && prop._class.structSize)
1383          instExternal = DeclareStruct(null, "ecere::com::Instance", false, true);
1384       structExternal = DeclareStruct(null, prop._class.fullName, prop._class.type != structClass /*true*/, false);
1385    }
1386
1387    // Get
1388    if(prop.Get && !symbol.externalGet)
1389    {
1390       Declaration decl;
1391       OldList * specifiers, * declarators;
1392       Declarator d;
1393       OldList * params;
1394       Specifier spec = null;
1395       External external;
1396       Declarator typeDecl;
1397       bool simple = false;
1398       bool needReference;
1399
1400       specifiers = MkList();
1401       declarators = MkList();
1402       params = MkList();
1403
1404       ListAdd(params, MkTypeName(MkListOne(MkSpecifierName(prop._class.fullName)),
1405          MkDeclaratorIdentifier(MkIdentifier("this"))));
1406
1407       d = MkDeclaratorIdentifier(MkIdentifier(getName));
1408       //if(imported)
1409       if(dllImport)
1410          d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1411
1412       {
1413          Context context = SetupTemplatesContext(prop._class);
1414          typeDecl = SpecDeclFromString(prop.dataTypeString, specifiers, null);
1415          FinishTemplatesContext(context);
1416       }
1417
1418       // Make sure the simple _class's type is declared
1419       needReference = !typeDecl || typeDecl.type == identifierDeclarator;
1420       for(spec = specifiers->first; spec; spec = spec.next)
1421       {
1422          if(spec.type == nameSpecifier)
1423          {
1424             Symbol classSym = spec.symbol;
1425             if(needReference)
1426             {
1427                symbol._class = classSym.registered;
1428                if(classSym.registered && classSym.registered.type == structClass)
1429                   simple = true;
1430             }
1431             break;
1432          }
1433       }
1434
1435       if(!simple)
1436          d = PlugDeclarator(typeDecl, d);
1437       else
1438       {
1439          ListAdd(params, MkTypeName(specifiers,
1440             PlugDeclarator(typeDecl, MkDeclaratorIdentifier(MkIdentifier("value")))));
1441          specifiers = MkList();
1442       }
1443
1444       d = MkDeclaratorFunction(d, params);
1445
1446       //if(imported)
1447       if(dllImport)
1448          specifiers->Insert(null, MkSpecifier(EXTERN));
1449       else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1450          specifiers->Insert(null, MkSpecifier(STATIC));
1451       if(simple)
1452          ListAdd(specifiers, MkSpecifier(VOID));
1453
1454       ListAdd(declarators, MkInitDeclarator(d, null));
1455
1456       decl = MkDeclaration(specifiers, declarators);
1457
1458       external = MkExternalDeclaration(decl);
1459
1460       if(structExternal)
1461          external.CreateEdge(structExternal, false);
1462       if(instExternal)
1463          external.CreateEdge(instExternal, false);
1464
1465       if(spec)
1466          DeclareStruct(external, spec.name, false, needReference);
1467
1468       ast->Add(external);
1469       external.symbol = symbol;
1470       symbol.externalGet = external;
1471
1472       ReplaceThisClassSpecifiers(specifiers, prop._class);
1473
1474       if(typeDecl)
1475          FreeDeclarator(typeDecl);
1476    }
1477
1478    // Set
1479    if(prop.Set && !symbol.externalSet)
1480    {
1481       Declaration decl;
1482       OldList * specifiers, * declarators;
1483       Declarator d;
1484       OldList * params;
1485       Specifier spec = null;
1486       External external;
1487       Declarator typeDecl;
1488       bool needReference;
1489
1490       declarators = MkList();
1491       params = MkList();
1492
1493       if(!prop.conversion || prop._class.type == structClass)
1494       {
1495          ListAdd(params, MkTypeName(MkListOne(MkSpecifierName(prop._class.fullName)),
1496             MkDeclaratorIdentifier(MkIdentifier("this"))));
1497       }
1498
1499       specifiers = MkList();
1500
1501       {
1502          Context context = SetupTemplatesContext(prop._class);
1503          typeDecl = d = SpecDeclFromString(prop.dataTypeString, specifiers,
1504             MkDeclaratorIdentifier(MkIdentifier("value")));
1505          FinishTemplatesContext(context);
1506       }
1507       if(!strcmp(prop._class.base.fullName, "eda::Row") || !strcmp(prop._class.base.fullName, "eda::Id"))
1508          specifiers->Insert(null, MkSpecifier(CONST));
1509
1510       ListAdd(params, MkTypeName(specifiers, d));
1511
1512       d = MkDeclaratorIdentifier(MkIdentifier(setName));
1513       if(dllImport)
1514          d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1515       d = MkDeclaratorFunction(d, params);
1516
1517       // Make sure the simple _class's type is declared
1518       needReference = !typeDecl || typeDecl.type == identifierDeclarator;
1519       for(spec = specifiers->first; spec; spec = spec.next)
1520       {
1521          if(spec.type == nameSpecifier)
1522          {
1523             Symbol classSym = spec.symbol;
1524             if(needReference)
1525                symbol._class = classSym.registered;
1526             break;
1527          }
1528       }
1529
1530       ListAdd(declarators, MkInitDeclarator(d, null));
1531
1532       specifiers = MkList();
1533       if(dllImport)
1534          specifiers->Insert(null, MkSpecifier(EXTERN));
1535       else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1536          specifiers->Insert(null, MkSpecifier(STATIC));
1537
1538       if(!prop.conversion || prop._class.type == structClass)
1539          ListAdd(specifiers, MkSpecifier(VOID));
1540       else
1541          ListAdd(specifiers, MkSpecifierName(prop._class.fullName));
1542
1543       decl = MkDeclaration(specifiers, declarators);
1544
1545       external = MkExternalDeclaration(decl);
1546
1547       if(structExternal)
1548          external.CreateEdge(structExternal, false);
1549       if(instExternal)
1550          external.CreateEdge(instExternal, false);
1551
1552       if(spec)
1553          DeclareStruct(external, spec.name, false, needReference);
1554
1555       ast->Add(external);
1556       external.symbol = symbol;
1557       symbol.externalSet = external;
1558
1559       ReplaceThisClassSpecifiers(specifiers, prop._class);
1560    }
1561
1562    // Property (for Watchers)
1563    if(!symbol.externalPtr)
1564    {
1565       Declaration decl;
1566       External external;
1567       OldList * specifiers = MkList();
1568       char propName[1024];
1569
1570       if(imported)
1571          specifiers->Insert(null, MkSpecifier(EXTERN));
1572       else
1573       {
1574          specifiers->Insert(null, MkSpecifier(STATIC));
1575          specifiers->Add(MkSpecifierExtended(MkExtDeclAttrib(MkAttrib(ATTRIB, MkListOne(MkAttribute(CopyString("unused"), null))))));
1576       }
1577
1578       ListAdd(specifiers, MkSpecifierName("Property"));
1579
1580       strcpy(propName, "__ecereProp_");
1581       FullClassNameCat(propName, prop._class.fullName, false);
1582       strcat(propName, "_");
1583       FullClassNameCat(propName, prop.name, true);
1584
1585       {
1586          OldList * list = MkList();
1587          ListAdd(list, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(propName)), null));
1588
1589          if(!imported)
1590          {
1591             strcpy(propName, "__ecerePropM_");
1592             FullClassNameCat(propName, prop._class.fullName, false);
1593             strcat(propName, "_");
1594             FullClassNameCat(propName, prop.name, true);
1595
1596             ListAdd(list, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(propName)), null));
1597          }
1598          decl = MkDeclaration(specifiers, list);
1599       }
1600
1601       external = MkExternalDeclaration(decl);
1602       ast->Insert(curExternal.prev, external);
1603       external.symbol = symbol;
1604       symbol.externalPtr = external;
1605    }
1606
1607    if(inCompiler && neededBy)
1608    {
1609       // Could improve this to create edge on only what is needed...
1610       if(symbol.externalPtr)
1611          neededBy.CreateUniqueEdge(symbol.externalPtr, false);
1612
1613       if(symbol.externalGet)
1614          neededBy.CreateUniqueEdge(symbol.externalGet, symbol.externalGet.type == functionExternal);
1615
1616       if(symbol.externalSet)
1617          neededBy.CreateUniqueEdge(symbol.externalSet, symbol.externalSet.type == functionExternal);
1618
1619       // IsSet ?
1620    }
1621 }
1622
1623 // ***************** EXPRESSION PROCESSING ***************************
1624 public Type Dereference(Type source)
1625 {
1626    Type type = null;
1627    if(source)
1628    {
1629       if(source.kind == pointerType || source.kind == arrayType)
1630       {
1631          type = source.type;
1632          source.type.refCount++;
1633       }
1634       else if(source.kind == classType && !strcmp(source._class.string, "String"))
1635       {
1636          type = Type
1637          {
1638             kind = charType;
1639             refCount = 1;
1640          };
1641       }
1642       // Support dereferencing of no head classes for now...
1643       else if(source.kind == classType && source._class && source._class.registered && source._class.registered.type == noHeadClass)
1644       {
1645          type = source;
1646          source.refCount++;
1647       }
1648       else
1649          Compiler_Error($"cannot dereference type\n");
1650    }
1651    return type;
1652 }
1653
1654 static Type Reference(Type source)
1655 {
1656    Type type = null;
1657    if(source)
1658    {
1659       type = Type
1660       {
1661          kind = pointerType;
1662          type = source;
1663          refCount = 1;
1664       };
1665       source.refCount++;
1666    }
1667    return type;
1668 }
1669
1670 void ProcessMemberInitData(MemberInit member, Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
1671 {
1672    Identifier ident = member.identifiers ? member.identifiers->first : null;
1673    bool found = false;
1674    DataMember dataMember = null;
1675    Method method = null;
1676    bool freeType = false;
1677
1678    yylloc = member.loc;
1679
1680    if(!ident)
1681    {
1682       if(curMember)
1683       {
1684          eClass_FindNextMember(_class, curClass, curMember, subMemberStack, subMemberStackPos);
1685          if(*curMember)
1686          {
1687             found = true;
1688             dataMember = *curMember;
1689          }
1690       }
1691    }
1692    else
1693    {
1694       DataMember thisMember = (DataMember)eClass_FindProperty(_class, ident.string, privateModule);
1695       DataMember _subMemberStack[256];
1696       int _subMemberStackPos = 0;
1697
1698       // FILL MEMBER STACK
1699       if(!thisMember)
1700          thisMember = eClass_FindDataMember(_class, ident.string, privateModule, _subMemberStack, &_subMemberStackPos);
1701       if(thisMember)
1702       {
1703          dataMember = thisMember;
1704          if(curMember && thisMember.memberAccess == publicAccess)
1705          {
1706             *curMember = thisMember;
1707             *curClass = thisMember._class;
1708             memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
1709             *subMemberStackPos = _subMemberStackPos;
1710          }
1711          found = true;
1712       }
1713       else
1714       {
1715          // Setting a method
1716          method = eClass_FindMethod(_class, ident.string, privateModule);
1717          if(method && method.type == virtualMethod)
1718             found = true;
1719          else
1720             method = null;
1721       }
1722    }
1723
1724    if(found)
1725    {
1726       Type type = null;
1727       if(dataMember)
1728       {
1729          if(!dataMember.dataType && dataMember.dataTypeString)
1730          {
1731             //Context context = SetupTemplatesContext(dataMember._class);
1732             Context context = SetupTemplatesContext(_class);
1733             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
1734             FinishTemplatesContext(context);
1735          }
1736          type = dataMember.dataType;
1737       }
1738       else if(method)
1739       {
1740          // This is for destination type...
1741          if(!method.dataType)
1742             ProcessMethodType(method);
1743          //DeclareMethod(method);
1744          // method.dataType = ((Symbol)method.symbol)->type;
1745          type = method.dataType;
1746       }
1747
1748       if(ident && ident.next)
1749       {
1750          for(ident = ident.next; ident && type; ident = ident.next)
1751          {
1752             if(type.kind == classType)
1753             {
1754                dataMember = (DataMember)eClass_FindProperty(type._class.registered, ident.string, privateModule);
1755                if(!dataMember)
1756                   dataMember = eClass_FindDataMember(type._class.registered, ident.string, privateModule, null, null);
1757                if(dataMember)
1758                   type = dataMember.dataType;
1759             }
1760             else if(type.kind == structType || type.kind == unionType)
1761             {
1762                Type memberType;
1763                for(memberType = type.members.first; memberType; memberType = memberType.next)
1764                {
1765                   if(!strcmp(memberType.name, ident.string))
1766                   {
1767                      type = memberType;
1768                      break;
1769                   }
1770                }
1771             }
1772          }
1773       }
1774
1775       // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
1776       if(type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type && _class.templateArgs /* TODO: Watch out for these _class.templateClass*/)
1777       {
1778          int id = 0;
1779          ClassTemplateParameter curParam = null;
1780          Class sClass;
1781          for(sClass = _class; sClass; sClass = sClass.base)
1782          {
1783             id = 0;
1784             if(sClass.templateClass) sClass = sClass.templateClass;
1785             for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
1786             {
1787                if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
1788                {
1789                   for(sClass = sClass.base; sClass; sClass = sClass.base)
1790                   {
1791                      if(sClass.templateClass) sClass = sClass.templateClass;
1792                      id += sClass.templateParams.count;
1793                   }
1794                   break;
1795                }
1796                id++;
1797             }
1798             if(curParam) break;
1799          }
1800
1801          if(curParam)
1802          {
1803             ClassTemplateArgument arg = _class.templateArgs[id];
1804             if(arg.dataTypeString)
1805             {
1806                bool constant = type.constant;
1807                // FreeType(type);
1808                type = ProcessTypeString(arg.dataTypeString, false);
1809                if(type.kind == classType && constant) type.constant = true;
1810                else if(type.kind == pointerType)
1811                {
1812                   Type t = type.type;
1813                   while(t.kind == pointerType) t = t.type;
1814                   if(constant) t.constant = constant;
1815                }
1816                freeType = true;
1817                if(type && _class.templateClass)
1818                   type.passAsTemplate = true;
1819                if(type)
1820                {
1821                   // type.refCount++;
1822                   /*if(!exp.destType)
1823                   {
1824                      exp.destType = ProcessTypeString(arg.dataTypeString, false);
1825                      exp.destType.refCount++;
1826                   }*/
1827                }
1828             }
1829          }
1830       }
1831       if(type && type.kind == classType && type._class && type._class.registered && strchr(type._class.registered.fullName, '<'))
1832       {
1833          Class expClass = type._class.registered;
1834          Class cClass = null;
1835          int paramCount = 0;
1836          int lastParam = -1;
1837
1838          char templateString[1024];
1839          ClassTemplateParameter param;
1840          sprintf(templateString, "%s<", expClass.templateClass.fullName);
1841          for(cClass = expClass; cClass; cClass = cClass.base)
1842          {
1843             int p = 0;
1844             if(cClass.templateClass) cClass = cClass.templateClass;
1845             for(param = cClass.templateParams.first; param; param = param.next)
1846             {
1847                int id = p;
1848                Class sClass;
1849                ClassTemplateArgument arg;
1850                for(sClass = cClass.base; sClass; sClass = sClass.base)
1851                {
1852                   if(sClass.templateClass) sClass = sClass.templateClass;
1853                   id += sClass.templateParams.count;
1854                }
1855                arg = expClass.templateArgs[id];
1856
1857                for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
1858                {
1859                   ClassTemplateParameter cParam;
1860                   //int p = numParams - sClass.templateParams.count;
1861                   int p = 0;
1862                   Class nextClass;
1863                   if(sClass.templateClass) sClass = sClass.templateClass;
1864
1865                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
1866                   {
1867                      if(nextClass.templateClass) nextClass = nextClass.templateClass;
1868                      p += nextClass.templateParams.count;
1869                   }
1870
1871                   for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
1872                   {
1873                      if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
1874                      {
1875                         if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1876                         {
1877                            arg.dataTypeString = _class.templateArgs[p].dataTypeString;
1878                            arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
1879                            break;
1880                         }
1881                      }
1882                   }
1883                }
1884
1885                {
1886                   char argument[256];
1887                   argument[0] = '\0';
1888                   /*if(arg.name)
1889                   {
1890                      strcat(argument, arg.name.string);
1891                      strcat(argument, " = ");
1892                   }*/
1893                   switch(param.type)
1894                   {
1895                      case expression:
1896                      {
1897                         // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
1898                         char expString[1024];
1899                         OldList * specs = MkList();
1900                         Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
1901                         Expression exp;
1902                         char * string = PrintHexUInt64(arg.expression.ui64);
1903                         exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
1904                         delete string;
1905
1906                         ProcessExpressionType(exp);
1907                         ComputeExpression(exp);
1908                         expString[0] = '\0';
1909                         PrintExpression(exp, expString);
1910                         strcat(argument, expString);
1911                         //delete exp;
1912                         FreeExpression(exp);
1913                         break;
1914                      }
1915                      case identifier:
1916                      {
1917                         strcat(argument, arg.member.name);
1918                         break;
1919                      }
1920                      case TemplateParameterType::type:
1921                      {
1922                         if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1923                            strcat(argument, arg.dataTypeString);
1924                         break;
1925                      }
1926                   }
1927                   if(argument[0])
1928                   {
1929                      if(paramCount) strcat(templateString, ", ");
1930                      if(lastParam != p - 1)
1931                      {
1932                         strcat(templateString, param.name);
1933                         strcat(templateString, " = ");
1934                      }
1935                      strcat(templateString, argument);
1936                      paramCount++;
1937                      lastParam = p;
1938                   }
1939                   p++;
1940                }
1941             }
1942          }
1943          {
1944             int len = strlen(templateString);
1945             if(templateString[len-1] == '<')
1946                len--;
1947             else
1948             {
1949                if(templateString[len-1] == '>')
1950                   templateString[len++] = ' ';
1951                templateString[len++] = '>';
1952             }
1953             templateString[len++] = '\0';
1954          }
1955          {
1956             Context context = SetupTemplatesContext(_class);
1957             if(freeType) FreeType(type);
1958             type = ProcessTypeString(templateString, false);
1959             freeType = true;
1960             FinishTemplatesContext(context);
1961          }
1962       }
1963
1964       if(method && member.initializer && member.initializer.type == expInitializer && member.initializer.exp)
1965       {
1966          ProcessExpressionType(member.initializer.exp);
1967          if(!member.initializer.exp.expType)
1968          {
1969             if(inCompiler)
1970             {
1971                char expString[10240];
1972                expString[0] = '\0';
1973                PrintExpression(member.initializer.exp, expString);
1974                ChangeCh(expString, '\n', ' ');
1975                Compiler_Error($"unresolved symbol used as an instance method %s\n", expString);
1976             }
1977          }
1978          //else if(!MatchTypes(member.exp.expType, type, null, _class, null, true, true, false, false))
1979          else if(!MatchTypes(member.initializer.exp.expType, type, null, null, _class, true, true, false, false, true))
1980          {
1981             Compiler_Error($"incompatible instance method %s\n", ident.string);
1982          }
1983       }
1984       else if(member.initializer)
1985       {
1986          /*
1987          FreeType(member.exp.destType);
1988          member.exp.destType = type;
1989          if(member.exp.destType)
1990             member.exp.destType.refCount++;
1991          ProcessExpressionType(member.exp);
1992          */
1993
1994          ProcessInitializer(member.initializer, type);
1995       }
1996       if(freeType) FreeType(type);
1997    }
1998    else
1999    {
2000       if(_class && _class.type == unitClass)
2001       {
2002          if(member.initializer)
2003          {
2004             /*
2005             FreeType(member.exp.destType);
2006             member.exp.destType = MkClassType(_class.fullName);
2007             ProcessExpressionType(member.initializer, type);
2008             */
2009             Type type = MkClassType(_class.fullName);
2010             ProcessInitializer(member.initializer, type);
2011             FreeType(type);
2012          }
2013       }
2014       else
2015       {
2016          if(member.initializer)
2017          {
2018             //ProcessExpressionType(member.exp);
2019             ProcessInitializer(member.initializer, null);
2020          }
2021          if(ident)
2022          {
2023             if(method)
2024             {
2025                Compiler_Error($"couldn't find virtual method %s in class %s\n", ident.string, _class.fullName);
2026             }
2027             else if(_class)
2028             {
2029                Compiler_Error($"couldn't find member %s in class %s\n", ident.string, _class.fullName);
2030                if(inCompiler)
2031                   eClass_AddDataMember(_class, ident.string, "int", 0, 0, publicAccess);
2032             }
2033          }
2034          else if(_class)
2035             Compiler_Error($"too many initializers for instantiation of class %s\n", _class.fullName);
2036       }
2037    }
2038 }
2039
2040 void ProcessInstantiationType(Instantiation inst)
2041 {
2042    yylloc = inst.loc;
2043    if(inst._class)
2044    {
2045       MembersInit members;
2046       Symbol classSym;
2047       Class _class;
2048
2049       classSym = inst._class.symbol;
2050       _class = classSym ? classSym.registered : null;
2051
2052       if(!_class || _class.type != noHeadClass)
2053          DeclareStruct(curExternal, inst._class.name, false, true);
2054
2055       afterExternal = afterExternal ? afterExternal : curExternal;
2056
2057       if(inst.exp)
2058          ProcessExpressionType(inst.exp);
2059
2060       inst.isConstant = true;
2061       if(inst.members)
2062       {
2063          DataMember curMember = null;
2064          Class curClass = null;
2065          DataMember subMemberStack[256];
2066          int subMemberStackPos = 0;
2067
2068          for(members = inst.members->first; members; members = members.next)
2069          {
2070             switch(members.type)
2071             {
2072                case methodMembersInit:
2073                {
2074                   char name[1024];
2075                   static uint instMethodID = 0;
2076                   External external = curExternal;
2077                   Context context = curContext;
2078                   Declarator declarator = members.function.declarator;
2079                   Identifier nameID = GetDeclId(declarator);
2080                   char * unmangled = nameID ? nameID.string : null;
2081                   Expression exp;
2082                   External createdExternal = null;
2083
2084                   if(inCompiler)
2085                   {
2086                      char number[16];
2087                      strcpy(name, "__ecereInstMeth_");
2088                      FullClassNameCat(name, _class ? _class.fullName : "_UNKNOWNCLASS", false);
2089                      strcat(name, "_");
2090                      strcat(name, nameID.string);
2091                      strcat(name, "_");
2092                      sprintf(number, "_%08d", instMethodID++);
2093                      strcat(name, number);
2094                      nameID.string = CopyString(name);
2095                   }
2096
2097                   // Do modifications here...
2098                   if(declarator)
2099                   {
2100                      Symbol symbol = declarator.symbol;
2101                      Method method = eClass_FindMethod(_class, unmangled, privateModule);
2102
2103                      if(method && method.type == virtualMethod)
2104                      {
2105                         symbol.method = method;
2106                         ProcessMethodType(method);
2107
2108                         if(!symbol.type.thisClass)
2109                         {
2110                            if(method.dataType.thisClass && currentClass &&
2111                               eClass_IsDerived(currentClass, method.dataType.thisClass.registered))
2112                            {
2113                               if(!currentClass.symbol)
2114                                  currentClass.symbol = FindClass(currentClass.fullName);
2115                               symbol.type.thisClass = currentClass.symbol;
2116                            }
2117                            else
2118                            {
2119                               if(!_class.symbol)
2120                                  _class.symbol = FindClass(_class.fullName);
2121                               symbol.type.thisClass = _class.symbol;
2122                            }
2123                         }
2124                         DeclareType(curExternal, symbol.type, true, true);
2125
2126                      }
2127                      else if(classSym)
2128                      {
2129                         Compiler_Error($"couldn't find virtual method %s in class %s\n",
2130                            unmangled, classSym.string);
2131                      }
2132                   }
2133
2134                   createdExternal = ProcessClassFunction(classSym ? classSym.registered : null, members.function, ast, afterExternal, true);
2135
2136                   if(nameID)
2137                   {
2138                      FreeSpecifier(nameID._class);
2139                      nameID._class = null;
2140                   }
2141
2142                   curExternal = createdExternal;
2143                   if(inCompiler)
2144                   {
2145                      if(createdExternal.function)
2146                         ProcessFunction(createdExternal.function);
2147                   }
2148                   else if(declarator)
2149                   {
2150                      curExternal = declarator.symbol.pointerExternal;
2151                      ProcessFunction((FunctionDefinition)members.function);
2152                   }
2153                   curExternal = external;
2154                   curContext = context;
2155
2156                   if(inCompiler)
2157                   {
2158                      FreeClassFunction(members.function);
2159
2160                      // In this pass, turn this into a MemberInitData
2161                      exp = QMkExpId(name);
2162                      members.type = dataMembersInit;
2163                      members.dataMembers = MkListOne(MkMemberInit(MkListOne(MkIdentifier(unmangled)), MkInitializerAssignment(exp)));
2164
2165                      delete unmangled;
2166                   }
2167                   break;
2168                }
2169                case dataMembersInit:
2170                {
2171                   if(members.dataMembers && classSym)
2172                   {
2173                      MemberInit member;
2174                      Location oldyyloc = yylloc;
2175                      for(member = members.dataMembers->first; member; member = member.next)
2176                      {
2177                         ProcessMemberInitData(member, classSym.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
2178                         if(member.initializer && !member.initializer.isConstant)
2179                            inst.isConstant = false;
2180                      }
2181                      yylloc = oldyyloc;
2182                   }
2183                   break;
2184                }
2185             }
2186          }
2187       }
2188    }
2189 }
2190
2191 void DeclareType(External neededFor, Type type, bool needDereference, bool forFunctionDef)
2192 {
2193    _DeclareType(neededFor, type, needDereference, forFunctionDef, false);
2194 }
2195
2196 void DeclareTypeForwardDeclare(External neededFor, Type type, bool needDereference, bool forFunctionDef)
2197 {
2198    _DeclareType(neededFor, type, needDereference, forFunctionDef, true);
2199 }
2200
2201 static void _DeclareType(External neededFor, Type type, bool needDereference, bool forFunctionDef, bool fwdDecl)
2202 {
2203    if(inCompiler)
2204    {
2205       if(type.kind == functionType)
2206       {
2207          Type param;
2208          for(param = type.params.first; param; param = param.next)
2209             _DeclareType(neededFor, param, forFunctionDef, false, fwdDecl);
2210          _DeclareType(neededFor, type.returnType, forFunctionDef, false, fwdDecl);
2211       }
2212       else if(type.kind == pointerType)
2213          _DeclareType(neededFor, type.type, false, false, fwdDecl);
2214       else if(type.kind == classType)
2215       {
2216          Class c = type._class.registered;
2217          _DeclareStruct(neededFor, c ? c.fullName : "ecere::com::Instance", c ? c.type == noHeadClass : false, needDereference && c && c.type == structClass, fwdDecl);
2218       }
2219       else if(type.kind == structType || type.kind == unionType)
2220       {
2221          Type member;
2222          for(member = type.members.first; member; member = member.next)
2223             _DeclareType(neededFor, member, needDereference, forFunctionDef, fwdDecl);
2224       }
2225       else if(type.kind == arrayType)
2226          _DeclareType(neededFor, type.arrayType, true, false, fwdDecl);
2227    }
2228 }
2229
2230 ClassTemplateArgument * FindTemplateArg(Class _class, TemplateParameter param)
2231 {
2232    ClassTemplateArgument * arg = null;
2233    int id = 0;
2234    ClassTemplateParameter curParam = null;
2235    Class sClass;
2236    for(sClass = _class; sClass; sClass = sClass.base)
2237    {
2238       id = 0;
2239       if(sClass.templateClass) sClass = sClass.templateClass;
2240       for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
2241       {
2242          if(curParam.type == TemplateParameterType::type && !strcmp(param.identifier.string, curParam.name))
2243          {
2244             for(sClass = sClass.base; sClass; sClass = sClass.base)
2245             {
2246                if(sClass.templateClass) sClass = sClass.templateClass;
2247                id += sClass.templateParams.count;
2248             }
2249             break;
2250          }
2251          id++;
2252       }
2253       if(curParam) break;
2254    }
2255    if(curParam)
2256    {
2257       arg = &_class.templateArgs[id];
2258       if(arg && param.type == type)
2259          arg->dataTypeClass = eSystem_FindClass(_class.module, arg->dataTypeString);
2260    }
2261    return arg;
2262 }
2263
2264 public Context SetupTemplatesContext(Class _class)
2265 {
2266    Context context = PushContext();
2267    context.templateTypesOnly = true;
2268    if(_class.symbol && ((Symbol)_class.symbol).templateParams)
2269    {
2270       TemplateParameter param = ((Symbol)_class.symbol).templateParams->first;
2271       for(; param; param = param.next)
2272       {
2273          if(param.type == type && param.identifier)
2274          {
2275             TemplatedType type { key = (uintptr)param.identifier.string, param = param };
2276             curContext.templateTypes.Add((BTNode)type);
2277          }
2278       }
2279    }
2280    else if(_class)
2281    {
2282       Class sClass;
2283       for(sClass = _class; sClass; sClass = sClass.base)
2284       {
2285          ClassTemplateParameter p;
2286          for(p = sClass.templateParams.first; p; p = p.next)
2287          {
2288             //OldList * specs = MkList();
2289             //Declarator decl = null;
2290             //decl = SpecDeclFromString(p.dataTypeString, specs, null);
2291             if(p.type == type)
2292             {
2293                TemplateParameter param = p.param;
2294                TemplatedType type;
2295                if(!param)
2296                {
2297                   // ADD DATA TYPE HERE...
2298                   p.param = param = TemplateParameter
2299                   {
2300                      identifier = MkIdentifier(p.name), type = p.type,
2301                      dataTypeString = p.dataTypeString /*, dataType = { specs, decl }*/
2302                   };
2303                }
2304                type = TemplatedType { key = (uintptr)p.name, param = param };
2305                curContext.templateTypes.Add((BTNode)type);
2306             }
2307          }
2308       }
2309    }
2310    return context;
2311 }
2312
2313 public void FinishTemplatesContext(Context context)
2314 {
2315    PopContext(context);
2316    FreeContext(context);
2317    delete context;
2318 }
2319
2320 public void ProcessMethodType(Method method)
2321 {
2322    if(!method.dataType)
2323    {
2324       Context context = SetupTemplatesContext(method._class);
2325
2326       method.dataType = ProcessTypeString(method.dataTypeString, false);
2327
2328       FinishTemplatesContext(context);
2329
2330       if(method.type != virtualMethod && method.dataType)
2331       {
2332          if(!method.dataType.thisClass && !method.dataType.staticMethod)
2333          {
2334             if(!method._class.symbol)
2335                method._class.symbol = FindClass(method._class.fullName);
2336             method.dataType.thisClass = method._class.symbol;
2337          }
2338       }
2339
2340       // Why was this commented out? Working fine without now...
2341
2342       /*
2343       if(method.dataType.kind == functionType && !method.dataType.staticMethod && !method.dataType.thisClass)
2344          method.dataType.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2345          */
2346    }
2347
2348    /*
2349    if(type)
2350    {
2351       char * par = strstr(type, "(");
2352       char * classOp = null;
2353       int classOpLen = 0;
2354       if(par)
2355       {
2356          int c;
2357          for(c = par-type-1; c >= 0; c++)
2358          {
2359             if(type[c] == ':' && type[c+1] == ':')
2360             {
2361                classOp = type + c - 1;
2362                for(c = c-1; c >=0 && !isspace(type[c]); c--)
2363                {
2364                   classOp--;
2365                   classOpLen++;
2366                }
2367                break;
2368             }
2369             else if(!isspace(type[c]))
2370                break;
2371          }
2372       }
2373       if(classOp)
2374       {
2375          char temp[1024];
2376          int typeLen = strlen(type);
2377          memcpy(temp, classOp, classOpLen);
2378          temp[classOpLen] = '\0';
2379          if(temp[0])
2380             _class = eSystem_FindClass(module, temp);
2381          else
2382             _class = null;
2383          method.dataTypeString = new char[typeLen - classOpLen + 1];
2384          memcpy(method.dataTypeString, type, classOp - type);
2385          memcpy(method.dataTypeString + (classOp - type), classOp + classOpLen, typeLen - (classOp - type + classOpLen));
2386       }
2387       else
2388          method.dataTypeString = type;
2389    }
2390    */
2391 }
2392
2393
2394 public void ProcessPropertyType(Property prop)
2395 {
2396    if(!prop.dataType)
2397    {
2398       Context context = SetupTemplatesContext(prop._class);
2399       prop.dataType = ProcessTypeString(prop.dataTypeString, false);
2400       FinishTemplatesContext(context);
2401    }
2402 }
2403
2404 public void DeclareMethod(External neededFor, Method method, const char * name)
2405 {
2406    Symbol symbol = method.symbol;
2407    if(!symbol || (!symbol.pointerExternal && (!symbol.methodCodeExternal || method.type == virtualMethod)))
2408    {
2409       bool dllImport = false;
2410
2411       if(!method.dataType)
2412          method.dataType = ProcessTypeString(method.dataTypeString, false);
2413
2414       //if(!symbol || symbol._import || method.type == virtualMethod)
2415       {
2416          if(!symbol || method.type == virtualMethod)
2417          {
2418             Symbol classSym;
2419             if(!method._class.symbol)
2420                method._class.symbol = FindClass(method._class.fullName);
2421             classSym = method._class.symbol;
2422             if(!classSym._import)
2423             {
2424                ModuleImport module;
2425
2426                if(method._class.module && method._class.module.name)
2427                   module = FindModule(method._class.module);
2428                else
2429                   module = mainModule;
2430                classSym._import = ClassImport
2431                {
2432                   name = CopyString(method._class.fullName);
2433                   isRemote = method._class.isRemote;
2434                };
2435                module.classes.Add(classSym._import);
2436             }
2437             if(!symbol)
2438             {
2439                symbol = method.symbol = Symbol { };
2440             }
2441             if(!symbol._import)
2442             {
2443                symbol._import = (ClassImport)MethodImport
2444                {
2445                   name = CopyString(method.name);
2446                   isVirtual = method.type == virtualMethod;
2447                };
2448                classSym._import.methods.Add(symbol._import);
2449             }
2450             if(!symbol)
2451             {
2452                symbol.type = method.dataType;
2453                if(symbol.type) symbol.type.refCount++;
2454             }
2455          }
2456          if(!method.dataType.dllExport)
2457          {
2458             if((method._class.module != privateModule || !strcmp(method._class.name, "float") || !strcmp(method._class.name, "double")) && method._class.module.importType != staticImport)
2459                dllImport = true;
2460          }
2461       }
2462
2463       if(inCompiler)
2464       {
2465          // We need a declaration here :)
2466          Declaration decl;
2467          OldList * specifiers, * declarators;
2468          Declarator d;
2469          Declarator funcDecl;
2470          External external;
2471
2472          specifiers = MkList();
2473          declarators = MkList();
2474
2475          if(dllImport)
2476             ListAdd(specifiers, MkSpecifier(EXTERN));
2477          else if(method._class.symbol && ((Symbol)method._class.symbol).isStatic)
2478             ListAdd(specifiers, MkSpecifier(STATIC));
2479
2480          if(method.type == virtualMethod)
2481          {
2482             ListAdd(specifiers, MkSpecifier(INT));
2483             d = MkDeclaratorIdentifier(MkIdentifier(name));
2484          }
2485          else
2486          {
2487             d = MkDeclaratorIdentifier(MkIdentifier(name));
2488             if(dllImport)
2489                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2490             {
2491                Context context = SetupTemplatesContext(method._class);
2492                d = SpecDeclFromString(method.dataTypeString, specifiers, d);
2493                FinishTemplatesContext(context);
2494             }
2495             funcDecl = GetFuncDecl(d);
2496
2497             if(dllImport)
2498             {
2499                Specifier spec, next;
2500                for(spec = specifiers->first; spec; spec = next)
2501                {
2502                   next = spec.next;
2503                   if(spec.type == extendedSpecifier)
2504                   {
2505                      specifiers->Remove(spec);
2506                      FreeSpecifier(spec);
2507                   }
2508                }
2509             }
2510
2511             // Add this parameter if not a static method
2512             if(method.dataType && !method.dataType.staticMethod)
2513             {
2514                if(funcDecl && funcDecl.function.parameters && funcDecl.function.parameters->count)
2515                {
2516                   Class _class = method.dataType.thisClass ? method.dataType.thisClass.registered : method._class;
2517                   TypeName thisParam = MkTypeName(MkListOne(
2518                      MkSpecifierName(method.dataType.thisClass ? method.dataType.thisClass.string : method._class.fullName)),
2519                      (_class && _class.type == systemClass) ? MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("this"))) : MkDeclaratorIdentifier(MkIdentifier("this")));
2520                   TypeName firstParam = ((TypeName)funcDecl.function.parameters->first);
2521                   Specifier firstSpec = firstParam.qualifiers ? firstParam.qualifiers->first : null;
2522
2523                   if(firstSpec && firstSpec.type == baseSpecifier && firstSpec.specifier == VOID && !firstParam.declarator)
2524                   {
2525                      TypeName param = funcDecl.function.parameters->first;
2526                      funcDecl.function.parameters->Remove(param);
2527                      FreeTypeName(param);
2528                   }
2529
2530                   if(!funcDecl.function.parameters)
2531                      funcDecl.function.parameters = MkList();
2532                   funcDecl.function.parameters->Insert(null, thisParam);
2533                }
2534             }
2535          }
2536          ProcessDeclarator(d, true);
2537
2538          ListAdd(declarators, MkInitDeclarator(d, null));
2539
2540          decl = MkDeclaration(specifiers, declarators);
2541
2542          ReplaceThisClassSpecifiers(specifiers, method._class);
2543
2544          external = MkExternalDeclaration(decl);
2545          external.symbol = symbol;
2546          symbol.pointerExternal = external;
2547          ast->Add(external);
2548          DeclareStruct(external, method._class.fullName, true, true);
2549          if(method.dataType)
2550             DeclareType(external, method.dataType, true, true);
2551       }
2552    }
2553    if(inCompiler && neededFor)
2554    {
2555       External external = symbol.pointerExternal ? symbol.pointerExternal : symbol.methodCodeExternal;
2556       neededFor.CreateUniqueEdge(external, external.type == functionExternal);
2557    }
2558 }
2559
2560 char * ReplaceThisClass(Class _class)
2561 {
2562    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2563    {
2564       bool first = true;
2565       int p = 0;
2566       ClassTemplateParameter param;
2567       int lastParam = -1;
2568
2569       char className[1024];
2570       strcpy(className, _class.fullName);
2571       for(param = _class.templateParams.first; param; param = param.next)
2572       {
2573          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2574          {
2575             if(first) strcat(className, "<");
2576             if(!first) strcat(className, ", ");
2577             if(lastParam + 1 != p)
2578             {
2579                strcat(className, param.name);
2580                strcat(className, " = ");
2581             }
2582             strcat(className, param.name);
2583             first = false;
2584             lastParam = p;
2585          }
2586          p++;
2587       }
2588       if(!first)
2589       {
2590          int len = strlen(className);
2591          if(className[len-1] == '>') className[len++] = ' ';
2592          className[len++] = '>';
2593          className[len++] = '\0';
2594       }
2595       return CopyString(className);
2596    }
2597    else
2598       return CopyString(_class.fullName);
2599 }
2600
2601 Type ReplaceThisClassType(Class _class)
2602 {
2603    Type type;
2604    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2605    {
2606       bool first = true;
2607       int p = 0;
2608       ClassTemplateParameter param;
2609       int lastParam = -1;
2610       char className[1024];
2611       strcpy(className, _class.fullName);
2612
2613       for(param = _class.templateParams.first; param; param = param.next)
2614       {
2615          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2616          {
2617             if(first) strcat(className, "<");
2618             if(!first) strcat(className, ", ");
2619             if(lastParam + 1 != p)
2620             {
2621                strcat(className, param.name);
2622                strcat(className, " = ");
2623             }
2624             strcat(className, param.name);
2625             first = false;
2626             lastParam = p;
2627          }
2628          p++;
2629       }
2630       if(!first)
2631       {
2632          int len = strlen(className);
2633          if(className[len-1] == '>') className[len++] = ' ';
2634          className[len++] = '>';
2635          className[len++] = '\0';
2636       }
2637       type = MkClassType(className);
2638       //type = ProcessTypeString(className, false);
2639    }
2640    else
2641    {
2642       type = MkClassType(_class.fullName);
2643       //type = ProcessTypeString(_class.fullName, false);
2644    }
2645    //type.wasThisClass = true;
2646    return type;
2647 }
2648
2649 void ReplaceThisClassSpecifiers(OldList specs, Class _class)
2650 {
2651    if(specs != null && _class)
2652    {
2653       Specifier spec;
2654       for(spec = specs.first; spec; spec = spec.next)
2655       {
2656          if(spec.type == baseSpecifier && spec.specifier == THISCLASS)
2657          {
2658             spec.type = nameSpecifier;
2659             spec.name = ReplaceThisClass(_class);
2660             spec.symbol = FindClass(spec.name); //_class.symbol;
2661          }
2662       }
2663    }
2664 }
2665
2666 // Returns imported or not
2667 bool DeclareFunction(External neededFor, GlobalFunction function, char * name)
2668 {
2669    Symbol symbol = function.symbol;
2670    // TOCHECK: Might get rid of the pointerExternal check in favor of marking the edge as breakable
2671    if(!symbol || !symbol.pointerExternal)
2672    {
2673       bool imported = false;
2674       bool dllImport = false;
2675
2676       if(!function.dataType)
2677       {
2678          function.dataType = ProcessTypeString(function.dataTypeString, false);
2679          if(!function.dataType.thisClass)
2680             function.dataType.staticMethod = true;
2681       }
2682
2683       if(inCompiler)
2684       {
2685          if(!symbol)
2686          {
2687             ModuleImport module = FindModule(function.module);
2688             // WARNING: This is not added anywhere...
2689             symbol = function.symbol = Symbol {  };
2690
2691             if(module.name)
2692             {
2693                if(!function.dataType.dllExport)
2694                {
2695                   symbol._import = (ClassImport)FunctionImport { name = CopyString(function.name) };
2696                   module.functions.Add(symbol._import);
2697                }
2698             }
2699             // Set the symbol type
2700             {
2701                symbol.type = ProcessTypeString(function.dataTypeString, false);
2702                if(!symbol.type.thisClass)
2703                   symbol.type.staticMethod = true;
2704             }
2705          }
2706          imported = symbol._import ? true : false;
2707          if(imported && function.module != privateModule && function.module.importType != staticImport)
2708             dllImport = true;
2709       }
2710
2711       if(inCompiler)
2712       {
2713          // TOCHECK: What's with the functionExternal check here? Is it Edge breaking / forward declaration?
2714          //if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2715          {
2716             // We need a declaration here :)
2717             Declaration decl;
2718             OldList * specifiers, * declarators;
2719             Declarator d;
2720             Declarator funcDecl;
2721             External external;
2722
2723             specifiers = MkList();
2724             declarators = MkList();
2725
2726             ListAdd(specifiers, MkSpecifier(EXTERN));
2727
2728             d = MkDeclaratorIdentifier(MkIdentifier(imported ? name : function.name));
2729             if(dllImport)
2730                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2731
2732             d = SpecDeclFromString(function.dataTypeString, specifiers, d);
2733             // TAKE OUT THE DLL EXPORT IF STATICALLY IMPORTED:
2734             if(function.module.importType == staticImport)
2735             {
2736                Specifier spec;
2737                for(spec = specifiers->first; spec; spec = spec.next)
2738                   if(spec.type == extendedSpecifier && spec.extDecl && spec.extDecl.type == extDeclString && !strcmp(spec.extDecl.s, "dllexport"))
2739                   {
2740                      specifiers->Remove(spec);
2741                      FreeSpecifier(spec);
2742                      break;
2743                   }
2744             }
2745
2746             funcDecl = GetFuncDecl(d);
2747
2748             // Make sure we don't have empty parameter declarations for static methods...
2749             if(funcDecl && !funcDecl.function.parameters)
2750             {
2751                funcDecl.function.parameters = MkList();
2752                funcDecl.function.parameters->Insert(null,
2753                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2754             }
2755
2756             ListAdd(declarators, MkInitDeclarator(d, null));
2757
2758             {
2759                Context oldCtx = curContext;
2760                curContext = globalContext;
2761                decl = MkDeclaration(specifiers, declarators);
2762                curContext = oldCtx;
2763             }
2764
2765             // Keep a different symbol for the function definition than the declaration...
2766             /* Note: This should be handled by the edge breaking...
2767             if(symbol.pointerExternal && symbol.pointerExternal.type == functionExternal)
2768             {
2769                Symbol functionSymbol { };
2770                // Copy symbol
2771                {
2772                   *functionSymbol = *symbol;
2773                   functionSymbol.string = CopyString(symbol.string);
2774                   if(functionSymbol.type)
2775                      functionSymbol.type.refCount++;
2776                }
2777
2778                excludedSymbols->Add(functionSymbol);
2779
2780                symbol.pointerExternal.symbol = functionSymbol;
2781             }
2782             */
2783             external = MkExternalDeclaration(decl);
2784             ast->Add(external);
2785             external.symbol = symbol;
2786             symbol.pointerExternal = external;
2787
2788             DeclareType(external, function.dataType, true, true);
2789          }
2790       }
2791    }
2792    if(inCompiler && neededFor && symbol && symbol.pointerExternal)
2793       neededFor.CreateUniqueEdge(symbol.pointerExternal, symbol.pointerExternal.type == functionExternal);
2794    return (symbol && symbol._import && function.module != privateModule && function.module.importType != staticImport) ? true : false;
2795 }
2796
2797 void DeclareGlobalData(External neededFor, GlobalData data)
2798 {
2799    Symbol symbol = data.symbol;
2800    // TOCHECK: Might get rid of the pointerExternal check in favor of marking the edge as breakable
2801    if(!symbol || !symbol.pointerExternal)
2802    {
2803       if(inCompiler)
2804       {
2805          if(!symbol)
2806             symbol = data.symbol = Symbol { };
2807       }
2808       if(!data.dataType)
2809          data.dataType = ProcessTypeString(data.dataTypeString, false);
2810
2811       if(inCompiler)
2812       {
2813          // We need a declaration here :)
2814          Declaration decl;
2815          OldList * specifiers, * declarators;
2816          Declarator d;
2817          External external;
2818
2819          specifiers = MkList();
2820          declarators = MkList();
2821
2822          ListAdd(specifiers, MkSpecifier(EXTERN));
2823          d = MkDeclaratorIdentifier(MkIdentifier(data.fullName));
2824          d = SpecDeclFromString(data.dataTypeString, specifiers, d);
2825
2826          ListAdd(declarators, MkInitDeclarator(d, null));
2827
2828          decl = MkDeclaration(specifiers, declarators);
2829          external = MkExternalDeclaration(decl);
2830          if(curExternal)
2831             ast->Insert(curExternal.prev, external);
2832          external.symbol = symbol;
2833          symbol.pointerExternal = external;
2834
2835          DeclareType(external, data.dataType, true, true);
2836       }
2837    }
2838    if(inCompiler && neededFor && symbol && symbol.pointerExternal)
2839       neededFor.CreateUniqueEdge(symbol.pointerExternal, false);
2840 }
2841
2842 class Conversion : struct
2843 {
2844    Conversion prev, next;
2845    Property convert;
2846    bool isGet;
2847    Type resultType;
2848 };
2849
2850 static bool CheckConstCompatibility(Type source, Type dest, bool warn)
2851 {
2852    bool status = true;
2853    if(((source.kind == classType && source._class && source._class.registered) || source.kind == arrayType || source.kind == pointerType) &&
2854       ((dest.kind == classType && dest._class && dest._class.registered) || /*dest.kind == arrayType || */dest.kind == pointerType))
2855    {
2856       Class sourceClass = source.kind == classType ? source._class.registered : null;
2857       Class destClass = dest.kind == classType ? dest._class.registered : null;
2858       if((!sourceClass || (sourceClass && sourceClass.type == normalClass && !sourceClass.structSize)) &&
2859          (!destClass || (destClass && destClass.type == normalClass && !destClass.structSize)))
2860       {
2861          Type sourceType = source, destType = dest;
2862          while((sourceType.kind == pointerType || sourceType.kind == arrayType) && sourceType.type) sourceType = sourceType.type;
2863          while((destType.kind == pointerType || destType.kind == arrayType) && destType.type) destType = destType.type;
2864          if(!destType.constant && sourceType.constant)
2865          {
2866             status = false;
2867             if(warn)
2868                Compiler_Warning($"discarding const qualifier\n");
2869          }
2870       }
2871    }
2872    return status;
2873 }
2874
2875 public bool MatchTypes(Type source, Type dest, OldList conversions, Class owningClassSource, Class owningClassDest, bool doConversion, bool enumBaseType, bool acceptReversedParams,
2876                        bool isConversionExploration, bool warnConst)
2877 {
2878    if(source && dest)
2879    {
2880       if(warnConst)
2881          CheckConstCompatibility(source, dest, true);
2882       // Property convert;
2883
2884       if(source.kind == templateType && dest.kind != templateType)
2885       {
2886          Type type = ProcessTemplateParameterType(source.templateParameter);
2887          if(type) source = type;
2888       }
2889
2890       if(dest.kind == templateType && source.kind != templateType)
2891       {
2892          Type type = ProcessTemplateParameterType(dest.templateParameter);
2893          if(type) dest = type;
2894       }
2895
2896       if(dest.classObjectType == typedObject && dest.kind != functionType)
2897       {
2898          if(source.classObjectType != anyObject)
2899             return true;
2900          else
2901          {
2902             // If either the source or the destination defines the class, accepts any_object as compatible for a typed_object
2903             if((dest._class && strcmp(dest._class.string, "class")) || (source._class && strcmp(source._class.string, "class")))
2904             {
2905                return true;
2906             }
2907          }
2908       }
2909       else
2910       {
2911          if(source.kind != functionType && source.classObjectType == anyObject)
2912             return true;
2913          if(dest.kind != functionType && dest.classObjectType == anyObject && source.classObjectType != typedObject)
2914             return true;
2915       }
2916
2917       if((dest.kind == structType && source.kind == structType) ||
2918          (dest.kind == unionType && source.kind == unionType))
2919       {
2920          if((dest.enumName && source.enumName && !strcmp(dest.enumName, source.enumName)) ||
2921              (source.members.first && source.members.first == dest.members.first))
2922             return true;
2923       }
2924
2925       if(dest.kind == ellipsisType && source.kind != voidType)
2926          return true;
2927
2928       if(dest.kind == pointerType && dest.type.kind == voidType &&
2929          ((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))
2930          || source.kind == subClassType || source.kind == pointerType || source.kind == arrayType || source.kind == functionType || source.kind == thisClassType)
2931
2932          /*source.kind != voidType && source.kind != structType && source.kind != unionType  */
2933
2934          /*&& (source.kind != classType /-*|| source._class.registered.type != structClass)*/)
2935          return true;
2936       if(!isConversionExploration && source.kind == pointerType && source.type.kind == voidType &&
2937          ((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))
2938          || dest.kind == subClassType || dest.kind == pointerType || dest.kind == arrayType || dest.kind == functionType || dest.kind == thisClassType)
2939          /* dest.kind != voidType && dest.kind != structType && dest.kind != unionType  */
2940
2941          /*&& (dest.kind != classType || dest._class.registered.type != structClass)*/)
2942          return true;
2943
2944       if(((source.kind == classType && dest.kind == classType) || (source.kind == subClassType && dest.kind == subClassType)) && source._class)
2945       {
2946          if(source._class.registered && source._class.registered.type == unitClass)
2947          {
2948             if(conversions != null)
2949             {
2950                if(source._class.registered == dest._class.registered)
2951                   return true;
2952             }
2953             else
2954             {
2955                Class sourceBase, destBase;
2956                for(sourceBase = source._class.registered; sourceBase && sourceBase.base.type != systemClass; sourceBase = sourceBase.base);
2957                for(destBase = dest._class.registered; destBase && destBase.base.type != systemClass; destBase = destBase.base);
2958                if(sourceBase == destBase)
2959                   return true;
2960             }
2961          }
2962          // Don't match enum inheriting from other enum if resolving enumeration values
2963          // TESTING: !dest.classObjectType
2964          else if(source._class && dest._class && (dest.classObjectType == source.classObjectType || !dest.classObjectType) &&
2965             (enumBaseType ||
2966                (!source._class.registered || source._class.registered.type != enumClass) ||
2967                (!dest._class.registered || dest._class.registered.type != enumClass)) && eClass_IsDerived(source._class.registered, dest._class.registered))
2968             return true;
2969          else
2970          {
2971             // Added this so that DefinedColor = Color doesn't go through ColorRGB property
2972             if(enumBaseType &&
2973                dest._class && dest._class.registered && dest._class.registered.type == enumClass &&
2974                ((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)
2975             {
2976                if(eClass_IsDerived(dest._class.registered, source._class.registered))
2977                {
2978                   return true;
2979                }
2980             }
2981          }
2982       }
2983
2984       // JUST ADDED THIS...
2985       if(source.kind == subClassType && dest.kind == classType && dest._class && !strcmp(dest._class.string, "ecere::com::Class"))
2986          return true;
2987
2988       if(doConversion)
2989       {
2990          // Just added this for Straight conversion of ColorAlpha => Color
2991          if(source.kind == classType)
2992          {
2993             Class _class;
2994             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
2995             {
2996                Property convert;
2997                for(convert = _class.conversions.first; convert; convert = convert.next)
2998                {
2999                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3000                   {
3001                      Conversion after = (conversions != null) ? conversions.last : null;
3002
3003                      if(!convert.dataType)
3004                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3005                      // Only go ahead with this conversion flow while processing an existing conversion if the conversion data type is a class
3006                      if((!isConversionExploration || convert.dataType.kind == classType || !strcmp(_class.name, "String")) &&
3007                         MatchTypes(convert.dataType, dest, conversions, null, null,
3008                            (convert.dataType.kind == classType && !strcmp(convert.dataTypeString, "String")) ? true : false,
3009                               convert.dataType.kind == classType, false, true, warnConst))
3010                      {
3011                         if(!conversions && !convert.Get)
3012                            return true;
3013                         else if(conversions != null)
3014                         {
3015                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3016                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3017                               (dest.kind != classType || dest._class.registered != _class.base))
3018                               return true;
3019                            else
3020                            {
3021                               Conversion conv { convert = convert, isGet = true };
3022                               // conversions.Add(conv);
3023                               conversions.Insert(after, conv);
3024
3025                               return true;
3026                            }
3027                         }
3028                      }
3029                   }
3030                }
3031             }
3032          }
3033
3034          // MOVING THIS??
3035
3036          if(dest.kind == classType)
3037          {
3038             Class _class;
3039             for(_class = dest._class ? dest._class.registered : null; _class; _class = _class.base)
3040             {
3041                Property convert;
3042                for(convert = _class.conversions.first; convert; convert = convert.next)
3043                {
3044                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3045                   {
3046                      Type constType = null;
3047                      bool success = false;
3048                      // Conversion after = (conversions != null) ? conversions.last : null;
3049
3050                      if(!convert.dataType)
3051                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3052
3053                      if(warnConst && convert.dataType.kind == pointerType && convert.dataType.type && dest.constant)
3054                      {
3055                         Type ptrType { };
3056                         constType = { kind = pointerType, refCount = 1, type = ptrType };
3057                         CopyTypeInto(ptrType, convert.dataType.type);
3058                         ptrType.constant = true;
3059                      }
3060
3061                      // Just added this equality check to prevent recursion.... Make it safer?
3062                      // Changed enumBaseType to false here to prevent all int-compatible enums to show up in AnchorValues
3063                      if((constType || convert.dataType != dest) && MatchTypes(source, constType ? constType : convert.dataType, conversions, null, null, true, false /*true*/, false, true, warnConst))
3064                      {
3065                         if(!conversions && !convert.Set)
3066                            success = true;
3067                         else if(conversions != null)
3068                         {
3069                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3070                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3071                               (source.kind != classType || source._class.registered != _class.base))
3072                               success = true;
3073                            else
3074                            {
3075                               // *** Testing this! ***
3076                               Conversion conv { convert = convert };
3077                               conversions.Add(conv);
3078                               //conversions.Insert(after, conv);
3079                               success = true;
3080                            }
3081                         }
3082                      }
3083                      if(constType)
3084                         FreeType(constType);
3085                      if(success)
3086                         return true;
3087                   }
3088                }
3089             }
3090             /*if(dest._class.registered && !strcmp(dest._class.registered.name, "bool"))
3091             {
3092                if(source.kind != voidType && source.kind != structType && source.kind != unionType &&
3093                   (source.kind != classType || source._class.registered.type != structClass))
3094                   return true;
3095             }*/
3096
3097             // TESTING THIS... IS THIS OK??
3098             if(enumBaseType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3099             {
3100                if(!dest._class.registered.dataType)
3101                   dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3102                // Only support this for classes...
3103                if(dest._class.registered.dataType.kind == classType || source.truth || dest.truth/* ||
3104                   !strcmp(dest._class.registered.name, "bool") || (source.kind == classType && !strcmp(source._class.string, "bool"))*/)
3105                {
3106                   if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, dest._class.registered.dataType.kind == classType, false, false, warnConst))
3107                   {
3108                      return true;
3109                   }
3110                }
3111             }
3112          }
3113
3114          // Moved this lower
3115          if(source.kind == classType)
3116          {
3117             Class _class;
3118             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3119             {
3120                Property convert;
3121                for(convert = _class.conversions.first; convert; convert = convert.next)
3122                {
3123                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3124                   {
3125                      Conversion after = (conversions != null) ? conversions.last : null;
3126
3127                      if(!convert.dataType)
3128                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3129                      if(convert.dataType != source &&
3130                         (!isConversionExploration || convert.dataType.kind == classType || !strcmp(_class.name, "String")) &&
3131                         MatchTypes(convert.dataType, dest, conversions, null, null, convert.dataType.kind == classType, convert.dataType.kind == classType, false, true, warnConst))
3132                      {
3133                         if(!conversions && !convert.Get)
3134                            return true;
3135                         else if(conversions != null)
3136                         {
3137                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3138                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3139                               (dest.kind != classType || dest._class.registered != _class.base))
3140                               return true;
3141                            else
3142                            {
3143                               Conversion conv { convert = convert, isGet = true };
3144
3145                               // conversions.Add(conv);
3146                               conversions.Insert(after, conv);
3147                               return true;
3148                            }
3149                         }
3150                      }
3151                   }
3152                }
3153             }
3154
3155             // TESTING THIS... IS THIS OK??
3156             if(enumBaseType && source._class && source._class.registered && source._class.registered.type == enumClass)
3157             {
3158                if(!source._class.registered.dataType)
3159                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3160                if(!isConversionExploration || source._class.registered.dataType.kind == classType || !strcmp(source._class.registered.name, "String"))
3161                {
3162                   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))
3163                      return true;
3164                   // For bool to be accepted by byte, short, etc.
3165                   else if(MatchTypes(dest, source._class.registered.dataType, null, null, null, false, false, false, false, warnConst))
3166                      return true;
3167                }
3168             }
3169          }
3170       }
3171
3172       if(source.kind == classType || source.kind == subClassType)
3173          ;
3174       else if(dest.kind == source.kind &&
3175          (dest.kind != structType && dest.kind != unionType &&
3176           dest.kind != functionType && dest.kind != arrayType && dest.kind != pointerType && dest.kind != methodType))
3177           return true;
3178       // RECENTLY ADDED THESE
3179       else if(dest.kind == doubleType && source.kind == floatType)
3180          return true;
3181       else if(dest.kind == shortType && (source.kind == charType || source.kind == _BoolType))
3182          return true;
3183       else if(dest.kind == intType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intSizeType /* Exception here for size_t */))
3184          return true;
3185       else if(dest.kind == int64Type && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intPtrType || source.kind == intSizeType))
3186          return true;
3187       else if(dest.kind == intPtrType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intSizeType || source.kind == int64Type))
3188          return true;
3189       else if(dest.kind == intSizeType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == int64Type || source.kind == intPtrType))
3190          return true;
3191       else if(source.kind == enumType &&
3192          (dest.kind == intType || dest.kind == shortType || dest.kind == charType || source.kind == _BoolType || dest.kind == longType || dest.kind == int64Type || dest.kind == intPtrType || dest.kind == intSizeType))
3193           return true;
3194       else if(dest.kind == enumType && !isConversionExploration &&
3195          (source.kind == intType || source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == longType || source.kind == int64Type || source.kind == intPtrType || source.kind == intSizeType))
3196           return true;
3197       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) &&
3198               ((source.kind == functionType || (source.kind == pointerType && source.type.kind == functionType) || source.kind == methodType)))
3199       {
3200          Type paramSource, paramDest;
3201
3202          if(dest.kind == methodType)
3203             owningClassDest = dest.methodClass ? dest.methodClass : dest.method._class;
3204          if(source.kind == methodType)
3205             owningClassSource = source.methodClass ? source.methodClass : source.method._class;
3206
3207          if(dest.kind == pointerType && dest.type.kind == functionType) dest = dest.type;
3208          if(source.kind == pointerType && source.type.kind == functionType) source = source.type;
3209          if(dest.kind == methodType)
3210             dest = dest.method.dataType;
3211          if(source.kind == methodType)
3212             source = source.method.dataType;
3213
3214          paramSource = source.params.first;
3215          if(paramSource && paramSource.kind == voidType) paramSource = null;
3216          paramDest = dest.params.first;
3217          if(paramDest && paramDest.kind == voidType) paramDest = null;
3218
3219
3220          if((dest.staticMethod || (!dest.thisClass && !owningClassDest)) &&
3221             !(source.staticMethod || (!source.thisClass && !owningClassSource)))
3222          {
3223             // Source thisClass must be derived from destination thisClass
3224             if(!paramDest || (!(paramDest.kind == pointerType && paramDest.type && paramDest.type.kind == voidType) && (paramDest.kind != classType ||
3225                !eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource,paramDest._class.registered))))
3226             {
3227                if(paramDest && paramDest.kind == classType)
3228                   Compiler_Error($"method class must be derived from %s\n", paramDest._class.string);
3229                else
3230                   Compiler_Error($"method class should not take an object\n");
3231                return false;
3232             }
3233             paramDest = paramDest.next;
3234          }
3235          else if(!dest.staticMethod && (dest.thisClass || owningClassDest))
3236          {
3237             if((source.staticMethod || (!source.thisClass && !owningClassSource)))
3238             {
3239                if(dest.thisClass)
3240                {
3241                   if(!paramSource || paramSource.kind != classType || !eClass_IsDerived(paramSource._class.registered,dest.thisClass.registered))
3242                   {
3243                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3244                      return false;
3245                   }
3246                }
3247                else
3248                {
3249                   // THIS WAS BACKWARDS:
3250                   // if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(owningClassDest, paramSource._class.registered)))
3251                   if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(paramSource._class.registered, owningClassDest)))
3252                   {
3253                      if(owningClassDest)
3254                        Compiler_Error($"%s expected to be derived from method class\n", owningClassDest.fullName);
3255                      else
3256                         Compiler_Error($"overriding class expected to be derived from method class\n");
3257                      return false;
3258                   }
3259                }
3260                paramSource = paramSource.next;
3261             }
3262             else
3263             {
3264                if(dest.thisClass)
3265                {
3266                   // Source thisClass must be derived from destination thisClass
3267                   if(!eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource, dest.thisClass.registered))
3268                   {
3269                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3270                      return false;
3271                   }
3272                }
3273                else
3274                {
3275                   // THIS WAS BACKWARDS TOO??
3276                   // if(source.thisClass && owningClassDest && !eClass_IsDerived(owningClassDest, source.thisClass.registered))
3277                   if(source.thisClass && source.thisClass.registered && owningClassDest && !eClass_IsDerived(source.thisClass.registered, owningClassDest))
3278                   {
3279                      //if(owningClass)
3280                         Compiler_Error($"%s expected to be derived from method class\n", /*owningClass.name*/ source.thisClass.registered.fullName);
3281                      //else
3282                         //Compiler_Error($"overriding class expected to be derived from method class\n");
3283                      return false;
3284                   }
3285                }
3286             }
3287          }
3288
3289
3290          // Source return type must be derived from destination return type
3291          if(!MatchTypes(source.returnType, dest.returnType, null, null, null, true, true, false, false, warnConst))
3292          {
3293             Compiler_Warning($"incompatible return type for function\n");
3294             return false;
3295          }
3296          // The const check is backwards from the MatchTypes above (for derivative classes checks)
3297          else
3298             CheckConstCompatibility(dest.returnType, source.returnType, true);
3299
3300          // Check parameters
3301
3302          for(; paramDest; paramDest = paramDest.next)
3303          {
3304             if(!paramSource)
3305             {
3306                //Compiler_Warning($"not enough parameters\n");
3307                Compiler_Error($"not enough parameters\n");
3308                return false;
3309             }
3310             {
3311                Type paramDestType = paramDest;
3312                Type paramSourceType = paramSource;
3313                Type type = paramDestType;
3314
3315                // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
3316                if(paramDest.kind == templateType && paramDest.templateParameter.type == TemplateParameterType::type && owningClassSource &&
3317                   paramSource.kind != templateType)
3318                {
3319                   int id = 0;
3320                   ClassTemplateParameter curParam = null;
3321                   Class sClass;
3322                   for(sClass = owningClassSource; sClass; sClass = sClass.base)
3323                   {
3324                      id = 0;
3325                      if(sClass.templateClass) sClass = sClass.templateClass;
3326                      for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
3327                      {
3328                         if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
3329                         {
3330                            for(sClass = sClass.base; sClass; sClass = sClass.base)
3331                            {
3332                               if(sClass.templateClass) sClass = sClass.templateClass;
3333                               id += sClass.templateParams.count;
3334                            }
3335                            break;
3336                         }
3337                         id++;
3338                      }
3339                      if(curParam) break;
3340                   }
3341
3342                   if(curParam)
3343                   {
3344                      ClassTemplateArgument arg = owningClassSource.templateArgs[id];
3345                      paramDestType = type = ProcessTypeString(arg.dataTypeString, false);
3346                   }
3347                }
3348
3349                // paramDest must be derived from paramSource
3350                if(!MatchTypes(paramDestType, paramSourceType, null, null, null, true, true, false, false, warnConst) &&
3351                   (!acceptReversedParams || !MatchTypes(paramSourceType, paramDestType, null, null, null, true, true, false, false, warnConst)))
3352                {
3353                   char type[1024];
3354                   type[0] = 0;
3355                   PrintType(paramDest, type, false, true);
3356                   Compiler_Warning($"incompatible parameter %s (expected %s)\n", paramSource.name, type);
3357
3358                   if(paramDestType != paramDest)
3359                      FreeType(paramDestType);
3360                   return false;
3361                }
3362                if(paramDestType != paramDest)
3363                   FreeType(paramDestType);
3364             }
3365
3366             paramSource = paramSource.next;
3367          }
3368          if(paramSource)
3369          {
3370             Compiler_Error($"too many parameters\n");
3371             return false;
3372          }
3373          return true;
3374       }
3375       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) && (source.kind == pointerType && source.type.kind == voidType))
3376       {
3377          return true;
3378       }
3379       else if((dest.kind == pointerType || dest.kind == arrayType) &&
3380          (source.kind == arrayType || source.kind == pointerType))
3381       {
3382          // Pointers to pointer is incompatible with non normal/nohead classes
3383          if(!(dest.type && dest.type.kind == pointerType && source.type.kind == classType && source.type._class &&
3384             source.type._class.registered && (source.type._class.registered.type != normalClass && source.type._class.registered.type != noHeadClass) && !source.type.byReference))
3385          {
3386             ComputeTypeSize(source.type);
3387             ComputeTypeSize(dest.type);
3388             if(source.type.size == dest.type.size && MatchTypes(source.type, dest.type, null, null, null, true, true, false, false, warnConst))
3389                return true;
3390          }
3391       }
3392    }
3393    return false;
3394 }
3395
3396 static void FreeConvert(Conversion convert)
3397 {
3398    if(convert.resultType)
3399       FreeType(convert.resultType);
3400 }
3401
3402 bool MatchWithEnums_NameSpace(NameSpace nameSpace, Expression sourceExp, Type dest,
3403                               char * string, OldList conversions)
3404 {
3405    BTNamedLink link;
3406
3407    for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
3408    {
3409       Class _class = link.data;
3410       if(_class.type == enumClass)
3411       {
3412          OldList converts { };
3413          Type type { };
3414          type.kind = classType;
3415
3416          if(!_class.symbol)
3417             _class.symbol = FindClass(_class.fullName);
3418          type._class = _class.symbol;
3419
3420          if(MatchTypes(type, dest, &converts, null, null, dest.kind != classType || !dest._class || strcmp(dest._class.string, "bool"),
3421                false, false, false, false))
3422          {
3423             NamedLink64 value;
3424             Class enumClass = eSystem_FindClass(privateModule, "enum");
3425             if(enumClass)
3426             {
3427                Class baseClass;
3428                for(baseClass = _class ; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
3429                {
3430                   EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
3431                   for(value = e.values.first; value; value = value.next)
3432                   {
3433                      if(!strcmp(value.name, string))
3434                         break;
3435                   }
3436                   if(value)
3437                   {
3438                      FreeType(sourceExp.expType);
3439
3440                      sourceExp.isConstant = true;
3441                      sourceExp.expType = MkClassType(baseClass.fullName);
3442                      if(inCompiler || inPreCompiler || inDebugger)
3443                      {
3444                         char constant[256];
3445                         FreeExpContents(sourceExp);
3446
3447                         sourceExp.type = constantExp;
3448                         if(!strcmp(baseClass.dataTypeString, "int") || !strcmp(baseClass.dataTypeString, "int64") || !strcmp(baseClass.dataTypeString, "short") || !strcmp(baseClass.dataTypeString, "char"))
3449                            sprintf(constant, FORMAT64D, value.data);
3450                         else
3451                            sprintf(constant, FORMAT64HEXLL, value.data);
3452                         sourceExp.constant = CopyString(constant);
3453                         //for(;baseClass.base && baseClass.base.type != systemClass; baseClass = baseClass.base);
3454                      }
3455
3456                      while(converts.first)
3457                      {
3458                         Conversion convert = converts.first;
3459                         converts.Remove(convert);
3460                         conversions.Add(convert);
3461                      }
3462                      delete type;
3463                      return true;
3464                   }
3465                }
3466             }
3467          }
3468          if(converts.first)
3469             converts.Free(FreeConvert);
3470          delete type;
3471       }
3472    }
3473    for(nameSpace = (NameSpace *)nameSpace.nameSpaces.first; nameSpace != null; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
3474       if(MatchWithEnums_NameSpace(nameSpace, sourceExp, dest, string, conversions))
3475          return true;
3476    return false;
3477 }
3478
3479 public bool ModuleVisibility(Module searchIn, Module searchFor)
3480 {
3481    SubModule subModule;
3482
3483    if(searchFor == searchIn)
3484       return true;
3485
3486    for(subModule = searchIn.modules.first; subModule; subModule = subModule.next)
3487    {
3488       if(subModule.importMode == publicAccess || searchIn == searchIn.application)
3489       {
3490          if(ModuleVisibility(subModule.module, searchFor))
3491             return true;
3492       }
3493    }
3494    return false;
3495 }
3496
3497 bool MatchWithEnums_Module(Module mainModule, Expression sourceExp, Type dest, char * string, OldList conversions)
3498 {
3499    Module module;
3500
3501    if(MatchWithEnums_NameSpace(mainModule.application.systemNameSpace, sourceExp, dest, string, conversions))
3502       return true;
3503    if(MatchWithEnums_NameSpace(mainModule.application.privateNameSpace, sourceExp, dest, string, conversions))
3504       return true;
3505    if(MatchWithEnums_NameSpace(mainModule.application.publicNameSpace, sourceExp, dest, string, conversions))
3506       return true;
3507
3508    for(module = mainModule.application.allModules.first; module; module = module.next)
3509    {
3510       if(ModuleVisibility(mainModule, module) && MatchWithEnums_NameSpace(module.publicNameSpace, sourceExp, dest, string, conversions))
3511          return true;
3512    }
3513    return false;
3514 }
3515
3516 bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, bool skipUnitBla, bool warnConst)
3517 {
3518    Type source;
3519    Type realDest = dest;
3520    Type backupSourceExpType = null;
3521    Expression nbExp = GetNonBracketsExp(sourceExp);
3522    Expression computedExp = nbExp;
3523    dest.refCount++;
3524
3525    if(sourceExp.isConstant && sourceExp.type != constantExp && sourceExp.type != identifierExp && sourceExp.type != castExp &&
3526       dest.kind == classType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3527    {
3528       computedExp = CopyExpression(nbExp);        // Keep the original expression, but compute for checking enum ranges
3529       ComputeExpression(computedExp /*sourceExp*/);
3530    }
3531
3532    source = sourceExp.expType;
3533
3534    if(dest.kind == pointerType && sourceExp.type == constantExp && !strtoul(sourceExp.constant, null, 0))
3535    {
3536       if(computedExp != nbExp)
3537       {
3538          FreeExpression(computedExp);
3539          computedExp = nbExp;
3540       }
3541       FreeType(dest);
3542       return true;
3543    }
3544
3545    if(!skipUnitBla && source && dest && source.kind == classType && dest.kind == classType)
3546    {
3547        if(source._class && source._class.registered && source._class.registered.type == unitClass)
3548        {
3549           Class sourceBase, destBase;
3550           for(sourceBase = source._class.registered;
3551               sourceBase && sourceBase.base && sourceBase.base.type != systemClass;
3552               sourceBase = sourceBase.base);
3553           for(destBase = dest._class.registered;
3554               destBase && destBase.base && destBase.base.type != systemClass;
3555               destBase = destBase.base);
3556           //if(source._class.registered == dest._class.registered)
3557           if(sourceBase == destBase)
3558           {
3559             if(computedExp != nbExp)
3560             {
3561                FreeExpression(computedExp);
3562                computedExp = nbExp;
3563             }
3564             FreeType(dest);
3565             return true;
3566          }
3567       }
3568    }
3569
3570    if(source)
3571    {
3572       OldList * specs;
3573       bool flag = false;
3574       int64 value = MAXINT;
3575
3576       source.refCount++;
3577
3578       if(computedExp.type == constantExp)
3579       {
3580          if(source.isSigned)
3581             value = strtoll(computedExp.constant, null, 0);
3582          else
3583             value = strtoull(computedExp.constant, null, 0);
3584       }
3585       else if(computedExp.type == opExp && sourceExp.op.op == '-' && !computedExp.op.exp1 && computedExp.op.exp2 && computedExp.op.exp2.type == constantExp)
3586       {
3587          if(source.isSigned)
3588             value = -strtoll(computedExp.op.exp2.constant, null, 0);
3589          else
3590             value = -strtoull(computedExp.op.exp2.constant, null, 0);
3591       }
3592       if(computedExp != nbExp)
3593       {
3594          FreeExpression(computedExp);
3595          computedExp = nbExp;
3596       }
3597
3598       if(dest.kind != classType && source.kind == classType && source._class && source._class.registered &&
3599          !strcmp(source._class.registered.fullName, "unichar" /*"ecere::com::unichar"*/))
3600       {
3601          FreeType(source);
3602          source = Type { kind = intType, isSigned = false, refCount = 1 };
3603       }
3604
3605       if(dest.kind == classType)
3606       {
3607          Class _class = dest._class ? dest._class.registered : null;
3608
3609          if(_class && _class.type == unitClass)
3610          {
3611             if(source.kind != classType)
3612             {
3613                Type tempType { };
3614                Type tempDest, tempSource;
3615
3616                for(; _class.base.type != systemClass; _class = _class.base);
3617                tempSource = dest;
3618                tempDest = tempType;
3619
3620                tempType.kind = classType;
3621                if(!_class.symbol)
3622                   _class.symbol = FindClass(_class.fullName);
3623
3624                tempType._class = _class.symbol;
3625                tempType.truth = dest.truth;
3626                if(tempType._class)
3627                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false, warnConst);
3628
3629                // NOTE: To handle bad warnings on int64 vs 32 bit eda::Id incompatibilities
3630                backupSourceExpType = sourceExp.expType;
3631                if(dest.passAsTemplate)
3632                {
3633                   // Don't carry passAsTemplate
3634                   sourceExp.expType = { };
3635                   CopyTypeInto(sourceExp.expType, dest);
3636                   sourceExp.expType.passAsTemplate = false;
3637                }
3638                else
3639                {
3640                   sourceExp.expType = dest;
3641                   dest.refCount++;
3642                }
3643                //sourceExp.expType = MkClassType(_class.fullName);
3644                flag = true;
3645
3646                delete tempType;
3647             }
3648          }
3649
3650
3651          // Why wasn't there something like this?
3652          if(_class && _class.type == bitClass && source.kind != classType)
3653          {
3654             if(!dest._class.registered.dataType)
3655                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3656             if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false, warnConst))
3657             {
3658                FreeType(source);
3659                FreeType(sourceExp.expType);
3660                source = sourceExp.expType = MkClassType(dest._class.string);
3661                source.refCount++;
3662
3663                //source.kind = classType;
3664                //source._class = dest._class;
3665             }
3666          }
3667
3668          // Adding two enumerations
3669          /*
3670          if(_class && _class.type == enumClass && source.kind == classType && source._class && source._class.registered && source._class.registered.type == enumClass)
3671          {
3672             if(!source._class.registered.dataType)
3673                source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3674             if(!dest._class.registered.dataType)
3675                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3676
3677             if(MatchTypes(source._class.registered.dataType, dest._class.registered.dataType, conversions, null, null, true, false, false))
3678             {
3679                FreeType(source);
3680                source = sourceExp.expType = MkClassType(dest._class.string);
3681                source.refCount++;
3682
3683                //source.kind = classType;
3684                //source._class = dest._class;
3685             }
3686          }*/
3687
3688          if(_class && !strcmp(_class.fullName, "ecere::com::Class") && source.kind == pointerType && source.type && source.type.kind == charType && sourceExp.type == stringExp)
3689          {
3690             OldList * specs = MkList();
3691             Declarator decl;
3692             char string[1024];
3693
3694             ReadString(string, sourceExp.string);
3695             decl = SpecDeclFromString(string, specs, null);
3696
3697             FreeExpContents(sourceExp);
3698             FreeType(sourceExp.expType);
3699
3700             sourceExp.type = classExp;
3701             sourceExp._classExp.specifiers = specs;
3702             sourceExp._classExp.decl = decl;
3703             sourceExp.expType = dest;
3704             dest.refCount++;
3705
3706             FreeType(source);
3707             FreeType(dest);
3708             if(backupSourceExpType) FreeType(backupSourceExpType);
3709             return true;
3710          }
3711       }
3712       else if(source.kind == classType)
3713       {
3714          Class _class = source._class ? source._class.registered : null;
3715
3716          if(_class && (_class.type == unitClass || /*!strcmp(_class.fullName, "bool") || _class.type == enumClass || */_class.type == bitClass ))  // TOCHECK: enumClass, bitClass is new here...
3717          {
3718             /*
3719             if(dest.kind != classType)
3720             {
3721                // Testing this simpler piece of code... (Broke Units Conversion to no unit Logic)
3722                if(!source._class.registered.dataType)
3723                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3724
3725                FreeType(dest);
3726                dest = MkClassType(source._class.string);
3727                //if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, false, false))
3728                //   dest = MkClassType(source._class.string);
3729             }
3730             */
3731
3732             if(dest.kind != classType)
3733             {
3734                Type tempType { };
3735                Type tempDest, tempSource;
3736
3737                if(!source._class.registered.dataType)
3738                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3739
3740                for(; _class.base.type != systemClass; _class = _class.base);
3741                tempDest = source;
3742                tempSource = tempType;
3743                tempType.kind = classType;
3744                tempType._class = FindClass(_class.fullName);
3745                tempType.truth = source.truth;
3746                tempType.classObjectType = source.classObjectType;
3747
3748                if(tempType._class)
3749                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false, warnConst);
3750
3751                // PUT THIS BACK TESTING UNITS?
3752                if(conversions && conversions.last)
3753                {
3754                   ((Conversion)(conversions.last)).resultType = dest;
3755                   dest.refCount++;
3756                }
3757
3758                FreeType(sourceExp.expType);
3759                sourceExp.expType = MkClassType(_class.fullName);
3760                sourceExp.expType.truth = source.truth;
3761                sourceExp.expType.classObjectType = source.classObjectType;
3762
3763                // *** This if was commented out, put it back because "int a =^ Destroy()" shows up bool enum values in autocomplete ***
3764
3765                if(!sourceExp.destType)
3766                {
3767                   FreeType(sourceExp.destType);
3768                   sourceExp.destType = sourceExp.expType;
3769                   if(sourceExp.expType)
3770                      sourceExp.expType.refCount++;
3771                }
3772                //flag = true;
3773                //source = _class.dataType;
3774
3775
3776                // TOCHECK: TESTING THIS NEW CODE
3777                if(!_class.dataType)
3778                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3779                FreeType(dest);
3780                dest = MkClassType(source._class.string);
3781                dest.truth = source.truth;
3782                dest.classObjectType = source.classObjectType;
3783
3784                FreeType(source);
3785                source = _class.dataType;
3786                source.refCount++;
3787
3788                delete tempType;
3789             }
3790          }
3791       }
3792
3793       if(!flag)
3794       {
3795          if(MatchTypes(source, dest, conversions, null, null, true, true, false, false, warnConst))
3796          {
3797             FreeType(source);
3798             FreeType(dest);
3799             return true;
3800          }
3801       }
3802
3803       // Implicit Casts
3804       /*
3805       if(source.kind == classType)
3806       {
3807          Class _class = source._class.registered;
3808          if(_class.type == unitClass)
3809          {
3810             if(!_class.dataType)
3811                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3812             source = _class.dataType;
3813          }
3814       }*/
3815
3816       if(dest.kind == classType)
3817       {
3818          Class _class = dest._class ? dest._class.registered : null;
3819          bool fittingValue = false;
3820          if(_class && _class.type == enumClass)
3821          {
3822             Class enumClass = eSystem_FindClass(privateModule, "enum");
3823             EnumClassData c = ACCESS_CLASSDATA(_class, enumClass);
3824             if(c && value >= 0 && value <= c.largest)
3825                fittingValue = true;
3826          }
3827
3828          if(_class && !dest.truth && (_class.type == unitClass || fittingValue ||
3829             (/*_class.type == enumClass*/_class.type != structClass && !value && source.kind == intType) || _class.type == bitClass))   // TOCHECK: enumClass, bitClass is new here...
3830          {
3831             if(_class.type == normalClass || _class.type == noHeadClass)
3832             {
3833                Expression newExp { };
3834                *newExp = *sourceExp;
3835                if(sourceExp.destType) sourceExp.destType.refCount++;
3836                if(sourceExp.expType)  sourceExp.expType.refCount++;
3837                sourceExp.type = castExp;
3838                sourceExp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
3839                sourceExp.cast.exp = newExp;
3840                FreeType(sourceExp.expType);
3841                sourceExp.expType = null;
3842                ProcessExpressionType(sourceExp);
3843
3844                // In Debugger, this helps with addresses (e.g. null pointers) that end up casted to a void *: keeps a classType instead of a pointerType
3845                if(!inCompiler)
3846                {
3847                   FreeType(sourceExp.expType);
3848                   sourceExp.expType = dest;
3849                }
3850
3851                FreeType(source);
3852                if(inCompiler) FreeType(dest);
3853
3854                if(backupSourceExpType) FreeType(backupSourceExpType);
3855                return true;
3856             }
3857
3858             if(!_class.dataType)
3859                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3860             FreeType(dest);
3861             dest = _class.dataType;
3862             dest.refCount++;
3863          }
3864
3865          // Accept lower precision types for units, since we want to keep the unit type
3866          if(dest.kind == doubleType &&
3867             (source.kind == doubleType || source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType ||
3868              source.kind == charType || source.kind == _BoolType))
3869          {
3870             specs = MkListOne(MkSpecifier(DOUBLE));
3871          }
3872          else if(dest.kind == floatType &&
3873             (source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3874             source.kind == _BoolType || source.kind == doubleType))
3875          {
3876             specs = MkListOne(MkSpecifier(FLOAT));
3877          }
3878          else if(dest.kind == int64Type && (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3879             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3880          {
3881             specs = MkList();
3882             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3883             ListAdd(specs, MkSpecifier(INT64));
3884          }
3885          else if(dest.kind == intType && (source.kind == intType || source.kind == shortType || source.kind == charType ||
3886             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3887          {
3888             specs = MkList();
3889             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3890             ListAdd(specs, MkSpecifier(INT));
3891          }
3892          else if(dest.kind == shortType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType ||
3893             source.kind == floatType || source.kind == doubleType))
3894          {
3895             specs = MkList();
3896             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3897             ListAdd(specs, MkSpecifier(SHORT));
3898          }
3899          else if(dest.kind == charType && (source.kind == charType || source.kind == _BoolType || source.kind == shortType || source.kind == intType ||
3900             source.kind == floatType || source.kind == doubleType))
3901          {
3902             specs = MkList();
3903             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3904             ListAdd(specs, MkSpecifier(CHAR));
3905          }
3906          else
3907          {
3908             FreeType(source);
3909             FreeType(dest);
3910             if(backupSourceExpType)
3911             {
3912                // Failed to convert: revert previous exp type
3913                if(sourceExp.expType) FreeType(sourceExp.expType);
3914                sourceExp.expType = backupSourceExpType;
3915             }
3916             return false;
3917          }
3918       }
3919       else if(dest.kind == doubleType &&
3920          (source.kind == doubleType || source.kind == floatType || source.kind == int64Type || source.kind == intType || source.kind == enumType || source.kind == shortType ||
3921           source.kind == _BoolType || source.kind == charType))
3922       {
3923          specs = MkListOne(MkSpecifier(DOUBLE));
3924       }
3925       else if(dest.kind == floatType &&
3926          (source.kind == floatType || source.kind == enumType || source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3927       {
3928          specs = MkListOne(MkSpecifier(FLOAT));
3929       }
3930       else if(dest.kind == _BoolType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3931          (value == 1 || value == 0))
3932       {
3933          specs = MkList();
3934          ListAdd(specs, MkSpecifier(BOOL));
3935       }
3936       else if(dest.kind == charType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3937          (dest.isSigned ? (value >= -128 && value <= 127) : (value >= 0 && value <= 255)))
3938       {
3939          if(source.kind == intType)
3940          {
3941             FreeType(dest);
3942             FreeType(source);
3943             if(backupSourceExpType) FreeType(backupSourceExpType);
3944             return true;
3945          }
3946          else
3947          {
3948             specs = MkList();
3949             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3950             ListAdd(specs, MkSpecifier(CHAR));
3951          }
3952       }
3953       else if(dest.kind == shortType && (source.kind == enumType || source.kind == _BoolType || source.kind == charType || source.kind == shortType ||
3954          (source.kind == intType && (dest.isSigned ? (value >= -32768 && value <= 32767) : (value >= 0 && value <= 65535)))))
3955       {
3956          if(source.kind == intType)
3957          {
3958             FreeType(dest);
3959             FreeType(source);
3960             if(backupSourceExpType) FreeType(backupSourceExpType);
3961             return true;
3962          }
3963          else
3964          {
3965             specs = MkList();
3966             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3967             ListAdd(specs, MkSpecifier(SHORT));
3968          }
3969       }
3970       else if(dest.kind == intType && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType))
3971       {
3972          specs = MkList();
3973          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3974          ListAdd(specs, MkSpecifier(INT));
3975       }
3976       else if(dest.kind == int64Type && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType || source.kind == int64Type))
3977       {
3978          specs = MkList();
3979          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3980          ListAdd(specs, MkSpecifier(INT64));
3981       }
3982       else if(dest.kind == enumType &&
3983          (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3984       {
3985          specs = MkListOne(MkEnum(MkIdentifier(dest.enumName), null));
3986       }
3987       else
3988       {
3989          FreeType(source);
3990          FreeType(dest);
3991          if(backupSourceExpType)
3992          {
3993             // Failed to convert: revert previous exp type
3994             if(sourceExp.expType) FreeType(sourceExp.expType);
3995             sourceExp.expType = backupSourceExpType;
3996          }
3997          return false;
3998       }
3999
4000       if(!flag && !sourceExp.opDestType)
4001       {
4002          Expression newExp { };
4003          *newExp = *sourceExp;
4004          newExp.prev = null;
4005          newExp.next = null;
4006          if(sourceExp.destType) sourceExp.destType.refCount++;
4007          if(sourceExp.expType)  sourceExp.expType.refCount++;
4008
4009          sourceExp.type = castExp;
4010          if(realDest.kind == classType)
4011          {
4012             sourceExp.cast.typeName = QMkClass(realDest._class.string, null);
4013             FreeList(specs, FreeSpecifier);
4014          }
4015          else
4016             sourceExp.cast.typeName = MkTypeName(specs, null);
4017          if(newExp.type == opExp)
4018          {
4019             sourceExp.cast.exp = MkExpBrackets(MkListOne(newExp));
4020          }
4021          else
4022             sourceExp.cast.exp = newExp;
4023
4024          FreeType(sourceExp.expType);
4025          sourceExp.expType = null;
4026          ProcessExpressionType(sourceExp);
4027       }
4028       else
4029          FreeList(specs, FreeSpecifier);
4030
4031       FreeType(dest);
4032       FreeType(source);
4033       if(backupSourceExpType) FreeType(backupSourceExpType);
4034
4035       return true;
4036    }
4037    else
4038    {
4039       if(computedExp != nbExp)
4040       {
4041          FreeExpression(computedExp);
4042          computedExp = nbExp;
4043       }
4044
4045       while((sourceExp.type == bracketsExp || sourceExp.type == extensionExpressionExp) && sourceExp.list) sourceExp = sourceExp.list->last;
4046       if(sourceExp.type == identifierExp)
4047       {
4048          Identifier id = sourceExp.identifier;
4049          if(dest.kind == classType)
4050          {
4051             if(dest._class && dest._class.registered && dest._class.registered.type == enumClass)
4052             {
4053                Class _class = dest._class.registered;
4054                Class enumClass = eSystem_FindClass(privateModule, "enum");
4055                if(enumClass)
4056                {
4057                   for( ; _class && _class.type == ClassType::enumClass; _class = _class.base)
4058                   {
4059                      NamedLink64 value;
4060                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4061                      for(value = e.values.first; value; value = value.next)
4062                      {
4063                         if(!strcmp(value.name, id.string))
4064                            break;
4065                      }
4066                      if(value)
4067                      {
4068                         FreeType(sourceExp.expType);
4069
4070                         sourceExp.isConstant = true;
4071                         sourceExp.expType = MkClassType(_class.fullName);
4072                         if(inCompiler || inPreCompiler || inDebugger)
4073                         {
4074                            FreeExpContents(sourceExp);
4075
4076                            sourceExp.type = constantExp;
4077                            if(_class.dataTypeString && (!strcmp(_class.dataTypeString, "int") || !strcmp(_class.dataTypeString, "int64") || !strcmp(_class.dataTypeString, "short") || !strcmp(_class.dataTypeString, "char"))) // _class cannot be null here!
4078                               sourceExp.constant = PrintInt64(value.data);
4079                            else
4080                               sourceExp.constant = PrintUInt64(value.data);
4081                            //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
4082                         }
4083                         FreeType(dest);
4084                         return true;
4085                      }
4086                   }
4087                }
4088             }
4089          }
4090
4091          // Loop through all enum classes
4092          if(dest.classObjectType != typedObject && dest.kind == classType /*!= ellipsisType */&& MatchWithEnums_Module(privateModule, sourceExp, dest, id.string, conversions))
4093          {
4094             FreeType(dest);
4095             return true;
4096          }
4097       }
4098       FreeType(dest);
4099    }
4100    return false;
4101 }
4102
4103 #define TERTIARY(o, name, m, t, p) \
4104    static bool name(Expression exp, Operand op1, Operand op2, Operand op3)   \
4105    {                                                              \
4106       exp.type = constantExp;                                    \
4107       exp.string = p(op1.m ? op2.m : op3.m);                     \
4108       if(!exp.expType) \
4109          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4110       return true;                                                \
4111    }
4112
4113 #define BINARY(o, name, m, t, p) \
4114    static bool name(Expression exp, Operand op1, Operand op2)   \
4115    {                                                              \
4116       t value2 = op2.m;                                           \
4117       exp.type = constantExp;                                    \
4118       exp.string = p((t)(op1.m o value2));                     \
4119       if(!exp.expType) \
4120          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4121       return true;                                                \
4122    }
4123
4124 #define BINARY_DIVIDEINT(o, name, m, t, p) \
4125    static bool name(Expression exp, Operand op1, Operand op2)   \
4126    {                                                              \
4127       t value2 = op2.m;                                           \
4128       exp.type = constantExp;                                    \
4129       exp.string = p(value2 ? ((t)(op1.m o value2)) : 0);             \
4130       if(!exp.expType) \
4131          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4132       return true;                                                \
4133    }
4134
4135 #define BINARY_DIVIDEREAL(o, name, m, t, p) \
4136    static bool name(Expression exp, Operand op1, Operand op2)   \
4137    {                                                              \
4138       t value2 = op2.m;                                           \
4139       exp.type = constantExp;                                    \
4140       exp.string = p((t)(op1.m o value2));             \
4141       if(!exp.expType) \
4142          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4143       return true;                                                \
4144    }
4145
4146 #define UNARY(o, name, m, t, p) \
4147    static bool name(Expression exp, Operand op1)                \
4148    {                                                              \
4149       exp.type = constantExp;                                    \
4150       exp.string = p((t)(o op1.m));                                   \
4151       if(!exp.expType) \
4152          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4153       return true;                                                \
4154    }
4155
4156 #define OPERATOR_ALL(macro, o, name) \
4157    macro(o, Int##name, i, int, PrintInt) \
4158    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4159    macro(o, Int64##name, i64, int64, PrintInt64) \
4160    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4161    macro(o, Short##name, s, short, PrintShort) \
4162    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4163    macro(o, Char##name, c, char, PrintChar) \
4164    macro(o, UChar##name, uc, unsigned char, PrintUChar) \
4165    macro(o, Float##name, f, float, PrintFloat) \
4166    macro(o, Double##name, d, double, PrintDouble)
4167
4168 #define OPERATOR_INTTYPES(macro, o, name) \
4169    macro(o, Int##name, i, int, PrintInt) \
4170    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4171    macro(o, Int64##name, i64, int64, PrintInt64) \
4172    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4173    macro(o, Short##name, s, short, PrintShort) \
4174    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4175    macro(o, Char##name, c, char, PrintChar) \
4176    macro(o, UChar##name, uc, unsigned char, PrintUChar)
4177
4178 #define OPERATOR_REALTYPES(macro, o, name) \
4179    macro(o, Float##name, f, float, PrintFloat) \
4180    macro(o, Double##name, d, double, PrintDouble)
4181
4182 // binary arithmetic
4183 OPERATOR_ALL(BINARY, +, Add)
4184 OPERATOR_ALL(BINARY, -, Sub)
4185 OPERATOR_ALL(BINARY, *, Mul)
4186 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /, Div)
4187 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /, Div)
4188 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %, Mod)
4189
4190 // unary arithmetic
4191 OPERATOR_ALL(UNARY, -, Neg)
4192
4193 // unary arithmetic increment and decrement
4194 OPERATOR_ALL(UNARY, ++, Inc)
4195 OPERATOR_ALL(UNARY, --, Dec)
4196
4197 // binary arithmetic assignment
4198 OPERATOR_ALL(BINARY, =, Asign)
4199 OPERATOR_ALL(BINARY, +=, AddAsign)
4200 OPERATOR_ALL(BINARY, -=, SubAsign)
4201 OPERATOR_ALL(BINARY, *=, MulAsign)
4202 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /=, DivAsign)
4203 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /=, DivAsign)
4204 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %=, ModAsign)
4205
4206 // binary bitwise
4207 OPERATOR_INTTYPES(BINARY, &, BitAnd)
4208 OPERATOR_INTTYPES(BINARY, |, BitOr)
4209 OPERATOR_INTTYPES(BINARY, ^, BitXor)
4210 OPERATOR_INTTYPES(BINARY, <<, LShift)
4211 OPERATOR_INTTYPES(BINARY, >>, RShift)
4212
4213 // unary bitwise
4214 OPERATOR_INTTYPES(UNARY, ~, BitNot)
4215
4216 // binary bitwise assignment
4217 OPERATOR_INTTYPES(BINARY, &=, AndAsign)
4218 OPERATOR_INTTYPES(BINARY, |=, OrAsign)
4219 OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
4220 OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
4221 OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
4222
4223 // unary logical negation
4224 OPERATOR_INTTYPES(UNARY, !, Not)
4225
4226 // binary logical equality
4227 OPERATOR_ALL(BINARY, ==, Equ)
4228 OPERATOR_ALL(BINARY, !=, Nqu)
4229
4230 // binary logical
4231 OPERATOR_ALL(BINARY, &&, And)
4232 OPERATOR_ALL(BINARY, ||, Or)
4233
4234 // binary logical relational
4235 OPERATOR_ALL(BINARY, >, Grt)
4236 OPERATOR_ALL(BINARY, <, Sma)
4237 OPERATOR_ALL(BINARY, >=, GrtEqu)
4238 OPERATOR_ALL(BINARY, <=, SmaEqu)
4239
4240 // tertiary condition operator
4241 OPERATOR_INTTYPES(TERTIARY, ?, Cond)
4242
4243 //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
4244 #define OPERATOR_TABLE_ALL(name, type) \
4245     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, type##Mod, \
4246                           type##Neg, \
4247                           type##Inc, type##Dec, \
4248                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, type##ModAsign, \
4249                           type##BitAnd, type##BitOr, type##BitXor, type##LShift, type##RShift, \
4250                           type##BitNot, \
4251                           type##AndAsign, type##OrAsign, type##XorAsign, type##LShiftAsign, type##RShiftAsign, \
4252                           type##Not, \
4253                           type##Equ, type##Nqu, \
4254                           type##And, type##Or, \
4255                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu, type##Cond \
4256                         }; \
4257
4258 #define OPERATOR_TABLE_INTTYPES(name, type) \
4259     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, null, \
4260                           type##Neg, \
4261                           type##Inc, type##Dec, \
4262                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, null, \
4263                           null, null, null, null, null, \
4264                           null, \
4265                           null, null, null, null, null, \
4266                           null, \
4267                           type##Equ, type##Nqu, \
4268                           type##And, type##Or, \
4269                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu \
4270                         }; \
4271
4272 OPERATOR_TABLE_ALL(int, Int)
4273 OPERATOR_TABLE_ALL(uint, UInt)
4274 OPERATOR_TABLE_ALL(int64, Int64)
4275 OPERATOR_TABLE_ALL(uint64, UInt64)
4276 OPERATOR_TABLE_ALL(short, Short)
4277 OPERATOR_TABLE_ALL(ushort, UShort)
4278 OPERATOR_TABLE_INTTYPES(float, Float)
4279 OPERATOR_TABLE_INTTYPES(double, Double)
4280 OPERATOR_TABLE_ALL(char, Char)
4281 OPERATOR_TABLE_ALL(uchar, UChar)
4282
4283 //OpTable intOps =    {    IntAdd,    IntSub,    IntMul,    IntDiv,    IntMod,    IntExp,    IntNot,    IntBwn,    IntOr,    IntAnd,    IntEqu,    IntNqu,    IntGrt,    IntSma,    IntGrtEqu,    IntSmaEqu,    IntNeg,    IntLBitSft,    IntRBitSft };
4284 //OpTable uintOps =   {   UIntAdd,   UIntSub,   UIntMul,   UIntDiv,   UIntMod,   UIntExp,   UIntNot,   UIntBwn,   UIntOr,   UIntAnd,   UIntEqu,   UIntNqu,   UIntGrt,   UIntSma,   UIntGrtEqu,   UIntSmaEqu,   UIntNeg,   UIntLBitSft,   UIntRBitSft };
4285 //OpTable shortOps =  {  ShortAdd,  ShortSub,  ShortMul,  ShortDiv,  ShortMod,  ShortExp,  ShortNot,  ShortBwn,  ShortOr,  ShortAnd,  ShortEqu,  ShortNqu,  ShortGrt,  ShortSma,  ShortGrtEqu,  ShortSmaEqu,  ShortNeg,  ShortLBitSft,  ShortRBitSft };
4286 //OpTable ushortOps = { UShortAdd, UShortSub, UShortMul, UShortDiv, UShortMod, UShortExp, UShortNot, UShortBwn, UShortOr, UShortAnd, UShortEqu, UShortNqu, UShortGrt, UShortSma, UShortGrtEqu, UShortSmaEqu, UShortNeg, UShortLBitSft, UShortRBitSft };
4287 //OpTable floatOps =  {  FloatAdd,  FloatSub,  FloatMul,  FloatDiv,      null,      null,      null,      null,     null,      null,  FloatEqu,  FloatNqu,  FloatGrt,  FloatSma,  FloatGrtEqu,  FloatSmaEqu,  FloatNeg,          null,          null };
4288 //OpTable doubleOps = { DoubleAdd, DoubleSub, DoubleMul, DoubleDiv,      null,      null,      null,      null,     null,      null, DoubleEqu, DoubleNqu, DoubleGrt, DoubleSma, DoubleGrtEqu, DoubleSmaEqu, DoubleNeg,          null,          null };
4289 //OpTable charOps =   {   CharAdd,   CharSub,   CharMul,   CharDiv,   CharMod,   CharExp,   CharNot,   CharBwn,   CharOr,   CharAnd,   CharEqu,   CharNqu,   CharGrt,   CharSma,   CharGrtEqu,   CharSmaEqu,   CharNeg,   CharLBitSft,   CharRBitSft };
4290 //OpTable ucharOps =  {  UCharAdd,  UCharSub,  UCharMul,  UCharDiv,  UCharMod,  UCharExp,  UCharNot,  UCharBwn,  UCharOr,  UCharAnd,  UCharEqu,  UCharNqu,  UCharGrt,  UCharSma,  UCharGrtEqu,  UCharSmaEqu,  UCharNeg,  UCharLBitSft,  UCharRBitSft };
4291
4292 public void ReadString(char * output,  char * string)
4293 {
4294    int len = strlen(string);
4295    int c,d = 0;
4296    bool quoted = false, escaped = false;
4297    for(c = 0; c<len; c++)
4298    {
4299       char ch = string[c];
4300       if(escaped)
4301       {
4302          switch(ch)
4303          {
4304             case 'n': output[d] = '\n'; break;
4305             case 't': output[d] = '\t'; break;
4306             case 'a': output[d] = '\a'; break;
4307             case 'b': output[d] = '\b'; break;
4308             case 'f': output[d] = '\f'; break;
4309             case 'r': output[d] = '\r'; break;
4310             case 'v': output[d] = '\v'; break;
4311             case '\\': output[d] = '\\'; break;
4312             case '\"': output[d] = '\"'; break;
4313             case '\'': output[d] = '\''; break;
4314             default: output[d] = ch;
4315          }
4316          d++;
4317          escaped = false;
4318       }
4319       else
4320       {
4321          if(ch == '\"')
4322             quoted ^= true;
4323          else if(quoted)
4324          {
4325             if(ch == '\\')
4326                escaped = true;
4327             else
4328                output[d++] = ch;
4329          }
4330       }
4331    }
4332    output[d] = '\0';
4333 }
4334
4335 // String Unescape Copy
4336
4337 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
4338 // This is the same as ReadString above (which also misses numeric escape codes) except it doesn't handle external quotes
4339 public int UnescapeString(char * d, char * s, int len)
4340 {
4341    int j = 0, k = 0;
4342    char ch;
4343    while(j < len && (ch = s[j]))
4344    {
4345       switch(ch)
4346       {
4347          case '\\':
4348             switch((ch = s[++j]))
4349             {
4350                case 'n': d[k] = '\n'; break;
4351                case 't': d[k] = '\t'; break;
4352                case 'a': d[k] = '\a'; break;
4353                case 'b': d[k] = '\b'; break;
4354                case 'f': d[k] = '\f'; break;
4355                case 'r': d[k] = '\r'; break;
4356                case 'v': d[k] = '\v'; break;
4357                case '\\': d[k] = '\\'; break;
4358                case '\"': d[k] = '\"'; break;
4359                case '\'': d[k] = '\''; break;
4360                default: d[k] = '\\'; d[k] = ch;
4361             }
4362             break;
4363          default:
4364             d[k] = ch;
4365       }
4366       j++, k++;
4367    }
4368    d[k] = '\0';
4369    return k;
4370 }
4371
4372 public char * OffsetEscapedString(char * s, int len, int offset)
4373 {
4374    char ch;
4375    int j = 0, k = 0;
4376    while(j < len && k < offset && (ch = s[j]))
4377    {
4378       if(ch == '\\') ++j;
4379       j++, k++;
4380    }
4381    return (k == offset) ? s + j : null;
4382 }
4383
4384 public Operand GetOperand(Expression exp)
4385 {
4386    Operand op { };
4387    Type type = exp.expType;
4388    if(type)
4389    {
4390       while(type.kind == classType &&
4391          type._class.registered && (type._class.registered.type == bitClass || type._class.registered.type == unitClass || type._class.registered.type == enumClass))
4392       {
4393          if(!type._class.registered.dataType)
4394             type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
4395          type = type._class.registered.dataType;
4396
4397       }
4398       if(exp.type == stringExp && op.kind == pointerType)
4399       {
4400          op.ui64 = (uint64)(uintptr)exp.string;
4401          op.kind = pointerType;
4402          op.ops = uint64Ops;
4403       }
4404       else if(exp.isConstant && exp.type == constantExp)
4405       {
4406          op.kind = type.kind;
4407          op.type = type;
4408
4409          switch(op.kind)
4410          {
4411             case _BoolType:
4412             case charType:
4413             {
4414                if(exp.constant[0] == '\'')
4415                {
4416                   op.c = exp.constant[1];
4417                   op.ops = charOps;
4418                }
4419                else if(type.isSigned)
4420                {
4421                   op.c = (char)strtol(exp.constant, null, 0);
4422                   op.ops = charOps;
4423                }
4424                else
4425                {
4426                   op.uc = (unsigned char)strtoul(exp.constant, null, 0);
4427                   op.ops = ucharOps;
4428                }
4429                break;
4430             }
4431             case shortType:
4432                if(exp.constant[0] == '\'')
4433                {
4434                   op.s = exp.constant[1];
4435                   op.ops = shortOps;
4436                }
4437                else if(type.isSigned)
4438                {
4439                   op.s = (short)strtol(exp.constant, null, 0);
4440                   op.ops = shortOps;
4441                }
4442                else
4443                {
4444                   op.us = (unsigned short)strtoul(exp.constant, null, 0);
4445                   op.ops = ushortOps;
4446                }
4447                break;
4448             case intType:
4449             case longType:
4450                if(exp.constant[0] == '\'')
4451                {
4452                   op.i = exp.constant[1];
4453                   op.ops = intOps;
4454                }
4455                else if(type.isSigned)
4456                {
4457                   op.i = (int)strtol(exp.constant, null, 0);
4458                   op.ops = intOps;
4459                }
4460                else
4461                {
4462                   op.ui = (unsigned int)strtoul(exp.constant, null, 0);
4463                   op.ops = uintOps;
4464                }
4465                op.kind = intType;
4466                break;
4467             case int64Type:
4468                if(type.isSigned)
4469                {
4470                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4471                   op.ops = int64Ops;
4472                }
4473                else
4474                {
4475                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4476                   op.ops = uint64Ops;
4477                }
4478                op.kind = int64Type;
4479                break;
4480             case intPtrType:
4481                if(type.isSigned)
4482                {
4483                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4484                   op.ops = int64Ops;
4485                }
4486                else
4487                {
4488                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4489                   op.ops = uint64Ops;
4490                }
4491                op.kind = int64Type;
4492                break;
4493             case intSizeType:
4494                if(type.isSigned)
4495                {
4496                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4497                   op.ops = int64Ops;
4498                }
4499                else
4500                {
4501                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4502                   op.ops = uint64Ops;
4503                }
4504                op.kind = int64Type;
4505                break;
4506             case floatType:
4507                if(!strcmp(exp.constant, "inf")) op.f = float::inf();
4508                else if(!strcmp(exp.constant, "-inf")) op.f = -float::inf();
4509                else if(!strcmp(exp.constant, "nan")) op.f = float::nan();
4510                else if(!strcmp(exp.constant, "-nan")) op.f = -float::nan();
4511                else
4512                   op.f = (float)strtod(exp.constant, null);
4513                op.ops = floatOps;
4514                break;
4515             case doubleType:
4516                if(!strcmp(exp.constant, "inf")) op.d = double::inf();
4517                else if(!strcmp(exp.constant, "-inf")) op.d = -double::inf();
4518                else if(!strcmp(exp.constant, "nan")) op.d = double::nan();
4519                else if(!strcmp(exp.constant, "-nan")) op.d = -double::nan();
4520                else
4521                   op.d = (double)strtod(exp.constant, null);
4522                op.ops = doubleOps;
4523                break;
4524             //case classType:    For when we have operator overloading...
4525             // Pointer additions
4526             //case functionType:
4527             case arrayType:
4528             case pointerType:
4529             case classType:
4530                op.ui64 = _strtoui64(exp.constant, null, 0);
4531                op.kind = pointerType;
4532                op.ops = uint64Ops;
4533                // op.ptrSize =
4534                break;
4535          }
4536       }
4537    }
4538    return op;
4539 }
4540
4541 static int64 GetEnumValue(Class _class, void * ptr)
4542 {
4543    int64 v = 0;
4544    switch(_class.typeSize)
4545    {
4546       case 8:
4547          if(!strcmp(_class.dataTypeString, "uint64"))
4548             v = (int64)*(uint64 *)ptr;
4549          else
4550             v = (int64)*(int64 *)ptr;
4551          break;
4552       case 4:
4553          if(!strcmp(_class.dataTypeString, "uint"))
4554             v = (int64)*(uint *)ptr;
4555          else
4556             v = (int64)*(int *)ptr;
4557          break;
4558       case 2:
4559          if(!strcmp(_class.dataTypeString, "uint16"))
4560             v = (int64)*(uint16 *)ptr;
4561          else
4562             v = (int64)*(short *)ptr;
4563          break;
4564       case 1:
4565          if(!strcmp(_class.dataTypeString, "byte"))
4566             v = (int64)*(byte *)ptr;
4567          else
4568             v = (int64)*(char *)ptr;
4569          break;
4570    }
4571    return v;
4572 }
4573
4574 static __attribute__((unused)) void UnusedFunction()
4575 {
4576    int a;
4577    a.OnGetString(0,0,0);
4578 }
4579 default:
4580 extern int __ecereVMethodID_class_OnGetString;
4581 public:
4582
4583 static void PopulateInstanceProcessMember(Instantiation inst, OldList * memberList, DataMember parentDataMember, uint offset)
4584 {
4585    DataMember dataMember;
4586    for(dataMember = parentDataMember.members.first; dataMember; dataMember = dataMember.next)
4587    {
4588       if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4589          PopulateInstanceProcessMember(inst, memberList, dataMember, offset + dataMember.offset);
4590       else
4591       {
4592          Expression exp { };
4593          MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4594          Type type;
4595          void * ptr = inst.data + dataMember.offset + offset;
4596          char * result = null;
4597          exp.loc = member.loc = inst.loc;
4598          ((Identifier)member.identifiers->first).loc = inst.loc;
4599
4600          if(!dataMember.dataType)
4601             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4602          type = dataMember.dataType;
4603          if(type.kind == classType)
4604          {
4605             Class _class = type._class.registered;
4606             if(_class.type == enumClass)
4607             {
4608                Class enumClass = eSystem_FindClass(privateModule, "enum");
4609                if(enumClass)
4610                {
4611                   EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4612                   NamedLink64 item;
4613                   for(item = e.values.first; item; item = item.next)
4614                   {
4615                      if(item.data == GetEnumValue(_class, ptr))
4616                      {
4617                         result = item.name;
4618                         break;
4619                      }
4620                   }
4621                   if(result)
4622                   {
4623                      exp.identifier = MkIdentifier(result);
4624                      exp.type = identifierExp;
4625                      exp.destType = MkClassType(_class.fullName);
4626                      ProcessExpressionType(exp);
4627                   }
4628                }
4629             }
4630             if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4631             {
4632                if(!_class.dataType)
4633                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4634                type = _class.dataType;
4635             }
4636          }
4637          if(!result)
4638          {
4639             switch(type.kind)
4640             {
4641                case floatType:
4642                {
4643                   FreeExpContents(exp);
4644
4645                   exp.constant = PrintFloat(*(float*)ptr);
4646                   exp.type = constantExp;
4647                   break;
4648                }
4649                case doubleType:
4650                {
4651                   FreeExpContents(exp);
4652
4653                   exp.constant = PrintDouble(*(double*)ptr);
4654                   exp.type = constantExp;
4655                   break;
4656                }
4657                case intType:
4658                {
4659                   FreeExpContents(exp);
4660
4661                   exp.constant = PrintInt(*(int*)ptr);
4662                   exp.type = constantExp;
4663                   break;
4664                }
4665                case int64Type:
4666                {
4667                   FreeExpContents(exp);
4668
4669                   exp.constant = PrintInt64(*(int64*)ptr);
4670                   exp.type = constantExp;
4671                   break;
4672                }
4673                case intPtrType:
4674                {
4675                   FreeExpContents(exp);
4676                   // TODO: This should probably use proper type
4677                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4678                   exp.type = constantExp;
4679                   break;
4680                }
4681                case intSizeType:
4682                {
4683                   FreeExpContents(exp);
4684                   // TODO: This should probably use proper type
4685                   exp.constant = PrintInt64((int64)*(intsize*)ptr);
4686                   exp.type = constantExp;
4687                   break;
4688                }
4689                default:
4690                   Compiler_Error($"Unhandled type populating instance\n");
4691             }
4692          }
4693          ListAdd(memberList, member);
4694       }
4695
4696       if(parentDataMember.type == unionMember)
4697          break;
4698    }
4699 }
4700
4701 void PopulateInstance(Instantiation inst)
4702 {
4703    Symbol classSym = inst._class.symbol; // FindClass(inst._class.name);
4704    Class _class = classSym.registered;
4705    DataMember dataMember;
4706    OldList * memberList = MkList();
4707    // Added this check and ->Add to prevent memory leaks on bad code
4708    if(!inst.members)
4709       inst.members = MkListOne(MkMembersInitList(memberList));
4710    else
4711       inst.members->Add(MkMembersInitList(memberList));
4712    for(dataMember = _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
4713    {
4714       if(!dataMember.isProperty)
4715       {
4716          if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4717             PopulateInstanceProcessMember(inst, memberList, dataMember, dataMember.offset);
4718          else
4719          {
4720             Expression exp { };
4721             MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4722             Type type;
4723             void * ptr = inst.data + dataMember.offset;
4724             char * result = null;
4725
4726             exp.loc = member.loc = inst.loc;
4727             ((Identifier)member.identifiers->first).loc = inst.loc;
4728
4729             if(!dataMember.dataType)
4730                dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4731             type = dataMember.dataType;
4732             if(type.kind == classType)
4733             {
4734                Class _class = type._class.registered;
4735                if(_class.type == enumClass)
4736                {
4737                   Class enumClass = eSystem_FindClass(privateModule, "enum");
4738                   if(enumClass)
4739                   {
4740                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4741                      NamedLink64 item;
4742                      for(item = e.values.first; item; item = item.next)
4743                      {
4744                         if(item.data == GetEnumValue(_class, ptr))
4745                         {
4746                            result = item.name;
4747                            break;
4748                         }
4749                      }
4750                   }
4751                   if(result)
4752                   {
4753                      exp.identifier = MkIdentifier(result);
4754                      exp.type = identifierExp;
4755                      exp.destType = MkClassType(_class.fullName);
4756                      ProcessExpressionType(exp);
4757                   }
4758                }
4759                if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4760                {
4761                   if(!_class.dataType)
4762                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4763                   type = _class.dataType;
4764                }
4765             }
4766             if(!result)
4767             {
4768                switch(type.kind)
4769                {
4770                   case floatType:
4771                   {
4772                      exp.constant = PrintFloat(*(float*)ptr);
4773                      exp.type = constantExp;
4774                      break;
4775                   }
4776                   case doubleType:
4777                   {
4778                      exp.constant = PrintDouble(*(double*)ptr);
4779                      exp.type = constantExp;
4780                      break;
4781                   }
4782                   case intType:
4783                   {
4784                      exp.constant = PrintInt(*(int*)ptr);
4785                      exp.type = constantExp;
4786                      break;
4787                   }
4788                   case int64Type:
4789                   {
4790                      exp.constant = PrintInt64(*(int64*)ptr);
4791                      exp.type = constantExp;
4792                      break;
4793                   }
4794                   case intPtrType:
4795                   {
4796                      exp.constant = PrintInt64((int64)*(intptr*)ptr);
4797                      exp.type = constantExp;
4798                      break;
4799                   }
4800                   default:
4801                      Compiler_Error($"Unhandled type populating instance\n");
4802                }
4803             }
4804             ListAdd(memberList, member);
4805          }
4806       }
4807    }
4808 }
4809
4810 void ComputeInstantiation(Expression exp)
4811 {
4812    Instantiation inst = exp.instance;
4813    MembersInit members;
4814    Symbol classSym = inst._class ? inst._class.symbol : null; // FindClass(inst._class.name);
4815    Class _class = classSym ? classSym.registered : null;
4816    DataMember curMember = null;
4817    Class curClass = null;
4818    DataMember subMemberStack[256];
4819    int subMemberStackPos = 0;
4820    uint64 bits = 0;
4821
4822    if(_class && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass ))
4823    {
4824       // Don't recompute the instantiation...
4825       // Non Simple classes will have become constants by now
4826       if(inst.data)
4827          return;
4828
4829       if(_class.type == normalClass || _class.type == noHeadClass)
4830       {
4831          inst.data = (byte *)eInstance_New(_class);
4832          if(_class.type == normalClass)
4833             ((Instance)inst.data)._refCount++;
4834       }
4835       else
4836          inst.data = new0 byte[_class.structSize];
4837    }
4838
4839    if(inst.members)
4840    {
4841       for(members = inst.members->first; members; members = members.next)
4842       {
4843          switch(members.type)
4844          {
4845             case dataMembersInit:
4846             {
4847                if(members.dataMembers)
4848                {
4849                   MemberInit member;
4850                   for(member = members.dataMembers->first; member; member = member.next)
4851                   {
4852                      Identifier ident = member.identifiers ? member.identifiers->first : null;
4853                      bool found = false;
4854
4855                      Property prop = null;
4856                      DataMember dataMember = null;
4857                      uint dataMemberOffset;
4858
4859                      if(!ident)
4860                      {
4861                         eClass_FindNextMember(_class, &curClass, &curMember, subMemberStack, &subMemberStackPos);
4862                         if(curMember)
4863                         {
4864                            if(curMember.isProperty)
4865                               prop = (Property)curMember;
4866                            else
4867                            {
4868                               dataMember = curMember;
4869
4870                               // CHANGED THIS HERE
4871                               eClass_FindDataMemberAndOffset(_class, dataMember.name, &dataMemberOffset, privateModule, null, null);
4872
4873                               // 2013/17/29 -- It seems that this was missing here!
4874                               if(_class.type == normalClass)
4875                                  dataMemberOffset += _class.base.structSize;
4876                               // dataMemberOffset = dataMember.offset;
4877                            }
4878                            found = true;
4879                         }
4880                      }
4881                      else
4882                      {
4883                         prop = eClass_FindProperty(_class, ident.string, privateModule);
4884                         if(prop)
4885                         {
4886                            found = true;
4887                            if(prop.memberAccess == publicAccess)
4888                            {
4889                               curMember = (DataMember)prop;
4890                               curClass = prop._class;
4891                            }
4892                         }
4893                         else
4894                         {
4895                            DataMember _subMemberStack[256];
4896                            int _subMemberStackPos = 0;
4897
4898                            // FILL MEMBER STACK
4899                            dataMember = eClass_FindDataMemberAndOffset(_class, ident.string, &dataMemberOffset, privateModule, _subMemberStack, &_subMemberStackPos);
4900
4901                            if(dataMember)
4902                            {
4903                               found = true;
4904                               if(dataMember.memberAccess == publicAccess)
4905                               {
4906                                  curMember = dataMember;
4907                                  curClass = dataMember._class;
4908                                  memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
4909                                  subMemberStackPos = _subMemberStackPos;
4910                               }
4911                            }
4912                         }
4913                      }
4914
4915                      if(found && member.initializer && member.initializer.type == expInitializer)
4916                      {
4917                         Expression value = member.initializer.exp;
4918                         Type type = null;
4919                         bool deepMember = false;
4920                         if(prop)
4921                         {
4922                            type = prop.dataType;
4923                         }
4924                         else if(dataMember)
4925                         {
4926                            if(!dataMember.dataType)
4927                               dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4928
4929                            type = dataMember.dataType;
4930                         }
4931
4932                         if(ident && ident.next)
4933                         {
4934                            deepMember = true;
4935
4936                            // for(; ident && type; ident = ident.next)
4937                            for(ident = ident.next; ident && type; ident = ident.next)
4938                            {
4939                               if(type.kind == classType)
4940                               {
4941                                  prop = eClass_FindProperty(type._class.registered,
4942                                     ident.string, privateModule);
4943                                  if(prop)
4944                                     type = prop.dataType;
4945                                  else
4946                                  {
4947                                     dataMember = eClass_FindDataMemberAndOffset(type._class.registered,
4948                                        ident.string, &dataMemberOffset, privateModule, null, null);
4949                                     if(dataMember)
4950                                        type = dataMember.dataType;
4951                                  }
4952                               }
4953                               else if(type.kind == structType || type.kind == unionType)
4954                               {
4955                                  Type memberType;
4956                                  for(memberType = type.members.first; memberType; memberType = memberType.next)
4957                                  {
4958                                     if(!strcmp(memberType.name, ident.string))
4959                                     {
4960                                        type = memberType;
4961                                        break;
4962                                     }
4963                                  }
4964                               }
4965                            }
4966                         }
4967                         if(value)
4968                         {
4969                            FreeType(value.destType);
4970                            value.destType = type;
4971                            if(type) type.refCount++;
4972                            ComputeExpression(value);
4973                         }
4974                         if(!deepMember && type && value && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass /*&& value.expType.kind == type.kind*/))
4975                         {
4976                            if(type.kind == classType)
4977                            {
4978                               Class _class = type._class.registered;
4979                               if(_class && (_class.type == bitClass || _class.type == unitClass || _class.type == enumClass))
4980                               {
4981                                  if(!_class.dataType)
4982                                     _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4983                                  type = _class.dataType;
4984                               }
4985                            }
4986
4987                            if(dataMember)
4988                            {
4989                               void * ptr = inst.data + dataMemberOffset;
4990
4991                               if(value.type == constantExp)
4992                               {
4993                                  switch(type.kind)
4994                                  {
4995                                     case intType:
4996                                     {
4997                                        GetInt(value, (int*)ptr);
4998                                        break;
4999                                     }
5000                                     case int64Type:
5001                                     {
5002                                        GetInt64(value, (int64*)ptr);
5003                                        break;
5004                                     }
5005                                     case intPtrType:
5006                                     {
5007                                        GetIntPtr(value, (intptr*)ptr);
5008                                        break;
5009                                     }
5010                                     case intSizeType:
5011                                     {
5012                                        GetIntSize(value, (intsize*)ptr);
5013                                        break;
5014                                     }
5015                                     case floatType:
5016                                     {
5017                                        GetFloat(value, (float*)ptr);
5018                                        break;
5019                                     }
5020                                     case doubleType:
5021                                     {
5022                                        GetDouble(value, (double *)ptr);
5023                                        break;
5024                                     }
5025                                  }
5026                               }
5027                               else if(value.type == instanceExp)
5028                               {
5029                                  if(type.kind == classType)
5030                                  {
5031                                     Class _class = type._class.registered;
5032                                     if(_class.type == structClass)
5033                                     {
5034                                        ComputeTypeSize(type);
5035                                        if(value.instance.data)
5036                                           memcpy(ptr, value.instance.data, type.size);
5037                                     }
5038                                  }
5039                               }
5040                            }
5041                            else if(prop && prop.Set != (void *)(intptr)1)
5042                            {
5043                               if(value.type == instanceExp && value.instance.data)
5044                               {
5045                                  if(type.kind == classType)
5046                                  {
5047                                     Class _class = type._class.registered;
5048                                     if(_class && (_class.type != normalClass || eClass_IsDerived(((Instance)value.instance.data)._class, _class)))
5049                                     {
5050                                        void (*Set)(void *, void *) = (void *)prop.Set;
5051                                        Set(inst.data, value.instance.data);
5052                                        PopulateInstance(inst);
5053                                     }
5054                                  }
5055                               }
5056                               else if(value.type == constantExp)
5057                               {
5058                                  switch(type.kind)
5059                                  {
5060                                     case doubleType:
5061                                     {
5062                                        void (*Set)(void *, double) = (void *)prop.Set;
5063                                        Set(inst.data, strtod(value.constant, null) );
5064                                        break;
5065                                     }
5066                                     case floatType:
5067                                     {
5068                                        void (*Set)(void *, float) = (void *)prop.Set;
5069                                        Set(inst.data, (float)(strtod(value.constant, null)));
5070                                        break;
5071                                     }
5072                                     case intType:
5073                                     {
5074                                        void (*Set)(void *, int) = (void *)prop.Set;
5075                                        Set(inst.data, (int)strtol(value.constant, null, 0));
5076                                        break;
5077                                     }
5078                                     case int64Type:
5079                                     {
5080                                        void (*Set)(void *, int64) = (void *)prop.Set;
5081                                        Set(inst.data, _strtoi64(value.constant, null, 0));
5082                                        break;
5083                                     }
5084                                     case intPtrType:
5085                                     {
5086                                        void (*Set)(void *, intptr) = (void *)prop.Set;
5087                                        Set(inst.data, (intptr)_strtoi64(value.constant, null, 0));
5088                                        break;
5089                                     }
5090                                     case intSizeType:
5091                                     {
5092                                        void (*Set)(void *, intsize) = (void *)prop.Set;
5093                                        Set(inst.data, (intsize)_strtoi64(value.constant, null, 0));
5094                                        break;
5095                                     }
5096                                  }
5097                               }
5098                               else if(value.type == stringExp)
5099                               {
5100                                  char temp[1024];
5101                                  ReadString(temp, value.string);
5102                                  ((void (*)(void *, void *))(void *)prop.Set)(inst.data, temp);
5103                               }
5104                            }
5105                         }
5106                         else if(!deepMember && type && _class.type == unitClass)
5107                         {
5108                            if(prop)
5109                            {
5110                               // Only support converting units to units for now...
5111                               if(value.type == constantExp)
5112                               {
5113                                  if(type.kind == classType)
5114                                  {
5115                                     Class _class = type._class.registered;
5116                                     if(_class.type == unitClass)
5117                                     {
5118                                        if(!_class.dataType)
5119                                           _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5120                                        type = _class.dataType;
5121                                     }
5122                                  }
5123                                  // TODO: Assuming same base type for units...
5124                                  switch(type.kind)
5125                                  {
5126                                     case floatType:
5127                                     {
5128                                        float fValue;
5129                                        float (*Set)(float) = (void *)prop.Set;
5130                                        GetFloat(member.initializer.exp, &fValue);
5131                                        exp.constant = PrintFloat(Set(fValue));
5132                                        exp.type = constantExp;
5133                                        break;
5134                                     }
5135                                     case doubleType:
5136                                     {
5137                                        double dValue;
5138                                        double (*Set)(double) = (void *)prop.Set;
5139                                        GetDouble(member.initializer.exp, &dValue);
5140                                        exp.constant = PrintDouble(Set(dValue));
5141                                        exp.type = constantExp;
5142                                        break;
5143                                     }
5144                                  }
5145                               }
5146                            }
5147                         }
5148                         else if(!deepMember && type && _class.type == bitClass)
5149                         {
5150                            if(prop)
5151                            {
5152                               if(value.type == instanceExp && value.instance.data)
5153                               {
5154                                  unsigned int (*Set)(void *) = (void *)prop.Set;
5155                                  bits = Set(value.instance.data);
5156                               }
5157                               else if(value.type == constantExp)
5158                               {
5159                               }
5160                            }
5161                            else if(dataMember)
5162                            {
5163                               BitMember bitMember = (BitMember) dataMember;
5164                               Type type;
5165                               uint64 part = 0;
5166                               bits = (bits & ~bitMember.mask);
5167                               if(!bitMember.dataType)
5168                                  bitMember.dataType = ProcessTypeString(bitMember.dataTypeString, false);
5169                               type = bitMember.dataType;
5170                               if(type.kind == classType && type._class && type._class.registered)
5171                               {
5172                                  if(!type._class.registered.dataType)
5173                                     type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
5174                                  type = type._class.registered.dataType;
5175                               }
5176                               switch(type.kind)
5177                               {
5178                                  case _BoolType:
5179                                  case charType:       { byte v; type.isSigned ? GetChar(value, (char *)&v) : GetUChar(value, &v); part = (uint64)v; break; }
5180                                  case shortType:      { uint16 v; type.isSigned ? GetShort(value, (short *)&v) : GetUShort(value, &v); part = (uint64)v; break; }
5181                                  case intType:
5182                                  case longType:       { uint v; type.isSigned ? GetInt(value, (int *)&v) : GetUInt(value, &v); part = (uint64)v; break; }
5183                                  case int64Type:      { uint64 v; type.isSigned ? GetInt64(value, (int64 *)&v) : GetUInt64(value, &v); part = (uint64)v; break; }
5184                                  case intPtrType:     { uintptr v; type.isSigned ? GetIntPtr(value, (intptr *)&v) : GetUIntPtr(value, &v); part = (uint64)v; break; }
5185                                  case intSizeType:    { uintsize v; type.isSigned ? GetIntSize(value, (intsize *)&v) : GetUIntSize(value, &v); part = (uint64)v; break; }
5186                               }
5187                               bits |= part << bitMember.pos;
5188                            }
5189                         }
5190                      }
5191                      else
5192                      {
5193                         if(_class && _class.type == unitClass)
5194                         {
5195                            ComputeExpression(member.initializer.exp);
5196                            exp.constant = member.initializer.exp.constant;
5197                            exp.type = constantExp;
5198
5199                            member.initializer.exp.constant = null;
5200                         }
5201                      }
5202                   }
5203                }
5204                break;
5205             }
5206          }
5207       }
5208    }
5209    if(_class && _class.type == bitClass)
5210    {
5211       exp.constant = PrintHexUInt(bits);
5212       exp.type = constantExp;
5213    }
5214    if(exp.type != instanceExp)
5215    {
5216       FreeInstance(inst);
5217    }
5218 }
5219
5220 static bool Promote(Operand op, TypeKind kind, bool isSigned)
5221 {
5222    bool result = false;
5223    switch(kind)
5224    {
5225       case shortType:
5226          if(op.kind == charType || op.kind == enumType || op.kind == _BoolType)
5227             result = isSigned ? GetOpShort(op, &op.s) : GetOpUShort(op, &op.us);
5228          break;
5229       case intType:
5230       case longType:
5231          if(op.kind == charType || op.kind == shortType || op.kind == enumType || op.kind == _BoolType)
5232             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5233          break;
5234       case int64Type:
5235          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5236             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5237             result = isSigned ? GetOpInt64(op, &op.i64) : GetOpUInt64(op, &op.ui64);
5238          break;
5239       case floatType:
5240          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType ||
5241             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5242             result = GetOpFloat(op, &op.f);
5243          break;
5244       case doubleType:
5245          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType ||
5246             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5247             result = GetOpDouble(op, &op.d);
5248          break;
5249       case pointerType:
5250          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5251             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5252             result = GetOpUInt64 /*GetOpUIntPtr*/(op, &op.ui64);
5253          break;
5254       case enumType:
5255          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5256             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5257             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5258          break;
5259       case intPtrType:
5260          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5261             result = isSigned ? GetOpInt64 /*GetOpIntPtr*/(op, &op.i64) : GetOpUInt64 /*GetOpUIntPtr*/(op, &op.ui64);
5262          break;
5263       case intSizeType:
5264          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5265             result = isSigned ? GetOpInt64 /*GetOpIntSize*/(op, &op.i64) : GetOpUInt64 /*GetOpUIntSize*/(op, &op.ui64);
5266          break;
5267    }
5268    return result;
5269 }
5270
5271 void CallOperator(Expression exp, Expression exp1, Expression exp2, Operand op1, Operand op2)
5272 {
5273    if(exp.op.op == SIZEOF)
5274    {
5275       FreeExpContents(exp);
5276       exp.type = constantExp;
5277       exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5278    }
5279    else
5280    {
5281       if(!exp.op.exp1)
5282       {
5283          switch(exp.op.op)
5284          {
5285             // unary arithmetic
5286             case '+':
5287             {
5288                // Provide default unary +
5289                Expression exp2 = exp.op.exp2;
5290                exp.op.exp2 = null;
5291                FreeExpContents(exp);
5292                FreeType(exp.expType);
5293                FreeType(exp.destType);
5294                *exp = *exp2;
5295                delete exp2;
5296                break;
5297             }
5298             case '-':
5299                if(op1.ops.Neg) { FreeExpContents(exp); op1.ops.Neg(exp, op1); }
5300                break;
5301             // unary arithmetic increment and decrement
5302                   //OPERATOR_ALL(UNARY, ++, Inc)
5303                   //OPERATOR_ALL(UNARY, --, Dec)
5304             // unary bitwise
5305             case '~':
5306                if(op1.ops.BitNot) { FreeExpContents(exp); op1.ops.BitNot(exp, op1); }
5307                break;
5308             // unary logical negation
5309             case '!':
5310                if(op1.ops.Not) { FreeExpContents(exp); op1.ops.Not(exp, op1); }
5311                break;
5312          }
5313       }
5314       else
5315       {
5316          if(op1 && op2 && op1.type && op2.type && op1.kind != op2.kind)
5317          {
5318             if(Promote(op2, op1.kind, op1.type.isSigned))
5319                op2.kind = op1.kind, op2.ops = op1.ops;
5320             else if(Promote(op1, op2.kind, op2.type.isSigned))
5321                op1.kind = op2.kind, op1.ops = op2.ops;
5322          }
5323          switch(exp.op.op)
5324          {
5325             // binary arithmetic
5326             case '+':
5327                if(op1.ops.Add) { FreeExpContents(exp); op1.ops.Add(exp, op1, op2); }
5328                break;
5329             case '-':
5330                if(op1.ops.Sub) { FreeExpContents(exp); op1.ops.Sub(exp, op1, op2); }
5331                break;
5332             case '*':
5333                if(op1.ops.Mul) { FreeExpContents(exp); op1.ops.Mul(exp, op1, op2); }
5334                break;
5335             case '/':
5336                if(op1.ops.Div) { FreeExpContents(exp); op1.ops.Div(exp, op1, op2); }
5337                break;
5338             case '%':
5339                if(op1.ops.Mod) { FreeExpContents(exp); op1.ops.Mod(exp, op1, op2); }
5340                break;
5341             // binary arithmetic assignment
5342                   //OPERATOR_ALL(BINARY, =, Asign)
5343                   //OPERATOR_ALL(BINARY, +=, AddAsign)
5344                   //OPERATOR_ALL(BINARY, -=, SubAsign)
5345                   //OPERATOR_ALL(BINARY, *=, MulAsign)
5346                   //OPERATOR_ALL(BINARY, /=, DivAsign)
5347                   //OPERATOR_ALL(BINARY, %=, ModAsign)
5348             // binary bitwise
5349             case '&':
5350                if(exp.op.exp2)
5351                {
5352                   if(op1.ops.BitAnd) { FreeExpContents(exp); op1.ops.BitAnd(exp, op1, op2); }
5353                }
5354                break;
5355             case '|':
5356                if(op1.ops.BitOr) { FreeExpContents(exp); op1.ops.BitOr(exp, op1, op2); }
5357                break;
5358             case '^':
5359                if(op1.ops.BitXor) { FreeExpContents(exp); op1.ops.BitXor(exp, op1, op2); }
5360                break;
5361             case LEFT_OP:
5362                if(op1.ops.LShift) { FreeExpContents(exp); op1.ops.LShift(exp, op1, op2); }
5363                break;
5364             case RIGHT_OP:
5365                if(op1.ops.RShift) { FreeExpContents(exp); op1.ops.RShift(exp, op1, op2); }
5366                break;
5367             // binary bitwise assignment
5368                   //OPERATOR_INTTYPES(BINARY, &=, AndAsign)
5369                   //OPERATOR_INTTYPES(BINARY, |=, OrAsign)
5370                   //OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
5371                   //OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
5372                   //OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
5373             // binary logical equality
5374             case EQ_OP:
5375                if(op1.ops.Equ) { FreeExpContents(exp); op1.ops.Equ(exp, op1, op2); }
5376                break;
5377             case NE_OP:
5378                if(op1.ops.Nqu) { FreeExpContents(exp); op1.ops.Nqu(exp, op1, op2); }
5379                break;
5380             // binary logical
5381             case AND_OP:
5382                if(op1.ops.And) { FreeExpContents(exp); op1.ops.And(exp, op1, op2); }
5383                break;
5384             case OR_OP:
5385                if(op1.ops.Or) { FreeExpContents(exp); op1.ops.Or(exp, op1, op2); }
5386                break;
5387             // binary logical relational
5388             case '>':
5389                if(op1.ops.Grt) { FreeExpContents(exp); op1.ops.Grt(exp, op1, op2); }
5390                break;
5391             case '<':
5392                if(op1.ops.Sma) { FreeExpContents(exp); op1.ops.Sma(exp, op1, op2); }
5393                break;
5394             case GE_OP:
5395                if(op1.ops.GrtEqu) { FreeExpContents(exp); op1.ops.GrtEqu(exp, op1, op2); }
5396                break;
5397             case LE_OP:
5398                if(op1.ops.SmaEqu) { FreeExpContents(exp); op1.ops.SmaEqu(exp, op1, op2); }
5399                break;
5400          }
5401       }
5402    }
5403 }
5404
5405 void ComputeExpression(Expression exp)
5406 {
5407 #ifdef _DEBUG
5408    char expString[10240];
5409    expString[0] = '\0';
5410    PrintExpression(exp, expString);
5411 #endif
5412
5413    switch(exp.type)
5414    {
5415       case identifierExp:
5416       {
5417          Identifier id = exp.identifier;
5418          if(id && exp.isConstant && !inCompiler && !inPreCompiler && !inDebugger)
5419          {
5420             Class c = (exp.expType && exp.expType.kind == classType && exp.expType._class) ? exp.expType._class.registered : null;
5421             if(c && c.type == enumClass)
5422             {
5423                Class enumClass = eSystem_FindClass(privateModule, "enum");
5424                if(enumClass)
5425                {
5426                   NamedLink64 value;
5427                   EnumClassData e = ACCESS_CLASSDATA(c, enumClass);
5428                   for(value = e.values.first; value; value = value.next)
5429                   {
5430                      if(!strcmp(value.name, id.string))
5431                         break;
5432                   }
5433                   if(value)
5434                   {
5435                      const String dts = c.dataTypeString;
5436                      FreeExpContents(exp);
5437                      exp.type = constantExp;
5438                      exp.constant = (dts && (!strcmp(dts, "int") || !strcmp(dts, "int64") || !strcmp(dts, "short") || !strcmp(dts, "char"))) ? PrintInt64(value.data) : PrintUInt64(value.data);
5439                   }
5440                }
5441             }
5442          }
5443          break;
5444       }
5445       case instanceExp:
5446       {
5447          ComputeInstantiation(exp);
5448          break;
5449       }
5450       /*
5451       case constantExp:
5452          break;
5453       */
5454       case opExp:
5455       {
5456          Expression exp1, exp2 = null;
5457          Operand op1 { };
5458          Operand op2 { };
5459
5460          // We don't care about operations with only exp2 (INC_OP, DEC_OP...)
5461          if(exp.op.exp2)
5462          {
5463             Expression e = exp.op.exp2;
5464
5465             while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
5466             {
5467                if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
5468                {
5469                   if(e.type == extensionCompoundExp)
5470                      e = ((Statement)e.compound.compound.statements->last).expressions->last;
5471                   else
5472                      e = e.list->last;
5473                }
5474             }
5475             if(exp.op.op == TokenType::sizeOf && e && e.expType)
5476             {
5477                if(e.type == stringExp && e.string)
5478                {
5479                   char * string = e.string;
5480                   int len = strlen(string);
5481                   char * tmp = new char[len-2+1];
5482                   len = UnescapeString(tmp, string + 1, len - 2);
5483                   delete tmp;
5484                   FreeExpContents(exp);
5485                   exp.type = constantExp;
5486                   exp.constant = PrintUInt(len + 1);
5487                }
5488                else
5489                {
5490                   Type type = e.expType;
5491                   type.refCount++;
5492                   FreeExpContents(exp);
5493                   exp.type = constantExp;
5494                   exp.constant = PrintUInt(ComputeTypeSize(type));
5495                   FreeType(type);
5496                }
5497                break;
5498             }
5499             else
5500                ComputeExpression(exp.op.exp2);
5501          }
5502          if(exp.op.exp1)
5503          {
5504             ComputeExpression(exp.op.exp1);
5505             exp1 = exp.op.exp1;
5506             exp2 = exp.op.exp2;
5507             op1 = GetOperand(exp1);
5508             if(op1.type) op1.type.refCount++;
5509             if(exp2)
5510             {
5511                op2 = GetOperand(exp2);
5512                if(op2.type) op2.type.refCount++;
5513             }
5514          }
5515          else
5516          {
5517             exp1 = exp.op.exp2;
5518             op1 = GetOperand(exp1);
5519             if(op1.type) op1.type.refCount++;
5520          }
5521
5522          CallOperator(exp, exp1, exp2, op1, op2);
5523          /*
5524          switch(exp.op.op)
5525          {
5526             // Unary operators
5527             case '&':
5528                // Also binary
5529                if(exp.op.exp1 && exp.op.exp2)
5530                {
5531                   // Binary And
5532                   if(op1.ops.BitAnd)
5533                   {
5534                      FreeExpContents(exp);
5535                      op1.ops.BitAnd(exp, op1, op2);
5536                   }
5537                }
5538                break;
5539             case '*':
5540                if(exp.op.exp1)
5541                {
5542                   if(op1.ops.Mul)
5543                   {
5544                      FreeExpContents(exp);
5545                      op1.ops.Mul(exp, op1, op2);
5546                   }
5547                }
5548                break;
5549             case '+':
5550                if(exp.op.exp1)
5551                {
5552                   if(op1.ops.Add)
5553                   {
5554                      FreeExpContents(exp);
5555                      op1.ops.Add(exp, op1, op2);
5556                   }
5557                }
5558                else
5559                {
5560                   // Provide default unary +
5561                   Expression exp2 = exp.op.exp2;
5562                   exp.op.exp2 = null;
5563                   FreeExpContents(exp);
5564                   FreeType(exp.expType);
5565                   FreeType(exp.destType);
5566
5567                   *exp = *exp2;
5568                   delete exp2;
5569                }
5570                break;
5571             case '-':
5572                if(exp.op.exp1)
5573                {
5574                   if(op1.ops.Sub)
5575                   {
5576                      FreeExpContents(exp);
5577                      op1.ops.Sub(exp, op1, op2);
5578                   }
5579                }
5580                else
5581                {
5582                   if(op1.ops.Neg)
5583                   {
5584                      FreeExpContents(exp);
5585                      op1.ops.Neg(exp, op1);
5586                   }
5587                }
5588                break;
5589             case '~':
5590                if(op1.ops.BitNot)
5591                {
5592                   FreeExpContents(exp);
5593                   op1.ops.BitNot(exp, op1);
5594                }
5595                break;
5596             case '!':
5597                if(op1.ops.Not)
5598                {
5599                   FreeExpContents(exp);
5600                   op1.ops.Not(exp, op1);
5601                }
5602                break;
5603             // Binary only operators
5604             case '/':
5605                if(op1.ops.Div)
5606                {
5607                   FreeExpContents(exp);
5608                   op1.ops.Div(exp, op1, op2);
5609                }
5610                break;
5611             case '%':
5612                if(op1.ops.Mod)
5613                {
5614                   FreeExpContents(exp);
5615                   op1.ops.Mod(exp, op1, op2);
5616                }
5617                break;
5618             case LEFT_OP:
5619                break;
5620             case RIGHT_OP:
5621                break;
5622             case '<':
5623                if(exp.op.exp1)
5624                {
5625                   if(op1.ops.Sma)
5626                   {
5627                      FreeExpContents(exp);
5628                      op1.ops.Sma(exp, op1, op2);
5629                   }
5630                }
5631                break;
5632             case '>':
5633                if(exp.op.exp1)
5634                {
5635                   if(op1.ops.Grt)
5636                   {
5637                      FreeExpContents(exp);
5638                      op1.ops.Grt(exp, op1, op2);
5639                   }
5640                }
5641                break;
5642             case LE_OP:
5643                if(exp.op.exp1)
5644                {
5645                   if(op1.ops.SmaEqu)
5646                   {
5647                      FreeExpContents(exp);
5648                      op1.ops.SmaEqu(exp, op1, op2);
5649                   }
5650                }
5651                break;
5652             case GE_OP:
5653                if(exp.op.exp1)
5654                {
5655                   if(op1.ops.GrtEqu)
5656                   {
5657                      FreeExpContents(exp);
5658                      op1.ops.GrtEqu(exp, op1, op2);
5659                   }
5660                }
5661                break;
5662             case EQ_OP:
5663                if(exp.op.exp1)
5664                {
5665                   if(op1.ops.Equ)
5666                   {
5667                      FreeExpContents(exp);
5668                      op1.ops.Equ(exp, op1, op2);
5669                   }
5670                }
5671                break;
5672             case NE_OP:
5673                if(exp.op.exp1)
5674                {
5675                   if(op1.ops.Nqu)
5676                   {
5677                      FreeExpContents(exp);
5678                      op1.ops.Nqu(exp, op1, op2);
5679                   }
5680                }
5681                break;
5682             case '|':
5683                if(op1.ops.BitOr)
5684                {
5685                   FreeExpContents(exp);
5686                   op1.ops.BitOr(exp, op1, op2);
5687                }
5688                break;
5689             case '^':
5690                if(op1.ops.BitXor)
5691                {
5692                   FreeExpContents(exp);
5693                   op1.ops.BitXor(exp, op1, op2);
5694                }
5695                break;
5696             case AND_OP:
5697                break;
5698             case OR_OP:
5699                break;
5700             case SIZEOF:
5701                FreeExpContents(exp);
5702                exp.type = constantExp;
5703                exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5704                break;
5705          }
5706          */
5707          if(op1.type) FreeType(op1.type);
5708          if(op2.type) FreeType(op2.type);
5709          break;
5710       }
5711       case bracketsExp:
5712       case extensionExpressionExp:
5713       {
5714          Expression e, n;
5715          for(e = exp.list->first; e; e = n)
5716          {
5717             n = e.next;
5718             if(!n)
5719             {
5720                OldList * list = exp.list;
5721                Expression prev = exp.prev;
5722                Expression next = exp.next;
5723                ComputeExpression(e);
5724                //FreeExpContents(exp);
5725                FreeType(exp.expType);
5726                FreeType(exp.destType);
5727                *exp = *e;
5728                exp.prev = prev;
5729                exp.next = next;
5730                delete e;
5731                delete list;
5732             }
5733             else
5734             {
5735                FreeExpression(e);
5736             }
5737          }
5738          break;
5739       }
5740       /*
5741
5742       case ExpIndex:
5743       {
5744          Expression e;
5745          exp.isConstant = true;
5746
5747          ComputeExpression(exp.index.exp);
5748          if(!exp.index.exp.isConstant)
5749             exp.isConstant = false;
5750
5751          for(e = exp.index.index->first; e; e = e.next)
5752          {
5753             ComputeExpression(e);
5754             if(!e.next)
5755             {
5756                // Check if this type is int
5757             }
5758             if(!e.isConstant)
5759                exp.isConstant = false;
5760          }
5761          exp.expType = Dereference(exp.index.exp.expType);
5762          break;
5763       }
5764       */
5765       case memberExp:
5766       {
5767          Expression memberExp = exp.member.exp;
5768          Identifier memberID = exp.member.member;
5769
5770          Type type;
5771          ComputeExpression(exp.member.exp);
5772          type = exp.member.exp.expType;
5773          if(type)
5774          {
5775             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);
5776             Property prop = null;
5777             DataMember member = null;
5778             Class convertTo = null;
5779             if(type.kind == subClassType && exp.member.exp.type == classExp)
5780                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
5781
5782             if(!_class)
5783             {
5784                char string[256];
5785                Symbol classSym;
5786                string[0] = '\0';
5787                PrintTypeNoConst(type, string, false, true);
5788                classSym = FindClass(string);
5789                _class = classSym ? classSym.registered : null;
5790             }
5791
5792             if(exp.member.member)
5793             {
5794                prop = eClass_FindProperty(_class, exp.member.member.string, privateModule);
5795                if(!prop)
5796                   member = eClass_FindDataMember(_class, exp.member.member.string, privateModule, null, null);
5797             }
5798             if(!prop && !member && _class && exp.member.member)
5799             {
5800                Symbol classSym = FindClass(exp.member.member.string);
5801                convertTo = _class;
5802                _class = classSym ? classSym.registered : null;
5803                prop = eClass_FindProperty(_class, convertTo.fullName, privateModule);
5804             }
5805
5806             if(prop)
5807             {
5808                if(prop.compiled)
5809                {
5810                   Type type = prop.dataType;
5811                   // TODO: Assuming same base type for units...
5812                   if(_class.type == unitClass)
5813                   {
5814                      if(type.kind == classType)
5815                      {
5816                         Class _class = type._class.registered;
5817                         if(_class.type == unitClass)
5818                         {
5819                            if(!_class.dataType)
5820                               _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5821                            type = _class.dataType;
5822                         }
5823                      }
5824                      switch(type.kind)
5825                      {
5826                         case floatType:
5827                         {
5828                            float value;
5829                            float (*Get)(float) = (void *)prop.Get;
5830                            GetFloat(exp.member.exp, &value);
5831                            exp.constant = PrintFloat(Get ? Get(value) : value);
5832                            exp.type = constantExp;
5833                            break;
5834                         }
5835                         case doubleType:
5836                         {
5837                            double value;
5838                            double (*Get)(double);
5839                            GetDouble(exp.member.exp, &value);
5840
5841                            if(convertTo)
5842                               Get = (void *)prop.Set;
5843                            else
5844                               Get = (void *)prop.Get;
5845                            exp.constant = PrintDouble(Get ? Get(value) : value);
5846                            exp.type = constantExp;
5847                            break;
5848                         }
5849                      }
5850                   }
5851                   else
5852                   {
5853                      if(convertTo)
5854                      {
5855                         Expression value = exp.member.exp;
5856                         Type type;
5857                         if(!prop.dataType)
5858                            ProcessPropertyType(prop);
5859
5860                         type = prop.dataType;
5861                         if(!type)
5862                         {
5863                             // printf("Investigate this\n");
5864                         }
5865                         else if(_class.type == structClass)
5866                         {
5867                            switch(type.kind)
5868                            {
5869                               case classType:
5870                               {
5871                                  Class propertyClass = type._class.registered;
5872                                  if(propertyClass.type == structClass && value.type == instanceExp)
5873                                  {
5874                                     void (*Set)(void *, void *) = (void *)prop.Set;
5875                                     exp.instance = Instantiation { };
5876                                     exp.instance.data = new0 byte[_class.structSize];
5877                                     exp.instance._class = MkSpecifierName(_class.fullName);
5878                                     exp.instance.loc = exp.loc;
5879                                     exp.type = instanceExp;
5880                                     Set(exp.instance.data, value.instance.data);
5881                                     PopulateInstance(exp.instance);
5882                                  }
5883                                  break;
5884                               }
5885                               case intType:
5886                               {
5887                                  int intValue;
5888                                  void (*Set)(void *, int) = (void *)prop.Set;
5889
5890                                  exp.instance = Instantiation { };
5891                                  exp.instance.data = new0 byte[_class.structSize];
5892                                  exp.instance._class = MkSpecifierName(_class.fullName);
5893                                  exp.instance.loc = exp.loc;
5894                                  exp.type = instanceExp;
5895
5896                                  GetInt(value, &intValue);
5897
5898                                  Set(exp.instance.data, intValue);
5899                                  PopulateInstance(exp.instance);
5900                                  break;
5901                               }
5902                               case int64Type:
5903                               {
5904                                  int64 intValue;
5905                                  void (*Set)(void *, int64) = (void *)prop.Set;
5906
5907                                  exp.instance = Instantiation { };
5908                                  exp.instance.data = new0 byte[_class.structSize];
5909                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5910                                  exp.instance.loc = exp.loc;
5911                                  exp.type = instanceExp;
5912
5913                                  GetInt64(value, &intValue);
5914
5915                                  Set(exp.instance.data, intValue);
5916                                  PopulateInstance(exp.instance);
5917                                  break;
5918                               }
5919                               case intPtrType:
5920                               {
5921                                  // TOFIX:
5922                                  intptr intValue;
5923                                  void (*Set)(void *, intptr) = (void *)prop.Set;
5924
5925                                  exp.instance = Instantiation { };
5926                                  exp.instance.data = new0 byte[_class.structSize];
5927                                  exp.instance._class = MkSpecifierName(_class.fullName);
5928                                  exp.instance.loc = exp.loc;
5929                                  exp.type = instanceExp;
5930
5931                                  GetIntPtr(value, &intValue);
5932
5933                                  Set(exp.instance.data, intValue);
5934                                  PopulateInstance(exp.instance);
5935                                  break;
5936                               }
5937                               case intSizeType:
5938                               {
5939                                  // TOFIX:
5940                                  intsize intValue;
5941                                  void (*Set)(void *, intsize) = (void *)prop.Set;
5942
5943                                  exp.instance = Instantiation { };
5944                                  exp.instance.data = new0 byte[_class.structSize];
5945                                  exp.instance._class = MkSpecifierName(_class.fullName);
5946                                  exp.instance.loc = exp.loc;
5947                                  exp.type = instanceExp;
5948
5949                                  GetIntSize(value, &intValue);
5950
5951                                  Set(exp.instance.data, intValue);
5952                                  PopulateInstance(exp.instance);
5953                                  break;
5954                               }
5955                               case floatType:
5956                               {
5957                                  float floatValue;
5958                                  void (*Set)(void *, float) = (void *)prop.Set;
5959
5960                                  exp.instance = Instantiation { };
5961                                  exp.instance.data = new0 byte[_class.structSize];
5962                                  exp.instance._class = MkSpecifierName(_class.fullName);
5963                                  exp.instance.loc = exp.loc;
5964                                  exp.type = instanceExp;
5965
5966                                  GetFloat(value, &floatValue);
5967
5968                                  Set(exp.instance.data, floatValue);
5969                                  PopulateInstance(exp.instance);
5970                                  break;
5971                               }
5972                               case doubleType:
5973                               {
5974                                  double doubleValue;
5975                                  void (*Set)(void *, double) = (void *)prop.Set;
5976
5977                                  exp.instance = Instantiation { };
5978                                  exp.instance.data = new0 byte[_class.structSize];
5979                                  exp.instance._class = MkSpecifierName(_class.fullName);
5980                                  exp.instance.loc = exp.loc;
5981                                  exp.type = instanceExp;
5982
5983                                  GetDouble(value, &doubleValue);
5984
5985                                  Set(exp.instance.data, doubleValue);
5986                                  PopulateInstance(exp.instance);
5987                                  break;
5988                               }
5989                            }
5990                         }
5991                         else if(_class.type == bitClass)
5992                         {
5993                            switch(type.kind)
5994                            {
5995                               case classType:
5996                               {
5997                                  Class propertyClass = type._class.registered;
5998                                  if(propertyClass.type == structClass && value.instance.data)
5999                                  {
6000                                     unsigned int (*Set)(void *) = (void *)prop.Set;
6001                                     unsigned int bits = Set(value.instance.data);
6002                                     exp.constant = PrintHexUInt(bits);
6003                                     exp.type = constantExp;
6004                                     break;
6005                                  }
6006                                  else if(_class.type == bitClass)
6007                                  {
6008                                     unsigned int value;
6009                                     unsigned int (*Set)(unsigned int) = (void *)prop.Set;
6010                                     unsigned int bits;
6011
6012                                     GetUInt(exp.member.exp, &value);
6013                                     bits = Set(value);
6014                                     exp.constant = PrintHexUInt(bits);
6015                                     exp.type = constantExp;
6016                                  }
6017                               }
6018                            }
6019                         }
6020                      }
6021                      else
6022                      {
6023                         if(_class.type == bitClass)
6024                         {
6025                            unsigned int value;
6026                            GetUInt(exp.member.exp, &value);
6027
6028                            switch(type.kind)
6029                            {
6030                               case classType:
6031                               {
6032                                  Class _class = type._class.registered;
6033                                  if(_class.type == structClass)
6034                                  {
6035                                     void (*Get)(unsigned int, void *) = (void *)prop.Get;
6036
6037                                     exp.instance = Instantiation { };
6038                                     exp.instance.data = new0 byte[_class.structSize];
6039                                     exp.instance._class = MkSpecifierName(_class.fullName);
6040                                     exp.instance.loc = exp.loc;
6041                                     //exp.instance.fullSet = true;
6042                                     exp.type = instanceExp;
6043                                     Get(value, exp.instance.data);
6044                                     PopulateInstance(exp.instance);
6045                                  }
6046                                  else if(_class.type == bitClass)
6047                                  {
6048                                     unsigned int (*Get)(unsigned int) = (void *)prop.Get;
6049                                     uint64 bits = Get(value);
6050                                     exp.constant = PrintHexUInt64(bits);
6051                                     exp.type = constantExp;
6052                                  }
6053                                  break;
6054                               }
6055                            }
6056                         }
6057                         else if(_class.type == structClass)
6058                         {
6059                            byte * value = (exp.member.exp.type == instanceExp ) ? exp.member.exp.instance.data : null;
6060                            switch(type.kind)
6061                            {
6062                               case classType:
6063                               {
6064                                  Class _class = type._class.registered;
6065                                  if(_class.type == structClass && value)
6066                                  {
6067                                     void (*Get)(void *, void *) = (void *)prop.Get;
6068
6069                                     exp.instance = Instantiation { };
6070                                     exp.instance.data = new0 byte[_class.structSize];
6071                                     exp.instance._class = MkSpecifierName(_class.fullName);
6072                                     exp.instance.loc = exp.loc;
6073                                     //exp.instance.fullSet = true;
6074                                     exp.type = instanceExp;
6075                                     Get(value, exp.instance.data);
6076                                     PopulateInstance(exp.instance);
6077                                  }
6078                                  break;
6079                               }
6080                            }
6081                         }
6082                         /*else
6083                         {
6084                            char * value = exp.member.exp.instance.data;
6085                            switch(type.kind)
6086                            {
6087                               case classType:
6088                               {
6089                                  Class _class = type._class.registered;
6090                                  if(_class.type == normalClass)
6091                                  {
6092                                     void *(*Get)(void *) = (void *)prop.Get;
6093
6094                                     exp.instance = Instantiation { };
6095                                     exp.instance._class = MkSpecifierName(_class.fullName); //MkClassName(_class.fullName);
6096                                     exp.type = instanceExp;
6097                                     exp.instance.data = Get(value, exp.instance.data);
6098                                  }
6099                                  break;
6100                               }
6101                            }
6102                         }
6103                         */
6104                      }
6105                   }
6106                }
6107                else
6108                {
6109                   exp.isConstant = false;
6110                }
6111             }
6112             else if(member)
6113             {
6114             }
6115          }
6116
6117          if(exp.type != ExpressionType::memberExp)
6118          {
6119             FreeExpression(memberExp);
6120             FreeIdentifier(memberID);
6121          }
6122          break;
6123       }
6124       case typeSizeExp:
6125       {
6126          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
6127          FreeExpContents(exp);
6128          exp.constant = PrintUInt(ComputeTypeSize(type));
6129          exp.type = constantExp;
6130          FreeType(type);
6131          break;
6132       }
6133       case classSizeExp:
6134       {
6135          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
6136          if(classSym && classSym.registered)
6137          {
6138             if(classSym.registered.fixed)
6139             {
6140                FreeSpecifier(exp._class);
6141                exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
6142                exp.type = constantExp;
6143             }
6144             else
6145             {
6146                char className[1024];
6147                strcpy(className, "__ecereClass_");
6148                FullClassNameCat(className, classSym.string, true);
6149
6150                DeclareClass(curExternal, classSym, className);
6151
6152                FreeExpContents(exp);
6153                exp.type = pointerExp;
6154                exp.member.exp = MkExpIdentifier(MkIdentifier(className));
6155                exp.member.member = MkIdentifier("structSize");
6156             }
6157          }
6158          break;
6159       }
6160       case castExp:
6161       //case constantExp:
6162       {
6163          Type type;
6164          Expression e = exp;
6165          if(exp.type == castExp)
6166          {
6167             if(exp.cast.exp)
6168                ComputeExpression(exp.cast.exp);
6169             e = exp.cast.exp;
6170          }
6171          if(e && exp.expType)
6172          {
6173             /*if(exp.destType)
6174                type = exp.destType;
6175             else*/
6176                type = exp.expType;
6177             if(type.kind == classType)
6178             {
6179                Class _class = type._class.registered;
6180                if(_class && (_class.type == unitClass || _class.type == bitClass))
6181                {
6182                   if(!_class.dataType)
6183                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
6184                   type = _class.dataType;
6185                }
6186             }
6187
6188             switch(type.kind)
6189             {
6190                case _BoolType:
6191                case charType:
6192                   if(type.isSigned)
6193                   {
6194                      char value = 0;
6195                      if(GetChar(e, &value))
6196                      {
6197                         FreeExpContents(exp);
6198                         exp.constant = PrintChar(value);
6199                         exp.type = constantExp;
6200                      }
6201                   }
6202                   else
6203                   {
6204                      unsigned char value = 0;
6205                      if(GetUChar(e, &value))
6206                      {
6207                         FreeExpContents(exp);
6208                         exp.constant = PrintUChar(value);
6209                         exp.type = constantExp;
6210                      }
6211                   }
6212                   break;
6213                case shortType:
6214                   if(type.isSigned)
6215                   {
6216                      short value = 0;
6217                      if(GetShort(e, &value))
6218                      {
6219                         FreeExpContents(exp);
6220                         exp.constant = PrintShort(value);
6221                         exp.type = constantExp;
6222                      }
6223                   }
6224                   else
6225                   {
6226                      unsigned short value = 0;
6227                      if(GetUShort(e, &value))
6228                      {
6229                         FreeExpContents(exp);
6230                         exp.constant = PrintUShort(value);
6231                         exp.type = constantExp;
6232                      }
6233                   }
6234                   break;
6235                case intType:
6236                   if(type.isSigned)
6237                   {
6238                      int value = 0;
6239                      if(GetInt(e, &value))
6240                      {
6241                         FreeExpContents(exp);
6242                         exp.constant = PrintInt(value);
6243                         exp.type = constantExp;
6244                      }
6245                   }
6246                   else
6247                   {
6248                      unsigned int value = 0;
6249                      if(GetUInt(e, &value))
6250                      {
6251                         FreeExpContents(exp);
6252                         exp.constant = PrintUInt(value);
6253                         exp.type = constantExp;
6254                      }
6255                   }
6256                   break;
6257                case int64Type:
6258                   if(type.isSigned)
6259                   {
6260                      int64 value = 0;
6261                      if(GetInt64(e, &value))
6262                      {
6263                         FreeExpContents(exp);
6264                         exp.constant = PrintInt64(value);
6265                         exp.type = constantExp;
6266                      }
6267                   }
6268                   else
6269                   {
6270                      uint64 value = 0;
6271                      if(GetUInt64(e, &value))
6272                      {
6273                         FreeExpContents(exp);
6274                         exp.constant = PrintUInt64(value);
6275                         exp.type = constantExp;
6276                      }
6277                   }
6278                   break;
6279                case intPtrType:
6280                   if(type.isSigned)
6281                   {
6282                      intptr value = 0;
6283                      if(GetIntPtr(e, &value))
6284                      {
6285                         FreeExpContents(exp);
6286                         exp.constant = PrintInt64((int64)value);
6287                         exp.type = constantExp;
6288                      }
6289                   }
6290                   else
6291                   {
6292                      uintptr value = 0;
6293                      if(GetUIntPtr(e, &value))
6294                      {
6295                         FreeExpContents(exp);
6296                         exp.constant = PrintUInt64((uint64)value);
6297                         exp.type = constantExp;
6298                      }
6299                   }
6300                   break;
6301                case intSizeType:
6302                   if(type.isSigned)
6303                   {
6304                      intsize value = 0;
6305                      if(GetIntSize(e, &value))
6306                      {
6307                         FreeExpContents(exp);
6308                         exp.constant = PrintInt64((int64)value);
6309                         exp.type = constantExp;
6310                      }
6311                   }
6312                   else
6313                   {
6314                      uintsize value = 0;
6315                      if(GetUIntSize(e, &value))
6316                      {
6317                         FreeExpContents(exp);
6318                         exp.constant = PrintUInt64((uint64)value);
6319                         exp.type = constantExp;
6320                      }
6321                   }
6322                   break;
6323                case floatType:
6324                {
6325                   float value = 0;
6326                   if(GetFloat(e, &value))
6327                   {
6328                      FreeExpContents(exp);
6329                      exp.constant = PrintFloat(value);
6330                      exp.type = constantExp;
6331                   }
6332                   break;
6333                }
6334                case doubleType:
6335                {
6336                   double value = 0;
6337                   if(GetDouble(e, &value))
6338                   {
6339                      FreeExpContents(exp);
6340                      exp.constant = PrintDouble(value);
6341                      exp.type = constantExp;
6342                   }
6343                   break;
6344                }
6345             }
6346          }
6347          break;
6348       }
6349       case conditionExp:
6350       {
6351          Operand op1 { };
6352          Operand op2 { };
6353          Operand op3 { };
6354
6355          if(exp.cond.exp)
6356             // Caring only about last expression for now...
6357             ComputeExpression(exp.cond.exp->last);
6358          if(exp.cond.elseExp)
6359             ComputeExpression(exp.cond.elseExp);
6360          if(exp.cond.cond)
6361             ComputeExpression(exp.cond.cond);
6362
6363          op1 = GetOperand(exp.cond.cond);
6364          if(op1.type) op1.type.refCount++;
6365          op2 = GetOperand(exp.cond.exp->last);
6366          if(op2.type) op2.type.refCount++;
6367          op3 = GetOperand(exp.cond.elseExp);
6368          if(op3.type) op3.type.refCount++;
6369
6370          if(op1.ops.Cond) { FreeExpContents(exp); op1.ops.Cond(exp, op1, op2, op3); }
6371          if(op1.type) FreeType(op1.type);
6372          if(op2.type) FreeType(op2.type);
6373          if(op3.type) FreeType(op3.type);
6374          break;
6375       }
6376    }
6377 }
6378
6379 static bool CheckExpressionType(Expression exp, Type destType, bool skipUnitBla, bool warnConst)
6380 {
6381    bool result = true;
6382    if(destType)
6383    {
6384       OldList converts { };
6385       Conversion convert;
6386
6387       if(destType.kind == voidType)
6388          return false;
6389
6390       if(!MatchTypeExpression(exp, destType, &converts, skipUnitBla, warnConst))
6391          result = false;
6392       if(converts.count)
6393       {
6394          // for(convert = converts.last; convert; convert = convert.prev)
6395          for(convert = converts.first; convert; convert = convert.next)
6396          {
6397             bool empty = !(convert.isGet ? (void *)convert.convert.Get : (void *)convert.convert.Set);
6398             if(!empty)
6399             {
6400                Expression newExp { };
6401                ClassObjectType objectType = exp.expType ? exp.expType.classObjectType : none;
6402
6403                // TODO: Check this...
6404                *newExp = *exp;
6405                newExp.prev = null;
6406                newExp.next = null;
6407                newExp.destType = null;
6408
6409                if(convert.isGet)
6410                {
6411                   // [exp].ColorRGB
6412                   exp.type = memberExp;
6413                   exp.addedThis = true;
6414                   exp.member.exp = newExp;
6415                   FreeType(exp.member.exp.expType);
6416
6417                   exp.member.exp.expType = MkClassType(convert.convert._class.fullName);
6418                   exp.member.exp.expType.classObjectType = objectType;
6419                   exp.member.member = MkIdentifier(convert.convert.dataTypeString);
6420                   exp.member.memberType = propertyMember;
6421                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6422                   // TESTING THIS... for (int)degrees
6423                   exp.needCast = true;
6424                   if(exp.expType) exp.expType.refCount++;
6425                   ApplyAnyObjectLogic(exp.member.exp);
6426                }
6427                else
6428                {
6429
6430                   /*if(exp.isConstant)
6431                   {
6432                      // Color { ColorRGB = [exp] };
6433                      exp.type = instanceExp;
6434                      exp.instance = MkInstantiation(MkSpecifierName((convert.convert._class.fullName), //MkClassName(convert.convert._class.fullName),
6435                         null, MkListOne(MkMembersInitList(MkListOne(MkMemberInit(
6436                         MkListOne(MkIdentifier(convert.convert.dataTypeString)), newExp)))));
6437                   }
6438                   else*/
6439                   {
6440                      // If not constant, don't turn it yet into an instantiation
6441                      // (Go through the deep members system first)
6442                      exp.type = memberExp;
6443                      exp.addedThis = true;
6444                      exp.member.exp = newExp;
6445
6446                      // ADDED THIS HERE TO SOLVE PROPERTY ISSUES WITH NOHEAD CLASSES
6447                      if(/*!notByReference && */newExp.expType && newExp.expType.kind == classType && newExp.expType._class && newExp.expType._class.registered &&
6448                         newExp.expType._class.registered.type == noHeadClass)
6449                      {
6450                         newExp.byReference = true;
6451                      }
6452
6453                      FreeType(exp.member.exp.expType);
6454                      /*exp.member.exp.expType = convert.convert.dataType;
6455                      if(convert.convert.dataType) convert.convert.dataType.refCount++;*/
6456                      exp.member.exp.expType = null;
6457                      if(convert.convert.dataType)
6458                      {
6459                         exp.member.exp.expType = { };
6460                         CopyTypeInto(exp.member.exp.expType, convert.convert.dataType);
6461                         exp.member.exp.expType.refCount = 1;
6462                         exp.member.exp.expType.classObjectType = objectType;
6463                         ApplyAnyObjectLogic(exp.member.exp);
6464                      }
6465
6466                      exp.member.member = MkIdentifier(convert.convert._class.fullName);
6467                      exp.member.memberType = reverseConversionMember;
6468                      exp.expType = convert.resultType ? convert.resultType :
6469                         MkClassType(convert.convert._class.fullName);
6470                      exp.needCast = true;
6471                      if(convert.resultType) convert.resultType.refCount++;
6472                   }
6473                }
6474             }
6475             else
6476             {
6477                FreeType(exp.expType);
6478                if(convert.isGet)
6479                {
6480                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6481                   if(exp.destType.casted)
6482                      exp.needCast = true;
6483                   if(exp.expType) exp.expType.refCount++;
6484                }
6485                else
6486                {
6487                   exp.expType = convert.resultType ? convert.resultType : MkClassType(convert.convert._class.fullName);
6488                   if(exp.destType.casted)
6489                      exp.needCast = true;
6490                   if(convert.resultType)
6491                      convert.resultType.refCount++;
6492                }
6493             }
6494          }
6495          if(exp.isConstant && inCompiler)
6496             ComputeExpression(exp);
6497
6498          converts.Free(FreeConvert);
6499       }
6500
6501       if(!result && exp.expType && converts.count)      // TO TEST: Added converts.count here to avoid a double warning with function type
6502       {
6503          result = MatchTypes(exp.expType, exp.destType, null, null, null, true, true, false, false, warnConst);
6504       }
6505       if(!result && exp.expType && exp.destType)
6506       {
6507          if((exp.destType.kind == classType && exp.expType.kind == pointerType &&
6508              exp.expType.type.kind == classType && exp.expType.type._class == exp.destType._class && exp.destType._class.registered && exp.destType._class.registered.type == structClass) ||
6509             (exp.expType.kind == classType && exp.destType.kind == pointerType &&
6510             exp.destType.type.kind == classType && exp.destType.type._class == exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass))
6511             result = true;
6512       }
6513    }
6514    // if(result) CheckTemplateTypes(exp);
6515    return result;
6516 }
6517
6518 void CheckTemplateTypes(Expression exp)
6519 {
6520    /*
6521    bool et = exp.expType ? exp.expType.passAsTemplate : false;
6522    bool dt = exp.destType ? exp.destType.passAsTemplate : false;
6523    */
6524    Expression nbExp = GetNonBracketsExp(exp);
6525    if(exp.destType && exp.destType.passAsTemplate && exp.expType && exp.expType.kind != templateType && !exp.expType.passAsTemplate &&
6526       (nbExp == exp || nbExp.type != castExp))
6527    {
6528       Expression newExp { };
6529       Context context;
6530       TypeKind kind = exp.expType.kind;
6531       *newExp = *exp;
6532       if(exp.destType) exp.destType.refCount++;
6533       if(exp.expType)  exp.expType.refCount++;
6534       newExp.prev = null;
6535       newExp.next = null;
6536
6537       if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered)
6538       {
6539          Class c = exp.expType._class.registered;
6540          if(c.type == bitClass || c.type == enumClass || c.type == unitClass)
6541          {
6542             if(!c.dataType)
6543                c.dataType = ProcessTypeString(c.dataTypeString, false);
6544             kind = c.dataType.kind;
6545          }
6546       }
6547
6548       switch(kind)
6549       {
6550          case doubleType:
6551             if(exp.destType.classObjectType)
6552             {
6553                // We need to pass the address, just pass it along (Undo what was done above)
6554                if(exp.destType) exp.destType.refCount--;
6555                if(exp.expType)  exp.expType.refCount--;
6556                delete newExp;
6557             }
6558             else
6559             {
6560                // If we're looking for value:
6561                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6562                OldList * specs;
6563                OldList * unionDefs = MkList();
6564                OldList * statements = MkList();
6565                context = PushContext();
6566                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6567                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6568                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6569                exp.type = extensionCompoundExp;
6570                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6571                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")), '=', newExp))));
6572                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
6573                exp.compound.compound.context = context;
6574                PopContext(context);
6575             }
6576             break;
6577          default:
6578             exp.type = castExp;
6579             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6580             if((exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass) || exp.expType.isPointerType)
6581                exp.cast.exp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), MkExpBrackets(MkListOne(newExp)));
6582             else
6583                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6584             exp.needCast = true;
6585             break;
6586       }
6587    }
6588    else if(exp.expType && exp.expType.passAsTemplate && exp.destType && exp.usage.usageGet && exp.destType.kind != templateType && !exp.destType.passAsTemplate)
6589    {
6590       Expression newExp { };
6591       Context context;
6592       TypeKind kind = exp.expType.kind;
6593       *newExp = *exp;
6594       if(exp.destType) exp.destType.refCount++;
6595       if(exp.expType)  exp.expType.refCount++;
6596       newExp.prev = null;
6597       newExp.next = null;
6598
6599       if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered)
6600       {
6601          Class c = exp.expType._class.registered;
6602          if(c.type == bitClass || c.type == enumClass || c.type == unitClass)
6603          {
6604             if(!c.dataType)
6605                c.dataType = ProcessTypeString(c.dataTypeString, false);
6606             kind = c.dataType.kind;
6607          }
6608       }
6609
6610       switch(kind)
6611       {
6612          case doubleType:
6613             if(exp.destType.classObjectType)
6614             {
6615                // We need to pass the address, just pass it along (Undo what was done above)
6616                if(exp.destType) exp.destType.refCount--;
6617                if(exp.expType)  exp.expType.refCount--;
6618                delete newExp;
6619             }
6620             else
6621             {
6622                // If we're looking for value:
6623                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6624                OldList * specs;
6625                OldList * unionDefs = MkList();
6626                OldList * statements = MkList();
6627                context = PushContext();
6628                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6629                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6630                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6631                exp.type = extensionCompoundExp;
6632                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6633                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
6634                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")))));
6635                exp.compound.compound.context = context;
6636                PopContext(context);
6637             }
6638             break;
6639          case classType:
6640          {
6641             if(exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass)
6642             {
6643                exp.type = bracketsExp;
6644
6645                newExp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), newExp);
6646                exp.list = MkListOne(MkExpOp(null, '*', MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)),
6647                   MkDeclaratorPointer(MkPointer(null, null), null)), newExp)));
6648                ProcessExpressionType(exp.list->first);
6649                break;
6650             }
6651             else
6652             {
6653                exp.type = bracketsExp;
6654                if(exp.expType.isPointerType)
6655                {
6656                   exp.needTemplateCast = 2;
6657                   newExp.needCast = true;
6658                   newExp.needTemplateCast = 2;
6659                   newExp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), newExp);
6660                }
6661
6662                exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)), null), newExp));
6663                exp.needTemplateCast = 2;
6664                newExp.needCast = true;
6665                newExp.needTemplateCast = 2;
6666                ProcessExpressionType(exp.list->first);
6667                break;
6668             }
6669          }
6670          default:
6671          {
6672             if(exp.expType.kind == templateType)
6673             {
6674                Type type = ProcessTemplateParameterType(exp.expType.templateParameter);
6675                if(type)
6676                {
6677                   FreeType(exp.destType);
6678                   FreeType(exp.expType);
6679                   delete newExp;
6680                   break;
6681                }
6682             }
6683             /*if(newExp.type == memberExp && newExp.member.memberType == dataMember)
6684             {
6685                // When was this required?    Removed to address using templated values to pass to printf()
6686                exp.type = opExp;
6687                exp.op.op = '*';
6688                exp.op.exp1 = null;
6689                exp.op.exp2 = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uint64")), MkDeclaratorPointer(MkPointer(null, null), null)),
6690                   MkExpBrackets(MkListOne(MkExpOp(null, '&', newExp))));
6691             }
6692             else*/
6693             {
6694                char typeString[1024];
6695                Declarator decl;
6696                OldList * specs = MkList();
6697                typeString[0] = '\0';
6698                PrintType(exp.expType, typeString, false, false);
6699                decl = SpecDeclFromString(typeString, specs, null);
6700
6701                exp.type = castExp;
6702                //exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6703                exp.cast.typeName = MkTypeName(specs, decl);
6704                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6705                exp.cast.exp.needCast = true;
6706                exp.needTemplateCast = 2;
6707                newExp.needTemplateCast = 2;
6708             }
6709             break;
6710          }
6711       }
6712    }
6713 }
6714 // TODO: The Symbol tree should be reorganized by namespaces
6715 // Name Space:
6716 //    - Tree of all symbols within (stored without namespace)
6717 //    - Tree of sub-namespaces
6718
6719 static Symbol ScanWithNameSpace(BinaryTree tree, const char * nameSpace, const char * name)
6720 {
6721    int nsLen = strlen(nameSpace);
6722    Symbol symbol;
6723    // Start at the name space prefix
6724    for(symbol = (Symbol)tree.FindPrefix(nameSpace); symbol; symbol = (Symbol)((BTNode)symbol).next)
6725    {
6726       char * s = symbol.string;
6727       if(!strncmp(s, nameSpace, nsLen))
6728       {
6729          // This supports e.g. matching ecere::Socket to ecere::net::Socket
6730          int c;
6731          char * namePart;
6732          for(c = strlen(s)-1; c >= 0; c--)
6733             if(s[c] == ':')
6734                break;
6735
6736          namePart = s+c+1;
6737          if(!strcmp(namePart, name))
6738          {
6739             // TODO: Error on ambiguity
6740             return symbol;
6741          }
6742       }
6743       else
6744          break;
6745    }
6746    return null;
6747 }
6748
6749 static Symbol FindWithNameSpace(BinaryTree tree, const char * name)
6750 {
6751    int c;
6752    char nameSpace[1024];
6753    const char * namePart;
6754    bool gotColon = false;
6755
6756    nameSpace[0] = '\0';
6757    for(c = strlen(name)-1; c >= 0; c--)
6758       if(name[c] == ':')
6759       {
6760          gotColon = true;
6761          break;
6762       }
6763
6764    namePart = name+c+1;
6765    while(c >= 0 && name[c] == ':') c--;
6766    if(c >= 0)
6767    {
6768       // Try an exact match first
6769       Symbol symbol = (Symbol)tree.FindString(name);
6770       if(symbol)
6771          return symbol;
6772
6773       // Namespace specified
6774       memcpy(nameSpace, name, c + 1);
6775       nameSpace[c+1] = 0;
6776
6777       return ScanWithNameSpace(tree, nameSpace, namePart);
6778    }
6779    else if(gotColon)
6780    {
6781       // Looking for a global symbol, e.g. ::Sleep()
6782       Symbol symbol = (Symbol)tree.FindString(namePart);
6783       return symbol;
6784    }
6785    else
6786    {
6787       // Name only (no namespace specified)
6788       Symbol symbol = (Symbol)tree.FindString(namePart);
6789       if(symbol)
6790          return symbol;
6791       return ScanWithNameSpace(tree, "", namePart);
6792    }
6793    return null;
6794 }
6795
6796 /*static */Symbol FindSymbol(const char * name, Context startContext, Context endContext, bool isStruct, bool globalNameSpace)
6797 {
6798 #ifdef _DEBUG
6799    //Time startTime = GetTime();
6800 #endif
6801    // Optimize this later? Do this before/less?
6802    Context ctx;
6803    Symbol symbol = null;
6804
6805    // First, check if the identifier is declared inside the function
6806    //for(ctx = curContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6807
6808    for(ctx = startContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6809    {
6810       if(ctx == globalContext && !globalNameSpace && ctx.hasNameSpace)
6811       {
6812          symbol = null;
6813          if(thisNameSpace)
6814          {
6815             char curName[1024];
6816             strcpy(curName, thisNameSpace);
6817             strcat(curName, "::");
6818             strcat(curName, name);
6819             // Try to resolve in current namespace first
6820             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, curName);
6821          }
6822          if(!symbol)
6823             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, name);
6824       }
6825       else
6826          symbol = (Symbol)(isStruct ? ctx.structSymbols : ctx.symbols).FindString(name);
6827
6828       if(symbol || ctx == endContext) break;
6829    }
6830    if(inCompiler && symbol && ctx == globalContext && symbol.pointerExternal && curExternal && symbol.pointerExternal != curExternal)
6831       curExternal.CreateUniqueEdge(symbol.pointerExternal, symbol.pointerExternal.type == functionExternal);
6832 #ifdef _DEBUG
6833    //findSymbolTotalTime += GetTime() - startTime;
6834 #endif
6835    return symbol;
6836 }
6837
6838 static void GetTypeSpecs(Type type, OldList * specs)
6839 {
6840    if(!type.isSigned && type.kind != intPtrType && type.kind != intSizeType) ListAdd(specs, MkSpecifier(UNSIGNED));
6841    switch(type.kind)
6842    {
6843       case classType:
6844       {
6845          if(type._class.registered)
6846          {
6847             if(!type._class.registered.dataType)
6848                type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
6849             GetTypeSpecs(type._class.registered.dataType, specs);
6850          }
6851          break;
6852       }
6853       case doubleType: ListAdd(specs, MkSpecifier(DOUBLE)); break;
6854       case floatType: ListAdd(specs, MkSpecifier(FLOAT)); break;
6855       case charType: ListAdd(specs, MkSpecifier(CHAR)); break;
6856       case _BoolType: ListAdd(specs, MkSpecifier(_BOOL)); break;
6857       case shortType: ListAdd(specs, MkSpecifier(SHORT)); break;
6858       case int64Type: ListAdd(specs, MkSpecifier(INT64)); break;
6859       case intPtrType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intptr" : "uintptr")); break;
6860       case intSizeType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intsize" : "uintsize")); break;
6861       case intType:
6862       default:
6863          ListAdd(specs, MkSpecifier(INT)); break;
6864    }
6865 }
6866
6867 static void PrintArraySize(Type arrayType, char * string)
6868 {
6869    char size[256];
6870    size[0] = '\0';
6871    strcat(size, "[");
6872    if(arrayType.enumClass)
6873       strcat(size, arrayType.enumClass.string);
6874    else if(arrayType.arraySizeExp)
6875       PrintExpression(arrayType.arraySizeExp, size);
6876    strcat(size, "]");
6877    strcat(string, size);
6878 }
6879
6880 // WARNING : This function expects a null terminated string since it recursively concatenate...
6881 static void PrintTypeSpecs(Type type, char * string, bool fullName, bool printConst)
6882 {
6883    if(type)
6884    {
6885       if(printConst && type.constant)
6886          strcat(string, "const ");
6887       switch(type.kind)
6888       {
6889          case classType:
6890          {
6891             Symbol c = type._class;
6892             bool isObjectBaseClass = !c || !c.string || !strcmp(c.string, "class");
6893             // TODO: typed_object does not fully qualify the type, as it may have taken up an actual class (Stored in _class) from overriding
6894             //       look into merging with thisclass ?
6895             if(type.classObjectType == typedObject && isObjectBaseClass)
6896                strcat(string, "typed_object");
6897             else if(type.classObjectType == anyObject && isObjectBaseClass)
6898                strcat(string, "any_object");
6899             else
6900             {
6901                if(c && c.string)
6902                   strcat(string, (fullName || !c.registered) ? c.string : c.registered.name);
6903             }
6904             if(type.byReference)
6905                strcat(string, " &");
6906             break;
6907          }
6908          case voidType: strcat(string, "void"); break;
6909          case intType:  strcat(string, type.isSigned ? "int" : "uint"); break;
6910          case int64Type:  strcat(string, type.isSigned ? "int64" : "uint64"); break;
6911          case intPtrType:  strcat(string, type.isSigned ? "intptr" : "uintptr"); break;
6912          case intSizeType:  strcat(string, type.isSigned ? "intsize" : "uintsize"); break;
6913          case charType: strcat(string, type.isSigned ? "char" : "byte"); break;
6914          case _BoolType: strcat(string, "_Bool"); break;
6915          case shortType: strcat(string, type.isSigned ? "short" : "uint16"); break;
6916          case floatType: strcat(string, "float"); break;
6917          case doubleType: strcat(string, "double"); break;
6918          case structType:
6919             if(type.enumName)
6920             {
6921                strcat(string, "struct ");
6922                strcat(string, type.enumName);
6923             }
6924             else if(type.typeName)
6925                strcat(string, type.typeName);
6926             else
6927             {
6928                Type member;
6929                strcat(string, "struct { ");
6930                for(member = type.members.first; member; member = member.next)
6931                {
6932                   PrintType(member, string, true, fullName);
6933                   strcat(string,"; ");
6934                }
6935                strcat(string,"}");
6936             }
6937             break;
6938          case unionType:
6939             if(type.enumName)
6940             {
6941                strcat(string, "union ");
6942                strcat(string, type.enumName);
6943             }
6944             else if(type.typeName)
6945                strcat(string, type.typeName);
6946             else
6947             {
6948                strcat(string, "union ");
6949                strcat(string,"(unnamed)");
6950             }
6951             break;
6952          case enumType:
6953             if(type.enumName)
6954             {
6955                strcat(string, "enum ");
6956                strcat(string, type.enumName);
6957             }
6958             else if(type.typeName)
6959                strcat(string, type.typeName);
6960             else
6961                strcat(string, "int"); // "enum");
6962             break;
6963          case ellipsisType:
6964             strcat(string, "...");
6965             break;
6966          case subClassType:
6967             strcat(string, "subclass(");
6968             strcat(string, type._class ? type._class.string : "int");
6969             strcat(string, ")");
6970             break;
6971          case templateType:
6972             strcat(string, type.templateParameter.identifier.string);
6973             break;
6974          case thisClassType:
6975             strcat(string, "thisclass");
6976             break;
6977          case vaListType:
6978             strcat(string, "__builtin_va_list");
6979             break;
6980       }
6981    }
6982 }
6983
6984 static void PrintName(Type type, char * string, bool fullName)
6985 {
6986    if(type.name && type.name[0])
6987    {
6988       if(fullName)
6989          strcat(string, type.name);
6990       else
6991       {
6992          char * name = RSearchString(type.name, "::", strlen(type.name), true, false);
6993          if(name) name += 2; else name = type.name;
6994          strcat(string, name);
6995       }
6996    }
6997 }
6998
6999 static void PrintAttribs(Type type, char * string)
7000 {
7001    if(type)
7002    {
7003       if(type.dllExport)   strcat(string, "dllexport ");
7004       if(type.attrStdcall) strcat(string, "stdcall ");
7005    }
7006 }
7007
7008 static void PrePrintType(Type type, char * string, bool fullName, Type parentType, bool printConst)
7009 {
7010    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
7011    {
7012       if((type.kind == functionType || type.kind == methodType) && (!parentType || parentType.kind != pointerType))
7013          PrintAttribs(type, string);
7014       if(printConst && type.constant && (type.kind == functionType || type.kind == methodType))
7015          strcat(string, " const");
7016       PrePrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName, type, printConst);
7017       if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
7018          strcat(string, " (");
7019       if(type.kind == pointerType)
7020       {
7021          if(type.type.kind == functionType || type.type.kind == methodType)
7022             PrintAttribs(type.type, string);
7023       }
7024       if(type.kind == pointerType)
7025       {
7026          if(type.type.kind == functionType || type.type.kind == methodType || type.type.kind == arrayType)
7027             strcat(string, "*");
7028          else
7029             strcat(string, " *");
7030       }
7031       if(printConst && type.constant && type.kind == pointerType)
7032          strcat(string, " const");
7033    }
7034    else
7035       PrintTypeSpecs(type, string, fullName, printConst);
7036 }
7037
7038 static void PostPrintType(Type type, char * string, bool fullName)
7039 {
7040    if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
7041       strcat(string, ")");
7042    if(type.kind == arrayType)
7043       PrintArraySize(type, string);
7044    else if(type.kind == functionType)
7045    {
7046       Type param;
7047       strcat(string, "(");
7048       for(param = type.params.first; param; param = param.next)
7049       {
7050          PrintType(param, string, true, fullName);
7051          if(param.next) strcat(string, ", ");
7052       }
7053       strcat(string, ")");
7054    }
7055    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
7056       PostPrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName);
7057 }
7058
7059 // *****
7060 // TODO: Add a max buffer size to avoid overflows. This function is used with static size char arrays.
7061 // *****
7062 static void _PrintType(Type type, char * string, bool printName, bool fullName, bool printConst)
7063 {
7064    PrePrintType(type, string, fullName, null, printConst);
7065
7066    if(type.thisClass || (printName && type.name && type.name[0]))
7067       strcat(string, " ");
7068    if(/*(type.kind == methodType || type.kind == functionType) && */(type.thisClass || type.staticMethod))
7069    {
7070       Symbol _class = type.thisClass;
7071       if((type.classObjectType == typedObject || type.classObjectType == classPointer) || (_class && !strcmp(_class.string, "class")))
7072       {
7073          if(type.classObjectType == classPointer)
7074             strcat(string, "class");
7075          else
7076             strcat(string, type.byReference ? "typed_object&" : "typed_object");
7077       }
7078       else if(_class && _class.string)
7079       {
7080          String s = _class.string;
7081          if(fullName)
7082             strcat(string, s);
7083          else
7084          {
7085             char * name = RSearchString(s, "::", strlen(s), true, false);
7086             if(name) name += 2; else name = s;
7087             strcat(string, name);
7088          }
7089       }
7090       strcat(string, "::");
7091    }
7092
7093    if(printName && type.name)
7094       PrintName(type, string, fullName);
7095    PostPrintType(type, string, fullName);
7096    if(type.bitFieldCount)
7097    {
7098       char count[100];
7099       sprintf(count, ":%d", type.bitFieldCount);
7100       strcat(string, count);
7101    }
7102 }
7103
7104 void PrintType(Type type, char * string, bool printName, bool fullName)
7105 {
7106    _PrintType(type, string, printName, fullName, true);
7107 }
7108
7109 void PrintTypeNoConst(Type type, char * string, bool printName, bool fullName)
7110 {
7111    _PrintType(type, string, printName, fullName, false);
7112 }
7113
7114 static Type FindMember(Type type, char * string)
7115 {
7116    Type memberType;
7117    for(memberType = type.members.first; memberType; memberType = memberType.next)
7118    {
7119       if(!memberType.name)
7120       {
7121          Type subType = FindMember(memberType, string);
7122          if(subType)
7123             return subType;
7124       }
7125       else if(!strcmp(memberType.name, string))
7126          return memberType;
7127    }
7128    return null;
7129 }
7130
7131 Type FindMemberAndOffset(Type type, char * string, uint * offset)
7132 {
7133    Type memberType;
7134    for(memberType = type.members.first; memberType; memberType = memberType.next)
7135    {
7136       if(!memberType.name)
7137       {
7138          Type subType = FindMember(memberType, string);
7139          if(subType)
7140          {
7141             *offset += memberType.offset;
7142             return subType;
7143          }
7144       }
7145       else if(!strcmp(memberType.name, string))
7146       {
7147          *offset += memberType.offset;
7148          return memberType;
7149       }
7150    }
7151    return null;
7152 }
7153
7154 public bool GetParseError() { return parseError; }
7155
7156 Expression ParseExpressionString(char * expression)
7157 {
7158    parseError = false;
7159
7160    fileInput = TempFile { };
7161    fileInput.Write(expression, 1, strlen(expression));
7162    fileInput.Seek(0, start);
7163
7164    echoOn = false;
7165    parsedExpression = null;
7166    resetScanner();
7167    expression_yyparse();
7168    delete fileInput;
7169
7170    return parsedExpression;
7171 }
7172
7173 static bool ResolveIdWithClass(Expression exp, Class _class, bool skipIDClassCheck)
7174 {
7175    Identifier id = exp.identifier;
7176    Method method = null;
7177    Property prop = null;
7178    DataMember member = null;
7179    ClassProperty classProp = null;
7180
7181    if(_class && _class.type == enumClass)
7182    {
7183       NamedLink64 value = null;
7184       Class enumClass = eSystem_FindClass(privateModule, "enum");
7185       if(enumClass)
7186       {
7187          Class baseClass;
7188          for(baseClass = _class; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
7189          {
7190             EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
7191             for(value = e.values.first; value; value = value.next)
7192             {
7193                if(!strcmp(value.name, id.string))
7194                   break;
7195             }
7196             if(value)
7197             {
7198                exp.isConstant = true;
7199                if(inCompiler || inPreCompiler || inDebugger)
7200                {
7201                   char constant[256];
7202                   FreeExpContents(exp);
7203
7204                   exp.type = constantExp;
7205                   if(!strcmp(baseClass.dataTypeString, "int") || !strcmp(baseClass.dataTypeString, "int64") || !strcmp(baseClass.dataTypeString, "char") || !strcmp(baseClass.dataTypeString, "short"))
7206                      sprintf(constant, FORMAT64D, value.data);
7207                   else
7208                      sprintf(constant, FORMAT64HEX, value.data);
7209                   exp.constant = CopyString(constant);
7210                }
7211                //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
7212                exp.expType = MkClassType(baseClass.fullName);
7213                break;
7214             }
7215          }
7216       }
7217       if(value)
7218          return true;
7219    }
7220    if((method = eClass_FindMethod(_class, id.string, privateModule)))
7221    {
7222       ProcessMethodType(method);
7223       exp.expType = Type
7224       {
7225          refCount = 1;
7226          kind = methodType;
7227          method = method;
7228          // Crash here?
7229          // TOCHECK: Put it back to what it was...
7230          // methodClass = _class;
7231          methodClass = (skipIDClassCheck || (id && id._class)) ? _class : null;
7232       };
7233       //id._class = null;
7234       return true;
7235    }
7236    else if((prop = eClass_FindProperty(_class, id.string, privateModule)))
7237    {
7238       if(!prop.dataType)
7239          ProcessPropertyType(prop);
7240       exp.expType = prop.dataType;
7241       if(prop.dataType) prop.dataType.refCount++;
7242       return true;
7243    }
7244    else if((member = eClass_FindDataMember(_class, id.string, privateModule, null, null)))
7245    {
7246       if(!member.dataType)
7247          member.dataType = ProcessTypeString(member.dataTypeString, false);
7248       exp.expType = member.dataType;
7249       if(member.dataType) member.dataType.refCount++;
7250       return true;
7251    }
7252    else if((classProp = eClass_FindClassProperty(_class, id.string)))
7253    {
7254       if(!classProp.dataType)
7255          classProp.dataType = ProcessTypeString(classProp.dataTypeString, false);
7256
7257       if(classProp.constant)
7258       {
7259          FreeExpContents(exp);
7260
7261          exp.isConstant = true;
7262          if(classProp.dataType.kind == pointerType && classProp.dataType.type.kind == charType)
7263          {
7264             //char constant[256];
7265             exp.type = stringExp;
7266             exp.constant = QMkString((char *)(uintptr)classProp.Get(_class));
7267          }
7268          else
7269          {
7270             char constant[256];
7271             exp.type = constantExp;
7272             sprintf(constant, "%d", (int)classProp.Get(_class));
7273             exp.constant = CopyString(constant);
7274          }
7275       }
7276       else
7277       {
7278          // TO IMPLEMENT...
7279       }
7280
7281       exp.expType = classProp.dataType;
7282       if(classProp.dataType) classProp.dataType.refCount++;
7283       return true;
7284    }
7285    return false;
7286 }
7287
7288 static GlobalData ScanGlobalData(NameSpace nameSpace, char * name)
7289 {
7290    BinaryTree * tree = &nameSpace.functions;
7291    GlobalData data = (GlobalData)tree->FindString(name);
7292    NameSpace * child;
7293    if(!data)
7294    {
7295       for(child = (NameSpace *)nameSpace.nameSpaces.first; child; child = (NameSpace *)((BTNode)child).next)
7296       {
7297          data = ScanGlobalData(child, name);
7298          if(data)
7299             break;
7300       }
7301    }
7302    return data;
7303 }
7304
7305 static GlobalData FindGlobalData(char * name)
7306 {
7307    int start = 0, c;
7308    NameSpace * nameSpace;
7309    nameSpace = globalData;
7310    for(c = 0; name[c]; c++)
7311    {
7312       if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
7313       {
7314          NameSpace * newSpace;
7315          char * spaceName = new char[c - start + 1];
7316          strncpy(spaceName, name + start, c - start);
7317          spaceName[c-start] = '\0';
7318          newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
7319          delete spaceName;
7320          if(!newSpace)
7321             return null;
7322          nameSpace = newSpace;
7323          if(name[c] == ':') c++;
7324          start = c+1;
7325       }
7326    }
7327    if(c - start)
7328    {
7329       return ScanGlobalData(nameSpace, name + start);
7330    }
7331    return null;
7332 }
7333
7334 static int definedExpStackPos;
7335 static void * definedExpStack[512];
7336
7337 // This function makes checkedExp equivalent to newExp, ending up freeing newExp
7338 void ReplaceExpContents(Expression checkedExp, Expression newExp)
7339 {
7340    Expression prev = checkedExp.prev, next = checkedExp.next;
7341
7342    FreeExpContents(checkedExp);
7343    FreeType(checkedExp.expType);
7344    FreeType(checkedExp.destType);
7345
7346    *checkedExp = *newExp;
7347
7348    delete newExp;
7349
7350    checkedExp.prev = prev;
7351    checkedExp.next = next;
7352 }
7353
7354 void ApplyAnyObjectLogic(Expression e)
7355 {
7356    Type destType = /*(e.destType && e.destType.kind == ellipsisType) ? ellipsisDestType : */e.destType;
7357 #ifdef _DEBUG
7358    char debugExpString[4096];
7359    debugExpString[0] = '\0';
7360    PrintExpression(e, debugExpString);
7361 #endif
7362
7363    if(destType && (/*destType.classObjectType == ClassObjectType::typedObject || */destType.classObjectType == anyObject))
7364    {
7365       //if(e.destType && e.destType.kind == ellipsisType) usedEllipsis = true;
7366       //ellipsisDestType = destType;
7367       if(e && e.expType)
7368       {
7369          Type type = e.expType;
7370          Class _class = null;
7371          //Type destType = e.destType;
7372
7373          if(type.kind == classType && type._class && type._class.registered)
7374          {
7375             _class = type._class.registered;
7376          }
7377          else if(type.kind == subClassType)
7378          {
7379             _class = FindClass("ecere::com::Class").registered;
7380          }
7381          else
7382          {
7383             char string[1024] = "";
7384             Symbol classSym;
7385
7386             PrintTypeNoConst(type, string, false, true);
7387             classSym = FindClass(string);
7388             if(classSym) _class = classSym.registered;
7389          }
7390
7391          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...
7392             (!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))) ||
7393             destType.byReference)))
7394          {
7395             if(!_class || strcmp(_class.fullName, "char *"))     // TESTING THIS WITH NEW String class...
7396             {
7397                Expression checkedExp = e, newExp;
7398
7399                while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7400                {
7401                   if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7402                   {
7403                      if(checkedExp.type == extensionCompoundExp)
7404                      {
7405                         checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7406                      }
7407                      else
7408                         checkedExp = checkedExp.list->last;
7409                   }
7410                   else if(checkedExp.type == castExp)
7411                      checkedExp = checkedExp.cast.exp;
7412                }
7413
7414                if(checkedExp && checkedExp.type == opExp && checkedExp.op.op == '*' && !checkedExp.op.exp1)
7415                {
7416                   newExp = checkedExp.op.exp2;
7417                   checkedExp.op.exp2 = null;
7418                   FreeExpContents(checkedExp);
7419
7420                   if(e.expType && e.expType.passAsTemplate)
7421                   {
7422                      char size[100];
7423                      ComputeTypeSize(e.expType);
7424                      sprintf(size, "%d", e.expType.size);   // Potential 32/64 Bootstrap issue
7425                      newExp = MkExpBrackets(MkListOne(MkExpOp(MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)),
7426                         MkDeclaratorPointer(MkPointer(null, null), null)), newExp), '+',
7427                            MkExpCall(MkExpIdentifier(MkIdentifier("__ENDIAN_PAD")), MkListOne(MkExpConstant(size))))));
7428                   }
7429
7430                   ReplaceExpContents(checkedExp, newExp);
7431                   e.byReference = true;
7432                }
7433                else if(!e.byReference || (_class && _class.type == noHeadClass))     // TESTING THIS HERE...
7434                {
7435                   Expression checkedExp; //, newExp;
7436
7437                   {
7438                      // TODO: Move code from debugTools.ec for hasAddress flag, this is just temporary
7439                      bool hasAddress =
7440                         e.type == identifierExp ||
7441                         (e.type == ExpressionType::memberExp && e.member.memberType == dataMember) ||
7442                         (e.type == ExpressionType::pointerExp && e.member.memberType == dataMember) ||
7443                         (e.type == opExp && !e.op.exp1 && e.op.op == '*') ||
7444                         e.type == indexExp;
7445
7446                      if(_class && _class.type != noHeadClass && _class.type != normalClass && _class.type != structClass && !hasAddress)
7447                      {
7448                         Context context = PushContext();
7449                         Declarator decl;
7450                         OldList * specs = MkList();
7451                         char typeString[1024];
7452                         Expression newExp { };
7453
7454                         typeString[0] = '\0';
7455                         *newExp = *e;
7456
7457                         //if(e.destType) e.destType.refCount++;
7458                         // if(exp.expType) exp.expType.refCount++;
7459                         newExp.prev = null;
7460                         newExp.next = null;
7461                         newExp.expType = null;
7462
7463                         PrintTypeNoConst(e.expType, typeString, false, true);
7464                         decl = SpecDeclFromString(typeString, specs, null);
7465                         newExp.destType = ProcessType(specs, decl);
7466
7467                         curContext = context;
7468
7469                         // We need a current compound for this
7470                         if(curCompound)
7471                         {
7472                            char name[100];
7473                            OldList * stmts = MkList();
7474                            e.type = extensionCompoundExp;
7475                            sprintf(name, "__internalValue%03X", internalValueCounter++);
7476                            if(!curCompound.compound.declarations)
7477                               curCompound.compound.declarations = MkList();
7478                            curCompound.compound.declarations->Insert(null, MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(name)), null))));
7479                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(name)), '=', newExp))));
7480                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier(name)))));
7481                            e.compound = MkCompoundStmt(null, stmts);
7482                         }
7483                         else
7484                            printf("libec: compiler error, curCompound is null in ApplyAnyObjectLogic\n");
7485
7486                         /*
7487                         e.compound = MkCompoundStmt(
7488                            MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(
7489                               MkDeclaratorIdentifier(MkIdentifier("__internalValue")), MkInitializerAssignment(newExp))))),
7490
7491                            MkListOne(MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier("__internalValue"))))));
7492                         */
7493
7494                         {
7495                            Type type = e.destType;
7496                            e.destType = { };
7497                            CopyTypeInto(e.destType, type);
7498                            e.destType.refCount = 1;
7499                            e.destType.classObjectType = none;
7500                            FreeType(type);
7501                         }
7502
7503                         e.compound.compound.context = context;
7504                         PopContext(context);
7505                         curContext = context.parent;
7506                      }
7507                   }
7508
7509                   // TODO: INTEGRATE THIS WITH VERSION ABOVE WHICH WAS ADDED TO ENCOMPASS OTHER CASE (*pointer)
7510                   checkedExp = e;
7511                   while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7512                   {
7513                      if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7514                      {
7515                         if(checkedExp.type == extensionCompoundExp)
7516                         {
7517                            checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7518                         }
7519                         else
7520                            checkedExp = checkedExp.list->last;
7521                      }
7522                      else if(checkedExp.type == castExp)
7523                         checkedExp = checkedExp.cast.exp;
7524                   }
7525                   {
7526                      Expression operand { };
7527                      operand = *checkedExp;
7528                      checkedExp.Clear();
7529                      checkedExp.destType = ProcessTypeString("void *", false);
7530                      checkedExp.expType = checkedExp.destType;
7531                      checkedExp.destType.refCount++;
7532
7533                      checkedExp.type = opExp;
7534                      checkedExp.op.op = '&';
7535                      checkedExp.op.exp1 = null;
7536                      checkedExp.op.exp2 = operand;
7537
7538                      //newExp = MkExpOp(null, '&', checkedExp);
7539                   }
7540                   //ReplaceExpContents(checkedExp, newExp);
7541                }
7542             }
7543          }
7544       }
7545    }
7546    {
7547       // If expression type is a simple class, make it an address
7548       // FixReference(e, true);
7549    }
7550 //#if 0
7551    if((!destType || destType.kind == ellipsisType || destType.kind == voidType) && e.expType && (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7552       (e.expType.byReference || (e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7553          (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass ) )))
7554    {
7555       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"))
7556       {
7557          return;  // LEAVE THIS CASE (typed_object & :: methods 's this) TO PASS 2 FOR NOW
7558       }
7559       else
7560       {
7561          Expression thisExp { };
7562
7563          *thisExp = *e;
7564          thisExp.prev = null;
7565          thisExp.next = null;
7566          e.Clear();
7567
7568          e.type = bracketsExp;
7569          e.list = MkListOne(MkExpOp(null, '*', thisExp.type == identifierExp ? thisExp : MkExpBrackets(MkListOne(thisExp))));
7570          if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && thisExp.expType._class.registered.type == noHeadClass)
7571             ((Expression)e.list->first).byReference = true;
7572
7573          /*if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && !strcmp(thisExp.expType._class.registered.name, "class"))
7574          {
7575             e.expType = thisExp.expType;
7576             e.expType.refCount++;
7577          }
7578          else*/
7579          {
7580             e.expType = { };
7581             CopyTypeInto(e.expType, thisExp.expType);
7582             e.expType.byReference = false;
7583             e.expType.refCount = 1;
7584
7585             if(e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7586                (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass))
7587             {
7588                e.expType.classObjectType = none;
7589             }
7590          }
7591       }
7592    }
7593 // TOFIX: Try this for a nice IDE crash!
7594 //#endif
7595    // The other way around
7596    else
7597 //#endif
7598    if(destType && e.expType &&
7599          //e.expType.kind == classType && e.expType._class && e.expType._class.registered && !strcmp(e.expType._class.registered.name, "class") &&
7600          (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7601          !destType.classObjectType && /*(destType.kind != pointerType || !destType.type || destType.type.kind != voidType) &&*/ destType.kind != voidType)
7602    {
7603       if(destType.kind == ellipsisType)
7604       {
7605          Compiler_Error($"Unspecified type\n");
7606       }
7607       else if(!(destType.truth && e.expType.kind == classType && e.expType._class && e.expType._class.registered && e.expType._class.registered.type == structClass))
7608       {
7609          bool byReference = e.expType.byReference;
7610          Expression thisExp { };
7611          Declarator decl;
7612          OldList * specs = MkList();
7613          char typeString[1024]; // Watch buffer overruns
7614          Type type;
7615          ClassObjectType backupClassObjectType;
7616          bool backupByReference;
7617
7618          if(e.expType.kind == classType && e.expType._class && e.expType._class.registered && strcmp(e.expType._class.registered.name, "class"))
7619             type = e.expType;
7620          else
7621             type = destType;
7622
7623          backupClassObjectType = type.classObjectType;
7624          backupByReference = type.byReference;
7625
7626          type.classObjectType = none;
7627          type.byReference = false;
7628
7629          typeString[0] = '\0';
7630          PrintType(type, typeString, false, true);
7631          decl = SpecDeclFromString(typeString, specs, null);
7632
7633          type.classObjectType = backupClassObjectType;
7634          type.byReference = backupByReference;
7635
7636          *thisExp = *e;
7637          thisExp.prev = null;
7638          thisExp.next = null;
7639          e.Clear();
7640
7641          if( ( type.kind == classType && type._class && type._class.registered &&
7642                    (type._class.registered.type == systemClass || type._class.registered.type == bitClass ||
7643                     type._class.registered.type == enumClass || type._class.registered.type == unitClass) ) ||
7644              (type.kind != pointerType && type.kind != intPtrType && type.kind != arrayType && type.kind != classType) ||
7645              (!destType.byReference && byReference && (destType.kind != pointerType || type.kind != pointerType)))
7646          {
7647             bool passAsTemplate = thisExp.destType.passAsTemplate;
7648             Type t;
7649
7650             destType.refCount++;
7651
7652             e.type = opExp;
7653             e.op.op = '*';
7654             e.op.exp1 = null;
7655             e.op.exp2 = MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), thisExp);
7656
7657             t = { };
7658             CopyTypeInto(t, thisExp.destType);
7659             t.passAsTemplate = false;
7660             FreeType(thisExp.destType);
7661             thisExp.destType = t;
7662
7663             t = { };
7664             CopyTypeInto(t, destType);
7665             t.passAsTemplate = passAsTemplate;
7666             FreeType(destType);
7667             destType = t;
7668             destType.refCount = 0;
7669
7670             e.expType = { };
7671             CopyTypeInto(e.expType, type);
7672             if(type.passAsTemplate)
7673             {
7674                e.expType.classObjectType = none;
7675                e.expType.passAsTemplate = false;
7676             }
7677             e.expType.byReference = false;
7678             e.expType.refCount = 1;
7679          }
7680          else
7681          {
7682             e.type = castExp;
7683             e.cast.typeName = MkTypeName(specs, decl);
7684             e.cast.exp = thisExp;
7685             e.byReference = true;
7686             e.expType = type;
7687             type.refCount++;
7688          }
7689
7690          if(e.destType)
7691             FreeType(e.destType);
7692
7693          e.destType = destType;
7694          destType.refCount++;
7695       }
7696    }
7697 }
7698
7699 void ApplyLocation(Expression exp, Location loc)
7700 {
7701    exp.loc = loc;
7702    switch(exp.type)
7703    {
7704       case opExp:
7705          if(exp.op.exp1) ApplyLocation(exp.op.exp1, loc);
7706          if(exp.op.exp2) ApplyLocation(exp.op.exp2, loc);
7707          break;
7708       case bracketsExp:
7709          if(exp.list)
7710          {
7711             Expression e;
7712             for(e = exp.list->first; e; e = e.next)
7713                ApplyLocation(e, loc);
7714          }
7715          break;
7716       case indexExp:
7717          if(exp.index.index)
7718          {
7719             Expression e;
7720             for(e = exp.index.index->first; e; e = e.next)
7721                ApplyLocation(e, loc);
7722          }
7723          if(exp.index.exp)
7724             ApplyLocation(exp.index.exp, loc);
7725          break;
7726       case callExp:
7727          if(exp.call.arguments)
7728          {
7729             Expression arg;
7730             for(arg = exp.call.arguments->first; arg; arg = arg.next)
7731                ApplyLocation(arg, loc);
7732          }
7733          if(exp.call.exp)
7734             ApplyLocation(exp.call.exp, loc);
7735          break;
7736       case memberExp:
7737       case pointerExp:
7738          if(exp.member.exp)
7739             ApplyLocation(exp.member.exp, loc);
7740          break;
7741       case castExp:
7742          if(exp.cast.exp)
7743             ApplyLocation(exp.cast.exp, loc);
7744          break;
7745       case conditionExp:
7746          if(exp.cond.exp)
7747          {
7748             Expression e;
7749             for(e = exp.cond.exp->first; e; e = e.next)
7750                ApplyLocation(e, loc);
7751          }
7752          if(exp.cond.cond)
7753             ApplyLocation(exp.cond.cond, loc);
7754          if(exp.cond.elseExp)
7755             ApplyLocation(exp.cond.elseExp, loc);
7756          break;
7757       case vaArgExp:
7758          if(exp.vaArg.exp)
7759             ApplyLocation(exp.vaArg.exp, loc);
7760          break;
7761       default:
7762          break;
7763    }
7764 }
7765
7766 void ProcessExpressionType(Expression exp)
7767 {
7768    bool unresolved = false;
7769    Location oldyylloc = yylloc;
7770    bool notByReference = false;
7771 #ifdef _DEBUG
7772    char debugExpString[4096];
7773    debugExpString[0] = '\0';
7774    PrintExpression(exp, debugExpString);
7775 #endif
7776    if(!exp || exp.expType)
7777       return;
7778
7779    //eSystem_Logf("%s\n", expString);
7780
7781    // Testing this here
7782    yylloc = exp.loc;
7783    switch(exp.type)
7784    {
7785       case identifierExp:
7786       {
7787          Identifier id = exp.identifier;
7788          if(!id || !topContext) return;
7789
7790          // DOING THIS LATER NOW...
7791          if(id._class && id._class.name)
7792          {
7793             id.classSym = id._class.symbol; // FindClass(id._class.name);
7794             /* TODO: Name Space Fix ups
7795             if(!id.classSym)
7796                id.nameSpace = eSystem_FindNameSpace(privateModule, id._class.name);
7797             */
7798          }
7799
7800          /* WHY WAS THIS COMMENTED OUT? if(!strcmp(id.string, "__thisModule"))
7801          {
7802             exp.expType = ProcessTypeString("Module", true);
7803             break;
7804          }
7805          else */
7806          if(!strcmp(id.string, "__runtimePlatform"))
7807          {
7808             exp.expType = ProcessTypeString("ecere::com::Platform", true);
7809             break;
7810          }
7811          else if(strstr(id.string, "__ecereClass") == id.string)
7812          {
7813             exp.expType = ProcessTypeString("ecere::com::Class", true);
7814             break;
7815          }
7816          else if(id._class && (id.classSym || (id._class.name && !strcmp(id._class.name, "property"))))
7817          {
7818             // Added this here as well
7819             ReplaceClassMembers(exp, thisClass);
7820             if(exp.type != identifierExp)
7821             {
7822                ProcessExpressionType(exp);
7823                break;
7824             }
7825
7826             if(id.classSym && ResolveIdWithClass(exp, id.classSym.registered, false))
7827                break;
7828          }
7829          else
7830          {
7831             Symbol symbol = FindSymbol(id.string, curContext, topContext /*exp.destType ? topContext : globalContext*/, false, id._class && id._class.name == null);
7832             // Enums should be resolved here (Special pass in opExp to fix identifiers not seen as enum on the first pass)
7833             if(!symbol/* && exp.destType*/)
7834             {
7835                if(exp.destType && CheckExpressionType(exp, exp.destType, false, false))
7836                   break;
7837                else
7838                {
7839                   if(thisClass)
7840                   {
7841                      ReplaceClassMembers(exp, thisClass ? thisClass : currentClass);
7842                      if(exp.type != identifierExp)
7843                      {
7844                         ProcessExpressionType(exp);
7845                         break;
7846                      }
7847                   }
7848                   // Static methods called from inside the _class
7849                   else if(currentClass && !id._class)
7850                   {
7851                      if(ResolveIdWithClass(exp, currentClass, true))
7852                         break;
7853                   }
7854                   symbol = FindSymbol(id.string, topContext.parent, globalContext, false, id._class && id._class.name == null);
7855                }
7856             }
7857
7858             // If we manage to resolve this symbol
7859             if(symbol)
7860             {
7861                Type type = symbol.type;
7862                Class _class = (type && type.kind == classType && type._class) ? type._class.registered : null;
7863
7864                if(_class && !strcmp(id.string, "this") && !type.classObjectType)
7865                {
7866                   Context context = SetupTemplatesContext(_class);
7867                   type = ReplaceThisClassType(_class);
7868                   FinishTemplatesContext(context);
7869                   if(type) type.refCount = 0;   // We'll be incrementing it right below...
7870                }
7871
7872                FreeSpecifier(id._class);
7873                id._class = null;
7874                delete id.string;
7875                id.string = CopyString(symbol.string);
7876
7877                id.classSym = null;
7878                exp.expType = type;
7879                if(type)
7880                   type.refCount++;
7881
7882                                                 // Commented this out, it was making non-constant enum parameters seen as constant
7883                                                 // enums should have been resolved by ResolveIdWithClass, changed to constantExp and marked as constant
7884                if(type && (type.kind == enumType /*|| (_class && _class.type == enumClass)*/))
7885                   // Add missing cases here... enum Classes...
7886                   exp.isConstant = true;
7887
7888                // TOCHECK: Why was !strcmp(id.string, "this") commented out?
7889                if(symbol.isParam || !strcmp(id.string, "this"))
7890                {
7891                   if(_class && _class.type == structClass && !type.declaredWithStruct)
7892                      exp.byReference = true;
7893
7894                   //TESTING COMMENTING THIS OUT IN FAVOR OF ApplyAnyObjectLogic
7895                   /*if(type && _class && (type.classObjectType == typedObject || type.classObjectType == anyObject) &&
7896                      ((_class.type == unitClass || _class.type == enumClass || _class.type == bitClass) ||
7897                      (type.byReference && (_class.type == normalClass || _class.type == noHeadClass))))
7898                   {
7899                      Identifier id = exp.identifier;
7900                      exp.type = bracketsExp;
7901                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(id)));
7902                   }*/
7903                }
7904
7905                if(symbol.isIterator)
7906                {
7907                   if(symbol.isIterator == 3)
7908                   {
7909                      exp.type = bracketsExp;
7910                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(exp.identifier)));
7911                      ((Expression)exp.list->first).op.exp2.expType = exp.expType;
7912                      exp.expType = null;
7913                      ProcessExpressionType(exp);
7914                   }
7915                   else if(symbol.isIterator != 4)
7916                   {
7917                      exp.type = memberExp;
7918                      exp.member.exp = MkExpIdentifier(exp.identifier);
7919                      exp.member.exp.expType = exp.expType;
7920                      /*if(symbol.isIterator == 6)
7921                         exp.member.member = MkIdentifier("key");
7922                      else*/
7923                         exp.member.member = MkIdentifier("data");
7924                      exp.expType = null;
7925                      ProcessExpressionType(exp);
7926                   }
7927                }
7928                break;
7929             }
7930             else
7931             {
7932                DefinedExpression definedExp = null;
7933                if(thisNameSpace && !(id._class && !id._class.name))
7934                {
7935                   char name[1024];
7936                   strcpy(name, thisNameSpace);
7937                   strcat(name, "::");
7938                   strcat(name, id.string);
7939                   definedExp = eSystem_FindDefine(privateModule, name);
7940                }
7941                if(!definedExp)
7942                   definedExp = eSystem_FindDefine(privateModule, id.string);
7943                if(definedExp)
7944                {
7945                   int c;
7946                   for(c = 0; c<definedExpStackPos; c++)
7947                      if(definedExpStack[c] == definedExp)
7948                         break;
7949                   if(c == definedExpStackPos && c < sizeof(definedExpStack) / sizeof(void *))
7950                   {
7951                      Location backupYylloc = yylloc;
7952                      File backInput = fileInput;
7953                      definedExpStack[definedExpStackPos++] = definedExp;
7954
7955                      fileInput = TempFile { };
7956                      fileInput.Write(definedExp.value, 1, strlen(definedExp.value));
7957                      fileInput.Seek(0, start);
7958
7959                      echoOn = false;
7960                      parsedExpression = null;
7961                      resetScanner();
7962                      expression_yyparse();
7963                      delete fileInput;
7964                      if(backInput)
7965                         fileInput = backInput;
7966
7967                      yylloc = backupYylloc;
7968
7969                      if(parsedExpression)
7970                      {
7971                         FreeIdentifier(id);
7972                         exp.type = bracketsExp;
7973                         exp.list = MkListOne(parsedExpression);
7974                         ApplyLocation(parsedExpression, yylloc);
7975                         ProcessExpressionType(exp);
7976                         definedExpStackPos--;
7977                         return;
7978                      }
7979                      definedExpStackPos--;
7980                   }
7981                   else
7982                   {
7983                      if(inCompiler)
7984                      {
7985                         Compiler_Error($"Recursion in defined expression %s\n", id.string);
7986                      }
7987                   }
7988                }
7989                else
7990                {
7991                   GlobalData data = null;
7992                   if(thisNameSpace && !(id._class && !id._class.name))
7993                   {
7994                      char name[1024];
7995                      strcpy(name, thisNameSpace);
7996                      strcat(name, "::");
7997                      strcat(name, id.string);
7998                      data = FindGlobalData(name);
7999                   }
8000                   if(!data)
8001                      data = FindGlobalData(id.string);
8002                   if(data)
8003                   {
8004                      DeclareGlobalData(curExternal, data);
8005                      exp.expType = data.dataType;
8006                      if(data.dataType) data.dataType.refCount++;
8007
8008                      delete id.string;
8009                      id.string = CopyString(data.fullName);
8010                      FreeSpecifier(id._class);
8011                      id._class = null;
8012
8013                      break;
8014                   }
8015                   else
8016                   {
8017                      GlobalFunction function = null;
8018                      if(thisNameSpace && !(id._class && !id._class.name))
8019                      {
8020                         char name[1024];
8021                         strcpy(name, thisNameSpace);
8022                         strcat(name, "::");
8023                         strcat(name, id.string);
8024                         function = eSystem_FindFunction(privateModule, name);
8025                      }
8026                      if(!function)
8027                         function = eSystem_FindFunction(privateModule, id.string);
8028                      if(function)
8029                      {
8030                         char name[1024];
8031                         delete id.string;
8032                         id.string = CopyString(function.name);
8033                         name[0] = 0;
8034
8035                         if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
8036                            strcpy(name, "__ecereFunction_");
8037                         FullClassNameCat(name, id.string, false); // Why is this using FullClassNameCat ?
8038                         if(DeclareFunction(curExternal, function, name))
8039                         {
8040                            delete id.string;
8041                            id.string = CopyString(name);
8042                         }
8043                         exp.expType = function.dataType;
8044                         if(function.dataType) function.dataType.refCount++;
8045
8046                         FreeSpecifier(id._class);
8047                         id._class = null;
8048
8049                         break;
8050                      }
8051                   }
8052                }
8053             }
8054          }
8055          unresolved = true;
8056          break;
8057       }
8058       case instanceExp:
8059       {
8060          // Class _class;
8061          // Symbol classSym;
8062
8063          if(!exp.instance._class)
8064          {
8065             if(exp.destType && exp.destType.kind == classType && exp.destType._class)
8066             {
8067                exp.instance._class = MkSpecifierName(exp.destType._class.string);
8068             }
8069          }
8070
8071          //classSym = FindClass(exp.instance._class.fullName);
8072          //_class = classSym ? classSym.registered : null;
8073
8074          ProcessInstantiationType(exp.instance);
8075
8076          exp.isConstant = exp.instance.isConstant;
8077
8078          /*
8079          if(_class.type == unitClass && _class.base.type != systemClass)
8080          {
8081             {
8082                Type destType = exp.destType;
8083
8084                exp.destType = MkClassType(_class.base.fullName);
8085                exp.expType = MkClassType(_class.fullName);
8086                CheckExpressionType(exp, exp.destType, true);
8087
8088                exp.destType = destType;
8089             }
8090             exp.expType = MkClassType(_class.fullName);
8091          }
8092          else*/
8093          if(exp.instance._class)
8094          {
8095             exp.expType = MkClassType(exp.instance._class.name);
8096             /*if(exp.expType._class && exp.expType._class.registered &&
8097                (exp.expType._class.registered.type == normalClass || exp.expType._class.registered.type == noHeadClass))
8098                exp.expType.byReference = true;*/
8099          }
8100          break;
8101       }
8102       case constantExp:
8103       {
8104          if(!exp.expType)
8105          {
8106             char * constant = exp.constant;
8107             Type type
8108             {
8109                refCount = 1;
8110                constant = true;
8111             };
8112             exp.expType = type;
8113
8114             if(constant[0] == '\'')
8115             {
8116                if((int)((byte *)constant)[1] > 127)
8117                {
8118                   int nb;
8119                   unichar ch = UTF8GetChar(constant + 1, &nb);
8120                   if(nb < 2) ch = constant[1];
8121                   delete constant;
8122                   exp.constant = PrintUInt(ch);
8123                   // type.kind = (ch > 0xFFFF) ? intType : shortType;
8124                   type.kind = classType; //(ch > 0xFFFF) ? intType : shortType;
8125                   type._class = FindClass("unichar");
8126
8127                   type.isSigned = false;
8128                }
8129                else
8130                {
8131                   type.kind = charType;
8132                   type.isSigned = true;
8133                }
8134             }
8135             else
8136             {
8137                char * dot = strchr(constant, '.');
8138                bool isHex = (constant[0] == '0' && (constant[1] == 'x' || constant[1] == 'X'));
8139                char * exponent;
8140                if(isHex)
8141                {
8142                   exponent = strchr(constant, 'p');
8143                   if(!exponent) exponent = strchr(constant, 'P');
8144                }
8145                else
8146                {
8147                   exponent = strchr(constant, 'e');
8148                   if(!exponent) exponent = strchr(constant, 'E');
8149                }
8150
8151                if(dot || exponent)
8152                {
8153                   if(strchr(constant, 'f') || strchr(constant, 'F'))
8154                      type.kind = floatType;
8155                   else
8156                      type.kind = doubleType;
8157                   type.isSigned = true;
8158                }
8159                else
8160                {
8161                   bool isSigned = constant[0] == '-';
8162                   char * endP = null;
8163                   int64 i64 = strtoll(constant, &endP, 0);
8164                   uint64 ui64 = strtoull(constant, &endP, 0);
8165                   bool is64Bit = endP && (!strcmp(endP, "LL") || !strcmp(endP, "ll") || !strcmp(endP, "LLU") || !strcmp(endP, "llu") || !strcmp(endP, "ull") || !strcmp(endP, "ULL"));
8166                   bool forceUnsigned = endP && (!strcmp(endP, "U") || !strcmp(endP, "u") || !strcmp(endP, "LLU") || !strcmp(endP, "llu") || !strcmp(endP, "ull") || !strcmp(endP, "ULL"));
8167                   if(isSigned)
8168                   {
8169                      if(i64 < MININT)
8170                         is64Bit = true;
8171                   }
8172                   else
8173                   {
8174                      if(ui64 > MAXINT)
8175                      {
8176                         if(ui64 > MAXDWORD)
8177                         {
8178                            is64Bit = true;
8179                            if(ui64 <= MAXINT64 && (constant[0] != '0' || !constant[1]))
8180                               isSigned = true;
8181                         }
8182                      }
8183                      else if(constant[0] != '0' || !constant[1])
8184                         isSigned = true;
8185                   }
8186                   if(forceUnsigned)
8187                      isSigned = false;
8188                   type.kind = is64Bit ? int64Type : intType;
8189                   type.isSigned = isSigned;
8190                }
8191             }
8192             exp.isConstant = true;
8193             if(exp.destType && exp.destType.kind == doubleType)
8194                type.kind = doubleType;
8195             else if(exp.destType && exp.destType.kind == floatType)
8196                type.kind = floatType;
8197             else if(exp.destType && exp.destType.kind == int64Type)
8198                type.kind = int64Type;
8199          }
8200          break;
8201       }
8202       case stringExp:
8203       {
8204          exp.isConstant = true;      // Why wasn't this constant?
8205          exp.expType = Type
8206          {
8207             refCount = 1;
8208             kind = pointerType;
8209             type = Type
8210             {
8211                refCount = 1;
8212                kind = exp.wideString ? shortType : charType;
8213                constant = true;
8214                isSigned = exp.wideString ? false : true;
8215             }
8216          };
8217          break;
8218       }
8219       case newExp:
8220       case new0Exp:
8221          ProcessExpressionType(exp._new.size);
8222          exp.expType = Type
8223          {
8224             refCount = 1;
8225             kind = pointerType;
8226             type = ProcessType(exp._new.typeName.qualifiers, exp._new.typeName.declarator);
8227          };
8228          DeclareType(curExternal, exp.expType.type, true, false);
8229          break;
8230       case renewExp:
8231       case renew0Exp:
8232          ProcessExpressionType(exp._renew.size);
8233          ProcessExpressionType(exp._renew.exp);
8234          exp.expType = Type
8235          {
8236             refCount = 1;
8237             kind = pointerType;
8238             type = ProcessType(exp._renew.typeName.qualifiers, exp._renew.typeName.declarator);
8239          };
8240          DeclareType(curExternal, exp.expType.type, true, false);
8241          break;
8242       case opExp:
8243       {
8244          bool assign = false, boolResult = false, boolOps = false;
8245          Type type1 = null, type2 = null;
8246          bool useDestType = false, useSideType = false;
8247          Location oldyylloc = yylloc;
8248          bool useSideUnit = false;
8249          Class destClass = (exp.destType && exp.destType.kind == classType && exp.destType._class) ? exp.destType._class.registered : null;
8250
8251          // Dummy type to prevent ProcessExpression of operands to say unresolved identifiers yet
8252          Type dummy
8253          {
8254             count = 1;
8255             refCount = 1;
8256          };
8257
8258          switch(exp.op.op)
8259          {
8260             // Assignment Operators
8261             case '=':
8262             case MUL_ASSIGN:
8263             case DIV_ASSIGN:
8264             case MOD_ASSIGN:
8265             case ADD_ASSIGN:
8266             case SUB_ASSIGN:
8267             case LEFT_ASSIGN:
8268             case RIGHT_ASSIGN:
8269             case AND_ASSIGN:
8270             case XOR_ASSIGN:
8271             case OR_ASSIGN:
8272                assign = true;
8273                break;
8274             // boolean Operators
8275             case '!':
8276                // Expect boolean operators
8277                //boolOps = true;
8278                //boolResult = true;
8279                break;
8280             case AND_OP:
8281             case OR_OP:
8282                // Expect boolean operands
8283                boolOps = true;
8284                boolResult = true;
8285                break;
8286             // Comparisons
8287             case EQ_OP:
8288             case '<':
8289             case '>':
8290             case LE_OP:
8291             case GE_OP:
8292             case NE_OP:
8293                // Gives boolean result
8294                boolResult = true;
8295                useSideType = true;
8296                break;
8297             case '+':
8298             case '-':
8299                useSideUnit = true;
8300                useSideType = true;
8301                useDestType = true;
8302                break;
8303
8304             case LEFT_OP:
8305             case RIGHT_OP:
8306                // useSideType = true;
8307                // useDestType = true;
8308                break;
8309
8310             case '|':
8311             case '^':
8312                useSideType = true;
8313                useDestType = true;
8314                break;
8315
8316             case '/':
8317             case '%':
8318                useSideType = true;
8319                useDestType = true;
8320                break;
8321             case '&':
8322             case '*':
8323                if(exp.op.exp1)
8324                {
8325                   // For & operator, useDestType nicely ensures the result will fit in a bool (TODO: Fix for generic enum)
8326                   useSideType = true;
8327                   useDestType = true;
8328                }
8329                break;
8330
8331             /*// Implement speed etc.
8332             case '*':
8333             case '/':
8334                break;
8335             */
8336          }
8337          if(exp.op.op == '&')
8338          {
8339             // Added this here earlier for Iterator address as key
8340             if(!exp.op.exp1 && exp.op.exp2 && exp.op.exp2.type == identifierExp && exp.op.exp2.identifier)
8341             {
8342                Identifier id = exp.op.exp2.identifier;
8343                Symbol symbol = FindSymbol(id.string, curContext, topContext, false, id._class && id._class.name == null);
8344                if(symbol && symbol.isIterator == 2)
8345                {
8346                   exp.type = memberExp;
8347                   exp.member.exp = exp.op.exp2;
8348                   exp.member.member = MkIdentifier("key");
8349                   exp.expType = null;
8350                   exp.op.exp2.expType = symbol.type;
8351                   symbol.type.refCount++;
8352                   ProcessExpressionType(exp);
8353                   FreeType(dummy);
8354                   break;
8355                }
8356                // exp.op.exp2.usage.usageRef = true;
8357             }
8358          }
8359
8360          //dummy.kind = TypeDummy;
8361          if(exp.op.exp1)
8362          {
8363             // Added this check here to use the dest type only for units derived from the base unit
8364             // So that untyped units will use the side unit as opposed to the untyped destination unit
8365             // This fixes (#771) sin(Degrees { 5 } + 5) to be equivalent to sin(Degrees { 10 }), since sin expects a generic Angle
8366             if(exp.op.exp2 && useSideUnit && useDestType && destClass && destClass.type == unitClass && destClass.base.type != unitClass)
8367                useDestType = false;
8368
8369             if(destClass && useDestType &&
8370               ((destClass.type == unitClass && useSideUnit) || destClass.type == enumClass || destClass.type == bitClass))
8371
8372               //(exp.destType._class.registered.type == unitClass || exp.destType._class.registered.type == enumClass) && useDestType)
8373             {
8374                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8375                exp.op.exp1.destType = exp.destType;
8376                exp.op.exp1.opDestType = true;
8377                if(exp.destType)
8378                   exp.destType.refCount++;
8379             }
8380             else if(!assign)
8381             {
8382                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8383                exp.op.exp1.destType = dummy;
8384                dummy.refCount++;
8385             }
8386
8387             // TESTING THIS HERE...
8388             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count++;
8389                ProcessExpressionType(exp.op.exp1);
8390             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count--;
8391
8392             exp.op.exp1.opDestType = false;
8393
8394             // Fix for unit and ++ / --
8395             if(!exp.op.exp2 && (exp.op.op == INC_OP || exp.op.op == DEC_OP) && exp.op.exp1.expType && exp.op.exp1.expType.kind == classType &&
8396                exp.op.exp1.expType._class && exp.op.exp1.expType._class.registered && exp.op.exp1.expType._class.registered.type == unitClass)
8397             {
8398                exp.op.exp2 = MkExpConstant("1");
8399                exp.op.op = exp.op.op == INC_OP ? ADD_ASSIGN : SUB_ASSIGN;
8400                assign = true;
8401             }
8402
8403             if(exp.op.exp1.destType == dummy)
8404             {
8405                FreeType(dummy);
8406                exp.op.exp1.destType = null;
8407             }
8408
8409             if(exp.op.exp2)
8410             {
8411                if(!assign && exp.op.exp1.expType && (exp.op.exp1.expType.kind == charType || exp.op.exp1.expType.kind == shortType))
8412                {
8413                   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 };
8414                   FreeType(exp.op.exp1.expType);
8415                   exp.op.exp1.expType = type;
8416                }
8417             }
8418
8419             type1 = exp.op.exp1.expType;
8420          }
8421
8422          if(exp.op.exp2)
8423          {
8424             char expString[10240];
8425             expString[0] = '\0';
8426             if(exp.op.exp2.type == instanceExp && !exp.op.exp2.instance._class)
8427             {
8428                if(exp.op.exp1)
8429                {
8430                   exp.op.exp2.destType = exp.op.exp1.expType;
8431                   if(exp.op.exp1.expType)
8432                      exp.op.exp1.expType.refCount++;
8433                }
8434                else
8435                {
8436                   exp.op.exp2.destType = exp.destType;
8437                   if(!exp.op.exp1 || (exp.op.op != '&' && exp.op.op != '^'))
8438                      exp.op.exp2.opDestType = true;
8439                   if(exp.destType)
8440                      exp.destType.refCount++;
8441                }
8442
8443                if(type1) type1.refCount++;
8444                exp.expType = type1;
8445             }
8446             else if(assign)
8447             {
8448                if(inCompiler)
8449                   PrintExpression(exp.op.exp2, expString);
8450
8451                if(type1 && type1.kind == pointerType)
8452                {
8453                   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 ||
8454                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN)
8455                      Compiler_Error($"operator %s illegal on pointer\n", exp.op.op);
8456                   else if(exp.op.op == '=')
8457                   {
8458                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8459                      exp.op.exp2.destType = type1;
8460                      if(type1)
8461                         type1.refCount++;
8462                   }
8463                }
8464                else
8465                {
8466                   // Don't convert to the type for those... (e.g.: Degrees a; a /= 2;)
8467                   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/* ||
8468                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN*/);
8469                   else
8470                   {
8471                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8472                      exp.op.exp2.destType = type1;
8473                      if(type1)
8474                         type1.refCount++;
8475                   }
8476                }
8477                if(type1) type1.refCount++;
8478                exp.expType = type1;
8479             }
8480             else if(destClass &&
8481                   ((destClass.type == unitClass && useDestType && useSideUnit) ||
8482                   (destClass.type == enumClass && useDestType)))
8483             {
8484                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8485                exp.op.exp2.destType = exp.destType;
8486                if(exp.op.op != '&' && exp.op.op != '^')
8487                   exp.op.exp2.opDestType = true;
8488                if(exp.destType)
8489                   exp.destType.refCount++;
8490             }
8491             else
8492             {
8493                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8494                exp.op.exp2.destType = dummy;
8495                dummy.refCount++;
8496             }
8497
8498             // TESTING THIS HERE... (DANGEROUS)
8499             if(type1 && boolResult && useSideType && type1.kind == classType && type1._class && type1._class.registered &&
8500                (type1._class.registered.type == bitClass || type1._class.registered.type == enumClass))
8501             {
8502                FreeType(exp.op.exp2.destType);
8503                exp.op.exp2.destType = type1;
8504                type1.refCount++;
8505             }
8506             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count++;
8507             // Cannot lose the cast on a sizeof
8508             if(exp.op.op == SIZEOF)
8509             {
8510                Expression e = exp.op.exp2;
8511                while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
8512                {
8513                   if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
8514                   {
8515                      if(e.type == extensionCompoundExp)
8516                         e = ((Statement)e.compound.compound.statements->last).expressions->last;
8517                      else
8518                         e = e.list->last;
8519                   }
8520                }
8521                if(e.type == castExp && e.cast.exp)
8522                   e.cast.exp.needCast = true;
8523             }
8524             ProcessExpressionType(exp.op.exp2);
8525             exp.op.exp2.opDestType = false;
8526             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count--;
8527
8528             if(!assign && (exp.op.exp1 || exp.op.op == '~'))
8529             {
8530                if(exp.op.exp2.expType && (exp.op.exp2.expType.kind == charType || exp.op.exp2.expType.kind == shortType))
8531                {
8532                   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 };
8533                   FreeType(exp.op.exp2.expType);
8534                   exp.op.exp2.expType = type;
8535                }
8536             }
8537
8538             if(assign && type1 && type1.kind == pointerType && exp.op.exp2.expType)
8539             {
8540                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)
8541                {
8542                   if(exp.op.op != '=' && type1.type.kind == voidType)
8543                      Compiler_Error($"void *: unknown size\n");
8544                }
8545                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||
8546                            (type1.type.kind == voidType && exp.op.exp2.expType.kind == classType && exp.op.exp2.expType._class.registered &&
8547                               (exp.op.exp2.expType._class.registered.type == normalClass ||
8548                               exp.op.exp2.expType._class.registered.type == structClass ||
8549                               exp.op.exp2.expType._class.registered.type == noHeadClass)))
8550                {
8551                   if(exp.op.op == ADD_ASSIGN)
8552                      Compiler_Error($"cannot add two pointers\n");
8553                }
8554                else if((exp.op.exp2.expType.kind == classType && type1.kind == pointerType && type1.type.kind == classType &&
8555                   type1.type._class == exp.op.exp2.expType._class && exp.op.exp2.expType._class.registered && exp.op.exp2.expType._class.registered.type == structClass))
8556                {
8557                   if(exp.op.op == ADD_ASSIGN)
8558                      Compiler_Error($"cannot add two pointers\n");
8559                }
8560                else if(inCompiler)
8561                {
8562                   char type1String[1024];
8563                   char type2String[1024];
8564                   type1String[0] = '\0';
8565                   type2String[0] = '\0';
8566
8567                   PrintType(exp.op.exp2.expType, type1String, false, true);
8568                   PrintType(type1, type2String, false, true);
8569                   ChangeCh(expString, '\n', ' ');
8570                   Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1String, type2String);
8571                }
8572             }
8573
8574             if(exp.op.exp2.destType == dummy)
8575             {
8576                FreeType(dummy);
8577                exp.op.exp2.destType = null;
8578             }
8579
8580             if(exp.op.op == '-' && !exp.op.exp1 && exp.op.exp2.expType && !exp.op.exp2.expType.isSigned)
8581             {
8582                type2 = { };
8583                type2.refCount = 1;
8584                CopyTypeInto(type2, exp.op.exp2.expType);
8585                type2.isSigned = true;
8586             }
8587             else if(exp.op.op == '~' && !exp.op.exp1 && exp.op.exp2.expType && (!exp.op.exp2.expType.isSigned || exp.op.exp2.expType.kind != intType))
8588             {
8589                type2 = { kind = intType };
8590                type2.refCount = 1;
8591                type2.isSigned = true;
8592             }
8593             else
8594             {
8595                type2 = exp.op.exp2.expType;
8596                if(type2) type2.refCount++;
8597             }
8598          }
8599
8600          dummy.kind = voidType;
8601
8602          if(exp.op.op == SIZEOF)
8603          {
8604             exp.expType = Type
8605             {
8606                refCount = 1;
8607                kind = intSizeType;
8608             };
8609             exp.isConstant = true;
8610          }
8611          // Get type of dereferenced pointer
8612          else if(exp.op.op == '*' && !exp.op.exp1)
8613          {
8614             exp.expType = Dereference(type2);
8615             if(type2 && type2.kind == classType)
8616                notByReference = true;
8617          }
8618          else if(exp.op.op == '&' && !exp.op.exp1)
8619             exp.expType = Reference(type2);
8620          else if(exp.op.op == LEFT_OP || exp.op.op == RIGHT_OP)
8621          {
8622             if(exp.op.exp1.expType)
8623             {
8624                exp.expType = exp.op.exp1.expType;
8625                exp.expType.refCount++;
8626             }
8627          }
8628          else if(!assign)
8629          {
8630             if(boolOps)
8631             {
8632                if(exp.op.exp1)
8633                {
8634                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8635                   exp.op.exp1.destType = MkClassType("bool");
8636                   exp.op.exp1.destType.truth = true;
8637                   if(!exp.op.exp1.expType)
8638                      ProcessExpressionType(exp.op.exp1);
8639                   else
8640                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8641                   FreeType(exp.op.exp1.expType);
8642                   exp.op.exp1.expType = MkClassType("bool");
8643                   exp.op.exp1.expType.truth = true;
8644                }
8645                if(exp.op.exp2)
8646                {
8647                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8648                   exp.op.exp2.destType = MkClassType("bool");
8649                   exp.op.exp2.destType.truth = true;
8650                   if(!exp.op.exp2.expType)
8651                      ProcessExpressionType(exp.op.exp2);
8652                   else
8653                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8654                   FreeType(exp.op.exp2.expType);
8655                   exp.op.exp2.expType = MkClassType("bool");
8656                   exp.op.exp2.expType.truth = true;
8657                }
8658             }
8659             else if(exp.op.exp1 && exp.op.exp2 &&
8660                ((useSideType /*&&
8661                      (useSideUnit ||
8662                         ((!type1 || type1.kind != classType || type1._class.registered.type != unitClass) &&
8663                          (!type2 || type2.kind != classType || type2._class.registered.type != unitClass)))*/) ||
8664                   ((!type1 || type1.kind != classType || !strcmp(type1._class.string, "String")) &&
8665                   (!type2 || type2.kind != classType || !strcmp(type2._class.string, "String")))))
8666             {
8667                if(type1 && type2 &&
8668                   // If either both are class or both are not class
8669                   ((type1.kind == classType && type1._class && strcmp(type1._class.string, "String")) == (type2.kind == classType && type2._class && strcmp(type2._class.string, "String"))))
8670                {
8671                   // Added this check for enum subtraction to result in an int type:
8672                   if(exp.op.op == '-' &&
8673                      ((type1.kind == classType && type1._class.registered && type1._class.registered.type == enumClass) ||
8674                       (type2.kind == classType && type2._class.registered && type2._class.registered.type == enumClass)) )
8675                   {
8676                      Type intType;
8677                      if(!type1._class.registered.dataType)
8678                         type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
8679                      if(!type2._class.registered.dataType)
8680                         type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
8681
8682                      intType = ProcessTypeString(
8683                         (type1._class.registered.dataType.kind == int64Type || type2._class.registered.dataType.kind == int64Type) ? "int64" : "int", false);
8684
8685                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8686                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8687                      exp.op.exp1.destType = intType;
8688                      exp.op.exp2.destType = intType;
8689                      intType.refCount++;
8690                   }
8691                   else
8692                   {
8693                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8694                      exp.op.exp2.destType = type1;
8695                      type1.refCount++;
8696                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8697                      exp.op.exp1.destType = type2;
8698                      type2.refCount++;
8699                   }
8700
8701                   // Warning here for adding Radians + Degrees with no destination type
8702                   if(!boolResult && type1.kind == classType && (!exp.destType || exp.destType.kind != classType) &&
8703                      type1._class.registered && type1._class.registered.type == unitClass &&
8704                      type2._class.registered && type2._class.registered.type == unitClass &&
8705                      type1._class.registered != type2._class.registered)
8706                      Compiler_Warning($"operating on %s and %s with an untyped result, assuming %s\n",
8707                         type1._class.string, type2._class.string, type1._class.string);
8708
8709                   if(type1.kind == pointerType && type1.type.kind == templateType && type2.kind != pointerType)
8710                   {
8711                      Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8712                      if(argExp)
8713                      {
8714                         Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8715
8716                         exp.op.exp1 = MkExpBrackets(MkListOne(MkExpCast(
8717                            MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
8718                            exp.op.exp1)));
8719
8720                         ProcessExpressionType(exp.op.exp1);
8721
8722                         if(type2.kind != pointerType)
8723                         {
8724                            ProcessExpressionType(classExp);
8725
8726                            exp.op.exp2 = MkExpBrackets(MkListOne(MkExpOp(exp.op.exp2, '*', MkExpMember(classExp, MkIdentifier("typeSize")) )));
8727
8728                            if(!exp.op.exp2.expType)
8729                            {
8730                               if(type2)
8731                                  FreeType(type2);
8732                               type2 = exp.op.exp2.expType = ProcessTypeString("int", false);
8733                               type2.refCount++;
8734                            }
8735
8736                            ProcessExpressionType(exp.op.exp2);
8737                         }
8738                      }
8739                   }
8740
8741                   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)))
8742                   {
8743                      if(type1.kind != classType && type1.type.kind == voidType)
8744                         Compiler_Error($"void *: unknown size\n");
8745                      exp.expType = type1;
8746                      if(type1) type1.refCount++;
8747                   }
8748                   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)))
8749                   {
8750                      if(type2.kind != classType && type2.type.kind == voidType)
8751                         Compiler_Error($"void *: unknown size\n");
8752                      exp.expType = type2;
8753                      if(type2) type2.refCount++;
8754                   }
8755                   else if((type1.kind == pointerType && type2.kind != pointerType && type2.kind != arrayType && type2.kind != functionType && type2.kind != methodType && type2.kind != classType && type2.kind != subClassType) ||
8756                           (type2.kind == pointerType && type1.kind != pointerType && type1.kind != arrayType && type1.kind != functionType && type1.kind != methodType && type1.kind != classType && type1.kind != subClassType))
8757                   {
8758                      Compiler_Warning($"different levels of indirection\n");
8759                   }
8760                   else
8761                   {
8762                      bool success = false;
8763                      if(type1.kind == pointerType && type2.kind == pointerType)
8764                      {
8765                         if(exp.op.op == '+')
8766                            Compiler_Error($"cannot add two pointers\n");
8767                         else if(exp.op.op == '-')
8768                         {
8769                            // Pointer Subtraction gives integer
8770                            if(MatchTypes(type1.type, type2.type, null, null, null, false, false, false, false, false))
8771                            {
8772                               exp.expType = Type
8773                               {
8774                                  kind = intType;
8775                                  refCount = 1;
8776                               };
8777                               success = true;
8778
8779                               if(type1.type.kind == templateType)
8780                               {
8781                                  Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8782                                  if(argExp)
8783                                  {
8784                                     Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8785
8786                                     ProcessExpressionType(classExp);
8787
8788                                     exp.type = bracketsExp;
8789                                     exp.list = MkListOne(MkExpOp(
8790                                        MkExpBrackets(MkListOne(MkExpOp(
8791                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp1)))
8792                                              , exp.op.op,
8793                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp2)))))), '/',
8794                                              MkExpMember(classExp, MkIdentifier("typeSize"))));
8795
8796                                     ProcessExpressionType(((Expression)exp.list->first).op.exp2);
8797                                     FreeType(dummy);
8798                                     return;
8799                                  }
8800                               }
8801                            }
8802                         }
8803                      }
8804
8805                      if(!success && exp.op.exp1.type == constantExp)
8806                      {
8807                         // If first expression is constant, try to match that first
8808                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8809                         {
8810                            if(exp.expType) FreeType(exp.expType);
8811                            exp.expType = exp.op.exp1.destType;
8812                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8813                            success = true;
8814                         }
8815                         else if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
8816                         {
8817                            if(exp.expType) FreeType(exp.expType);
8818                            exp.expType = exp.op.exp2.destType;
8819                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8820                            success = true;
8821                         }
8822                      }
8823                      else if(!success)
8824                      {
8825                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
8826                         {
8827                            if(exp.expType) FreeType(exp.expType);
8828                            exp.expType = exp.op.exp2.destType;
8829                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8830                            success = true;
8831                         }
8832                         else if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8833                         {
8834                            if(exp.expType) FreeType(exp.expType);
8835                            exp.expType = exp.op.exp1.destType;
8836                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8837                            success = true;
8838                         }
8839                      }
8840                      if(!success)
8841                      {
8842                         char expString1[10240];
8843                         char expString2[10240];
8844                         char type1[1024];
8845                         char type2[1024];
8846                         expString1[0] = '\0';
8847                         expString2[0] = '\0';
8848                         type1[0] = '\0';
8849                         type2[0] = '\0';
8850                         if(inCompiler)
8851                         {
8852                            PrintExpression(exp.op.exp1, expString1);
8853                            ChangeCh(expString1, '\n', ' ');
8854                            PrintExpression(exp.op.exp2, expString2);
8855                            ChangeCh(expString2, '\n', ' ');
8856                            PrintType(exp.op.exp1.expType, type1, false, true);
8857                            PrintType(exp.op.exp2.expType, type2, false, true);
8858                         }
8859
8860                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1, expString2, type2);
8861                      }
8862                   }
8863                }
8864                // ADDED THESE TWO FROM OUTSIDE useSideType CHECK
8865                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type2 && type1 && type2.kind == classType && type1.kind != classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
8866                {
8867                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8868                   // Convert e.g. / 4 into / 4.0
8869                   exp.op.exp1.destType = type2._class.registered.dataType;
8870                   if(type2._class.registered.dataType)
8871                      type2._class.registered.dataType.refCount++;
8872                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8873                   exp.expType = type2;
8874                   if(type2) type2.refCount++;
8875                }
8876                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type1 && type2 && type1.kind == classType && type2.kind != classType && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
8877                {
8878                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8879                   // Convert e.g. / 4 into / 4.0
8880                   exp.op.exp2.destType = type1._class.registered.dataType;
8881                   if(type1._class.registered.dataType)
8882                      type1._class.registered.dataType.refCount++;
8883                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8884                   exp.expType = type1;
8885                   if(type1) type1.refCount++;
8886                }
8887                else if(type1)
8888                {
8889                   bool valid = false;
8890
8891                   if(!boolResult && useSideUnit && type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8892                   {
8893                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8894
8895                      if(!type1._class.registered.dataType)
8896                         type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
8897                      exp.op.exp2.destType = type1._class.registered.dataType;
8898                      exp.op.exp2.destType.refCount++;
8899
8900                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8901                      if(type2)
8902                         FreeType(type2);
8903                      type2 = exp.op.exp2.destType;
8904                      if(type2) type2.refCount++;
8905
8906                      exp.expType = type2;
8907                      type2.refCount++;
8908                   }
8909
8910                   if(!boolResult && useSideUnit && type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8911                   {
8912                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8913
8914                      if(!type2._class.registered.dataType)
8915                         type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
8916                      exp.op.exp1.destType = type2._class.registered.dataType;
8917                      exp.op.exp1.destType.refCount++;
8918
8919                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8920                      type1 = exp.op.exp1.destType;
8921                      exp.expType = type1;
8922                      type1.refCount++;
8923                   }
8924
8925                   // TESTING THIS NEW CODE
8926                   if(!boolResult || exp.op.op == '>' || exp.op.op == '<' || exp.op.op == GE_OP || exp.op.op == LE_OP)
8927                   {
8928                      bool op1IsEnum = type1 && type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass;
8929                      bool op2IsEnum = type2 && type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass;
8930                      if(exp.op.op == '*' || exp.op.op == '/' || exp.op.op == '-' || exp.op.op == '|' || exp.op.op == '^')
8931                      {
8932                         // Convert the enum to an int instead for these operators
8933                         if(op1IsEnum && exp.op.exp2.expType)
8934                         {
8935                            if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false, false))
8936                            {
8937                               if(exp.expType) FreeType(exp.expType);
8938                               exp.expType = exp.op.exp2.expType;
8939                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8940                               valid = true;
8941                            }
8942                         }
8943                         else if(op2IsEnum && exp.op.exp1.expType)
8944                         {
8945                            if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false, false))
8946                            {
8947                               if(exp.expType) FreeType(exp.expType);
8948                               exp.expType = exp.op.exp1.expType;
8949                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8950                               valid = true;
8951                            }
8952                         }
8953                      }
8954                      else
8955                      {
8956                         if(op1IsEnum && exp.op.exp2.expType)
8957                         {
8958                            if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false, false))
8959                            {
8960                               if(exp.expType) FreeType(exp.expType);
8961                               exp.expType = exp.op.exp1.expType;
8962                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8963                               valid = true;
8964                            }
8965                         }
8966                         else if(op2IsEnum && exp.op.exp1.expType)
8967                         {
8968                            if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false, false))
8969                            {
8970                               if(exp.expType) FreeType(exp.expType);
8971                               exp.expType = exp.op.exp2.expType;
8972                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8973                               valid = true;
8974                            }
8975                         }
8976                      }
8977                   }
8978
8979                   if(!valid)
8980                   {
8981                      // 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
8982                      if(type2 && type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass &&
8983                         (type1.kind != classType || !type1._class || !type1._class.registered || type1._class.registered.type != unitClass))
8984                      {
8985                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8986                         exp.op.exp1.destType = type2;
8987                         type2.refCount++;
8988
8989                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8990                         {
8991                            if(exp.expType) FreeType(exp.expType);
8992                            exp.expType = exp.op.exp1.destType;
8993                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8994                         }
8995                      }
8996                      else
8997                      {
8998                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8999                         exp.op.exp2.destType = type1;
9000                         type1.refCount++;
9001
9002                      /*
9003                      // Maybe this was meant to be an enum...
9004                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
9005                      {
9006                         Type oldType = exp.op.exp2.expType;
9007                         exp.op.exp2.expType = null;
9008                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
9009                            FreeType(oldType);
9010                         else
9011                            exp.op.exp2.expType = oldType;
9012                      }
9013                      */
9014
9015                      /*
9016                      // TESTING THIS HERE... LATEST ADDITION
9017                      if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
9018                      {
9019                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9020                         exp.op.exp2.destType = type2._class.registered.dataType;
9021                         if(type2._class.registered.dataType)
9022                            type2._class.registered.dataType.refCount++;
9023                         CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
9024
9025                         //exp.expType = type2._class.registered.dataType; //type2;
9026                         //if(type2) type2.refCount++;
9027                      }
9028
9029                      // TESTING THIS HERE... LATEST ADDITION
9030                      if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
9031                      {
9032                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9033                         exp.op.exp1.destType = type1._class.registered.dataType;
9034                         if(type1._class.registered.dataType)
9035                            type1._class.registered.dataType.refCount++;
9036                         CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
9037                         exp.expType = type1._class.registered.dataType; //type1;
9038                         if(type1) type1.refCount++;
9039                      }
9040                      */
9041
9042                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
9043                         {
9044                            if(exp.expType) FreeType(exp.expType);
9045                            exp.expType = exp.op.exp2.destType;
9046                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
9047                         }
9048                         else if(type1 && type2)
9049                         {
9050                            char expString1[10240];
9051                            char expString2[10240];
9052                            char type1String[1024];
9053                            char type2String[1024];
9054                            expString1[0] = '\0';
9055                            expString2[0] = '\0';
9056                            type1String[0] = '\0';
9057                            type2String[0] = '\0';
9058                            if(inCompiler)
9059                            {
9060                               PrintExpression(exp.op.exp1, expString1);
9061                               ChangeCh(expString1, '\n', ' ');
9062                               PrintExpression(exp.op.exp2, expString2);
9063                               ChangeCh(expString2, '\n', ' ');
9064                               PrintType(exp.op.exp1.expType, type1String, false, true);
9065                               PrintType(exp.op.exp2.expType, type2String, false, true);
9066                            }
9067
9068                            Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1String, expString2, type2String);
9069
9070                            if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
9071                            {
9072                               exp.expType = exp.op.exp1.expType;
9073                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
9074                            }
9075                            else if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
9076                            {
9077                               exp.expType = exp.op.exp2.expType;
9078                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
9079                            }
9080                         }
9081                      }
9082                   }
9083                }
9084                else if(type2)
9085                {
9086                   // Maybe this was meant to be an enum...
9087                   if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
9088                   {
9089                      Type oldType = exp.op.exp1.expType;
9090                      exp.op.exp1.expType = null;
9091                      if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
9092                         FreeType(oldType);
9093                      else
9094                         exp.op.exp1.expType = oldType;
9095                   }
9096
9097                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9098                   exp.op.exp1.destType = type2;
9099                   type2.refCount++;
9100                   /*
9101                   // TESTING THIS HERE... LATEST ADDITION
9102                   if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
9103                   {
9104                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9105                      exp.op.exp1.destType = type1._class.registered.dataType;
9106                      if(type1._class.registered.dataType)
9107                         type1._class.registered.dataType.refCount++;
9108                   }
9109
9110                   // TESTING THIS HERE... LATEST ADDITION
9111                   if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
9112                   {
9113                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9114                      exp.op.exp2.destType = type2._class.registered.dataType;
9115                      if(type2._class.registered.dataType)
9116                         type2._class.registered.dataType.refCount++;
9117                   }
9118                   */
9119
9120                   if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
9121                   {
9122                      if(exp.expType) FreeType(exp.expType);
9123                      exp.expType = exp.op.exp1.destType;
9124                      if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
9125                   }
9126                }
9127             }
9128             else if(type2 && (!type1 || (type2.kind == classType && type1.kind != classType)))
9129             {
9130                if(type1 && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
9131                {
9132                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9133                   // Convert e.g. / 4 into / 4.0
9134                   exp.op.exp1.destType = type2._class.registered.dataType;
9135                   if(type2._class.registered.dataType)
9136                      type2._class.registered.dataType.refCount++;
9137                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
9138                }
9139                if(exp.op.op == '!')
9140                {
9141                   exp.expType = MkClassType("bool");
9142                   exp.expType.truth = true;
9143                }
9144                else
9145                {
9146                   exp.expType = type2;
9147                   if(type2) type2.refCount++;
9148                }
9149             }
9150             else if(type1 && (!type2 || (type1.kind == classType && type2.kind != classType)))
9151             {
9152                if(type2 && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
9153                {
9154                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9155                   // Convert e.g. / 4 into / 4.0
9156                   exp.op.exp2.destType = type1._class.registered.dataType;
9157                   if(type1._class.registered.dataType)
9158                      type1._class.registered.dataType.refCount++;
9159                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
9160                }
9161                exp.expType = type1;
9162                if(type1) type1.refCount++;
9163             }
9164          }
9165
9166          yylloc = exp.loc;
9167          if(exp.op.exp1 && !exp.op.exp1.expType)
9168          {
9169             char expString[10000];
9170             expString[0] = '\0';
9171             if(inCompiler)
9172             {
9173                PrintExpression(exp.op.exp1, expString);
9174                ChangeCh(expString, '\n', ' ');
9175             }
9176             if(expString[0])
9177                Compiler_Error($"couldn't determine type of %s\n", expString);
9178          }
9179          if(exp.op.exp2 && !exp.op.exp2.expType)
9180          {
9181             char expString[10240];
9182             expString[0] = '\0';
9183             if(inCompiler)
9184             {
9185                PrintExpression(exp.op.exp2, expString);
9186                ChangeCh(expString, '\n', ' ');
9187             }
9188             if(expString[0])
9189                Compiler_Error($"couldn't determine type of %s\n", expString);
9190          }
9191
9192          if(boolResult)
9193          {
9194             FreeType(exp.expType);
9195             exp.expType = MkClassType("bool");
9196             exp.expType.truth = true;
9197          }
9198
9199          if(exp.op.op != SIZEOF)
9200             exp.isConstant = (!exp.op.exp1 || exp.op.exp1.isConstant) &&
9201                (!exp.op.exp2 || exp.op.exp2.isConstant);
9202
9203          if(exp.op.op == SIZEOF && exp.op.exp2.expType)
9204          {
9205             DeclareType(curExternal, exp.op.exp2.expType, true, false);
9206          }
9207
9208          if(exp.op.op == DELETE && exp.op.exp2 && exp.op.exp2.expType && exp.op.exp2.expType.specConst)
9209             Compiler_Warning($"deleting const qualified object\n");
9210
9211          yylloc = oldyylloc;
9212
9213          FreeType(dummy);
9214          if(type2)
9215             FreeType(type2);
9216          break;
9217       }
9218       case bracketsExp:
9219       case extensionExpressionExp:
9220       {
9221          Expression e;
9222          exp.isConstant = true;
9223          for(e = exp.list->first; e; e = e.next)
9224          {
9225             //bool inced = false;
9226             if(!e.next)
9227             {
9228                FreeType(e.destType);
9229                e.opDestType = exp.opDestType;
9230                e.destType = exp.destType;
9231                if(e.destType) { exp.destType.refCount++; /*e.destType.count++; inced = true;*/ }
9232             }
9233             ProcessExpressionType(e);
9234             /*if(inced)
9235                exp.destType.count--;*/
9236             if(!exp.expType && !e.next)
9237             {
9238                exp.expType = e.expType;
9239                if(e.expType) e.expType.refCount++;
9240             }
9241             if(!e.isConstant)
9242                exp.isConstant = false;
9243          }
9244
9245          // In case a cast became a member...
9246          e = exp.list->first;
9247          if(!e.next && e.type == memberExp)
9248          {
9249             // Preserve prev, next
9250             Expression next = exp.next, prev = exp.prev;
9251
9252
9253             FreeType(exp.expType);
9254             FreeType(exp.destType);
9255             delete exp.list;
9256
9257             *exp = *e;
9258
9259             exp.prev = prev;
9260             exp.next = next;
9261
9262             delete e;
9263
9264             ProcessExpressionType(exp);
9265          }
9266          break;
9267       }
9268       case indexExp:
9269       {
9270          Expression e;
9271          exp.isConstant = true;
9272
9273          ProcessExpressionType(exp.index.exp);
9274          if(!exp.index.exp.isConstant)
9275             exp.isConstant = false;
9276
9277          if(exp.index.exp.expType)
9278          {
9279             Type source = exp.index.exp.expType;
9280             if(source.kind == classType && source._class && source._class.registered)
9281             {
9282                Class _class = source._class.registered;
9283                Class c = _class.templateClass ? _class.templateClass : _class;
9284                if(_class != containerClass && eClass_IsDerived(c, containerClass) && _class.templateArgs)
9285                {
9286                   exp.expType = ProcessTypeString(_class.templateArgs[2].dataTypeString, false);
9287
9288                   if(exp.index.index && exp.index.index->last)
9289                   {
9290                      Type type = ProcessTypeString(_class.templateArgs[1].dataTypeString, false);
9291
9292                      if(type.kind == classType) type.constant = true;
9293                      else if(type.kind == pointerType)
9294                      {
9295                         Type t = type;
9296                         while(t.kind == pointerType) t = t.type;
9297                         t.constant = true;
9298                      }
9299
9300                      ((Expression)exp.index.index->last).destType = type;
9301                   }
9302                }
9303             }
9304          }
9305
9306          for(e = exp.index.index->first; e; e = e.next)
9307          {
9308             if(!e.next && exp.index.exp.expType && exp.index.exp.expType.kind == arrayType && exp.index.exp.expType.enumClass)
9309             {
9310                if(e.destType) FreeType(e.destType);
9311                e.destType = MkClassType(exp.index.exp.expType.enumClass.string);
9312             }
9313             ProcessExpressionType(e);
9314             if(!e.next)
9315             {
9316                // Check if this type is int
9317             }
9318             if(!e.isConstant)
9319                exp.isConstant = false;
9320          }
9321
9322          if(!exp.expType)
9323             exp.expType = Dereference(exp.index.exp.expType);
9324          if(exp.expType)
9325             DeclareType(curExternal, exp.expType, true, false);
9326          break;
9327       }
9328       case callExp:
9329       {
9330          Expression e;
9331          Type functionType;
9332          Type methodType = null;
9333          char name[1024];
9334          name[0] = '\0';
9335
9336          if(inCompiler)
9337          {
9338             PrintExpression(exp.call.exp,  name);
9339             if(exp.call.exp.expType && !exp.call.exp.expType.returnType)
9340             {
9341                //exp.call.exp.expType = null;
9342                PrintExpression(exp.call.exp,  name);
9343             }
9344          }
9345          if(exp.call.exp.type == identifierExp)
9346          {
9347             Expression idExp = exp.call.exp;
9348             Identifier id = idExp.identifier;
9349             if(!strcmp(id.string, "__builtin_frame_address"))
9350             {
9351                exp.expType = ProcessTypeString("void *", true);
9352                if(exp.call.arguments && exp.call.arguments->first)
9353                   ProcessExpressionType(exp.call.arguments->first);
9354                break;
9355             }
9356             else if(!strcmp(id.string, "__ENDIAN_PAD"))
9357             {
9358                exp.expType = ProcessTypeString("int", true);
9359                if(exp.call.arguments && exp.call.arguments->first)
9360                   ProcessExpressionType(exp.call.arguments->first);
9361                break;
9362             }
9363             else if(!strcmp(id.string, "Max") ||
9364                !strcmp(id.string, "Min") ||
9365                !strcmp(id.string, "Sgn") ||
9366                !strcmp(id.string, "Abs"))
9367             {
9368                Expression a = null;
9369                Expression b = null;
9370                Expression tempExp1 = null, tempExp2 = null;
9371                if((!strcmp(id.string, "Max") ||
9372                   !strcmp(id.string, "Min")) && exp.call.arguments->count == 2)
9373                {
9374                   a = exp.call.arguments->first;
9375                   b = exp.call.arguments->last;
9376                   tempExp1 = a;
9377                   tempExp2 = b;
9378                }
9379                else if(exp.call.arguments->count == 1)
9380                {
9381                   a = exp.call.arguments->first;
9382                   tempExp1 = a;
9383                }
9384
9385                if(a)
9386                {
9387                   exp.call.arguments->Clear();
9388                   idExp.identifier = null;
9389
9390                   FreeExpContents(exp);
9391
9392                   ProcessExpressionType(a);
9393                   if(b)
9394                      ProcessExpressionType(b);
9395
9396                   exp.type = bracketsExp;
9397                   exp.list = MkList();
9398
9399                   if(a.expType && (!b || b.expType))
9400                   {
9401                      if((!a.isConstant && a.type != identifierExp) || (b && !b.isConstant && b.type != identifierExp))
9402                      {
9403                         // Use the simpleStruct name/ids for now...
9404                         if(inCompiler)
9405                         {
9406                            OldList * specs = MkList();
9407                            OldList * decls = MkList();
9408                            Declaration decl;
9409                            char temp1[1024], temp2[1024];
9410
9411                            GetTypeSpecs(a.expType, specs);
9412
9413                            if(a && !a.isConstant && a.type != identifierExp)
9414                            {
9415                               sprintf(temp1, "__simpleStruct%d", curContext.simpleID++);
9416                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp1)), null));
9417                               tempExp1 = QMkExpId(temp1);
9418                               tempExp1.expType = a.expType;
9419                               if(a.expType)
9420                                  a.expType.refCount++;
9421                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp1), '=', a));
9422                            }
9423                            if(b && !b.isConstant && b.type != identifierExp)
9424                            {
9425                               sprintf(temp2, "__simpleStruct%d", curContext.simpleID++);
9426                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp2)), null));
9427                               tempExp2 = QMkExpId(temp2);
9428                               tempExp2.expType = b.expType;
9429                               if(b.expType)
9430                                  b.expType.refCount++;
9431                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp2), '=', b));
9432                            }
9433
9434                            decl = MkDeclaration(specs, decls);
9435                            if(!curCompound.compound.declarations)
9436                               curCompound.compound.declarations = MkList();
9437                            curCompound.compound.declarations->Insert(null, decl);
9438                         }
9439                      }
9440                   }
9441
9442                   if(!strcmp(id.string, "Max") || !strcmp(id.string, "Min"))
9443                   {
9444                      int op = (!strcmp(id.string, "Max")) ? '>' : '<';
9445                      ListAdd(exp.list,
9446                         MkExpCondition(MkExpBrackets(MkListOne(
9447                            MkExpOp(CopyExpression(tempExp1), op, CopyExpression(tempExp2)))),
9448                            MkListOne(CopyExpression(tempExp1)), CopyExpression(tempExp2)));
9449                      exp.expType = a.expType;
9450                      if(a.expType)
9451                         a.expType.refCount++;
9452                   }
9453                   else if(!strcmp(id.string, "Abs"))
9454                   {
9455                      ListAdd(exp.list,
9456                         MkExpCondition(MkExpBrackets(MkListOne(
9457                            MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9458                            MkListOne(MkExpOp(null, '-', CopyExpression(tempExp1))), CopyExpression(tempExp1)));
9459                      exp.expType = a.expType;
9460                      if(a.expType)
9461                         a.expType.refCount++;
9462                   }
9463                   else if(!strcmp(id.string, "Sgn"))
9464                   {
9465                      // ((!(a))?(0):(((a)<0)?(-1):(1)))
9466                      ListAdd(exp.list,
9467                         MkExpCondition(MkExpBrackets(MkListOne(
9468                            MkExpOp(null, '!', CopyExpression(tempExp1)))), MkListOne(MkExpConstant("0")),
9469                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(
9470                                  MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9471                                  MkListOne(MkExpConstant("-1")), MkExpConstant("1"))))));
9472                      exp.expType = ProcessTypeString("int", false);
9473                   }
9474
9475                   FreeExpression(tempExp1);
9476                   if(tempExp2) FreeExpression(tempExp2);
9477
9478                   FreeIdentifier(id);
9479                   break;
9480                }
9481             }
9482          }
9483
9484          {
9485             Type dummy
9486             {
9487                count = 1;
9488                refCount = 1;
9489             };
9490             if(!exp.call.exp.destType)
9491             {
9492                exp.call.exp.destType = dummy;
9493                dummy.refCount++;
9494             }
9495             ProcessExpressionType(exp.call.exp);
9496             if(exp.call.exp.destType == dummy)
9497             {
9498                FreeType(dummy);
9499                exp.call.exp.destType = null;
9500             }
9501             FreeType(dummy);
9502          }
9503
9504          // Check argument types against parameter types
9505          functionType = exp.call.exp.expType;
9506
9507          if(functionType && functionType.kind == TypeKind::methodType)
9508          {
9509             methodType = functionType;
9510             functionType = methodType.method.dataType;
9511
9512             //if(functionType.returnType && functionType.returnType.kind == thisClassType)
9513             // TOCHECK: Instead of doing this here could this be done per param?
9514             if(exp.call.exp.expType.usedClass)
9515             {
9516                char typeString[1024];
9517                typeString[0] = '\0';
9518                {
9519                   Symbol back = functionType.thisClass;
9520                   // Do not output class specifier here (thisclass was added to this)
9521                   functionType.thisClass = null;
9522                   PrintType(functionType, typeString, true, true);
9523                   functionType.thisClass = back;
9524                }
9525                if(strstr(typeString, "thisclass"))
9526                {
9527                   OldList * specs = MkList();
9528                   Declarator decl;
9529                   {
9530                      Context context = SetupTemplatesContext(exp.call.exp.expType.usedClass);
9531
9532                      decl = SpecDeclFromString(typeString, specs, null);
9533
9534                      // SET THIS TO FALSE WHEN PROCESSING THISCLASS OUTSIDE THE CLASS
9535                      if(thisClass != (exp.call.exp.expType.usedClass.templateClass ? exp.call.exp.expType.usedClass.templateClass :
9536                         exp.call.exp.expType.usedClass))
9537                         thisClassParams = false;
9538
9539                      ReplaceThisClassSpecifiers(specs, exp.call.exp.expType.usedClass);
9540                      {
9541                         Class backupThisClass = thisClass;
9542                         thisClass = exp.call.exp.expType.usedClass;
9543                         ProcessDeclarator(decl, true);
9544                         thisClass = backupThisClass;
9545                      }
9546
9547                      thisClassParams = true;
9548
9549                      functionType = ProcessType(specs, decl);
9550                      functionType.refCount = 0;
9551                      FinishTemplatesContext(context);
9552
9553                      // Mark parameters that were 'thisclass'
9554                      {
9555                         Type p, op;
9556                         for(p = functionType.params.first, op = methodType.method.dataType.params.first; p && op; p = p.next, op = op.next)
9557                         {
9558                            //p.wasThisClass = op.kind == thisClassType;
9559                            if(op.kind == thisClassType)
9560                               p.thisClassFrom = methodType.method._class;
9561                         }
9562                      }
9563                      if(methodType.method.dataType.returnType.kind == thisClassType)
9564                      {
9565                         // functionType.returnType.wasThisClass = true;
9566                         functionType.returnType.thisClassFrom = methodType.method._class;
9567                      }
9568                   }
9569
9570                   FreeList(specs, FreeSpecifier);
9571                   FreeDeclarator(decl);
9572                 }
9573             }
9574          }
9575          if(functionType && functionType.kind == pointerType && functionType.type && functionType.type.kind == TypeKind::functionType)
9576          {
9577             Type type = functionType.type;
9578             if(!functionType.refCount)
9579             {
9580                functionType.type = null;
9581                FreeType(functionType);
9582             }
9583             //methodType = functionType;
9584             functionType = type;
9585          }
9586          if(functionType && functionType.kind != TypeKind::functionType)
9587          {
9588             Compiler_Error($"called object %s is not a function\n", name);
9589          }
9590          else if(functionType)
9591          {
9592             bool emptyParams = false, noParams = false;
9593             Expression e = exp.call.arguments ? exp.call.arguments->first : null;
9594             Type type = functionType.params.first;
9595             Expression memberExp = (exp.call.exp.type == ExpressionType::memberExp) ? exp.call.exp : null;
9596             int extra = 0;
9597             Location oldyylloc = yylloc;
9598
9599             if(!type) emptyParams = true;
9600
9601             // WORKING ON THIS:
9602             if(functionType.extraParam && e && functionType.thisClass)
9603             {
9604                e.destType = MkClassType(functionType.thisClass.string);
9605                e = e.next;
9606             }
9607
9608             // WHY WAS THIS COMMENTED OUT ? Broke DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
9609             // Fixed #141 by adding '&& !functionType.extraParam'
9610             if(!functionType.staticMethod && !functionType.extraParam)
9611             {
9612                if(memberExp && memberExp.member.exp && memberExp.member.exp.expType && memberExp.member.exp.expType.kind == subClassType &&
9613                   memberExp.member.exp.expType._class)
9614                {
9615                   type = MkClassType(memberExp.member.exp.expType._class.string);
9616                   if(e)
9617                   {
9618                      e.destType = type;
9619                      e = e.next;
9620                      type = functionType.params.first;
9621                   }
9622                   else
9623                      type.refCount = 0;
9624                }
9625                else if(!memberExp && (functionType.thisClass || (methodType && methodType.methodClass)))
9626                {
9627                   type = MkClassType(functionType.thisClass ? functionType.thisClass.string : (methodType ? methodType.methodClass.fullName : null));
9628                   type.byReference = functionType.byReference;
9629                   type.typedByReference = functionType.typedByReference;
9630                   if(e)
9631                   {
9632                      // Allow manually passing a class for typed object
9633                      if(e.next && type.kind == classType && (functionType && functionType.thisClass) && functionType.classObjectType == typedObject)
9634                         e = e.next;
9635                      e.destType = type;
9636                      e = e.next;
9637                      type = functionType.params.first;
9638                   }
9639                   else
9640                      type.refCount = 0;
9641                   //extra = 1;
9642                }
9643             }
9644
9645             if(type && type.kind == voidType)
9646             {
9647                noParams = true;
9648                if(!type.refCount) FreeType(type);
9649                type = null;
9650             }
9651
9652             for( ; e; e = e.next)
9653             {
9654                if(!type && !emptyParams)
9655                {
9656                   yylloc = e.loc;
9657                   if(methodType && methodType.methodClass)
9658                      Compiler_Error($"too many arguments for method %s::%s (%d given, expected %d)\n",
9659                         methodType.methodClass.fullName, methodType.method.name, exp.call.arguments->count,
9660                         noParams ? 0 : functionType.params.count);
9661                   else
9662                      Compiler_Error($"too many arguments for function %s (%d given, expected %d)\n",
9663                         name /*exp.call.exp.identifier.string*/, exp.call.arguments->count,
9664                         noParams ? 0 : functionType.params.count);
9665                   break;
9666                }
9667
9668                if(methodType && type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type)
9669                {
9670                   Type templatedType = null;
9671                   Class _class = methodType.usedClass;
9672                   ClassTemplateParameter curParam = null;
9673                   int id = 0;
9674                   if(_class && _class.templateArgs /*&& _class.templateClass*/)
9675                   {
9676                      Class sClass;
9677                      for(sClass = _class; sClass; sClass = sClass.base)
9678                      {
9679                         if(sClass.templateClass) sClass = sClass.templateClass;
9680                         id = 0;
9681                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9682                         {
9683                            if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
9684                            {
9685                               Class nextClass;
9686                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
9687                               {
9688                                  if(nextClass.templateClass) nextClass = nextClass.templateClass;
9689                                  id += nextClass.templateParams.count;
9690                               }
9691                               break;
9692                            }
9693                            id++;
9694                         }
9695                         if(curParam) break;
9696                      }
9697                   }
9698                   if(curParam && _class.templateArgs[id].dataTypeString)
9699                   {
9700                      bool constant = type.constant;
9701                      ClassTemplateArgument arg = _class.templateArgs[id];
9702                      {
9703                         Context context = SetupTemplatesContext(_class);
9704
9705                         /*if(!arg.dataType)
9706                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9707                         templatedType = ProcessTypeString(arg.dataTypeString, false);
9708                         FinishTemplatesContext(context);
9709                      }
9710
9711                      if(templatedType.kind == classType && constant) templatedType.constant = true;
9712                      else if(templatedType.kind == pointerType)
9713                      {
9714                         Type t = templatedType.type;
9715                         while(t.kind == pointerType) t = t.type;
9716                         if(constant) t.constant = constant;
9717                      }
9718
9719                      e.destType = templatedType;
9720                      if(templatedType)
9721                      {
9722                         templatedType.passAsTemplate = true;
9723                         // templatedType.refCount++;
9724                      }
9725                   }
9726                   else
9727                   {
9728                      e.destType = type;
9729                      if(type) type.refCount++;
9730                   }
9731                }
9732                else
9733                {
9734                   if(type && type.kind == ellipsisType && type.prev && type.prev.kind == classType && type.prev.classObjectType)
9735                   {
9736                      e.destType = type.prev;
9737                      e.destType.refCount++;
9738                   }
9739                   else
9740                   {
9741                      e.destType = type;
9742                      if(type) type.refCount++;
9743                   }
9744                }
9745                // Don't reach the end for the ellipsis
9746                if(type && type.kind != ellipsisType)
9747                {
9748                   Type next = type.next;
9749                   if(!type.refCount) FreeType(type);
9750                   type = next;
9751                }
9752             }
9753
9754             if(type && type.kind != ellipsisType)
9755             {
9756                if(methodType && methodType.methodClass)
9757                   Compiler_Warning($"not enough arguments for method %s::%s (%d given, expected %d)\n",
9758                      methodType.methodClass.fullName, methodType.method.name, exp.call.arguments ? exp.call.arguments->count : 0,
9759                      functionType.params.count + extra);
9760                else
9761                   Compiler_Warning($"not enough arguments for function %s (%d given, expected %d)\n",
9762                      name /*exp.call.exp.identifier.string*/, exp.call.arguments ? exp.call.arguments->count : 0,
9763                      functionType.params.count + extra);
9764             }
9765             yylloc = oldyylloc;
9766             if(type && !type.refCount) FreeType(type);
9767          }
9768          else
9769          {
9770             functionType = Type
9771             {
9772                refCount = 0;
9773                kind = TypeKind::functionType;
9774             };
9775
9776             if(exp.call.exp.type == identifierExp)
9777             {
9778                char * string = exp.call.exp.identifier.string;
9779                if(inCompiler)
9780                {
9781                   Symbol symbol;
9782                   Location oldyylloc = yylloc;
9783
9784                   yylloc = exp.call.exp.identifier.loc;
9785                   if(strstr(string, "__builtin_") == string)
9786                   {
9787                      if(exp.destType)
9788                      {
9789                         functionType.returnType = exp.destType;
9790                         exp.destType.refCount++;
9791                      }
9792                   }
9793                   else
9794                      Compiler_Warning($"%s undefined; assuming extern returning int\n", string);
9795                   symbol = Symbol { string = CopyString(string), type = ProcessTypeString("int()", true) };
9796                   globalContext.symbols.Add((BTNode)symbol);
9797                   if(strstr(symbol.string, "::"))
9798                      globalContext.hasNameSpace = true;
9799
9800                   yylloc = oldyylloc;
9801                }
9802             }
9803             else if(exp.call.exp.type == memberExp)
9804             {
9805                /*Compiler_Warning($"%s undefined; assuming returning int\n",
9806                   exp.call.exp.member.member.string);*/
9807             }
9808             else
9809                Compiler_Warning($"callable object undefined; extern assuming returning int\n");
9810
9811             if(!functionType.returnType)
9812             {
9813                functionType.returnType = Type
9814                {
9815                   refCount = 1;
9816                   kind = intType;
9817                };
9818             }
9819          }
9820          if(functionType && functionType.kind == TypeKind::functionType)
9821          {
9822             exp.expType = functionType.returnType;
9823
9824             if(functionType.returnType)
9825                functionType.returnType.refCount++;
9826
9827             if(!functionType.refCount)
9828                FreeType(functionType);
9829          }
9830
9831          if(exp.call.arguments)
9832          {
9833             for(e = exp.call.arguments->first; e; e = e.next)
9834                ProcessExpressionType(e);
9835          }
9836          break;
9837       }
9838       case memberExp:
9839       {
9840          Type type;
9841          Location oldyylloc = yylloc;
9842          bool thisPtr;
9843          Expression checkExp = exp.member.exp;
9844          while(checkExp)
9845          {
9846             if(checkExp.type == castExp)
9847                checkExp = checkExp.cast.exp;
9848             else if(checkExp.type == bracketsExp)
9849                checkExp = checkExp.list ? checkExp.list->first : null;
9850             else
9851                break;
9852          }
9853
9854          thisPtr = (checkExp && checkExp.type == identifierExp && !strcmp(checkExp.identifier.string, "this"));
9855          exp.thisPtr = thisPtr;
9856
9857          // DOING THIS LATER NOW...
9858          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
9859          {
9860             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
9861             /* TODO: Name Space Fix ups
9862             if(!exp.member.member.classSym)
9863                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.fullName);
9864             */
9865          }
9866
9867          ProcessExpressionType(exp.member.exp);
9868          if(exp.member.exp.expType && exp.member.exp.expType.kind == classType && exp.member.exp.expType._class &&
9869             exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == normalClass)
9870          {
9871             exp.isConstant = false;
9872          }
9873          else
9874             exp.isConstant = exp.member.exp.isConstant;
9875          type = exp.member.exp.expType;
9876
9877          yylloc = exp.loc;
9878
9879          if(type && (type.kind == templateType))
9880          {
9881             Class _class = thisClass ? thisClass : currentClass;
9882             ClassTemplateParameter param = null;
9883             if(_class)
9884             {
9885                for(param = _class.templateParams.first; param; param = param.next)
9886                {
9887                   if(param.type == identifier && exp.member.member && exp.member.member.string && !strcmp(param.name, exp.member.member.string))
9888                      break;
9889                }
9890             }
9891             if(param && param.defaultArg.member)
9892             {
9893                Expression argExp = GetTemplateArgExpByName(param.name, thisClass, TemplateParameterType::identifier);
9894                if(argExp)
9895                {
9896                   Expression expMember = exp.member.exp;
9897                   Declarator decl;
9898                   OldList * specs = MkList();
9899                   char thisClassTypeString[1024];
9900
9901                   FreeIdentifier(exp.member.member);
9902
9903                   ProcessExpressionType(argExp);
9904
9905                   {
9906                      char * colon = strstr(param.defaultArg.memberString, "::");
9907                      if(colon)
9908                      {
9909                         memcpy(thisClassTypeString, param.defaultArg.memberString, colon - param.defaultArg.memberString);
9910                         thisClassTypeString[colon - param.defaultArg.memberString] = '\0';
9911                      }
9912                      else
9913                         strcpy(thisClassTypeString, _class.fullName);
9914                   }
9915
9916                   decl = SpecDeclFromString(param.defaultArg.member.dataTypeString, specs, null);
9917
9918                   exp.expType = ProcessType(specs, decl);
9919                   if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.templateClass)
9920                   {
9921                      Class expClass = exp.expType._class.registered;
9922                      Class cClass = null;
9923                      int paramCount = 0;
9924                      int lastParam = -1;
9925
9926                      char templateString[1024];
9927                      ClassTemplateParameter param;
9928                      sprintf(templateString, "%s<", expClass.templateClass.fullName);
9929                      for(cClass = expClass; cClass; cClass = cClass.base)
9930                      {
9931                         int p = 0;
9932                         for(param = cClass.templateParams.first; param; param = param.next)
9933                         {
9934                            int id = p;
9935                            Class sClass;
9936                            ClassTemplateArgument arg;
9937                            for(sClass = cClass.base; sClass; sClass = sClass.base) id += sClass.templateParams.count;
9938                            arg = expClass.templateArgs[id];
9939
9940                            for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
9941                            {
9942                               ClassTemplateParameter cParam;
9943                               //int p = numParams - sClass.templateParams.count;
9944                               int p = 0;
9945                               Class nextClass;
9946                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) p += nextClass.templateParams.count;
9947
9948                               for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
9949                               {
9950                                  if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
9951                                  {
9952                                     if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9953                                     {
9954                                        arg.dataTypeString = _class.templateArgs[p].dataTypeString;
9955                                        arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
9956                                        break;
9957                                     }
9958                                  }
9959                               }
9960                            }
9961
9962                            {
9963                               char argument[256];
9964                               argument[0] = '\0';
9965                               /*if(arg.name)
9966                               {
9967                                  strcat(argument, arg.name.string);
9968                                  strcat(argument, " = ");
9969                               }*/
9970                               switch(param.type)
9971                               {
9972                                  case expression:
9973                                  {
9974                                     // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
9975                                     char expString[1024];
9976                                     OldList * specs = MkList();
9977                                     Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
9978                                     Expression exp;
9979                                     char * string = PrintHexUInt64(arg.expression.ui64);
9980                                     exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
9981                                     delete string;
9982
9983                                     ProcessExpressionType(exp);
9984                                     ComputeExpression(exp);
9985                                     expString[0] = '\0';
9986                                     PrintExpression(exp, expString);
9987                                     strcat(argument, expString);
9988                                     // delete exp;
9989                                     FreeExpression(exp);
9990                                     break;
9991                                  }
9992                                  case identifier:
9993                                  {
9994                                     strcat(argument, arg.member.name);
9995                                     break;
9996                                  }
9997                                  case TemplateParameterType::type:
9998                                  {
9999                                     if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10000                                     {
10001                                        if(!strcmp(arg.dataTypeString, "thisclass"))
10002                                           strcat(argument, thisClassTypeString);
10003                                        else
10004                                           strcat(argument, arg.dataTypeString);
10005                                     }
10006                                     break;
10007                                  }
10008                               }
10009                               if(argument[0])
10010                               {
10011                                  if(paramCount) strcat(templateString, ", ");
10012                                  if(lastParam != p - 1)
10013                                  {
10014                                     strcat(templateString, param.name);
10015                                     strcat(templateString, " = ");
10016                                  }
10017                                  strcat(templateString, argument);
10018                                  paramCount++;
10019                                  lastParam = p;
10020                               }
10021                               p++;
10022                            }
10023                         }
10024                      }
10025                      {
10026                         int len = strlen(templateString);
10027                         if(templateString[len-1] == '>') templateString[len++] = ' ';
10028                         templateString[len++] = '>';
10029                         templateString[len++] = '\0';
10030                      }
10031                      {
10032                         Context context = SetupTemplatesContext(_class);
10033                         FreeType(exp.expType);
10034                         exp.expType = ProcessTypeString(templateString, false);
10035                         FinishTemplatesContext(context);
10036                      }
10037                   }
10038
10039                   if(!expMember.expType.isPointerType)
10040                      expMember = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), expMember);
10041                   // *([expType] *)(((byte *)(uintptr)[exp.member.exp]) + [argExp].member.offset)
10042                   exp.type = bracketsExp;
10043                   exp.list = MkListOne(MkExpOp(null, '*',
10044                   /*opExp;
10045                   exp.op.op = '*';
10046                   exp.op.exp1 = null;
10047                   exp.op.exp2 = */
10048                   MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpBrackets(MkListOne(MkExpOp(
10049                      MkExpBrackets(MkListOne(
10050                         MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
10051                            expMember))),
10052                               '+',
10053                               MkExpOp(MkExpMember(MkExpMember(argExp, MkIdentifier("member")), MkIdentifier("offset")),
10054                               '+',
10055                               MkExpMember(MkExpMember(MkExpMember(CopyExpression(argExp), MkIdentifier("member")), MkIdentifier("_class")), MkIdentifier("offset")))))))
10056
10057                            ));
10058                }
10059             }
10060             else if(type.templateParameter && type.templateParameter.type == TemplateParameterType::type &&
10061                (type.templateParameter.dataType || type.templateParameter.dataTypeString))
10062             {
10063                type = ProcessTemplateParameterType(type.templateParameter);
10064             }
10065          }
10066          // TODO: *** This seems to be where we should add method support for all basic types ***
10067          if(type && (type.kind == templateType));
10068          else if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType ||
10069                           type.kind == int64Type || type.kind == shortType || type.kind == longType || type.kind == charType || type.kind == _BoolType ||
10070                           type.kind == intPtrType || type.kind == intSizeType || type.kind == floatType || type.kind == doubleType ||
10071                           (type.kind == pointerType && type.type.kind == charType)))
10072          {
10073             Identifier id = exp.member.member;
10074             TypeKind typeKind = type.kind;
10075             Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10076             if(typeKind == subClassType && exp.member.exp.type == classExp)
10077             {
10078                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
10079                typeKind = classType;
10080             }
10081
10082             if(id)
10083             {
10084                if(typeKind == intType || typeKind == enumType)
10085                   _class = eSystem_FindClass(privateModule, "int");
10086                else if(!_class)
10087                {
10088                   if(type.kind == classType && type._class && type._class.registered)
10089                   {
10090                      _class = type._class.registered;
10091                   }
10092                   else if((type.kind == arrayType || type.kind == pointerType) && type.type && type.type.kind == charType)
10093                   {
10094                      _class = FindClass("char *").registered;
10095                   }
10096                   else if(type.kind == pointerType)
10097                   {
10098                      _class = eSystem_FindClass(privateModule, "uintptr");
10099                      FreeType(exp.expType);
10100                      exp.expType = ProcessTypeString("uintptr", false);
10101                      exp.byReference = true;
10102                   }
10103                   else
10104                   {
10105                      char string[1024] = "";
10106                      Symbol classSym;
10107                      PrintTypeNoConst(type, string, false, true);
10108                      classSym = FindClass(string);
10109                      if(classSym) _class = classSym.registered;
10110                   }
10111                }
10112             }
10113
10114             if(_class && id)
10115             {
10116                /*bool thisPtr =
10117                   (exp.member.exp.type == identifierExp &&
10118                   !strcmp(exp.member.exp.identifier.string, "this"));*/
10119                Property prop = null;
10120                Method method = null;
10121                DataMember member = null;
10122                Property revConvert = null;
10123                ClassProperty classProp = null;
10124
10125                if(id && id._class && id._class.name && !strcmp(id._class.name, "property"))
10126                   exp.member.memberType = propertyMember;
10127
10128                if(id && id._class && type._class && !eClass_IsDerived(type._class.registered, _class))
10129                   Compiler_Error($"invalid class specifier %s for object of class %s\n", _class.fullName, type._class.string);
10130
10131                if(typeKind != subClassType)
10132                {
10133                   // Prioritize data members over properties for "this"
10134                   if((exp.member.memberType == unresolvedMember && thisPtr) || exp.member.memberType == dataMember)
10135                   {
10136                      member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
10137                      if(member && member._class != (_class.templateClass ? _class.templateClass : _class) && exp.member.memberType != dataMember)
10138                      {
10139                         prop = eClass_FindProperty(_class, id.string, privateModule);
10140                         if(prop)
10141                            member = null;
10142                      }
10143                      if(!member && !prop)
10144                         prop = eClass_FindProperty(_class, id.string, privateModule);
10145                      if((member && member._class == (_class.templateClass ? _class.templateClass : _class)) ||
10146                         (prop && prop._class == (_class.templateClass ? _class.templateClass : _class)))
10147                         exp.member.thisPtr = true;
10148                   }
10149                   // Prioritize properties over data members otherwise
10150                   else
10151                   {
10152                      bool useMemberForNonConst = false;
10153                      // First look for Public Members (Unless class specifier is provided, which skips public priority)
10154                      if(!id.classSym)
10155                      {
10156                         prop = eClass_FindProperty(_class, id.string, null);
10157
10158                         useMemberForNonConst = prop && exp.destType &&
10159                            ( (exp.destType.kind == classType && !exp.destType.constant) || ((exp.destType.kind == pointerType || exp.destType.kind == arrayType) && exp.destType.type && !exp.destType.type.constant) ) &&
10160                               !strncmp(prop.dataTypeString, "const ", 6);
10161
10162                         if(useMemberForNonConst || !id._class || !id._class.name || strcmp(id._class.name, "property"))
10163                            member = eClass_FindDataMember(_class, id.string, null, null, null);
10164                      }
10165
10166                      if((!prop || useMemberForNonConst) && !member)
10167                      {
10168                         method = useMemberForNonConst ? null : eClass_FindMethod(_class, id.string, null);
10169                         if(!method)
10170                         {
10171                            prop = eClass_FindProperty(_class, id.string, privateModule);
10172
10173                            useMemberForNonConst |= prop && exp.destType &&
10174                               ( (exp.destType.kind == classType && !exp.destType.constant) || ((exp.destType.kind == pointerType || exp.destType.kind == arrayType) && exp.destType.type && !exp.destType.type.constant) ) &&
10175                                  !strncmp(prop.dataTypeString, "const ", 6);
10176
10177                            if(useMemberForNonConst || !id._class || !id._class.name || strcmp(id._class.name, "property"))
10178                               member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
10179                         }
10180                      }
10181
10182                      if(member && prop)
10183                      {
10184                         if(useMemberForNonConst || (member._class != prop._class && !id._class && eClass_IsDerived(member._class, prop._class)))
10185                            prop = null;
10186                         else
10187                            member = null;
10188                      }
10189                   }
10190                }
10191                if(!prop && !member && !method)     // NOTE: Recently added the !method here, causes private methods to unprioritized
10192                   method = eClass_FindMethod(_class, id.string, privateModule);
10193                if(!prop && !member && !method)
10194                {
10195                   if(typeKind == subClassType)
10196                   {
10197                      classProp = eClass_FindClassProperty(type._class.registered, exp.member.member.string);
10198                      if(classProp)
10199                      {
10200                         exp.member.memberType = classPropertyMember;
10201                         exp.expType = ProcessTypeString(classProp.dataTypeString, false);
10202                      }
10203                      else
10204                      {
10205                         // Assume this is a class_data member
10206                         char structName[1024];
10207                         Identifier id = exp.member.member;
10208                         Expression classExp = exp.member.exp;
10209                         type.refCount++;
10210
10211                         FreeType(classExp.expType);
10212                         classExp.expType = ProcessTypeString("ecere::com::Class", false);
10213
10214                         strcpy(structName, "__ecereClassData_");
10215                         FullClassNameCat(structName, type._class.string, false);
10216                         exp.type = pointerExp;
10217                         exp.member.member = id;
10218
10219                         exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10220                            MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10221                               MkExpBrackets(MkListOne(MkExpOp(
10222                                  MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10223                                     MkExpMember(classExp, MkIdentifier("data"))), '+',
10224                                        MkExpMember(MkExpClass(MkListOne(MkSpecifierName(type._class.string)), null), MkIdentifier("offsetClass")))))
10225                                  )));
10226
10227                         FreeType(type);
10228
10229                         ProcessExpressionType(exp);
10230                         return;
10231                      }
10232                   }
10233                   else
10234                   {
10235                      // Check for reverse conversion
10236                      // (Convert in an instantiation later, so that we can use
10237                      //  deep properties system)
10238                      Symbol classSym = FindClass(id.string);
10239                      if(classSym)
10240                      {
10241                         Class convertClass = classSym.registered;
10242                         if(convertClass)
10243                            revConvert = eClass_FindProperty(convertClass, _class.fullName, privateModule);
10244                      }
10245                   }
10246                }
10247
10248                //if(!exp.member.exp.destType)
10249                if(exp.member.exp.destType)
10250                   FreeType(exp.member.exp.destType);
10251                {
10252                   if(method && !method._class.symbol)
10253                      method._class.symbol = FindClass(method._class.fullName);
10254                   if(prop && !prop._class.symbol)
10255                      prop._class.symbol = FindClass(prop._class.fullName);
10256
10257                   exp.member.exp.destType = Type
10258                   {
10259                      refCount = 1;
10260                      kind = classType;
10261                      _class = prop ? prop._class.symbol : method ? method._class.symbol : _class.symbol;
10262                      // wasThisClass = type ? type.wasThisClass : false;
10263                      thisClassFrom = type ? type.thisClassFrom : null;
10264                   };
10265                }
10266
10267                if(prop)
10268                {
10269                   exp.member.memberType = propertyMember;
10270                   if(!prop.dataType)
10271                      ProcessPropertyType(prop);
10272                   exp.expType = prop.dataType;
10273                   if(!strcmp(_class.base.fullName, "eda::Row") && !exp.expType.constant && !exp.destType)
10274                   {
10275                      Type type { };
10276                      CopyTypeInto(type, exp.expType);
10277                      type.refCount = 1;
10278                      type.constant = true;
10279                      exp.expType = type;
10280                   }
10281                   else if(prop.dataType)
10282                      prop.dataType.refCount++;
10283                }
10284                else if(member)
10285                {
10286                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
10287                   {
10288                      FreeExpContents(exp);
10289                      exp.type = identifierExp;
10290                      exp.identifier = MkIdentifier("class");
10291                      ProcessExpressionType(exp);
10292                      return;
10293                   }
10294
10295                   exp.member.memberType = dataMember;
10296                   DeclareStruct(curExternal, _class.fullName, false, true);
10297                   if(member._class != _class)
10298                      DeclareStruct(curExternal, member._class.fullName, false, true);
10299
10300                   if(!member.dataType)
10301                   {
10302                      Context context = SetupTemplatesContext(_class);
10303                      member.dataType = ProcessTypeString(member.dataTypeString, false);
10304                      FinishTemplatesContext(context);
10305                   }
10306                   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)
10307                      member.dataType.bitMemberSize = ((BitMember)member).size;
10308                   exp.expType = member.dataType;
10309                   if(member.dataType) member.dataType.refCount++;
10310                }
10311                else if(revConvert)
10312                {
10313                   exp.member.memberType = reverseConversionMember;
10314                   exp.expType = MkClassType(revConvert._class.fullName);
10315                }
10316                else if(method)
10317                {
10318                   //if(inCompiler)
10319                   {
10320                      /*if(id._class)
10321                      {
10322                         exp.type = identifierExp;
10323                         exp.identifier = exp.member.member;
10324                      }
10325                      else*/
10326                         exp.member.memberType = methodMember;
10327                   }
10328                   if(!method.dataType)
10329                      ProcessMethodType(method);
10330                   exp.expType = Type
10331                   {
10332                      refCount = 1;
10333                      kind = methodType;
10334                      method = method;
10335                   };
10336
10337                   // Tricky spot here... To use instance versus class virtual table
10338                   // Put it back to what it was... What did we break?
10339
10340                   // Had to put it back for overriding Main of Thread global instance
10341
10342                   //exp.expType.methodClass = _class;
10343                   exp.expType.methodClass = (id && id._class) ? _class : null;
10344
10345                   // Need the actual class used for templated classes
10346                   exp.expType.usedClass = _class;
10347                }
10348                else if(!classProp)
10349                {
10350                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
10351                   {
10352                      FreeExpContents(exp);
10353                      exp.type = identifierExp;
10354                      exp.identifier = MkIdentifier("class");
10355                      FreeType(exp.expType);
10356                      exp.expType = MkClassType("ecere::com::Class");
10357                      return;
10358                   }
10359                   yylloc = exp.member.member.loc;
10360                   Compiler_Error($"couldn't find member %s in class %s\n", id.string, _class.fullName);
10361                   if(inCompiler)
10362                      eClass_AddDataMember(_class, id.string, "int", 0, 0, publicAccess);
10363                }
10364
10365                if(_class && /*(_class.templateClass || _class.templateArgs) && */exp.expType)
10366                {
10367                   Class tClass;
10368
10369                   tClass = type._class && type._class.registered ? type._class.registered : _class;
10370                   while(tClass && !tClass.templateClass) tClass = tClass.base;
10371
10372                   if(tClass && exp.expType.kind == templateType && exp.expType.templateParameter.type == TemplateParameterType::type)
10373                   {
10374                      int id = 0;
10375                      ClassTemplateParameter curParam = null;
10376                      Class sClass;
10377
10378                      for(sClass = tClass; sClass; sClass = sClass.base)
10379                      {
10380                         id = 0;
10381                         if(sClass.templateClass) sClass = sClass.templateClass;
10382                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
10383                         {
10384                            if(curParam.type == TemplateParameterType::type && !strcmp(exp.expType.templateParameter.identifier.string, curParam.name))
10385                            {
10386                               for(sClass = sClass.base; sClass; sClass = sClass.base)
10387                                  id += sClass.templateParams.count;
10388                               break;
10389                            }
10390                            id++;
10391                         }
10392                         if(curParam) break;
10393                      }
10394
10395                      if(curParam && tClass.templateArgs[id].dataTypeString)
10396                      {
10397                         ClassTemplateArgument arg = tClass.templateArgs[id];
10398                         Context context = SetupTemplatesContext(tClass);
10399                         bool constant = exp.expType.constant;
10400                         bool passAsTemplate = false;
10401                         Class thisClassFrom = null;
10402                         Type t = ProcessTypeString(exp.expType.templateParameter.dataTypeString, false);
10403                         if(t && t.kind == classType && t._class)
10404                            thisClassFrom = t._class.registered;
10405                         else
10406                            // Mark that 'thisClassFrom' was set to something
10407                            thisClassFrom = eSystem_FindClass(GetPrivateModule(), "class");
10408
10409                         FreeType(t);
10410
10411                         passAsTemplate = tClass.templateClass && (exp.expType.kind != templateType ||
10412                            (!exp.expType.templateParameter || (!exp.expType.templateParameter.dataTypeString && !exp.expType.templateParameter.dataType)));
10413
10414                         /*if(!arg.dataType)
10415                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
10416                         FreeType(exp.expType);
10417
10418                         exp.expType = ProcessTypeString(arg.dataTypeString, false);
10419                         exp.expType.thisClassFrom = thisClassFrom;
10420                         if(exp.expType.kind == classType && constant) exp.expType.constant = true;
10421                         else if(exp.expType.kind == pointerType)
10422                         {
10423                            Type t = exp.expType.type;
10424                            while(t.kind == pointerType) t = t.type;
10425                            if(constant) t.constant = constant;
10426                         }
10427                         if(exp.expType)
10428                         {
10429                            if(exp.expType.kind == thisClassType)
10430                            {
10431                               FreeType(exp.expType);
10432                               exp.expType = ReplaceThisClassType(_class);
10433                            }
10434
10435                            if(passAsTemplate)
10436                               exp.expType.passAsTemplate = true;
10437                            //exp.expType.refCount++;
10438                            if(!exp.destType)
10439                            {
10440                               exp.destType = ProcessTypeString(arg.dataTypeString, false);
10441                               if(exp.destType.kind == classType && constant) exp.destType.constant = true;
10442                               else if(exp.destType.kind == pointerType)
10443                               {
10444                                  Type t = exp.destType.type;
10445                                  while(t.kind == pointerType) t = t.type;
10446                                  if(constant) t.constant = constant;
10447                               }
10448
10449                               //exp.destType.refCount++;
10450
10451                               if(exp.destType.kind == thisClassType)
10452                               {
10453                                  FreeType(exp.destType);
10454                                  exp.destType = ReplaceThisClassType(_class);
10455                               }
10456                            }
10457                         }
10458                         FinishTemplatesContext(context);
10459                      }
10460                   }
10461                   // TODO: MORE GENERIC SUPPORT FOR DEEPER TYPES
10462                   else if(tClass && exp.expType.kind == pointerType && exp.expType.type && exp.expType.type.kind == templateType && exp.expType.type.templateParameter.type == TemplateParameterType::type)
10463                   {
10464                      int id = 0;
10465                      ClassTemplateParameter curParam = null;
10466                      Class sClass;
10467
10468                      for(sClass = tClass; sClass; sClass = sClass.base)
10469                      {
10470                         id = 0;
10471                         if(sClass.templateClass) sClass = sClass.templateClass;
10472                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
10473                         {
10474                            if(curParam.type == TemplateParameterType::type &&
10475                               !strcmp(exp.expType.type.templateParameter.identifier.string, curParam.name))
10476                            {
10477                               for(sClass = sClass.base; sClass; sClass = sClass.base)
10478                                  id += sClass.templateParams.count;
10479                               break;
10480                            }
10481                            id++;
10482                         }
10483                         if(curParam) break;
10484                      }
10485
10486                      if(curParam)
10487                      {
10488                         ClassTemplateArgument arg = tClass.templateArgs[id];
10489                         Context context = SetupTemplatesContext(tClass);
10490                         Type basicType;
10491                         /*if(!arg.dataType)
10492                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
10493
10494                         basicType = ProcessTypeString(arg.dataTypeString, false);
10495                         if(basicType)
10496                         {
10497                            if(basicType.kind == thisClassType)
10498                            {
10499                               FreeType(basicType);
10500                               basicType = ReplaceThisClassType(_class);
10501                            }
10502
10503                            /*    DO WE REALLY WANT THIS HERE? IT SEEMS TO BE ONLY USED WITH Array::array which was causing bug 135
10504                            if(tClass.templateClass)
10505                               basicType.passAsTemplate = true;
10506                            */
10507
10508                            FreeType(exp.expType);
10509
10510                            exp.expType = Type { refCount = 1, kind = pointerType, type = basicType };
10511                            //exp.expType.refCount++;
10512                            if(!exp.destType)
10513                            {
10514                               exp.destType = exp.expType;
10515                               exp.destType.refCount++;
10516                            }
10517
10518                            {
10519                               Expression newExp { };
10520                               OldList * specs = MkList();
10521                               Declarator decl;
10522                               decl = SpecDeclFromString(arg.dataTypeString, specs, null);
10523                               *newExp = *exp;
10524                               if(exp.destType) exp.destType.refCount++;
10525                               if(exp.expType)  exp.expType.refCount++;
10526                               exp.type = castExp;
10527                               exp.cast.typeName = MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl));
10528                               exp.cast.exp = newExp;
10529                               //FreeType(exp.expType);
10530                               //exp.expType = null;
10531                               //ProcessExpressionType(sourceExp);
10532                            }
10533                         }
10534                         FinishTemplatesContext(context);
10535                      }
10536                   }
10537                   else if(tClass && exp.expType.kind == classType && exp.expType._class && strchr(exp.expType._class.string, '<'))
10538                   {
10539                      Class expClass = exp.expType._class.registered;
10540                      if(expClass)
10541                      {
10542                         Class cClass = null;
10543                         int p = 0;
10544                         int paramCount = 0;
10545                         int lastParam = -1;
10546                         char templateString[1024];
10547                         ClassTemplateParameter param;
10548                         sprintf(templateString, "%s<", expClass.templateClass.fullName);
10549                         while(cClass != expClass)
10550                         {
10551                            Class sClass;
10552                            for(sClass = expClass; sClass && sClass.base != cClass; sClass = sClass.base);
10553                            cClass = sClass;
10554
10555                            for(param = cClass.templateParams.first; param; param = param.next)
10556                            {
10557                               Class cClassCur = null;
10558                               int cp = 0;
10559                               ClassTemplateParameter paramCur = null;
10560                               ClassTemplateArgument arg;
10561                               while(cClassCur != tClass && !paramCur)
10562                               {
10563                                  Class sClassCur;
10564                                  for(sClassCur = tClass; sClassCur && sClassCur.base != cClassCur; sClassCur = sClassCur.base);
10565                                  cClassCur = sClassCur;
10566
10567                                  for(paramCur = cClassCur.templateParams.first; paramCur; paramCur = paramCur.next)
10568                                  {
10569                                     if(!strcmp(paramCur.name, param.name))
10570                                     {
10571
10572                                        break;
10573                                     }
10574                                     cp++;
10575                                  }
10576                               }
10577                               if(paramCur && paramCur.type == TemplateParameterType::type)
10578                                  arg = tClass.templateArgs[cp];
10579                               else
10580                                  arg = expClass.templateArgs[p];
10581
10582                               {
10583                                  char argument[256];
10584                                  argument[0] = '\0';
10585                                  /*if(arg.name)
10586                                  {
10587                                     strcat(argument, arg.name.string);
10588                                     strcat(argument, " = ");
10589                                  }*/
10590                                  switch(param.type)
10591                                  {
10592                                     case expression:
10593                                     {
10594                                        // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
10595                                        char expString[1024];
10596                                        OldList * specs = MkList();
10597                                        Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
10598                                        Expression exp;
10599                                        char * string = PrintHexUInt64(arg.expression.ui64);
10600                                        exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
10601                                        delete string;
10602
10603                                        ProcessExpressionType(exp);
10604                                        ComputeExpression(exp);
10605                                        expString[0] = '\0';
10606                                        PrintExpression(exp, expString);
10607                                        strcat(argument, expString);
10608                                        // delete exp;
10609                                        FreeExpression(exp);
10610                                        break;
10611                                     }
10612                                     case identifier:
10613                                     {
10614                                        strcat(argument, arg.member.name);
10615                                        break;
10616                                     }
10617                                     case TemplateParameterType::type:
10618                                     {
10619                                        if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10620                                           strcat(argument, arg.dataTypeString);
10621                                        break;
10622                                     }
10623                                  }
10624                                  if(argument[0])
10625                                  {
10626                                     if(paramCount) strcat(templateString, ", ");
10627                                     if(lastParam != p - 1)
10628                                     {
10629                                        strcat(templateString, param.name);
10630                                        strcat(templateString, " = ");
10631                                     }
10632                                     strcat(templateString, argument);
10633                                     paramCount++;
10634                                     lastParam = p;
10635                                  }
10636                               }
10637                               p++;
10638                            }
10639                         }
10640                         {
10641                            int len = strlen(templateString);
10642                            if(templateString[len-1] == '>') templateString[len++] = ' ';
10643                            templateString[len++] = '>';
10644                            templateString[len++] = '\0';
10645                         }
10646
10647                         FreeType(exp.expType);
10648                         {
10649                            Context context = SetupTemplatesContext(tClass);
10650                            exp.expType = ProcessTypeString(templateString, false);
10651                            FinishTemplatesContext(context);
10652                         }
10653                      }
10654                   }
10655                }
10656             }
10657             else
10658                Compiler_Error($"undefined class %s\n", (id && (!id._class || id._class.name))? (id.classSym ? id.classSym.string : (type._class ? type._class.string : null)) : "(null)");
10659          }
10660          else if(type && (type.kind == structType || type.kind == unionType))
10661          {
10662             Type memberType = exp.member.member ? FindMember(type, exp.member.member.string) : null;
10663             if(memberType)
10664             {
10665                exp.expType = memberType;
10666                if(memberType)
10667                   memberType.refCount++;
10668             }
10669          }
10670          else
10671          {
10672             char expString[10240];
10673             expString[0] = '\0';
10674             if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10675             Compiler_Error($"member operator on non-structure type expression %s\n", expString);
10676          }
10677
10678          if(exp.expType && exp.expType.kind == thisClassType && (!exp.destType || exp.destType.kind != thisClassType))
10679          {
10680             if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType))
10681             {
10682                Identifier id = exp.member.member;
10683                Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10684                if(_class)
10685                {
10686                   FreeType(exp.expType);
10687                   exp.expType = ReplaceThisClassType(_class);
10688                }
10689             }
10690          }
10691          yylloc = oldyylloc;
10692          break;
10693       }
10694       // Convert x->y into (*x).y
10695       case pointerExp:
10696       {
10697          Type destType = exp.destType;
10698
10699          // DOING THIS LATER NOW...
10700          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
10701          {
10702             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
10703             /* TODO: Name Space Fix ups
10704             if(!exp.member.member.classSym)
10705                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.name);
10706             */
10707          }
10708
10709          exp.member.exp = MkExpBrackets(MkListOne(MkExpOp(null, '*', exp.member.exp)));
10710          exp.type = memberExp;
10711          if(destType)
10712             destType.count++;
10713          ProcessExpressionType(exp);
10714          if(destType)
10715             destType.count--;
10716          break;
10717       }
10718       case classSizeExp:
10719       {
10720          //ComputeExpression(exp);
10721
10722          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
10723          if(classSym && classSym.registered)
10724          {
10725             if(classSym.registered.type == noHeadClass || (classSym.registered.fixed && classSym.registered.structSize))
10726             {
10727                char name[1024];
10728                Class b = classSym.registered;
10729                name[0] = '\0';
10730                DeclareStruct(curExternal, classSym.string, false, true);
10731                FreeSpecifier(exp._class);
10732                FullClassNameCat(name, classSym.string, false);
10733
10734                if(b.offset == 0)
10735                {
10736                   exp.type = typeSizeExp;
10737                   exp.typeName = MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null);
10738                }
10739                else
10740                {
10741                   Expression e;
10742                   exp.type = opExp;
10743                   if(b.structSize == b.offset)
10744                      exp.op.exp1 = MkExpConstant("0");
10745                   else
10746                      exp.op.exp1 = MkExpTypeSize(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null));
10747                   exp.op.op = '+';
10748                   e = exp;
10749                   while(b.offset != 0)
10750                   {
10751                      Symbol sym;
10752                      Expression typeSize;
10753
10754                      b = b.base;
10755                      sym = FindClass(b.fullName);
10756
10757                      name[0] = '\0';
10758                      DeclareStruct(curExternal, sym.string, false, true);
10759                      FullClassNameCat(name, sym.string, false);
10760
10761                      if(b.structSize == b.offset)
10762                         typeSize = MkExpConstant("0");
10763                      else
10764                         typeSize = MkExpTypeSize(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null));
10765                      e.op.exp2 = b.offset ? MkExpOp(typeSize, '+', null) : typeSize;
10766                      e = e.op.exp2;
10767                   }
10768                }
10769             }
10770             else
10771             {
10772                if(classSym.registered.fixed && !classSym.registered.structSize)
10773                {
10774                   FreeSpecifier(exp._class);
10775                   exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
10776                   exp.type = constantExp;
10777                }
10778                else
10779                {
10780                   char className[1024];
10781                   strcpy(className, "__ecereClass_");
10782                   FullClassNameCat(className, classSym.string, true);
10783
10784                   DeclareClass(curExternal, classSym, className);
10785
10786                   FreeExpContents(exp);
10787                   exp.type = pointerExp;
10788                   exp.member.exp = MkExpIdentifier(MkIdentifier(className));
10789                   exp.member.member = MkIdentifier("structSize");
10790                }
10791             }
10792          }
10793
10794          exp.expType = Type
10795          {
10796             refCount = 1;
10797             kind = intSizeType;
10798          };
10799          // exp.isConstant = true;
10800          break;
10801       }
10802       case typeSizeExp:
10803       {
10804          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
10805
10806          exp.expType = Type
10807          {
10808             refCount = 1;
10809             kind = intSizeType;
10810          };
10811          exp.isConstant = true;
10812
10813          DeclareType(curExternal, type, true, false);
10814          FreeType(type);
10815          break;
10816       }
10817       case castExp:
10818       {
10819          Type type = ProcessType(exp.cast.typeName.qualifiers, exp.cast.typeName.declarator);
10820          type.count = 1;
10821          FreeType(exp.cast.exp.destType);
10822          exp.cast.exp.destType = type;
10823          type.refCount++;
10824          type.casted = true;
10825          ProcessExpressionType(exp.cast.exp);
10826          type.casted = false;
10827          type.count = 0;
10828          exp.expType = type;
10829          //type.refCount++;
10830
10831          // if(!NeedCast(exp.cast.exp.expType, exp.cast.exp.destType))
10832          if(!exp.cast.exp.needCast && !NeedCast(exp.cast.exp.expType, type))
10833          {
10834             void * prev = exp.prev, * next = exp.next;
10835             Type expType = exp.cast.exp.destType;
10836             Expression castExp = exp.cast.exp;
10837             Type destType = exp.destType;
10838
10839             if(expType) expType.refCount++;
10840
10841             //FreeType(exp.destType);
10842             FreeType(exp.expType);
10843             FreeTypeName(exp.cast.typeName);
10844
10845             *exp = *castExp;
10846             FreeType(exp.expType);
10847             FreeType(exp.destType);
10848
10849             exp.expType = expType;
10850             exp.destType = destType;
10851
10852             delete castExp;
10853
10854             exp.prev = prev;
10855             exp.next = next;
10856
10857          }
10858          else
10859          {
10860             exp.isConstant = exp.cast.exp.isConstant;
10861          }
10862          //FreeType(type);
10863          break;
10864       }
10865       case extensionInitializerExp:
10866       {
10867          Type type = ProcessType(exp.initializer.typeName.qualifiers, exp.initializer.typeName.declarator);
10868          // We have yet to support this... ( { } initializers are currently processed inside ProcessDeclaration()'s initDeclaration case statement
10869          // ProcessInitializer(exp.initializer.initializer, type);
10870          exp.expType = type;
10871          break;
10872       }
10873       case vaArgExp:
10874       {
10875          Type type = ProcessType(exp.vaArg.typeName.qualifiers, exp.vaArg.typeName.declarator);
10876          ProcessExpressionType(exp.vaArg.exp);
10877          exp.expType = type;
10878          break;
10879       }
10880       case conditionExp:
10881       {
10882          Expression e;
10883          Type t = exp.destType;
10884          if(t && !exp.destType.casted)
10885          {
10886             t = { };
10887             CopyTypeInto(t, exp.destType);
10888             t.count = 0;
10889          }
10890          else if(t)
10891             t.refCount++;
10892
10893          exp.isConstant = true;
10894
10895          FreeType(exp.cond.cond.destType);
10896          exp.cond.cond.destType = MkClassType("bool");
10897          exp.cond.cond.destType.truth = true;
10898          ProcessExpressionType(exp.cond.cond);
10899          if(!exp.cond.cond.isConstant)
10900             exp.isConstant = false;
10901          for(e = exp.cond.exp->first; e; e = e.next)
10902          {
10903             if(!e.next)
10904             {
10905                FreeType(e.destType);
10906                e.destType = t;
10907                if(e.destType) e.destType.refCount++;
10908             }
10909             ProcessExpressionType(e);
10910             if(!e.next)
10911             {
10912                exp.expType = e.expType;
10913                if(e.expType) e.expType.refCount++;
10914             }
10915             if(!e.isConstant)
10916                exp.isConstant = false;
10917          }
10918
10919          FreeType(exp.cond.elseExp.destType);
10920          // Added this check if we failed to find an expType
10921          // exp.cond.elseExp.destType = exp.expType ? exp.expType : exp.destType;
10922
10923          // Reversed it...
10924          exp.cond.elseExp.destType = t ? t : exp.expType;
10925
10926          if(exp.cond.elseExp.destType)
10927             exp.cond.elseExp.destType.refCount++;
10928          ProcessExpressionType(exp.cond.elseExp);
10929
10930          // FIXED THIS: Was done before calling process on elseExp
10931          if(!exp.cond.elseExp.isConstant)
10932             exp.isConstant = false;
10933
10934          FreeType(t);
10935          break;
10936       }
10937       case extensionCompoundExp:
10938       {
10939          if(exp.compound && exp.compound.compound.statements && exp.compound.compound.statements->last)
10940          {
10941             Statement last = exp.compound.compound.statements->last;
10942             if(last.type == expressionStmt && last.expressions && last.expressions->last)
10943             {
10944                ((Expression)last.expressions->last).destType = exp.destType;
10945                if(exp.destType)
10946                   exp.destType.refCount++;
10947             }
10948             ProcessStatement(exp.compound);
10949             exp.expType = (last.expressions && last.expressions->last) ? ((Expression)last.expressions->last).expType : null;
10950             if(exp.expType)
10951                exp.expType.refCount++;
10952          }
10953          break;
10954       }
10955       case classExp:
10956       {
10957          Specifier spec = exp._classExp.specifiers->first;
10958          if(spec && spec.type == nameSpecifier)
10959          {
10960             exp.expType = MkClassType(spec.name);
10961             exp.expType.kind = subClassType;
10962             exp.byReference = true;
10963          }
10964          else
10965          {
10966             exp.expType = MkClassType("ecere::com::Class");
10967             exp.byReference = true;
10968          }
10969          break;
10970       }
10971       case classDataExp:
10972       {
10973          Class _class = thisClass ? thisClass : currentClass;
10974          if(_class)
10975          {
10976             Identifier id = exp.classData.id;
10977             char structName[1024];
10978             Expression classExp;
10979             strcpy(structName, "__ecereClassData_");
10980             FullClassNameCat(structName, _class.fullName, false);
10981             exp.type = pointerExp;
10982             exp.member.member = id;
10983             if(curCompound && FindSymbol("this", curContext, curCompound.compound.context, false, false))
10984                classExp = MkExpMember(MkExpIdentifier(MkIdentifier("this")), MkIdentifier("_class"));
10985             else
10986                classExp = MkExpIdentifier(MkIdentifier("class"));
10987
10988             exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10989                MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10990                   MkExpBrackets(MkListOne(MkExpOp(
10991                      MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10992                         MkExpMember(classExp, MkIdentifier("data"))), '+',
10993                            MkExpMember(MkExpClass(MkListOne(MkSpecifierName(_class.fullName)), null), MkIdentifier("offsetClass")))))
10994                      )));
10995
10996             ProcessExpressionType(exp);
10997             return;
10998          }
10999          break;
11000       }
11001       case arrayExp:
11002       {
11003          Type type = null;
11004          const char * typeString = null;
11005          char typeStringBuf[1024];
11006          if(exp.destType && exp.destType.kind == classType && exp.destType._class && exp.destType._class.registered &&
11007             exp.destType._class.registered != containerClass && eClass_IsDerived(exp.destType._class.registered, containerClass))
11008          {
11009             Class templateClass = exp.destType._class.registered;
11010             typeString = templateClass.templateArgs[2].dataTypeString;
11011          }
11012          else if(exp.list)
11013          {
11014             // Guess type from expressions in the array
11015             Expression e;
11016             for(e = exp.list->first; e; e = e.next)
11017             {
11018                ProcessExpressionType(e);
11019                if(e.expType)
11020                {
11021                   if(!type) { type = e.expType; type.refCount++; }
11022                   else
11023                   {
11024                      // if(!MatchType(e.expType, type, null, null, null, false, false, false))
11025                      if(!MatchTypeExpression(e, type, null, false, true))
11026                      {
11027                         FreeType(type);
11028                         type = e.expType;
11029                         e.expType = null;
11030
11031                         e = exp.list->first;
11032                         ProcessExpressionType(e);
11033                         if(e.expType)
11034                         {
11035                            //if(!MatchTypes(e.expType, type, null, null, null, false, false, false))
11036                            if(!MatchTypeExpression(e, type, null, false, true))
11037                            {
11038                               FreeType(e.expType);
11039                               e.expType = null;
11040                               FreeType(type);
11041                               type = null;
11042                               break;
11043                            }
11044                         }
11045                      }
11046                   }
11047                   if(e.expType)
11048                   {
11049                      FreeType(e.expType);
11050                      e.expType = null;
11051                   }
11052                }
11053             }
11054             if(type)
11055             {
11056                typeStringBuf[0] = '\0';
11057                PrintTypeNoConst(type, typeStringBuf, false, true);
11058                typeString = typeStringBuf;
11059                FreeType(type);
11060                type = null;
11061             }
11062          }
11063          if(typeString)
11064          {
11065             /*
11066             (Container)& (struct BuiltInContainer)
11067             {
11068                ._vTbl = class(BuiltInContainer)._vTbl,
11069                ._class = class(BuiltInContainer),
11070                .refCount = 0,
11071                .data = (int[]){ 1, 7, 3, 4, 5 },
11072                .count = 5,
11073                .type = class(int),
11074             }
11075             */
11076             char templateString[1024];
11077             OldList * initializers = MkList();
11078             OldList * structInitializers = MkList();
11079             OldList * specs = MkList();
11080             Expression expExt;
11081             Declarator decl = SpecDeclFromString(typeString, specs, null);
11082             sprintf(templateString, "Container<%s>", typeString);
11083
11084             if(exp.list)
11085             {
11086                Expression e;
11087                type = ProcessTypeString(typeString, false);
11088                while((e = exp.list->first))
11089                {
11090                   exp.list->Remove(e);
11091                   e.destType = type;
11092                   type.refCount++;
11093                   ProcessExpressionType(e);
11094                   ListAdd(initializers, MkInitializerAssignment(e));
11095                }
11096                FreeType(type);
11097                delete exp.list;
11098             }
11099
11100             DeclareStruct(curExternal, "ecere::com::BuiltInContainer", false, true);
11101
11102             ListAdd(structInitializers, /*MkIdentifier("_vTbl")*/    MkInitializerAssignment(MkExpMember(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null), MkIdentifier("_vTbl"))));
11103                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11104             ListAdd(structInitializers, /*MkIdentifier("_class")*/   MkInitializerAssignment(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null)));
11105                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11106             ListAdd(structInitializers, /*MkIdentifier("_refCount")*/MkInitializerAssignment(MkExpConstant("0")));
11107                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11108             ListAdd(structInitializers, /*MkIdentifier("data")*/     MkInitializerAssignment(MkExpExtensionInitializer(
11109                MkTypeName(specs, MkDeclaratorArray(decl, null)),
11110                MkInitializerList(initializers))));
11111                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11112             ListAdd(structInitializers, /*MkIdentifier("count")*/    MkInitializerAssignment({ type = constantExp, constant = PrintString(initializers->count) }));
11113                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11114             ListAdd(structInitializers, /*MkIdentifier("type")*/     MkInitializerAssignment(MkExpClass(CopyList(specs, CopySpecifier), CopyDeclarator(decl))));
11115                ProcessExpressionType(((Initializer)structInitializers->last).exp);
11116             exp.expType = ProcessTypeString(templateString, false);
11117             exp.type = bracketsExp;
11118             exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(templateString)), null),
11119                MkExpOp(null, '&',
11120                expExt = MkExpExtensionInitializer(MkTypeName(MkListOne(MkSpecifierName("BuiltInContainer")), null),
11121                   MkInitializerList(structInitializers)))));
11122             ProcessExpressionType(expExt);
11123          }
11124          else
11125          {
11126             exp.expType = ProcessTypeString("Container", false);
11127             Compiler_Error($"Couldn't determine type of array elements\n");
11128          }
11129          break;
11130       }
11131    }
11132
11133    if(exp.expType && exp.expType.kind == thisClassType && thisClass && (!exp.destType || exp.destType.kind != thisClassType))
11134    {
11135       FreeType(exp.expType);
11136       exp.expType = ReplaceThisClassType(thisClass);
11137    }
11138
11139    // Resolve structures here
11140    if(exp.expType && (exp.expType.kind == structType || exp.expType.kind == unionType || exp.expType.kind == enumType) && !exp.expType.members.first && exp.expType.enumName)
11141    {
11142       Symbol symbol = FindSymbol(exp.expType.enumName, curContext, globalContext, true, false);
11143       // TODO: Fix members reference...
11144       if(symbol)
11145       {
11146          if(exp.expType.kind != enumType)
11147          {
11148             Type member;
11149             String enumName = CopyString(exp.expType.enumName);
11150
11151             // Fixed a memory leak on self-referencing C structs typedefs
11152             // by instantiating a new type rather than simply copying members
11153             // into exp.expType
11154             FreeType(exp.expType);
11155             exp.expType = Type { };
11156             exp.expType.kind = symbol.type.kind;
11157             exp.expType.refCount++;
11158             exp.expType.enumName = enumName;
11159
11160             exp.expType.members = symbol.type.members;
11161             for(member = symbol.type.members.first; member; member = member.next)
11162                member.refCount++;
11163          }
11164          else
11165          {
11166             NamedLink64 member;
11167             for(member = symbol.type.members.first; member; member = member.next)
11168             {
11169                NamedLink64 value { name = CopyString(member.name) };
11170                exp.expType.members.Add(value);
11171             }
11172          }
11173       }
11174    }
11175
11176    // Trying to do this here before conversion properties kick in and this becomes a new expression... (Fixing Class c; const char * a = c;)
11177    // Mark nohead classes as by reference, unless we're casting them to an integral type
11178    if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
11179       exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
11180          (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
11181           exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
11182    {
11183       exp.byReference = true;
11184    }
11185
11186    yylloc = exp.loc;
11187    if(exp.destType && (/*exp.destType.kind == voidType || */exp.destType.kind == dummyType) );
11188    else if(exp.destType && !exp.destType.keepCast)
11189    {
11190       if(!exp.needTemplateCast && exp.expType && (exp.expType.kind == templateType || exp.expType.passAsTemplate)) // && exp.destType && !exp.destType.passAsTemplate)
11191          exp.needTemplateCast = 1;
11192
11193       if(exp.destType.kind == voidType);
11194       else if(!CheckExpressionType(exp, exp.destType, false, !exp.destType.casted))
11195       {
11196          // Warn for casting unrelated types to/from struct classes
11197          bool invalidCast = false;
11198          if(inCompiler && exp.destType.count && exp.expType)
11199          {
11200             Class c1 = (exp.expType.kind == classType && exp.expType._class) ? exp.expType._class.registered : null;
11201             Class c2 = (exp.destType.kind == classType && exp.destType._class) ? exp.destType._class.registered : null;
11202             if(c1 && c1.type != structClass) c1 = null;
11203             if(c2 && c2.type != structClass) c2 = null;
11204             if((c1 && !exp.expType.byReference && !c2 && !exp.destType.isPointerType) || (c2 && !exp.destType.byReference && !c1 && !exp.expType.isPointerType))
11205                invalidCast = true;
11206          }
11207          if(!exp.destType.count || unresolved || invalidCast)
11208          {
11209             if(!exp.expType)
11210             {
11211                yylloc = exp.loc;
11212                if(exp.destType.kind != ellipsisType)
11213                {
11214                   char type2[1024];
11215                   type2[0] = '\0';
11216                   if(inCompiler)
11217                   {
11218                      char expString[10240];
11219                      expString[0] = '\0';
11220
11221                      PrintType(exp.destType, type2, false, true);
11222
11223                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11224                      if(unresolved)
11225                         Compiler_Error($"unresolved identifier %s; expected %s\n", expString, type2);
11226                      else if(exp.type != dummyExp)
11227                         Compiler_Error($"couldn't determine type of %s; expected %s\n", expString, type2);
11228                   }
11229                }
11230                else
11231                {
11232                   char expString[10240] ;
11233                   expString[0] = '\0';
11234                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11235
11236                   if(unresolved)
11237                      Compiler_Error($"unresolved identifier %s\n", expString);
11238                   else if(exp.type != dummyExp)
11239                      Compiler_Error($"couldn't determine type of %s\n", expString);
11240                }
11241             }
11242             else
11243             {
11244                char type1[1024];
11245                char type2[1024];
11246                type1[0] = '\0';
11247                type2[0] = '\0';
11248                if(inCompiler)
11249                {
11250                   PrintType(exp.expType, type1, false, true);
11251                   PrintType(exp.destType, type2, false, true);
11252                }
11253
11254                //CheckExpressionType(exp, exp.destType, false);
11255
11256                if(exp.destType.truth && exp.destType._class && exp.destType._class.registered && !strcmp(exp.destType._class.registered.name, "bool") &&
11257                   exp.expType.kind != voidType && exp.expType.kind != structType && exp.expType.kind != unionType &&
11258                   (exp.expType.kind != classType || exp.expType.classObjectType || (exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type != structClass)));
11259                else
11260                {
11261                   Expression nbExp = GetNonBracketsExp(exp);
11262                   bool skipWarning = false;
11263                   TypeKind kind = exp.destType.kind;
11264                   if(nbExp.type == conditionExp && !nbExp.destType.casted && nbExp.destType.kind == exp.destType.kind)
11265                      // The if/else operands have already been checked / warned about
11266                      skipWarning = true;
11267                   if((kind == charType || kind == shortType) && exp.destType.isSigned == exp.expType.signedBeforePromotion && nbExp.type == opExp && nbExp.op.exp1 && nbExp.op.exp2)
11268                   {
11269                      int op = nbExp.op.op;
11270                      Expression nbExp1, nbExp2;
11271                      TypeKind from;
11272
11273                      switch(op)
11274                      {
11275                         case '%': case '/':
11276                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11277                            from = nbExp1.expType.promotedFrom;
11278                            // Division and Modulo will not take more room than type before promotion
11279                            if(from == charType || (kind == shortType && from == shortType))
11280                               skipWarning = true;
11281                            break;
11282                         // Left shift
11283                         case LEFT_OP: case RIGHT_OP:
11284                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11285                            nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11286                            from = nbExp1.expType.promotedFrom;
11287                            // Right shift will not take more room than type before promotion
11288                            if(op == RIGHT_OP && (from == charType || (kind == shortType && from == shortType)))
11289                               skipWarning = true;
11290                            else if(nbExp2.isConstant && nbExp2.type == constantExp && (nbExp.op.op == RIGHT_OP || nbExp1.expType.bitMemberSize))
11291                            {
11292                               int n = (int)strtol(nbExp2.constant, null, 0);
11293                               int s = from == charType ? 8 : 16;
11294                               // Left shifting a bit member constrained in size may still fit in type before promotion
11295                               if(nbExp1.expType.bitMemberSize && nbExp1.expType.bitMemberSize < s)
11296                                  s = nbExp1.expType.bitMemberSize;
11297
11298                               // If right shifted enough things will fit in smaller type
11299                               if(nbExp.op.op == RIGHT_OP)
11300                                  s -= n;
11301                               else
11302                                  s += n;
11303                               if(s <= (kind == charType ? 8 : 16))
11304                                  skipWarning = true;
11305                            }
11306                            break;
11307                         case '-':
11308                            if(!exp.destType.isSigned)
11309                            {
11310                               nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11311                               nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11312                               from = nbExp2.expType.promotedFrom;
11313                               // Max value of unsigned type before promotion minus the same will always fit
11314                               if((from == charType || from == shortType) && nbExp1.isConstant && nbExp1.type == constantExp)
11315                               {
11316                                  int n = (int)strtol(nbExp1.constant, null, 0);
11317                                  if(n == (from == charType ? 255 : 65535))
11318                                     skipWarning = true;
11319                               }
11320                            }
11321                            break;
11322                         case '|':
11323                         {
11324                            TypeKind kind1, kind2;
11325                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11326                            nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11327                            kind1 = nbExp1.expType.promotedFrom ? nbExp1.expType.promotedFrom : nbExp1.expType.kind;
11328                            kind2 = nbExp2.expType.promotedFrom ? nbExp2.expType.promotedFrom : nbExp2.expType.kind;
11329                            if(((kind1 == charType || (kind1 == shortType && kind == shortType)) || MatchTypeExpression(nbExp1, exp.destType, null, false, false)) &&
11330                               ((kind2 == charType || (kind2 == shortType && kind == shortType)) || MatchTypeExpression(nbExp2, exp.destType, null, false, false)))
11331                               skipWarning = true;
11332                            break;
11333                         }
11334                         case '&':
11335                         {
11336                            TypeKind kind1, kind2;
11337                            nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
11338                            nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
11339                            kind1 = nbExp1.expType.promotedFrom ? nbExp1.expType.promotedFrom : nbExp1.expType.kind;
11340                            kind2 = nbExp2.expType.promotedFrom ? nbExp2.expType.promotedFrom : nbExp2.expType.kind;
11341                            if(((kind1 == charType || (kind1 == shortType && kind == shortType)) || MatchTypeExpression(nbExp1, exp.destType, null, false, false)) ||
11342                               ((kind2 == charType || (kind2 == shortType && kind == shortType)) || MatchTypeExpression(nbExp2, exp.destType, null, false, false)))
11343                               skipWarning = true;
11344                            break;
11345                         }
11346                      }
11347                   }
11348
11349                   if(!skipWarning)
11350                   {
11351                      char expString[10240];
11352                      expString[0] = '\0';
11353                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11354
11355 #ifdef _DEBUG
11356                      CheckExpressionType(exp, exp.destType, false, true);
11357 #endif
11358
11359                      // Flex & Bison generate code that triggers this, so we ignore it for a quiet sdk build:
11360                      if(!sourceFile || (!strstr(sourceFile, "src\\lexer.ec") && !strstr(sourceFile, "src/lexer.ec") &&
11361                                         !strstr(sourceFile, "src\\grammar.ec") && !strstr(sourceFile, "src/grammar.ec") &&
11362                                         !strstr(sourceFile, "src\\type.ec") && !strstr(sourceFile, "src/type.ec") &&
11363                                         !strstr(sourceFile, "src\\expression.ec") && !strstr(sourceFile, "src/expression.ec")))
11364                      {
11365                         if(invalidCast)
11366                            Compiler_Error($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
11367                         else
11368                            Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
11369                      }
11370                   }
11371
11372                   // TO CHECK: FORCING HERE TO HELP DEBUGGER
11373                   if(!inCompiler)
11374                   {
11375                      FreeType(exp.expType);
11376                      exp.destType.refCount++;
11377                      exp.expType = exp.destType;
11378                   }
11379                }
11380             }
11381          }
11382       }
11383       // Cast function pointers to void * as eC already checked compatibility
11384       else if(exp.destType && exp.destType.kind == pointerType && exp.destType.type && exp.destType.type.kind == functionType &&
11385               exp.expType && (exp.expType.kind == functionType || exp.expType.kind == methodType))
11386       {
11387          Expression nbExp = GetNonBracketsExp(exp);
11388          if(nbExp.type != castExp || !IsVoidPtrCast(nbExp.cast.typeName))
11389          {
11390             Expression e = MoveExpContents(exp);
11391             exp.cast.exp = MkExpBrackets(MkListOne(e));
11392             exp.type = castExp;
11393             exp.cast.exp.destType = exp.destType;
11394             if(exp.destType) exp.destType.refCount++;
11395             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
11396          }
11397       }
11398    }
11399    else if(unresolved)
11400    {
11401       if(exp.identifier._class && exp.identifier._class.name)
11402          Compiler_Error($"unresolved identifier %s::%s\n", exp.identifier._class.name, exp.identifier.string);
11403       else if(exp.identifier.string && exp.identifier.string[0])
11404          Compiler_Error($"unresolved identifier %s\n", exp.identifier.string);
11405    }
11406    else if(!exp.expType && exp.type != dummyExp)
11407    {
11408       char expString[10240];
11409       expString[0] = '\0';
11410       if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11411       Compiler_Error($"couldn't determine type of %s\n", expString);
11412    }
11413
11414    // Let's try to support any_object & typed_object here:
11415    if(inCompiler)
11416       ApplyAnyObjectLogic(exp);
11417
11418    // Mark nohead classes as by reference, unless we're casting them to an integral type
11419    if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
11420       exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
11421          (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
11422           exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
11423    {
11424       exp.byReference = true;
11425    }
11426    yylloc = oldyylloc;
11427 }
11428
11429 static void FindNextDataMember(Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
11430 {
11431    // THIS CODE WILL FIND NEXT MEMBER...
11432    if(*curMember)
11433    {
11434       *curMember = (*curMember).next;
11435
11436       if(subMemberStackPos && *subMemberStackPos > 0 && subMemberStack[*subMemberStackPos-1].type == unionMember)
11437       {
11438          *curMember = subMemberStack[--(*subMemberStackPos)];
11439          *curMember = (*curMember).next;
11440       }
11441
11442       // SKIP ALL PROPERTIES HERE...
11443       while((*curMember) && (*curMember).isProperty)
11444          *curMember = (*curMember).next;
11445
11446       if(subMemberStackPos)
11447       {
11448          while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
11449          {
11450             subMemberStack[(*subMemberStackPos)++] = *curMember;
11451
11452             *curMember = (*curMember).members.first;
11453             while(*curMember && (*curMember).isProperty)
11454                *curMember = (*curMember).next;
11455          }
11456       }
11457    }
11458    while(!*curMember)
11459    {
11460       if(!*curMember)
11461       {
11462          if(subMemberStackPos && *subMemberStackPos)
11463          {
11464             *curMember = subMemberStack[--(*subMemberStackPos)];
11465             *curMember = (*curMember).next;
11466          }
11467          else
11468          {
11469             Class lastCurClass = *curClass;
11470
11471             if(*curClass == _class) break;     // REACHED THE END
11472
11473             for(*curClass = _class; (*curClass).base != lastCurClass && (*curClass).base.type != systemClass; *curClass = (*curClass).base);
11474             *curMember = (*curClass).membersAndProperties.first;
11475          }
11476
11477          while((*curMember) && (*curMember).isProperty)
11478             *curMember = (*curMember).next;
11479          if(subMemberStackPos)
11480          {
11481             while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
11482             {
11483                subMemberStack[(*subMemberStackPos)++] = *curMember;
11484
11485                *curMember = (*curMember).members.first;
11486                while(*curMember && (*curMember).isProperty)
11487                   *curMember = (*curMember).next;
11488             }
11489          }
11490       }
11491    }
11492 }
11493
11494
11495 static void ProcessInitializer(Initializer init, Type type)
11496 {
11497    switch(init.type)
11498    {
11499       case expInitializer:
11500          if(!init.exp || init.exp.type != instanceExp || !init.exp.instance || init.exp.instance._class || !type || type.kind == classType)
11501          {
11502             // TESTING THIS FOR SHUTTING = 0 WARNING
11503             if(init.exp && !init.exp.destType)
11504             {
11505                FreeType(init.exp.destType);
11506                init.exp.destType = type;
11507                if(type) type.refCount++;
11508             }
11509             if(init.exp)
11510             {
11511                ProcessExpressionType(init.exp);
11512                init.isConstant = init.exp.isConstant;
11513             }
11514             break;
11515          }
11516          else
11517          {
11518             Expression exp = init.exp;
11519             Instantiation inst = exp.instance;
11520             MembersInit members;
11521
11522             init.type = listInitializer;
11523             init.list = MkList();
11524
11525             if(inst.members)
11526             {
11527                for(members = inst.members->first; members; members = members.next)
11528                {
11529                   if(members.type == dataMembersInit)
11530                   {
11531                      MemberInit member;
11532                      for(member = members.dataMembers->first; member; member = member.next)
11533                      {
11534                         ListAdd(init.list, member.initializer);
11535                         member.initializer = null;
11536                      }
11537                   }
11538                   // Discard all MembersInitMethod
11539                }
11540             }
11541             FreeExpression(exp);
11542          }
11543       case listInitializer:
11544       {
11545          Initializer i;
11546          Type initializerType = null;
11547          Class curClass = null;
11548          DataMember curMember = null;
11549          DataMember subMemberStack[256];
11550          int subMemberStackPos = 0;
11551
11552          if(type && type.kind == arrayType)
11553             initializerType = Dereference(type);
11554          else if(type && (type.kind == structType || type.kind == unionType))
11555             initializerType = type.members.first;
11556
11557          for(i = init.list->first; i; i = i.next)
11558          {
11559             if(type && type.kind == classType && type._class && type._class.registered)
11560             {
11561                // 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)
11562                FindNextDataMember(type._class.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
11563                // TODO: Generate error on initializing a private data member this way from another module...
11564                if(curMember)
11565                {
11566                   if(!curMember.dataType)
11567                      curMember.dataType = ProcessTypeString(curMember.dataTypeString, false);
11568                   initializerType = curMember.dataType;
11569                }
11570             }
11571             ProcessInitializer(i, initializerType);
11572             if(initializerType && type && (type.kind == structType || type.kind == unionType))
11573                initializerType = initializerType.next;
11574             if(!i.isConstant)
11575                init.isConstant = false;
11576          }
11577
11578          if(type && type.kind == arrayType)
11579             FreeType(initializerType);
11580
11581          if(type && type.kind != arrayType && type.kind != structType && type.kind != unionType && (type.kind != classType || !type._class.registered || type._class.registered.type != structClass))
11582          {
11583             Compiler_Error($"Assigning list initializer to non list\n");
11584          }
11585          break;
11586       }
11587    }
11588 }
11589
11590 static void ProcessSpecifier(Specifier spec, bool declareStruct, bool warnClasses)
11591 {
11592    switch(spec.type)
11593    {
11594       case baseSpecifier:
11595       {
11596          if(spec.specifier == THISCLASS)
11597          {
11598             if(thisClass)
11599             {
11600                spec.type = nameSpecifier;
11601                spec.name = ReplaceThisClass(thisClass);
11602                spec.symbol = FindClass(spec.name);
11603                ProcessSpecifier(spec, declareStruct, false);
11604             }
11605          }
11606          break;
11607       }
11608       case nameSpecifier:
11609       {
11610          Symbol symbol = FindType(curContext, spec.name);
11611          if(symbol)
11612             DeclareType(curExternal, symbol.type, true, true);
11613          else if(spec.symbol /*&& declareStruct*/)
11614          {
11615             Class c = spec.symbol.registered;
11616             if(warnClasses && !c)
11617                Compiler_Warning("Undeclared class %s\n", spec.name);
11618             DeclareStruct(curExternal, spec.name, c && c.type == noHeadClass, declareStruct && c && c.type == structClass);
11619          }
11620          break;
11621       }
11622       case enumSpecifier:
11623       {
11624          Enumerator e;
11625          if(spec.list)
11626          {
11627             for(e = spec.list->first; e; e = e.next)
11628             {
11629                if(e.exp)
11630                   ProcessExpressionType(e.exp);
11631             }
11632          }
11633          // Fall through for IDE type processing
11634          if(inCompiler)
11635             break;
11636       }
11637       case structSpecifier:
11638       case unionSpecifier:
11639       {
11640          if(spec.definitions)
11641          {
11642             //ClassDef def;
11643             Symbol symbol = spec.id ? FindClass(spec.id.string) : null;
11644             //if(symbol)
11645                ProcessClass(spec.definitions, symbol);
11646             /*else
11647             {
11648                for(def = spec.definitions->first; def; def = def.next)
11649                {
11650                   //if(def.type == declarationClassDef && def.decl && def.decl.type == DeclarationStruct)
11651                      ProcessDeclaration(def.decl);
11652                }
11653             }*/
11654          }
11655          break;
11656       }
11657       /*
11658       case classSpecifier:
11659       {
11660          Symbol classSym = FindClass(spec.name);
11661          if(classSym && classSym.registered && classSym.registered.type == structClass)
11662             DeclareStruct(spec.name, false, true);
11663          break;
11664       }
11665       */
11666    }
11667 }
11668
11669
11670 static void ProcessDeclarator(Declarator decl, bool isFunction)
11671 {
11672    switch(decl.type)
11673    {
11674       case identifierDeclarator:
11675          if(decl.identifier.classSym /* TODO: Name Space Fix ups  || decl.identifier.nameSpace*/)
11676          {
11677             FreeSpecifier(decl.identifier._class);
11678             decl.identifier._class = null;
11679          }
11680          break;
11681       case arrayDeclarator:
11682          if(decl.array.exp)
11683             ProcessExpressionType(decl.array.exp);
11684       case structDeclarator:
11685       case bracketsDeclarator:
11686       case functionDeclarator:
11687       case pointerDeclarator:
11688       case extendedDeclarator:
11689       case extendedDeclaratorEnd:
11690       {
11691          Identifier id = null;
11692          Specifier classSpec = null;
11693          if(decl.type == functionDeclarator)
11694          {
11695             id = GetDeclId(decl);
11696             if(id && id._class)
11697             {
11698                classSpec = id._class;
11699                id._class = null;
11700             }
11701          }
11702          if(decl.declarator)
11703             ProcessDeclarator(decl.declarator, isFunction);
11704          if(decl.type == functionDeclarator)
11705          {
11706             if(classSpec)
11707             {
11708                TypeName param
11709                {
11710                   qualifiers = MkListOne(classSpec);
11711                   declarator = null;
11712                };
11713                if(!decl.function.parameters)
11714                   decl.function.parameters = MkList();
11715                decl.function.parameters->Insert(null, param);
11716             }
11717             if(decl.function.parameters)
11718             {
11719                TypeName param;
11720
11721                for(param = decl.function.parameters->first; param; param = param.next)
11722                {
11723                   if(param.qualifiers)
11724                   {
11725                      Specifier spec;
11726                      for(spec = param.qualifiers->first; spec; spec = spec.next)
11727                      {
11728                         if(spec.type == baseSpecifier)
11729                         {
11730                            if(spec.specifier == TYPED_OBJECT)
11731                            {
11732                               Declarator d = param.declarator;
11733                               TypeName newParam
11734                               {
11735                                  qualifiers = MkListOne(MkSpecifier(VOID));
11736                                  declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11737                               };
11738                               if(d.type != pointerDeclarator)
11739                                  newParam.qualifiers->Insert(null, MkSpecifier(CONST));
11740
11741                               FreeList(param.qualifiers, FreeSpecifier);
11742
11743                               param.qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
11744                               param.declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
11745
11746                               DeclareStruct(curExternal, "ecere::com::Class", false, true);
11747
11748                               decl.function.parameters->Insert(param, newParam);
11749                               param = newParam;
11750                               break;
11751                            }
11752                            else if(spec.specifier == ANY_OBJECT)
11753                            {
11754                               Declarator d = param.declarator;
11755
11756                               FreeList(param.qualifiers, FreeSpecifier);
11757
11758                               param.qualifiers = MkListOne(MkSpecifier(VOID));
11759                               if(d.type != pointerDeclarator)
11760                                  param.qualifiers->Insert(null, MkSpecifier(CONST));
11761                               param.declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11762                               break;
11763                            }
11764                            else if(spec.specifier == THISCLASS)
11765                            {
11766                               if(thisClass)
11767                               {
11768                                  spec.type = nameSpecifier;
11769                                  spec.name = ReplaceThisClass(thisClass);
11770                                  spec.symbol = FindClass(spec.name);
11771                                  ProcessSpecifier(spec, false, false);
11772                               }
11773                               break;
11774                            }
11775                         }
11776                         else if(spec.type == nameSpecifier)
11777                         {
11778                            ProcessSpecifier(spec, isFunction, true);
11779                         }
11780                      }
11781                   }
11782
11783                   if(param.declarator)
11784                      ProcessDeclarator(param.declarator, false);
11785                }
11786             }
11787          }
11788          break;
11789       }
11790    }
11791 }
11792
11793 static void ProcessDeclaration(Declaration decl, bool warnClasses)
11794 {
11795    yylloc = decl.loc;
11796    switch(decl.type)
11797    {
11798       case initDeclaration:
11799       {
11800          bool declareStruct = false;
11801          /*
11802          lineNum = decl.pos.line;
11803          column = decl.pos.col;
11804          */
11805
11806          if(decl.declarators)
11807          {
11808             InitDeclarator d;
11809
11810             for(d = decl.declarators->first; d; d = d.next)
11811             {
11812                Type type, subType;
11813                ProcessDeclarator(d.declarator, false);
11814
11815                type = ProcessType(decl.specifiers, d.declarator);
11816
11817                if(d.initializer)
11818                {
11819                   ProcessInitializer(d.initializer, type);
11820
11821                   // Change "ColorRGB a = ColorRGB { 1,2,3 } => ColorRGB a { 1,2,3 }
11822
11823                   if(decl.declarators->count == 1 && d.initializer.type == expInitializer &&
11824                      d.initializer.exp.type == instanceExp)
11825                   {
11826                      if(type.kind == classType && type._class ==
11827                         d.initializer.exp.expType._class)
11828                      {
11829                         Instantiation inst = d.initializer.exp.instance;
11830                         inst.exp = MkExpIdentifier(CopyIdentifier(GetDeclId(d.declarator)));
11831
11832                         d.initializer.exp.instance = null;
11833                         if(decl.specifiers)
11834                            FreeList(decl.specifiers, FreeSpecifier);
11835                         FreeList(decl.declarators, FreeInitDeclarator);
11836
11837                         d = null;
11838
11839                         decl.type = instDeclaration;
11840                         decl.inst = inst;
11841                      }
11842                   }
11843                }
11844                for(subType = type; subType;)
11845                {
11846                   if(subType.kind == classType)
11847                   {
11848                      declareStruct = true;
11849                      break;
11850                   }
11851                   else if(subType.kind == pointerType)
11852                      break;
11853                   else if(subType.kind == arrayType)
11854                      subType = subType.arrayType;
11855                   else
11856                      break;
11857                }
11858
11859                FreeType(type);
11860                if(!d) break;
11861             }
11862          }
11863
11864          if(decl.specifiers)
11865          {
11866             Specifier s;
11867             for(s = decl.specifiers->first; s; s = s.next)
11868             {
11869                ProcessSpecifier(s, declareStruct, true);
11870             }
11871          }
11872          break;
11873       }
11874       case instDeclaration:
11875       {
11876          ProcessInstantiationType(decl.inst);
11877          break;
11878       }
11879       case structDeclaration:
11880       {
11881          Specifier spec;
11882          Declarator d;
11883          bool declareStruct = false;
11884
11885          if(decl.declarators)
11886          {
11887             for(d = decl.declarators->first; d; d = d.next)
11888             {
11889                Type type = ProcessType(decl.specifiers, d.declarator);
11890                Type subType;
11891                ProcessDeclarator(d, false);
11892                for(subType = type; subType;)
11893                {
11894                   if(subType.kind == classType)
11895                   {
11896                      declareStruct = true;
11897                      break;
11898                   }
11899                   else if(subType.kind == pointerType)
11900                      break;
11901                   else if(subType.kind == arrayType)
11902                      subType = subType.arrayType;
11903                   else
11904                      break;
11905                }
11906                FreeType(type);
11907             }
11908          }
11909          if(decl.specifiers)
11910          {
11911             for(spec = decl.specifiers->first; spec; spec = spec.next)
11912                ProcessSpecifier(spec, declareStruct, warnClasses);
11913          }
11914          break;
11915       }
11916    }
11917 }
11918
11919 static FunctionDefinition curFunction;
11920
11921 static void CreateFireWatcher(Property prop, Expression object, Statement stmt)
11922 {
11923    char propName[1024], propNameM[1024];
11924    char getName[1024], setName[1024];
11925    OldList * args;
11926
11927    DeclareProperty(curExternal, prop, setName, getName);
11928
11929    // eInstance_FireWatchers(object, prop);
11930    strcpy(propName, "__ecereProp_");
11931    FullClassNameCat(propName, prop._class.fullName, false);
11932    strcat(propName, "_");
11933    FullClassNameCat(propName, prop.name, true);
11934
11935    strcpy(propNameM, "__ecerePropM_");
11936    FullClassNameCat(propNameM, prop._class.fullName, false);
11937    strcat(propNameM, "_");
11938    FullClassNameCat(propNameM, prop.name, true);
11939
11940    if(prop.isWatchable)
11941    {
11942       args = MkList();
11943       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11944       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11945       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11946
11947       args = MkList();
11948       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11949       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11950       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11951
11952       DeclareFunctionUtil(curExternal, "eInstance_FireWatchers");
11953    }
11954
11955    {
11956       args = MkList();
11957       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11958       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11959       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11960
11961       args = MkList();
11962       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11963       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11964       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11965
11966       DeclareFunctionUtil(curExternal, "eInstance_FireSelfWatchers");
11967    }
11968
11969    if(curFunction.propSet && !strcmp(curFunction.propSet.string, prop.name) &&
11970       (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
11971       curFunction.propSet.fireWatchersDone = true;
11972 }
11973
11974 static void ProcessStatement(Statement stmt)
11975 {
11976    yylloc = stmt.loc;
11977    /*
11978    lineNum = stmt.pos.line;
11979    column = stmt.pos.col;
11980    */
11981    switch(stmt.type)
11982    {
11983       case labeledStmt:
11984          ProcessStatement(stmt.labeled.stmt);
11985          break;
11986       case caseStmt:
11987          // This expression should be constant...
11988          if(stmt.caseStmt.exp)
11989          {
11990             FreeType(stmt.caseStmt.exp.destType);
11991             stmt.caseStmt.exp.destType = curSwitchType;
11992             if(curSwitchType) curSwitchType.refCount++;
11993             ProcessExpressionType(stmt.caseStmt.exp);
11994             ComputeExpression(stmt.caseStmt.exp);
11995          }
11996          if(stmt.caseStmt.stmt)
11997             ProcessStatement(stmt.caseStmt.stmt);
11998          break;
11999       case compoundStmt:
12000       {
12001          if(stmt.compound.context)
12002          {
12003             Declaration decl;
12004             Statement s;
12005
12006             Statement prevCompound = curCompound;
12007             Context prevContext = curContext;
12008
12009             if(!stmt.compound.isSwitch)
12010                curCompound = stmt;
12011             curContext = stmt.compound.context;
12012
12013             if(stmt.compound.declarations)
12014             {
12015                for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
12016                   ProcessDeclaration(decl, true);
12017             }
12018             if(stmt.compound.statements)
12019             {
12020                for(s = stmt.compound.statements->first; s; s = s.next)
12021                   ProcessStatement(s);
12022             }
12023
12024             curContext = prevContext;
12025             curCompound = prevCompound;
12026          }
12027          break;
12028       }
12029       case expressionStmt:
12030       {
12031          Expression exp;
12032          if(stmt.expressions)
12033          {
12034             for(exp = stmt.expressions->first; exp; exp = exp.next)
12035                ProcessExpressionType(exp);
12036          }
12037          break;
12038       }
12039       case ifStmt:
12040       {
12041          Expression exp;
12042
12043          FreeType(((Expression)stmt.ifStmt.exp->last).destType);
12044          ((Expression)stmt.ifStmt.exp->last).destType = MkClassType("bool");
12045          ((Expression)stmt.ifStmt.exp->last).destType.truth = true;
12046          for(exp = stmt.ifStmt.exp->first; exp; exp = exp.next)
12047          {
12048             ProcessExpressionType(exp);
12049          }
12050          if(stmt.ifStmt.stmt)
12051             ProcessStatement(stmt.ifStmt.stmt);
12052          if(stmt.ifStmt.elseStmt)
12053             ProcessStatement(stmt.ifStmt.elseStmt);
12054          break;
12055       }
12056       case switchStmt:
12057       {
12058          Type oldSwitchType = curSwitchType;
12059          if(stmt.switchStmt.exp)
12060          {
12061             Expression exp;
12062             for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
12063             {
12064                if(!exp.next)
12065                {
12066                   /*
12067                   Type destType
12068                   {
12069                      kind = intType;
12070                      refCount = 1;
12071                   };
12072                   e.exp.destType = destType;
12073                   */
12074
12075                   ProcessExpressionType(exp);
12076                }
12077                if(!exp.next)
12078                   curSwitchType = exp.expType;
12079             }
12080          }
12081          ProcessStatement(stmt.switchStmt.stmt);
12082          curSwitchType = oldSwitchType;
12083          break;
12084       }
12085       case whileStmt:
12086       {
12087          if(stmt.whileStmt.exp)
12088          {
12089             Expression exp;
12090
12091             FreeType(((Expression)stmt.whileStmt.exp->last).destType);
12092             ((Expression)stmt.whileStmt.exp->last).destType = MkClassType("bool");
12093             ((Expression)stmt.whileStmt.exp->last).destType.truth = true;
12094             for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
12095             {
12096                ProcessExpressionType(exp);
12097             }
12098          }
12099          if(stmt.whileStmt.stmt)
12100             ProcessStatement(stmt.whileStmt.stmt);
12101          break;
12102       }
12103       case doWhileStmt:
12104       {
12105          if(stmt.doWhile.exp)
12106          {
12107             Expression exp;
12108
12109             if(stmt.doWhile.exp->last)
12110             {
12111                FreeType(((Expression)stmt.doWhile.exp->last).destType);
12112                ((Expression)stmt.doWhile.exp->last).destType = MkClassType("bool");
12113                ((Expression)stmt.doWhile.exp->last).destType.truth = true;
12114             }
12115             for(exp = stmt.doWhile.exp->first; exp; exp = exp.next)
12116             {
12117                ProcessExpressionType(exp);
12118             }
12119          }
12120          if(stmt.doWhile.stmt)
12121             ProcessStatement(stmt.doWhile.stmt);
12122          break;
12123       }
12124       case forStmt:
12125       {
12126          Expression exp;
12127          if(stmt.forStmt.init)
12128             ProcessStatement(stmt.forStmt.init);
12129
12130          if(stmt.forStmt.check && stmt.forStmt.check.expressions)
12131          {
12132             FreeType(((Expression)stmt.forStmt.check.expressions->last).destType);
12133             ((Expression)stmt.forStmt.check.expressions->last).destType = MkClassType("bool");
12134             ((Expression)stmt.forStmt.check.expressions->last).destType.truth = true;
12135          }
12136
12137          if(stmt.forStmt.check)
12138             ProcessStatement(stmt.forStmt.check);
12139          if(stmt.forStmt.increment)
12140          {
12141             for(exp = stmt.forStmt.increment->first; exp; exp = exp.next)
12142                ProcessExpressionType(exp);
12143          }
12144
12145          if(stmt.forStmt.stmt)
12146             ProcessStatement(stmt.forStmt.stmt);
12147          break;
12148       }
12149       case forEachStmt:
12150       {
12151          Identifier id = stmt.forEachStmt.id;
12152          OldList * exp = stmt.forEachStmt.exp;
12153          OldList * filter = stmt.forEachStmt.filter;
12154          Statement block = stmt.forEachStmt.stmt;
12155          char iteratorType[1024];
12156          Type source;
12157          Expression e;
12158          bool isBuiltin = exp && exp->last &&
12159             (((Expression)exp->last).type == ExpressionType::arrayExp ||
12160               (((Expression)exp->last).type == castExp && ((Expression)exp->last).cast.exp.type == ExpressionType::arrayExp));
12161          Expression arrayExp;
12162          const char * typeString = null;
12163          int builtinCount = 0;
12164
12165          for(e = exp ? exp->first : null; e; e = e.next)
12166          {
12167             if(!e.next)
12168             {
12169                FreeType(e.destType);
12170                e.destType = ProcessTypeString("Container", false);
12171             }
12172             if(!isBuiltin || e.next)
12173                ProcessExpressionType(e);
12174          }
12175
12176          source = (exp && exp->last) ? ((Expression)exp->last).expType : null;
12177          if(isBuiltin || (source && source.kind == classType && source._class && source._class.registered && source._class.registered != containerClass &&
12178             eClass_IsDerived(source._class.registered, containerClass)))
12179          {
12180             Class _class = source ? source._class.registered : null;
12181             Symbol symbol;
12182             Expression expIt = null;
12183             bool isMap = false, isArray = false, isLinkList = false, isList = false, isCustomAVLTree = false; //, isAVLTree = false;
12184             Class arrayClass = eSystem_FindClass(privateModule, "Array");
12185             Class linkListClass = eSystem_FindClass(privateModule, "LinkList");
12186             Class customAVLTreeClass = eSystem_FindClass(privateModule, "CustomAVLTree");
12187
12188             if(inCompiler)
12189             {
12190                stmt.type = compoundStmt;
12191
12192                stmt.compound.context = Context { };
12193                stmt.compound.context.parent = curContext;
12194                curContext = stmt.compound.context;
12195             }
12196
12197             if(source && eClass_IsDerived(source._class.registered, customAVLTreeClass))
12198             {
12199                Class mapClass = eSystem_FindClass(privateModule, "Map");
12200                //Class avlTreeClass = eSystem_FindClass(privateModule, "AVLTree");
12201                isCustomAVLTree = true;
12202                /*if(eClass_IsDerived(source._class.registered, avlTreeClass))
12203                   isAVLTree = true;
12204                else */if(eClass_IsDerived(source._class.registered, mapClass))
12205                   isMap = true;
12206             }
12207             else if(source && eClass_IsDerived(source._class.registered, arrayClass)) isArray = true;
12208             else if(source && eClass_IsDerived(source._class.registered, linkListClass))
12209             {
12210                Class listClass = eSystem_FindClass(privateModule, "List");
12211                isLinkList = true;
12212                isList = eClass_IsDerived(source._class.registered, listClass);
12213             }
12214
12215             if(inCompiler && isArray)
12216             {
12217                Declarator decl;
12218                OldList * specs = MkList();
12219                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
12220                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
12221                stmt.compound.declarations = MkListOne(
12222                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12223                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12224                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalArray")),
12225                      MkInitializerAssignment(MkExpBrackets(exp))))));
12226             }
12227             else if(isBuiltin)
12228             {
12229                Type type = null;
12230                char typeStringBuf[1024];
12231
12232                // TODO: Merge this code?
12233                arrayExp = (((Expression)exp->last).type == ExpressionType::arrayExp) ? (Expression)exp->last : ((Expression)exp->last).cast.exp;
12234                if(((Expression)exp->last).type == castExp)
12235                {
12236                   TypeName typeName = ((Expression)exp->last).cast.typeName;
12237                   if(typeName)
12238                      arrayExp.destType = ProcessType(typeName.qualifiers, typeName.declarator);
12239                }
12240
12241                if(arrayExp.destType && arrayExp.destType.kind == classType && arrayExp.destType._class && arrayExp.destType._class.registered &&
12242                   arrayExp.destType._class.registered != containerClass && eClass_IsDerived(arrayExp.destType._class.registered, containerClass) &&
12243                   arrayExp.destType._class.registered.templateArgs)
12244                {
12245                   Class templateClass = arrayExp.destType._class.registered;
12246                   typeString = templateClass.templateArgs[2].dataTypeString;
12247                }
12248                else if(arrayExp.list)
12249                {
12250                   // Guess type from expressions in the array
12251                   Expression e;
12252                   for(e = arrayExp.list->first; e; e = e.next)
12253                   {
12254                      ProcessExpressionType(e);
12255                      if(e.expType)
12256                      {
12257                         if(!type) { type = e.expType; type.refCount++; }
12258                         else
12259                         {
12260                            // if(!MatchType(e.expType, type, null, null, null, false, false, false))
12261                            if(!MatchTypeExpression(e, type, null, false, true))
12262                            {
12263                               FreeType(type);
12264                               type = e.expType;
12265                               e.expType = null;
12266
12267                               e = arrayExp.list->first;
12268                               ProcessExpressionType(e);
12269                               if(e.expType)
12270                               {
12271                                  //if(!MatchTypes(e.expType, type, null, null, null, false, false, false, false))
12272                                  if(!MatchTypeExpression(e, type, null, false, true))
12273                                  {
12274                                     FreeType(e.expType);
12275                                     e.expType = null;
12276                                     FreeType(type);
12277                                     type = null;
12278                                     break;
12279                                  }
12280                               }
12281                            }
12282                         }
12283                         if(e.expType)
12284                         {
12285                            FreeType(e.expType);
12286                            e.expType = null;
12287                         }
12288                      }
12289                   }
12290                   if(type)
12291                   {
12292                      typeStringBuf[0] = '\0';
12293                      PrintType(type, typeStringBuf, false, true);
12294                      typeString = typeStringBuf;
12295                      FreeType(type);
12296                   }
12297                }
12298                if(typeString)
12299                {
12300                   if(inCompiler)
12301                   {
12302                      OldList * initializers = MkList();
12303                      Declarator decl;
12304                      OldList * specs = MkList();
12305                      if(arrayExp.list)
12306                      {
12307                         Expression e;
12308
12309                         builtinCount = arrayExp.list->count;
12310                         type = ProcessTypeString(typeString, false);
12311                         while((e = arrayExp.list->first))
12312                         {
12313                            arrayExp.list->Remove(e);
12314                            e.destType = type;
12315                            type.refCount++;
12316                            ProcessExpressionType(e);
12317                            if(inCompiler)
12318                               ListAdd(initializers, MkInitializerAssignment(e));
12319                         }
12320                         FreeType(type);
12321                         delete arrayExp.list;
12322                      }
12323                      decl = SpecDeclFromString(typeString, specs, MkDeclaratorIdentifier(id));
12324
12325                      stmt.compound.declarations = MkListOne(MkDeclaration(CopyList(specs, CopySpecifier),
12326                         MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), /*CopyDeclarator(*/decl/*)*/), null))));
12327
12328                      ListAdd(stmt.compound.declarations, MkDeclaration(specs, MkListOne(MkInitDeclarator(
12329                         PlugDeclarator(
12330                            /*CopyDeclarator(*/decl/*)*/, MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__internalArray")), null)
12331                            ), MkInitializerList(initializers)))));
12332                      FreeList(exp, FreeExpression);
12333                   }
12334                   else if(arrayExp.list)
12335                   {
12336                      Expression e;
12337                      type = ProcessTypeString(typeString, false);
12338                      for(e = arrayExp.list->first; e; e = e.next)
12339                      {
12340                         e.destType = type;
12341                         type.refCount++;
12342                         ProcessExpressionType(e);
12343                      }
12344                      FreeType(type);
12345                   }
12346                }
12347                else
12348                {
12349                   arrayExp.expType = ProcessTypeString("Container", false);
12350                   Compiler_Error($"Couldn't determine type of array elements\n");
12351                }
12352
12353                /*
12354                Declarator decl;
12355                OldList * specs = MkList();
12356
12357                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
12358                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
12359                stmt.compound.declarations = MkListOne(
12360                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12361                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName("BuiltInContainer")),
12362                   MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(MkIdentifier("__internalArray"))),
12363                      MkInitializerAssignment(MkExpBrackets(exp))))));
12364                */
12365             }
12366             else if(inCompiler && isLinkList && !isList)
12367             {
12368                Declarator decl;
12369                OldList * specs = MkList();
12370                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
12371                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12372                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12373                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalLinkList")),
12374                      MkInitializerAssignment(MkExpBrackets(exp))))));
12375             }
12376             /*else if(isCustomAVLTree)
12377             {
12378                Declarator decl;
12379                OldList * specs = MkList();
12380                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
12381                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12382                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12383                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalTree")),
12384                      MkInitializerAssignment(MkExpBrackets(exp))))));
12385             }*/
12386             else if(inCompiler && _class.templateArgs)
12387             {
12388                if(isMap)
12389                   sprintf(iteratorType, "MapIterator<%s, %s >", _class.templateArgs[5].dataTypeString, _class.templateArgs[6].dataTypeString);
12390                else
12391                   sprintf(iteratorType, "Iterator<%s, %s >", _class.templateArgs[2].dataTypeString, _class.templateArgs[1].dataTypeString);
12392
12393                stmt.compound.declarations = MkListOne(
12394                   MkDeclarationInst(MkInstantiationNamed(MkListOne(MkSpecifierName(iteratorType)),
12395                   MkExpIdentifier(id), MkListOne(MkMembersInitList(MkListOne(MkMemberInit(isMap ? MkListOne(MkIdentifier("map")) : null,
12396                   MkInitializerAssignment(MkExpBrackets(exp)))))))));
12397             }
12398             if(inCompiler)
12399             {
12400                symbol = FindSymbol(id.string, curContext, curContext, false, false);
12401
12402                if(block)
12403                {
12404                   // Reparent sub-contexts in this statement
12405                   switch(block.type)
12406                   {
12407                      case compoundStmt:
12408                         if(block.compound.context)
12409                            block.compound.context.parent = stmt.compound.context;
12410                         break;
12411                      case ifStmt:
12412                         if(block.ifStmt.stmt && block.ifStmt.stmt.type == compoundStmt && block.ifStmt.stmt.compound.context)
12413                            block.ifStmt.stmt.compound.context.parent = stmt.compound.context;
12414                         if(block.ifStmt.elseStmt && block.ifStmt.elseStmt.type == compoundStmt && block.ifStmt.elseStmt.compound.context)
12415                            block.ifStmt.elseStmt.compound.context.parent = stmt.compound.context;
12416                         break;
12417                      case switchStmt:
12418                         if(block.switchStmt.stmt && block.switchStmt.stmt.type == compoundStmt && block.switchStmt.stmt.compound.context)
12419                            block.switchStmt.stmt.compound.context.parent = stmt.compound.context;
12420                         break;
12421                      case whileStmt:
12422                         if(block.whileStmt.stmt && block.whileStmt.stmt.type == compoundStmt && block.whileStmt.stmt.compound.context)
12423                            block.whileStmt.stmt.compound.context.parent = stmt.compound.context;
12424                         break;
12425                      case doWhileStmt:
12426                         if(block.doWhile.stmt && block.doWhile.stmt.type == compoundStmt && block.doWhile.stmt.compound.context)
12427                            block.doWhile.stmt.compound.context.parent = stmt.compound.context;
12428                         break;
12429                      case forStmt:
12430                         if(block.forStmt.stmt && block.forStmt.stmt.type == compoundStmt && block.forStmt.stmt.compound.context)
12431                            block.forStmt.stmt.compound.context.parent = stmt.compound.context;
12432                         break;
12433                      case forEachStmt:
12434                         if(block.forEachStmt.stmt && block.forEachStmt.stmt.type == compoundStmt && block.forEachStmt.stmt.compound.context)
12435                            block.forEachStmt.stmt.compound.context.parent = stmt.compound.context;
12436                         break;
12437                      /* Only handle those with compound blocks for now... (Potential limitation on compound statements within expressions)
12438                      case labeledStmt:
12439                      case caseStmt
12440                      case expressionStmt:
12441                      case gotoStmt:
12442                      case continueStmt:
12443                      case breakStmt
12444                      case returnStmt:
12445                      case asmStmt:
12446                      case badDeclarationStmt:
12447                      case fireWatchersStmt:
12448                      case stopWatchingStmt:
12449                      case watchStmt:
12450                      */
12451                   }
12452                }
12453
12454                if(filter)
12455                {
12456                   block = MkIfStmt(filter, block, null);
12457                }
12458                if(isArray)
12459                {
12460                   stmt.compound.statements = MkListOne(MkForStmt(
12461                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array"))))),
12462                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12463                         MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array")), '+', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
12464                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12465                      block));
12466                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12467                  ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12468                  ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12469                }
12470                else if(isBuiltin)
12471                {
12472                   char count[128];
12473                   //OldList * specs = MkList();
12474                   // Declarator decl = SpecDeclFromString(typeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
12475
12476                   sprintf(count, "%d", builtinCount);
12477
12478                   stmt.compound.statements = MkListOne(MkForStmt(
12479                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpIdentifier(MkIdentifier("__internalArray"))))),
12480                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12481                         MkExpOp(MkExpIdentifier(MkIdentifier("__internalArray")), '+', MkExpConstant(count))))),
12482                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12483                      block));
12484
12485                   /*
12486                   Declarator decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
12487                   stmt.compound.statements = MkListOne(MkForStmt(
12488                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))))),
12489                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12490                         MkExpOp(MkExpCast(MkTypeName(specs, decl), MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))), '+', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
12491                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
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(isLinkList && !isList)
12499                {
12500                   Class typeClass = eSystem_FindClass(_class.module, _class.templateArgs[3].dataTypeString);
12501                   Class listItemClass = eSystem_FindClass(_class.module, "ListItem");
12502                   if(typeClass && eClass_IsDerived(typeClass, listItemClass) && _class.templateArgs[5].dataTypeString &&
12503                      !strcmp(_class.templateArgs[5].dataTypeString, "LT::link"))
12504                   {
12505                      stmt.compound.statements = MkListOne(MkForStmt(
12506                         MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
12507                         MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12508                         MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
12509                         block));
12510                   }
12511                   else
12512                   {
12513                      OldList * specs = MkList();
12514                      Declarator decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, null);
12515                      stmt.compound.statements = MkListOne(MkForStmt(
12516                         MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
12517                         MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12518                         MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpCast(MkTypeName(specs, decl), MkExpCall(
12519                            MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("GetNext")),
12520                               MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName("IteratorPointer")), null), MkExpIdentifier(CopyIdentifier(id)))))))),
12521                         block));
12522                   }
12523                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12524                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12525                   ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12526                }
12527                /*else if(isCustomAVLTree)
12528                {
12529                   stmt.compound.statements = MkListOne(MkForStmt(
12530                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpMember(MkExpIdentifier(
12531                         MkIdentifier("__internalTree")), MkIdentifier("root")), MkIdentifier("minimum"))))),
12532                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12533                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
12534                      block));
12535
12536                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12537                   ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12538                   ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12539                }*/
12540                else
12541                {
12542                   stmt.compound.statements = MkListOne(MkWhileStmt(MkListOne(MkExpCall(MkExpMember(expIt = MkExpIdentifier(CopyIdentifier(id)),
12543                      MkIdentifier("Next")), null)), block));
12544                }
12545                ProcessExpressionType(expIt);
12546                if(stmt.compound.declarations->first)
12547                   ProcessDeclaration(stmt.compound.declarations->first, true);
12548
12549                if(symbol)
12550                   symbol.isIterator = isMap ? 2 : ((isArray || isBuiltin) ? 3 : (isLinkList ? (isList ? 5 : 4) : (isCustomAVLTree ? 6 : 1)));
12551
12552                ProcessStatement(stmt);
12553             }
12554             else
12555                ProcessStatement(stmt.forEachStmt.stmt);
12556             if(inCompiler)
12557                curContext = stmt.compound.context.parent;
12558             break;
12559          }
12560          else
12561          {
12562             Compiler_Error($"Expression is not a container\n");
12563          }
12564          break;
12565       }
12566       case gotoStmt:
12567          break;
12568       case continueStmt:
12569          break;
12570       case breakStmt:
12571          break;
12572       case returnStmt:
12573       {
12574          Expression exp;
12575          if(stmt.expressions)
12576          {
12577             for(exp = stmt.expressions->first; exp; exp = exp.next)
12578             {
12579                if(!exp.next)
12580                {
12581                   if(curFunction && !curFunction.type)
12582                      curFunction.type = ProcessType(
12583                         curFunction.specifiers, curFunction.declarator);
12584                   FreeType(exp.destType);
12585                   // TODO: current property if not compiling
12586                   exp.destType = (curFunction && curFunction.type && curFunction.type.kind == functionType) ? curFunction.type.returnType : null;
12587                   if(exp.destType) exp.destType.refCount++;
12588                }
12589                ProcessExpressionType(exp);
12590             }
12591          }
12592          break;
12593       }
12594       case badDeclarationStmt:
12595       {
12596          ProcessDeclaration(stmt.decl, true);
12597          break;
12598       }
12599       case asmStmt:
12600       {
12601          AsmField field;
12602          if(stmt.asmStmt.inputFields)
12603          {
12604             for(field = stmt.asmStmt.inputFields->first; field; field = field.next)
12605                if(field.expression)
12606                   ProcessExpressionType(field.expression);
12607          }
12608          if(stmt.asmStmt.outputFields)
12609          {
12610             for(field = stmt.asmStmt.outputFields->first; field; field = field.next)
12611                if(field.expression)
12612                   ProcessExpressionType(field.expression);
12613          }
12614          if(stmt.asmStmt.clobberedFields)
12615          {
12616             for(field = stmt.asmStmt.clobberedFields->first; field; field = field.next)
12617             {
12618                if(field.expression)
12619                   ProcessExpressionType(field.expression);
12620             }
12621          }
12622          break;
12623       }
12624       case watchStmt:
12625       {
12626          PropertyWatch propWatch;
12627          OldList * watches = stmt._watch.watches;
12628          Expression object = stmt._watch.object;
12629          Expression watcher = stmt._watch.watcher;
12630          if(watcher)
12631             ProcessExpressionType(watcher);
12632          if(object)
12633             ProcessExpressionType(object);
12634
12635          if(inCompiler)
12636          {
12637             if(watcher || thisClass)
12638             {
12639                External external = curExternal;
12640                Context context = curContext;
12641
12642                stmt.type = expressionStmt;
12643                stmt.expressions = MkList();
12644
12645                for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12646                {
12647                   ClassFunction func;
12648                   char watcherName[1024];
12649                   Class watcherClass = watcher ?
12650                      ((watcher.expType && watcher.expType.kind == classType && watcher.expType._class) ? watcher.expType._class.registered : null) : thisClass;
12651                   External createdExternal;
12652
12653                   sprintf(watcherName,"__ecerePropertyWatcher_%d", propWatcherID++);
12654                   if(propWatch.deleteWatch)
12655                      strcat(watcherName, "_delete");
12656                   else
12657                   {
12658                      Identifier propID;
12659                      for(propID = propWatch.properties->first; propID; propID = propID.next)
12660                      {
12661                         strcat(watcherName, "_");
12662                         strcat(watcherName, propID.string);
12663                      }
12664                   }
12665
12666                   if(object && object.expType && object.expType.kind == classType && object.expType._class && object.expType._class.registered)
12667                   {
12668                      func = MkClassFunction(MkListOne(MkSpecifier(VOID)), null, MkDeclaratorFunction(MkDeclaratorIdentifier(MkIdentifier(watcherName)),
12669                         MkListOne(MkTypeName(MkListOne(MkSpecifierName(object.expType._class.string)), MkDeclaratorIdentifier(MkIdentifier("value"))))), null);
12670                      ProcessClassFunctionBody(func, propWatch.compound);
12671                      propWatch.compound = null;
12672
12673                      createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal, true);
12674
12675                      FreeClassFunction(func);
12676
12677                      curExternal = createdExternal;
12678                      ProcessFunction(createdExternal.function);
12679
12680                      if(propWatch.deleteWatch)
12681                      {
12682                         OldList * args = MkList();
12683                         ListAdd(args, CopyExpression(object));
12684                         ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12685                         ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
12686                         ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_WatchDestruction")), args));
12687                      }
12688                      else
12689                      {
12690                         Class _class = object.expType._class.registered;
12691                         Identifier propID;
12692
12693                         for(propID = propWatch.properties->first; propID; propID = propID.next)
12694                         {
12695                            char propName[1024];
12696                            Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12697                            if(prop)
12698                            {
12699                               char getName[1024], setName[1024];
12700                               OldList * args = MkList();
12701
12702                               DeclareProperty(createdExternal, prop, setName, getName);
12703
12704                               // eInstance_Watch(stmt.watch.object, prop, stmt.watch.watcher, callback);
12705                               strcpy(propName, "__ecereProp_");
12706                               FullClassNameCat(propName, prop._class.fullName, false);
12707                               strcat(propName, "_");
12708                               FullClassNameCat(propName, prop.name, true);
12709
12710                               ListAdd(args, CopyExpression(object));
12711                               ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12712                               ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12713                               ListAdd(args, MkExpCast(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpIdentifier(MkIdentifier(watcherName))));
12714
12715                               ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_Watch")), args));
12716
12717                               external.CreateUniqueEdge(createdExternal, true);
12718                            }
12719                            else
12720                               Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12721                         }
12722                      }
12723                   }
12724                   else
12725                      Compiler_Error($"Invalid watched object\n");
12726                }
12727
12728                curExternal = external;
12729                curContext = context;
12730
12731                if(watcher)
12732                   FreeExpression(watcher);
12733                if(object)
12734                   FreeExpression(object);
12735                FreeList(watches, FreePropertyWatch);
12736             }
12737             else
12738                Compiler_Error($"No observer specified and not inside a class\n");
12739          }
12740          else
12741          {
12742             for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12743             {
12744                ProcessStatement(propWatch.compound);
12745             }
12746
12747          }
12748          break;
12749       }
12750       case fireWatchersStmt:
12751       {
12752          OldList * watches = stmt._watch.watches;
12753          Expression object = stmt._watch.object;
12754          Class _class;
12755          // DEBUGGER BUG: Why doesn't watches evaluate to null??
12756          // printf("%X\n", watches);
12757          // printf("%X\n", stmt._watch.watches);
12758          if(object)
12759             ProcessExpressionType(object);
12760
12761          if(inCompiler)
12762          {
12763             _class = object ?
12764                   ((object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null) : thisClass;
12765
12766             if(_class)
12767             {
12768                Identifier propID;
12769
12770                stmt.type = expressionStmt;
12771                stmt.expressions = MkList();
12772
12773                // Check if we're inside a property set
12774                if(!watches && curFunction.propSet && (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
12775                {
12776                   watches = MkListOne(MkIdentifier(curFunction.propSet.string));
12777                }
12778                else if(!watches)
12779                {
12780                   //Compiler_Error($"No property specified and not inside a property set\n");
12781                }
12782                if(watches)
12783                {
12784                   for(propID = watches->first; propID; propID = propID.next)
12785                   {
12786                      Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12787                      if(prop)
12788                      {
12789                         CreateFireWatcher(prop, object, stmt);
12790                      }
12791                      else
12792                         Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12793                   }
12794                }
12795                else
12796                {
12797                   // Fire all properties!
12798                   Property prop;
12799                   Class base;
12800                   for(base = _class; base; base = base.base)
12801                   {
12802                      for(prop = base.membersAndProperties.first; prop; prop = prop.next)
12803                      {
12804                         if(prop.isProperty && prop.isWatchable)
12805                         {
12806                            CreateFireWatcher(prop, object, stmt);
12807                         }
12808                      }
12809                   }
12810                }
12811
12812                if(object)
12813                   FreeExpression(object);
12814                FreeList(watches, FreeIdentifier);
12815             }
12816             else
12817                Compiler_Error($"Invalid object specified and not inside a class\n");
12818          }
12819          break;
12820       }
12821       case stopWatchingStmt:
12822       {
12823          OldList * watches = stmt._watch.watches;
12824          Expression object = stmt._watch.object;
12825          Expression watcher = stmt._watch.watcher;
12826          Class _class;
12827          if(object)
12828             ProcessExpressionType(object);
12829          if(watcher)
12830             ProcessExpressionType(watcher);
12831          if(inCompiler)
12832          {
12833             _class = (object && object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null;
12834
12835             if(watcher || thisClass)
12836             {
12837                if(_class)
12838                {
12839                   Identifier propID;
12840
12841                   stmt.type = expressionStmt;
12842                   stmt.expressions = MkList();
12843
12844                   if(!watches)
12845                   {
12846                      OldList * args;
12847                      // eInstance_StopWatching(object, null, watcher);
12848                      args = MkList();
12849                      ListAdd(args, CopyExpression(object));
12850                      ListAdd(args, MkExpConstant("0"));
12851                      ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12852                      ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12853                   }
12854                   else
12855                   {
12856                      for(propID = watches->first; propID; propID = propID.next)
12857                      {
12858                         char propName[1024];
12859                         Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12860                         if(prop)
12861                         {
12862                            char getName[1024], setName[1024];
12863                            OldList * args = MkList();
12864
12865                            DeclareProperty(curExternal, prop, setName, getName);
12866
12867                            // eInstance_StopWatching(object, prop, watcher);
12868                            strcpy(propName, "__ecereProp_");
12869                            FullClassNameCat(propName, prop._class.fullName, false);
12870                            strcat(propName, "_");
12871                            FullClassNameCat(propName, prop.name, true);
12872
12873                            ListAdd(args, CopyExpression(object));
12874                            ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12875                            ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12876                            ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12877                         }
12878                         else
12879                            Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12880                      }
12881                   }
12882
12883                   if(object)
12884                      FreeExpression(object);
12885                   if(watcher)
12886                      FreeExpression(watcher);
12887                   FreeList(watches, FreeIdentifier);
12888                }
12889                else
12890                   Compiler_Error($"Invalid object specified and not inside a class\n");
12891             }
12892             else
12893                Compiler_Error($"No observer specified and not inside a class\n");
12894          }
12895          break;
12896       }
12897    }
12898 }
12899
12900 static void ProcessFunction(FunctionDefinition function)
12901 {
12902    Identifier id = GetDeclId(function.declarator);
12903    Symbol symbol = function.declarator ? function.declarator.symbol : null;
12904    Type type = symbol ? symbol.type : null;
12905    Class oldThisClass = thisClass;
12906    Context oldTopContext = topContext;
12907
12908    yylloc = function.loc;
12909    // Process thisClass
12910
12911    if(type && type.thisClass)
12912    {
12913       Symbol classSym = type.thisClass;
12914       Class _class = type.thisClass.registered;
12915       char className[1024];
12916       char structName[1024];
12917       Declarator funcDecl;
12918       Symbol thisSymbol;
12919
12920       bool typedObject = false;
12921
12922       if(_class && !_class.base)
12923       {
12924          _class = currentClass;
12925          if(_class && !_class.symbol)
12926             _class.symbol = FindClass(_class.fullName);
12927          classSym = _class ? _class.symbol : null;
12928          typedObject = true;
12929       }
12930
12931       thisClass = _class;
12932
12933       if(inCompiler && _class)
12934       {
12935          if(type.kind == functionType)
12936          {
12937             if(symbol.type.params.count == 1 && ((Type)symbol.type.params.first).kind == voidType)
12938             {
12939                //TypeName param = symbol.type.params.first;
12940                Type param = symbol.type.params.first;
12941                symbol.type.params.Remove(param);
12942                //FreeTypeName(param);
12943                FreeType(param);
12944             }
12945             if(type.classObjectType != classPointer)
12946             {
12947                symbol.type.params.Insert(null, MkClassType(_class.fullName));
12948                symbol.type.staticMethod = true;
12949                symbol.type.thisClass = null;
12950
12951                // HIGH DANGER: VERIFYING THIS...
12952                symbol.type.extraParam = false;
12953             }
12954          }
12955
12956          strcpy(className, "__ecereClass_");
12957          FullClassNameCat(className, _class.fullName, true);
12958
12959          structName[0] = 0;
12960          FullClassNameCat(structName, _class.fullName, false);
12961
12962          // [class] this
12963          funcDecl = GetFuncDecl(function.declarator);
12964          if(funcDecl)
12965          {
12966             if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12967             {
12968                TypeName param = funcDecl.function.parameters->first;
12969                if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12970                {
12971                   funcDecl.function.parameters->Remove(param);
12972                   FreeTypeName(param);
12973                }
12974             }
12975
12976             if(!function.propertyNoThis)
12977             {
12978                TypeName thisParam = null;
12979
12980                if(type.classObjectType != classPointer)
12981                {
12982                   thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12983                   if(!funcDecl.function.parameters)
12984                      funcDecl.function.parameters = MkList();
12985                   funcDecl.function.parameters->Insert(null, thisParam);
12986                }
12987
12988                if(typedObject)
12989                {
12990                   if(type.classObjectType != classPointer)
12991                   {
12992                      if(type.byReference || _class.type == unitClass || _class.type == systemClass || _class.type == enumClass || _class.type == bitClass)
12993                         thisParam.declarator = MkDeclaratorPointer(MkPointer(null,null), thisParam.declarator);
12994                   }
12995
12996                   thisParam = TypeName
12997                   {
12998                      declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
12999                      qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
13000                   };
13001                   DeclareStruct(curExternal, "ecere::com::Class", false, true);
13002                   funcDecl.function.parameters->Insert(null, thisParam);
13003                }
13004             }
13005          }
13006
13007          if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
13008          {
13009             InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
13010             funcDecl = GetFuncDecl(initDecl.declarator);
13011             if(funcDecl)
13012             {
13013                if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
13014                {
13015                   TypeName param = funcDecl.function.parameters->first;
13016                   if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
13017                   {
13018                      funcDecl.function.parameters->Remove(param);
13019                      FreeTypeName(param);
13020                   }
13021                }
13022
13023                if(type.classObjectType != classPointer)
13024                {
13025                   if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
13026                   {
13027                      TypeName thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
13028
13029                      if(!funcDecl.function.parameters)
13030                         funcDecl.function.parameters = MkList();
13031                      funcDecl.function.parameters->Insert(null, thisParam);
13032                   }
13033                }
13034             }
13035          }
13036       }
13037
13038       // Add this to the context
13039       if(function.body)
13040       {
13041          if(type.classObjectType != classPointer)
13042          {
13043             thisSymbol = Symbol
13044             {
13045                string = CopyString("this");
13046                type = classSym ? MkClassType(classSym.string) : null;
13047             };
13048             function.body.compound.context.symbols.Add((BTNode)thisSymbol);
13049
13050             if(typedObject && thisSymbol.type)
13051             {
13052                thisSymbol.type.classObjectType = ClassObjectType::typedObject;
13053                thisSymbol.type.byReference = type.byReference;
13054                thisSymbol.type.typedByReference = type.byReference;
13055             }
13056          }
13057       }
13058
13059       // Pointer to class data
13060       if(inCompiler && _class && _class.type == normalClass && type.classObjectType != classPointer)
13061       {
13062          DataMember member = null;
13063          {
13064             Class base;
13065             for(base = _class; base && base.type != systemClass; base = base.next)
13066             {
13067                for(member = base.membersAndProperties.first; member; member = member.next)
13068                   if(!member.isProperty)
13069                      break;
13070                if(member)
13071                   break;
13072             }
13073          }
13074          for(member = _class.membersAndProperties.first; member; member = member.next)
13075             if(!member.isProperty)
13076                break;
13077          if(member)
13078          {
13079             char pointerName[1024];
13080
13081             Declaration decl;
13082             Initializer initializer;
13083             Expression exp, bytePtr;
13084
13085             strcpy(pointerName, "__ecerePointer_");
13086             FullClassNameCat(pointerName, _class.fullName, false);
13087             {
13088                char className[1024];
13089                strcpy(className, "__ecereClass_");
13090                FullClassNameCat(className, classSym.string, true);
13091
13092                DeclareClass(curExternal, classSym, className);
13093             }
13094
13095             // ((byte *) this)
13096             bytePtr = QBrackets(MkExpCast(QMkType("char", QMkPtrDecl(null)), QMkExpId("this")));
13097
13098             if(_class.fixed)
13099             {
13100                Expression e;
13101                if(_class.offset && _class.offset == _class.base.structSize)
13102                {
13103                   e = MkExpClassSize(MkSpecifierName(_class.base.fullName));
13104                   ProcessExpressionType(e);
13105                }
13106                else
13107                {
13108                   char string[256];
13109                   sprintf(string, "%d", _class.offset);  // Need Bootstrap Fix
13110                   e = MkExpConstant(string);
13111                }
13112                exp = QBrackets(MkExpOp(bytePtr, '+', e));
13113             }
13114             else
13115             {
13116                // ([bytePtr] + [className]->offset)
13117                exp = QBrackets(MkExpOp(bytePtr, '+',
13118                   MkExpPointer(QMkExpId(className), MkIdentifier("offset"))));
13119             }
13120
13121             // (this ? [exp] : 0)
13122             exp = QBrackets(QMkExpCond(QMkExpId("this"), exp, MkExpConstant("0")));
13123             exp.expType = Type
13124             {
13125                refCount = 1;
13126                kind = pointerType;
13127                type = Type { refCount = 1, kind = voidType };
13128             };
13129
13130             if(function.body)
13131             {
13132                yylloc = function.body.loc;
13133                // ([structName] *) [exp]
13134                // initializer = MkInitializerAssignment(MkExpCast(QMkType(structName, QMkPtrDecl(null)), exp));
13135                initializer = MkInitializerAssignment(
13136                   MkExpCast(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)), exp));
13137
13138                // [structName] * [pointerName] = [initializer];
13139                // decl = QMkDeclaration(structName, MkInitDeclarator(QMkPtrDecl(pointerName), initializer));
13140
13141                {
13142                   Context prevContext = curContext;
13143                   OldList * list;
13144                   curContext = function.body.compound.context;
13145
13146                   decl = MkDeclaration((list = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null))),
13147                      MkListOne(MkInitDeclarator(QMkPtrDecl(pointerName), initializer)));
13148                   list->Insert(null, MkSpecifierExtended(MkExtDeclAttrib(MkAttrib(ATTRIB, MkListOne(MkAttribute(CopyString("unused"), null))))));
13149
13150                   curContext = prevContext;
13151                }
13152
13153                // WHY?
13154                decl.symbol = null;
13155
13156                if(!function.body.compound.declarations)
13157                   function.body.compound.declarations = MkList();
13158                function.body.compound.declarations->Insert(null, decl);
13159             }
13160          }
13161       }
13162
13163
13164       // Loop through the function and replace undeclared identifiers
13165       // which are a member of the class (methods, properties or data)
13166       // by "this.[member]"
13167    }
13168    else
13169       thisClass = null;
13170
13171    if(id)
13172    {
13173       FreeSpecifier(id._class);
13174       id._class = null;
13175
13176       if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
13177       {
13178          InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
13179          id = GetDeclId(initDecl.declarator);
13180
13181          FreeSpecifier(id._class);
13182          id._class = null;
13183       }
13184    }
13185    if(function.body)
13186       topContext = function.body.compound.context;
13187    {
13188       FunctionDefinition oldFunction = curFunction;
13189       curFunction = function;
13190       if(function.body)
13191          ProcessStatement(function.body);
13192
13193       // If this is a property set and no firewatchers has been done yet, add one here
13194       if(inCompiler && function.propSet && !function.propSet.fireWatchersDone)
13195       {
13196          Statement prevCompound = curCompound;
13197          Context prevContext = curContext;
13198
13199          Statement fireWatchers = MkFireWatchersStmt(null, null);
13200          if(!function.body.compound.statements) function.body.compound.statements = MkList();
13201          ListAdd(function.body.compound.statements, fireWatchers);
13202
13203          curCompound = function.body;
13204          curContext = function.body.compound.context;
13205
13206          ProcessStatement(fireWatchers);
13207
13208          curContext = prevContext;
13209          curCompound = prevCompound;
13210
13211       }
13212
13213       curFunction = oldFunction;
13214    }
13215
13216    if(function.declarator)
13217    {
13218       ProcessDeclarator(function.declarator, true);
13219    }
13220
13221    topContext = oldTopContext;
13222    thisClass = oldThisClass;
13223 }
13224
13225 /////////// INSTANTIATIONS / DATA TYPES PASS /////////////////////////////////////////////
13226 static void ProcessClass(OldList definitions, Symbol symbol)
13227 {
13228    ClassDef def;
13229    External external = curExternal;
13230    Class regClass = symbol ? symbol.registered : null;
13231
13232    // Process all functions
13233    for(def = definitions.first; def; def = def.next)
13234    {
13235       if(def.type == functionClassDef)
13236       {
13237          if(def.function.declarator)
13238             curExternal = def.function.declarator.symbol.pointerExternal;
13239          else
13240             curExternal = external;
13241
13242          ProcessFunction((FunctionDefinition)def.function);
13243       }
13244       else if(def.type == declarationClassDef)
13245       {
13246          if(def.decl.type == instDeclaration)
13247          {
13248             thisClass = regClass;
13249             ProcessInstantiationType(def.decl.inst);
13250             thisClass = null;
13251          }
13252          // Testing this
13253          else
13254          {
13255             Class backThisClass = thisClass;
13256             if(regClass) thisClass = regClass;
13257             ProcessDeclaration(def.decl, symbol ? true : false);
13258             thisClass = backThisClass;
13259          }
13260       }
13261       else if(def.type == defaultPropertiesClassDef && def.defProperties)
13262       {
13263          MemberInit defProperty;
13264
13265          // Add this to the context
13266          Symbol thisSymbol = Symbol
13267          {
13268             string = CopyString("this");
13269             type = regClass ? MkClassType(regClass.fullName) : null;
13270          };
13271          globalContext.symbols.Add((BTNode)thisSymbol);
13272
13273          for(defProperty = def.defProperties->first; defProperty; defProperty = defProperty.next)
13274          {
13275             thisClass = regClass;
13276             ProcessMemberInitData(defProperty, regClass, null, null, null, null);
13277             thisClass = null;
13278          }
13279
13280          globalContext.symbols.Remove((BTNode)thisSymbol);
13281          FreeSymbol(thisSymbol);
13282       }
13283       else if(def.type == propertyClassDef && def.propertyDef)
13284       {
13285          PropertyDef prop = def.propertyDef;
13286
13287          // Add this to the context
13288          thisClass = regClass;
13289          if(prop.setStmt)
13290          {
13291             if(regClass)
13292             {
13293                Symbol thisSymbol
13294                {
13295                   string = CopyString("this");
13296                   type = MkClassType(regClass.fullName);
13297                };
13298                prop.setStmt.compound.context.symbols.Add((BTNode)thisSymbol);
13299             }
13300
13301             curExternal = prop.symbol ? prop.symbol.externalSet : null;
13302             ProcessStatement(prop.setStmt);
13303          }
13304          if(prop.getStmt)
13305          {
13306             if(regClass)
13307             {
13308                Symbol thisSymbol
13309                {
13310                   string = CopyString("this");
13311                   type = MkClassType(regClass.fullName);
13312                };
13313                prop.getStmt.compound.context.symbols.Add((BTNode)thisSymbol);
13314             }
13315
13316             curExternal = prop.symbol ? prop.symbol.externalGet : null;
13317             ProcessStatement(prop.getStmt);
13318          }
13319          if(prop.issetStmt)
13320          {
13321             if(regClass)
13322             {
13323                Symbol thisSymbol
13324                {
13325                   string = CopyString("this");
13326                   type = MkClassType(regClass.fullName);
13327                };
13328                prop.issetStmt.compound.context.symbols.Add((BTNode)thisSymbol);
13329             }
13330
13331             curExternal = prop.symbol ? prop.symbol.externalIsSet : null;
13332             ProcessStatement(prop.issetStmt);
13333          }
13334
13335          thisClass = null;
13336       }
13337       else if(def.type == propertyWatchClassDef && def.propertyWatch)
13338       {
13339          PropertyWatch propertyWatch = def.propertyWatch;
13340
13341          thisClass = regClass;
13342          if(propertyWatch.compound)
13343          {
13344             Symbol thisSymbol
13345             {
13346                string = CopyString("this");
13347                type = regClass ? MkClassType(regClass.fullName) : null;
13348             };
13349
13350             propertyWatch.compound.compound.context.symbols.Add((BTNode)thisSymbol);
13351
13352             curExternal = null;
13353             ProcessStatement(propertyWatch.compound);
13354          }
13355          thisClass = null;
13356       }
13357    }
13358 }
13359
13360 void DeclareFunctionUtil(External neededBy, const String s)
13361 {
13362    GlobalFunction function = eSystem_FindFunction(privateModule, s);
13363    if(function)
13364    {
13365       char name[1024];
13366       name[0] = 0;
13367       if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
13368          strcpy(name, "__ecereFunction_");
13369       FullClassNameCat(name, s, false); // Why is this using FullClassNameCat ?
13370       DeclareFunction(neededBy, function, name);
13371    }
13372    else if(neededBy)
13373       FindSymbol(s, globalContext, globalContext, false, false);
13374 }
13375
13376 bool reachedPass15;
13377
13378 void ComputeDataTypes()
13379 {
13380    External external;
13381
13382    currentClass = null;
13383
13384    containerClass = eSystem_FindClass(GetPrivateModule(), "Container");
13385
13386    DeclareStruct(null, "ecere::com::Class", false, true);
13387    DeclareStruct(null, "ecere::com::Instance", false, true);
13388    DeclareStruct(null, "ecere::com::Property", false, true);
13389    DeclareStruct(null, "ecere::com::DataMember", false, true);
13390    DeclareStruct(null, "ecere::com::Method", false, true);
13391    DeclareStruct(null, "ecere::com::SerialBuffer", false, true);
13392    DeclareStruct(null, "ecere::com::ClassTemplateArgument", false, true);
13393
13394    DeclareFunctionUtil(null, "eSystem_New");
13395    DeclareFunctionUtil(null, "eSystem_New0");
13396    DeclareFunctionUtil(null, "eSystem_Renew");
13397    DeclareFunctionUtil(null, "eSystem_Renew0");
13398    DeclareFunctionUtil(null, "eSystem_Delete");
13399    DeclareFunctionUtil(null, "eClass_GetProperty");
13400    DeclareFunctionUtil(null, "eClass_SetProperty");
13401    DeclareFunctionUtil(null, "eInstance_FireSelfWatchers");
13402    DeclareFunctionUtil(null, "eInstance_SetMethod");
13403    DeclareFunctionUtil(null, "eInstance_IncRef");
13404    DeclareFunctionUtil(null, "eInstance_StopWatching");
13405    DeclareFunctionUtil(null, "eInstance_Watch");
13406    DeclareFunctionUtil(null, "eInstance_FireWatchers");
13407    reachedPass15 = true;
13408
13409    for(external = ast->first; external; external = external.next)
13410    {
13411       afterExternal = curExternal = external;
13412       if(external.type == functionExternal)
13413       {
13414          if(memoryGuard)
13415          {
13416             DeclareFunctionUtil(external, "MemoryGuard_PushLoc");
13417             DeclareFunctionUtil(external, "MemoryGuard_PopLoc");
13418          }
13419
13420          currentClass = external.function._class;
13421          ProcessFunction(external.function);
13422       }
13423       // There shouldn't be any _class member access here anyways...
13424       else if(external.type == declarationExternal)
13425       {
13426          if(memoryGuard && external.declaration && external.declaration.type == instDeclaration)
13427          {
13428             DeclareFunctionUtil(external, "MemoryGuard_PushLoc");
13429             DeclareFunctionUtil(external, "MemoryGuard_PopLoc");
13430          }
13431
13432          currentClass = null;
13433          if(external.declaration)
13434             ProcessDeclaration(external.declaration, true);
13435       }
13436       else if(external.type == classExternal)
13437       {
13438          ClassDefinition _class = external._class;
13439          currentClass = external.symbol.registered;
13440          if(memoryGuard)
13441          {
13442             DeclareFunctionUtil(external, "MemoryGuard_PushLoc");
13443             DeclareFunctionUtil(external, "MemoryGuard_PopLoc");
13444          }
13445          if(_class.definitions)
13446          {
13447             ProcessClass(_class.definitions, _class.symbol);
13448          }
13449          if(inCompiler)
13450          {
13451             // Free class data...
13452             ast->Remove(external);
13453             delete external;
13454          }
13455       }
13456       else if(external.type == nameSpaceExternal)
13457       {
13458          thisNameSpace = external.id.string;
13459       }
13460    }
13461    currentClass = null;
13462    thisNameSpace = null;
13463    curExternal = null;
13464 }