compiler/libec; eda, extras: const fixes for DB apps
[sdk] / compiler / libec / src / pass15.ec
1 import "ecdefs"
2
3 #define uint _uint
4 #include <stdlib.h>  // For strtoll
5 #undef uint
6
7 // UNTIL IMPLEMENTED IN GRAMMAR
8 #define ACCESS_CLASSDATA(_class, baseClass) \
9    (_class ? ((void *)(((char *)_class.data) + baseClass.offsetClass)) : null)
10
11 #define YYLTYPE Location
12 #include "grammar.h"
13
14 extern OldList * ast;
15 extern int returnCode;
16 extern Expression parsedExpression;
17 extern bool yydebug;
18 public void SetYydebug(bool b) { yydebug = b; }
19 extern bool echoOn;
20
21 void resetScanner();
22
23 // TODO: Reset this to 0 on reinitialization
24 int propWatcherID;
25
26 int expression_yyparse();
27 static Statement curCompound;
28 External curExternal, afterExternal;
29 static Type curSwitchType;
30 static Class currentClass;
31 Class thisClass;
32 public void SetThisClass(Class c) { thisClass = c; } public Class GetThisClass() { return thisClass; }
33 static char * thisNameSpace;
34 /*static */Class containerClass;
35 bool thisClassParams = true;
36
37 uint internalValueCounter;
38
39 #ifdef _DEBUG
40 Time findSymbolTotalTime;
41 #endif
42
43 // WARNING: PrintExpression CONCATENATES to string. Please initialize.
44 /*static */public void PrintExpression(Expression exp, char * string)
45 {
46    //if(inCompiler)
47    {
48       TempFile f { };
49       int count;
50       bool backOutputLineNumbers = outputLineNumbers;
51       outputLineNumbers = false;
52
53       if(exp)
54          OutputExpression(exp, f);
55       f.Seek(0, start);
56       count = strlen(string);
57       count += f.Read(string + count, 1, 1023);
58       string[count] = '\0';
59       delete f;
60
61       outputLineNumbers = backOutputLineNumbers;
62    }
63 }
64
65 Type ProcessTemplateParameterType(TemplateParameter param)
66 {
67    if(param && param.type == TemplateParameterType::type && (param.dataType || param.dataTypeString))
68    {
69       // TOFIX: Will need to free this Type
70       if(!param.baseType)
71       {
72          if(param.dataTypeString)
73             param.baseType = ProcessTypeString(param.dataTypeString, false);
74          else
75             param.baseType = ProcessType(param.dataType.specifiers, param.dataType.decl);
76       }
77       return param.baseType;
78    }
79    return null;
80 }
81
82 bool NeedCast(Type type1, Type type2)
83 {
84    if(!type1 || !type2 || type1.keepCast || type2.keepCast) return true;
85
86    if(type1.kind == templateType && type2.kind == int64Type && type2.passAsTemplate == false)
87    {
88       return false;
89    }
90
91    if(type1.kind == type2.kind)
92    {
93       switch(type1.kind)
94       {
95          case _BoolType:
96          case charType:
97          case shortType:
98          case intType:
99          case int64Type:
100          case intPtrType:
101          case intSizeType:
102             if(type1.passAsTemplate && !type2.passAsTemplate)
103                return true;
104             return type1.isSigned != type2.isSigned;
105          case classType:
106             return type1._class != type2._class;
107          case pointerType:
108             return (type1.type && type2.type && type1.type.constant != type2.type.constant) || NeedCast(type1.type, type2.type);
109          default:
110             return true; //false; ????
111       }
112    }
113    return true;
114 }
115
116 static void ReplaceClassMembers(Expression exp, Class _class)
117 {
118    if(exp.type == identifierExp && exp.identifier)
119    {
120       Identifier id = exp.identifier;
121       Context ctx;
122       Symbol symbol = null;
123       if(!id._class || !id._class.name || strcmp(id._class.name, "property"))
124       {
125          // First, check if the identifier is declared inside the function
126          for(ctx = curContext; ctx != topContext.parent && !symbol; ctx = ctx.parent)
127          {
128             symbol = (Symbol)ctx.symbols.FindString(id.string);
129             if(symbol) break;
130          }
131       }
132
133       // If it is not, check if it is a member of the _class
134       if(!symbol && ((!id._class || (id._class.name && !strcmp(id._class.name, "property"))) || (id.classSym && eClass_IsDerived(_class, id.classSym.registered))))
135       {
136          Property prop = eClass_FindProperty(_class, id.string, privateModule);
137          Method method = null;
138          DataMember member = null;
139          ClassProperty classProp = null;
140          if(!prop)
141          {
142             method = eClass_FindMethod(_class, id.string, privateModule);
143          }
144          if(!prop && !method)
145             member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
146          if(!prop && !method && !member)
147          {
148             classProp = eClass_FindClassProperty(_class, id.string);
149          }
150          if(prop || method || member || classProp)
151          {
152             // Replace by this.[member]
153             exp.type = memberExp;
154             exp.member.member = id;
155             exp.member.memberType = unresolvedMember;
156             exp.member.exp = QMkExpId("this");
157             //exp.member.exp.loc = exp.loc;
158             exp.addedThis = true;
159          }
160          else if(_class && _class.templateParams.first)
161          {
162             Class sClass;
163             for(sClass = _class; sClass; sClass = sClass.base)
164             {
165                if(sClass.templateParams.first)
166                {
167                   ClassTemplateParameter param;
168                   for(param = sClass.templateParams.first; param; param = param.next)
169                   {
170                      if(param.type == expression && !strcmp(param.name, id.string))
171                      {
172                         Expression argExp = GetTemplateArgExpByName(param.name, _class, TemplateParameterType::expression);
173
174                         if(argExp)
175                         {
176                            Declarator decl;
177                            OldList * specs = MkList();
178
179                            FreeIdentifier(exp.member.member);
180
181                            ProcessExpressionType(argExp);
182
183                            decl = SpecDeclFromString(param.dataTypeString, specs, null);
184
185                            exp.expType = ProcessType(specs, decl);
186
187                            // *[expType] *[argExp]
188                            exp.type = bracketsExp;
189                            exp.list = MkListOne(MkExpOp(null, '*',
190                               MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpOp(null, '&', argExp))));
191                         }
192                      }
193                   }
194                }
195             }
196          }
197       }
198    }
199 }
200
201 ////////////////////////////////////////////////////////////////////////
202 // PRINTING ////////////////////////////////////////////////////////////
203 ////////////////////////////////////////////////////////////////////////
204
205 public char * PrintInt(int64 result)
206 {
207    char temp[100];
208    if(result > MAXINT)
209       sprintf(temp, FORMAT64HEX /*"0x%I64XLL"*/, result);
210    else
211       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
212    if(result > MAXINT || result < MININT)
213       strcat(temp, "LL");
214    return CopyString(temp);
215 }
216
217 public char * PrintUInt(uint64 result)
218 {
219    char temp[100];
220    if(result > MAXDWORD)
221       sprintf(temp, FORMAT64HEXLL /*"0x%I64XLL"*/, result);
222    else if(result > MAXINT)
223       sprintf(temp, FORMAT64HEX /*"0x%I64X"*/, result);
224    else
225       sprintf(temp, FORMAT64D /*"%I64d"*/, result);
226    return CopyString(temp);
227 }
228
229 public char * PrintInt64(int64 result)
230 {
231    char temp[100];
232    sprintf(temp, FORMAT64DLL /*"%I64d"*/, result);
233    return CopyString(temp);
234 }
235
236 public char * PrintUInt64(uint64 result)
237 {
238    char temp[100];
239    if(result > MAXINT64)
240       sprintf(temp, FORMAT64HEXLL /*"0x%I64XLL"*/, result);
241    else
242       sprintf(temp, FORMAT64DLL /*"%I64d"*/, result);
243    return CopyString(temp);
244 }
245
246 public char * PrintHexUInt(uint64 result)
247 {
248    char temp[100];
249    if(result > MAXDWORD)
250       sprintf(temp, FORMAT64HEX /*"0x%I64xLL"*/, result);
251    else
252       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
253    if(result > MAXDWORD)
254       strcat(temp, "LL");
255    return CopyString(temp);
256 }
257
258 public char * PrintHexUInt64(uint64 result)
259 {
260    char temp[100];
261    if(result > MAXDWORD)
262       sprintf(temp, FORMAT64HEXLL /*"0x%I64xLL"*/, result);
263    else
264       sprintf(temp, FORMAT64HEX /*"0x%I64x"*/, result);
265    return CopyString(temp);
266 }
267
268 public char * PrintShort(short result)
269 {
270    char temp[100];
271    sprintf(temp, "%d", (unsigned short)result);
272    return CopyString(temp);
273 }
274
275 public char * PrintUShort(unsigned short result)
276 {
277    char temp[100];
278    if(result > 32767)
279       sprintf(temp, "0x%X", (int)result);
280    else
281       sprintf(temp, "%d", (int)result);
282    return CopyString(temp);
283 }
284
285 public char * PrintChar(char result)
286 {
287    char temp[100];
288    if(result > 0 && isprint(result))
289       sprintf(temp, "'%c'", result);
290    else if(result < 0)
291       sprintf(temp, "%d", (int)result);
292    else
293       //sprintf(temp, "%#X", result);
294       sprintf(temp, "0x%X", (unsigned char)result);
295    return CopyString(temp);
296 }
297
298 public char * PrintUChar(unsigned char result)
299 {
300    char temp[100];
301    sprintf(temp, "0x%X", result);
302    return CopyString(temp);
303 }
304
305 public char * PrintFloat(float result)
306 {
307    char temp[350];
308    if(result.isInf)
309    {
310       if(result.signBit)
311          strcpy(temp, "-inf");
312       else
313          strcpy(temp, "inf");
314    }
315    else if(result.isNan)
316    {
317       if(result.signBit)
318          strcpy(temp, "-nan");
319       else
320          strcpy(temp, "nan");
321    }
322    else
323       sprintf(temp, "%.16ff", result);
324    return CopyString(temp);
325 }
326
327 public char * PrintDouble(double result)
328 {
329    char temp[350];
330    if(result.isInf)
331    {
332       if(result.signBit)
333          strcpy(temp, "-inf");
334       else
335          strcpy(temp, "inf");
336    }
337    else if(result.isNan)
338    {
339       if(result.signBit)
340          strcpy(temp, "-nan");
341       else
342          strcpy(temp, "nan");
343    }
344    else
345       sprintf(temp, "%.16f", result);
346    return CopyString(temp);
347 }
348
349 ////////////////////////////////////////////////////////////////////////
350 ////////////////////////////////////////////////////////////////////////
351
352 //public Operand GetOperand(Expression exp);
353
354 #define GETVALUE(name, t) \
355    public bool GetOp##name(Operand op2, t * value2) \
356    {                                                        \
357       if(op2.kind == intType && op2.type.isSigned) *value2 = (t) op2.i; \
358       else if(op2.kind == intType) *value2 = (t) op2.ui;                 \
359       else if(op2.kind == int64Type && op2.type.isSigned) *value2 = (t) op2.i64; \
360       else if(op2.kind == int64Type) *value2 = (t) op2.ui64;                 \
361       else if(op2.kind == intSizeType && op2.type.isSigned) *value2 = (t) op2.i64; \
362       else if(op2.kind == intSizeType) *value2 = (t) op2.ui64; \
363       else if(op2.kind == intPtrType && op2.type.isSigned) *value2 = (t) op2.i64; \
364       else if(op2.kind == intPtrType) *value2 = (t) op2.ui64;                 \
365       else if(op2.kind == shortType && op2.type.isSigned) *value2 = (t) op2.s;   \
366       else if(op2.kind == shortType) *value2 = (t) op2.us;                        \
367       else if(op2.kind == charType && op2.type.isSigned) *value2 = (t) op2.c;    \
368       else if(op2.kind == _BoolType || op2.kind == charType) *value2 = (t) op2.uc; \
369       else if(op2.kind == floatType) *value2 = (t) op2.f;                         \
370       else if(op2.kind == doubleType) *value2 = (t) op2.d;                        \
371       else if(op2.kind == pointerType) *value2 = (t) op2.ui64;                    \
372       else                                                                          \
373          return false;                                                              \
374       return true;                                                                  \
375    } \
376    public bool Get##name(Expression exp, t * value2) \
377    {                                                        \
378       Operand op2 = GetOperand(exp);                        \
379       return GetOp##name(op2, value2); \
380    }
381
382 // To help the deubugger currently not preprocessing...
383 #define HELP(x) x
384
385 GETVALUE(Int, HELP(int));
386 GETVALUE(UInt, HELP(unsigned int));
387 GETVALUE(Int64, HELP(int64));
388 GETVALUE(UInt64, HELP(uint64));
389 GETVALUE(IntPtr, HELP(intptr));
390 GETVALUE(UIntPtr, HELP(uintptr));
391 GETVALUE(IntSize, HELP(intsize));
392 GETVALUE(UIntSize, HELP(uintsize));
393 GETVALUE(Short, HELP(short));
394 GETVALUE(UShort, HELP(unsigned short));
395 GETVALUE(Char, HELP(char));
396 GETVALUE(UChar, HELP(unsigned char));
397 GETVALUE(Float, HELP(float));
398 GETVALUE(Double, HELP(double));
399
400 void ComputeExpression(Expression exp);
401
402 void ComputeClassMembers(Class _class, bool isMember)
403 {
404    DataMember member = isMember ? (DataMember) _class : null;
405    Context context = isMember ? null : SetupTemplatesContext(_class);
406    if(member || ((_class.type == bitClass || _class.type == normalClass || _class.type == structClass || _class.type == noHeadClass) &&
407                  (_class.type == bitClass || (!_class.structSize || _class.structSize == _class.offset)) && _class.computeSize))
408    {
409       int unionMemberOffset = 0;
410       int bitFields = 0;
411
412       /*
413       if(!member && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass) && _class.memberOffset && _class.memberOffset > _class.base.structSize)
414          _class.memberOffset = (_class.base && _class.base.type != systemClass) ? _class.base.structSize : 0;
415       */
416
417       if(member)
418       {
419          member.memberOffset = 0;
420          if(targetBits < sizeof(void *) * 8)
421             member.structAlignment = 0;
422       }
423       else if(targetBits < sizeof(void *) * 8)
424          _class.structAlignment = 0;
425
426       // Confusion here: non struct classes seem to have their memberOffset restart at 0 at each hierarchy level
427       if(!member && ((_class.type == normalClass || _class.type == noHeadClass) || (_class.type == structClass && _class.memberOffset && _class.memberOffset > _class.base.structSize)))
428          _class.memberOffset = (_class.base && _class.type == structClass) ? _class.base.structSize : 0;
429
430       if(!member && _class.destructionWatchOffset)
431          _class.memberOffset += sizeof(OldList);
432
433       // To avoid reentrancy...
434       //_class.structSize = -1;
435
436       {
437          DataMember dataMember;
438          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
439          {
440             if(!dataMember.isProperty)
441             {
442                if(dataMember.type == normalMember && dataMember.dataTypeString && !dataMember.dataType)
443                {
444                   dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
445                   /*if(!dataMember.dataType)
446                      dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
447                      */
448                }
449             }
450          }
451       }
452
453       {
454          DataMember dataMember;
455          for(dataMember = member ? member.members.first : _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
456          {
457             if(!dataMember.isProperty && (dataMember.type != normalMember || dataMember.dataTypeString))
458             {
459                if(!isMember && _class.type == bitClass && dataMember.dataType)
460                {
461                   BitMember bitMember = (BitMember) dataMember;
462                   uint64 mask = 0;
463                   int d;
464
465                   ComputeTypeSize(dataMember.dataType);
466
467                   if(bitMember.pos == -1) bitMember.pos = _class.memberOffset;
468                   if(!bitMember.size) bitMember.size = dataMember.dataType.size * 8;
469
470                   _class.memberOffset = bitMember.pos + bitMember.size;
471                   for(d = 0; d<bitMember.size; d++)
472                   {
473                      if(d)
474                         mask <<= 1;
475                      mask |= 1;
476                   }
477                   bitMember.mask = mask << bitMember.pos;
478                }
479                else if(dataMember.type == normalMember && dataMember.dataType)
480                {
481                   int size;
482                   int alignment = 0;
483
484                   // Prevent infinite recursion
485                   if(dataMember.dataType.kind != classType ||
486                      ((!dataMember.dataType._class || !dataMember.dataType._class.registered || dataMember.dataType._class.registered != _class ||
487                      _class.type != structClass)))
488                      ComputeTypeSize(dataMember.dataType);
489
490                   if(dataMember.dataType.bitFieldCount)
491                   {
492                      bitFields += dataMember.dataType.bitFieldCount;
493                      size = 0;
494                   }
495                   else
496                   {
497                      if(bitFields)
498                      {
499                         int size = (bitFields + 7) / 8;
500
501                         if(isMember)
502                         {
503                            // TESTING THIS PADDING CODE
504                            if(alignment)
505                            {
506                               member.structAlignment = Max(member.structAlignment, alignment);
507
508                               if(member.memberOffset % alignment)
509                                  member.memberOffset += alignment - (member.memberOffset % alignment);
510                            }
511
512                            dataMember.offset = member.memberOffset;
513                            if(member.type == unionMember)
514                               unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
515                            else
516                            {
517                               member.memberOffset += size;
518                            }
519                         }
520                         else
521                         {
522                            // TESTING THIS PADDING CODE
523                            if(alignment)
524                            {
525                               _class.structAlignment = Max(_class.structAlignment, alignment);
526
527                               if(_class.memberOffset % alignment)
528                                  _class.memberOffset += alignment - (_class.memberOffset % alignment);
529                            }
530
531                            dataMember.offset = _class.memberOffset;
532                            _class.memberOffset += size;
533                         }
534                         bitFields = 0;
535                      }
536                      size = dataMember.dataType.size;
537                      alignment = dataMember.dataType.alignment;
538                   }
539
540                   if(isMember)
541                   {
542                      // TESTING THIS PADDING CODE
543                      if(alignment)
544                      {
545                         member.structAlignment = Max(member.structAlignment, alignment);
546
547                         if(member.memberOffset % alignment)
548                            member.memberOffset += alignment - (member.memberOffset % alignment);
549                      }
550
551                      dataMember.offset = member.memberOffset;
552                      if(member.type == unionMember)
553                         unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
554                      else
555                      {
556                         member.memberOffset += size;
557                      }
558                   }
559                   else
560                   {
561                      // TESTING THIS PADDING CODE
562                      if(alignment)
563                      {
564                         _class.structAlignment = Max(_class.structAlignment, alignment);
565
566                         if(_class.memberOffset % alignment)
567                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
568                      }
569
570                      dataMember.offset = _class.memberOffset;
571                      _class.memberOffset += size;
572                   }
573                }
574                else
575                {
576                   int alignment;
577
578                   ComputeClassMembers((Class)dataMember, true);
579                   alignment = dataMember.structAlignment;
580
581                   if(isMember)
582                   {
583                      if(alignment)
584                      {
585                         if(member.memberOffset % alignment)
586                            member.memberOffset += alignment - (member.memberOffset % alignment);
587
588                         member.structAlignment = Max(member.structAlignment, alignment);
589                      }
590                      dataMember.offset = member.memberOffset;
591                      if(member.type == unionMember)
592                         unionMemberOffset = Max(unionMemberOffset, dataMember.memberOffset);
593                      else
594                         member.memberOffset += dataMember.memberOffset;
595                   }
596                   else
597                   {
598                      if(alignment)
599                      {
600                         if(_class.memberOffset % alignment)
601                            _class.memberOffset += alignment - (_class.memberOffset % alignment);
602                         _class.structAlignment = Max(_class.structAlignment, alignment);
603                      }
604                      dataMember.offset = _class.memberOffset;
605                      _class.memberOffset += dataMember.memberOffset;
606                   }
607                }
608             }
609          }
610          if(bitFields)
611          {
612             int alignment = 0;
613             int size = (bitFields + 7) / 8;
614
615             if(isMember)
616             {
617                // TESTING THIS PADDING CODE
618                if(alignment)
619                {
620                   member.structAlignment = Max(member.structAlignment, alignment);
621
622                   if(member.memberOffset % alignment)
623                      member.memberOffset += alignment - (member.memberOffset % alignment);
624                }
625
626                if(member.type == unionMember)
627                   unionMemberOffset = Max(unionMemberOffset, dataMember.dataType.size);
628                else
629                {
630                   member.memberOffset += size;
631                }
632             }
633             else
634             {
635                // TESTING THIS PADDING CODE
636                if(alignment)
637                {
638                   _class.structAlignment = Max(_class.structAlignment, alignment);
639
640                   if(_class.memberOffset % alignment)
641                      _class.memberOffset += alignment - (_class.memberOffset % alignment);
642                }
643                _class.memberOffset += size;
644             }
645             bitFields = 0;
646          }
647       }
648       if(member && member.type == unionMember)
649       {
650          member.memberOffset = unionMemberOffset;
651       }
652
653       if(!isMember)
654       {
655          /*if(_class.type == structClass)
656             _class.size = _class.memberOffset;
657          else
658          */
659
660          if(_class.type != bitClass)
661          {
662             int extra = 0;
663             if(_class.structAlignment)
664             {
665                if(_class.memberOffset % _class.structAlignment)
666                   extra += _class.structAlignment - (_class.memberOffset % _class.structAlignment);
667             }
668             _class.structSize = (_class.base ? (_class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize) : 0) + _class.memberOffset + extra;
669             if(!member)
670             {
671                Property prop;
672                for(prop = _class.membersAndProperties.first; prop; prop = prop.next)
673                {
674                   if(prop.isProperty && prop.isWatchable)
675                   {
676                      prop.watcherOffset = _class.structSize;
677                      _class.structSize += sizeof(OldList);
678                   }
679                }
680             }
681
682             // Fix Derivatives
683             {
684                OldLink derivative;
685                for(derivative = _class.derivatives.first; derivative; derivative = derivative.next)
686                {
687                   Class deriv = derivative.data;
688
689                   if(deriv.computeSize)
690                   {
691                      // TESTING THIS NEW CODE HERE... TRYING TO FIX ScrollBar MEMBERS DEBUGGING
692                      deriv.offset = /*_class.offset + */_class.structSize;
693                      deriv.memberOffset = 0;
694                      // ----------------------
695
696                      deriv.structSize = deriv.offset;
697
698                      ComputeClassMembers(deriv, false);
699                   }
700                }
701             }
702          }
703       }
704    }
705    if(context)
706       FinishTemplatesContext(context);
707 }
708
709 public void ComputeModuleClasses(Module module)
710 {
711    Class _class;
712    OldLink subModule;
713
714    for(subModule = module.modules.first; subModule; subModule = subModule.next)
715       ComputeModuleClasses(subModule.data);
716    for(_class = module.classes.first; _class; _class = _class.next)
717       ComputeClassMembers(_class, false);
718 }
719
720
721 public int ComputeTypeSize(Type type)
722 {
723    uint size = type ? type.size : 0;
724    if(!size && type && !type.computing)
725    {
726       type.computing = true;
727       switch(type.kind)
728       {
729          case _BoolType: type.alignment = size = sizeof(char); break;   // Assuming 1 byte _Bool
730          case charType: type.alignment = size = sizeof(char); break;
731          case intType: type.alignment = size = sizeof(int); break;
732          case int64Type: type.alignment = size = sizeof(int64); break;
733          case intPtrType: type.alignment = size = targetBits / 8; break;
734          case intSizeType: type.alignment = size = targetBits / 8; break;
735          case longType: type.alignment = size = sizeof(long); break;
736          case shortType: type.alignment = size = sizeof(short); break;
737          case floatType: type.alignment = size = sizeof(float); break;
738          case doubleType: type.alignment = size = sizeof(double); break;
739          case classType:
740          {
741             Class _class = type._class ? type._class.registered : null;
742
743             if(_class && _class.type == structClass)
744             {
745                // Ensure all members are properly registered
746                ComputeClassMembers(_class, false);
747                type.alignment = _class.structAlignment;
748                size = _class.structSize;
749                if(type.alignment && size % type.alignment)
750                   size += type.alignment - (size % type.alignment);
751
752             }
753             else if(_class && (_class.type == unitClass ||
754                    _class.type == enumClass ||
755                    _class.type == bitClass))
756             {
757                if(!_class.dataType)
758                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
759                size = type.alignment = ComputeTypeSize(_class.dataType);
760             }
761             else
762                size = type.alignment = targetBits / 8; // sizeof(Instance *);
763             break;
764          }
765          case pointerType: case subClassType: size = type.alignment = targetBits / 8; /*sizeof(void *); */break;
766          case arrayType:
767             if(type.arraySizeExp)
768             {
769                ProcessExpressionType(type.arraySizeExp);
770                ComputeExpression(type.arraySizeExp);
771                if(!type.arraySizeExp.isConstant || (type.arraySizeExp.expType.kind != intType &&
772                   type.arraySizeExp.expType.kind != shortType &&
773                   type.arraySizeExp.expType.kind != charType &&
774                   type.arraySizeExp.expType.kind != longType &&
775                   type.arraySizeExp.expType.kind != int64Type &&
776                   type.arraySizeExp.expType.kind != intSizeType &&
777                   type.arraySizeExp.expType.kind != intPtrType &&
778                   type.arraySizeExp.expType.kind != enumType &&
779                   (type.arraySizeExp.expType.kind != classType || !type.arraySizeExp.expType._class.registered || type.arraySizeExp.expType._class.registered.type != enumClass)))
780                {
781                   Location oldLoc = yylloc;
782                   // bool isConstant = type.arraySizeExp.isConstant;
783                   char expression[10240];
784                   expression[0] = '\0';
785                   type.arraySizeExp.expType = null;
786                   yylloc = type.arraySizeExp.loc;
787                   if(inCompiler)
788                      PrintExpression(type.arraySizeExp, expression);
789                   Compiler_Error($"Array size not constant int (%s)\n", expression);
790                   yylloc = oldLoc;
791                }
792                GetInt(type.arraySizeExp, &type.arraySize);
793             }
794             else if(type.enumClass)
795             {
796                if(type.enumClass && type.enumClass.registered && type.enumClass.registered.type == enumClass)
797                {
798                   type.arraySize = (int)eClass_GetProperty(type.enumClass.registered, "enumSize");
799                }
800                else
801                   type.arraySize = 0;
802             }
803             else
804             {
805                // Unimplemented auto size
806                type.arraySize = 0;
807             }
808
809             size = ComputeTypeSize(type.type) * type.arraySize;
810             if(type.type)
811                type.alignment = type.type.alignment;
812
813             break;
814          case structType:
815          {
816             Type member;
817             for(member = type.members.first; member; member = member.next)
818             {
819                uint addSize = ComputeTypeSize(member);
820
821                member.offset = size;
822                if(member.alignment && size % member.alignment)
823                   member.offset += member.alignment - (size % member.alignment);
824                size = member.offset;
825
826                type.alignment = Max(type.alignment, member.alignment);
827                size += addSize;
828             }
829             if(type.alignment && size % type.alignment)
830                size += type.alignment - (size % type.alignment);
831             break;
832          }
833          case unionType:
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                type.alignment = Max(type.alignment, member.alignment);
846                size = Max(size, addSize);
847             }
848             if(type.alignment && size % type.alignment)
849                size += type.alignment - (size % type.alignment);
850             break;
851          }
852          case templateType:
853          {
854             TemplateParameter param = type.templateParameter;
855             Type baseType = ProcessTemplateParameterType(param);
856             if(baseType)
857             {
858                size = ComputeTypeSize(baseType);
859                type.alignment = baseType.alignment;
860             }
861             else
862                type.alignment = size = sizeof(uint64);
863             break;
864          }
865          case enumType:
866          {
867             type.alignment = size = sizeof(enum { test });
868             break;
869          }
870          case thisClassType:
871          {
872             type.alignment = size = targetBits / 8; //sizeof(void *);
873             break;
874          }
875       }
876       type.size = size;
877       type.computing = false;
878    }
879    return size;
880 }
881
882
883 /*static */int AddMembers(OldList * declarations, Class _class, bool isMember, uint * retSize, Class topClass, bool *addedPadding)
884 {
885    // This function is in need of a major review when implementing private members etc.
886    DataMember topMember = isMember ? (DataMember) _class : null;
887    uint totalSize = 0;
888    uint maxSize = 0;
889    int alignment;
890    uint size;
891    DataMember member;
892    Context context = isMember ? null : SetupTemplatesContext(_class);
893    if(addedPadding)
894       *addedPadding = false;
895
896    if(!isMember && _class.base)
897    {
898       maxSize = _class.structSize;
899       //if(_class.base.type != systemClass) // Commented out with new Instance _class
900       {
901          // DANGER: Testing this noHeadClass here...
902          if(_class.type == structClass || _class.type == noHeadClass)
903             /*totalSize = */AddMembers(declarations, _class.base, false, &totalSize, topClass, null);
904          else
905          {
906             uint baseSize = _class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize;
907             if(maxSize > baseSize)
908                maxSize -= baseSize;
909             else
910                maxSize = 0;
911          }
912       }
913    }
914
915    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
916    {
917       if(!member.isProperty)
918       {
919          switch(member.type)
920          {
921             case normalMember:
922             {
923                if(member.dataTypeString)
924                {
925                   OldList * specs = MkList(), * decls = MkList();
926                   Declarator decl;
927
928                   decl = SpecDeclFromString(member.dataTypeString, specs,
929                      MkDeclaratorIdentifier(MkIdentifier(member.name)));
930                   ListAdd(decls, MkStructDeclarator(decl, null));
931                   ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, decls, null)));
932
933                   if(!member.dataType)
934                      member.dataType = ProcessType(specs, decl);
935
936                   ReplaceThisClassSpecifiers(specs, topClass /*member._class*/);
937
938                   {
939                      Type type = ProcessType(specs, decl);
940                      DeclareType(member.dataType, false, false);
941                      FreeType(type);
942                   }
943                   /*
944                   if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
945                      member.dataType._class.registered && member.dataType._class.registered.type == structClass)
946                      DeclareStruct(member.dataType._class.string, false);
947                   */
948
949                   ComputeTypeSize(member.dataType);
950                   size = member.dataType.size;
951                   alignment = member.dataType.alignment;
952
953                   if(alignment)
954                   {
955                      if(totalSize % alignment)
956                         totalSize += alignment - (totalSize % alignment);
957                   }
958                   totalSize += size;
959                }
960                break;
961             }
962             case unionMember:
963             case structMember:
964             {
965                OldList * specs = MkList(), * list = MkList();
966
967                size = 0;
968                AddMembers(list, (Class)member, true, &size, topClass, null);
969                ListAdd(specs,
970                   MkStructOrUnion((member.type == unionMember)?unionSpecifier:structSpecifier, null, list));
971                ListAdd(declarations, MkClassDefDeclaration(MkStructDeclaration(specs, null, null)));
972                alignment = member.structAlignment;
973
974                if(alignment)
975                {
976                   if(totalSize % alignment)
977                      totalSize += alignment - (totalSize % alignment);
978                }
979                totalSize += size;
980                break;
981             }
982          }
983       }
984    }
985    if(retSize)
986    {
987       if(topMember && topMember.type == unionMember)
988          *retSize = Max(*retSize, totalSize);
989       else
990          *retSize += totalSize;
991    }
992    else if(totalSize < maxSize && _class.type != systemClass)
993    {
994       int autoPadding = 0;
995       if(!isMember && _class.structAlignment && totalSize % _class.structAlignment)
996          autoPadding = _class.structAlignment - (totalSize % _class.structAlignment);
997       if(totalSize + autoPadding < maxSize)
998       {
999          char sizeString[50];
1000          sprintf(sizeString, "%d", maxSize - totalSize);
1001          ListAdd(declarations,
1002             MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(CHAR)),
1003             MkListOne(MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__ecere_padding")), MkExpConstant(sizeString))), null)));
1004          if(addedPadding)
1005             *addedPadding = true;
1006       }
1007    }
1008    if(context)
1009       FinishTemplatesContext(context);
1010    return topMember ? topMember.memberID : _class.memberID;
1011 }
1012
1013 static int DeclareMembers(Class _class, bool isMember)
1014 {
1015    DataMember topMember = isMember ? (DataMember) _class : null;
1016    DataMember member;
1017    Context context = isMember ? null : SetupTemplatesContext(_class);
1018
1019    if(!isMember && (_class.type == structClass || _class.type == noHeadClass) && _class.base.type != systemClass)
1020       DeclareMembers(_class.base, false);
1021
1022    for(member = isMember ? topMember.members.first : _class.membersAndProperties.first; member; member = member.next)
1023    {
1024       if(!member.isProperty)
1025       {
1026          switch(member.type)
1027          {
1028             case normalMember:
1029             {
1030                /*
1031                if(member.dataType && member.dataType.kind == classType && member.dataType._class &&
1032                   member.dataType._class.registered && member.dataType._class.registered.type == structClass)
1033                   DeclareStruct(member.dataType._class.string, false);
1034                   */
1035                if(!member.dataType && member.dataTypeString)
1036                   member.dataType = ProcessTypeString(member.dataTypeString, false);
1037                if(member.dataType)
1038                   DeclareType(member.dataType, false, false);
1039                break;
1040             }
1041             case unionMember:
1042             case structMember:
1043             {
1044                DeclareMembers((Class)member, true);
1045                break;
1046             }
1047          }
1048       }
1049    }
1050    if(context)
1051       FinishTemplatesContext(context);
1052
1053    return topMember ? topMember.memberID : _class.memberID;
1054 }
1055
1056 void DeclareStruct(const char * name, bool skipNoHead)
1057 {
1058    External external = null;
1059    Symbol classSym = FindClass(name);
1060
1061    if(!inCompiler || !classSym) return;
1062
1063    // We don't need any declaration for bit classes...
1064    if(classSym.registered &&
1065       (classSym.registered.type == bitClass || classSym.registered.type == unitClass || classSym.registered.type == enumClass))
1066       return;
1067
1068    /*if(classSym.registered.templateClass)
1069       return DeclareStruct(classSym.registered.templateClass.fullName, skipNoHead);
1070    */
1071
1072    if(classSym.registered && classSym.imported && !classSym.declaredStructSym)
1073    {
1074       // Add typedef struct
1075       Declaration decl;
1076       OldList * specifiers, * declarators;
1077       OldList * declarations = null;
1078       char structName[1024];
1079       Specifier spec = null;
1080       external = (classSym.registered && classSym.registered.type == structClass) ?
1081          classSym.pointerExternal : classSym.structExternal;
1082
1083       // TEMPORARY HACK: Pass 3 will move up struct declarations without moving members
1084       // Moved this one up because DeclareClass done later will need it
1085
1086       classSym.declaring++;
1087
1088       if(strchr(classSym.string, '<'))
1089       {
1090          if(classSym.registered.templateClass)
1091          {
1092             DeclareStruct(classSym.registered.templateClass.fullName, skipNoHead);
1093             classSym.declaring--;
1094          }
1095          return;
1096       }
1097
1098       //if(!skipNoHead)
1099          DeclareMembers(classSym.registered, false);
1100
1101       structName[0] = 0;
1102       FullClassNameCat(structName, name, false);
1103
1104       if(external && external.declaration && external.declaration.specifiers)
1105       {
1106          for(spec = external.declaration.specifiers->first; spec; spec = spec.next)
1107          {
1108             if(spec.type == structSpecifier || spec.type == unionSpecifier)
1109                break;
1110          }
1111       }
1112
1113       /*if(!external)
1114          external = MkExternalDeclaration(null);*/
1115
1116       if(!skipNoHead && (!spec || !spec.definitions))
1117       {
1118          bool addedPadding = false;
1119          classSym.declaredStructSym = true;
1120
1121          declarations = MkList();
1122
1123          AddMembers(declarations, classSym.registered, false, null, classSym.registered, &addedPadding);
1124
1125          //ListAdd(specifiers, MkSpecifier(TYPEDEF));
1126          //ListAdd(specifiers, MkStructOrUnion(structSpecifier, null, declarations));
1127
1128          if(!declarations->count || (declarations->count == 1 && addedPadding))
1129          {
1130             FreeList(declarations, FreeClassDef);
1131             declarations = null;
1132          }
1133       }
1134       if(skipNoHead || declarations)
1135       {
1136          if(spec)
1137          {
1138             if(declarations)
1139                spec.definitions = declarations;
1140
1141             if(curExternal && curExternal.symbol && curExternal.symbol.idCode < classSym.id)
1142             {
1143                // TODO: Fix this
1144                //ast->Move(classSym.structExternal ? classSym.structExternal : classSym.pointerExternal, curExternal.prev);
1145
1146                // DANGER
1147                if(classSym.structExternal)
1148                   ast->Move(classSym.structExternal, curExternal.prev);
1149                ast->Move(classSym.pointerExternal, curExternal.prev);
1150
1151                classSym.id = curExternal.symbol.idCode;
1152                classSym.idCode = curExternal.symbol.idCode;
1153                // external = classSym.pointerExternal;
1154                //external = classSym.structExternal ? classSym.structExternal : classSym.pointerExternal;
1155             }
1156          }
1157          else
1158          {
1159             if(!external)
1160                external = MkExternalDeclaration(null);
1161
1162             specifiers = MkList();
1163             declarators = MkList();
1164             ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), declarations));
1165
1166             /*
1167             d = MkDeclaratorIdentifier(MkIdentifier(structName));
1168             ListAdd(declarators, MkInitDeclarator(d, null));
1169             */
1170             external.declaration = decl = MkDeclaration(specifiers, declarators);
1171             if(decl.symbol && !decl.symbol.pointerExternal)
1172                decl.symbol.pointerExternal = external;
1173
1174             // For simple classes, keep the declaration as the external to move around
1175             if(classSym.registered && classSym.registered.type == structClass)
1176             {
1177                char className[1024];
1178                strcpy(className, "__ecereClass_");
1179                FullClassNameCat(className, classSym.string, true);
1180                MangleClassName(className);
1181
1182                // Testing This
1183                DeclareClass(classSym, className);
1184
1185                external.symbol = classSym;
1186                classSym.pointerExternal = external;
1187                classSym.id = (curExternal && curExternal.symbol) ? curExternal.symbol.idCode : 0;
1188                classSym.idCode = (curExternal && curExternal.symbol) ? curExternal.symbol.idCode : 0;
1189             }
1190             else
1191             {
1192                char className[1024];
1193                strcpy(className, "__ecereClass_");
1194                FullClassNameCat(className, classSym.string, true);
1195                MangleClassName(className);
1196
1197                // TOFIX: TESTING THIS...
1198                classSym.structExternal = external;
1199                DeclareClass(classSym, className);
1200                external.symbol = classSym;
1201             }
1202
1203             //if(curExternal)
1204                ast->Insert(curExternal ? curExternal.prev : null, external);
1205          }
1206       }
1207
1208       classSym.declaring--;
1209    }
1210    else if(curExternal && curExternal.symbol && curExternal.symbol.idCode < classSym.id)
1211    {
1212       // TEMPORARY HACK: Pass 3 will move up struct declarations without moving members
1213       // Moved this one up because DeclareClass done later will need it
1214
1215       // TESTING THIS:
1216       classSym.declaring++;
1217
1218       //if(!skipNoHead)
1219       {
1220          if(classSym.registered)
1221             DeclareMembers(classSym.registered, false);
1222       }
1223
1224       if(classSym.registered && (classSym.registered.type == structClass || classSym.registered.type == noHeadClass))
1225       {
1226          // TODO: Fix this
1227          //ast->Move(classSym.structExternal ? classSym.structExternal : classSym.pointerExternal, curExternal.prev);
1228
1229          // DANGER
1230          if(classSym.structExternal)
1231             ast->Move(classSym.structExternal, curExternal.prev);
1232          ast->Move(classSym.pointerExternal, curExternal.prev);
1233
1234          classSym.id = curExternal.symbol.idCode;
1235          classSym.idCode = curExternal.symbol.idCode;
1236          // external = classSym.pointerExternal;
1237          // external = classSym.structExternal ? classSym.structExternal : classSym.pointerExternal;
1238       }
1239
1240       classSym.declaring--;
1241    }
1242    //return external;
1243 }
1244
1245 void DeclareProperty(Property prop, char * setName, char * getName)
1246 {
1247    Symbol symbol = prop.symbol;
1248
1249    strcpy(setName, "__ecereProp_");
1250    FullClassNameCat(setName, prop._class.fullName, false);
1251    strcat(setName, "_Set_");
1252    // strcat(setName, prop.name);
1253    FullClassNameCat(setName, prop.name, true);
1254    MangleClassName(setName);
1255
1256    strcpy(getName, "__ecereProp_");
1257    FullClassNameCat(getName, prop._class.fullName, false);
1258    strcat(getName, "_Get_");
1259    FullClassNameCat(getName, prop.name, true);
1260    // strcat(getName, prop.name);
1261
1262    // To support "char *" property
1263    MangleClassName(getName);
1264
1265    if(prop._class.type == structClass)
1266       DeclareStruct(prop._class.fullName, false);
1267
1268    if(!symbol || curExternal.symbol.idCode < symbol.id)
1269    {
1270       bool imported = false;
1271       bool dllImport = false;
1272
1273       if(!symbol || symbol._import)
1274       {
1275          if(!symbol)
1276          {
1277             Symbol classSym;
1278             if(!prop._class.symbol)
1279                prop._class.symbol = FindClass(prop._class.fullName);
1280             classSym = prop._class.symbol;
1281             if(classSym && !classSym._import)
1282             {
1283                ModuleImport module;
1284
1285                if(prop._class.module)
1286                   module = FindModule(prop._class.module);
1287                else
1288                   module = mainModule;
1289
1290                classSym._import = ClassImport
1291                {
1292                   name = CopyString(prop._class.fullName);
1293                   isRemote = prop._class.isRemote;
1294                };
1295                module.classes.Add(classSym._import);
1296             }
1297             symbol = prop.symbol = Symbol { };
1298             symbol._import = (ClassImport)PropertyImport
1299             {
1300                name = CopyString(prop.name);
1301                isVirtual = false; //prop.isVirtual;
1302                hasSet = prop.Set ? true : false;
1303                hasGet = prop.Get ? true : false;
1304             };
1305             if(classSym)
1306                classSym._import.properties.Add(symbol._import);
1307          }
1308          imported = true;
1309          // Ugly work around for isNan properties declared within float/double classes which are initialized with ecereCOM
1310          if((prop._class.module != privateModule || !strcmp(prop._class.name, "float") || !strcmp(prop._class.name, "double")) &&
1311             prop._class.module.importType != staticImport)
1312             dllImport = true;
1313       }
1314
1315       if(!symbol.type)
1316       {
1317          Context context = SetupTemplatesContext(prop._class);
1318          symbol.type = ProcessTypeString(prop.dataTypeString, false);
1319          FinishTemplatesContext(context);
1320       }
1321
1322       // Get
1323       if(prop.Get)
1324       {
1325          if(!symbol.externalGet || symbol.externalGet.type == functionExternal)
1326          {
1327             Declaration decl;
1328             OldList * specifiers, * declarators;
1329             Declarator d;
1330             OldList * params;
1331             Specifier spec;
1332             External external;
1333             Declarator typeDecl;
1334             bool simple = false;
1335
1336             specifiers = MkList();
1337             declarators = MkList();
1338             params = MkList();
1339
1340             ListAdd(params, MkTypeName(MkListOne(MkSpecifierName /*MkClassName*/(prop._class.fullName)),
1341                MkDeclaratorIdentifier(MkIdentifier("this"))));
1342
1343             d = MkDeclaratorIdentifier(MkIdentifier(getName));
1344             //if(imported)
1345             if(dllImport)
1346                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1347
1348             {
1349                Context context = SetupTemplatesContext(prop._class);
1350                typeDecl = SpecDeclFromString(prop.dataTypeString, specifiers, null);
1351                FinishTemplatesContext(context);
1352             }
1353
1354             // Make sure the simple _class's type is declared
1355             for(spec = specifiers->first; spec; spec = spec.next)
1356             {
1357                if(spec.type == nameSpecifier /*SpecifierClass*/)
1358                {
1359                   if((!typeDecl || typeDecl.type == identifierDeclarator))
1360                   {
1361                      Symbol classSym = spec.symbol; // FindClass(spec.name);
1362                      symbol._class = classSym.registered;
1363                      if(classSym.registered && classSym.registered.type == structClass)
1364                      {
1365                         DeclareStruct(spec.name, false);
1366                         simple = true;
1367                      }
1368                   }
1369                }
1370             }
1371
1372             if(!simple)
1373                d = PlugDeclarator(typeDecl, d);
1374             else
1375             {
1376                ListAdd(params, MkTypeName(specifiers,
1377                   PlugDeclarator(typeDecl, MkDeclaratorIdentifier(MkIdentifier("value")))));
1378                specifiers = MkList();
1379             }
1380
1381             d = MkDeclaratorFunction(d, params);
1382
1383             //if(imported)
1384             if(dllImport)
1385                specifiers->Insert(null, MkSpecifier(EXTERN));
1386             else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1387                specifiers->Insert(null, MkSpecifier(STATIC));
1388             if(simple)
1389                ListAdd(specifiers, MkSpecifier(VOID));
1390
1391             ListAdd(declarators, MkInitDeclarator(d, null));
1392
1393             decl = MkDeclaration(specifiers, declarators);
1394
1395             external = MkExternalDeclaration(decl);
1396             ast->Insert(curExternal.prev, external);
1397             external.symbol = symbol;
1398             symbol.externalGet = external;
1399
1400             ReplaceThisClassSpecifiers(specifiers, prop._class);
1401
1402             if(typeDecl)
1403                FreeDeclarator(typeDecl);
1404          }
1405          else
1406          {
1407             // Move declaration higher...
1408             ast->Move(symbol.externalGet, curExternal.prev);
1409          }
1410       }
1411
1412       // Set
1413       if(prop.Set)
1414       {
1415          if(!symbol.externalSet || symbol.externalSet.type == functionExternal)
1416          {
1417             Declaration decl;
1418             OldList * specifiers, * declarators;
1419             Declarator d;
1420             OldList * params;
1421             Specifier spec;
1422             External external;
1423             Declarator typeDecl;
1424
1425             declarators = MkList();
1426             params = MkList();
1427
1428             // TESTING COMMENTING THIS FIRST LINE OUT, what was the problem? Trying to add noHeadClass here ...
1429             if(!prop.conversion || prop._class.type == structClass)
1430             {
1431                ListAdd(params, MkTypeName(MkListOne(MkSpecifierName/*MkClassName*/(prop._class.fullName)),
1432                   MkDeclaratorIdentifier(MkIdentifier("this"))));
1433             }
1434
1435             specifiers = MkList();
1436
1437             {
1438                Context context = SetupTemplatesContext(prop._class);
1439                typeDecl = d = SpecDeclFromString(prop.dataTypeString, specifiers,
1440                   MkDeclaratorIdentifier(MkIdentifier("value")));
1441                FinishTemplatesContext(context);
1442             }
1443             if(!strcmp(prop._class.base.fullName, "eda::Row") || !strcmp(prop._class.base.fullName, "eda::Id"))
1444                specifiers->Insert(null, MkSpecifier(CONST));
1445
1446             ListAdd(params, MkTypeName(specifiers, d));
1447
1448             d = MkDeclaratorIdentifier(MkIdentifier(setName));
1449             //if(imported)
1450             if(dllImport)
1451                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
1452             d = MkDeclaratorFunction(d, params);
1453
1454             // Make sure the simple _class's type is declared
1455             for(spec = specifiers->first; spec; spec = spec.next)
1456             {
1457                if(spec.type == nameSpecifier /*SpecifierClass*/)
1458                {
1459                   if((!typeDecl || typeDecl.type == identifierDeclarator))
1460                   {
1461                      Symbol classSym = spec.symbol; // FindClass(spec.name);
1462                      symbol._class = classSym.registered;
1463                      if(classSym.registered && classSym.registered.type == structClass)
1464                         DeclareStruct(spec.name, false);
1465                   }
1466                }
1467             }
1468
1469             ListAdd(declarators, MkInitDeclarator(d, null));
1470
1471             specifiers = MkList();
1472             //if(imported)
1473             if(dllImport)
1474                specifiers->Insert(null, MkSpecifier(EXTERN));
1475             else if(prop._class.symbol && ((Symbol)prop._class.symbol).isStatic)
1476                specifiers->Insert(null, MkSpecifier(STATIC));
1477
1478             // TESTING COMMENTING THIS FIRST LINE OUT, what was the problem? Trying to add noHeadClass here ...
1479             if(!prop.conversion || prop._class.type == structClass)
1480                ListAdd(specifiers, MkSpecifier(VOID));
1481             else
1482                ListAdd(specifiers, MkSpecifierName/*MkClassName*/(prop._class.fullName));
1483
1484             decl = MkDeclaration(specifiers, declarators);
1485
1486             external = MkExternalDeclaration(decl);
1487             ast->Insert(curExternal.prev, external);
1488             external.symbol = symbol;
1489             symbol.externalSet = external;
1490
1491             ReplaceThisClassSpecifiers(specifiers, prop._class);
1492          }
1493          else
1494          {
1495             // Move declaration higher...
1496             ast->Move(symbol.externalSet, curExternal.prev);
1497          }
1498       }
1499
1500       // Property (for Watchers)
1501       if(!symbol.externalPtr)
1502       {
1503          Declaration decl;
1504          External external;
1505          OldList * specifiers = MkList();
1506          char propName[1024];
1507
1508          if(imported)
1509             specifiers->Insert(null, MkSpecifier(EXTERN));
1510          else
1511             specifiers->Insert(null, MkSpecifier(STATIC));
1512
1513          ListAdd(specifiers, MkSpecifierName("Property"));
1514
1515          strcpy(propName, "__ecereProp_");
1516          FullClassNameCat(propName, prop._class.fullName, false);
1517          strcat(propName, "_");
1518          FullClassNameCat(propName, prop.name, true);
1519          // strcat(propName, prop.name);
1520          MangleClassName(propName);
1521
1522          {
1523             OldList * list = MkList();
1524             ListAdd(list, MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null),
1525                   MkDeclaratorIdentifier(MkIdentifier(propName))), null));
1526
1527             if(!imported)
1528             {
1529                strcpy(propName, "__ecerePropM_");
1530                FullClassNameCat(propName, prop._class.fullName, false);
1531                strcat(propName, "_");
1532                // strcat(propName, prop.name);
1533                FullClassNameCat(propName, prop.name, true);
1534
1535                MangleClassName(propName);
1536
1537                ListAdd(list, MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null),
1538                      MkDeclaratorIdentifier(MkIdentifier(propName))), null));
1539             }
1540             decl = MkDeclaration(specifiers, list);
1541          }
1542
1543          external = MkExternalDeclaration(decl);
1544          ast->Insert(curExternal.prev, external);
1545          external.symbol = symbol;
1546          symbol.externalPtr = external;
1547       }
1548       else
1549       {
1550          // Move declaration higher...
1551          ast->Move(symbol.externalPtr, curExternal.prev);
1552       }
1553
1554       symbol.id = curExternal.symbol.idCode;
1555    }
1556 }
1557
1558 // ***************** EXPRESSION PROCESSING ***************************
1559 public Type Dereference(Type source)
1560 {
1561    Type type = null;
1562    if(source)
1563    {
1564       if(source.kind == pointerType || source.kind == arrayType)
1565       {
1566          type = source.type;
1567          source.type.refCount++;
1568       }
1569       else if(source.kind == classType && !strcmp(source._class.string, "String"))
1570       {
1571          type = Type
1572          {
1573             kind = charType;
1574             refCount = 1;
1575          };
1576       }
1577       // Support dereferencing of no head classes for now...
1578       else if(source.kind == classType && source._class && source._class.registered && source._class.registered.type == noHeadClass)
1579       {
1580          type = source;
1581          source.refCount++;
1582       }
1583       else
1584          Compiler_Error($"cannot dereference type\n");
1585    }
1586    return type;
1587 }
1588
1589 static Type Reference(Type source)
1590 {
1591    Type type = null;
1592    if(source)
1593    {
1594       type = Type
1595       {
1596          kind = pointerType;
1597          type = source;
1598          refCount = 1;
1599       };
1600       source.refCount++;
1601    }
1602    return type;
1603 }
1604
1605 void ProcessMemberInitData(MemberInit member, Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
1606 {
1607    Identifier ident = member.identifiers ? member.identifiers->first : null;
1608    bool found = false;
1609    DataMember dataMember = null;
1610    Method method = null;
1611    bool freeType = false;
1612
1613    yylloc = member.loc;
1614
1615    if(!ident)
1616    {
1617       if(curMember)
1618       {
1619          eClass_FindNextMember(_class, curClass, curMember, subMemberStack, subMemberStackPos);
1620          if(*curMember)
1621          {
1622             found = true;
1623             dataMember = *curMember;
1624          }
1625       }
1626    }
1627    else
1628    {
1629       DataMember thisMember = (DataMember)eClass_FindProperty(_class, ident.string, privateModule);
1630       DataMember _subMemberStack[256];
1631       int _subMemberStackPos = 0;
1632
1633       // FILL MEMBER STACK
1634       if(!thisMember)
1635          thisMember = eClass_FindDataMember(_class, ident.string, privateModule, _subMemberStack, &_subMemberStackPos);
1636       if(thisMember)
1637       {
1638          dataMember = thisMember;
1639          if(curMember && thisMember.memberAccess == publicAccess)
1640          {
1641             *curMember = thisMember;
1642             *curClass = thisMember._class;
1643             memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
1644             *subMemberStackPos = _subMemberStackPos;
1645          }
1646          found = true;
1647       }
1648       else
1649       {
1650          // Setting a method
1651          method = eClass_FindMethod(_class, ident.string, privateModule);
1652          if(method && method.type == virtualMethod)
1653             found = true;
1654          else
1655             method = null;
1656       }
1657    }
1658
1659    if(found)
1660    {
1661       Type type = null;
1662       if(dataMember)
1663       {
1664          if(!dataMember.dataType && dataMember.dataTypeString)
1665          {
1666             //Context context = SetupTemplatesContext(dataMember._class);
1667             Context context = SetupTemplatesContext(_class);
1668             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
1669             FinishTemplatesContext(context);
1670          }
1671          type = dataMember.dataType;
1672       }
1673       else if(method)
1674       {
1675          // This is for destination type...
1676          if(!method.dataType)
1677             ProcessMethodType(method);
1678          //DeclareMethod(method);
1679          // method.dataType = ((Symbol)method.symbol)->type;
1680          type = method.dataType;
1681       }
1682
1683       if(ident && ident.next)
1684       {
1685          for(ident = ident.next; ident && type; ident = ident.next)
1686          {
1687             if(type.kind == classType)
1688             {
1689                dataMember = (DataMember)eClass_FindProperty(type._class.registered, ident.string, privateModule);
1690                if(!dataMember)
1691                   dataMember = eClass_FindDataMember(type._class.registered, ident.string, privateModule, null, null);
1692                if(dataMember)
1693                   type = dataMember.dataType;
1694             }
1695             else if(type.kind == structType || type.kind == unionType)
1696             {
1697                Type memberType;
1698                for(memberType = type.members.first; memberType; memberType = memberType.next)
1699                {
1700                   if(!strcmp(memberType.name, ident.string))
1701                   {
1702                      type = memberType;
1703                      break;
1704                   }
1705                }
1706             }
1707          }
1708       }
1709
1710       // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
1711       if(type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type && _class.templateArgs /* TODO: Watch out for these _class.templateClass*/)
1712       {
1713          int id = 0;
1714          ClassTemplateParameter curParam = null;
1715          Class sClass;
1716          for(sClass = _class; sClass; sClass = sClass.base)
1717          {
1718             id = 0;
1719             if(sClass.templateClass) sClass = sClass.templateClass;
1720             for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
1721             {
1722                if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
1723                {
1724                   for(sClass = sClass.base; sClass; sClass = sClass.base)
1725                   {
1726                      if(sClass.templateClass) sClass = sClass.templateClass;
1727                      id += sClass.templateParams.count;
1728                   }
1729                   break;
1730                }
1731                id++;
1732             }
1733             if(curParam) break;
1734          }
1735
1736          if(curParam)
1737          {
1738             ClassTemplateArgument arg = _class.templateArgs[id];
1739             if(arg.dataTypeString)
1740             {
1741                bool constant = type.constant;
1742                // FreeType(type);
1743                type = ProcessTypeString(arg.dataTypeString, false);
1744                if(type.kind == classType && constant) type.constant = true;
1745                else if(type.kind == pointerType)
1746                {
1747                   Type t = type.type;
1748                   while(t.kind == pointerType) t = t.type;
1749                   if(constant) t.constant = constant;
1750                }
1751                freeType = true;
1752                if(type && _class.templateClass)
1753                   type.passAsTemplate = true;
1754                if(type)
1755                {
1756                   // type.refCount++;
1757                   /*if(!exp.destType)
1758                   {
1759                      exp.destType = ProcessTypeString(arg.dataTypeString, false);
1760                      exp.destType.refCount++;
1761                   }*/
1762                }
1763             }
1764          }
1765       }
1766       if(type && type.kind == classType && type._class && type._class.registered && strchr(type._class.registered.fullName, '<'))
1767       {
1768          Class expClass = type._class.registered;
1769          Class cClass = null;
1770          int c;
1771          int paramCount = 0;
1772          int lastParam = -1;
1773
1774          char templateString[1024];
1775          ClassTemplateParameter param;
1776          sprintf(templateString, "%s<", expClass.templateClass.fullName);
1777          for(cClass = expClass; cClass; cClass = cClass.base)
1778          {
1779             int p = 0;
1780             if(cClass.templateClass) cClass = cClass.templateClass;
1781             for(param = cClass.templateParams.first; param; param = param.next)
1782             {
1783                int id = p;
1784                Class sClass;
1785                ClassTemplateArgument arg;
1786                for(sClass = cClass.base; sClass; sClass = sClass.base)
1787                {
1788                   if(sClass.templateClass) sClass = sClass.templateClass;
1789                   id += sClass.templateParams.count;
1790                }
1791                arg = expClass.templateArgs[id];
1792
1793                for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
1794                {
1795                   ClassTemplateParameter cParam;
1796                   //int p = numParams - sClass.templateParams.count;
1797                   int p = 0;
1798                   Class nextClass;
1799                   if(sClass.templateClass) sClass = sClass.templateClass;
1800
1801                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
1802                   {
1803                      if(nextClass.templateClass) nextClass = nextClass.templateClass;
1804                      p += nextClass.templateParams.count;
1805                   }
1806
1807                   for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
1808                   {
1809                      if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
1810                      {
1811                         if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1812                         {
1813                            arg.dataTypeString = _class.templateArgs[p].dataTypeString;
1814                            arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
1815                            break;
1816                         }
1817                      }
1818                   }
1819                }
1820
1821                {
1822                   char argument[256];
1823                   argument[0] = '\0';
1824                   /*if(arg.name)
1825                   {
1826                      strcat(argument, arg.name.string);
1827                      strcat(argument, " = ");
1828                   }*/
1829                   switch(param.type)
1830                   {
1831                      case expression:
1832                      {
1833                         // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
1834                         char expString[1024];
1835                         OldList * specs = MkList();
1836                         Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
1837                         Expression exp;
1838                         char * string = PrintHexUInt64(arg.expression.ui64);
1839                         exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
1840                         delete string;
1841
1842                         ProcessExpressionType(exp);
1843                         ComputeExpression(exp);
1844                         expString[0] = '\0';
1845                         PrintExpression(exp, expString);
1846                         strcat(argument, expString);
1847                         //delete exp;
1848                         FreeExpression(exp);
1849                         break;
1850                      }
1851                      case identifier:
1852                      {
1853                         strcat(argument, arg.member.name);
1854                         break;
1855                      }
1856                      case TemplateParameterType::type:
1857                      {
1858                         if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
1859                            strcat(argument, arg.dataTypeString);
1860                         break;
1861                      }
1862                   }
1863                   if(argument[0])
1864                   {
1865                      if(paramCount) strcat(templateString, ", ");
1866                      if(lastParam != p - 1)
1867                      {
1868                         strcat(templateString, param.name);
1869                         strcat(templateString, " = ");
1870                      }
1871                      strcat(templateString, argument);
1872                      paramCount++;
1873                      lastParam = p;
1874                   }
1875                   p++;
1876                }
1877             }
1878          }
1879          {
1880             int len = strlen(templateString);
1881             if(templateString[len-1] == '<')
1882                len--;
1883             else
1884             {
1885                if(templateString[len-1] == '>')
1886                   templateString[len++] = ' ';
1887                templateString[len++] = '>';
1888             }
1889             templateString[len++] = '\0';
1890          }
1891          {
1892             Context context = SetupTemplatesContext(_class);
1893             if(freeType) FreeType(type);
1894             type = ProcessTypeString(templateString, false);
1895             freeType = true;
1896             FinishTemplatesContext(context);
1897          }
1898       }
1899
1900       if(method && member.initializer && member.initializer.type == expInitializer && member.initializer.exp)
1901       {
1902          ProcessExpressionType(member.initializer.exp);
1903          if(!member.initializer.exp.expType)
1904          {
1905             if(inCompiler)
1906             {
1907                char expString[10240];
1908                expString[0] = '\0';
1909                PrintExpression(member.initializer.exp, expString);
1910                ChangeCh(expString, '\n', ' ');
1911                Compiler_Error($"unresolved symbol used as an instance method %s\n", expString);
1912             }
1913          }
1914          //else if(!MatchTypes(member.exp.expType, type, null, _class, null, true, true, false, false))
1915          else if(!MatchTypes(member.initializer.exp.expType, type, null, null, _class, true, true, false, false, true))
1916          {
1917             Compiler_Error($"incompatible instance method %s\n", ident.string);
1918          }
1919       }
1920       else if(member.initializer)
1921       {
1922          /*
1923          FreeType(member.exp.destType);
1924          member.exp.destType = type;
1925          if(member.exp.destType)
1926             member.exp.destType.refCount++;
1927          ProcessExpressionType(member.exp);
1928          */
1929
1930          ProcessInitializer(member.initializer, type);
1931       }
1932       if(freeType) FreeType(type);
1933    }
1934    else
1935    {
1936       if(_class && _class.type == unitClass)
1937       {
1938          if(member.initializer)
1939          {
1940             /*
1941             FreeType(member.exp.destType);
1942             member.exp.destType = MkClassType(_class.fullName);
1943             ProcessExpressionType(member.initializer, type);
1944             */
1945             Type type = MkClassType(_class.fullName);
1946             ProcessInitializer(member.initializer, type);
1947             FreeType(type);
1948          }
1949       }
1950       else
1951       {
1952          if(member.initializer)
1953          {
1954             //ProcessExpressionType(member.exp);
1955             ProcessInitializer(member.initializer, null);
1956          }
1957          if(ident)
1958          {
1959             if(method)
1960             {
1961                Compiler_Error($"couldn't find virtual method %s in class %s\n", ident.string, _class.fullName);
1962             }
1963             else if(_class)
1964             {
1965                Compiler_Error($"couldn't find member %s in class %s\n", ident.string, _class.fullName);
1966                if(inCompiler)
1967                   eClass_AddDataMember(_class, ident.string, "int", 0, 0, publicAccess);
1968             }
1969          }
1970          else if(_class)
1971             Compiler_Error($"too many initializers for instantiation of class %s\n", _class.fullName);
1972       }
1973    }
1974 }
1975
1976 void ProcessInstantiationType(Instantiation inst)
1977 {
1978    yylloc = inst.loc;
1979    if(inst._class)
1980    {
1981       MembersInit members;
1982       Symbol classSym; // = inst._class.symbol; // FindClass(inst._class.name);
1983       Class _class;
1984
1985       /*if(!inst._class.symbol)
1986          inst._class.symbol = FindClass(inst._class.name);*/
1987       classSym = inst._class.symbol;
1988       _class = classSym ? classSym.registered : null;
1989
1990       // DANGER: Patch for mutex not declaring its struct when not needed
1991       if(!_class || _class.type != noHeadClass)
1992          DeclareStruct(inst._class.name, false); //_class && _class.type == noHeadClass);
1993
1994       afterExternal = afterExternal ? afterExternal : curExternal;
1995
1996       if(inst.exp)
1997          ProcessExpressionType(inst.exp);
1998
1999       inst.isConstant = true;
2000       if(inst.members)
2001       {
2002          DataMember curMember = null;
2003          Class curClass = null;
2004          DataMember subMemberStack[256];
2005          int subMemberStackPos = 0;
2006
2007          for(members = inst.members->first; members; members = members.next)
2008          {
2009             switch(members.type)
2010             {
2011                case methodMembersInit:
2012                {
2013                   char name[1024];
2014                   static uint instMethodID = 0;
2015                   External external = curExternal;
2016                   Context context = curContext;
2017                   Declarator declarator = members.function.declarator;
2018                   Identifier nameID = GetDeclId(declarator);
2019                   char * unmangled = nameID ? nameID.string : null;
2020                   Expression exp;
2021                   External createdExternal = null;
2022
2023                   if(inCompiler)
2024                   {
2025                      char number[16];
2026                      //members.function.dontMangle = true;
2027                      strcpy(name, "__ecereInstMeth_");
2028                      FullClassNameCat(name, _class ? _class.fullName : "_UNKNOWNCLASS", false);
2029                      strcat(name, "_");
2030                      strcat(name, nameID.string);
2031                      strcat(name, "_");
2032                      sprintf(number, "_%08d", instMethodID++);
2033                      strcat(name, number);
2034                      nameID.string = CopyString(name);
2035                   }
2036
2037                   // Do modifications here...
2038                   if(declarator)
2039                   {
2040                      Symbol symbol = declarator.symbol;
2041                      Method method = eClass_FindMethod(_class, unmangled, privateModule);
2042
2043                      if(method && method.type == virtualMethod)
2044                      {
2045                         symbol.method = method;
2046                         ProcessMethodType(method);
2047
2048                         if(!symbol.type.thisClass)
2049                         {
2050                            if(method.dataType.thisClass && currentClass &&
2051                               eClass_IsDerived(currentClass, method.dataType.thisClass.registered))
2052                            {
2053                               if(!currentClass.symbol)
2054                                  currentClass.symbol = FindClass(currentClass.fullName);
2055                               symbol.type.thisClass = currentClass.symbol;
2056                            }
2057                            else
2058                            {
2059                               if(!_class.symbol)
2060                                  _class.symbol = FindClass(_class.fullName);
2061                               symbol.type.thisClass = _class.symbol;
2062                            }
2063                         }
2064                         // TESTING THIS HERE:
2065                         DeclareType(symbol.type, true, true);
2066
2067                      }
2068                      else if(classSym)
2069                      {
2070                         Compiler_Error($"couldn't find virtual method %s in class %s\n",
2071                            unmangled, classSym.string);
2072                      }
2073                   }
2074
2075                   //declarator.symbol.id = declarator.symbol.idCode = curExternal.symbol.idCode;
2076                   createdExternal = ProcessClassFunction(classSym ? classSym.registered : null, members.function, ast, afterExternal, true);
2077
2078                   if(nameID)
2079                   {
2080                      FreeSpecifier(nameID._class);
2081                      nameID._class = null;
2082                   }
2083
2084                   if(inCompiler)
2085                   {
2086                      //Type type = declarator.symbol.type;
2087                      External oldExternal = curExternal;
2088
2089                      // *** Commented this out... Any negative impact? Yes: makes double prototypes declarations... Why was it commented out?
2090                      // *** It was commented out for problems such as
2091                      /*
2092                            class VirtualDesktop : Window
2093                            {
2094                               clientSize = Size { };
2095                               Timer timer
2096                               {
2097                                  bool DelayExpired()
2098                                  {
2099                                     clientSize.w;
2100                                     return true;
2101                                  }
2102                               };
2103                            }
2104                      */
2105                      // Commented Out: Good for bet.ec in Poker (Otherwise: obj\bet.c:187: error: `currentBet' undeclared (first use in this function))
2106
2107                      declarator.symbol.id = declarator.symbol.idCode = curExternal.symbol.idCode;
2108
2109                      /*
2110                      if(strcmp(declarator.symbol.string, name))
2111                      {
2112                         printf("TOCHECK: Look out for this\n");
2113                         delete declarator.symbol.string;
2114                         declarator.symbol.string = CopyString(name);
2115                      }
2116
2117                      if(!declarator.symbol.parent && globalContext.symbols.root != (BTNode)declarator.symbol)
2118                      {
2119                         printf("TOCHECK: Will this ever be in a list? Yes.\n");
2120                         excludedSymbols->Remove(declarator.symbol);
2121                         globalContext.symbols.Add((BTNode)declarator.symbol);
2122                         if(strstr(declarator.symbol.string), "::")
2123                            globalContext.hasNameSpace = true;
2124
2125                      }
2126                      */
2127
2128                      //curExternal = curExternal.prev;
2129                      //afterExternal = afterExternal->next;
2130
2131                      //ProcessFunction(afterExternal->function);
2132
2133                      //curExternal = afterExternal;
2134                      {
2135                         External externalDecl;
2136                         externalDecl = MkExternalDeclaration(null);
2137                         ast->Insert(oldExternal.prev, externalDecl);
2138
2139                         // Which function does this process?
2140                         if(createdExternal.function)
2141                         {
2142                            ProcessFunction(createdExternal.function);
2143
2144                            //curExternal = oldExternal;
2145
2146                            {
2147                               //Declaration decl = MkDeclaration(members.function.specifiers, MkListOne(MkInitDeclarator(CopyDeclarator(declarator), null)));
2148
2149                               Declaration decl = MkDeclaration(CopyList(createdExternal.function.specifiers, CopySpecifier),
2150                                  MkListOne(MkInitDeclarator(CopyDeclarator(declarator), null)));
2151
2152                               //externalDecl = MkExternalDeclaration(decl);
2153
2154                               //***** ast->Insert(external.prev, externalDecl);
2155                               //ast->Insert(curExternal.prev, externalDecl);
2156                               externalDecl.declaration = decl;
2157                               if(decl.symbol && !decl.symbol.pointerExternal)
2158                                  decl.symbol.pointerExternal = externalDecl;
2159
2160                               // Trying this out...
2161                               declarator.symbol.pointerExternal = externalDecl;
2162                            }
2163                         }
2164                      }
2165                   }
2166                   else if(declarator)
2167                   {
2168                      curExternal = declarator.symbol.pointerExternal;
2169                      ProcessFunction((FunctionDefinition)members.function);
2170                   }
2171                   curExternal = external;
2172                   curContext = context;
2173
2174                   if(inCompiler)
2175                   {
2176                      FreeClassFunction(members.function);
2177
2178                      // In this pass, turn this into a MemberInitData
2179                      exp = QMkExpId(name);
2180                      members.type = dataMembersInit;
2181                      members.dataMembers = MkListOne(MkMemberInit(MkListOne(MkIdentifier(unmangled)), MkInitializerAssignment(exp)));
2182
2183                      delete unmangled;
2184                   }
2185                   break;
2186                }
2187                case dataMembersInit:
2188                {
2189                   if(members.dataMembers && classSym)
2190                   {
2191                      MemberInit member;
2192                      Location oldyyloc = yylloc;
2193                      for(member = members.dataMembers->first; member; member = member.next)
2194                      {
2195                         ProcessMemberInitData(member, classSym.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
2196                         if(member.initializer && !member.initializer.isConstant)
2197                            inst.isConstant = false;
2198                      }
2199                      yylloc = oldyyloc;
2200                   }
2201                   break;
2202                }
2203             }
2204          }
2205       }
2206    }
2207 }
2208
2209 static void DeclareType(Type type, bool declarePointers, bool declareParams)
2210 {
2211    // OPTIMIZATIONS: TESTING THIS...
2212    if(inCompiler)
2213    {
2214       if(type.kind == functionType)
2215       {
2216          Type param;
2217          if(declareParams)
2218          {
2219             for(param = type.params.first; param; param = param.next)
2220                DeclareType(param, declarePointers, true);
2221          }
2222          DeclareType(type.returnType, declarePointers, true);
2223       }
2224       else if(type.kind == pointerType && declarePointers)
2225          DeclareType(type.type, declarePointers, false);
2226       else if(type.kind == classType)
2227       {
2228          if(type._class.registered && (type._class.registered.type == structClass || type._class.registered.type == noHeadClass) && !type._class.declaring)
2229             DeclareStruct(type._class.registered.fullName, type._class.registered.type == noHeadClass);
2230       }
2231       else if(type.kind == structType || type.kind == unionType)
2232       {
2233          Type member;
2234          for(member = type.members.first; member; member = member.next)
2235             DeclareType(member, false, false);
2236       }
2237       else if(type.kind == arrayType)
2238          DeclareType(type.arrayType, declarePointers, false);
2239    }
2240 }
2241
2242 ClassTemplateArgument * FindTemplateArg(Class _class, TemplateParameter param)
2243 {
2244    ClassTemplateArgument * arg = null;
2245    int id = 0;
2246    ClassTemplateParameter curParam = null;
2247    Class sClass;
2248    for(sClass = _class; sClass; sClass = sClass.base)
2249    {
2250       id = 0;
2251       if(sClass.templateClass) sClass = sClass.templateClass;
2252       for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
2253       {
2254          if(curParam.type == TemplateParameterType::type && !strcmp(param.identifier.string, curParam.name))
2255          {
2256             for(sClass = sClass.base; sClass; sClass = sClass.base)
2257             {
2258                if(sClass.templateClass) sClass = sClass.templateClass;
2259                id += sClass.templateParams.count;
2260             }
2261             break;
2262          }
2263          id++;
2264       }
2265       if(curParam) break;
2266    }
2267    if(curParam)
2268    {
2269       arg = &_class.templateArgs[id];
2270       if(arg && param.type == type)
2271          arg->dataTypeClass = eSystem_FindClass(_class.module, arg->dataTypeString);
2272    }
2273    return arg;
2274 }
2275
2276 public Context SetupTemplatesContext(Class _class)
2277 {
2278    Context context = PushContext();
2279    context.templateTypesOnly = true;
2280    if(_class.symbol && ((Symbol)_class.symbol).templateParams)
2281    {
2282       TemplateParameter param = ((Symbol)_class.symbol).templateParams->first;
2283       for(; param; param = param.next)
2284       {
2285          if(param.type == type && param.identifier)
2286          {
2287             TemplatedType type { key = (uintptr)param.identifier.string, param = param };
2288             curContext.templateTypes.Add((BTNode)type);
2289          }
2290       }
2291    }
2292    else if(_class)
2293    {
2294       Class sClass;
2295       for(sClass = _class; sClass; sClass = sClass.base)
2296       {
2297          ClassTemplateParameter p;
2298          for(p = sClass.templateParams.first; p; p = p.next)
2299          {
2300             //OldList * specs = MkList();
2301             //Declarator decl = null;
2302             //decl = SpecDeclFromString(p.dataTypeString, specs, null);
2303             if(p.type == type)
2304             {
2305                TemplateParameter param = p.param;
2306                TemplatedType type;
2307                if(!param)
2308                {
2309                   // ADD DATA TYPE HERE...
2310                   p.param = param = TemplateParameter
2311                   {
2312                      identifier = MkIdentifier(p.name), type = p.type,
2313                      dataTypeString = p.dataTypeString /*, dataType = { specs, decl }*/
2314                   };
2315                }
2316                type = TemplatedType { key = (uintptr)p.name, param = param };
2317                curContext.templateTypes.Add((BTNode)type);
2318             }
2319          }
2320       }
2321    }
2322    return context;
2323 }
2324
2325 public void FinishTemplatesContext(Context context)
2326 {
2327    PopContext(context);
2328    FreeContext(context);
2329    delete context;
2330 }
2331
2332 public void ProcessMethodType(Method method)
2333 {
2334    if(!method.dataType)
2335    {
2336       Context context = SetupTemplatesContext(method._class);
2337
2338       method.dataType = ProcessTypeString(method.dataTypeString, false);
2339
2340       FinishTemplatesContext(context);
2341
2342       if(method.type != virtualMethod && method.dataType)
2343       {
2344          if(!method.dataType.thisClass && !method.dataType.staticMethod)
2345          {
2346             if(!method._class.symbol)
2347                method._class.symbol = FindClass(method._class.fullName);
2348             method.dataType.thisClass = method._class.symbol;
2349          }
2350       }
2351
2352       // Why was this commented out? Working fine without now...
2353
2354       /*
2355       if(method.dataType.kind == functionType && !method.dataType.staticMethod && !method.dataType.thisClass)
2356          method.dataType.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2357          */
2358    }
2359
2360    /*
2361    if(type)
2362    {
2363       char * par = strstr(type, "(");
2364       char * classOp = null;
2365       int classOpLen = 0;
2366       if(par)
2367       {
2368          int c;
2369          for(c = par-type-1; c >= 0; c++)
2370          {
2371             if(type[c] == ':' && type[c+1] == ':')
2372             {
2373                classOp = type + c - 1;
2374                for(c = c-1; c >=0 && !isspace(type[c]); c--)
2375                {
2376                   classOp--;
2377                   classOpLen++;
2378                }
2379                break;
2380             }
2381             else if(!isspace(type[c]))
2382                break;
2383          }
2384       }
2385       if(classOp)
2386       {
2387          char temp[1024];
2388          int typeLen = strlen(type);
2389          memcpy(temp, classOp, classOpLen);
2390          temp[classOpLen] = '\0';
2391          if(temp[0])
2392             _class = eSystem_FindClass(module, temp);
2393          else
2394             _class = null;
2395          method.dataTypeString = new char[typeLen - classOpLen + 1];
2396          memcpy(method.dataTypeString, type, classOp - type);
2397          memcpy(method.dataTypeString + (classOp - type), classOp + classOpLen, typeLen - (classOp - type + classOpLen));
2398       }
2399       else
2400          method.dataTypeString = type;
2401    }
2402    */
2403 }
2404
2405
2406 public void ProcessPropertyType(Property prop)
2407 {
2408    if(!prop.dataType)
2409    {
2410       Context context = SetupTemplatesContext(prop._class);
2411       prop.dataType = ProcessTypeString(prop.dataTypeString, false);
2412       FinishTemplatesContext(context);
2413    }
2414 }
2415
2416 public void DeclareMethod(Method method, const char * name)
2417 {
2418    Symbol symbol = method.symbol;
2419    if(!symbol || (!symbol.pointerExternal && method.type == virtualMethod) || symbol.id > (curExternal ? curExternal.symbol.idCode : -1))
2420    {
2421       bool imported = false;
2422       bool dllImport = false;
2423
2424       if(!method.dataType)
2425          method.dataType = ProcessTypeString(method.dataTypeString, false);
2426
2427       if(!symbol || symbol._import || method.type == virtualMethod)
2428       {
2429          if(!symbol || method.type == virtualMethod)
2430          {
2431             Symbol classSym;
2432             if(!method._class.symbol)
2433                method._class.symbol = FindClass(method._class.fullName);
2434             classSym = method._class.symbol;
2435             if(!classSym._import)
2436             {
2437                ModuleImport module;
2438
2439                if(method._class.module && method._class.module.name)
2440                   module = FindModule(method._class.module);
2441                else
2442                   module = mainModule;
2443                classSym._import = ClassImport
2444                {
2445                   name = CopyString(method._class.fullName);
2446                   isRemote = method._class.isRemote;
2447                };
2448                module.classes.Add(classSym._import);
2449             }
2450             if(!symbol)
2451             {
2452                symbol = method.symbol = Symbol { };
2453             }
2454             if(!symbol._import)
2455             {
2456                symbol._import = (ClassImport)MethodImport
2457                {
2458                   name = CopyString(method.name);
2459                   isVirtual = method.type == virtualMethod;
2460                };
2461                classSym._import.methods.Add(symbol._import);
2462             }
2463             if(!symbol)
2464             {
2465                // Set the symbol type
2466                /*
2467                if(!type.thisClass)
2468                {
2469                   type.thisClass = method._class.symbol; // FindClass(method._class.fullName);
2470                }
2471                else if(type.thisClass == (void *)-1)
2472                {
2473                   type.thisClass = null;
2474                }
2475                */
2476                // symbol.type = ProcessTypeString(method.dataTypeString, false);
2477                symbol.type = method.dataType;
2478                if(symbol.type) symbol.type.refCount++;
2479             }
2480             /*
2481             if(!method.thisClass || strcmp(method.thisClass, "void"))
2482                symbol.type.params.Insert(null,
2483                   MkClassType(method.thisClass ? method.thisClass : method._class.fullName));
2484             */
2485          }
2486          if(!method.dataType.dllExport)
2487          {
2488             imported = true;
2489             if((method._class.module != privateModule || !strcmp(method._class.name, "float") || !strcmp(method._class.name, "double")) && method._class.module.importType != staticImport)
2490                dllImport = true;
2491          }
2492       }
2493
2494       /* MOVING THIS UP
2495       if(!method.dataType)
2496          method.dataType = ((Symbol)method.symbol).type;
2497          //ProcessMethodType(method);
2498       */
2499
2500       if(method.type != virtualMethod && method.dataType)
2501          DeclareType(method.dataType, true, true);
2502
2503       if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2504       {
2505          // We need a declaration here :)
2506          Declaration decl;
2507          OldList * specifiers, * declarators;
2508          Declarator d;
2509          Declarator funcDecl;
2510          External external;
2511
2512          specifiers = MkList();
2513          declarators = MkList();
2514
2515          //if(imported)
2516          if(dllImport)
2517             ListAdd(specifiers, MkSpecifier(EXTERN));
2518          else if(method._class.symbol && ((Symbol)method._class.symbol).isStatic)
2519             ListAdd(specifiers, MkSpecifier(STATIC));
2520
2521          if(method.type == virtualMethod)
2522          {
2523             ListAdd(specifiers, MkSpecifier(INT));
2524             d = MkDeclaratorIdentifier(MkIdentifier(name));
2525          }
2526          else
2527          {
2528             d = MkDeclaratorIdentifier(MkIdentifier(name));
2529             //if(imported)
2530             if(dllImport)
2531                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2532             {
2533                Context context = SetupTemplatesContext(method._class);
2534                d = SpecDeclFromString(method.dataTypeString, specifiers, d);
2535                FinishTemplatesContext(context);
2536             }
2537             funcDecl = GetFuncDecl(d);
2538
2539             if(dllImport)
2540             {
2541                Specifier spec, next;
2542                for(spec = specifiers->first; spec; spec = next)
2543                {
2544                   next = spec.next;
2545                   if(spec.type == extendedSpecifier)
2546                   {
2547                      specifiers->Remove(spec);
2548                      FreeSpecifier(spec);
2549                   }
2550                }
2551             }
2552
2553             // Add this parameter if not a static method
2554             if(method.dataType && !method.dataType.staticMethod)
2555             {
2556                if(funcDecl && funcDecl.function.parameters && funcDecl.function.parameters->count)
2557                {
2558                   Class _class = method.dataType.thisClass ? method.dataType.thisClass.registered : method._class;
2559                   TypeName thisParam = MkTypeName(MkListOne(
2560                      MkSpecifierName/*MkClassName*/(method.dataType.thisClass ? method.dataType.thisClass.string : method._class.fullName)),
2561                      (_class && _class.type == systemClass) ? MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("this"))) : MkDeclaratorIdentifier(MkIdentifier("this")));
2562                   TypeName firstParam = ((TypeName)funcDecl.function.parameters->first);
2563                   Specifier firstSpec = firstParam.qualifiers ? firstParam.qualifiers->first : null;
2564
2565                   if(firstSpec && firstSpec.type == baseSpecifier && firstSpec.specifier == VOID && !firstParam.declarator)
2566                   {
2567                      TypeName param = funcDecl.function.parameters->first;
2568                      funcDecl.function.parameters->Remove(param);
2569                      FreeTypeName(param);
2570                   }
2571
2572                   if(!funcDecl.function.parameters)
2573                      funcDecl.function.parameters = MkList();
2574                   funcDecl.function.parameters->Insert(null, thisParam);
2575                }
2576             }
2577             // Make sure we don't have empty parameter declarations for static methods...
2578             /*
2579             else if(!funcDecl.function.parameters)
2580             {
2581                funcDecl.function.parameters = MkList();
2582                funcDecl.function.parameters->Insert(null,
2583                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2584             }*/
2585          }
2586          // TESTING THIS:
2587          ProcessDeclarator(d);
2588
2589          ListAdd(declarators, MkInitDeclarator(d, null));
2590
2591          decl = MkDeclaration(specifiers, declarators);
2592
2593          ReplaceThisClassSpecifiers(specifiers, method._class);
2594
2595          // Keep a different symbol for the function definition than the declaration...
2596          if(symbol.pointerExternal)
2597          {
2598             Symbol functionSymbol { };
2599
2600             // Copy symbol
2601             {
2602                *functionSymbol = *symbol;
2603                functionSymbol.string = CopyString(symbol.string);
2604                if(functionSymbol.type)
2605                   functionSymbol.type.refCount++;
2606             }
2607
2608             excludedSymbols->Add(functionSymbol);
2609             symbol.pointerExternal.symbol = functionSymbol;
2610          }
2611          external = MkExternalDeclaration(decl);
2612          if(curExternal)
2613             ast->Insert(curExternal ? curExternal.prev : null, external);
2614          external.symbol = symbol;
2615          symbol.pointerExternal = external;
2616       }
2617       else if(ast)
2618       {
2619          // Move declaration higher...
2620          ast->Move(symbol.pointerExternal, curExternal.prev);
2621       }
2622
2623       symbol.id = curExternal ? curExternal.symbol.idCode : MAXINT;
2624    }
2625 }
2626
2627 char * ReplaceThisClass(Class _class)
2628 {
2629    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2630    {
2631       bool first = true;
2632       int p = 0;
2633       ClassTemplateParameter param;
2634       int lastParam = -1;
2635
2636       char className[1024];
2637       strcpy(className, _class.fullName);
2638       for(param = _class.templateParams.first; param; param = param.next)
2639       {
2640          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2641          {
2642             if(first) strcat(className, "<");
2643             if(!first) strcat(className, ", ");
2644             if(lastParam + 1 != p)
2645             {
2646                strcat(className, param.name);
2647                strcat(className, " = ");
2648             }
2649             strcat(className, param.name);
2650             first = false;
2651             lastParam = p;
2652          }
2653          p++;
2654       }
2655       if(!first)
2656       {
2657          int len = strlen(className);
2658          if(className[len-1] == '>') className[len++] = ' ';
2659          className[len++] = '>';
2660          className[len++] = '\0';
2661       }
2662       return CopyString(className);
2663    }
2664    else
2665       return CopyString(_class.fullName);
2666 }
2667
2668 Type ReplaceThisClassType(Class _class)
2669 {
2670    if(thisClassParams && _class.templateParams.count && !_class.templateClass)
2671    {
2672       bool first = true;
2673       int p = 0;
2674       ClassTemplateParameter param;
2675       int lastParam = -1;
2676       char className[1024];
2677       strcpy(className, _class.fullName);
2678
2679       for(param = _class.templateParams.first; param; param = param.next)
2680       {
2681          // if((!param.defaultArg.dataTypeString && !param.defaultArg.expression.ui64))
2682          {
2683             if(first) strcat(className, "<");
2684             if(!first) strcat(className, ", ");
2685             if(lastParam + 1 != p)
2686             {
2687                strcat(className, param.name);
2688                strcat(className, " = ");
2689             }
2690             strcat(className, param.name);
2691             first = false;
2692             lastParam = p;
2693          }
2694          p++;
2695       }
2696       if(!first)
2697       {
2698          int len = strlen(className);
2699          if(className[len-1] == '>') className[len++] = ' ';
2700          className[len++] = '>';
2701          className[len++] = '\0';
2702       }
2703       return MkClassType(className);
2704       //return ProcessTypeString(className, false);
2705    }
2706    else
2707    {
2708       return MkClassType(_class.fullName);
2709       //return ProcessTypeString(_class.fullName, false);
2710    }
2711 }
2712
2713 void ReplaceThisClassSpecifiers(OldList specs, Class _class)
2714 {
2715    if(specs != null && _class)
2716    {
2717       Specifier spec;
2718       for(spec = specs.first; spec; spec = spec.next)
2719       {
2720          if(spec.type == baseSpecifier && spec.specifier == THISCLASS)
2721          {
2722             spec.type = nameSpecifier;
2723             spec.name = ReplaceThisClass(_class);
2724             spec.symbol = FindClass(spec.name); //_class.symbol;
2725          }
2726       }
2727    }
2728 }
2729
2730 // Returns imported or not
2731 bool DeclareFunction(GlobalFunction function, char * name)
2732 {
2733    Symbol symbol = function.symbol;
2734    if(curExternal && (!symbol || symbol.id > curExternal.symbol.idCode))
2735    {
2736       bool imported = false;
2737       bool dllImport = false;
2738
2739       if(!function.dataType)
2740       {
2741          function.dataType = ProcessTypeString(function.dataTypeString, false);
2742          if(!function.dataType.thisClass)
2743             function.dataType.staticMethod = true;
2744       }
2745
2746       if(inCompiler)
2747       {
2748          if(!symbol)
2749          {
2750             ModuleImport module = FindModule(function.module);
2751             // WARNING: This is not added anywhere...
2752             symbol = function.symbol = Symbol {  };
2753
2754             if(module.name)
2755             {
2756                if(!function.dataType.dllExport)
2757                {
2758                   symbol._import = (ClassImport)FunctionImport { name = CopyString(function.name) };
2759                   module.functions.Add(symbol._import);
2760                }
2761             }
2762             // Set the symbol type
2763             {
2764                symbol.type = ProcessTypeString(function.dataTypeString, false);
2765                if(!symbol.type.thisClass)
2766                   symbol.type.staticMethod = true;
2767             }
2768          }
2769          imported = symbol._import ? true : false;
2770          if(imported && function.module != privateModule && function.module.importType != staticImport)
2771             dllImport = true;
2772       }
2773
2774       DeclareType(function.dataType, true, true);
2775
2776       if(inCompiler)
2777       {
2778          if(!symbol.pointerExternal || symbol.pointerExternal.type == functionExternal)
2779          {
2780             // We need a declaration here :)
2781             Declaration decl;
2782             OldList * specifiers, * declarators;
2783             Declarator d;
2784             Declarator funcDecl;
2785             External external;
2786
2787             specifiers = MkList();
2788             declarators = MkList();
2789
2790             //if(imported)
2791                ListAdd(specifiers, MkSpecifier(EXTERN));
2792             /*
2793             else
2794                ListAdd(specifiers, MkSpecifier(STATIC));
2795             */
2796
2797             d = MkDeclaratorIdentifier(MkIdentifier(imported ? name : function.name));
2798             //if(imported)
2799             if(dllImport)
2800                d = MkDeclaratorBrackets(MkDeclaratorPointer(MkPointer(null, null), d));
2801
2802             d = SpecDeclFromString(function.dataTypeString, specifiers, d);
2803             // TAKE OUT THE DLL EXPORT IF STATICALLY IMPORTED:
2804             if(function.module.importType == staticImport)
2805             {
2806                Specifier spec;
2807                for(spec = specifiers->first; spec; spec = spec.next)
2808                   if(spec.type == extendedSpecifier && spec.extDecl && spec.extDecl.type == extDeclString && !strcmp(spec.extDecl.s, "dllexport"))
2809                   {
2810                      specifiers->Remove(spec);
2811                      FreeSpecifier(spec);
2812                      break;
2813                   }
2814             }
2815
2816             funcDecl = GetFuncDecl(d);
2817
2818             // Make sure we don't have empty parameter declarations for static methods...
2819             if(funcDecl && !funcDecl.function.parameters)
2820             {
2821                funcDecl.function.parameters = MkList();
2822                funcDecl.function.parameters->Insert(null,
2823                   MkTypeName(MkListOne(MkSpecifier(VOID)),null));
2824             }
2825
2826             ListAdd(declarators, MkInitDeclarator(d, null));
2827
2828             {
2829                Context oldCtx = curContext;
2830                curContext = globalContext;
2831                decl = MkDeclaration(specifiers, declarators);
2832                curContext = oldCtx;
2833             }
2834
2835             // Keep a different symbol for the function definition than the declaration...
2836             if(symbol.pointerExternal)
2837             {
2838                Symbol functionSymbol { };
2839                // Copy symbol
2840                {
2841                   *functionSymbol = *symbol;
2842                   functionSymbol.string = CopyString(symbol.string);
2843                   if(functionSymbol.type)
2844                      functionSymbol.type.refCount++;
2845                }
2846
2847                excludedSymbols->Add(functionSymbol);
2848
2849                symbol.pointerExternal.symbol = functionSymbol;
2850             }
2851             external = MkExternalDeclaration(decl);
2852             if(curExternal)
2853                ast->Insert(curExternal.prev, external);
2854             external.symbol = symbol;
2855             symbol.pointerExternal = external;
2856          }
2857          else
2858          {
2859             // Move declaration higher...
2860             ast->Move(symbol.pointerExternal, curExternal.prev);
2861          }
2862
2863          if(curExternal)
2864             symbol.id = curExternal.symbol.idCode;
2865       }
2866    }
2867    return (symbol && symbol._import && function.module != privateModule && function.module.importType != staticImport) ? true : false;
2868 }
2869
2870 void DeclareGlobalData(GlobalData data)
2871 {
2872    Symbol symbol = data.symbol;
2873    if(curExternal && (!symbol || symbol.id > curExternal.symbol.idCode))
2874    {
2875       if(inCompiler)
2876       {
2877          if(!symbol)
2878             symbol = data.symbol = Symbol { };
2879       }
2880       if(!data.dataType)
2881          data.dataType = ProcessTypeString(data.dataTypeString, false);
2882       DeclareType(data.dataType, true, true);
2883       if(inCompiler)
2884       {
2885          if(!symbol.pointerExternal)
2886          {
2887             // We need a declaration here :)
2888             Declaration decl;
2889             OldList * specifiers, * declarators;
2890             Declarator d;
2891             External external;
2892
2893             specifiers = MkList();
2894             declarators = MkList();
2895
2896             ListAdd(specifiers, MkSpecifier(EXTERN));
2897             d = MkDeclaratorIdentifier(MkIdentifier(data.fullName));
2898             d = SpecDeclFromString(data.dataTypeString, specifiers, d);
2899
2900             ListAdd(declarators, MkInitDeclarator(d, null));
2901
2902             decl = MkDeclaration(specifiers, declarators);
2903             external = MkExternalDeclaration(decl);
2904             if(curExternal)
2905                ast->Insert(curExternal.prev, external);
2906             external.symbol = symbol;
2907             symbol.pointerExternal = external;
2908          }
2909          else
2910          {
2911             // Move declaration higher...
2912             ast->Move(symbol.pointerExternal, curExternal.prev);
2913          }
2914
2915          if(curExternal)
2916             symbol.id = curExternal.symbol.idCode;
2917       }
2918    }
2919 }
2920
2921 class Conversion : struct
2922 {
2923    Conversion prev, next;
2924    Property convert;
2925    bool isGet;
2926    Type resultType;
2927 };
2928
2929 static bool CheckConstCompatibility(Type source, Type dest, bool warn)
2930 {
2931    bool status = true;
2932    if(((source.kind == classType && source._class && source._class.registered) || source.kind == arrayType || source.kind == pointerType) &&
2933       ((dest.kind == classType && dest._class && dest._class.registered) || /*dest.kind == arrayType || */dest.kind == pointerType))
2934    {
2935       Class sourceClass = source.kind == classType ? source._class.registered : null;
2936       Class destClass = dest.kind == classType ? dest._class.registered : null;
2937       if((!sourceClass || (sourceClass && sourceClass.type == normalClass && !sourceClass.structSize)) &&
2938          (!destClass || (destClass && destClass.type == normalClass && !destClass.structSize)))
2939       {
2940          Type sourceType = source, destType = dest;
2941          while((sourceType.kind == pointerType || sourceType.kind == arrayType) && sourceType.type) sourceType = sourceType.type;
2942          while((destType.kind == pointerType || destType.kind == arrayType) && destType.type) destType = destType.type;
2943          if(!destType.constant && sourceType.constant)
2944          {
2945             status = false;
2946             if(warn)
2947                Compiler_Warning($"discarding const qualifier\n");
2948          }
2949       }
2950    }
2951    return status;
2952 }
2953
2954 public bool MatchTypes(Type source, Type dest, OldList conversions, Class owningClassSource, Class owningClassDest, bool doConversion, bool enumBaseType, bool acceptReversedParams,
2955                        bool isConversionExploration, bool warnConst)
2956 {
2957    if(source && dest)
2958    {
2959       if(warnConst)
2960          CheckConstCompatibility(source, dest, true);
2961       // Property convert;
2962
2963       if(source.kind == templateType && dest.kind != templateType)
2964       {
2965          Type type = ProcessTemplateParameterType(source.templateParameter);
2966          if(type) source = type;
2967       }
2968
2969       if(dest.kind == templateType && source.kind != templateType)
2970       {
2971          Type type = ProcessTemplateParameterType(dest.templateParameter);
2972          if(type) dest = type;
2973       }
2974
2975       if(dest.classObjectType == typedObject && dest.kind != functionType)
2976       {
2977          if(source.classObjectType != anyObject)
2978             return true;
2979          else
2980          {
2981             // If either the source or the destination defines the class, accepts any_object as compatible for a typed_object
2982             if((dest._class && strcmp(dest._class.string, "class")) || (source._class && strcmp(source._class.string, "class")))
2983             {
2984                return true;
2985             }
2986          }
2987       }
2988       else
2989       {
2990          if(source.kind != functionType && source.classObjectType == anyObject)
2991             return true;
2992          if(dest.kind != functionType && dest.classObjectType == anyObject && source.classObjectType != typedObject)
2993             return true;
2994       }
2995
2996       if((dest.kind == structType && source.kind == structType) ||
2997          (dest.kind == unionType && source.kind == unionType))
2998       {
2999          if((dest.enumName && source.enumName && !strcmp(dest.enumName, source.enumName)) ||
3000              (source.members.first && source.members.first == dest.members.first))
3001             return true;
3002       }
3003
3004       if(dest.kind == ellipsisType && source.kind != voidType)
3005          return true;
3006
3007       if(dest.kind == pointerType && dest.type.kind == voidType &&
3008          ((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))
3009          || source.kind == subClassType || source.kind == pointerType || source.kind == arrayType || source.kind == functionType || source.kind == thisClassType)
3010
3011          /*source.kind != voidType && source.kind != structType && source.kind != unionType  */
3012
3013          /*&& (source.kind != classType /-*|| source._class.registered.type != structClass)*/)
3014          return true;
3015       if(!isConversionExploration && source.kind == pointerType && source.type.kind == voidType &&
3016          ((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))
3017          || dest.kind == subClassType || dest.kind == pointerType || dest.kind == arrayType || dest.kind == functionType || dest.kind == thisClassType)
3018          /* dest.kind != voidType && dest.kind != structType && dest.kind != unionType  */
3019
3020          /*&& (dest.kind != classType || dest._class.registered.type != structClass)*/)
3021          return true;
3022
3023       if(((source.kind == classType && dest.kind == classType) || (source.kind == subClassType && dest.kind == subClassType)) && source._class)
3024       {
3025          if(source._class.registered && source._class.registered.type == unitClass)
3026          {
3027             if(conversions != null)
3028             {
3029                if(source._class.registered == dest._class.registered)
3030                   return true;
3031             }
3032             else
3033             {
3034                Class sourceBase, destBase;
3035                for(sourceBase = source._class.registered; sourceBase && sourceBase.base.type != systemClass; sourceBase = sourceBase.base);
3036                for(destBase = dest._class.registered; destBase && destBase.base.type != systemClass; destBase = destBase.base);
3037                if(sourceBase == destBase)
3038                   return true;
3039             }
3040          }
3041          // Don't match enum inheriting from other enum if resolving enumeration values
3042          // TESTING: !dest.classObjectType
3043          else if(source._class && dest._class && (dest.classObjectType == source.classObjectType || !dest.classObjectType) &&
3044             (enumBaseType ||
3045                (!source._class.registered || source._class.registered.type != enumClass) ||
3046                (!dest._class.registered || dest._class.registered.type != enumClass)) && eClass_IsDerived(source._class.registered, dest._class.registered))
3047             return true;
3048          else
3049          {
3050             // Added this so that DefinedColor = Color doesn't go through ColorRGB property
3051             if(enumBaseType &&
3052                dest._class && dest._class.registered && dest._class.registered.type == enumClass &&
3053                ((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)
3054             {
3055                if(eClass_IsDerived(dest._class.registered, source._class.registered))
3056                {
3057                   return true;
3058                }
3059             }
3060          }
3061       }
3062
3063       // JUST ADDED THIS...
3064       if(source.kind == subClassType && dest.kind == classType && dest._class && !strcmp(dest._class.string, "ecere::com::Class"))
3065          return true;
3066
3067       if(doConversion)
3068       {
3069          // Just added this for Straight conversion of ColorAlpha => Color
3070          if(source.kind == classType)
3071          {
3072             Class _class;
3073             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3074             {
3075                Property convert;
3076                for(convert = _class.conversions.first; convert; convert = convert.next)
3077                {
3078                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3079                   {
3080                      Conversion after = (conversions != null) ? conversions.last : null;
3081
3082                      if(!convert.dataType)
3083                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3084                      // Only go ahead with this conversion flow while processing an existing conversion if the conversion data type is a class
3085                      if((!isConversionExploration || convert.dataType.kind == classType || !strcmp(_class.name, "String")) &&
3086                         MatchTypes(convert.dataType, dest, conversions, null, null,
3087                            (convert.dataType.kind == classType && !strcmp(convert.dataTypeString, "String")) ? true : false,
3088                               convert.dataType.kind == classType, false, true, warnConst))
3089                      {
3090                         if(!conversions && !convert.Get)
3091                            return true;
3092                         else if(conversions != null)
3093                         {
3094                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3095                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3096                               (dest.kind != classType || dest._class.registered != _class.base))
3097                               return true;
3098                            else
3099                            {
3100                               Conversion conv { convert = convert, isGet = true };
3101                               // conversions.Add(conv);
3102                               conversions.Insert(after, conv);
3103
3104                               return true;
3105                            }
3106                         }
3107                      }
3108                   }
3109                }
3110             }
3111          }
3112
3113          // MOVING THIS??
3114
3115          if(dest.kind == classType)
3116          {
3117             Class _class;
3118             for(_class = dest._class ? dest._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                      Type constType = null;
3126                      bool success = false;
3127                      // Conversion after = (conversions != null) ? conversions.last : null;
3128
3129                      if(!convert.dataType)
3130                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3131
3132                      if(warnConst && convert.dataType.kind == pointerType && convert.dataType.type && dest.constant)
3133                      {
3134                         Type ptrType { };
3135                         constType = { kind = pointerType, refCount = 1, type = ptrType };
3136                         CopyTypeInto(ptrType, convert.dataType.type);
3137                         ptrType.refCount++;
3138                         ptrType.constant = true;
3139                      }
3140
3141                      // Just added this equality check to prevent recursion.... Make it safer?
3142                      // Changed enumBaseType to false here to prevent all int-compatible enums to show up in AnchorValues
3143                      if((constType || convert.dataType != dest) && MatchTypes(source, constType ? constType : convert.dataType, conversions, null, null, true, false /*true*/, false, true, warnConst))
3144                      {
3145                         if(!conversions && !convert.Set)
3146                            success = true;
3147                         else if(conversions != null)
3148                         {
3149                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3150                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3151                               (source.kind != classType || source._class.registered != _class.base))
3152                               success = true;
3153                            else
3154                            {
3155                               // *** Testing this! ***
3156                               Conversion conv { convert = convert };
3157                               conversions.Add(conv);
3158                               //conversions.Insert(after, conv);
3159                               success = true;
3160                            }
3161                         }
3162                      }
3163                      if(success)
3164                         return true;
3165                      if(constType)
3166                         FreeType(constType);
3167                   }
3168                }
3169             }
3170             /*if(dest._class.registered && !strcmp(dest._class.registered.name, "bool"))
3171             {
3172                if(source.kind != voidType && source.kind != structType && source.kind != unionType &&
3173                   (source.kind != classType || source._class.registered.type != structClass))
3174                   return true;
3175             }*/
3176
3177             // TESTING THIS... IS THIS OK??
3178             if(enumBaseType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3179             {
3180                if(!dest._class.registered.dataType)
3181                   dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3182                // Only support this for classes...
3183                if(dest._class.registered.dataType.kind == classType || source.truth || dest.truth/* ||
3184                   !strcmp(dest._class.registered.name, "bool") || (source.kind == classType && !strcmp(source._class.string, "bool"))*/)
3185                {
3186                   if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, dest._class.registered.dataType.kind == classType, false, false, warnConst))
3187                   {
3188                      return true;
3189                   }
3190                }
3191             }
3192          }
3193
3194          // Moved this lower
3195          if(source.kind == classType)
3196          {
3197             Class _class;
3198             for(_class = source._class ? source._class.registered : null; _class; _class = _class.base)
3199             {
3200                Property convert;
3201                for(convert = _class.conversions.first; convert; convert = convert.next)
3202                {
3203                   if(convert.memberAccess == publicAccess || _class.module == privateModule)
3204                   {
3205                      Conversion after = (conversions != null) ? conversions.last : null;
3206
3207                      if(!convert.dataType)
3208                         convert.dataType = ProcessTypeString(convert.dataTypeString, false);
3209                      if(convert.dataType != source &&
3210                         (!isConversionExploration || convert.dataType.kind == classType || !strcmp(_class.name, "String")) &&
3211                         MatchTypes(convert.dataType, dest, conversions, null, null, convert.dataType.kind == classType, convert.dataType.kind == classType, false, true, warnConst))
3212                      {
3213                         if(!conversions && !convert.Get)
3214                            return true;
3215                         else if(conversions != null)
3216                         {
3217                            if(_class.type == unitClass && convert.dataType.kind == classType && convert.dataType._class &&
3218                               convert.dataType._class.registered && _class.base == convert.dataType._class.registered.base &&
3219                               (dest.kind != classType || dest._class.registered != _class.base))
3220                               return true;
3221                            else
3222                            {
3223                               Conversion conv { convert = convert, isGet = true };
3224
3225                               // conversions.Add(conv);
3226                               conversions.Insert(after, conv);
3227                               return true;
3228                            }
3229                         }
3230                      }
3231                   }
3232                }
3233             }
3234
3235             // TESTING THIS... IS THIS OK??
3236             if(enumBaseType && source._class && source._class.registered && source._class.registered.type == enumClass)
3237             {
3238                if(!source._class.registered.dataType)
3239                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3240                if(!isConversionExploration || source._class.registered.dataType.kind == classType || !strcmp(source._class.registered.name, "String"))
3241                {
3242                   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))
3243                      return true;
3244                   // For bool to be accepted by byte, short, etc.
3245                   else if(MatchTypes(dest, source._class.registered.dataType, null, null, null, false, false, false, false, warnConst))
3246                      return true;
3247                }
3248             }
3249          }
3250       }
3251
3252       if(source.kind == classType || source.kind == subClassType)
3253          ;
3254       else if(dest.kind == source.kind &&
3255          (dest.kind != structType && dest.kind != unionType &&
3256           dest.kind != functionType && dest.kind != arrayType && dest.kind != pointerType && dest.kind != methodType))
3257           return true;
3258       // RECENTLY ADDED THESE
3259       else if(dest.kind == doubleType && source.kind == floatType)
3260          return true;
3261       else if(dest.kind == shortType && (source.kind == charType || source.kind == _BoolType))
3262          return true;
3263       else if(dest.kind == intType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intSizeType /* Exception here for size_t */))
3264          return true;
3265       else if(dest.kind == int64Type && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intPtrType || source.kind == intSizeType))
3266          return true;
3267       else if(dest.kind == intPtrType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intSizeType || source.kind == int64Type))
3268          return true;
3269       else if(dest.kind == intSizeType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == int64Type || source.kind == intPtrType))
3270          return true;
3271       else if(source.kind == enumType &&
3272          (dest.kind == intType || dest.kind == shortType || dest.kind == charType || source.kind == _BoolType || dest.kind == longType || dest.kind == int64Type || dest.kind == intPtrType || dest.kind == intSizeType))
3273           return true;
3274       else if(dest.kind == enumType && !isConversionExploration &&
3275          (source.kind == intType || source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == longType || source.kind == int64Type || source.kind == intPtrType || source.kind == intSizeType))
3276           return true;
3277       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) &&
3278               ((source.kind == functionType || (source.kind == pointerType && source.type.kind == functionType) || source.kind == methodType)))
3279       {
3280          Type paramSource, paramDest;
3281
3282          if(dest.kind == methodType)
3283             owningClassDest = dest.methodClass ? dest.methodClass : dest.method._class;
3284          if(source.kind == methodType)
3285             owningClassSource = source.methodClass ? source.methodClass : source.method._class;
3286
3287          if(dest.kind == pointerType && dest.type.kind == functionType) dest = dest.type;
3288          if(source.kind == pointerType && source.type.kind == functionType) source = source.type;
3289          if(dest.kind == methodType)
3290             dest = dest.method.dataType;
3291          if(source.kind == methodType)
3292             source = source.method.dataType;
3293
3294          paramSource = source.params.first;
3295          if(paramSource && paramSource.kind == voidType) paramSource = null;
3296          paramDest = dest.params.first;
3297          if(paramDest && paramDest.kind == voidType) paramDest = null;
3298
3299
3300          if((dest.staticMethod || (!dest.thisClass && !owningClassDest)) &&
3301             !(source.staticMethod || (!source.thisClass && !owningClassSource)))
3302          {
3303             // Source thisClass must be derived from destination thisClass
3304             if(!paramDest || (!(paramDest.kind == pointerType && paramDest.type && paramDest.type.kind == voidType) && (paramDest.kind != classType ||
3305                !eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource,paramDest._class.registered))))
3306             {
3307                if(paramDest && paramDest.kind == classType)
3308                   Compiler_Error($"method class must be derived from %s\n", paramDest._class.string);
3309                else
3310                   Compiler_Error($"method class should not take an object\n");
3311                return false;
3312             }
3313             paramDest = paramDest.next;
3314          }
3315          else if(!dest.staticMethod && (dest.thisClass || owningClassDest))
3316          {
3317             if((source.staticMethod || (!source.thisClass && !owningClassSource)))
3318             {
3319                if(dest.thisClass)
3320                {
3321                   if(!paramSource || paramSource.kind != classType || !eClass_IsDerived(paramSource._class.registered,dest.thisClass.registered))
3322                   {
3323                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3324                      return false;
3325                   }
3326                }
3327                else
3328                {
3329                   // THIS WAS BACKWARDS:
3330                   // if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(owningClassDest, paramSource._class.registered)))
3331                   if(!paramSource || paramSource.kind != classType || (owningClassDest && !eClass_IsDerived(paramSource._class.registered, owningClassDest)))
3332                   {
3333                      if(owningClassDest)
3334                        Compiler_Error($"%s expected to be derived from method class\n", owningClassDest.fullName);
3335                      else
3336                         Compiler_Error($"overriding class expected to be derived from method class\n");
3337                      return false;
3338                   }
3339                }
3340                paramSource = paramSource.next;
3341             }
3342             else
3343             {
3344                if(dest.thisClass)
3345                {
3346                   // Source thisClass must be derived from destination thisClass
3347                   if(!eClass_IsDerived(source.thisClass ? source.thisClass.registered : owningClassSource, dest.thisClass.registered))
3348                   {
3349                      Compiler_Error($"method class must be derived from %s\n", dest.thisClass.string);
3350                      return false;
3351                   }
3352                }
3353                else
3354                {
3355                   // THIS WAS BACKWARDS TOO??
3356                   // if(source.thisClass && owningClassDest && !eClass_IsDerived(owningClassDest, source.thisClass.registered))
3357                   if(source.thisClass && source.thisClass.registered && owningClassDest && !eClass_IsDerived(source.thisClass.registered, owningClassDest))
3358                   {
3359                      //if(owningClass)
3360                         Compiler_Error($"%s expected to be derived from method class\n", /*owningClass.name*/ source.thisClass.registered.fullName);
3361                      //else
3362                         //Compiler_Error($"overriding class expected to be derived from method class\n");
3363                      return false;
3364                   }
3365                }
3366             }
3367          }
3368
3369
3370          // Source return type must be derived from destination return type
3371          if(!MatchTypes(source.returnType, dest.returnType, null, null, null, true, true, false, false, warnConst))
3372          {
3373             Compiler_Warning($"incompatible return type for function\n");
3374             return false;
3375          }
3376          // The const check is backwards from the MatchTypes above (for derivative classes checks)
3377          else
3378             CheckConstCompatibility(dest.returnType, source.returnType, true);
3379
3380          // Check parameters
3381
3382          for(; paramDest; paramDest = paramDest.next)
3383          {
3384             if(!paramSource)
3385             {
3386                //Compiler_Warning($"not enough parameters\n");
3387                Compiler_Error($"not enough parameters\n");
3388                return false;
3389             }
3390             {
3391                Type paramDestType = paramDest;
3392                Type paramSourceType = paramSource;
3393                Type type = paramDestType;
3394
3395                // *** WORKING CODE: TESTING THIS HERE FOR TEMPLATES ***
3396                if(paramDest.kind == templateType && paramDest.templateParameter.type == TemplateParameterType::type && owningClassSource &&
3397                   paramSource.kind != templateType)
3398                {
3399                   int id = 0;
3400                   ClassTemplateParameter curParam = null;
3401                   Class sClass;
3402                   for(sClass = owningClassSource; sClass; sClass = sClass.base)
3403                   {
3404                      id = 0;
3405                      if(sClass.templateClass) sClass = sClass.templateClass;
3406                      for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
3407                      {
3408                         if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
3409                         {
3410                            for(sClass = sClass.base; sClass; sClass = sClass.base)
3411                            {
3412                               if(sClass.templateClass) sClass = sClass.templateClass;
3413                               id += sClass.templateParams.count;
3414                            }
3415                            break;
3416                         }
3417                         id++;
3418                      }
3419                      if(curParam) break;
3420                   }
3421
3422                   if(curParam)
3423                   {
3424                      ClassTemplateArgument arg = owningClassSource.templateArgs[id];
3425                      paramDestType = type = ProcessTypeString(arg.dataTypeString, false);
3426                   }
3427                }
3428
3429                // paramDest must be derived from paramSource
3430                if(!MatchTypes(paramDestType, paramSourceType, null, null, null, true, true, false, false, warnConst) &&
3431                   (!acceptReversedParams || !MatchTypes(paramSourceType, paramDestType, null, null, null, true, true, false, false, warnConst)))
3432                {
3433                   char type[1024];
3434                   type[0] = 0;
3435                   PrintType(paramDest, type, false, true);
3436                   Compiler_Warning($"incompatible parameter %s (expected %s)\n", paramSource.name, type);
3437
3438                   if(paramDestType != paramDest)
3439                      FreeType(paramDestType);
3440                   return false;
3441                }
3442                if(paramDestType != paramDest)
3443                   FreeType(paramDestType);
3444             }
3445
3446             paramSource = paramSource.next;
3447          }
3448          if(paramSource)
3449          {
3450             Compiler_Error($"too many parameters\n");
3451             return false;
3452          }
3453          return true;
3454       }
3455       else if((dest.kind == functionType || (dest.kind == pointerType && dest.type.kind == functionType) || dest.kind == methodType) && (source.kind == pointerType && source.type.kind == voidType))
3456       {
3457          return true;
3458       }
3459       else if((dest.kind == pointerType || dest.kind == arrayType) &&
3460          (source.kind == arrayType || source.kind == pointerType))
3461       {
3462          if(MatchTypes(source.type, dest.type, null, null, null, true, true, false, false, warnConst))
3463             return true;
3464       }
3465    }
3466    return false;
3467 }
3468
3469 static void FreeConvert(Conversion convert)
3470 {
3471    if(convert.resultType)
3472       FreeType(convert.resultType);
3473 }
3474
3475 bool MatchWithEnums_NameSpace(NameSpace nameSpace, Expression sourceExp, Type dest,
3476                               char * string, OldList conversions)
3477 {
3478    BTNamedLink link;
3479
3480    for(link = (BTNamedLink)nameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
3481    {
3482       Class _class = link.data;
3483       if(_class.type == enumClass)
3484       {
3485          OldList converts { };
3486          Type type { };
3487          type.kind = classType;
3488
3489          if(!_class.symbol)
3490             _class.symbol = FindClass(_class.fullName);
3491          type._class = _class.symbol;
3492
3493          if(MatchTypes(type, dest, &converts, null, null, true, false, false, false, false))
3494          {
3495             NamedLink value;
3496             Class enumClass = eSystem_FindClass(privateModule, "enum");
3497             if(enumClass)
3498             {
3499                Class baseClass;
3500                for(baseClass = _class ; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
3501                {
3502                   EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
3503                   for(value = e.values.first; value; value = value.next)
3504                   {
3505                      if(!strcmp(value.name, string))
3506                         break;
3507                   }
3508                   if(value)
3509                   {
3510                      FreeExpContents(sourceExp);
3511                      FreeType(sourceExp.expType);
3512
3513                      sourceExp.isConstant = true;
3514                      sourceExp.expType = MkClassType(baseClass.fullName);
3515                      //if(inCompiler)
3516                      {
3517                         char constant[256];
3518                         sourceExp.type = constantExp;
3519                         if(!strcmp(baseClass.dataTypeString, "int"))
3520                            sprintf(constant, "%d",(int)value.data);
3521                         else
3522                            sprintf(constant, "0x%X",(int)value.data);
3523                         sourceExp.constant = CopyString(constant);
3524                         //for(;baseClass.base && baseClass.base.type != systemClass; baseClass = baseClass.base);
3525                      }
3526
3527                      while(converts.first)
3528                      {
3529                         Conversion convert = converts.first;
3530                         converts.Remove(convert);
3531                         conversions.Add(convert);
3532                      }
3533                      delete type;
3534                      return true;
3535                   }
3536                }
3537             }
3538          }
3539          if(converts.first)
3540             converts.Free(FreeConvert);
3541          delete type;
3542       }
3543    }
3544    for(nameSpace = (NameSpace *)nameSpace.nameSpaces.first; nameSpace != null; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
3545       if(MatchWithEnums_NameSpace(nameSpace, sourceExp, dest, string, conversions))
3546          return true;
3547    return false;
3548 }
3549
3550 public bool ModuleVisibility(Module searchIn, Module searchFor)
3551 {
3552    SubModule subModule;
3553
3554    if(searchFor == searchIn)
3555       return true;
3556
3557    for(subModule = searchIn.modules.first; subModule; subModule = subModule.next)
3558    {
3559       if(subModule.importMode == publicAccess || searchIn == searchIn.application)
3560       {
3561          if(ModuleVisibility(subModule.module, searchFor))
3562             return true;
3563       }
3564    }
3565    return false;
3566 }
3567
3568 bool MatchWithEnums_Module(Module mainModule, Expression sourceExp, Type dest, char * string, OldList conversions)
3569 {
3570    Module module;
3571
3572    if(MatchWithEnums_NameSpace(mainModule.application.systemNameSpace, sourceExp, dest, string, conversions))
3573       return true;
3574    if(MatchWithEnums_NameSpace(mainModule.application.privateNameSpace, sourceExp, dest, string, conversions))
3575       return true;
3576    if(MatchWithEnums_NameSpace(mainModule.application.publicNameSpace, sourceExp, dest, string, conversions))
3577       return true;
3578
3579    for(module = mainModule.application.allModules.first; module; module = module.next)
3580    {
3581       if(ModuleVisibility(mainModule, module) && MatchWithEnums_NameSpace(module.publicNameSpace, sourceExp, dest, string, conversions))
3582          return true;
3583    }
3584    return false;
3585 }
3586
3587 bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, bool skipUnitBla, bool warnConst)
3588 {
3589    Type source;
3590    Type realDest = dest;
3591    Type backupSourceExpType = null;
3592    Expression computedExp = sourceExp;
3593    dest.refCount++;
3594
3595    if(sourceExp.isConstant && sourceExp.type != constantExp && sourceExp.type != identifierExp && sourceExp.type != castExp &&
3596       dest.kind == classType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
3597    {
3598       computedExp = CopyExpression(sourceExp);        // Keep the original expression, but compute for checking enum ranges
3599       ComputeExpression(computedExp /*sourceExp*/);
3600    }
3601
3602    source = sourceExp.expType;
3603
3604    if(dest.kind == pointerType && sourceExp.type == constantExp && !strtoul(sourceExp.constant, null, 0))
3605    {
3606       if(computedExp != sourceExp)
3607       {
3608          FreeExpression(computedExp);
3609          computedExp = sourceExp;
3610       }
3611       FreeType(dest);
3612       return true;
3613    }
3614
3615    if(!skipUnitBla && source && dest && source.kind == classType && dest.kind == classType)
3616    {
3617        if(source._class && source._class.registered && source._class.registered.type == unitClass)
3618        {
3619           Class sourceBase, destBase;
3620           for(sourceBase = source._class.registered;
3621               sourceBase && sourceBase.base && sourceBase.base.type != systemClass;
3622               sourceBase = sourceBase.base);
3623           for(destBase = dest._class.registered;
3624               destBase && destBase.base && destBase.base.type != systemClass;
3625               destBase = destBase.base);
3626           //if(source._class.registered == dest._class.registered)
3627           if(sourceBase == destBase)
3628           {
3629             if(computedExp != sourceExp)
3630             {
3631                FreeExpression(computedExp);
3632                computedExp = sourceExp;
3633             }
3634             FreeType(dest);
3635             return true;
3636          }
3637       }
3638    }
3639
3640    if(source)
3641    {
3642       OldList * specs;
3643       bool flag = false;
3644       int64 value = MAXINT;
3645
3646       source.refCount++;
3647
3648       if(computedExp.type == constantExp)
3649       {
3650          if(source.isSigned)
3651             value = strtoll(computedExp.constant, null, 0);
3652          else
3653             value = strtoull(computedExp.constant, null, 0);
3654       }
3655       else if(computedExp.type == opExp && sourceExp.op.op == '-' && !computedExp.op.exp1 && computedExp.op.exp2 && computedExp.op.exp2.type == constantExp)
3656       {
3657          if(source.isSigned)
3658             value = -strtoll(computedExp.op.exp2.constant, null, 0);
3659          else
3660             value = -strtoull(computedExp.op.exp2.constant, null, 0);
3661       }
3662       if(computedExp != sourceExp)
3663       {
3664          FreeExpression(computedExp);
3665          computedExp = sourceExp;
3666       }
3667
3668       if(dest.kind != classType && source.kind == classType && source._class && source._class.registered &&
3669          !strcmp(source._class.registered.fullName, "ecere::com::unichar"))
3670       {
3671          FreeType(source);
3672          source = Type { kind = intType, isSigned = false, refCount = 1 };
3673       }
3674
3675       if(dest.kind == classType)
3676       {
3677          Class _class = dest._class ? dest._class.registered : null;
3678
3679          if(_class && _class.type == unitClass)
3680          {
3681             if(source.kind != classType)
3682             {
3683                Type tempType { };
3684                Type tempDest, tempSource;
3685
3686                for(; _class.base.type != systemClass; _class = _class.base);
3687                tempSource = dest;
3688                tempDest = tempType;
3689
3690                tempType.kind = classType;
3691                if(!_class.symbol)
3692                   _class.symbol = FindClass(_class.fullName);
3693
3694                tempType._class = _class.symbol;
3695                tempType.truth = dest.truth;
3696                if(tempType._class)
3697                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false, warnConst);
3698
3699                // NOTE: To handle bad warnings on int64 vs 32 bit eda::Id incompatibilities
3700                backupSourceExpType = sourceExp.expType;
3701                sourceExp.expType = dest; dest.refCount++;
3702                //sourceExp.expType = MkClassType(_class.fullName);
3703                flag = true;
3704
3705                delete tempType;
3706             }
3707          }
3708
3709
3710          // Why wasn't there something like this?
3711          if(_class && _class.type == bitClass && source.kind != classType)
3712          {
3713             if(!dest._class.registered.dataType)
3714                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3715             if(MatchTypes(source, dest._class.registered.dataType, conversions, null, null, true, true, false, false, warnConst))
3716             {
3717                FreeType(source);
3718                FreeType(sourceExp.expType);
3719                source = sourceExp.expType = MkClassType(dest._class.string);
3720                source.refCount++;
3721
3722                //source.kind = classType;
3723                //source._class = dest._class;
3724             }
3725          }
3726
3727          // Adding two enumerations
3728          /*
3729          if(_class && _class.type == enumClass && source.kind == classType && source._class && source._class.registered && source._class.registered.type == enumClass)
3730          {
3731             if(!source._class.registered.dataType)
3732                source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3733             if(!dest._class.registered.dataType)
3734                dest._class.registered.dataType = ProcessTypeString(dest._class.registered.dataTypeString, false);
3735
3736             if(MatchTypes(source._class.registered.dataType, dest._class.registered.dataType, conversions, null, null, true, false, false))
3737             {
3738                FreeType(source);
3739                source = sourceExp.expType = MkClassType(dest._class.string);
3740                source.refCount++;
3741
3742                //source.kind = classType;
3743                //source._class = dest._class;
3744             }
3745          }*/
3746
3747          if(_class && !strcmp(_class.fullName, "ecere::com::Class") && source.kind == pointerType && source.type && source.type.kind == charType && sourceExp.type == stringExp)
3748          {
3749             OldList * specs = MkList();
3750             Declarator decl;
3751             char string[1024];
3752
3753             ReadString(string, sourceExp.string);
3754             decl = SpecDeclFromString(string, specs, null);
3755
3756             FreeExpContents(sourceExp);
3757             FreeType(sourceExp.expType);
3758
3759             sourceExp.type = classExp;
3760             sourceExp._classExp.specifiers = specs;
3761             sourceExp._classExp.decl = decl;
3762             sourceExp.expType = dest;
3763             dest.refCount++;
3764
3765             FreeType(source);
3766             FreeType(dest);
3767             if(backupSourceExpType) FreeType(backupSourceExpType);
3768             return true;
3769          }
3770       }
3771       else if(source.kind == classType)
3772       {
3773          Class _class = source._class ? source._class.registered : null;
3774
3775          if(_class && (_class.type == unitClass || /*!strcmp(_class.fullName, "bool") || /*_class.type == enumClass || */_class.type == bitClass ))  // TOCHECK: enumClass, bitClass is new here...
3776          {
3777             /*
3778             if(dest.kind != classType)
3779             {
3780                // Testing this simpler piece of code... (Broke Units Conversion to no unit Logic)
3781                if(!source._class.registered.dataType)
3782                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3783
3784                FreeType(dest);
3785                dest = MkClassType(source._class.string);
3786                //if(MatchTypes(source._class.registered.dataType, dest, conversions, null, null, true, false, false))
3787                //   dest = MkClassType(source._class.string);
3788             }
3789             */
3790
3791             if(dest.kind != classType)
3792             {
3793                Type tempType { };
3794                Type tempDest, tempSource;
3795
3796                if(!source._class.registered.dataType)
3797                   source._class.registered.dataType = ProcessTypeString(source._class.registered.dataTypeString, false);
3798
3799                for(; _class.base.type != systemClass; _class = _class.base);
3800                tempDest = source;
3801                tempSource = tempType;
3802                tempType.kind = classType;
3803                tempType._class = FindClass(_class.fullName);
3804                tempType.truth = source.truth;
3805                tempType.classObjectType = source.classObjectType;
3806
3807                if(tempType._class)
3808                   MatchTypes(tempSource, tempDest, conversions, null, null, true, true, false, false, warnConst);
3809
3810                // PUT THIS BACK TESTING UNITS?
3811                if(conversions.last)
3812                {
3813                   ((Conversion)(conversions.last)).resultType = dest;
3814                   dest.refCount++;
3815                }
3816
3817                FreeType(sourceExp.expType);
3818                sourceExp.expType = MkClassType(_class.fullName);
3819                sourceExp.expType.truth = source.truth;
3820                sourceExp.expType.classObjectType = source.classObjectType;
3821
3822                // *** This if was commented out, put it back because "int a =^ Destroy()" shows up bool enum values in autocomplete ***
3823
3824                if(!sourceExp.destType)
3825                {
3826                   FreeType(sourceExp.destType);
3827                   sourceExp.destType = sourceExp.expType;
3828                   if(sourceExp.expType)
3829                      sourceExp.expType.refCount++;
3830                }
3831                //flag = true;
3832                //source = _class.dataType;
3833
3834
3835                // TOCHECK: TESTING THIS NEW CODE
3836                if(!_class.dataType)
3837                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3838                FreeType(dest);
3839                dest = MkClassType(source._class.string);
3840                dest.truth = source.truth;
3841                dest.classObjectType = source.classObjectType;
3842
3843                FreeType(source);
3844                source = _class.dataType;
3845                source.refCount++;
3846
3847                delete tempType;
3848             }
3849          }
3850       }
3851
3852       if(!flag)
3853       {
3854          if(MatchTypes(source, dest, conversions, null, null, true, true, false, false, warnConst))
3855          {
3856             FreeType(source);
3857             FreeType(dest);
3858             return true;
3859          }
3860       }
3861
3862       // Implicit Casts
3863       /*
3864       if(source.kind == classType)
3865       {
3866          Class _class = source._class.registered;
3867          if(_class.type == unitClass)
3868          {
3869             if(!_class.dataType)
3870                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3871             source = _class.dataType;
3872          }
3873       }*/
3874
3875       if(dest.kind == classType)
3876       {
3877          Class _class = dest._class ? dest._class.registered : null;
3878          bool fittingValue = false;
3879          if(_class && _class.type == enumClass)
3880          {
3881             Class enumClass = eSystem_FindClass(privateModule, "enum");
3882             EnumClassData c = ACCESS_CLASSDATA(_class, enumClass);
3883             if(c && value >= 0 && value <= c.largest)
3884                fittingValue = true;
3885          }
3886
3887          if(_class && !dest.truth && (_class.type == unitClass || fittingValue ||
3888             (/*_class.type == enumClass*/_class.type != structClass && !value && source.kind == intType) || _class.type == bitClass))   // TOCHECK: enumClass, bitClass is new here...
3889          {
3890             if(_class.type == normalClass || _class.type == noHeadClass)
3891             {
3892                Expression newExp { };
3893                *newExp = *sourceExp;
3894                if(sourceExp.destType) sourceExp.destType.refCount++;
3895                if(sourceExp.expType)  sourceExp.expType.refCount++;
3896                sourceExp.type = castExp;
3897                sourceExp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, null), null));
3898                sourceExp.cast.exp = newExp;
3899                FreeType(sourceExp.expType);
3900                sourceExp.expType = null;
3901                ProcessExpressionType(sourceExp);
3902
3903                // In Debugger, this helps with addresses (e.g. null pointers) that end up casted to a void *: keeps a classType instead of a pointerType
3904                if(!inCompiler)
3905                {
3906                   FreeType(sourceExp.expType);
3907                   sourceExp.expType = dest;
3908                }
3909
3910                FreeType(source);
3911                if(inCompiler) FreeType(dest);
3912
3913                if(backupSourceExpType) FreeType(backupSourceExpType);
3914                return true;
3915             }
3916
3917             if(!_class.dataType)
3918                _class.dataType = ProcessTypeString(_class.dataTypeString, false);
3919             FreeType(dest);
3920             dest = _class.dataType;
3921             dest.refCount++;
3922          }
3923
3924          // Accept lower precision types for units, since we want to keep the unit type
3925          if(dest.kind == doubleType &&
3926             (source.kind == doubleType || source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType ||
3927              source.kind == charType || source.kind == _BoolType))
3928          {
3929             specs = MkListOne(MkSpecifier(DOUBLE));
3930          }
3931          else if(dest.kind == floatType &&
3932             (source.kind == floatType || dest.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3933             source.kind == _BoolType || source.kind == doubleType))
3934          {
3935             specs = MkListOne(MkSpecifier(FLOAT));
3936          }
3937          else if(dest.kind == int64Type && (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == charType ||
3938             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3939          {
3940             specs = MkList();
3941             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3942             ListAdd(specs, MkSpecifier(INT64));
3943          }
3944          else if(dest.kind == intType && (source.kind == intType || source.kind == shortType || source.kind == charType ||
3945             source.kind == _BoolType || source.kind == floatType || source.kind == doubleType))
3946          {
3947             specs = MkList();
3948             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3949             ListAdd(specs, MkSpecifier(INT));
3950          }
3951          else if(dest.kind == shortType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType ||
3952             source.kind == floatType || source.kind == doubleType))
3953          {
3954             specs = MkList();
3955             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3956             ListAdd(specs, MkSpecifier(SHORT));
3957          }
3958          else if(dest.kind == charType && (source.kind == charType || source.kind == _BoolType || source.kind == shortType || source.kind == intType ||
3959             source.kind == floatType || source.kind == doubleType))
3960          {
3961             specs = MkList();
3962             if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
3963             ListAdd(specs, MkSpecifier(CHAR));
3964          }
3965          else
3966          {
3967             FreeType(source);
3968             FreeType(dest);
3969             if(backupSourceExpType)
3970             {
3971                // Failed to convert: revert previous exp type
3972                if(sourceExp.expType) FreeType(sourceExp.expType);
3973                sourceExp.expType = backupSourceExpType;
3974             }
3975             return false;
3976          }
3977       }
3978       else if(dest.kind == doubleType &&
3979          (source.kind == doubleType || source.kind == floatType || source.kind == int64Type || source.kind == intType || source.kind == enumType || source.kind == shortType ||
3980           source.kind == _BoolType || source.kind == charType))
3981       {
3982          specs = MkListOne(MkSpecifier(DOUBLE));
3983       }
3984       else if(dest.kind == floatType &&
3985          (source.kind == floatType || source.kind == enumType || source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
3986       {
3987          specs = MkListOne(MkSpecifier(FLOAT));
3988       }
3989       else if(dest.kind == _BoolType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3990          (value == 1 || value == 0))
3991       {
3992          specs = MkList();
3993          ListAdd(specs, MkSpecifier(BOOL));
3994       }
3995       else if(dest.kind == charType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
3996          (dest.isSigned ? (value >= -128 && value <= 127) : (value >= 0 && value <= 255)))
3997       {
3998          specs = MkList();
3999          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
4000          ListAdd(specs, MkSpecifier(CHAR));
4001       }
4002       else if(dest.kind == shortType && (source.kind == enumType || source.kind == _BoolType || source.kind == charType || source.kind == shortType ||
4003          (source.kind == intType && (dest.isSigned ? (value >= -32768 && value <= 32767) : (value >= 0 && value <= 65535)))))
4004       {
4005          specs = MkList();
4006          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
4007          ListAdd(specs, MkSpecifier(SHORT));
4008       }
4009       else if(dest.kind == intType && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType))
4010       {
4011          specs = MkList();
4012          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
4013          ListAdd(specs, MkSpecifier(INT));
4014       }
4015       else if(dest.kind == int64Type && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType || source.kind == int64Type))
4016       {
4017          specs = MkList();
4018          if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
4019          ListAdd(specs, MkSpecifier(INT64));
4020       }
4021       else if(dest.kind == enumType &&
4022          (source.kind == int64Type || source.kind == intType || source.kind == shortType || source.kind == _BoolType || source.kind == charType))
4023       {
4024          specs = MkListOne(MkEnum(MkIdentifier(dest.enumName), null));
4025       }
4026       else
4027       {
4028          FreeType(source);
4029          FreeType(dest);
4030          if(backupSourceExpType)
4031          {
4032             // Failed to convert: revert previous exp type
4033             if(sourceExp.expType) FreeType(sourceExp.expType);
4034             sourceExp.expType = backupSourceExpType;
4035          }
4036          return false;
4037       }
4038
4039       if(!flag && !sourceExp.opDestType)
4040       {
4041          Expression newExp { };
4042          *newExp = *sourceExp;
4043          newExp.prev = null;
4044          newExp.next = null;
4045          if(sourceExp.destType) sourceExp.destType.refCount++;
4046          if(sourceExp.expType)  sourceExp.expType.refCount++;
4047
4048          sourceExp.type = castExp;
4049          if(realDest.kind == classType)
4050          {
4051             sourceExp.cast.typeName = QMkClass(realDest._class.string, null);
4052             FreeList(specs, FreeSpecifier);
4053          }
4054          else
4055             sourceExp.cast.typeName = MkTypeName(specs, null);
4056          if(newExp.type == opExp)
4057          {
4058             sourceExp.cast.exp = MkExpBrackets(MkListOne(newExp));
4059          }
4060          else
4061             sourceExp.cast.exp = newExp;
4062
4063          FreeType(sourceExp.expType);
4064          sourceExp.expType = null;
4065          ProcessExpressionType(sourceExp);
4066       }
4067       else
4068          FreeList(specs, FreeSpecifier);
4069
4070       FreeType(dest);
4071       FreeType(source);
4072       if(backupSourceExpType) FreeType(backupSourceExpType);
4073
4074       return true;
4075    }
4076    else
4077    {
4078       if(computedExp != sourceExp)
4079       {
4080          FreeExpression(computedExp);
4081          computedExp = sourceExp;
4082       }
4083
4084       while((sourceExp.type == bracketsExp || sourceExp.type == extensionExpressionExp) && sourceExp.list) sourceExp = sourceExp.list->last;
4085       if(sourceExp.type == identifierExp)
4086       {
4087          Identifier id = sourceExp.identifier;
4088          if(dest.kind == classType)
4089          {
4090             if(dest._class && dest._class.registered && dest._class.registered.type == enumClass)
4091             {
4092                Class _class = dest._class.registered;
4093                Class enumClass = eSystem_FindClass(privateModule, "enum");
4094                if(enumClass)
4095                {
4096                   for( ; _class && _class.type == ClassType::enumClass; _class = _class.base)
4097                   {
4098                      NamedLink value;
4099                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4100                      for(value = e.values.first; value; value = value.next)
4101                      {
4102                         if(!strcmp(value.name, id.string))
4103                            break;
4104                      }
4105                      if(value)
4106                      {
4107                         FreeExpContents(sourceExp);
4108                         FreeType(sourceExp.expType);
4109
4110                         sourceExp.isConstant = true;
4111                         sourceExp.expType = MkClassType(_class.fullName);
4112                         //if(inCompiler)
4113                         {
4114                            char constant[256];
4115                            sourceExp.type = constantExp;
4116                            if(/*_class && */_class.dataTypeString && !strcmp(_class.dataTypeString, "int")) // _class cannot be null here!
4117                               sprintf(constant, "%d", (int) value.data);
4118                            else
4119                               sprintf(constant, "0x%X", (int) value.data);
4120                            sourceExp.constant = CopyString(constant);
4121                            //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
4122                         }
4123                         FreeType(dest);
4124                         return true;
4125                      }
4126                   }
4127                }
4128             }
4129          }
4130
4131          // Loop through all enum classes
4132          if(dest.classObjectType != typedObject && dest.kind == classType /*!= ellipsisType */&& MatchWithEnums_Module(privateModule, sourceExp, dest, id.string, conversions))
4133          {
4134             FreeType(dest);
4135             return true;
4136          }
4137       }
4138       FreeType(dest);
4139    }
4140    return false;
4141 }
4142
4143 #define TERTIARY(o, name, m, t, p) \
4144    static bool name(Expression exp, Operand op1, Operand op2, Operand op3)   \
4145    {                                                              \
4146       exp.type = constantExp;                                    \
4147       exp.string = p(op1.m ? op2.m : op3.m);                     \
4148       if(!exp.expType) \
4149          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4150       return true;                                                \
4151    }
4152
4153 #define BINARY(o, name, m, t, p) \
4154    static bool name(Expression exp, Operand op1, Operand op2)   \
4155    {                                                              \
4156       t value2 = op2.m;                                           \
4157       exp.type = constantExp;                                    \
4158       exp.string = p((t)(op1.m o value2));                     \
4159       if(!exp.expType) \
4160          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4161       return true;                                                \
4162    }
4163
4164 #define BINARY_DIVIDEINT(o, name, m, t, p) \
4165    static bool name(Expression exp, Operand op1, Operand op2)   \
4166    {                                                              \
4167       t value2 = op2.m;                                           \
4168       exp.type = constantExp;                                    \
4169       exp.string = p(value2 ? (op1.m o value2) : 0);             \
4170       if(!exp.expType) \
4171          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4172       return true;                                                \
4173    }
4174
4175 #define BINARY_DIVIDEREAL(o, name, m, t, p) \
4176    static bool name(Expression exp, Operand op1, Operand op2)   \
4177    {                                                              \
4178       t value2 = op2.m;                                           \
4179       exp.type = constantExp;                                    \
4180       exp.string = p(op1.m o value2);             \
4181       if(!exp.expType) \
4182          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4183       return true;                                                \
4184    }
4185
4186 #define UNARY(o, name, m, t, p) \
4187    static bool name(Expression exp, Operand op1)                \
4188    {                                                              \
4189       exp.type = constantExp;                                    \
4190       exp.string = p((t)(o op1.m));                                   \
4191       if(!exp.expType) \
4192          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
4193       return true;                                                \
4194    }
4195
4196 #define OPERATOR_ALL(macro, o, name) \
4197    macro(o, Int##name, i, int, PrintInt) \
4198    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4199    macro(o, Int64##name, i64, int64, PrintInt64) \
4200    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4201    macro(o, Short##name, s, short, PrintShort) \
4202    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4203    macro(o, Char##name, c, char, PrintChar) \
4204    macro(o, UChar##name, uc, unsigned char, PrintUChar) \
4205    macro(o, Float##name, f, float, PrintFloat) \
4206    macro(o, Double##name, d, double, PrintDouble)
4207
4208 #define OPERATOR_INTTYPES(macro, o, name) \
4209    macro(o, Int##name, i, int, PrintInt) \
4210    macro(o, UInt##name, ui, unsigned int, PrintUInt) \
4211    macro(o, Int64##name, i64, int64, PrintInt64) \
4212    macro(o, UInt64##name, ui64, uint64, PrintUInt64) \
4213    macro(o, Short##name, s, short, PrintShort) \
4214    macro(o, UShort##name, us, unsigned short, PrintUShort) \
4215    macro(o, Char##name, c, char, PrintChar) \
4216    macro(o, UChar##name, uc, unsigned char, PrintUChar)
4217
4218 #define OPERATOR_REALTYPES(macro, o, name) \
4219    macro(o, Float##name, f, float, PrintFloat) \
4220    macro(o, Double##name, d, double, PrintDouble)
4221
4222 // binary arithmetic
4223 OPERATOR_ALL(BINARY, +, Add)
4224 OPERATOR_ALL(BINARY, -, Sub)
4225 OPERATOR_ALL(BINARY, *, Mul)
4226 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /, Div)
4227 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /, Div)
4228 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %, Mod)
4229
4230 // unary arithmetic
4231 OPERATOR_ALL(UNARY, -, Neg)
4232
4233 // unary arithmetic increment and decrement
4234 OPERATOR_ALL(UNARY, ++, Inc)
4235 OPERATOR_ALL(UNARY, --, Dec)
4236
4237 // binary arithmetic assignment
4238 OPERATOR_ALL(BINARY, =, Asign)
4239 OPERATOR_ALL(BINARY, +=, AddAsign)
4240 OPERATOR_ALL(BINARY, -=, SubAsign)
4241 OPERATOR_ALL(BINARY, *=, MulAsign)
4242 OPERATOR_INTTYPES(BINARY_DIVIDEINT, /=, DivAsign)
4243 OPERATOR_REALTYPES(BINARY_DIVIDEREAL, /=, DivAsign)
4244 OPERATOR_INTTYPES(BINARY_DIVIDEINT, %=, ModAsign)
4245
4246 // binary bitwise
4247 OPERATOR_INTTYPES(BINARY, &, BitAnd)
4248 OPERATOR_INTTYPES(BINARY, |, BitOr)
4249 OPERATOR_INTTYPES(BINARY, ^, BitXor)
4250 OPERATOR_INTTYPES(BINARY, <<, LShift)
4251 OPERATOR_INTTYPES(BINARY, >>, RShift)
4252
4253 // unary bitwise
4254 OPERATOR_INTTYPES(UNARY, ~, BitNot)
4255
4256 // binary bitwise assignment
4257 OPERATOR_INTTYPES(BINARY, &=, AndAsign)
4258 OPERATOR_INTTYPES(BINARY, |=, OrAsign)
4259 OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
4260 OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
4261 OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
4262
4263 // unary logical negation
4264 OPERATOR_INTTYPES(UNARY, !, Not)
4265
4266 // binary logical equality
4267 OPERATOR_ALL(BINARY, ==, Equ)
4268 OPERATOR_ALL(BINARY, !=, Nqu)
4269
4270 // binary logical
4271 OPERATOR_ALL(BINARY, &&, And)
4272 OPERATOR_ALL(BINARY, ||, Or)
4273
4274 // binary logical relational
4275 OPERATOR_ALL(BINARY, >, Grt)
4276 OPERATOR_ALL(BINARY, <, Sma)
4277 OPERATOR_ALL(BINARY, >=, GrtEqu)
4278 OPERATOR_ALL(BINARY, <=, SmaEqu)
4279
4280 // tertiary condition operator
4281 OPERATOR_INTTYPES(TERTIARY, ?, Cond)
4282
4283 //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
4284 #define OPERATOR_TABLE_ALL(name, type) \
4285     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, type##Mod, \
4286                           type##Neg, \
4287                           type##Inc, type##Dec, \
4288                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, type##ModAsign, \
4289                           type##BitAnd, type##BitOr, type##BitXor, type##LShift, type##RShift, \
4290                           type##BitNot, \
4291                           type##AndAsign, type##OrAsign, type##XorAsign, type##LShiftAsign, type##RShiftAsign, \
4292                           type##Not, \
4293                           type##Equ, type##Nqu, \
4294                           type##And, type##Or, \
4295                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu, type##Cond \
4296                         }; \
4297
4298 #define OPERATOR_TABLE_INTTYPES(name, type) \
4299     OpTable name##Ops = { type##Add, type##Sub, type##Mul, type##Div, null, \
4300                           type##Neg, \
4301                           type##Inc, type##Dec, \
4302                           type##Asign, type##AddAsign, type##SubAsign, type##MulAsign, type##DivAsign, null, \
4303                           null, null, null, null, null, \
4304                           null, \
4305                           null, null, null, null, null, \
4306                           null, \
4307                           type##Equ, type##Nqu, \
4308                           type##And, type##Or, \
4309                           type##Grt, type##Sma, type##GrtEqu, type##SmaEqu \
4310                         }; \
4311
4312 OPERATOR_TABLE_ALL(int, Int)
4313 OPERATOR_TABLE_ALL(uint, UInt)
4314 OPERATOR_TABLE_ALL(int64, Int64)
4315 OPERATOR_TABLE_ALL(uint64, UInt64)
4316 OPERATOR_TABLE_ALL(short, Short)
4317 OPERATOR_TABLE_ALL(ushort, UShort)
4318 OPERATOR_TABLE_INTTYPES(float, Float)
4319 OPERATOR_TABLE_INTTYPES(double, Double)
4320 OPERATOR_TABLE_ALL(char, Char)
4321 OPERATOR_TABLE_ALL(uchar, UChar)
4322
4323 //OpTable intOps =    {    IntAdd,    IntSub,    IntMul,    IntDiv,    IntMod,    IntExp,    IntNot,    IntBwn,    IntOr,    IntAnd,    IntEqu,    IntNqu,    IntGrt,    IntSma,    IntGrtEqu,    IntSmaEqu,    IntNeg,    IntLBitSft,    IntRBitSft };
4324 //OpTable uintOps =   {   UIntAdd,   UIntSub,   UIntMul,   UIntDiv,   UIntMod,   UIntExp,   UIntNot,   UIntBwn,   UIntOr,   UIntAnd,   UIntEqu,   UIntNqu,   UIntGrt,   UIntSma,   UIntGrtEqu,   UIntSmaEqu,   UIntNeg,   UIntLBitSft,   UIntRBitSft };
4325 //OpTable shortOps =  {  ShortAdd,  ShortSub,  ShortMul,  ShortDiv,  ShortMod,  ShortExp,  ShortNot,  ShortBwn,  ShortOr,  ShortAnd,  ShortEqu,  ShortNqu,  ShortGrt,  ShortSma,  ShortGrtEqu,  ShortSmaEqu,  ShortNeg,  ShortLBitSft,  ShortRBitSft };
4326 //OpTable ushortOps = { UShortAdd, UShortSub, UShortMul, UShortDiv, UShortMod, UShortExp, UShortNot, UShortBwn, UShortOr, UShortAnd, UShortEqu, UShortNqu, UShortGrt, UShortSma, UShortGrtEqu, UShortSmaEqu, UShortNeg, UShortLBitSft, UShortRBitSft };
4327 //OpTable floatOps =  {  FloatAdd,  FloatSub,  FloatMul,  FloatDiv,      null,      null,      null,      null,     null,      null,  FloatEqu,  FloatNqu,  FloatGrt,  FloatSma,  FloatGrtEqu,  FloatSmaEqu,  FloatNeg,          null,          null };
4328 //OpTable doubleOps = { DoubleAdd, DoubleSub, DoubleMul, DoubleDiv,      null,      null,      null,      null,     null,      null, DoubleEqu, DoubleNqu, DoubleGrt, DoubleSma, DoubleGrtEqu, DoubleSmaEqu, DoubleNeg,          null,          null };
4329 //OpTable charOps =   {   CharAdd,   CharSub,   CharMul,   CharDiv,   CharMod,   CharExp,   CharNot,   CharBwn,   CharOr,   CharAnd,   CharEqu,   CharNqu,   CharGrt,   CharSma,   CharGrtEqu,   CharSmaEqu,   CharNeg,   CharLBitSft,   CharRBitSft };
4330 //OpTable ucharOps =  {  UCharAdd,  UCharSub,  UCharMul,  UCharDiv,  UCharMod,  UCharExp,  UCharNot,  UCharBwn,  UCharOr,  UCharAnd,  UCharEqu,  UCharNqu,  UCharGrt,  UCharSma,  UCharGrtEqu,  UCharSmaEqu,  UCharNeg,  UCharLBitSft,  UCharRBitSft };
4331
4332 public void ReadString(char * output,  char * string)
4333 {
4334    int len = strlen(string);
4335    int c,d = 0;
4336    bool quoted = false, escaped = false;
4337    for(c = 0; c<len; c++)
4338    {
4339       char ch = string[c];
4340       if(escaped)
4341       {
4342          switch(ch)
4343          {
4344             case 'n': output[d] = '\n'; break;
4345             case 't': output[d] = '\t'; break;
4346             case 'a': output[d] = '\a'; break;
4347             case 'b': output[d] = '\b'; break;
4348             case 'f': output[d] = '\f'; break;
4349             case 'r': output[d] = '\r'; break;
4350             case 'v': output[d] = '\v'; break;
4351             case '\\': output[d] = '\\'; break;
4352             case '\"': output[d] = '\"'; break;
4353             case '\'': output[d] = '\''; break;
4354             default: output[d] = ch;
4355          }
4356          d++;
4357          escaped = false;
4358       }
4359       else
4360       {
4361          if(ch == '\"')
4362             quoted ^= true;
4363          else if(quoted)
4364          {
4365             if(ch == '\\')
4366                escaped = true;
4367             else
4368                output[d++] = ch;
4369          }
4370       }
4371    }
4372    output[d] = '\0';
4373 }
4374
4375 // String Unescape Copy
4376
4377 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
4378 // This is the same as ReadString above (which also misses numeric escape codes) except it doesn't handle external quotes
4379 public int UnescapeString(char * d, char * s, int len)
4380 {
4381    int j = 0, k = 0;
4382    char ch;
4383    while(j < len && (ch = s[j]))
4384    {
4385       switch(ch)
4386       {
4387          case '\\':
4388             switch((ch = s[++j]))
4389             {
4390                case 'n': d[k] = '\n'; break;
4391                case 't': d[k] = '\t'; break;
4392                case 'a': d[k] = '\a'; break;
4393                case 'b': d[k] = '\b'; break;
4394                case 'f': d[k] = '\f'; break;
4395                case 'r': d[k] = '\r'; break;
4396                case 'v': d[k] = '\v'; break;
4397                case '\\': d[k] = '\\'; break;
4398                case '\"': d[k] = '\"'; break;
4399                case '\'': d[k] = '\''; break;
4400                default: d[k] = '\\'; d[k] = ch;
4401             }
4402             break;
4403          default:
4404             d[k] = ch;
4405       }
4406       j++, k++;
4407    }
4408    d[k] = '\0';
4409    return k;
4410 }
4411
4412 public char * OffsetEscapedString(char * s, int len, int offset)
4413 {
4414    char ch;
4415    int j = 0, k = 0;
4416    while(j < len && k < offset && (ch = s[j]))
4417    {
4418       if(ch == '\\') ++j;
4419       j++, k++;
4420    }
4421    return (k == offset) ? s + j : null;
4422 }
4423
4424 public Operand GetOperand(Expression exp)
4425 {
4426    Operand op { };
4427    Type type = exp.expType;
4428    if(type)
4429    {
4430       while(type.kind == classType &&
4431          type._class.registered && (type._class.registered.type == bitClass || type._class.registered.type == unitClass || type._class.registered.type == enumClass))
4432       {
4433          if(!type._class.registered.dataType)
4434             type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
4435          type = type._class.registered.dataType;
4436
4437       }
4438       if(exp.type == stringExp && op.kind == pointerType)
4439       {
4440          op.ui64 = (uint64)exp.string;
4441          op.kind = pointerType;
4442          op.ops = uint64Ops;
4443       }
4444       else if(exp.isConstant && exp.type == constantExp)
4445       {
4446          op.kind = type.kind;
4447          op.type = exp.expType;
4448
4449          switch(op.kind)
4450          {
4451             case _BoolType:
4452             case charType:
4453             {
4454                if(exp.constant[0] == '\'')
4455                {
4456                   op.c = exp.constant[1];
4457                   op.ops = charOps;
4458                }
4459                else if(type.isSigned)
4460                {
4461                   op.c = (char)strtol(exp.constant, null, 0);
4462                   op.ops = charOps;
4463                }
4464                else
4465                {
4466                   op.uc = (unsigned char)strtoul(exp.constant, null, 0);
4467                   op.ops = ucharOps;
4468                }
4469                break;
4470             }
4471             case shortType:
4472                if(type.isSigned)
4473                {
4474                   op.s = (short)strtol(exp.constant, null, 0);
4475                   op.ops = shortOps;
4476                }
4477                else
4478                {
4479                   op.us = (unsigned short)strtoul(exp.constant, null, 0);
4480                   op.ops = ushortOps;
4481                }
4482                break;
4483             case intType:
4484             case longType:
4485                if(type.isSigned)
4486                {
4487                   op.i = (int)strtol(exp.constant, null, 0);
4488                   op.ops = intOps;
4489                }
4490                else
4491                {
4492                   op.ui = (unsigned int)strtoul(exp.constant, null, 0);
4493                   op.ops = uintOps;
4494                }
4495                op.kind = intType;
4496                break;
4497             case int64Type:
4498                if(type.isSigned)
4499                {
4500                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4501                   op.ops = int64Ops;
4502                }
4503                else
4504                {
4505                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4506                   op.ops = uint64Ops;
4507                }
4508                op.kind = int64Type;
4509                break;
4510             case intPtrType:
4511                if(type.isSigned)
4512                {
4513                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4514                   op.ops = int64Ops;
4515                }
4516                else
4517                {
4518                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4519                   op.ops = uint64Ops;
4520                }
4521                op.kind = int64Type;
4522                break;
4523             case intSizeType:
4524                if(type.isSigned)
4525                {
4526                   op.i64 = (int64)_strtoi64(exp.constant, null, 0);
4527                   op.ops = int64Ops;
4528                }
4529                else
4530                {
4531                   op.ui64 = (uint64)_strtoui64(exp.constant, null, 0);
4532                   op.ops = uint64Ops;
4533                }
4534                op.kind = int64Type;
4535                break;
4536             case floatType:
4537                if(!strcmp(exp.constant, "inf")) op.f = float::inf();
4538                else if(!strcmp(exp.constant, "-inf")) op.f = -float::inf();
4539                else if(!strcmp(exp.constant, "nan")) op.f = float::nan();
4540                else if(!strcmp(exp.constant, "-nan")) op.f = -float::nan();
4541                else
4542                   op.f = (float)strtod(exp.constant, null);
4543                op.ops = floatOps;
4544                break;
4545             case doubleType:
4546                if(!strcmp(exp.constant, "inf")) op.d = double::inf();
4547                else if(!strcmp(exp.constant, "-inf")) op.d = -double::inf();
4548                else if(!strcmp(exp.constant, "nan")) op.d = double::nan();
4549                else if(!strcmp(exp.constant, "-nan")) op.d = -double::nan();
4550                else
4551                   op.d = (double)strtod(exp.constant, null);
4552                op.ops = doubleOps;
4553                break;
4554             //case classType:    For when we have operator overloading...
4555             // Pointer additions
4556             //case functionType:
4557             case arrayType:
4558             case pointerType:
4559             case classType:
4560                op.ui64 = _strtoui64(exp.constant, null, 0);
4561                op.kind = pointerType;
4562                op.ops = uint64Ops;
4563                // op.ptrSize =
4564                break;
4565          }
4566       }
4567    }
4568    return op;
4569 }
4570
4571 static __attribute__((unused)) void UnusedFunction()
4572 {
4573    int a;
4574    a.OnGetString(0,0,0);
4575 }
4576 default:
4577 extern int __ecereVMethodID_class_OnGetString;
4578 public:
4579
4580 static void PopulateInstanceProcessMember(Instantiation inst, OldList * memberList, DataMember parentDataMember, uint offset)
4581 {
4582    DataMember dataMember;
4583    for(dataMember = parentDataMember.members.first; dataMember; dataMember = dataMember.next)
4584    {
4585       if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4586          PopulateInstanceProcessMember(inst, memberList, dataMember, offset + dataMember.offset);
4587       else
4588       {
4589          Expression exp { };
4590          MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4591          Type type;
4592          void * ptr = inst.data + dataMember.offset + offset;
4593          char * result = null;
4594          exp.loc = member.loc = inst.loc;
4595          ((Identifier)member.identifiers->first).loc = inst.loc;
4596
4597          if(!dataMember.dataType)
4598             dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4599          type = dataMember.dataType;
4600          if(type.kind == classType)
4601          {
4602             Class _class = type._class.registered;
4603             if(_class.type == enumClass)
4604             {
4605                Class enumClass = eSystem_FindClass(privateModule, "enum");
4606                if(enumClass)
4607                {
4608                   EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4609                   NamedLink item;
4610                   for(item = e.values.first; item; item = item.next)
4611                   {
4612                      if((int)item.data == *(int *)ptr)
4613                      {
4614                         result = item.name;
4615                         break;
4616                      }
4617                   }
4618                   if(result)
4619                   {
4620                      exp.identifier = MkIdentifier(result);
4621                      exp.type = identifierExp;
4622                      exp.destType = MkClassType(_class.fullName);
4623                      ProcessExpressionType(exp);
4624                   }
4625                }
4626             }
4627             if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4628             {
4629                if(!_class.dataType)
4630                   _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4631                type = _class.dataType;
4632             }
4633          }
4634          if(!result)
4635          {
4636             switch(type.kind)
4637             {
4638                case floatType:
4639                {
4640                   FreeExpContents(exp);
4641
4642                   exp.constant = PrintFloat(*(float*)ptr);
4643                   exp.type = constantExp;
4644                   break;
4645                }
4646                case doubleType:
4647                {
4648                   FreeExpContents(exp);
4649
4650                   exp.constant = PrintDouble(*(double*)ptr);
4651                   exp.type = constantExp;
4652                   break;
4653                }
4654                case intType:
4655                {
4656                   FreeExpContents(exp);
4657
4658                   exp.constant = PrintInt(*(int*)ptr);
4659                   exp.type = constantExp;
4660                   break;
4661                }
4662                case int64Type:
4663                {
4664                   FreeExpContents(exp);
4665
4666                   exp.constant = PrintInt64(*(int64*)ptr);
4667                   exp.type = constantExp;
4668                   break;
4669                }
4670                case intPtrType:
4671                {
4672                   FreeExpContents(exp);
4673                   // TODO: This should probably use proper type
4674                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4675                   exp.type = constantExp;
4676                   break;
4677                }
4678                case intSizeType:
4679                {
4680                   FreeExpContents(exp);
4681                   // TODO: This should probably use proper type
4682                   exp.constant = PrintInt64((int64)*(intptr*)ptr);
4683                   exp.type = constantExp;
4684                   break;
4685                }
4686                default:
4687                   Compiler_Error($"Unhandled type populating instance\n");
4688             }
4689          }
4690          ListAdd(memberList, member);
4691       }
4692
4693       if(parentDataMember.type == unionMember)
4694          break;
4695    }
4696 }
4697
4698 void PopulateInstance(Instantiation inst)
4699 {
4700    Symbol classSym = inst._class.symbol; // FindClass(inst._class.name);
4701    Class _class = classSym.registered;
4702    DataMember dataMember;
4703    OldList * memberList = MkList();
4704    // Added this check and ->Add to prevent memory leaks on bad code
4705    if(!inst.members)
4706       inst.members = MkListOne(MkMembersInitList(memberList));
4707    else
4708       inst.members->Add(MkMembersInitList(memberList));
4709    for(dataMember = _class.membersAndProperties.first; dataMember; dataMember = dataMember.next)
4710    {
4711       if(!dataMember.isProperty)
4712       {
4713          if(!dataMember.name && (dataMember.type == structMember || dataMember.type == unionMember))
4714             PopulateInstanceProcessMember(inst, memberList, dataMember, dataMember.offset);
4715          else
4716          {
4717             Expression exp { };
4718             MemberInit member = MkMemberInit(MkListOne(MkIdentifier(dataMember.name)), MkInitializerAssignment(exp));
4719             Type type;
4720             void * ptr = inst.data + dataMember.offset;
4721             char * result = null;
4722
4723             exp.loc = member.loc = inst.loc;
4724             ((Identifier)member.identifiers->first).loc = inst.loc;
4725
4726             if(!dataMember.dataType)
4727                dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4728             type = dataMember.dataType;
4729             if(type.kind == classType)
4730             {
4731                Class _class = type._class.registered;
4732                if(_class.type == enumClass)
4733                {
4734                   Class enumClass = eSystem_FindClass(privateModule, "enum");
4735                   if(enumClass)
4736                   {
4737                      EnumClassData e = ACCESS_CLASSDATA(_class, enumClass);
4738                      NamedLink item;
4739                      for(item = e.values.first; item; item = item.next)
4740                      {
4741                         if((int)item.data == *(int *)ptr)
4742                         {
4743                            result = item.name;
4744                            break;
4745                         }
4746                      }
4747                   }
4748                   if(result)
4749                   {
4750                      exp.identifier = MkIdentifier(result);
4751                      exp.type = identifierExp;
4752                      exp.destType = MkClassType(_class.fullName);
4753                      ProcessExpressionType(exp);
4754                   }
4755                }
4756                if(_class.type == enumClass || _class.type == unitClass || _class.type == bitClass)
4757                {
4758                   if(!_class.dataType)
4759                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4760                   type = _class.dataType;
4761                }
4762             }
4763             if(!result)
4764             {
4765                switch(type.kind)
4766                {
4767                   case floatType:
4768                   {
4769                      exp.constant = PrintFloat(*(float*)ptr);
4770                      exp.type = constantExp;
4771                      break;
4772                   }
4773                   case doubleType:
4774                   {
4775                      exp.constant = PrintDouble(*(double*)ptr);
4776                      exp.type = constantExp;
4777                      break;
4778                   }
4779                   case intType:
4780                   {
4781                      exp.constant = PrintInt(*(int*)ptr);
4782                      exp.type = constantExp;
4783                      break;
4784                   }
4785                   case int64Type:
4786                   {
4787                      exp.constant = PrintInt64(*(int64*)ptr);
4788                      exp.type = constantExp;
4789                      break;
4790                   }
4791                   case intPtrType:
4792                   {
4793                      exp.constant = PrintInt64((int64)*(intptr*)ptr);
4794                      exp.type = constantExp;
4795                      break;
4796                   }
4797                   default:
4798                      Compiler_Error($"Unhandled type populating instance\n");
4799                }
4800             }
4801             ListAdd(memberList, member);
4802          }
4803       }
4804    }
4805 }
4806
4807 void ComputeInstantiation(Expression exp)
4808 {
4809    Instantiation inst = exp.instance;
4810    MembersInit members;
4811    Symbol classSym = inst._class ? inst._class.symbol : null; // FindClass(inst._class.name);
4812    Class _class = classSym ? classSym.registered : null;
4813    DataMember curMember = null;
4814    Class curClass = null;
4815    DataMember subMemberStack[256];
4816    int subMemberStackPos = 0;
4817    uint64 bits = 0;
4818
4819    if(_class && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass ))
4820    {
4821       // Don't recompute the instantiation...
4822       // Non Simple classes will have become constants by now
4823       if(inst.data)
4824          return;
4825
4826       if(_class.type == normalClass || _class.type == noHeadClass)
4827       {
4828          inst.data = (byte *)eInstance_New(_class);
4829          if(_class.type == normalClass)
4830             ((Instance)inst.data)._refCount++;
4831       }
4832       else
4833          inst.data = new0 byte[_class.structSize];
4834    }
4835
4836    if(inst.members)
4837    {
4838       for(members = inst.members->first; members; members = members.next)
4839       {
4840          switch(members.type)
4841          {
4842             case dataMembersInit:
4843             {
4844                if(members.dataMembers)
4845                {
4846                   MemberInit member;
4847                   for(member = members.dataMembers->first; member; member = member.next)
4848                   {
4849                      Identifier ident = member.identifiers ? member.identifiers->first : null;
4850                      bool found = false;
4851
4852                      Property prop = null;
4853                      DataMember dataMember = null;
4854                      Method method = null;
4855                      uint dataMemberOffset;
4856
4857                      if(!ident)
4858                      {
4859                         eClass_FindNextMember(_class, &curClass, &curMember, subMemberStack, &subMemberStackPos);
4860                         if(curMember)
4861                         {
4862                            if(curMember.isProperty)
4863                               prop = (Property)curMember;
4864                            else
4865                            {
4866                               dataMember = curMember;
4867
4868                               // CHANGED THIS HERE
4869                               eClass_FindDataMemberAndOffset(_class, dataMember.name, &dataMemberOffset, privateModule, null, null);
4870
4871                               // 2013/17/29 -- It seems that this was missing here!
4872                               if(_class.type == normalClass)
4873                                  dataMemberOffset += _class.base.structSize;
4874                               // dataMemberOffset = dataMember.offset;
4875                            }
4876                            found = true;
4877                         }
4878                      }
4879                      else
4880                      {
4881                         prop = eClass_FindProperty(_class, ident.string, privateModule);
4882                         if(prop)
4883                         {
4884                            found = true;
4885                            if(prop.memberAccess == publicAccess)
4886                            {
4887                               curMember = (DataMember)prop;
4888                               curClass = prop._class;
4889                            }
4890                         }
4891                         else
4892                         {
4893                            DataMember _subMemberStack[256];
4894                            int _subMemberStackPos = 0;
4895
4896                            // FILL MEMBER STACK
4897                            dataMember = eClass_FindDataMemberAndOffset(_class, ident.string, &dataMemberOffset, privateModule, _subMemberStack, &_subMemberStackPos);
4898
4899                            if(dataMember)
4900                            {
4901                               found = true;
4902                               if(dataMember.memberAccess == publicAccess)
4903                               {
4904                                  curMember = dataMember;
4905                                  curClass = dataMember._class;
4906                                  memcpy(subMemberStack, _subMemberStack, sizeof(DataMember) * _subMemberStackPos);
4907                                  subMemberStackPos = _subMemberStackPos;
4908                               }
4909                            }
4910                         }
4911                      }
4912
4913                      if(found && member.initializer && member.initializer.type == expInitializer)
4914                      {
4915                         Expression value = member.initializer.exp;
4916                         Type type = null;
4917                         bool deepMember = false;
4918                         if(prop)
4919                         {
4920                            type = prop.dataType;
4921                         }
4922                         else if(dataMember)
4923                         {
4924                            if(!dataMember.dataType)
4925                               dataMember.dataType = ProcessTypeString(dataMember.dataTypeString, false);
4926
4927                            type = dataMember.dataType;
4928                         }
4929
4930                         if(ident && ident.next)
4931                         {
4932                            deepMember = true;
4933
4934                            // for(; ident && type; ident = ident.next)
4935                            for(ident = ident.next; ident && type; ident = ident.next)
4936                            {
4937                               if(type.kind == classType)
4938                               {
4939                                  prop = eClass_FindProperty(type._class.registered,
4940                                     ident.string, privateModule);
4941                                  if(prop)
4942                                     type = prop.dataType;
4943                                  else
4944                                  {
4945                                     dataMember = eClass_FindDataMemberAndOffset(type._class.registered,
4946                                        ident.string, &dataMemberOffset, privateModule, null, null);
4947                                     if(dataMember)
4948                                        type = dataMember.dataType;
4949                                  }
4950                               }
4951                               else if(type.kind == structType || type.kind == unionType)
4952                               {
4953                                  Type memberType;
4954                                  for(memberType = type.members.first; memberType; memberType = memberType.next)
4955                                  {
4956                                     if(!strcmp(memberType.name, ident.string))
4957                                     {
4958                                        type = memberType;
4959                                        break;
4960                                     }
4961                                  }
4962                               }
4963                            }
4964                         }
4965                         if(value)
4966                         {
4967                            FreeType(value.destType);
4968                            value.destType = type;
4969                            if(type) type.refCount++;
4970                            ComputeExpression(value);
4971                         }
4972                         if(!deepMember && type && value && (_class.type == structClass || _class.type == normalClass || _class.type == noHeadClass /*&& value.expType.kind == type.kind*/))
4973                         {
4974                            if(type.kind == classType)
4975                            {
4976                               Class _class = type._class.registered;
4977                               if(_class.type == bitClass || _class.type == unitClass ||
4978                                  _class.type == enumClass)
4979                               {
4980                                  if(!_class.dataType)
4981                                     _class.dataType = ProcessTypeString(_class.dataTypeString, false);
4982                                  type = _class.dataType;
4983                               }
4984                            }
4985
4986                            if(dataMember)
4987                            {
4988                               void * ptr = inst.data + dataMemberOffset;
4989
4990                               if(value.type == constantExp)
4991                               {
4992                                  switch(type.kind)
4993                                  {
4994                                     case intType:
4995                                     {
4996                                        GetInt(value, (int*)ptr);
4997                                        break;
4998                                     }
4999                                     case int64Type:
5000                                     {
5001                                        GetInt64(value, (int64*)ptr);
5002                                        break;
5003                                     }
5004                                     case intPtrType:
5005                                     {
5006                                        GetIntPtr(value, (intptr*)ptr);
5007                                        break;
5008                                     }
5009                                     case intSizeType:
5010                                     {
5011                                        GetIntSize(value, (intsize*)ptr);
5012                                        break;
5013                                     }
5014                                     case floatType:
5015                                     {
5016                                        GetFloat(value, (float*)ptr);
5017                                        break;
5018                                     }
5019                                     case doubleType:
5020                                     {
5021                                        GetDouble(value, (double *)ptr);
5022                                        break;
5023                                     }
5024                                  }
5025                               }
5026                               else if(value.type == instanceExp)
5027                               {
5028                                  if(type.kind == classType)
5029                                  {
5030                                     Class _class = type._class.registered;
5031                                     if(_class.type == structClass)
5032                                     {
5033                                        ComputeTypeSize(type);
5034                                        if(value.instance.data)
5035                                           memcpy(ptr, value.instance.data, type.size);
5036                                     }
5037                                  }
5038                               }
5039                            }
5040                            else if(prop)
5041                            {
5042                               if(value.type == instanceExp && value.instance.data)
5043                               {
5044                                  if(type.kind == classType)
5045                                  {
5046                                     Class _class = type._class.registered;
5047                                     if(_class && (_class.type != normalClass || eClass_IsDerived(((Instance)value.instance.data)._class, _class)))
5048                                     {
5049                                        void (*Set)(void *, void *) = (void *)prop.Set;
5050                                        Set(inst.data, value.instance.data);
5051                                        PopulateInstance(inst);
5052                                     }
5053                                  }
5054                               }
5055                               else if(value.type == constantExp)
5056                               {
5057                                  switch(type.kind)
5058                                  {
5059                                     case doubleType:
5060                                     {
5061                                        void (*Set)(void *, double) = (void *)prop.Set;
5062                                        Set(inst.data, strtod(value.constant, null) );
5063                                        break;
5064                                     }
5065                                     case floatType:
5066                                     {
5067                                        void (*Set)(void *, float) = (void *)prop.Set;
5068                                        Set(inst.data, (float)(strtod(value.constant, null)));
5069                                        break;
5070                                     }
5071                                     case intType:
5072                                     {
5073                                        void (*Set)(void *, int) = (void *)prop.Set;
5074                                        Set(inst.data, (int)strtol(value.constant, null, 0));
5075                                        break;
5076                                     }
5077                                     case int64Type:
5078                                     {
5079                                        void (*Set)(void *, int64) = (void *)prop.Set;
5080                                        Set(inst.data, _strtoi64(value.constant, null, 0));
5081                                        break;
5082                                     }
5083                                     case intPtrType:
5084                                     {
5085                                        void (*Set)(void *, intptr) = (void *)prop.Set;
5086                                        Set(inst.data, (intptr)_strtoi64(value.constant, null, 0));
5087                                        break;
5088                                     }
5089                                     case intSizeType:
5090                                     {
5091                                        void (*Set)(void *, intsize) = (void *)prop.Set;
5092                                        Set(inst.data, (intsize)_strtoi64(value.constant, null, 0));
5093                                        break;
5094                                     }
5095                                  }
5096                               }
5097                               else if(value.type == stringExp)
5098                               {
5099                                  char temp[1024];
5100                                  ReadString(temp, value.string);
5101                                  ((void (*)(void *, void *))(void *)prop.Set)(inst.data, temp);
5102                               }
5103                            }
5104                         }
5105                         else if(!deepMember && type && _class.type == unitClass)
5106                         {
5107                            if(prop)
5108                            {
5109                               // Only support converting units to units for now...
5110                               if(value.type == constantExp)
5111                               {
5112                                  if(type.kind == classType)
5113                                  {
5114                                     Class _class = type._class.registered;
5115                                     if(_class.type == unitClass)
5116                                     {
5117                                        if(!_class.dataType)
5118                                           _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5119                                        type = _class.dataType;
5120                                     }
5121                                  }
5122                                  // TODO: Assuming same base type for units...
5123                                  switch(type.kind)
5124                                  {
5125                                     case floatType:
5126                                     {
5127                                        float fValue;
5128                                        float (*Set)(float) = (void *)prop.Set;
5129                                        GetFloat(member.initializer.exp, &fValue);
5130                                        exp.constant = PrintFloat(Set(fValue));
5131                                        exp.type = constantExp;
5132                                        break;
5133                                     }
5134                                     case doubleType:
5135                                     {
5136                                        double dValue;
5137                                        double (*Set)(double) = (void *)prop.Set;
5138                                        GetDouble(member.initializer.exp, &dValue);
5139                                        exp.constant = PrintDouble(Set(dValue));
5140                                        exp.type = constantExp;
5141                                        break;
5142                                     }
5143                                  }
5144                               }
5145                            }
5146                         }
5147                         else if(!deepMember && type && _class.type == bitClass)
5148                         {
5149                            if(prop)
5150                            {
5151                               if(value.type == instanceExp && value.instance.data)
5152                               {
5153                                  unsigned int (*Set)(void *) = (void *)prop.Set;
5154                                  bits = Set(value.instance.data);
5155                               }
5156                               else if(value.type == constantExp)
5157                               {
5158                               }
5159                            }
5160                            else if(dataMember)
5161                            {
5162                               BitMember bitMember = (BitMember) dataMember;
5163                               Type type;
5164                               uint64 part;
5165                               bits = (bits & ~bitMember.mask);
5166                               if(!bitMember.dataType)
5167                                  bitMember.dataType = ProcessTypeString(bitMember.dataTypeString, false);
5168                               type = bitMember.dataType;
5169                               if(type.kind == classType && type._class && type._class.registered)
5170                               {
5171                                  if(!type._class.registered.dataType)
5172                                     type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
5173                                  type = type._class.registered.dataType;
5174                               }
5175                               switch(type.kind)
5176                               {
5177                                  case _BoolType:
5178                                  case charType:       { byte v; type.isSigned ? GetChar(value, (char *)&v) : GetUChar(value, &v); part = (uint64)v; break; }
5179                                  case shortType:      { uint16 v; type.isSigned ? GetShort(value, (uint16 *)&v) : GetUShort(value, &v); part = (uint64)v; break; }
5180                                  case intType:
5181                                  case longType:       { uint v; type.isSigned ? GetInt(value, (uint *)&v) : GetUInt(value, &v); part = (uint64)v; break; }
5182                                  case int64Type:      { uint64 v; type.isSigned ? GetInt64(value, (uint64 *)&v) : GetUInt64(value, &v); part = (uint64)v; break; }
5183                                  case intPtrType:     { uintptr v; type.isSigned ? GetIntPtr(value, (uintptr *)&v) : GetUIntPtr(value, &v); part = (uint64)v; break; }
5184                                  case intSizeType:    { uintsize v; type.isSigned ? GetIntSize(value, (uintsize *)&v) : GetUIntSize(value, &v); part = (uint64)v; break; }
5185                               }
5186                               bits |= part << bitMember.pos;
5187                            }
5188                         }
5189                      }
5190                      else
5191                      {
5192                         if(_class && _class.type == unitClass)
5193                         {
5194                            ComputeExpression(member.initializer.exp);
5195                            exp.constant = member.initializer.exp.constant;
5196                            exp.type = constantExp;
5197
5198                            member.initializer.exp.constant = null;
5199                         }
5200                      }
5201                   }
5202                }
5203                break;
5204             }
5205          }
5206       }
5207    }
5208    if(_class && _class.type == bitClass)
5209    {
5210       exp.constant = PrintHexUInt(bits);
5211       exp.type = constantExp;
5212    }
5213    if(exp.type != instanceExp)
5214    {
5215       FreeInstance(inst);
5216    }
5217 }
5218
5219 static bool Promote(Operand op, TypeKind kind, bool isSigned)
5220 {
5221    bool result = false;
5222    switch(kind)
5223    {
5224       case shortType:
5225          if(op.kind == charType || op.kind == enumType || op.kind == _BoolType)
5226             result = isSigned ? GetOpShort(op, &op.s) : GetOpUShort(op, &op.us);
5227          break;
5228       case intType:
5229       case longType:
5230          if(op.kind == charType || op.kind == shortType || op.kind == enumType || op.kind == _BoolType)
5231             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5232          break;
5233       case int64Type:
5234          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5235             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5236             result = isSigned ? GetOpInt64(op, &op.i64) : GetOpUInt64(op, &op.ui64);
5237          break;
5238       case floatType:
5239          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType ||
5240             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5241             result = GetOpFloat(op, &op.f);
5242          break;
5243       case doubleType:
5244          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType ||
5245             op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5246             result = GetOpDouble(op, &op.d);
5247          break;
5248       case pointerType:
5249          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5250             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5251             result = GetOpUIntPtr(op, &op.ui64);
5252          break;
5253       case enumType:
5254          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == int64Type || op.kind == longType || op.kind == floatType || op.kind == doubleType ||
5255             op.kind == pointerType || op.kind == enumType || op.kind == intPtrType || op.kind == intSizeType || op.kind == _BoolType)
5256             result = isSigned ? GetOpInt(op, &op.i) : GetOpUInt(op, &op.ui);
5257          break;
5258       case intPtrType:
5259          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5260             result = isSigned ? GetOpIntPtr(op, &op.i64) : GetOpUIntPtr(op, &op.i64);
5261          break;
5262       case intSizeType:
5263          if(op.kind == charType || op.kind == shortType || op.kind == intType || op.kind == longType || op.kind == enumType || op.kind == _BoolType)
5264             result = isSigned ? GetOpIntSize(op, &op.ui64) : GetOpUIntSize(op, &op.ui64);
5265          break;
5266    }
5267    return result;
5268 }
5269
5270 void CallOperator(Expression exp, Expression exp1, Expression exp2, Operand op1, Operand op2)
5271 {
5272    if(exp.op.op == SIZEOF)
5273    {
5274       FreeExpContents(exp);
5275       exp.type = constantExp;
5276       exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5277    }
5278    else
5279    {
5280       if(!exp.op.exp1)
5281       {
5282          switch(exp.op.op)
5283          {
5284             // unary arithmetic
5285             case '+':
5286             {
5287                // Provide default unary +
5288                Expression exp2 = exp.op.exp2;
5289                exp.op.exp2 = null;
5290                FreeExpContents(exp);
5291                FreeType(exp.expType);
5292                FreeType(exp.destType);
5293                *exp = *exp2;
5294                delete exp2;
5295                break;
5296             }
5297             case '-':
5298                if(op1.ops.Neg) { FreeExpContents(exp); op1.ops.Neg(exp, op1); }
5299                break;
5300             // unary arithmetic increment and decrement
5301                   //OPERATOR_ALL(UNARY, ++, Inc)
5302                   //OPERATOR_ALL(UNARY, --, Dec)
5303             // unary bitwise
5304             case '~':
5305                if(op1.ops.BitNot) { FreeExpContents(exp); op1.ops.BitNot(exp, op1); }
5306                break;
5307             // unary logical negation
5308             case '!':
5309                if(op1.ops.Not) { FreeExpContents(exp); op1.ops.Not(exp, op1); }
5310                break;
5311          }
5312       }
5313       else
5314       {
5315          if(op1 && op2 && op1.type && op2.type && op1.kind != op2.kind)
5316          {
5317             if(Promote(op2, op1.kind, op1.type.isSigned))
5318                op2.kind = op1.kind, op2.ops = op1.ops;
5319             else if(Promote(op1, op2.kind, op2.type.isSigned))
5320                op1.kind = op2.kind, op1.ops = op2.ops;
5321          }
5322          switch(exp.op.op)
5323          {
5324             // binary arithmetic
5325             case '+':
5326                if(op1.ops.Add) { FreeExpContents(exp); op1.ops.Add(exp, op1, op2); }
5327                break;
5328             case '-':
5329                if(op1.ops.Sub) { FreeExpContents(exp); op1.ops.Sub(exp, op1, op2); }
5330                break;
5331             case '*':
5332                if(op1.ops.Mul) { FreeExpContents(exp); op1.ops.Mul(exp, op1, op2); }
5333                break;
5334             case '/':
5335                if(op1.ops.Div) { FreeExpContents(exp); op1.ops.Div(exp, op1, op2); }
5336                break;
5337             case '%':
5338                if(op1.ops.Mod) { FreeExpContents(exp); op1.ops.Mod(exp, op1, op2); }
5339                break;
5340             // binary arithmetic assignment
5341                   //OPERATOR_ALL(BINARY, =, Asign)
5342                   //OPERATOR_ALL(BINARY, +=, AddAsign)
5343                   //OPERATOR_ALL(BINARY, -=, SubAsign)
5344                   //OPERATOR_ALL(BINARY, *=, MulAsign)
5345                   //OPERATOR_ALL(BINARY, /=, DivAsign)
5346                   //OPERATOR_ALL(BINARY, %=, ModAsign)
5347             // binary bitwise
5348             case '&':
5349                if(exp.op.exp2)
5350                {
5351                   if(op1.ops.BitAnd) { FreeExpContents(exp); op1.ops.BitAnd(exp, op1, op2); }
5352                }
5353                break;
5354             case '|':
5355                if(op1.ops.BitOr) { FreeExpContents(exp); op1.ops.BitOr(exp, op1, op2); }
5356                break;
5357             case '^':
5358                if(op1.ops.BitXor) { FreeExpContents(exp); op1.ops.BitXor(exp, op1, op2); }
5359                break;
5360             case LEFT_OP:
5361                if(op1.ops.LShift) { FreeExpContents(exp); op1.ops.LShift(exp, op1, op2); }
5362                break;
5363             case RIGHT_OP:
5364                if(op1.ops.RShift) { FreeExpContents(exp); op1.ops.RShift(exp, op1, op2); }
5365                break;
5366             // binary bitwise assignment
5367                   //OPERATOR_INTTYPES(BINARY, &=, AndAsign)
5368                   //OPERATOR_INTTYPES(BINARY, |=, OrAsign)
5369                   //OPERATOR_INTTYPES(BINARY, ^=, XorAsign)
5370                   //OPERATOR_INTTYPES(BINARY, <<=, LShiftAsign)
5371                   //OPERATOR_INTTYPES(BINARY, >>=, RShiftAsign)
5372             // binary logical equality
5373             case EQ_OP:
5374                if(op1.ops.Equ) { FreeExpContents(exp); op1.ops.Equ(exp, op1, op2); }
5375                break;
5376             case NE_OP:
5377                if(op1.ops.Nqu) { FreeExpContents(exp); op1.ops.Nqu(exp, op1, op2); }
5378                break;
5379             // binary logical
5380             case AND_OP:
5381                if(op1.ops.And) { FreeExpContents(exp); op1.ops.And(exp, op1, op2); }
5382                break;
5383             case OR_OP:
5384                if(op1.ops.Or) { FreeExpContents(exp); op1.ops.Or(exp, op1, op2); }
5385                break;
5386             // binary logical relational
5387             case '>':
5388                if(op1.ops.Grt) { FreeExpContents(exp); op1.ops.Grt(exp, op1, op2); }
5389                break;
5390             case '<':
5391                if(op1.ops.Sma) { FreeExpContents(exp); op1.ops.Sma(exp, op1, op2); }
5392                break;
5393             case GE_OP:
5394                if(op1.ops.GrtEqu) { FreeExpContents(exp); op1.ops.GrtEqu(exp, op1, op2); }
5395                break;
5396             case LE_OP:
5397                if(op1.ops.SmaEqu) { FreeExpContents(exp); op1.ops.SmaEqu(exp, op1, op2); }
5398                break;
5399          }
5400       }
5401    }
5402 }
5403
5404 void ComputeExpression(Expression exp)
5405 {
5406    char expString[10240];
5407    expString[0] = '\0';
5408 #ifdef _DEBUG
5409    PrintExpression(exp, expString);
5410 #endif
5411
5412    switch(exp.type)
5413    {
5414       case instanceExp:
5415       {
5416          ComputeInstantiation(exp);
5417          break;
5418       }
5419       /*
5420       case constantExp:
5421          break;
5422       */
5423       case opExp:
5424       {
5425          Expression exp1, exp2 = null;
5426          Operand op1 { };
5427          Operand op2 { };
5428
5429          // We don't care about operations with only exp2 (INC_OP, DEC_OP...)
5430          if(exp.op.exp2)
5431          {
5432             Expression e = exp.op.exp2;
5433
5434             while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
5435             {
5436                if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
5437                {
5438                   if(e.type == extensionCompoundExp)
5439                      e = ((Statement)e.compound.compound.statements->last).expressions->last;
5440                   else
5441                      e = e.list->last;
5442                }
5443             }
5444             if(exp.op.op == TokenType::sizeOf && e && e.expType)
5445             {
5446                if(e.type == stringExp && e.string)
5447                {
5448                   char * string = e.string;
5449                   int len = strlen(string);
5450                   char * tmp = new char[len-2+1];
5451                   len = UnescapeString(tmp, string + 1, len - 2);
5452                   delete tmp;
5453                   FreeExpContents(exp);
5454                   exp.type = constantExp;
5455                   exp.constant = PrintUInt(len + 1);
5456                }
5457                else
5458                {
5459                   Type type = e.expType;
5460                   type.refCount++;
5461                   FreeExpContents(exp);
5462                   exp.type = constantExp;
5463                   exp.constant = PrintUInt(ComputeTypeSize(type));
5464                   FreeType(type);
5465                }
5466                break;
5467             }
5468             else
5469                ComputeExpression(exp.op.exp2);
5470          }
5471          if(exp.op.exp1)
5472          {
5473             ComputeExpression(exp.op.exp1);
5474             exp1 = exp.op.exp1;
5475             exp2 = exp.op.exp2;
5476             op1 = GetOperand(exp1);
5477             if(op1.type) op1.type.refCount++;
5478             if(exp2)
5479             {
5480                op2 = GetOperand(exp2);
5481                if(op2.type) op2.type.refCount++;
5482             }
5483          }
5484          else
5485          {
5486             exp1 = exp.op.exp2;
5487             op1 = GetOperand(exp1);
5488             if(op1.type) op1.type.refCount++;
5489          }
5490
5491          CallOperator(exp, exp1, exp2, op1, op2);
5492          /*
5493          switch(exp.op.op)
5494          {
5495             // Unary operators
5496             case '&':
5497                // Also binary
5498                if(exp.op.exp1 && exp.op.exp2)
5499                {
5500                   // Binary And
5501                   if(op1.ops.BitAnd)
5502                   {
5503                      FreeExpContents(exp);
5504                      op1.ops.BitAnd(exp, op1, op2);
5505                   }
5506                }
5507                break;
5508             case '*':
5509                if(exp.op.exp1)
5510                {
5511                   if(op1.ops.Mul)
5512                   {
5513                      FreeExpContents(exp);
5514                      op1.ops.Mul(exp, op1, op2);
5515                   }
5516                }
5517                break;
5518             case '+':
5519                if(exp.op.exp1)
5520                {
5521                   if(op1.ops.Add)
5522                   {
5523                      FreeExpContents(exp);
5524                      op1.ops.Add(exp, op1, op2);
5525                   }
5526                }
5527                else
5528                {
5529                   // Provide default unary +
5530                   Expression exp2 = exp.op.exp2;
5531                   exp.op.exp2 = null;
5532                   FreeExpContents(exp);
5533                   FreeType(exp.expType);
5534                   FreeType(exp.destType);
5535
5536                   *exp = *exp2;
5537                   delete exp2;
5538                }
5539                break;
5540             case '-':
5541                if(exp.op.exp1)
5542                {
5543                   if(op1.ops.Sub)
5544                   {
5545                      FreeExpContents(exp);
5546                      op1.ops.Sub(exp, op1, op2);
5547                   }
5548                }
5549                else
5550                {
5551                   if(op1.ops.Neg)
5552                   {
5553                      FreeExpContents(exp);
5554                      op1.ops.Neg(exp, op1);
5555                   }
5556                }
5557                break;
5558             case '~':
5559                if(op1.ops.BitNot)
5560                {
5561                   FreeExpContents(exp);
5562                   op1.ops.BitNot(exp, op1);
5563                }
5564                break;
5565             case '!':
5566                if(op1.ops.Not)
5567                {
5568                   FreeExpContents(exp);
5569                   op1.ops.Not(exp, op1);
5570                }
5571                break;
5572             // Binary only operators
5573             case '/':
5574                if(op1.ops.Div)
5575                {
5576                   FreeExpContents(exp);
5577                   op1.ops.Div(exp, op1, op2);
5578                }
5579                break;
5580             case '%':
5581                if(op1.ops.Mod)
5582                {
5583                   FreeExpContents(exp);
5584                   op1.ops.Mod(exp, op1, op2);
5585                }
5586                break;
5587             case LEFT_OP:
5588                break;
5589             case RIGHT_OP:
5590                break;
5591             case '<':
5592                if(exp.op.exp1)
5593                {
5594                   if(op1.ops.Sma)
5595                   {
5596                      FreeExpContents(exp);
5597                      op1.ops.Sma(exp, op1, op2);
5598                   }
5599                }
5600                break;
5601             case '>':
5602                if(exp.op.exp1)
5603                {
5604                   if(op1.ops.Grt)
5605                   {
5606                      FreeExpContents(exp);
5607                      op1.ops.Grt(exp, op1, op2);
5608                   }
5609                }
5610                break;
5611             case LE_OP:
5612                if(exp.op.exp1)
5613                {
5614                   if(op1.ops.SmaEqu)
5615                   {
5616                      FreeExpContents(exp);
5617                      op1.ops.SmaEqu(exp, op1, op2);
5618                   }
5619                }
5620                break;
5621             case GE_OP:
5622                if(exp.op.exp1)
5623                {
5624                   if(op1.ops.GrtEqu)
5625                   {
5626                      FreeExpContents(exp);
5627                      op1.ops.GrtEqu(exp, op1, op2);
5628                   }
5629                }
5630                break;
5631             case EQ_OP:
5632                if(exp.op.exp1)
5633                {
5634                   if(op1.ops.Equ)
5635                   {
5636                      FreeExpContents(exp);
5637                      op1.ops.Equ(exp, op1, op2);
5638                   }
5639                }
5640                break;
5641             case NE_OP:
5642                if(exp.op.exp1)
5643                {
5644                   if(op1.ops.Nqu)
5645                   {
5646                      FreeExpContents(exp);
5647                      op1.ops.Nqu(exp, op1, op2);
5648                   }
5649                }
5650                break;
5651             case '|':
5652                if(op1.ops.BitOr)
5653                {
5654                   FreeExpContents(exp);
5655                   op1.ops.BitOr(exp, op1, op2);
5656                }
5657                break;
5658             case '^':
5659                if(op1.ops.BitXor)
5660                {
5661                   FreeExpContents(exp);
5662                   op1.ops.BitXor(exp, op1, op2);
5663                }
5664                break;
5665             case AND_OP:
5666                break;
5667             case OR_OP:
5668                break;
5669             case SIZEOF:
5670                FreeExpContents(exp);
5671                exp.type = constantExp;
5672                exp.constant = PrintUInt(ComputeTypeSize(op1.type));
5673                break;
5674          }
5675          */
5676          if(op1.type) FreeType(op1.type);
5677          if(op2.type) FreeType(op2.type);
5678          break;
5679       }
5680       case bracketsExp:
5681       case extensionExpressionExp:
5682       {
5683          Expression e, n;
5684          for(e = exp.list->first; e; e = n)
5685          {
5686             n = e.next;
5687             if(!n)
5688             {
5689                OldList * list = exp.list;
5690                Expression prev = exp.prev;
5691                Expression next = exp.next;
5692                ComputeExpression(e);
5693                //FreeExpContents(exp);
5694                FreeType(exp.expType);
5695                FreeType(exp.destType);
5696                *exp = *e;
5697                exp.prev = prev;
5698                exp.next = next;
5699                delete e;
5700                delete list;
5701             }
5702             else
5703             {
5704                FreeExpression(e);
5705             }
5706          }
5707          break;
5708       }
5709       /*
5710
5711       case ExpIndex:
5712       {
5713          Expression e;
5714          exp.isConstant = true;
5715
5716          ComputeExpression(exp.index.exp);
5717          if(!exp.index.exp.isConstant)
5718             exp.isConstant = false;
5719
5720          for(e = exp.index.index->first; e; e = e.next)
5721          {
5722             ComputeExpression(e);
5723             if(!e.next)
5724             {
5725                // Check if this type is int
5726             }
5727             if(!e.isConstant)
5728                exp.isConstant = false;
5729          }
5730          exp.expType = Dereference(exp.index.exp.expType);
5731          break;
5732       }
5733       */
5734       case memberExp:
5735       {
5736          Expression memberExp = exp.member.exp;
5737          Identifier memberID = exp.member.member;
5738
5739          Type type;
5740          ComputeExpression(exp.member.exp);
5741          type = exp.member.exp.expType;
5742          if(type)
5743          {
5744             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);
5745             Property prop = null;
5746             DataMember member = null;
5747             Class convertTo = null;
5748             if(type.kind == subClassType && exp.member.exp.type == classExp)
5749                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
5750
5751             if(!_class)
5752             {
5753                char string[256];
5754                Symbol classSym;
5755                string[0] = '\0';
5756                PrintTypeNoConst(type, string, false, true);
5757                classSym = FindClass(string);
5758                _class = classSym ? classSym.registered : null;
5759             }
5760
5761             if(exp.member.member)
5762             {
5763                prop = eClass_FindProperty(_class, exp.member.member.string, privateModule);
5764                if(!prop)
5765                   member = eClass_FindDataMember(_class, exp.member.member.string, privateModule, null, null);
5766             }
5767             if(!prop && !member && _class && exp.member.member)
5768             {
5769                Symbol classSym = FindClass(exp.member.member.string);
5770                convertTo = _class;
5771                _class = classSym ? classSym.registered : null;
5772                prop = eClass_FindProperty(_class, convertTo.fullName, privateModule);
5773             }
5774
5775             if(prop)
5776             {
5777                if(prop.compiled)
5778                {
5779                   Type type = prop.dataType;
5780                   // TODO: Assuming same base type for units...
5781                   if(_class.type == unitClass)
5782                   {
5783                      if(type.kind == classType)
5784                      {
5785                         Class _class = type._class.registered;
5786                         if(_class.type == unitClass)
5787                         {
5788                            if(!_class.dataType)
5789                               _class.dataType = ProcessTypeString(_class.dataTypeString, false);
5790                            type = _class.dataType;
5791                         }
5792                      }
5793                      switch(type.kind)
5794                      {
5795                         case floatType:
5796                         {
5797                            float value;
5798                            float (*Get)(float) = (void *)prop.Get;
5799                            GetFloat(exp.member.exp, &value);
5800                            exp.constant = PrintFloat(Get ? Get(value) : value);
5801                            exp.type = constantExp;
5802                            break;
5803                         }
5804                         case doubleType:
5805                         {
5806                            double value;
5807                            double (*Get)(double);
5808                            GetDouble(exp.member.exp, &value);
5809
5810                            if(convertTo)
5811                               Get = (void *)prop.Set;
5812                            else
5813                               Get = (void *)prop.Get;
5814                            exp.constant = PrintDouble(Get ? Get(value) : value);
5815                            exp.type = constantExp;
5816                            break;
5817                         }
5818                      }
5819                   }
5820                   else
5821                   {
5822                      if(convertTo)
5823                      {
5824                         Expression value = exp.member.exp;
5825                         Type type;
5826                         if(!prop.dataType)
5827                            ProcessPropertyType(prop);
5828
5829                         type = prop.dataType;
5830                         if(!type)
5831                         {
5832                             // printf("Investigate this\n");
5833                         }
5834                         else if(_class.type == structClass)
5835                         {
5836                            switch(type.kind)
5837                            {
5838                               case classType:
5839                               {
5840                                  Class propertyClass = type._class.registered;
5841                                  if(propertyClass.type == structClass && value.type == instanceExp)
5842                                  {
5843                                     void (*Set)(void *, void *) = (void *)prop.Set;
5844                                     exp.instance = Instantiation { };
5845                                     exp.instance.data = new0 byte[_class.structSize];
5846                                     exp.instance._class = MkSpecifierName(_class.fullName);
5847                                     exp.instance.loc = exp.loc;
5848                                     exp.type = instanceExp;
5849                                     Set(exp.instance.data, value.instance.data);
5850                                     PopulateInstance(exp.instance);
5851                                  }
5852                                  break;
5853                               }
5854                               case intType:
5855                               {
5856                                  int intValue;
5857                                  void (*Set)(void *, int) = (void *)prop.Set;
5858
5859                                  exp.instance = Instantiation { };
5860                                  exp.instance.data = new0 byte[_class.structSize];
5861                                  exp.instance._class = MkSpecifierName(_class.fullName);
5862                                  exp.instance.loc = exp.loc;
5863                                  exp.type = instanceExp;
5864
5865                                  GetInt(value, &intValue);
5866
5867                                  Set(exp.instance.data, intValue);
5868                                  PopulateInstance(exp.instance);
5869                                  break;
5870                               }
5871                               case int64Type:
5872                               {
5873                                  int64 intValue;
5874                                  void (*Set)(void *, int64) = (void *)prop.Set;
5875
5876                                  exp.instance = Instantiation { };
5877                                  exp.instance.data = new0 byte[_class.structSize];
5878                                  exp.instance._class = MkSpecifierName/*MkClassName*/(_class.fullName);
5879                                  exp.instance.loc = exp.loc;
5880                                  exp.type = instanceExp;
5881
5882                                  GetInt64(value, &intValue);
5883
5884                                  Set(exp.instance.data, intValue);
5885                                  PopulateInstance(exp.instance);
5886                                  break;
5887                               }
5888                               case intPtrType:
5889                               {
5890                                  // TOFIX:
5891                                  intptr intValue;
5892                                  void (*Set)(void *, intptr) = (void *)prop.Set;
5893
5894                                  exp.instance = Instantiation { };
5895                                  exp.instance.data = new0 byte[_class.structSize];
5896                                  exp.instance._class = MkSpecifierName(_class.fullName);
5897                                  exp.instance.loc = exp.loc;
5898                                  exp.type = instanceExp;
5899
5900                                  GetIntPtr(value, &intValue);
5901
5902                                  Set(exp.instance.data, intValue);
5903                                  PopulateInstance(exp.instance);
5904                                  break;
5905                               }
5906                               case intSizeType:
5907                               {
5908                                  // TOFIX:
5909                                  intsize intValue;
5910                                  void (*Set)(void *, intsize) = (void *)prop.Set;
5911
5912                                  exp.instance = Instantiation { };
5913                                  exp.instance.data = new0 byte[_class.structSize];
5914                                  exp.instance._class = MkSpecifierName(_class.fullName);
5915                                  exp.instance.loc = exp.loc;
5916                                  exp.type = instanceExp;
5917
5918                                  GetIntSize(value, &intValue);
5919
5920                                  Set(exp.instance.data, intValue);
5921                                  PopulateInstance(exp.instance);
5922                                  break;
5923                               }
5924                               case floatType:
5925                               {
5926                                  float floatValue;
5927                                  void (*Set)(void *, float) = (void *)prop.Set;
5928
5929                                  exp.instance = Instantiation { };
5930                                  exp.instance.data = new0 byte[_class.structSize];
5931                                  exp.instance._class = MkSpecifierName(_class.fullName);
5932                                  exp.instance.loc = exp.loc;
5933                                  exp.type = instanceExp;
5934
5935                                  GetFloat(value, &floatValue);
5936
5937                                  Set(exp.instance.data, floatValue);
5938                                  PopulateInstance(exp.instance);
5939                                  break;
5940                               }
5941                               case doubleType:
5942                               {
5943                                  double doubleValue;
5944                                  void (*Set)(void *, double) = (void *)prop.Set;
5945
5946                                  exp.instance = Instantiation { };
5947                                  exp.instance.data = new0 byte[_class.structSize];
5948                                  exp.instance._class = MkSpecifierName(_class.fullName);
5949                                  exp.instance.loc = exp.loc;
5950                                  exp.type = instanceExp;
5951
5952                                  GetDouble(value, &doubleValue);
5953
5954                                  Set(exp.instance.data, doubleValue);
5955                                  PopulateInstance(exp.instance);
5956                                  break;
5957                               }
5958                            }
5959                         }
5960                         else if(_class.type == bitClass)
5961                         {
5962                            switch(type.kind)
5963                            {
5964                               case classType:
5965                               {
5966                                  Class propertyClass = type._class.registered;
5967                                  if(propertyClass.type == structClass && value.instance.data)
5968                                  {
5969                                     unsigned int (*Set)(void *) = (void *)prop.Set;
5970                                     unsigned int bits = Set(value.instance.data);
5971                                     exp.constant = PrintHexUInt(bits);
5972                                     exp.type = constantExp;
5973                                     break;
5974                                  }
5975                                  else if(_class.type == bitClass)
5976                                  {
5977                                     unsigned int value;
5978                                     unsigned int (*Set)(unsigned int) = (void *)prop.Set;
5979                                     unsigned int bits;
5980
5981                                     GetUInt(exp.member.exp, &value);
5982                                     bits = Set(value);
5983                                     exp.constant = PrintHexUInt(bits);
5984                                     exp.type = constantExp;
5985                                  }
5986                               }
5987                            }
5988                         }
5989                      }
5990                      else
5991                      {
5992                         if(_class.type == bitClass)
5993                         {
5994                            unsigned int value;
5995                            GetUInt(exp.member.exp, &value);
5996
5997                            switch(type.kind)
5998                            {
5999                               case classType:
6000                               {
6001                                  Class _class = type._class.registered;
6002                                  if(_class.type == structClass)
6003                                  {
6004                                     void (*Get)(unsigned int, void *) = (void *)prop.Get;
6005
6006                                     exp.instance = Instantiation { };
6007                                     exp.instance.data = new0 byte[_class.structSize];
6008                                     exp.instance._class = MkSpecifierName(_class.fullName);
6009                                     exp.instance.loc = exp.loc;
6010                                     //exp.instance.fullSet = true;
6011                                     exp.type = instanceExp;
6012                                     Get(value, exp.instance.data);
6013                                     PopulateInstance(exp.instance);
6014                                  }
6015                                  else if(_class.type == bitClass)
6016                                  {
6017                                     unsigned int (*Get)(unsigned int) = (void *)prop.Get;
6018                                     uint64 bits = Get(value);
6019                                     exp.constant = PrintHexUInt64(bits);
6020                                     exp.type = constantExp;
6021                                  }
6022                                  break;
6023                               }
6024                            }
6025                         }
6026                         else if(_class.type == structClass)
6027                         {
6028                            char * value = (exp.member.exp.type == instanceExp ) ? exp.member.exp.instance.data : null;
6029                            switch(type.kind)
6030                            {
6031                               case classType:
6032                               {
6033                                  Class _class = type._class.registered;
6034                                  if(_class.type == structClass && value)
6035                                  {
6036                                     void (*Get)(void *, void *) = (void *)prop.Get;
6037
6038                                     exp.instance = Instantiation { };
6039                                     exp.instance.data = new0 byte[_class.structSize];
6040                                     exp.instance._class = MkSpecifierName(_class.fullName);
6041                                     exp.instance.loc = exp.loc;
6042                                     //exp.instance.fullSet = true;
6043                                     exp.type = instanceExp;
6044                                     Get(value, exp.instance.data);
6045                                     PopulateInstance(exp.instance);
6046                                  }
6047                                  break;
6048                               }
6049                            }
6050                         }
6051                         /*else
6052                         {
6053                            char * value = exp.member.exp.instance.data;
6054                            switch(type.kind)
6055                            {
6056                               case classType:
6057                               {
6058                                  Class _class = type._class.registered;
6059                                  if(_class.type == normalClass)
6060                                  {
6061                                     void *(*Get)(void *) = (void *)prop.Get;
6062
6063                                     exp.instance = Instantiation { };
6064                                     exp.instance._class = MkSpecifierName(_class.fullName); //MkClassName(_class.fullName);
6065                                     exp.type = instanceExp;
6066                                     exp.instance.data = Get(value, exp.instance.data);
6067                                  }
6068                                  break;
6069                               }
6070                            }
6071                         }
6072                         */
6073                      }
6074                   }
6075                }
6076                else
6077                {
6078                   exp.isConstant = false;
6079                }
6080             }
6081             else if(member)
6082             {
6083             }
6084          }
6085
6086          if(exp.type != ExpressionType::memberExp)
6087          {
6088             FreeExpression(memberExp);
6089             FreeIdentifier(memberID);
6090          }
6091          break;
6092       }
6093       case typeSizeExp:
6094       {
6095          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
6096          FreeExpContents(exp);
6097          exp.constant = PrintUInt(ComputeTypeSize(type));
6098          exp.type = constantExp;
6099          FreeType(type);
6100          break;
6101       }
6102       case classSizeExp:
6103       {
6104          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
6105          if(classSym && classSym.registered)
6106          {
6107             if(classSym.registered.fixed)
6108             {
6109                FreeSpecifier(exp._class);
6110                exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
6111                exp.type = constantExp;
6112             }
6113             else
6114             {
6115                char className[1024];
6116                strcpy(className, "__ecereClass_");
6117                FullClassNameCat(className, classSym.string, true);
6118                MangleClassName(className);
6119
6120                DeclareClass(classSym, className);
6121
6122                FreeExpContents(exp);
6123                exp.type = pointerExp;
6124                exp.member.exp = MkExpIdentifier(MkIdentifier(className));
6125                exp.member.member = MkIdentifier("structSize");
6126             }
6127          }
6128          break;
6129       }
6130       case castExp:
6131       //case constantExp:
6132       {
6133          Type type;
6134          Expression e = exp;
6135          if(exp.type == castExp)
6136          {
6137             if(exp.cast.exp)
6138                ComputeExpression(exp.cast.exp);
6139             e = exp.cast.exp;
6140          }
6141          if(e && exp.expType)
6142          {
6143             /*if(exp.destType)
6144                type = exp.destType;
6145             else*/
6146                type = exp.expType;
6147             if(type.kind == classType)
6148             {
6149                Class _class = type._class.registered;
6150                if(_class && (_class.type == unitClass || _class.type == bitClass))
6151                {
6152                   if(!_class.dataType)
6153                      _class.dataType = ProcessTypeString(_class.dataTypeString, false);
6154                   type = _class.dataType;
6155                }
6156             }
6157
6158             switch(type.kind)
6159             {
6160                case _BoolType:
6161                case charType:
6162                   if(type.isSigned)
6163                   {
6164                      char value = 0;
6165                      if(GetChar(e, &value))
6166                      {
6167                         FreeExpContents(exp);
6168                         exp.constant = PrintChar(value);
6169                         exp.type = constantExp;
6170                      }
6171                   }
6172                   else
6173                   {
6174                      unsigned char value = 0;
6175                      if(GetUChar(e, &value))
6176                      {
6177                         FreeExpContents(exp);
6178                         exp.constant = PrintUChar(value);
6179                         exp.type = constantExp;
6180                      }
6181                   }
6182                   break;
6183                case shortType:
6184                   if(type.isSigned)
6185                   {
6186                      short value = 0;
6187                      if(GetShort(e, &value))
6188                      {
6189                         FreeExpContents(exp);
6190                         exp.constant = PrintShort(value);
6191                         exp.type = constantExp;
6192                      }
6193                   }
6194                   else
6195                   {
6196                      unsigned short value = 0;
6197                      if(GetUShort(e, &value))
6198                      {
6199                         FreeExpContents(exp);
6200                         exp.constant = PrintUShort(value);
6201                         exp.type = constantExp;
6202                      }
6203                   }
6204                   break;
6205                case intType:
6206                   if(type.isSigned)
6207                   {
6208                      int value = 0;
6209                      if(GetInt(e, &value))
6210                      {
6211                         FreeExpContents(exp);
6212                         exp.constant = PrintInt(value);
6213                         exp.type = constantExp;
6214                      }
6215                   }
6216                   else
6217                   {
6218                      unsigned int value = 0;
6219                      if(GetUInt(e, &value))
6220                      {
6221                         FreeExpContents(exp);
6222                         exp.constant = PrintUInt(value);
6223                         exp.type = constantExp;
6224                      }
6225                   }
6226                   break;
6227                case int64Type:
6228                   if(type.isSigned)
6229                   {
6230                      int64 value = 0;
6231                      if(GetInt64(e, &value))
6232                      {
6233                         FreeExpContents(exp);
6234                         exp.constant = PrintInt64(value);
6235                         exp.type = constantExp;
6236                      }
6237                   }
6238                   else
6239                   {
6240                      uint64 value = 0;
6241                      if(GetUInt64(e, &value))
6242                      {
6243                         FreeExpContents(exp);
6244                         exp.constant = PrintUInt64(value);
6245                         exp.type = constantExp;
6246                      }
6247                   }
6248                   break;
6249                case intPtrType:
6250                   if(type.isSigned)
6251                   {
6252                      intptr value = 0;
6253                      if(GetIntPtr(e, &value))
6254                      {
6255                         FreeExpContents(exp);
6256                         exp.constant = PrintInt64((int64)value);
6257                         exp.type = constantExp;
6258                      }
6259                   }
6260                   else
6261                   {
6262                      uintptr value = 0;
6263                      if(GetUIntPtr(e, &value))
6264                      {
6265                         FreeExpContents(exp);
6266                         exp.constant = PrintUInt64((uint64)value);
6267                         exp.type = constantExp;
6268                      }
6269                   }
6270                   break;
6271                case intSizeType:
6272                   if(type.isSigned)
6273                   {
6274                      intsize value = 0;
6275                      if(GetIntSize(e, &value))
6276                      {
6277                         FreeExpContents(exp);
6278                         exp.constant = PrintInt64((int64)value);
6279                         exp.type = constantExp;
6280                      }
6281                   }
6282                   else
6283                   {
6284                      uintsize value = 0;
6285                      if(GetUIntSize(e, &value))
6286                      {
6287                         FreeExpContents(exp);
6288                         exp.constant = PrintUInt64((uint64)value);
6289                         exp.type = constantExp;
6290                      }
6291                   }
6292                   break;
6293                case floatType:
6294                {
6295                   float value = 0;
6296                   if(GetFloat(e, &value))
6297                   {
6298                      FreeExpContents(exp);
6299                      exp.constant = PrintFloat(value);
6300                      exp.type = constantExp;
6301                   }
6302                   break;
6303                }
6304                case doubleType:
6305                {
6306                   double value = 0;
6307                   if(GetDouble(e, &value))
6308                   {
6309                      FreeExpContents(exp);
6310                      exp.constant = PrintDouble(value);
6311                      exp.type = constantExp;
6312                   }
6313                   break;
6314                }
6315             }
6316          }
6317          break;
6318       }
6319       case conditionExp:
6320       {
6321          Operand op1 { };
6322          Operand op2 { };
6323          Operand op3 { };
6324
6325          if(exp.cond.exp)
6326             // Caring only about last expression for now...
6327             ComputeExpression(exp.cond.exp->last);
6328          if(exp.cond.elseExp)
6329             ComputeExpression(exp.cond.elseExp);
6330          if(exp.cond.cond)
6331             ComputeExpression(exp.cond.cond);
6332
6333          op1 = GetOperand(exp.cond.cond);
6334          if(op1.type) op1.type.refCount++;
6335          op2 = GetOperand(exp.cond.exp->last);
6336          if(op2.type) op2.type.refCount++;
6337          op3 = GetOperand(exp.cond.elseExp);
6338          if(op3.type) op3.type.refCount++;
6339
6340          if(op1.ops.Cond) { FreeExpContents(exp); op1.ops.Cond(exp, op1, op2, op3); }
6341          if(op1.type) FreeType(op1.type);
6342          if(op2.type) FreeType(op2.type);
6343          if(op3.type) FreeType(op3.type);
6344          break;
6345       }
6346    }
6347 }
6348
6349 static bool CheckExpressionType(Expression exp, Type destType, bool skipUnitBla, bool warnConst)
6350 {
6351    bool result = true;
6352    if(destType)
6353    {
6354       OldList converts { };
6355       Conversion convert;
6356
6357       if(destType.kind == voidType)
6358          return false;
6359
6360       if(!MatchTypeExpression(exp, destType, &converts, skipUnitBla, warnConst))
6361          result = false;
6362       if(converts.count)
6363       {
6364          // for(convert = converts.last; convert; convert = convert.prev)
6365          for(convert = converts.first; convert; convert = convert.next)
6366          {
6367             bool empty = !(convert.isGet ? (void *)convert.convert.Get : (void *)convert.convert.Set);
6368             if(!empty)
6369             {
6370                Expression newExp { };
6371                ClassObjectType objectType = exp.expType ? exp.expType.classObjectType : none;
6372
6373                // TODO: Check this...
6374                *newExp = *exp;
6375                newExp.prev = null;
6376                newExp.next = null;
6377                newExp.destType = null;
6378
6379                if(convert.isGet)
6380                {
6381                   // [exp].ColorRGB
6382                   exp.type = memberExp;
6383                   exp.addedThis = true;
6384                   exp.member.exp = newExp;
6385                   FreeType(exp.member.exp.expType);
6386
6387                   exp.member.exp.expType = MkClassType(convert.convert._class.fullName);
6388                   exp.member.exp.expType.classObjectType = objectType;
6389                   exp.member.member = MkIdentifier(convert.convert.dataTypeString);
6390                   exp.member.memberType = propertyMember;
6391                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6392                   // TESTING THIS... for (int)degrees
6393                   exp.needCast = true;
6394                   if(exp.expType) exp.expType.refCount++;
6395                   ApplyAnyObjectLogic(exp.member.exp);
6396                }
6397                else
6398                {
6399
6400                   /*if(exp.isConstant)
6401                   {
6402                      // Color { ColorRGB = [exp] };
6403                      exp.type = instanceExp;
6404                      exp.instance = MkInstantiation(MkSpecifierName((convert.convert._class.fullName), //MkClassName(convert.convert._class.fullName),
6405                         null, MkListOne(MkMembersInitList(MkListOne(MkMemberInit(
6406                         MkListOne(MkIdentifier(convert.convert.dataTypeString)), newExp)))));
6407                   }
6408                   else*/
6409                   {
6410                      // If not constant, don't turn it yet into an instantiation
6411                      // (Go through the deep members system first)
6412                      exp.type = memberExp;
6413                      exp.addedThis = true;
6414                      exp.member.exp = newExp;
6415
6416                      // ADDED THIS HERE TO SOLVE PROPERTY ISSUES WITH NOHEAD CLASSES
6417                      if(/*!notByReference && */newExp.expType && newExp.expType.kind == classType && newExp.expType._class && newExp.expType._class.registered &&
6418                         newExp.expType._class.registered.type == noHeadClass)
6419                      {
6420                         newExp.byReference = true;
6421                      }
6422
6423                      FreeType(exp.member.exp.expType);
6424                      /*exp.member.exp.expType = convert.convert.dataType;
6425                      if(convert.convert.dataType) convert.convert.dataType.refCount++;*/
6426                      exp.member.exp.expType = null;
6427                      if(convert.convert.dataType)
6428                      {
6429                         exp.member.exp.expType = { };
6430                         CopyTypeInto(exp.member.exp.expType, convert.convert.dataType);
6431                         exp.member.exp.expType.refCount = 1;
6432                         exp.member.exp.expType.classObjectType = objectType;
6433                         ApplyAnyObjectLogic(exp.member.exp);
6434                      }
6435
6436                      exp.member.member = MkIdentifier(convert.convert._class.fullName);
6437                      exp.member.memberType = reverseConversionMember;
6438                      exp.expType = convert.resultType ? convert.resultType :
6439                         MkClassType(convert.convert._class.fullName);
6440                      exp.needCast = true;
6441                      if(convert.resultType) convert.resultType.refCount++;
6442                   }
6443                }
6444             }
6445             else
6446             {
6447                FreeType(exp.expType);
6448                if(convert.isGet)
6449                {
6450                   exp.expType = convert.resultType ? convert.resultType : convert.convert.dataType;
6451                   exp.needCast = true;
6452                   if(exp.expType) exp.expType.refCount++;
6453                }
6454                else
6455                {
6456                   exp.expType = convert.resultType ? convert.resultType : MkClassType(convert.convert._class.fullName);
6457                   exp.needCast = true;
6458                   if(convert.resultType)
6459                      convert.resultType.refCount++;
6460                }
6461             }
6462          }
6463          if(exp.isConstant && inCompiler)
6464             ComputeExpression(exp);
6465
6466          converts.Free(FreeConvert);
6467       }
6468
6469       if(!result && exp.expType && converts.count)      // TO TEST: Added converts.count here to avoid a double warning with function type
6470       {
6471          result = MatchTypes(exp.expType, exp.destType, null, null, null, true, true, false, false, warnConst);
6472       }
6473       if(!result && exp.expType && exp.destType)
6474       {
6475          if((exp.destType.kind == classType && exp.expType.kind == pointerType &&
6476              exp.expType.type.kind == classType && exp.expType.type._class == exp.destType._class && exp.destType._class.registered && exp.destType._class.registered.type == structClass) ||
6477             (exp.expType.kind == classType && exp.destType.kind == pointerType &&
6478             exp.destType.type.kind == classType && exp.destType.type._class == exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass))
6479             result = true;
6480       }
6481    }
6482    // if(result) CheckTemplateTypes(exp);
6483    return result;
6484 }
6485
6486 void CheckTemplateTypes(Expression exp)
6487 {
6488    if(exp.destType && exp.destType.passAsTemplate && exp.expType && exp.expType.kind != templateType && !exp.expType.passAsTemplate)
6489    {
6490       Expression newExp { };
6491       Context context;
6492       *newExp = *exp;
6493       if(exp.destType) exp.destType.refCount++;
6494       if(exp.expType)  exp.expType.refCount++;
6495       newExp.prev = null;
6496       newExp.next = null;
6497
6498       switch(exp.expType.kind)
6499       {
6500          case doubleType:
6501             if(exp.destType.classObjectType)
6502             {
6503                // We need to pass the address, just pass it along (Undo what was done above)
6504                if(exp.destType) exp.destType.refCount--;
6505                if(exp.expType)  exp.expType.refCount--;
6506                delete newExp;
6507             }
6508             else
6509             {
6510                // If we're looking for value:
6511                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6512                OldList * specs;
6513                OldList * unionDefs = MkList();
6514                OldList * statements = MkList();
6515                context = PushContext();
6516                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6517                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6518                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6519                exp.type = extensionCompoundExp;
6520                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6521                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")), '=', newExp))));
6522                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
6523                exp.compound.compound.context = context;
6524                PopContext(context);
6525             }
6526             break;
6527          default:
6528             exp.type = castExp;
6529             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6530             exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6531             break;
6532       }
6533    }
6534    else if(exp.expType && exp.expType.passAsTemplate && exp.destType && exp.usage.usageGet && exp.destType.kind != templateType && !exp.destType.passAsTemplate)
6535    {
6536       Expression newExp { };
6537       Statement compound;
6538       Context context;
6539       *newExp = *exp;
6540       if(exp.destType) exp.destType.refCount++;
6541       if(exp.expType)  exp.expType.refCount++;
6542       newExp.prev = null;
6543       newExp.next = null;
6544
6545       switch(exp.expType.kind)
6546       {
6547          case doubleType:
6548             if(exp.destType.classObjectType)
6549             {
6550                // We need to pass the address, just pass it along (Undo what was done above)
6551                if(exp.destType) exp.destType.refCount--;
6552                if(exp.expType)  exp.expType.refCount--;
6553                delete newExp;
6554             }
6555             else
6556             {
6557                // If we're looking for value:
6558                // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
6559                OldList * specs;
6560                OldList * unionDefs = MkList();
6561                OldList * statements = MkList();
6562                context = PushContext();
6563                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(DOUBLE)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("d"))), null)));
6564                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
6565                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
6566                exp.type = extensionCompoundExp;
6567                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
6568                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
6569                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")))));
6570                exp.compound.compound.context = context;
6571                PopContext(context);
6572             }
6573             break;
6574          case classType:
6575          {
6576             if(exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass)
6577             {
6578                exp.type = bracketsExp;
6579                exp.list = MkListOne(MkExpOp(null, '*', MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)),
6580                   MkDeclaratorPointer(MkPointer(null, null), null)), newExp)));
6581                ProcessExpressionType(exp.list->first);
6582                break;
6583             }
6584             else
6585             {
6586                exp.type = bracketsExp;
6587                exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(exp.expType._class.string)), null), newExp));
6588                newExp.needCast = true;
6589                ProcessExpressionType(exp.list->first);
6590                break;
6591             }
6592          }
6593          default:
6594          {
6595             if(exp.expType.kind == templateType)
6596             {
6597                Type type = ProcessTemplateParameterType(exp.expType.templateParameter);
6598                if(type)
6599                {
6600                   FreeType(exp.destType);
6601                   FreeType(exp.expType);
6602                   delete newExp;
6603                   break;
6604                }
6605             }
6606             if(newExp.type == memberExp && newExp.member.memberType == dataMember)
6607             {
6608                exp.type = opExp;
6609                exp.op.op = '*';
6610                exp.op.exp1 = null;
6611                exp.op.exp2 = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uint64")), MkDeclaratorPointer(MkPointer(null, null), null)),
6612                   MkExpBrackets(MkListOne(MkExpOp(null, '&', newExp))));
6613             }
6614             else
6615             {
6616                char typeString[1024];
6617                Declarator decl;
6618                OldList * specs = MkList();
6619                typeString[0] = '\0';
6620                PrintType(exp.expType, typeString, false, false);
6621                decl = SpecDeclFromString(typeString, specs, null);
6622
6623                exp.type = castExp;
6624                //exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
6625                exp.cast.typeName = MkTypeName(specs, decl);
6626                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
6627                exp.cast.exp.needCast = true;
6628             }
6629             break;
6630          }
6631       }
6632    }
6633 }
6634 // TODO: The Symbol tree should be reorganized by namespaces
6635 // Name Space:
6636 //    - Tree of all symbols within (stored without namespace)
6637 //    - Tree of sub-namespaces
6638
6639 static Symbol ScanWithNameSpace(BinaryTree tree, const char * nameSpace, const char * name)
6640 {
6641    int nsLen = strlen(nameSpace);
6642    Symbol symbol;
6643    // Start at the name space prefix
6644    for(symbol = (Symbol)tree.FindPrefix(nameSpace); symbol; symbol = (Symbol)((BTNode)symbol).next)
6645    {
6646       char * s = symbol.string;
6647       if(!strncmp(s, nameSpace, nsLen))
6648       {
6649          // This supports e.g. matching ecere::Socket to ecere::net::Socket
6650          int c;
6651          char * namePart;
6652          for(c = strlen(s)-1; c >= 0; c--)
6653             if(s[c] == ':')
6654                break;
6655
6656          namePart = s+c+1;
6657          if(!strcmp(namePart, name))
6658          {
6659             // TODO: Error on ambiguity
6660             return symbol;
6661          }
6662       }
6663       else
6664          break;
6665    }
6666    return null;
6667 }
6668
6669 static Symbol FindWithNameSpace(BinaryTree tree, const char * name)
6670 {
6671    int c;
6672    char nameSpace[1024];
6673    const char * namePart;
6674    bool gotColon = false;
6675
6676    nameSpace[0] = '\0';
6677    for(c = strlen(name)-1; c >= 0; c--)
6678       if(name[c] == ':')
6679       {
6680          gotColon = true;
6681          break;
6682       }
6683
6684    namePart = name+c+1;
6685    while(c >= 0 && name[c] == ':') c--;
6686    if(c >= 0)
6687    {
6688       // Try an exact match first
6689       Symbol symbol = (Symbol)tree.FindString(name);
6690       if(symbol)
6691          return symbol;
6692
6693       // Namespace specified
6694       memcpy(nameSpace, name, c + 1);
6695       nameSpace[c+1] = 0;
6696
6697       return ScanWithNameSpace(tree, nameSpace, namePart);
6698    }
6699    else if(gotColon)
6700    {
6701       // Looking for a global symbol, e.g. ::Sleep()
6702       Symbol symbol = (Symbol)tree.FindString(namePart);
6703       return symbol;
6704    }
6705    else
6706    {
6707       // Name only (no namespace specified)
6708       Symbol symbol = (Symbol)tree.FindString(namePart);
6709       if(symbol)
6710          return symbol;
6711       return ScanWithNameSpace(tree, "", namePart);
6712    }
6713    return null;
6714 }
6715
6716 static void ProcessDeclaration(Declaration decl);
6717
6718 /*static */Symbol FindSymbol(const char * name, Context startContext, Context endContext, bool isStruct, bool globalNameSpace)
6719 {
6720 #ifdef _DEBUG
6721    //Time startTime = GetTime();
6722 #endif
6723    // Optimize this later? Do this before/less?
6724    Context ctx;
6725    Symbol symbol = null;
6726    // First, check if the identifier is declared inside the function
6727    //for(ctx = curContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6728
6729    for(ctx = startContext; ctx /*!= topContext.parent */&& !symbol; ctx = ctx.parent)
6730    {
6731       if(ctx == globalContext && !globalNameSpace && ctx.hasNameSpace)
6732       {
6733          symbol = null;
6734          if(thisNameSpace)
6735          {
6736             char curName[1024];
6737             strcpy(curName, thisNameSpace);
6738             strcat(curName, "::");
6739             strcat(curName, name);
6740             // Try to resolve in current namespace first
6741             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, curName);
6742          }
6743          if(!symbol)
6744             symbol = FindWithNameSpace(isStruct ? ctx.structSymbols : ctx.symbols, name);
6745       }
6746       else
6747          symbol = (Symbol)(isStruct ? ctx.structSymbols : ctx.symbols).FindString(name);
6748
6749       if(symbol || ctx == endContext) break;
6750    }
6751    if(inCompiler && curExternal && symbol && ctx == globalContext && curExternal.symbol && symbol.id > curExternal.symbol.idCode && symbol.pointerExternal)
6752    {
6753       if(symbol.pointerExternal.type == functionExternal)
6754       {
6755          FunctionDefinition function = symbol.pointerExternal.function;
6756
6757          // Modified this recently...
6758          Context tmpContext = curContext;
6759          curContext = null;
6760          symbol.pointerExternal = MkExternalDeclaration(MkDeclaration(CopyList(function.specifiers, CopySpecifier), MkListOne(MkInitDeclarator(CopyDeclarator(function.declarator), null))));
6761          curContext = tmpContext;
6762
6763          symbol.pointerExternal.symbol = symbol;
6764
6765          // TESTING THIS:
6766          DeclareType(symbol.type, true, true);
6767
6768          ast->Insert(curExternal.prev, symbol.pointerExternal);
6769
6770          symbol.id = curExternal.symbol.idCode;
6771
6772       }
6773       else if(symbol.pointerExternal.type == declarationExternal && curExternal.symbol.idCode < symbol.pointerExternal.symbol.id) // Added id comparison because Global Function prototypes were broken
6774       {
6775          ast->Move(symbol.pointerExternal, curExternal.prev);
6776          symbol.id = curExternal.symbol.idCode;
6777       }
6778    }
6779 #ifdef _DEBUG
6780    //findSymbolTotalTime += GetTime() - startTime;
6781 #endif
6782    return symbol;
6783 }
6784
6785 static void GetTypeSpecs(Type type, OldList * specs)
6786 {
6787    if(!type.isSigned && type.kind != intPtrType && type.kind != intSizeType) ListAdd(specs, MkSpecifier(UNSIGNED));
6788    switch(type.kind)
6789    {
6790       case classType:
6791       {
6792          if(type._class.registered)
6793          {
6794             if(!type._class.registered.dataType)
6795                type._class.registered.dataType = ProcessTypeString(type._class.registered.dataTypeString, false);
6796             GetTypeSpecs(type._class.registered.dataType, specs);
6797          }
6798          break;
6799       }
6800       case doubleType: ListAdd(specs, MkSpecifier(DOUBLE)); break;
6801       case floatType: ListAdd(specs, MkSpecifier(FLOAT)); break;
6802       case charType: ListAdd(specs, MkSpecifier(CHAR)); break;
6803       case _BoolType: ListAdd(specs, MkSpecifier(_BOOL)); break;
6804       case shortType: ListAdd(specs, MkSpecifier(SHORT)); break;
6805       case int64Type: ListAdd(specs, MkSpecifier(INT64)); break;
6806       case intPtrType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intptr" : "uintptr")); break;
6807       case intSizeType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intsize" : "uintsize")); break;
6808       case intType:
6809       default:
6810          ListAdd(specs, MkSpecifier(INT)); break;
6811    }
6812 }
6813
6814 static void PrintArraySize(Type arrayType, char * string)
6815 {
6816    char size[256];
6817    size[0] = '\0';
6818    strcat(size, "[");
6819    if(arrayType.enumClass)
6820       strcat(size, arrayType.enumClass.string);
6821    else if(arrayType.arraySizeExp)
6822       PrintExpression(arrayType.arraySizeExp, size);
6823    strcat(size, "]");
6824    strcat(string, size);
6825 }
6826
6827 // WARNING : This function expects a null terminated string since it recursively concatenate...
6828 static void PrintTypeSpecs(Type type, char * string, bool fullName, bool printConst)
6829 {
6830    if(type)
6831    {
6832       if(printConst && type.constant)
6833          strcat(string, "const ");
6834       switch(type.kind)
6835       {
6836          case classType:
6837          {
6838             Symbol c = type._class;
6839             // TODO: typed_object does not fully qualify the type, as it may have taken up an actual class (Stored in _class) from overriding
6840             //       look into merging with thisclass ?
6841             if(type.classObjectType == typedObject)
6842                strcat(string, "typed_object");
6843             else if(type.classObjectType == anyObject)
6844                strcat(string, "any_object");
6845             else
6846             {
6847                if(c && c.string)
6848                   strcat(string, (fullName || !c.registered) ? c.string : c.registered.name);
6849             }
6850             if(type.byReference)
6851                strcat(string, " &");
6852             break;
6853          }
6854          case voidType: strcat(string, "void"); break;
6855          case intType:  strcat(string, type.isSigned ? "int" : "uint"); break;
6856          case int64Type:  strcat(string, type.isSigned ? "int64" : "uint64"); break;
6857          case intPtrType:  strcat(string, type.isSigned ? "intptr" : "uintptr"); break;
6858          case intSizeType:  strcat(string, type.isSigned ? "intsize" : "uintsize"); break;
6859          case charType: strcat(string, type.isSigned ? "char" : "byte"); break;
6860          case _BoolType: strcat(string, "_Bool"); break;
6861          case shortType: strcat(string, type.isSigned ? "short" : "uint16"); break;
6862          case floatType: strcat(string, "float"); break;
6863          case doubleType: strcat(string, "double"); break;
6864          case structType:
6865             if(type.enumName)
6866             {
6867                strcat(string, "struct ");
6868                strcat(string, type.enumName);
6869             }
6870             else if(type.typeName)
6871                strcat(string, type.typeName);
6872             else
6873             {
6874                Type member;
6875                strcat(string, "struct { ");
6876                for(member = type.members.first; member; member = member.next)
6877                {
6878                   PrintType(member, string, true, fullName);
6879                   strcat(string,"; ");
6880                }
6881                strcat(string,"}");
6882             }
6883             break;
6884          case unionType:
6885             if(type.enumName)
6886             {
6887                strcat(string, "union ");
6888                strcat(string, type.enumName);
6889             }
6890             else if(type.typeName)
6891                strcat(string, type.typeName);
6892             else
6893             {
6894                strcat(string, "union ");
6895                strcat(string,"(unnamed)");
6896             }
6897             break;
6898          case enumType:
6899             if(type.enumName)
6900             {
6901                strcat(string, "enum ");
6902                strcat(string, type.enumName);
6903             }
6904             else if(type.typeName)
6905                strcat(string, type.typeName);
6906             else
6907                strcat(string, "int"); // "enum");
6908             break;
6909          case ellipsisType:
6910             strcat(string, "...");
6911             break;
6912          case subClassType:
6913             strcat(string, "subclass(");
6914             strcat(string, type._class ? type._class.string : "int");
6915             strcat(string, ")");
6916             break;
6917          case templateType:
6918             strcat(string, type.templateParameter.identifier.string);
6919             break;
6920          case thisClassType:
6921             strcat(string, "thisclass");
6922             break;
6923          case vaListType:
6924             strcat(string, "__builtin_va_list");
6925             break;
6926       }
6927    }
6928 }
6929
6930 static void PrintName(Type type, char * string, bool fullName)
6931 {
6932    if(type.name && type.name[0])
6933    {
6934       if(fullName)
6935          strcat(string, type.name);
6936       else
6937       {
6938          char * name = RSearchString(type.name, "::", strlen(type.name), true, false);
6939          if(name) name += 2; else name = type.name;
6940          strcat(string, name);
6941       }
6942    }
6943 }
6944
6945 static void PrintAttribs(Type type, char * string)
6946 {
6947    if(type)
6948    {
6949       if(type.dllExport)   strcat(string, "dllexport ");
6950       if(type.attrStdcall) strcat(string, "stdcall ");
6951    }
6952 }
6953
6954 static void PrePrintType(Type type, char * string, bool fullName, Type parentType, bool printConst)
6955 {
6956    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
6957    {
6958       Type attrType = null;
6959       if((type.kind == functionType || type.kind == methodType) && (!parentType || parentType.kind != pointerType))
6960          PrintAttribs(type, string);
6961       if(printConst && type.constant && (type.kind == functionType || type.kind == methodType))
6962          strcat(string, " const");
6963       PrePrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName, type, printConst);
6964       if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
6965          strcat(string, " (");
6966       if(type.kind == pointerType)
6967       {
6968          if(type.type.kind == functionType || type.type.kind == methodType)
6969             PrintAttribs(type.type, string);
6970       }
6971       if(type.kind == pointerType)
6972       {
6973          if(type.type.kind == functionType || type.type.kind == methodType || type.type.kind == arrayType)
6974             strcat(string, "*");
6975          else
6976             strcat(string, " *");
6977       }
6978       if(printConst && type.constant && type.kind == pointerType)
6979          strcat(string, " const");
6980    }
6981    else
6982       PrintTypeSpecs(type, string, fullName, printConst);
6983 }
6984
6985 static void PostPrintType(Type type, char * string, bool fullName)
6986 {
6987    if(type.kind == pointerType && (type.type.kind == arrayType || type.type.kind == functionType || type.type.kind == methodType))
6988       strcat(string, ")");
6989    if(type.kind == arrayType)
6990       PrintArraySize(type, string);
6991    else if(type.kind == functionType)
6992    {
6993       Type param;
6994       strcat(string, "(");
6995       for(param = type.params.first; param; param = param.next)
6996       {
6997          PrintType(param, string, true, fullName);
6998          if(param.next) strcat(string, ", ");
6999       }
7000       strcat(string, ")");
7001    }
7002    if(type.kind == arrayType || type.kind == pointerType || type.kind == functionType || type.kind == methodType)
7003       PostPrintType(type.kind == methodType ? type.method.dataType : type.type, string, fullName);
7004 }
7005
7006 // *****
7007 // TODO: Add a max buffer size to avoid overflows. This function is used with static size char arrays.
7008 // *****
7009 static void _PrintType(Type type, char * string, bool printName, bool fullName, bool printConst)
7010 {
7011    PrePrintType(type, string, fullName, null, printConst);
7012
7013    if(type.thisClass || (printName && type.name && type.name[0]))
7014       strcat(string, " ");
7015    if(/*(type.kind == methodType || type.kind == functionType) && */(type.thisClass || type.staticMethod))
7016    {
7017       Symbol _class = type.thisClass;
7018       if((type.classObjectType == typedObject || type.classObjectType == classPointer) || (_class && !strcmp(_class.string, "class")))
7019       {
7020          if(type.classObjectType == classPointer)
7021             strcat(string, "class");
7022          else
7023             strcat(string, type.byReference ? "typed_object&" : "typed_object");
7024       }
7025       else if(_class && _class.string)
7026       {
7027          String s = _class.string;
7028          if(fullName)
7029             strcat(string, s);
7030          else
7031          {
7032             char * name = RSearchString(s, "::", strlen(s), true, false);
7033             if(name) name += 2; else name = s;
7034             strcat(string, name);
7035          }
7036       }
7037       strcat(string, "::");
7038    }
7039
7040    if(printName && type.name)
7041       PrintName(type, string, fullName);
7042    PostPrintType(type, string, fullName);
7043    if(type.bitFieldCount)
7044    {
7045       char count[100];
7046       sprintf(count, ":%d", type.bitFieldCount);
7047       strcat(string, count);
7048    }
7049 }
7050
7051 void PrintType(Type type, char * string, bool printName, bool fullName)
7052 {
7053    _PrintType(type, string, printName, fullName, true);
7054 }
7055
7056 void PrintTypeNoConst(Type type, char * string, bool printName, bool fullName)
7057 {
7058    _PrintType(type, string, printName, fullName, false);
7059 }
7060
7061 static Type FindMember(Type type, char * string)
7062 {
7063    Type memberType;
7064    for(memberType = type.members.first; memberType; memberType = memberType.next)
7065    {
7066       if(!memberType.name)
7067       {
7068          Type subType = FindMember(memberType, string);
7069          if(subType)
7070             return subType;
7071       }
7072       else if(!strcmp(memberType.name, string))
7073          return memberType;
7074    }
7075    return null;
7076 }
7077
7078 Type FindMemberAndOffset(Type type, char * string, uint * offset)
7079 {
7080    Type memberType;
7081    for(memberType = type.members.first; memberType; memberType = memberType.next)
7082    {
7083       if(!memberType.name)
7084       {
7085          Type subType = FindMember(memberType, string);
7086          if(subType)
7087          {
7088             *offset += memberType.offset;
7089             return subType;
7090          }
7091       }
7092       else if(!strcmp(memberType.name, string))
7093       {
7094          *offset += memberType.offset;
7095          return memberType;
7096       }
7097    }
7098    return null;
7099 }
7100
7101 public bool GetParseError() { return parseError; }
7102
7103 Expression ParseExpressionString(char * expression)
7104 {
7105    parseError = false;
7106
7107    fileInput = TempFile { };
7108    fileInput.Write(expression, 1, strlen(expression));
7109    fileInput.Seek(0, start);
7110
7111    echoOn = false;
7112    parsedExpression = null;
7113    resetScanner();
7114    expression_yyparse();
7115    delete fileInput;
7116
7117    return parsedExpression;
7118 }
7119
7120 static bool ResolveIdWithClass(Expression exp, Class _class, bool skipIDClassCheck)
7121 {
7122    Identifier id = exp.identifier;
7123    Method method = null;
7124    Property prop = null;
7125    DataMember member = null;
7126    ClassProperty classProp = null;
7127
7128    if(_class && _class.type == enumClass)
7129    {
7130       NamedLink value = null;
7131       Class enumClass = eSystem_FindClass(privateModule, "enum");
7132       if(enumClass)
7133       {
7134          Class baseClass;
7135          for(baseClass = _class; baseClass && baseClass.type == ClassType::enumClass; baseClass = baseClass.base)
7136          {
7137             EnumClassData e = ACCESS_CLASSDATA(baseClass, enumClass);
7138             for(value = e.values.first; value; value = value.next)
7139             {
7140                if(!strcmp(value.name, id.string))
7141                   break;
7142             }
7143             if(value)
7144             {
7145                char constant[256];
7146
7147                FreeExpContents(exp);
7148
7149                exp.type = constantExp;
7150                exp.isConstant = true;
7151                if(!strcmp(baseClass.dataTypeString, "int"))
7152                   sprintf(constant, "%d",(int)value.data);
7153                else
7154                   sprintf(constant, "0x%X",(int)value.data);
7155                exp.constant = CopyString(constant);
7156                //for(;_class.base && _class.base.type != systemClass; _class = _class.base);
7157                exp.expType = MkClassType(baseClass.fullName);
7158                break;
7159             }
7160          }
7161       }
7162       if(value)
7163          return true;
7164    }
7165    if((method = eClass_FindMethod(_class, id.string, privateModule)))
7166    {
7167       ProcessMethodType(method);
7168       exp.expType = Type
7169       {
7170          refCount = 1;
7171          kind = methodType;
7172          method = method;
7173          // Crash here?
7174          // TOCHECK: Put it back to what it was...
7175          // methodClass = _class;
7176          methodClass = (skipIDClassCheck || (id && id._class)) ? _class : null;
7177       };
7178       //id._class = null;
7179       return true;
7180    }
7181    else if((prop = eClass_FindProperty(_class, id.string, privateModule)))
7182    {
7183       if(!prop.dataType)
7184          ProcessPropertyType(prop);
7185       exp.expType = prop.dataType;
7186       if(prop.dataType) prop.dataType.refCount++;
7187       return true;
7188    }
7189    else if((member = eClass_FindDataMember(_class, id.string, privateModule, null, null)))
7190    {
7191       if(!member.dataType)
7192          member.dataType = ProcessTypeString(member.dataTypeString, false);
7193       exp.expType = member.dataType;
7194       if(member.dataType) member.dataType.refCount++;
7195       return true;
7196    }
7197    else if((classProp = eClass_FindClassProperty(_class, id.string)))
7198    {
7199       if(!classProp.dataType)
7200          classProp.dataType = ProcessTypeString(classProp.dataTypeString, false);
7201
7202       if(classProp.constant)
7203       {
7204          FreeExpContents(exp);
7205
7206          exp.isConstant = true;
7207          if(classProp.dataType.kind == pointerType && classProp.dataType.type.kind == charType)
7208          {
7209             //char constant[256];
7210             exp.type = stringExp;
7211             exp.constant = QMkString((char *)classProp.Get(_class));
7212          }
7213          else
7214          {
7215             char constant[256];
7216             exp.type = constantExp;
7217             sprintf(constant, "%d", (int)classProp.Get(_class));
7218             exp.constant = CopyString(constant);
7219          }
7220       }
7221       else
7222       {
7223          // TO IMPLEMENT...
7224       }
7225
7226       exp.expType = classProp.dataType;
7227       if(classProp.dataType) classProp.dataType.refCount++;
7228       return true;
7229    }
7230    return false;
7231 }
7232
7233 static GlobalData ScanGlobalData(NameSpace nameSpace, char * name)
7234 {
7235    BinaryTree * tree = &nameSpace.functions;
7236    GlobalData data = (GlobalData)tree->FindString(name);
7237    NameSpace * child;
7238    if(!data)
7239    {
7240       for(child = (NameSpace *)nameSpace.nameSpaces.first; child; child = (NameSpace *)((BTNode)child).next)
7241       {
7242          data = ScanGlobalData(child, name);
7243          if(data)
7244             break;
7245       }
7246    }
7247    return data;
7248 }
7249
7250 static GlobalData FindGlobalData(char * name)
7251 {
7252    int start = 0, c;
7253    NameSpace * nameSpace;
7254    nameSpace = globalData;
7255    for(c = 0; name[c]; c++)
7256    {
7257       if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
7258       {
7259          NameSpace * newSpace;
7260          char * spaceName = new char[c - start + 1];
7261          strncpy(spaceName, name + start, c - start);
7262          spaceName[c-start] = '\0';
7263          newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
7264          delete spaceName;
7265          if(!newSpace)
7266             return null;
7267          nameSpace = newSpace;
7268          if(name[c] == ':') c++;
7269          start = c+1;
7270       }
7271    }
7272    if(c - start)
7273    {
7274       return ScanGlobalData(nameSpace, name + start);
7275    }
7276    return null;
7277 }
7278
7279 static int definedExpStackPos;
7280 static void * definedExpStack[512];
7281
7282 // This function makes checkedExp equivalent to newExp, ending up freeing newExp
7283 void ReplaceExpContents(Expression checkedExp, Expression newExp)
7284 {
7285    Expression prev = checkedExp.prev, next = checkedExp.next;
7286
7287    FreeExpContents(checkedExp);
7288    FreeType(checkedExp.expType);
7289    FreeType(checkedExp.destType);
7290
7291    *checkedExp = *newExp;
7292
7293    delete newExp;
7294
7295    checkedExp.prev = prev;
7296    checkedExp.next = next;
7297 }
7298
7299 void ApplyAnyObjectLogic(Expression e)
7300 {
7301    Type destType = /*(e.destType && e.destType.kind == ellipsisType) ? ellipsisDestType : */e.destType;
7302 #ifdef _DEBUG
7303    char debugExpString[4096];
7304    debugExpString[0] = '\0';
7305    PrintExpression(e, debugExpString);
7306 #endif
7307
7308    if(destType && (/*destType.classObjectType == ClassObjectType::typedObject || */destType.classObjectType == anyObject))
7309    {
7310       //if(e.destType && e.destType.kind == ellipsisType) usedEllipsis = true;
7311       //ellipsisDestType = destType;
7312       if(e && e.expType)
7313       {
7314          Type type = e.expType;
7315          Class _class = null;
7316          //Type destType = e.destType;
7317
7318          if(type.kind == classType && type._class && type._class.registered)
7319          {
7320             _class = type._class.registered;
7321          }
7322          else if(type.kind == subClassType)
7323          {
7324             _class = FindClass("ecere::com::Class").registered;
7325          }
7326          else
7327          {
7328             char string[1024] = "";
7329             Symbol classSym;
7330
7331             PrintTypeNoConst(type, string, false, true);
7332             classSym = FindClass(string);
7333             if(classSym) _class = classSym.registered;
7334          }
7335
7336          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...
7337             (!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))) ||
7338             destType.byReference)))
7339          {
7340             if(!_class || strcmp(_class.fullName, "char *"))     // TESTING THIS WITH NEW String class...
7341             {
7342                Expression checkedExp = e, newExp;
7343
7344                while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7345                {
7346                   if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7347                   {
7348                      if(checkedExp.type == extensionCompoundExp)
7349                      {
7350                         checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7351                      }
7352                      else
7353                         checkedExp = checkedExp.list->last;
7354                   }
7355                   else if(checkedExp.type == castExp)
7356                      checkedExp = checkedExp.cast.exp;
7357                }
7358
7359                if(checkedExp && checkedExp.type == opExp && checkedExp.op.op == '*' && !checkedExp.op.exp1)
7360                {
7361                   newExp = checkedExp.op.exp2;
7362                   checkedExp.op.exp2 = null;
7363                   FreeExpContents(checkedExp);
7364
7365                   if(e.expType && e.expType.passAsTemplate)
7366                   {
7367                      char size[100];
7368                      ComputeTypeSize(e.expType);
7369                      sprintf(size, "%d", e.expType.size);
7370                      newExp = MkExpBrackets(MkListOne(MkExpOp(MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)),
7371                         MkDeclaratorPointer(MkPointer(null, null), null)), newExp), '+',
7372                            MkExpCall(MkExpIdentifier(MkIdentifier("__ENDIAN_PAD")), MkListOne(MkExpConstant(size))))));
7373                   }
7374
7375                   ReplaceExpContents(checkedExp, newExp);
7376                   e.byReference = true;
7377                }
7378                else if(!e.byReference || (_class && _class.type == noHeadClass))     // TESTING THIS HERE...
7379                {
7380                   Expression checkedExp; //, newExp;
7381
7382                   {
7383                      // TODO: Move code from debugTools.ec for hasAddress flag, this is just temporary
7384                      bool hasAddress =
7385                         e.type == identifierExp ||
7386                         (e.type == ExpressionType::memberExp && e.member.memberType == dataMember) ||
7387                         (e.type == ExpressionType::pointerExp && e.member.memberType == dataMember) ||
7388                         (e.type == opExp && !e.op.exp1 && e.op.op == '*') ||
7389                         e.type == indexExp;
7390
7391                      if(_class && _class.type != noHeadClass && _class.type != normalClass && _class.type != structClass && !hasAddress)
7392                      {
7393                         Context context = PushContext();
7394                         Declarator decl;
7395                         OldList * specs = MkList();
7396                         char typeString[1024];
7397                         Expression newExp { };
7398
7399                         typeString[0] = '\0';
7400                         *newExp = *e;
7401
7402                         //if(e.destType) e.destType.refCount++;
7403                         // if(exp.expType) exp.expType.refCount++;
7404                         newExp.prev = null;
7405                         newExp.next = null;
7406                         newExp.expType = null;
7407
7408                         PrintTypeNoConst(e.expType, typeString, false, true);
7409                         decl = SpecDeclFromString(typeString, specs, null);
7410                         newExp.destType = ProcessType(specs, decl);
7411
7412                         curContext = context;
7413
7414                         // We need a current compound for this
7415                         if(curCompound)
7416                         {
7417                            char name[100];
7418                            OldList * stmts = MkList();
7419                            e.type = extensionCompoundExp;
7420                            sprintf(name, "__internalValue%03X", internalValueCounter++);
7421                            if(!curCompound.compound.declarations)
7422                               curCompound.compound.declarations = MkList();
7423                            curCompound.compound.declarations->Insert(null, MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(name)), null))));
7424                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(name)), '=', newExp))));
7425                            ListAdd(stmts, MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier(name)))));
7426                            e.compound = MkCompoundStmt(null, stmts);
7427                         }
7428                         else
7429                            printf("libec: compiler error, curCompound is null in ApplyAnyObjectLogic\n");
7430
7431                         /*
7432                         e.compound = MkCompoundStmt(
7433                            MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(
7434                               MkDeclaratorIdentifier(MkIdentifier("__internalValue")), MkInitializerAssignment(newExp))))),
7435
7436                            MkListOne(MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier("__internalValue"))))));
7437                         */
7438
7439                         {
7440                            Type type = e.destType;
7441                            e.destType = { };
7442                            CopyTypeInto(e.destType, type);
7443                            e.destType.refCount = 1;
7444                            e.destType.classObjectType = none;
7445                            FreeType(type);
7446                         }
7447
7448                         e.compound.compound.context = context;
7449                         PopContext(context);
7450                         curContext = context.parent;
7451                      }
7452                   }
7453
7454                   // TODO: INTEGRATE THIS WITH VERSION ABOVE WHICH WAS ADDED TO ENCOMPASS OTHER CASE (*pointer)
7455                   checkedExp = e;
7456                   while(((checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp) && checkedExp.list) || checkedExp.type == castExp)
7457                   {
7458                      if(checkedExp.type == bracketsExp || checkedExp.type == extensionExpressionExp || checkedExp.type == extensionCompoundExp)
7459                      {
7460                         if(checkedExp.type == extensionCompoundExp)
7461                         {
7462                            checkedExp = ((Statement)checkedExp.compound.compound.statements->last).expressions->last;
7463                         }
7464                         else
7465                            checkedExp = checkedExp.list->last;
7466                      }
7467                      else if(checkedExp.type == castExp)
7468                         checkedExp = checkedExp.cast.exp;
7469                   }
7470                   {
7471                      Expression operand { };
7472                      operand = *checkedExp;
7473                      checkedExp.destType = null;
7474                      checkedExp.expType = null;
7475                      checkedExp.Clear();
7476                      checkedExp.type = opExp;
7477                      checkedExp.op.op = '&';
7478                      checkedExp.op.exp1 = null;
7479                      checkedExp.op.exp2 = operand;
7480
7481                      //newExp = MkExpOp(null, '&', checkedExp);
7482                   }
7483                   //ReplaceExpContents(checkedExp, newExp);
7484                }
7485             }
7486          }
7487       }
7488    }
7489    {
7490       // If expression type is a simple class, make it an address
7491       // FixReference(e, true);
7492    }
7493 //#if 0
7494    if((!destType || destType.kind == ellipsisType || destType.kind == voidType) && e.expType && (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7495       (e.expType.byReference || (e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7496          (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass ) )))
7497    {
7498       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"))
7499       {
7500          return;  // LEAVE THIS CASE (typed_object & :: methods 's this) TO PASS 2 FOR NOW
7501       }
7502       else
7503       {
7504          Expression thisExp { };
7505
7506          *thisExp = *e;
7507          thisExp.prev = null;
7508          thisExp.next = null;
7509          e.Clear();
7510
7511          e.type = bracketsExp;
7512          e.list = MkListOne(MkExpOp(null, '*', thisExp.type == identifierExp ? thisExp : MkExpBrackets(MkListOne(thisExp))));
7513          if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && thisExp.expType._class.registered.type == noHeadClass)
7514             ((Expression)e.list->first).byReference = true;
7515
7516          /*if(thisExp.expType.kind == classType && thisExp.expType._class && thisExp.expType._class.registered && !strcmp(thisExp.expType._class.registered.name, "class"))
7517          {
7518             e.expType = thisExp.expType;
7519             e.expType.refCount++;
7520          }
7521          else*/
7522          {
7523             e.expType = { };
7524             CopyTypeInto(e.expType, thisExp.expType);
7525             e.expType.byReference = false;
7526             e.expType.refCount = 1;
7527
7528             if(e.expType.kind == classType && e.expType._class && e.expType._class.registered &&
7529                (e.expType._class.registered.type == bitClass || e.expType._class.registered.type == enumClass || e.expType._class.registered.type == unitClass))
7530             {
7531                e.expType.classObjectType = none;
7532             }
7533          }
7534       }
7535    }
7536 // TOFIX: Try this for a nice IDE crash!
7537 //#endif
7538    // The other way around
7539    else
7540 //#endif
7541    if(destType && e.expType &&
7542          //e.expType.kind == classType && e.expType._class && e.expType._class.registered && !strcmp(e.expType._class.registered.name, "class") &&
7543          (e.expType.classObjectType == anyObject || e.expType.classObjectType == typedObject) &&
7544          !destType.classObjectType && /*(destType.kind != pointerType || !destType.type || destType.type.kind != voidType) &&*/ destType.kind != voidType)
7545    {
7546       if(destType.kind == ellipsisType)
7547       {
7548          Compiler_Error($"Unspecified type\n");
7549       }
7550       else if(!(destType.truth && e.expType.kind == classType && e.expType._class && e.expType._class.registered && e.expType._class.registered.type == structClass))
7551       {
7552          bool byReference = e.expType.byReference;
7553          Expression thisExp { };
7554          Declarator decl;
7555          OldList * specs = MkList();
7556          char typeString[1024]; // Watch buffer overruns
7557          Type type;
7558          ClassObjectType backupClassObjectType;
7559          bool backupByReference;
7560
7561          if(e.expType.kind == classType && e.expType._class && e.expType._class.registered && strcmp(e.expType._class.registered.name, "class"))
7562             type = e.expType;
7563          else
7564             type = destType;
7565
7566          backupClassObjectType = type.classObjectType;
7567          backupByReference = type.byReference;
7568
7569          type.classObjectType = none;
7570          type.byReference = false;
7571
7572          typeString[0] = '\0';
7573          PrintType(type, typeString, false, true);
7574          decl = SpecDeclFromString(typeString, specs, null);
7575
7576          type.classObjectType = backupClassObjectType;
7577          type.byReference = backupByReference;
7578
7579          *thisExp = *e;
7580          thisExp.prev = null;
7581          thisExp.next = null;
7582          e.Clear();
7583
7584          if( ( type.kind == classType && type._class && type._class.registered &&
7585                    (type._class.registered.type == systemClass || type._class.registered.type == bitClass ||
7586                     type._class.registered.type == enumClass || type._class.registered.type == unitClass) ) ||
7587              (type.kind != pointerType && type.kind != intPtrType && type.kind != arrayType && type.kind != classType) ||
7588              (!destType.byReference && byReference && (destType.kind != pointerType || type.kind != pointerType)))
7589          {
7590             e.type = opExp;
7591             e.op.op = '*';
7592             e.op.exp1 = null;
7593             e.op.exp2 = MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), thisExp);
7594
7595             e.expType = { };
7596             CopyTypeInto(e.expType, type);
7597             e.expType.byReference = false;
7598             e.expType.refCount = 1;
7599          }
7600          else
7601          {
7602             e.type = castExp;
7603             e.cast.typeName = MkTypeName(specs, decl);
7604             e.cast.exp = thisExp;
7605             e.byReference = true;
7606             e.expType = type;
7607             type.refCount++;
7608          }
7609          e.destType = destType;
7610          destType.refCount++;
7611       }
7612    }
7613 }
7614
7615 void ApplyLocation(Expression exp, Location loc)
7616 {
7617    exp.loc = loc;
7618    switch(exp.type)
7619    {
7620       case opExp:
7621          if(exp.op.exp1) ApplyLocation(exp.op.exp1, loc);
7622          if(exp.op.exp2) ApplyLocation(exp.op.exp2, loc);
7623          break;
7624       case bracketsExp:
7625          if(exp.list)
7626          {
7627             Expression e;
7628             for(e = exp.list->first; e; e = e.next)
7629                ApplyLocation(e, loc);
7630          }
7631          break;
7632       case indexExp:
7633          if(exp.index.index)
7634          {
7635             Expression e;
7636             for(e = exp.index.index->first; e; e = e.next)
7637                ApplyLocation(e, loc);
7638          }
7639          if(exp.index.exp)
7640             ApplyLocation(exp.index.exp, loc);
7641          break;
7642       case callExp:
7643          if(exp.call.arguments)
7644          {
7645             Expression arg;
7646             for(arg = exp.call.arguments->first; arg; arg = arg.next)
7647                ApplyLocation(arg, loc);
7648          }
7649          if(exp.call.exp)
7650             ApplyLocation(exp.call.exp, loc);
7651          break;
7652       case memberExp:
7653       case pointerExp:
7654          if(exp.member.exp)
7655             ApplyLocation(exp.member.exp, loc);
7656          break;
7657       case castExp:
7658          if(exp.cast.exp)
7659             ApplyLocation(exp.cast.exp, loc);
7660          break;
7661       case conditionExp:
7662          if(exp.cond.exp)
7663          {
7664             Expression e;
7665             for(e = exp.cond.exp->first; e; e = e.next)
7666                ApplyLocation(e, loc);
7667          }
7668          if(exp.cond.cond)
7669             ApplyLocation(exp.cond.cond, loc);
7670          if(exp.cond.elseExp)
7671             ApplyLocation(exp.cond.elseExp, loc);
7672          break;
7673       case vaArgExp:
7674          if(exp.vaArg.exp)
7675             ApplyLocation(exp.vaArg.exp, loc);
7676          break;
7677       default:
7678          break;
7679    }
7680 }
7681
7682 void ProcessExpressionType(Expression exp)
7683 {
7684    bool unresolved = false;
7685    Location oldyylloc = yylloc;
7686    bool notByReference = false;
7687 #ifdef _DEBUG
7688    char debugExpString[4096];
7689    debugExpString[0] = '\0';
7690    PrintExpression(exp, debugExpString);
7691 #endif
7692    if(!exp || exp.expType)
7693       return;
7694
7695    //eSystem_Logf("%s\n", expString);
7696
7697    // Testing this here
7698    yylloc = exp.loc;
7699    switch(exp.type)
7700    {
7701       case identifierExp:
7702       {
7703          Identifier id = exp.identifier;
7704          if(!id || !topContext) return;
7705
7706          // DOING THIS LATER NOW...
7707          if(id._class && id._class.name)
7708          {
7709             id.classSym = id._class.symbol; // FindClass(id._class.name);
7710             /* TODO: Name Space Fix ups
7711             if(!id.classSym)
7712                id.nameSpace = eSystem_FindNameSpace(privateModule, id._class.name);
7713             */
7714          }
7715
7716          /* WHY WAS THIS COMMENTED OUT? if(!strcmp(id.string, "__thisModule"))
7717          {
7718             exp.expType = ProcessTypeString("Module", true);
7719             break;
7720          }
7721          else */if(strstr(id.string, "__ecereClass") == id.string)
7722          {
7723             exp.expType = ProcessTypeString("ecere::com::Class", true);
7724             break;
7725          }
7726          else if(id._class && (id.classSym || (id._class.name && !strcmp(id._class.name, "property"))))
7727          {
7728             // Added this here as well
7729             ReplaceClassMembers(exp, thisClass);
7730             if(exp.type != identifierExp)
7731             {
7732                ProcessExpressionType(exp);
7733                break;
7734             }
7735
7736             if(id.classSym && ResolveIdWithClass(exp, id.classSym.registered, false))
7737                break;
7738          }
7739          else
7740          {
7741             Symbol symbol = FindSymbol(id.string, curContext, topContext /*exp.destType ? topContext : globalContext*/, false, id._class && id._class.name == null);
7742             // Enums should be resolved here (Special pass in opExp to fix identifiers not seen as enum on the first pass)
7743             if(!symbol/* && exp.destType*/)
7744             {
7745                if(exp.destType && CheckExpressionType(exp, exp.destType, false, false))
7746                   break;
7747                else
7748                {
7749                   if(thisClass)
7750                   {
7751                      ReplaceClassMembers(exp, thisClass ? thisClass : currentClass);
7752                      if(exp.type != identifierExp)
7753                      {
7754                         ProcessExpressionType(exp);
7755                         break;
7756                      }
7757                   }
7758                   // Static methods called from inside the _class
7759                   else if(currentClass && !id._class)
7760                   {
7761                      if(ResolveIdWithClass(exp, currentClass, true))
7762                         break;
7763                   }
7764                   symbol = FindSymbol(id.string, topContext.parent, globalContext, false, id._class && id._class.name == null);
7765                }
7766             }
7767
7768             // If we manage to resolve this symbol
7769             if(symbol)
7770             {
7771                Type type = symbol.type;
7772                Class _class = (type && type.kind == classType && type._class) ? type._class.registered : null;
7773
7774                if(_class && !strcmp(id.string, "this") && !type.classObjectType)
7775                {
7776                   Context context = SetupTemplatesContext(_class);
7777                   type = ReplaceThisClassType(_class);
7778                   FinishTemplatesContext(context);
7779                   if(type) type.refCount = 0;   // We'll be incrementing it right below...
7780                }
7781
7782                FreeSpecifier(id._class);
7783                id._class = null;
7784                delete id.string;
7785                id.string = CopyString(symbol.string);
7786
7787                id.classSym = null;
7788                exp.expType = type;
7789                if(type)
7790                   type.refCount++;
7791
7792                                                 // Commented this out, it was making non-constant enum parameters seen as constant
7793                                                 // enums should have been resolved by ResolveIdWithClass, changed to constantExp and marked as constant
7794                if(type && (type.kind == enumType /*|| (_class && _class.type == enumClass)*/))
7795                   // Add missing cases here... enum Classes...
7796                   exp.isConstant = true;
7797
7798                // TOCHECK: Why was !strcmp(id.string, "this") commented out?
7799                if(symbol.isParam || !strcmp(id.string, "this"))
7800                {
7801                   if(_class && _class.type == structClass && !type.declaredWithStruct)
7802                      exp.byReference = true;
7803
7804                   //TESTING COMMENTING THIS OUT IN FAVOR OF ApplyAnyObjectLogic
7805                   /*if(type && _class && (type.classObjectType == typedObject || type.classObjectType == anyObject) &&
7806                      ((_class.type == unitClass || _class.type == enumClass || _class.type == bitClass) ||
7807                      (type.byReference && (_class.type == normalClass || _class.type == noHeadClass))))
7808                   {
7809                      Identifier id = exp.identifier;
7810                      exp.type = bracketsExp;
7811                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(id)));
7812                   }*/
7813                }
7814
7815                if(symbol.isIterator)
7816                {
7817                   if(symbol.isIterator == 3)
7818                   {
7819                      exp.type = bracketsExp;
7820                      exp.list = MkListOne(MkExpOp(null, '*', MkExpIdentifier(exp.identifier)));
7821                      ((Expression)exp.list->first).op.exp2.expType = exp.expType;
7822                      exp.expType = null;
7823                      ProcessExpressionType(exp);
7824                   }
7825                   else if(symbol.isIterator != 4)
7826                   {
7827                      exp.type = memberExp;
7828                      exp.member.exp = MkExpIdentifier(exp.identifier);
7829                      exp.member.exp.expType = exp.expType;
7830                      /*if(symbol.isIterator == 6)
7831                         exp.member.member = MkIdentifier("key");
7832                      else*/
7833                         exp.member.member = MkIdentifier("data");
7834                      exp.expType = null;
7835                      ProcessExpressionType(exp);
7836                   }
7837                }
7838                break;
7839             }
7840             else
7841             {
7842                DefinedExpression definedExp = null;
7843                if(thisNameSpace && !(id._class && !id._class.name))
7844                {
7845                   char name[1024];
7846                   strcpy(name, thisNameSpace);
7847                   strcat(name, "::");
7848                   strcat(name, id.string);
7849                   definedExp = eSystem_FindDefine(privateModule, name);
7850                }
7851                if(!definedExp)
7852                   definedExp = eSystem_FindDefine(privateModule, id.string);
7853                if(definedExp)
7854                {
7855                   int c;
7856                   for(c = 0; c<definedExpStackPos; c++)
7857                      if(definedExpStack[c] == definedExp)
7858                         break;
7859                   if(c == definedExpStackPos && c < sizeof(definedExpStack) / sizeof(void *))
7860                   {
7861                      Location backupYylloc = yylloc;
7862                      File backInput = fileInput;
7863                      definedExpStack[definedExpStackPos++] = definedExp;
7864
7865                      fileInput = TempFile { };
7866                      fileInput.Write(definedExp.value, 1, strlen(definedExp.value));
7867                      fileInput.Seek(0, start);
7868
7869                      echoOn = false;
7870                      parsedExpression = null;
7871                      resetScanner();
7872                      expression_yyparse();
7873                      delete fileInput;
7874                      if(backInput)
7875                         fileInput = backInput;
7876
7877                      yylloc = backupYylloc;
7878
7879                      if(parsedExpression)
7880                      {
7881                         FreeIdentifier(id);
7882                         exp.type = bracketsExp;
7883                         exp.list = MkListOne(parsedExpression);
7884                         ApplyLocation(parsedExpression, yylloc);
7885                         ProcessExpressionType(exp);
7886                         definedExpStackPos--;
7887                         return;
7888                      }
7889                      definedExpStackPos--;
7890                   }
7891                   else
7892                   {
7893                      if(inCompiler)
7894                      {
7895                         Compiler_Error($"Recursion in defined expression %s\n", id.string);
7896                      }
7897                   }
7898                }
7899                else
7900                {
7901                   GlobalData data = null;
7902                   if(thisNameSpace && !(id._class && !id._class.name))
7903                   {
7904                      char name[1024];
7905                      strcpy(name, thisNameSpace);
7906                      strcat(name, "::");
7907                      strcat(name, id.string);
7908                      data = FindGlobalData(name);
7909                   }
7910                   if(!data)
7911                      data = FindGlobalData(id.string);
7912                   if(data)
7913                   {
7914                      DeclareGlobalData(data);
7915                      exp.expType = data.dataType;
7916                      if(data.dataType) data.dataType.refCount++;
7917
7918                      delete id.string;
7919                      id.string = CopyString(data.fullName);
7920                      FreeSpecifier(id._class);
7921                      id._class = null;
7922
7923                      break;
7924                   }
7925                   else
7926                   {
7927                      GlobalFunction function = null;
7928                      if(thisNameSpace && !(id._class && !id._class.name))
7929                      {
7930                         char name[1024];
7931                         strcpy(name, thisNameSpace);
7932                         strcat(name, "::");
7933                         strcat(name, id.string);
7934                         function = eSystem_FindFunction(privateModule, name);
7935                      }
7936                      if(!function)
7937                         function = eSystem_FindFunction(privateModule, id.string);
7938                      if(function)
7939                      {
7940                         char name[1024];
7941                         delete id.string;
7942                         id.string = CopyString(function.name);
7943                         name[0] = 0;
7944
7945                         if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
7946                            strcpy(name, "__ecereFunction_");
7947                         FullClassNameCat(name, id.string, false); // Why is this using FullClassNameCat ?
7948                         if(DeclareFunction(function, name))
7949                         {
7950                            delete id.string;
7951                            id.string = CopyString(name);
7952                         }
7953                         exp.expType = function.dataType;
7954                         if(function.dataType) function.dataType.refCount++;
7955
7956                         FreeSpecifier(id._class);
7957                         id._class = null;
7958
7959                         break;
7960                      }
7961                   }
7962                }
7963             }
7964          }
7965          unresolved = true;
7966          break;
7967       }
7968       case instanceExp:
7969       {
7970          Class _class;
7971          // Symbol classSym;
7972
7973          if(!exp.instance._class)
7974          {
7975             if(exp.destType && exp.destType.kind == classType && exp.destType._class)
7976             {
7977                exp.instance._class = MkSpecifierName(exp.destType._class.string);
7978             }
7979          }
7980
7981          //classSym = FindClass(exp.instance._class.fullName);
7982          //_class = classSym ? classSym.registered : null;
7983
7984          ProcessInstantiationType(exp.instance);
7985
7986          exp.isConstant = exp.instance.isConstant;
7987
7988          /*
7989          if(_class.type == unitClass && _class.base.type != systemClass)
7990          {
7991             {
7992                Type destType = exp.destType;
7993
7994                exp.destType = MkClassType(_class.base.fullName);
7995                exp.expType = MkClassType(_class.fullName);
7996                CheckExpressionType(exp, exp.destType, true);
7997
7998                exp.destType = destType;
7999             }
8000             exp.expType = MkClassType(_class.fullName);
8001          }
8002          else*/
8003          if(exp.instance._class)
8004          {
8005             exp.expType = MkClassType(exp.instance._class.name);
8006             /*if(exp.expType._class && exp.expType._class.registered &&
8007                (exp.expType._class.registered.type == normalClass || exp.expType._class.registered.type == noHeadClass))
8008                exp.expType.byReference = true;*/
8009          }
8010          break;
8011       }
8012       case constantExp:
8013       {
8014          if(!exp.expType)
8015          {
8016             char * constant = exp.constant;
8017             Type type
8018             {
8019                refCount = 1;
8020                constant = true;
8021             };
8022             exp.expType = type;
8023
8024             if(constant[0] == '\'')
8025             {
8026                if((int)((byte *)constant)[1] > 127)
8027                {
8028                   int nb;
8029                   unichar ch = UTF8GetChar(constant + 1, &nb);
8030                   if(nb < 2) ch = constant[1];
8031                   delete constant;
8032                   exp.constant = PrintUInt(ch);
8033                   // type.kind = (ch > 0xFFFF) ? intType : shortType;
8034                   type.kind = classType; //(ch > 0xFFFF) ? intType : shortType;
8035                   type._class = FindClass("unichar");
8036
8037                   type.isSigned = false;
8038                }
8039                else
8040                {
8041                   type.kind = charType;
8042                   type.isSigned = true;
8043                }
8044             }
8045             else
8046             {
8047                char * dot = strchr(constant, '.');
8048                bool isHex = (constant[0] == '0' && (constant[1] == 'x' || constant[1] == 'X'));
8049                char * exponent;
8050                if(isHex)
8051                {
8052                   exponent = strchr(constant, 'p');
8053                   if(!exponent) exponent = strchr(constant, 'P');
8054                }
8055                else
8056                {
8057                   exponent = strchr(constant, 'e');
8058                   if(!exponent) exponent = strchr(constant, 'E');
8059                }
8060
8061                if(dot || exponent)
8062                {
8063                   if(strchr(constant, 'f') || strchr(constant, 'F'))
8064                      type.kind = floatType;
8065                   else
8066                      type.kind = doubleType;
8067                   type.isSigned = true;
8068                }
8069                else
8070                {
8071                   bool isSigned = constant[0] == '-';
8072                   char * endP = null;
8073                   int64 i64 = strtoll(constant, &endP, 0);
8074                   uint64 ui64 = strtoull(constant, &endP, 0);
8075                   bool is64Bit = endP && (!strcmp(endP, "LL") || !strcmp(endP, "ll"));
8076                   if(isSigned)
8077                   {
8078                      if(i64 < MININT)
8079                         is64Bit = true;
8080                   }
8081                   else
8082                   {
8083                      if(ui64 > MAXINT)
8084                      {
8085                         if(ui64 > MAXDWORD)
8086                         {
8087                            is64Bit = true;
8088                            if(ui64 <= MAXINT64 && (constant[0] != '0' || !constant[1]))
8089                               isSigned = true;
8090                         }
8091                      }
8092                      else if(constant[0] != '0' || !constant[1])
8093                         isSigned = true;
8094                   }
8095                   type.kind = is64Bit ? int64Type : intType;
8096                   type.isSigned = isSigned;
8097                }
8098             }
8099             exp.isConstant = true;
8100             if(exp.destType && exp.destType.kind == doubleType)
8101                type.kind = doubleType;
8102             else if(exp.destType && exp.destType.kind == floatType)
8103                type.kind = floatType;
8104             else if(exp.destType && exp.destType.kind == int64Type)
8105                type.kind = int64Type;
8106          }
8107          break;
8108       }
8109       case stringExp:
8110       {
8111          exp.isConstant = true;      // Why wasn't this constant?
8112          exp.expType = Type
8113          {
8114             refCount = 1;
8115             kind = pointerType;
8116             type = Type
8117             {
8118                refCount = 1;
8119                kind = charType;
8120                constant = true;
8121                isSigned = true;
8122             }
8123          };
8124          break;
8125       }
8126       case newExp:
8127       case new0Exp:
8128          ProcessExpressionType(exp._new.size);
8129          exp.expType = Type
8130          {
8131             refCount = 1;
8132             kind = pointerType;
8133             type = ProcessType(exp._new.typeName.qualifiers, exp._new.typeName.declarator);
8134          };
8135          DeclareType(exp.expType.type, false, false);
8136          break;
8137       case renewExp:
8138       case renew0Exp:
8139          ProcessExpressionType(exp._renew.size);
8140          ProcessExpressionType(exp._renew.exp);
8141          exp.expType = Type
8142          {
8143             refCount = 1;
8144             kind = pointerType;
8145             type = ProcessType(exp._renew.typeName.qualifiers, exp._renew.typeName.declarator);
8146          };
8147          DeclareType(exp.expType.type, false, false);
8148          break;
8149       case opExp:
8150       {
8151          bool assign = false, boolResult = false, boolOps = false;
8152          Type type1 = null, type2 = null;
8153          bool useDestType = false, useSideType = false;
8154          Location oldyylloc = yylloc;
8155          bool useSideUnit = false;
8156          Class destClass = (exp.destType && exp.destType.kind == classType && exp.destType._class) ? exp.destType._class.registered : null;
8157
8158          // Dummy type to prevent ProcessExpression of operands to say unresolved identifiers yet
8159          Type dummy
8160          {
8161             count = 1;
8162             refCount = 1;
8163          };
8164
8165          switch(exp.op.op)
8166          {
8167             // Assignment Operators
8168             case '=':
8169             case MUL_ASSIGN:
8170             case DIV_ASSIGN:
8171             case MOD_ASSIGN:
8172             case ADD_ASSIGN:
8173             case SUB_ASSIGN:
8174             case LEFT_ASSIGN:
8175             case RIGHT_ASSIGN:
8176             case AND_ASSIGN:
8177             case XOR_ASSIGN:
8178             case OR_ASSIGN:
8179                assign = true;
8180                break;
8181             // boolean Operators
8182             case '!':
8183                // Expect boolean operators
8184                //boolOps = true;
8185                //boolResult = true;
8186                break;
8187             case AND_OP:
8188             case OR_OP:
8189                // Expect boolean operands
8190                boolOps = true;
8191                boolResult = true;
8192                break;
8193             // Comparisons
8194             case EQ_OP:
8195             case '<':
8196             case '>':
8197             case LE_OP:
8198             case GE_OP:
8199             case NE_OP:
8200                // Gives boolean result
8201                boolResult = true;
8202                useSideType = true;
8203                break;
8204             case '+':
8205             case '-':
8206                useSideUnit = true;
8207                useSideType = true;
8208                useDestType = true;
8209                break;
8210
8211             case LEFT_OP:
8212             case RIGHT_OP:
8213                useSideType = true;
8214                useDestType = true;
8215                break;
8216
8217             case '|':
8218             case '^':
8219                useSideType = true;
8220                useDestType = true;
8221                break;
8222
8223             case '/':
8224             case '%':
8225                useSideType = true;
8226                useDestType = true;
8227                break;
8228             case '&':
8229             case '*':
8230                if(exp.op.exp1)
8231                {
8232                   // For & operator, useDestType nicely ensures the result will fit in a bool (TODO: Fix for generic enum)
8233                   useSideType = true;
8234                   useDestType = true;
8235                }
8236                break;
8237
8238             /*// Implement speed etc.
8239             case '*':
8240             case '/':
8241                break;
8242             */
8243          }
8244          if(exp.op.op == '&')
8245          {
8246             // Added this here earlier for Iterator address as key
8247             if(!exp.op.exp1 && exp.op.exp2 && exp.op.exp2.type == identifierExp && exp.op.exp2.identifier)
8248             {
8249                Identifier id = exp.op.exp2.identifier;
8250                Symbol symbol = FindSymbol(id.string, curContext, topContext, false, id._class && id._class.name == null);
8251                if(symbol && symbol.isIterator == 2)
8252                {
8253                   exp.type = memberExp;
8254                   exp.member.exp = exp.op.exp2;
8255                   exp.member.member = MkIdentifier("key");
8256                   exp.expType = null;
8257                   exp.op.exp2.expType = symbol.type;
8258                   symbol.type.refCount++;
8259                   ProcessExpressionType(exp);
8260                   FreeType(dummy);
8261                   break;
8262                }
8263                // exp.op.exp2.usage.usageRef = true;
8264             }
8265          }
8266
8267          //dummy.kind = TypeDummy;
8268          if(exp.op.exp1)
8269          {
8270             // Added this check here to use the dest type only for units derived from the base unit
8271             // So that untyped units will use the side unit as opposed to the untyped destination unit
8272             // This fixes (#771) sin(Degrees { 5 } + 5) to be equivalent to sin(Degrees { 10 }), since sin expects a generic Angle
8273             if(exp.op.exp2 && useSideUnit && useDestType && destClass && destClass.type == unitClass && destClass.base.type != unitClass)
8274                useDestType = false;
8275
8276             if(destClass && useDestType &&
8277               ((destClass.type == unitClass && useSideUnit) || destClass.type == enumClass || destClass.type == bitClass))
8278
8279               //(exp.destType._class.registered.type == unitClass || exp.destType._class.registered.type == enumClass) && useDestType)
8280             {
8281                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8282                exp.op.exp1.destType = exp.destType;
8283                exp.op.exp1.opDestType = true;
8284                if(exp.destType)
8285                   exp.destType.refCount++;
8286             }
8287             else if(!assign)
8288             {
8289                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8290                exp.op.exp1.destType = dummy;
8291                dummy.refCount++;
8292             }
8293
8294             // TESTING THIS HERE...
8295             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count++;
8296                ProcessExpressionType(exp.op.exp1);
8297             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count--;
8298
8299             exp.op.exp1.opDestType = false;
8300
8301             // Fix for unit and ++ / --
8302             if(!exp.op.exp2 && (exp.op.op == INC_OP || exp.op.op == DEC_OP) && exp.op.exp1.expType && exp.op.exp1.expType.kind == classType &&
8303                exp.op.exp1.expType._class && exp.op.exp1.expType._class.registered && exp.op.exp1.expType._class.registered.type == unitClass)
8304             {
8305                exp.op.exp2 = MkExpConstant("1");
8306                exp.op.op = exp.op.op == INC_OP ? ADD_ASSIGN : SUB_ASSIGN;
8307                assign = true;
8308             }
8309
8310             if(exp.op.exp1.destType == dummy)
8311             {
8312                FreeType(dummy);
8313                exp.op.exp1.destType = null;
8314             }
8315             type1 = exp.op.exp1.expType;
8316          }
8317
8318          if(exp.op.exp2)
8319          {
8320             char expString[10240];
8321             expString[0] = '\0';
8322             if(exp.op.exp2.type == instanceExp && !exp.op.exp2.instance._class)
8323             {
8324                if(exp.op.exp1)
8325                {
8326                   exp.op.exp2.destType = exp.op.exp1.expType;
8327                   if(exp.op.exp1.expType)
8328                      exp.op.exp1.expType.refCount++;
8329                }
8330                else
8331                {
8332                   exp.op.exp2.destType = exp.destType;
8333                   if(!exp.op.exp1 || exp.op.op != '&')
8334                      exp.op.exp2.opDestType = true;
8335                   if(exp.destType)
8336                      exp.destType.refCount++;
8337                }
8338
8339                if(type1) type1.refCount++;
8340                exp.expType = type1;
8341             }
8342             else if(assign)
8343             {
8344                if(inCompiler)
8345                   PrintExpression(exp.op.exp2, expString);
8346
8347                if(type1 && type1.kind == pointerType)
8348                {
8349                   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 ||
8350                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN)
8351                      Compiler_Error($"operator %s illegal on pointer\n", exp.op.op);
8352                   else if(exp.op.op == '=')
8353                   {
8354                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8355                      exp.op.exp2.destType = type1;
8356                      if(type1)
8357                         type1.refCount++;
8358                   }
8359                }
8360                else
8361                {
8362                   // Don't convert to the type for those... (e.g.: Degrees a; a /= 2;)
8363                   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/* ||
8364                      exp.op.op == AND_ASSIGN || exp.op.op == OR_ASSIGN*/);
8365                   else
8366                   {
8367                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8368                      exp.op.exp2.destType = type1;
8369                      if(type1)
8370                         type1.refCount++;
8371                   }
8372                }
8373                if(type1) type1.refCount++;
8374                exp.expType = type1;
8375             }
8376             else if(destClass &&
8377                   ((destClass.type == unitClass && useDestType && useSideUnit) ||
8378                   (destClass.type == enumClass && useDestType)))
8379             {
8380                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8381                exp.op.exp2.destType = exp.destType;
8382                if(exp.op.op != '&')
8383                   exp.op.exp2.opDestType = true;
8384                if(exp.destType)
8385                   exp.destType.refCount++;
8386             }
8387             else
8388             {
8389                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8390                exp.op.exp2.destType = dummy;
8391                dummy.refCount++;
8392             }
8393
8394             // TESTING THIS HERE... (DANGEROUS)
8395             if(type1 && boolResult && useSideType && type1.kind == classType && type1._class && type1._class.registered &&
8396                (type1._class.registered.type == bitClass || type1._class.registered.type == enumClass))
8397             {
8398                FreeType(exp.op.exp2.destType);
8399                exp.op.exp2.destType = type1;
8400                type1.refCount++;
8401             }
8402             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count++;
8403             // Cannot lose the cast on a sizeof
8404             if(exp.op.op == SIZEOF)
8405             {
8406                Expression e = exp.op.exp2;
8407                while((e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp) && e.list)
8408                {
8409                   if(e.type == bracketsExp || e.type == extensionExpressionExp || e.type == extensionCompoundExp)
8410                   {
8411                      if(e.type == extensionCompoundExp)
8412                         e = ((Statement)e.compound.compound.statements->last).expressions->last;
8413                      else
8414                         e = e.list->last;
8415                   }
8416                }
8417                if(e.type == castExp && e.cast.exp)
8418                   e.cast.exp.needCast = true;
8419             }
8420             ProcessExpressionType(exp.op.exp2);
8421             exp.op.exp2.opDestType = false;
8422             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count--;
8423
8424             if(assign && type1 && type1.kind == pointerType && exp.op.exp2.expType)
8425             {
8426                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)
8427                {
8428                   if(exp.op.op != '=' && type1.type.kind == voidType)
8429                      Compiler_Error($"void *: unknown size\n");
8430                }
8431                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||
8432                            (type1.type.kind == voidType && exp.op.exp2.expType.kind == classType && exp.op.exp2.expType._class.registered &&
8433                               (exp.op.exp2.expType._class.registered.type == normalClass ||
8434                               exp.op.exp2.expType._class.registered.type == structClass ||
8435                               exp.op.exp2.expType._class.registered.type == noHeadClass)))
8436                {
8437                   if(exp.op.op == ADD_ASSIGN)
8438                      Compiler_Error($"cannot add two pointers\n");
8439                }
8440                else if((exp.op.exp2.expType.kind == classType && type1.kind == pointerType && type1.type.kind == classType &&
8441                   type1.type._class == exp.op.exp2.expType._class && exp.op.exp2.expType._class.registered && exp.op.exp2.expType._class.registered.type == structClass))
8442                {
8443                   if(exp.op.op == ADD_ASSIGN)
8444                      Compiler_Error($"cannot add two pointers\n");
8445                }
8446                else if(inCompiler)
8447                {
8448                   char type1String[1024];
8449                   char type2String[1024];
8450                   type1String[0] = '\0';
8451                   type2String[0] = '\0';
8452
8453                   PrintType(exp.op.exp2.expType, type1String, false, true);
8454                   PrintType(type1, type2String, false, true);
8455                   ChangeCh(expString, '\n', ' ');
8456                   Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1String, type2String);
8457                }
8458             }
8459
8460             if(exp.op.exp2.destType == dummy)
8461             {
8462                FreeType(dummy);
8463                exp.op.exp2.destType = null;
8464             }
8465
8466             if(exp.op.op == '-' && !exp.op.exp1 && exp.op.exp2.expType && !exp.op.exp2.expType.isSigned)
8467             {
8468                type2 = { };
8469                type2.refCount = 1;
8470                CopyTypeInto(type2, exp.op.exp2.expType);
8471                type2.isSigned = true;
8472             }
8473             else if(exp.op.op == '~' && !exp.op.exp1 && exp.op.exp2.expType && (!exp.op.exp2.expType.isSigned || exp.op.exp2.expType.kind != intType))
8474             {
8475                type2 = { kind = intType };
8476                type2.refCount = 1;
8477                type2.isSigned = true;
8478             }
8479             else
8480             {
8481                type2 = exp.op.exp2.expType;
8482                if(type2) type2.refCount++;
8483             }
8484          }
8485
8486          dummy.kind = voidType;
8487
8488          if(exp.op.op == SIZEOF)
8489          {
8490             exp.expType = Type
8491             {
8492                refCount = 1;
8493                kind = intSizeType;
8494             };
8495             exp.isConstant = true;
8496          }
8497          // Get type of dereferenced pointer
8498          else if(exp.op.op == '*' && !exp.op.exp1)
8499          {
8500             exp.expType = Dereference(type2);
8501             if(type2 && type2.kind == classType)
8502                notByReference = true;
8503          }
8504          else if(exp.op.op == '&' && !exp.op.exp1)
8505             exp.expType = Reference(type2);
8506          else if(!assign)
8507          {
8508             if(boolOps)
8509             {
8510                if(exp.op.exp1)
8511                {
8512                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8513                   exp.op.exp1.destType = MkClassType("bool");
8514                   exp.op.exp1.destType.truth = true;
8515                   if(!exp.op.exp1.expType)
8516                      ProcessExpressionType(exp.op.exp1);
8517                   else
8518                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8519                   FreeType(exp.op.exp1.expType);
8520                   exp.op.exp1.expType = MkClassType("bool");
8521                   exp.op.exp1.expType.truth = true;
8522                }
8523                if(exp.op.exp2)
8524                {
8525                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8526                   exp.op.exp2.destType = MkClassType("bool");
8527                   exp.op.exp2.destType.truth = true;
8528                   if(!exp.op.exp2.expType)
8529                      ProcessExpressionType(exp.op.exp2);
8530                   else
8531                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8532                   FreeType(exp.op.exp2.expType);
8533                   exp.op.exp2.expType = MkClassType("bool");
8534                   exp.op.exp2.expType.truth = true;
8535                }
8536             }
8537             else if(exp.op.exp1 && exp.op.exp2 &&
8538                ((useSideType /*&&
8539                      (useSideUnit ||
8540                         ((!type1 || type1.kind != classType || type1._class.registered.type != unitClass) &&
8541                          (!type2 || type2.kind != classType || type2._class.registered.type != unitClass)))*/) ||
8542                   ((!type1 || type1.kind != classType || !strcmp(type1._class.string, "String")) &&
8543                   (!type2 || type2.kind != classType || !strcmp(type2._class.string, "String")))))
8544             {
8545                if(type1 && type2 &&
8546                   // If either both are class or both are not class
8547                   ((type1.kind == classType && type1._class && strcmp(type1._class.string, "String")) == (type2.kind == classType && type2._class && strcmp(type2._class.string, "String"))))
8548                {
8549                   // Added this check for enum subtraction to result in an int type:
8550                   if(exp.op.op == '-' &&
8551                      ((type1.kind == classType && type1._class.registered && type1._class.registered.type == enumClass) ||
8552                       (type2.kind == classType && type2._class.registered && type2._class.registered.type == enumClass)) )
8553                   {
8554                      Type intType;
8555                      if(!type1._class.registered.dataType)
8556                         type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
8557                      if(!type2._class.registered.dataType)
8558                         type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
8559
8560                      intType = ProcessTypeString(
8561                         (type1._class.registered.dataType.kind == int64Type || type2._class.registered.dataType.kind == int64Type) ? "int64" : "int", false);
8562
8563                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8564                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8565                      exp.op.exp1.destType = intType;
8566                      exp.op.exp2.destType = intType;
8567                      intType.refCount++;
8568                   }
8569                   else
8570                   {
8571                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8572                      exp.op.exp2.destType = type1;
8573                      type1.refCount++;
8574                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8575                      exp.op.exp1.destType = type2;
8576                      type2.refCount++;
8577                   }
8578
8579                   // Warning here for adding Radians + Degrees with no destination type
8580                   if(!boolResult && type1.kind == classType && (!exp.destType || exp.destType.kind != classType) &&
8581                      type1._class.registered && type1._class.registered.type == unitClass &&
8582                      type2._class.registered && type2._class.registered.type == unitClass &&
8583                      type1._class.registered != type2._class.registered)
8584                      Compiler_Warning($"operating on %s and %s with an untyped result, assuming %s\n",
8585                         type1._class.string, type2._class.string, type1._class.string);
8586
8587                   if(type1.kind == pointerType && type1.type.kind == templateType && type2.kind != pointerType)
8588                   {
8589                      Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8590                      if(argExp)
8591                      {
8592                         Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8593
8594                         exp.op.exp1 = MkExpBrackets(MkListOne(MkExpCast(
8595                            MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)),
8596                            exp.op.exp1)));
8597
8598                         ProcessExpressionType(exp.op.exp1);
8599
8600                         if(type2.kind != pointerType)
8601                         {
8602                            ProcessExpressionType(classExp);
8603
8604                            exp.op.exp2 = MkExpBrackets(MkListOne(MkExpOp(exp.op.exp2, '*',
8605                               // ((_class.type == noHeadClass || _class.type == normalClass) ? sizeof(void *) : type.size)
8606                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(MkExpOp(
8607                                  // noHeadClass
8608                                  MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpConstant("5")),
8609                                     OR_OP,
8610                                  // normalClass
8611                                  MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpConstant("0"))))),
8612                                     MkListOne(MkExpTypeSize(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(
8613                                        MkPointer(null, null), null)))),
8614                                        MkExpMember(classExp, MkIdentifier("typeSize"))))))));
8615
8616                            if(!exp.op.exp2.expType)
8617                            {
8618                               if(type2)
8619                                  FreeType(type2);
8620                               type2 = exp.op.exp2.expType = ProcessTypeString("int", false);
8621                               type2.refCount++;
8622                            }
8623
8624                            ProcessExpressionType(exp.op.exp2);
8625                         }
8626                      }
8627                   }
8628
8629                   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)))
8630                   {
8631                      if(type1.kind != classType && type1.type.kind == voidType)
8632                         Compiler_Error($"void *: unknown size\n");
8633                      exp.expType = type1;
8634                      if(type1) type1.refCount++;
8635                   }
8636                   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)))
8637                   {
8638                      if(type2.kind != classType && type2.type.kind == voidType)
8639                         Compiler_Error($"void *: unknown size\n");
8640                      exp.expType = type2;
8641                      if(type2) type2.refCount++;
8642                   }
8643                   else if((type1.kind == pointerType && type2.kind != pointerType && type2.kind != arrayType && type2.kind != functionType && type2.kind != methodType && type2.kind != classType && type2.kind != subClassType) ||
8644                           (type2.kind == pointerType && type1.kind != pointerType && type1.kind != arrayType && type1.kind != functionType && type1.kind != methodType && type1.kind != classType && type1.kind != subClassType))
8645                   {
8646                      Compiler_Warning($"different levels of indirection\n");
8647                   }
8648                   else
8649                   {
8650                      bool success = false;
8651                      if(type1.kind == pointerType && type2.kind == pointerType)
8652                      {
8653                         if(exp.op.op == '+')
8654                            Compiler_Error($"cannot add two pointers\n");
8655                         else if(exp.op.op == '-')
8656                         {
8657                            // Pointer Subtraction gives integer
8658                            if(MatchTypes(type1.type, type2.type, null, null, null, false, false, false, false, false))
8659                            {
8660                               exp.expType = Type
8661                               {
8662                                  kind = intType;
8663                                  refCount = 1;
8664                               };
8665                               success = true;
8666
8667                               if(type1.type.kind == templateType)
8668                               {
8669                                  Expression argExp = GetTemplateArgExp(type1.type.templateParameter, thisClass, true);
8670                                  if(argExp)
8671                                  {
8672                                     Expression classExp = MkExpMember(argExp, MkIdentifier("dataTypeClass"));
8673
8674                                     ProcessExpressionType(classExp);
8675
8676                                     exp.type = bracketsExp;
8677                                     exp.list = MkListOne(MkExpOp(
8678                                        MkExpBrackets(MkListOne(MkExpOp(
8679                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp1)))
8680                                              , exp.op.op,
8681                                              MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), MkExpBrackets(MkListOne(exp.op.exp2)))))), '/',
8682
8683                                              //MkExpMember(classExp, MkIdentifier("typeSize"))
8684
8685                                              // ((_class.type == noHeadClass || _class.type == normalClass) ? sizeof(void *) : type.size)
8686                                              MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(MkExpOp(
8687                                                 // noHeadClass
8688                                                 MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpIdentifier(MkIdentifier("noHeadClass"))),
8689                                                    OR_OP,
8690                                                 // normalClass
8691                                                 MkExpOp(MkExpMember(CopyExpression(classExp), MkIdentifier("type")), EQ_OP, MkExpIdentifier(MkIdentifier("normalClass")))))),
8692                                                    MkListOne(MkExpTypeSize(MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(
8693                                                       MkPointer(null, null), null)))),
8694                                                       MkExpMember(classExp, MkIdentifier("typeSize")))))
8695
8696
8697                                              ));
8698
8699                                     ProcessExpressionType(((Expression)exp.list->first).op.exp2);
8700                                     FreeType(dummy);
8701                                     return;
8702                                  }
8703                               }
8704                            }
8705                         }
8706                      }
8707
8708                      if(!success && exp.op.exp1.type == constantExp)
8709                      {
8710                         // If first expression is constant, try to match that first
8711                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8712                         {
8713                            if(exp.expType) FreeType(exp.expType);
8714                            exp.expType = exp.op.exp1.destType;
8715                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8716                            success = true;
8717                         }
8718                         else if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
8719                         {
8720                            if(exp.expType) FreeType(exp.expType);
8721                            exp.expType = exp.op.exp2.destType;
8722                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8723                            success = true;
8724                         }
8725                      }
8726                      else if(!success)
8727                      {
8728                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
8729                         {
8730                            if(exp.expType) FreeType(exp.expType);
8731                            exp.expType = exp.op.exp2.destType;
8732                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8733                            success = true;
8734                         }
8735                         else if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8736                         {
8737                            if(exp.expType) FreeType(exp.expType);
8738                            exp.expType = exp.op.exp1.destType;
8739                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8740                            success = true;
8741                         }
8742                      }
8743                      if(!success)
8744                      {
8745                         char expString1[10240];
8746                         char expString2[10240];
8747                         char type1[1024];
8748                         char type2[1024];
8749                         expString1[0] = '\0';
8750                         expString2[0] = '\0';
8751                         type1[0] = '\0';
8752                         type2[0] = '\0';
8753                         if(inCompiler)
8754                         {
8755                            PrintExpression(exp.op.exp1, expString1);
8756                            ChangeCh(expString1, '\n', ' ');
8757                            PrintExpression(exp.op.exp2, expString2);
8758                            ChangeCh(expString2, '\n', ' ');
8759                            PrintType(exp.op.exp1.expType, type1, false, true);
8760                            PrintType(exp.op.exp2.expType, type2, false, true);
8761                         }
8762
8763                         Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1, expString2, type2);
8764                      }
8765                   }
8766                }
8767                // ADDED THESE TWO FROM OUTSIDE useSideType CHECK
8768                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type2 && type1 && type2.kind == classType && type1.kind != classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
8769                {
8770                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8771                   // Convert e.g. / 4 into / 4.0
8772                   exp.op.exp1.destType = type2._class.registered.dataType;
8773                   if(type2._class.registered.dataType)
8774                      type2._class.registered.dataType.refCount++;
8775                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8776                   exp.expType = type2;
8777                   if(type2) type2.refCount++;
8778                }
8779                else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type1 && type2 && type1.kind == classType && type2.kind != classType && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
8780                {
8781                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8782                   // Convert e.g. / 4 into / 4.0
8783                   exp.op.exp2.destType = type1._class.registered.dataType;
8784                   if(type1._class.registered.dataType)
8785                      type1._class.registered.dataType.refCount++;
8786                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8787                   exp.expType = type1;
8788                   if(type1) type1.refCount++;
8789                }
8790                else if(type1)
8791                {
8792                   bool valid = false;
8793
8794                   if(!boolResult && useSideUnit && type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8795                   {
8796                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8797
8798                      if(!type1._class.registered.dataType)
8799                         type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
8800                      exp.op.exp2.destType = type1._class.registered.dataType;
8801                      exp.op.exp2.destType.refCount++;
8802
8803                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
8804                      if(type2)
8805                         FreeType(type2);
8806                      type2 = exp.op.exp2.destType;
8807                      if(type2) type2.refCount++;
8808
8809                      exp.expType = type2;
8810                      type2.refCount++;
8811                   }
8812
8813                   if(!boolResult && useSideUnit && type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8814                   {
8815                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8816
8817                      if(!type2._class.registered.dataType)
8818                         type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
8819                      exp.op.exp1.destType = type2._class.registered.dataType;
8820                      exp.op.exp1.destType.refCount++;
8821
8822                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
8823                      type1 = exp.op.exp1.destType;
8824                      exp.expType = type1;
8825                      type1.refCount++;
8826                   }
8827
8828                   // TESTING THIS NEW CODE
8829                   if(!boolResult || exp.op.op == '>' || exp.op.op == '<' || exp.op.op == GE_OP || exp.op.op == LE_OP)
8830                   {
8831                      bool op1IsEnum = type1 && type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass;
8832                      bool op2IsEnum = type2 && type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass;
8833                      if(exp.op.op == '*' || exp.op.op == '/' || exp.op.op == '-' || exp.op.op == '|' || exp.op.op == '^')
8834                      {
8835                         // Convert the enum to an int instead for these operators
8836                         if(op1IsEnum && exp.op.exp2.expType)
8837                         {
8838                            if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false, false))
8839                            {
8840                               if(exp.expType) FreeType(exp.expType);
8841                               exp.expType = exp.op.exp2.expType;
8842                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8843                               valid = true;
8844                            }
8845                         }
8846                         else if(op2IsEnum && exp.op.exp1.expType)
8847                         {
8848                            if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false, false))
8849                            {
8850                               if(exp.expType) FreeType(exp.expType);
8851                               exp.expType = exp.op.exp1.expType;
8852                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8853                               valid = true;
8854                            }
8855                         }
8856                      }
8857                      else
8858                      {
8859                         if(op1IsEnum && exp.op.exp2.expType)
8860                         {
8861                            if(CheckExpressionType(exp.op.exp1, exp.op.exp2.expType, false, false))
8862                            {
8863                               if(exp.expType) FreeType(exp.expType);
8864                               exp.expType = exp.op.exp1.expType;
8865                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8866                               valid = true;
8867                            }
8868                         }
8869                         else if(op2IsEnum && exp.op.exp1.expType)
8870                         {
8871                            if(CheckExpressionType(exp.op.exp2, exp.op.exp1.expType, false, false))
8872                            {
8873                               if(exp.expType) FreeType(exp.expType);
8874                               exp.expType = exp.op.exp2.expType;
8875                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8876                               valid = true;
8877                            }
8878                         }
8879                      }
8880                   }
8881
8882                   if(!valid)
8883                   {
8884                      // 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
8885                      if(type2 && type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass &&
8886                         (type1.kind != classType || !type1._class || !type1._class.registered || type1._class.registered.type != unitClass))
8887                      {
8888                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8889                         exp.op.exp1.destType = type2;
8890                         type2.refCount++;
8891
8892                         if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8893                         {
8894                            if(exp.expType) FreeType(exp.expType);
8895                            exp.expType = exp.op.exp1.destType;
8896                            if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
8897                         }
8898                      }
8899                      else
8900                      {
8901                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8902                         exp.op.exp2.destType = type1;
8903                         type1.refCount++;
8904
8905                      /*
8906                      // Maybe this was meant to be an enum...
8907                      if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
8908                      {
8909                         Type oldType = exp.op.exp2.expType;
8910                         exp.op.exp2.expType = null;
8911                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false))
8912                            FreeType(oldType);
8913                         else
8914                            exp.op.exp2.expType = oldType;
8915                      }
8916                      */
8917
8918                      /*
8919                      // TESTING THIS HERE... LATEST ADDITION
8920                      if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
8921                      {
8922                         if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
8923                         exp.op.exp2.destType = type2._class.registered.dataType;
8924                         if(type2._class.registered.dataType)
8925                            type2._class.registered.dataType.refCount++;
8926                         CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false);
8927
8928                         //exp.expType = type2._class.registered.dataType; //type2;
8929                         //if(type2) type2.refCount++;
8930                      }
8931
8932                      // TESTING THIS HERE... LATEST ADDITION
8933                      if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
8934                      {
8935                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
8936                         exp.op.exp1.destType = type1._class.registered.dataType;
8937                         if(type1._class.registered.dataType)
8938                            type1._class.registered.dataType.refCount++;
8939                         CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false);
8940                         exp.expType = type1._class.registered.dataType; //type1;
8941                         if(type1) type1.refCount++;
8942                      }
8943                      */
8944
8945                         if(CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false))
8946                         {
8947                            if(exp.expType) FreeType(exp.expType);
8948                            exp.expType = exp.op.exp2.destType;
8949                            if(exp.op.exp2.destType) exp.op.exp2.destType.refCount++;
8950                         }
8951                         else if(type1 && type2)
8952                         {
8953                            char expString1[10240];
8954                            char expString2[10240];
8955                            char type1String[1024];
8956                            char type2String[1024];
8957                            expString1[0] = '\0';
8958                            expString2[0] = '\0';
8959                            type1String[0] = '\0';
8960                            type2String[0] = '\0';
8961                            if(inCompiler)
8962                            {
8963                               PrintExpression(exp.op.exp1, expString1);
8964                               ChangeCh(expString1, '\n', ' ');
8965                               PrintExpression(exp.op.exp2, expString2);
8966                               ChangeCh(expString2, '\n', ' ');
8967                               PrintType(exp.op.exp1.expType, type1String, false, true);
8968                               PrintType(exp.op.exp2.expType, type2String, false, true);
8969                            }
8970
8971                            Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1String, expString2, type2String);
8972
8973                            if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
8974                            {
8975                               exp.expType = exp.op.exp1.expType;
8976                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
8977                            }
8978                            else if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
8979                            {
8980                               exp.expType = exp.op.exp2.expType;
8981                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
8982                            }
8983                         }
8984                      }
8985                   }
8986                }
8987                else if(type2)
8988                {
8989                   // Maybe this was meant to be an enum...
8990                   if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
8991                   {
8992                      Type oldType = exp.op.exp1.expType;
8993                      exp.op.exp1.expType = null;
8994                      if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
8995                         FreeType(oldType);
8996                      else
8997                         exp.op.exp1.expType = oldType;
8998                   }
8999
9000                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9001                   exp.op.exp1.destType = type2;
9002                   type2.refCount++;
9003                   /*
9004                   // TESTING THIS HERE... LATEST ADDITION
9005                   if(type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
9006                   {
9007                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9008                      exp.op.exp1.destType = type1._class.registered.dataType;
9009                      if(type1._class.registered.dataType)
9010                         type1._class.registered.dataType.refCount++;
9011                   }
9012
9013                   // TESTING THIS HERE... LATEST ADDITION
9014                   if(type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
9015                   {
9016                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9017                      exp.op.exp2.destType = type2._class.registered.dataType;
9018                      if(type2._class.registered.dataType)
9019                         type2._class.registered.dataType.refCount++;
9020                   }
9021                   */
9022
9023                   if(CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false))
9024                   {
9025                      if(exp.expType) FreeType(exp.expType);
9026                      exp.expType = exp.op.exp1.destType;
9027                      if(exp.op.exp1.destType) exp.op.exp1.destType.refCount++;
9028                   }
9029                }
9030             }
9031             else if(type2 && (!type1 || (type2.kind == classType && type1.kind != classType)))
9032             {
9033                if(type1 && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
9034                {
9035                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
9036                   // Convert e.g. / 4 into / 4.0
9037                   exp.op.exp1.destType = type2._class.registered.dataType;
9038                   if(type2._class.registered.dataType)
9039                      type2._class.registered.dataType.refCount++;
9040                   CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
9041                }
9042                if(exp.op.op == '!')
9043                {
9044                   exp.expType = MkClassType("bool");
9045                   exp.expType.truth = true;
9046                }
9047                else
9048                {
9049                   exp.expType = type2;
9050                   if(type2) type2.refCount++;
9051                }
9052             }
9053             else if(type1 && (!type2 || (type1.kind == classType && type2.kind != classType)))
9054             {
9055                if(type2 && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
9056                {
9057                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
9058                   // Convert e.g. / 4 into / 4.0
9059                   exp.op.exp2.destType = type1._class.registered.dataType;
9060                   if(type1._class.registered.dataType)
9061                      type1._class.registered.dataType.refCount++;
9062                   CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
9063                }
9064                exp.expType = type1;
9065                if(type1) type1.refCount++;
9066             }
9067          }
9068
9069          yylloc = exp.loc;
9070          if(exp.op.exp1 && !exp.op.exp1.expType)
9071          {
9072             char expString[10000];
9073             expString[0] = '\0';
9074             if(inCompiler)
9075             {
9076                PrintExpression(exp.op.exp1, expString);
9077                ChangeCh(expString, '\n', ' ');
9078             }
9079             if(expString[0])
9080                Compiler_Error($"couldn't determine type of %s\n", expString);
9081          }
9082          if(exp.op.exp2 && !exp.op.exp2.expType)
9083          {
9084             char expString[10240];
9085             expString[0] = '\0';
9086             if(inCompiler)
9087             {
9088                PrintExpression(exp.op.exp2, expString);
9089                ChangeCh(expString, '\n', ' ');
9090             }
9091             if(expString[0])
9092                Compiler_Error($"couldn't determine type of %s\n", expString);
9093          }
9094
9095          if(boolResult)
9096          {
9097             FreeType(exp.expType);
9098             exp.expType = MkClassType("bool");
9099             exp.expType.truth = true;
9100          }
9101
9102          if(exp.op.op != SIZEOF)
9103             exp.isConstant = (!exp.op.exp1 || exp.op.exp1.isConstant) &&
9104                (!exp.op.exp2 || exp.op.exp2.isConstant);
9105
9106          if(exp.op.op == SIZEOF && exp.op.exp2.expType)
9107          {
9108             DeclareType(exp.op.exp2.expType, false, false);
9109          }
9110
9111          yylloc = oldyylloc;
9112
9113          FreeType(dummy);
9114          if(type2)
9115             FreeType(type2);
9116          break;
9117       }
9118       case bracketsExp:
9119       case extensionExpressionExp:
9120       {
9121          Expression e;
9122          exp.isConstant = true;
9123          for(e = exp.list->first; e; e = e.next)
9124          {
9125             bool inced = false;
9126             if(!e.next)
9127             {
9128                FreeType(e.destType);
9129                e.opDestType = exp.opDestType;
9130                e.destType = exp.destType;
9131                if(e.destType) { exp.destType.refCount++; e.destType.count++; inced = true; }
9132             }
9133             ProcessExpressionType(e);
9134             if(inced)
9135                exp.destType.count--;
9136             if(!exp.expType && !e.next)
9137             {
9138                exp.expType = e.expType;
9139                if(e.expType) e.expType.refCount++;
9140             }
9141             if(!e.isConstant)
9142                exp.isConstant = false;
9143          }
9144
9145          // In case a cast became a member...
9146          e = exp.list->first;
9147          if(!e.next && e.type == memberExp)
9148          {
9149             // Preserve prev, next
9150             Expression next = exp.next, prev = exp.prev;
9151
9152
9153             FreeType(exp.expType);
9154             FreeType(exp.destType);
9155             delete exp.list;
9156
9157             *exp = *e;
9158
9159             exp.prev = prev;
9160             exp.next = next;
9161
9162             delete e;
9163
9164             ProcessExpressionType(exp);
9165          }
9166          break;
9167       }
9168       case indexExp:
9169       {
9170          Expression e;
9171          exp.isConstant = true;
9172
9173          ProcessExpressionType(exp.index.exp);
9174          if(!exp.index.exp.isConstant)
9175             exp.isConstant = false;
9176
9177          if(exp.index.exp.expType)
9178          {
9179             Type source = exp.index.exp.expType;
9180             if(source.kind == classType && source._class && source._class.registered)
9181             {
9182                Class _class = source._class.registered;
9183                Class c = _class.templateClass ? _class.templateClass : _class;
9184                if(_class != containerClass && eClass_IsDerived(c, containerClass) && _class.templateArgs)
9185                {
9186                   exp.expType = ProcessTypeString(_class.templateArgs[2].dataTypeString, false);
9187
9188                   if(exp.index.index && exp.index.index->last)
9189                   {
9190                      Type type = ProcessTypeString(_class.templateArgs[1].dataTypeString, false);
9191
9192                      if(type.kind == classType) type.constant = true;
9193                      else if(type.kind == pointerType)
9194                      {
9195                         Type t = type;
9196                         while(t.kind == pointerType) t = t.type;
9197                         t.constant = true;
9198                      }
9199
9200                      ((Expression)exp.index.index->last).destType = type;
9201                   }
9202                }
9203             }
9204          }
9205
9206          for(e = exp.index.index->first; e; e = e.next)
9207          {
9208             if(!e.next && exp.index.exp.expType && exp.index.exp.expType.kind == arrayType && exp.index.exp.expType.enumClass)
9209             {
9210                if(e.destType) FreeType(e.destType);
9211                e.destType = MkClassType(exp.index.exp.expType.enumClass.string);
9212             }
9213             ProcessExpressionType(e);
9214             if(!e.next)
9215             {
9216                // Check if this type is int
9217             }
9218             if(!e.isConstant)
9219                exp.isConstant = false;
9220          }
9221
9222          if(!exp.expType)
9223             exp.expType = Dereference(exp.index.exp.expType);
9224          if(exp.expType)
9225             DeclareType(exp.expType, false, false);
9226          break;
9227       }
9228       case callExp:
9229       {
9230          Expression e;
9231          Type functionType;
9232          Type methodType = null;
9233          char name[1024];
9234          name[0] = '\0';
9235
9236          if(inCompiler)
9237          {
9238             PrintExpression(exp.call.exp,  name);
9239             if(exp.call.exp.expType && !exp.call.exp.expType.returnType)
9240             {
9241                //exp.call.exp.expType = null;
9242                PrintExpression(exp.call.exp,  name);
9243             }
9244          }
9245          if(exp.call.exp.type == identifierExp)
9246          {
9247             Expression idExp = exp.call.exp;
9248             Identifier id = idExp.identifier;
9249             if(!strcmp(id.string, "__builtin_frame_address"))
9250             {
9251                exp.expType = ProcessTypeString("void *", true);
9252                if(exp.call.arguments && exp.call.arguments->first)
9253                   ProcessExpressionType(exp.call.arguments->first);
9254                break;
9255             }
9256             else if(!strcmp(id.string, "__ENDIAN_PAD"))
9257             {
9258                exp.expType = ProcessTypeString("int", true);
9259                if(exp.call.arguments && exp.call.arguments->first)
9260                   ProcessExpressionType(exp.call.arguments->first);
9261                break;
9262             }
9263             else if(!strcmp(id.string, "Max") ||
9264                !strcmp(id.string, "Min") ||
9265                !strcmp(id.string, "Sgn") ||
9266                !strcmp(id.string, "Abs"))
9267             {
9268                Expression a = null;
9269                Expression b = null;
9270                Expression tempExp1 = null, tempExp2 = null;
9271                if((!strcmp(id.string, "Max") ||
9272                   !strcmp(id.string, "Min")) && exp.call.arguments->count == 2)
9273                {
9274                   a = exp.call.arguments->first;
9275                   b = exp.call.arguments->last;
9276                   tempExp1 = a;
9277                   tempExp2 = b;
9278                }
9279                else if(exp.call.arguments->count == 1)
9280                {
9281                   a = exp.call.arguments->first;
9282                   tempExp1 = a;
9283                }
9284
9285                if(a)
9286                {
9287                   exp.call.arguments->Clear();
9288                   idExp.identifier = null;
9289
9290                   FreeExpContents(exp);
9291
9292                   ProcessExpressionType(a);
9293                   if(b)
9294                      ProcessExpressionType(b);
9295
9296                   exp.type = bracketsExp;
9297                   exp.list = MkList();
9298
9299                   if(a.expType && (!b || b.expType))
9300                   {
9301                      if((!a.isConstant && a.type != identifierExp) || (b && !b.isConstant && b.type != identifierExp))
9302                      {
9303                         // Use the simpleStruct name/ids for now...
9304                         if(inCompiler)
9305                         {
9306                            OldList * specs = MkList();
9307                            OldList * decls = MkList();
9308                            Declaration decl;
9309                            char temp1[1024], temp2[1024];
9310
9311                            GetTypeSpecs(a.expType, specs);
9312
9313                            if(a && !a.isConstant && a.type != identifierExp)
9314                            {
9315                               sprintf(temp1, "__simpleStruct%d", curContext.simpleID++);
9316                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp1)), null));
9317                               tempExp1 = QMkExpId(temp1);
9318                               tempExp1.expType = a.expType;
9319                               if(a.expType)
9320                                  a.expType.refCount++;
9321                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp1), '=', a));
9322                            }
9323                            if(b && !b.isConstant && b.type != identifierExp)
9324                            {
9325                               sprintf(temp2, "__simpleStruct%d", curContext.simpleID++);
9326                               ListAdd(decls, MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(temp2)), null));
9327                               tempExp2 = QMkExpId(temp2);
9328                               tempExp2.expType = b.expType;
9329                               if(b.expType)
9330                                  b.expType.refCount++;
9331                               ListAdd(exp.list, MkExpOp(CopyExpression(tempExp2), '=', b));
9332                            }
9333
9334                            decl = MkDeclaration(specs, decls);
9335                            if(!curCompound.compound.declarations)
9336                               curCompound.compound.declarations = MkList();
9337                            curCompound.compound.declarations->Insert(null, decl);
9338                         }
9339                      }
9340                   }
9341
9342                   if(!strcmp(id.string, "Max") || !strcmp(id.string, "Min"))
9343                   {
9344                      int op = (!strcmp(id.string, "Max")) ? '>' : '<';
9345                      ListAdd(exp.list,
9346                         MkExpCondition(MkExpBrackets(MkListOne(
9347                            MkExpOp(CopyExpression(tempExp1), op, CopyExpression(tempExp2)))),
9348                            MkListOne(CopyExpression(tempExp1)), CopyExpression(tempExp2)));
9349                      exp.expType = a.expType;
9350                      if(a.expType)
9351                         a.expType.refCount++;
9352                   }
9353                   else if(!strcmp(id.string, "Abs"))
9354                   {
9355                      ListAdd(exp.list,
9356                         MkExpCondition(MkExpBrackets(MkListOne(
9357                            MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9358                            MkListOne(MkExpOp(null, '-', CopyExpression(tempExp1))), CopyExpression(tempExp1)));
9359                      exp.expType = a.expType;
9360                      if(a.expType)
9361                         a.expType.refCount++;
9362                   }
9363                   else if(!strcmp(id.string, "Sgn"))
9364                   {
9365                      // ((!(a))?(0):(((a)<0)?(-1):(1)))
9366                      ListAdd(exp.list,
9367                         MkExpCondition(MkExpBrackets(MkListOne(
9368                            MkExpOp(null, '!', CopyExpression(tempExp1)))), MkListOne(MkExpConstant("0")),
9369                               MkExpBrackets(MkListOne(MkExpCondition(MkExpBrackets(MkListOne(
9370                                  MkExpOp(CopyExpression(tempExp1), '<', MkExpConstant("0")))),
9371                                  MkListOne(MkExpConstant("-1")), MkExpConstant("1"))))));
9372                      exp.expType = ProcessTypeString("int", false);
9373                   }
9374
9375                   FreeExpression(tempExp1);
9376                   if(tempExp2) FreeExpression(tempExp2);
9377
9378                   FreeIdentifier(id);
9379                   break;
9380                }
9381             }
9382          }
9383
9384          {
9385             Type dummy
9386             {
9387                count = 1;
9388                refCount = 1;
9389             };
9390             if(!exp.call.exp.destType)
9391             {
9392                exp.call.exp.destType = dummy;
9393                dummy.refCount++;
9394             }
9395             ProcessExpressionType(exp.call.exp);
9396             if(exp.call.exp.destType == dummy)
9397             {
9398                FreeType(dummy);
9399                exp.call.exp.destType = null;
9400             }
9401             FreeType(dummy);
9402          }
9403
9404          // Check argument types against parameter types
9405          functionType = exp.call.exp.expType;
9406
9407          if(functionType && functionType.kind == TypeKind::methodType)
9408          {
9409             methodType = functionType;
9410             functionType = methodType.method.dataType;
9411
9412             //if(functionType.returnType && functionType.returnType.kind == thisClassType)
9413             // TOCHECK: Instead of doing this here could this be done per param?
9414             if(exp.call.exp.expType.usedClass)
9415             {
9416                char typeString[1024];
9417                typeString[0] = '\0';
9418                {
9419                   Symbol back = functionType.thisClass;
9420                   // Do not output class specifier here (thisclass was added to this)
9421                   functionType.thisClass = null;
9422                   PrintType(functionType, typeString, true, true);
9423                   functionType.thisClass = back;
9424                }
9425                if(strstr(typeString, "thisclass"))
9426                {
9427                   OldList * specs = MkList();
9428                   Declarator decl;
9429                   {
9430                      Context context = SetupTemplatesContext(exp.call.exp.expType.usedClass);
9431
9432                      decl = SpecDeclFromString(typeString, specs, null);
9433
9434                      // SET THIS TO FALSE WHEN PROCESSING THISCLASS OUTSIDE THE CLASS
9435                      if(thisClass != (exp.call.exp.expType.usedClass.templateClass ? exp.call.exp.expType.usedClass.templateClass :
9436                         exp.call.exp.expType.usedClass))
9437                         thisClassParams = false;
9438
9439                      ReplaceThisClassSpecifiers(specs, exp.call.exp.expType.usedClass);
9440                      {
9441                         Class backupThisClass = thisClass;
9442                         thisClass = exp.call.exp.expType.usedClass;
9443                         ProcessDeclarator(decl);
9444                         thisClass = backupThisClass;
9445                      }
9446
9447                      thisClassParams = true;
9448
9449                      functionType = ProcessType(specs, decl);
9450                      functionType.refCount = 0;
9451                      FinishTemplatesContext(context);
9452                   }
9453
9454                   FreeList(specs, FreeSpecifier);
9455                   FreeDeclarator(decl);
9456                 }
9457             }
9458          }
9459          if(functionType && functionType.kind == pointerType && functionType.type && functionType.type.kind == TypeKind::functionType)
9460          {
9461             Type type = functionType.type;
9462             if(!functionType.refCount)
9463             {
9464                functionType.type = null;
9465                FreeType(functionType);
9466             }
9467             //methodType = functionType;
9468             functionType = type;
9469          }
9470          if(functionType && functionType.kind != TypeKind::functionType)
9471          {
9472             Compiler_Error($"called object %s is not a function\n", name);
9473          }
9474          else if(functionType)
9475          {
9476             bool emptyParams = false, noParams = false;
9477             Expression e = exp.call.arguments ? exp.call.arguments->first : null;
9478             Type type = functionType.params.first;
9479             Expression memberExp = (exp.call.exp.type == ExpressionType::memberExp) ? exp.call.exp : null;
9480             int extra = 0;
9481             Location oldyylloc = yylloc;
9482
9483             if(!type) emptyParams = true;
9484
9485             // WORKING ON THIS:
9486             if(functionType.extraParam && e && functionType.thisClass)
9487             {
9488                e.destType = MkClassType(functionType.thisClass.string);
9489                e = e.next;
9490             }
9491
9492             // WHY WAS THIS COMMENTED OUT ? Broke DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
9493             // Fixed #141 by adding '&& !functionType.extraParam'
9494             if(!functionType.staticMethod && !functionType.extraParam)
9495             {
9496                if(memberExp && memberExp.member.exp && memberExp.member.exp.expType && memberExp.member.exp.expType.kind == subClassType &&
9497                   memberExp.member.exp.expType._class)
9498                {
9499                   type = MkClassType(memberExp.member.exp.expType._class.string);
9500                   if(e)
9501                   {
9502                      e.destType = type;
9503                      e = e.next;
9504                      type = functionType.params.first;
9505                   }
9506                   else
9507                      type.refCount = 0;
9508                }
9509                else if(!memberExp && (functionType.thisClass || (methodType && methodType.methodClass)))
9510                {
9511                   type = MkClassType(functionType.thisClass ? functionType.thisClass.string : (methodType ? methodType.methodClass.fullName : null));
9512                   type.byReference = functionType.byReference;
9513                   type.typedByReference = functionType.typedByReference;
9514                   if(e)
9515                   {
9516                      // Allow manually passing a class for typed object
9517                      if(e.next && type.kind == classType && (functionType && functionType.thisClass) && functionType.classObjectType == typedObject)
9518                         e = e.next;
9519                      e.destType = type;
9520                      e = e.next;
9521                      type = functionType.params.first;
9522                   }
9523                   else
9524                      type.refCount = 0;
9525                   //extra = 1;
9526                }
9527             }
9528
9529             if(type && type.kind == voidType)
9530             {
9531                noParams = true;
9532                if(!type.refCount) FreeType(type);
9533                type = null;
9534             }
9535
9536             for( ; e; e = e.next)
9537             {
9538                if(!type && !emptyParams)
9539                {
9540                   yylloc = e.loc;
9541                   if(methodType && methodType.methodClass)
9542                      Compiler_Error($"too many arguments for method %s::%s (%d given, expected %d)\n",
9543                         methodType.methodClass.fullName, methodType.method.name, exp.call.arguments->count,
9544                         noParams ? 0 : functionType.params.count);
9545                   else
9546                      Compiler_Error($"too many arguments for function %s (%d given, expected %d)\n",
9547                         name /*exp.call.exp.identifier.string*/, exp.call.arguments->count,
9548                         noParams ? 0 : functionType.params.count);
9549                   break;
9550                }
9551
9552                if(methodType && type && type.kind == templateType && type.templateParameter.type == TemplateParameterType::type)
9553                {
9554                   Type templatedType = null;
9555                   Class _class = methodType.usedClass;
9556                   ClassTemplateParameter curParam = null;
9557                   int id = 0;
9558                   if(_class && _class.templateArgs /*&& _class.templateClass*/)
9559                   {
9560                      Class sClass;
9561                      for(sClass = _class; sClass; sClass = sClass.base)
9562                      {
9563                         if(sClass.templateClass) sClass = sClass.templateClass;
9564                         id = 0;
9565                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
9566                         {
9567                            if(curParam.type == TemplateParameterType::type && !strcmp(type.templateParameter.identifier.string, curParam.name))
9568                            {
9569                               Class nextClass;
9570                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
9571                               {
9572                                  if(nextClass.templateClass) nextClass = nextClass.templateClass;
9573                                  id += nextClass.templateParams.count;
9574                               }
9575                               break;
9576                            }
9577                            id++;
9578                         }
9579                         if(curParam) break;
9580                      }
9581                   }
9582                   if(curParam && _class.templateArgs[id].dataTypeString)
9583                   {
9584                      bool constant = type.constant;
9585                      ClassTemplateArgument arg = _class.templateArgs[id];
9586                      {
9587                         Context context = SetupTemplatesContext(_class);
9588
9589                         /*if(!arg.dataType)
9590                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
9591                         templatedType = ProcessTypeString(arg.dataTypeString, false);
9592                         FinishTemplatesContext(context);
9593                      }
9594
9595                      if(templatedType.kind == classType && constant) templatedType.constant = true;
9596                      else if(templatedType.kind == pointerType)
9597                      {
9598                         Type t = templatedType.type;
9599                         while(t.kind == pointerType) t = t.type;
9600                         if(constant) t.constant = constant;
9601                      }
9602
9603                      e.destType = templatedType;
9604                      if(templatedType)
9605                      {
9606                         templatedType.passAsTemplate = true;
9607                         // templatedType.refCount++;
9608                      }
9609                   }
9610                   else
9611                   {
9612                      e.destType = type;
9613                      if(type) type.refCount++;
9614                   }
9615                }
9616                else
9617                {
9618                   if(type && type.kind == ellipsisType && type.prev && type.prev.kind == classType && type.prev.classObjectType)
9619                   {
9620                      e.destType = type.prev;
9621                      e.destType.refCount++;
9622                   }
9623                   else
9624                   {
9625                      e.destType = type;
9626                      if(type) type.refCount++;
9627                   }
9628                }
9629                // Don't reach the end for the ellipsis
9630                if(type && type.kind != ellipsisType)
9631                {
9632                   Type next = type.next;
9633                   if(!type.refCount) FreeType(type);
9634                   type = next;
9635                }
9636             }
9637
9638             if(type && type.kind != ellipsisType)
9639             {
9640                if(methodType && methodType.methodClass)
9641                   Compiler_Warning($"not enough arguments for method %s::%s (%d given, expected %d)\n",
9642                      methodType.methodClass.fullName, methodType.method.name, exp.call.arguments ? exp.call.arguments->count : 0,
9643                      functionType.params.count + extra);
9644                else
9645                   Compiler_Warning($"not enough arguments for function %s (%d given, expected %d)\n",
9646                      name /*exp.call.exp.identifier.string*/, exp.call.arguments ? exp.call.arguments->count : 0,
9647                      functionType.params.count + extra);
9648             }
9649             yylloc = oldyylloc;
9650             if(type && !type.refCount) FreeType(type);
9651          }
9652          else
9653          {
9654             functionType = Type
9655             {
9656                refCount = 0;
9657                kind = TypeKind::functionType;
9658             };
9659
9660             if(exp.call.exp.type == identifierExp)
9661             {
9662                char * string = exp.call.exp.identifier.string;
9663                if(inCompiler)
9664                {
9665                   Symbol symbol;
9666                   Location oldyylloc = yylloc;
9667
9668                   yylloc = exp.call.exp.identifier.loc;
9669                   if(strstr(string, "__builtin_") == string)
9670                   {
9671                      if(exp.destType)
9672                      {
9673                         functionType.returnType = exp.destType;
9674                         exp.destType.refCount++;
9675                      }
9676                   }
9677                   else
9678                      Compiler_Warning($"%s undefined; assuming extern returning int\n", string);
9679                   symbol = Symbol { string = CopyString(string), type = ProcessTypeString("int()", true) };
9680                   globalContext.symbols.Add((BTNode)symbol);
9681                   if(strstr(symbol.string, "::"))
9682                      globalContext.hasNameSpace = true;
9683
9684                   yylloc = oldyylloc;
9685                }
9686             }
9687             else if(exp.call.exp.type == memberExp)
9688             {
9689                /*Compiler_Warning($"%s undefined; assuming returning int\n",
9690                   exp.call.exp.member.member.string);*/
9691             }
9692             else
9693                Compiler_Warning($"callable object undefined; extern assuming returning int\n");
9694
9695             if(!functionType.returnType)
9696             {
9697                functionType.returnType = Type
9698                {
9699                   refCount = 1;
9700                   kind = intType;
9701                };
9702             }
9703          }
9704          if(functionType && functionType.kind == TypeKind::functionType)
9705          {
9706             exp.expType = functionType.returnType;
9707
9708             if(functionType.returnType)
9709                functionType.returnType.refCount++;
9710
9711             if(!functionType.refCount)
9712                FreeType(functionType);
9713          }
9714
9715          if(exp.call.arguments)
9716          {
9717             for(e = exp.call.arguments->first; e; e = e.next)
9718             {
9719                Type destType = e.destType;
9720                ProcessExpressionType(e);
9721             }
9722          }
9723          break;
9724       }
9725       case memberExp:
9726       {
9727          Type type;
9728          Location oldyylloc = yylloc;
9729          bool thisPtr;
9730          Expression checkExp = exp.member.exp;
9731          while(checkExp)
9732          {
9733             if(checkExp.type == castExp)
9734                checkExp = checkExp.cast.exp;
9735             else if(checkExp.type == bracketsExp)
9736                checkExp = checkExp.list ? checkExp.list->first : null;
9737             else
9738                break;
9739          }
9740
9741          thisPtr = (checkExp && checkExp.type == identifierExp && !strcmp(checkExp.identifier.string, "this"));
9742          exp.thisPtr = thisPtr;
9743
9744          // DOING THIS LATER NOW...
9745          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
9746          {
9747             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
9748             /* TODO: Name Space Fix ups
9749             if(!exp.member.member.classSym)
9750                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.fullName);
9751             */
9752          }
9753
9754          ProcessExpressionType(exp.member.exp);
9755          if(exp.member.exp.expType && exp.member.exp.expType.kind == classType && exp.member.exp.expType._class &&
9756             exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == normalClass)
9757          {
9758             exp.isConstant = false;
9759          }
9760          else
9761             exp.isConstant = exp.member.exp.isConstant;
9762          type = exp.member.exp.expType;
9763
9764          yylloc = exp.loc;
9765
9766          if(type && (type.kind == templateType))
9767          {
9768             Class _class = thisClass ? thisClass : currentClass;
9769             ClassTemplateParameter param = null;
9770             if(_class)
9771             {
9772                for(param = _class.templateParams.first; param; param = param.next)
9773                {
9774                   if(param.type == identifier && exp.member.member && exp.member.member.string && !strcmp(param.name, exp.member.member.string))
9775                      break;
9776                }
9777             }
9778             if(param && param.defaultArg.member)
9779             {
9780                Expression argExp = GetTemplateArgExpByName(param.name, thisClass, TemplateParameterType::identifier);
9781                if(argExp)
9782                {
9783                   Expression expMember = exp.member.exp;
9784                   Declarator decl;
9785                   OldList * specs = MkList();
9786                   char thisClassTypeString[1024];
9787
9788                   FreeIdentifier(exp.member.member);
9789
9790                   ProcessExpressionType(argExp);
9791
9792                   {
9793                      char * colon = strstr(param.defaultArg.memberString, "::");
9794                      if(colon)
9795                      {
9796                         char className[1024];
9797                         Class sClass;
9798
9799                         memcpy(thisClassTypeString, param.defaultArg.memberString, colon - param.defaultArg.memberString);
9800                         thisClassTypeString[colon - param.defaultArg.memberString] = '\0';
9801                      }
9802                      else
9803                         strcpy(thisClassTypeString, _class.fullName);
9804                   }
9805
9806                   decl = SpecDeclFromString(param.defaultArg.member.dataTypeString, specs, null);
9807
9808                   exp.expType = ProcessType(specs, decl);
9809                   if(exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.templateClass)
9810                   {
9811                      Class expClass = exp.expType._class.registered;
9812                      Class cClass = null;
9813                      int c;
9814                      int paramCount = 0;
9815                      int lastParam = -1;
9816
9817                      char templateString[1024];
9818                      ClassTemplateParameter param;
9819                      sprintf(templateString, "%s<", expClass.templateClass.fullName);
9820                      for(cClass = expClass; cClass; cClass = cClass.base)
9821                      {
9822                         int p = 0;
9823                         for(param = cClass.templateParams.first; param; param = param.next)
9824                         {
9825                            int id = p;
9826                            Class sClass;
9827                            ClassTemplateArgument arg;
9828                            for(sClass = cClass.base; sClass; sClass = sClass.base) id += sClass.templateParams.count;
9829                            arg = expClass.templateArgs[id];
9830
9831                            for(sClass = _class /*expClass*/; sClass; sClass = sClass.base)
9832                            {
9833                               ClassTemplateParameter cParam;
9834                               //int p = numParams - sClass.templateParams.count;
9835                               int p = 0;
9836                               Class nextClass;
9837                               for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) p += nextClass.templateParams.count;
9838
9839                               for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next, p++)
9840                               {
9841                                  if(cParam.type == TemplateParameterType::type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
9842                                  {
9843                                     if(_class.templateArgs && arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9844                                     {
9845                                        arg.dataTypeString = _class.templateArgs[p].dataTypeString;
9846                                        arg.dataTypeClass = _class.templateArgs[p].dataTypeClass;
9847                                        break;
9848                                     }
9849                                  }
9850                               }
9851                            }
9852
9853                            {
9854                               char argument[256];
9855                               argument[0] = '\0';
9856                               /*if(arg.name)
9857                               {
9858                                  strcat(argument, arg.name.string);
9859                                  strcat(argument, " = ");
9860                               }*/
9861                               switch(param.type)
9862                               {
9863                                  case expression:
9864                                  {
9865                                     // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
9866                                     char expString[1024];
9867                                     OldList * specs = MkList();
9868                                     Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
9869                                     Expression exp;
9870                                     char * string = PrintHexUInt64(arg.expression.ui64);
9871                                     exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
9872                                     delete string;
9873
9874                                     ProcessExpressionType(exp);
9875                                     ComputeExpression(exp);
9876                                     expString[0] = '\0';
9877                                     PrintExpression(exp, expString);
9878                                     strcat(argument, expString);
9879                                     // delete exp;
9880                                     FreeExpression(exp);
9881                                     break;
9882                                  }
9883                                  case identifier:
9884                                  {
9885                                     strcat(argument, arg.member.name);
9886                                     break;
9887                                  }
9888                                  case TemplateParameterType::type:
9889                                  {
9890                                     if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
9891                                     {
9892                                        if(!strcmp(arg.dataTypeString, "thisclass"))
9893                                           strcat(argument, thisClassTypeString);
9894                                        else
9895                                           strcat(argument, arg.dataTypeString);
9896                                     }
9897                                     break;
9898                                  }
9899                               }
9900                               if(argument[0])
9901                               {
9902                                  if(paramCount) strcat(templateString, ", ");
9903                                  if(lastParam != p - 1)
9904                                  {
9905                                     strcat(templateString, param.name);
9906                                     strcat(templateString, " = ");
9907                                  }
9908                                  strcat(templateString, argument);
9909                                  paramCount++;
9910                                  lastParam = p;
9911                               }
9912                               p++;
9913                            }
9914                         }
9915                      }
9916                      {
9917                         int len = strlen(templateString);
9918                         if(templateString[len-1] == '>') templateString[len++] = ' ';
9919                         templateString[len++] = '>';
9920                         templateString[len++] = '\0';
9921                      }
9922                      {
9923                         Context context = SetupTemplatesContext(_class);
9924                         FreeType(exp.expType);
9925                         exp.expType = ProcessTypeString(templateString, false);
9926                         FinishTemplatesContext(context);
9927                      }
9928                   }
9929
9930                   // *([expType] *)(((byte *)[exp.member.exp]) + [argExp].member.offset)
9931                   exp.type = bracketsExp;
9932                   exp.list = MkListOne(MkExpOp(null, '*',
9933                   /*opExp;
9934                   exp.op.op = '*';
9935                   exp.op.exp1 = null;
9936                   exp.op.exp2 = */
9937                   MkExpCast(MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl)), MkExpBrackets(MkListOne(MkExpOp(
9938                      MkExpBrackets(MkListOne(
9939                         MkExpCast(MkTypeName(MkListOne(MkSpecifierName("byte")), MkDeclaratorPointer(MkPointer(null, null), null)), expMember))),
9940                            '+',
9941                            MkExpOp(MkExpMember(MkExpMember(argExp, MkIdentifier("member")), MkIdentifier("offset")),
9942                            '+',
9943                            MkExpMember(MkExpMember(MkExpMember(CopyExpression(argExp), MkIdentifier("member")), MkIdentifier("_class")), MkIdentifier("offset")))))))
9944
9945                            ));
9946                }
9947             }
9948             else if(type.templateParameter && type.templateParameter.type == TemplateParameterType::type &&
9949                (type.templateParameter.dataType || type.templateParameter.dataTypeString))
9950             {
9951                type = ProcessTemplateParameterType(type.templateParameter);
9952             }
9953          }
9954          // TODO: *** This seems to be where we should add method support for all basic types ***
9955          if(type && (type.kind == templateType));
9956          else if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType ||
9957                           type.kind == int64Type || type.kind == shortType || type.kind == longType || type.kind == charType || type.kind == _BoolType ||
9958                           type.kind == intPtrType || type.kind == intSizeType || type.kind == floatType || type.kind == doubleType ||
9959                           (type.kind == pointerType && type.type.kind == charType)))
9960          {
9961             Identifier id = exp.member.member;
9962             TypeKind typeKind = type.kind;
9963             Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
9964             if(typeKind == subClassType && exp.member.exp.type == classExp)
9965             {
9966                _class = eSystem_FindClass(privateModule, "ecere::com::Class");
9967                typeKind = classType;
9968             }
9969
9970             if(id)
9971             {
9972                if(typeKind == intType || typeKind == enumType)
9973                   _class = eSystem_FindClass(privateModule, "int");
9974                else if(!_class)
9975                {
9976                   if(type.kind == classType && type._class && type._class.registered)
9977                   {
9978                      _class = type._class.registered;
9979                   }
9980                   else if((type.kind == arrayType || type.kind == pointerType) && type.type && type.type.kind == charType)
9981                   {
9982                      _class = FindClass("char *").registered;
9983                   }
9984                   else if(type.kind == pointerType)
9985                   {
9986                      _class = eSystem_FindClass(privateModule, "uintptr");
9987                      FreeType(exp.expType);
9988                      exp.expType = ProcessTypeString("uintptr", false);
9989                      exp.byReference = true;
9990                   }
9991                   else
9992                   {
9993                      char string[1024] = "";
9994                      Symbol classSym;
9995                      PrintTypeNoConst(type, string, false, true);
9996                      classSym = FindClass(string);
9997                      if(classSym) _class = classSym.registered;
9998                   }
9999                }
10000             }
10001
10002             if(_class && id)
10003             {
10004                /*bool thisPtr =
10005                   (exp.member.exp.type == identifierExp &&
10006                   !strcmp(exp.member.exp.identifier.string, "this"));*/
10007                Property prop = null;
10008                Method method = null;
10009                DataMember member = null;
10010                Property revConvert = null;
10011                ClassProperty classProp = null;
10012
10013                if(id && id._class && id._class.name && !strcmp(id._class.name, "property"))
10014                   exp.member.memberType = propertyMember;
10015
10016                if(id && id._class && type._class && !eClass_IsDerived(type._class.registered, _class))
10017                   Compiler_Error($"invalid class specifier %s for object of class %s\n", _class.fullName, type._class.string);
10018
10019                if(typeKind != subClassType)
10020                {
10021                   // Prioritize data members over properties for "this"
10022                   if((exp.member.memberType == unresolvedMember && thisPtr) || exp.member.memberType == dataMember)
10023                   {
10024                      member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
10025                      if(member && member._class != (_class.templateClass ? _class.templateClass : _class) && exp.member.memberType != dataMember)
10026                      {
10027                         prop = eClass_FindProperty(_class, id.string, privateModule);
10028                         if(prop)
10029                            member = null;
10030                      }
10031                      if(!member && !prop)
10032                         prop = eClass_FindProperty(_class, id.string, privateModule);
10033                      if((member && member._class == (_class.templateClass ? _class.templateClass : _class)) ||
10034                         (prop && prop._class == (_class.templateClass ? _class.templateClass : _class)))
10035                         exp.member.thisPtr = true;
10036                   }
10037                   // Prioritize properties over data members otherwise
10038                   else
10039                   {
10040                      bool useMemberForNonConst = false;
10041                      // First look for Public Members (Unless class specifier is provided, which skips public priority)
10042                      if(!id.classSym)
10043                      {
10044                         prop = eClass_FindProperty(_class, id.string, null);
10045
10046                         useMemberForNonConst = prop && exp.destType &&
10047                            ( (exp.destType.kind == classType && !exp.destType.constant) || ((exp.destType.kind == pointerType || exp.destType.kind == arrayType) && exp.destType.type && !exp.destType.type.constant) ) &&
10048                               !strncmp(prop.dataTypeString, "const ", 6);
10049
10050                         if(useMemberForNonConst || !id._class || !id._class.name || strcmp(id._class.name, "property"))
10051                            member = eClass_FindDataMember(_class, id.string, null, null, null);
10052                      }
10053
10054                      if((!prop || useMemberForNonConst) && !member)
10055                      {
10056                         method = useMemberForNonConst ? null : eClass_FindMethod(_class, id.string, null);
10057                         if(!method)
10058                         {
10059                            prop = eClass_FindProperty(_class, id.string, privateModule);
10060
10061                            useMemberForNonConst |= prop && exp.destType &&
10062                               ( (exp.destType.kind == classType && !exp.destType.constant) || ((exp.destType.kind == pointerType || exp.destType.kind == arrayType) && exp.destType.type && !exp.destType.type.constant) ) &&
10063                                  !strncmp(prop.dataTypeString, "const ", 6);
10064
10065                            if(useMemberForNonConst || !id._class || !id._class.name || strcmp(id._class.name, "property"))
10066                               member = eClass_FindDataMember(_class, id.string, privateModule, null, null);
10067                         }
10068                      }
10069
10070                      if(member && prop)
10071                      {
10072                         if(useMemberForNonConst || (member._class != prop._class && !id._class && eClass_IsDerived(member._class, prop._class)))
10073                            prop = null;
10074                         else
10075                            member = null;
10076                      }
10077                   }
10078                }
10079                if(!prop && !member && !method)     // NOTE: Recently added the !method here, causes private methods to unprioritized
10080                   method = eClass_FindMethod(_class, id.string, privateModule);
10081                if(!prop && !member && !method)
10082                {
10083                   if(typeKind == subClassType)
10084                   {
10085                      classProp = eClass_FindClassProperty(type._class.registered, exp.member.member.string);
10086                      if(classProp)
10087                      {
10088                         exp.member.memberType = classPropertyMember;
10089                         exp.expType = ProcessTypeString(classProp.dataTypeString, false);
10090                      }
10091                      else
10092                      {
10093                         // Assume this is a class_data member
10094                         char structName[1024];
10095                         Identifier id = exp.member.member;
10096                         Expression classExp = exp.member.exp;
10097                         type.refCount++;
10098
10099                         FreeType(classExp.expType);
10100                         classExp.expType = ProcessTypeString("ecere::com::Class", false);
10101
10102                         strcpy(structName, "__ecereClassData_");
10103                         FullClassNameCat(structName, type._class.string, false);
10104                         exp.type = pointerExp;
10105                         exp.member.member = id;
10106
10107                         exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10108                            MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10109                               MkExpBrackets(MkListOne(MkExpOp(
10110                                  MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10111                                     MkExpMember(classExp, MkIdentifier("data"))), '+',
10112                                        MkExpMember(MkExpClass(MkListOne(MkSpecifierName(type._class.string)), null), MkIdentifier("offsetClass")))))
10113                                  )));
10114
10115                         FreeType(type);
10116
10117                         ProcessExpressionType(exp);
10118                         return;
10119                      }
10120                   }
10121                   else
10122                   {
10123                      // Check for reverse conversion
10124                      // (Convert in an instantiation later, so that we can use
10125                      //  deep properties system)
10126                      Symbol classSym = FindClass(id.string);
10127                      if(classSym)
10128                      {
10129                         Class convertClass = classSym.registered;
10130                         if(convertClass)
10131                            revConvert = eClass_FindProperty(convertClass, _class.fullName, privateModule);
10132                      }
10133                   }
10134                }
10135
10136                if(prop)
10137                {
10138                   exp.member.memberType = propertyMember;
10139                   if(!prop.dataType)
10140                      ProcessPropertyType(prop);
10141                   exp.expType = prop.dataType;
10142                   if(!strcmp(_class.base.fullName, "eda::Row") && !exp.expType.constant && !exp.destType)
10143                   {
10144                      Type type { };
10145                      CopyTypeInto(type, exp.expType);
10146                      type.refCount = 1;
10147                      type.constant = true;
10148                      exp.expType = type;
10149                   }
10150                   else if(prop.dataType)
10151                      prop.dataType.refCount++;
10152                }
10153                else if(member)
10154                {
10155                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
10156                   {
10157                      FreeExpContents(exp);
10158                      exp.type = identifierExp;
10159                      exp.identifier = MkIdentifier("class");
10160                      ProcessExpressionType(exp);
10161                      return;
10162                   }
10163
10164                   exp.member.memberType = dataMember;
10165                   DeclareStruct(_class.fullName, false);
10166                   if(!member.dataType)
10167                   {
10168                      Context context = SetupTemplatesContext(_class);
10169                      member.dataType = ProcessTypeString(member.dataTypeString, false);
10170                      FinishTemplatesContext(context);
10171                   }
10172                   exp.expType = member.dataType;
10173                   if(member.dataType) member.dataType.refCount++;
10174                }
10175                else if(revConvert)
10176                {
10177                   exp.member.memberType = reverseConversionMember;
10178                   exp.expType = MkClassType(revConvert._class.fullName);
10179                }
10180                else if(method)
10181                {
10182                   //if(inCompiler)
10183                   {
10184                      /*if(id._class)
10185                      {
10186                         exp.type = identifierExp;
10187                         exp.identifier = exp.member.member;
10188                      }
10189                      else*/
10190                         exp.member.memberType = methodMember;
10191                   }
10192                   if(!method.dataType)
10193                      ProcessMethodType(method);
10194                   exp.expType = Type
10195                   {
10196                      refCount = 1;
10197                      kind = methodType;
10198                      method = method;
10199                   };
10200
10201                   // Tricky spot here... To use instance versus class virtual table
10202                   // Put it back to what it was... What did we break?
10203
10204                   // Had to put it back for overriding Main of Thread global instance
10205
10206                   //exp.expType.methodClass = _class;
10207                   exp.expType.methodClass = (id && id._class) ? _class : null;
10208
10209                   // Need the actual class used for templated classes
10210                   exp.expType.usedClass = _class;
10211                }
10212                else if(!classProp)
10213                {
10214                   if(exp.member.exp.expType.classObjectType == typedObject && !strcmp(exp.member.member.string, "_class"))
10215                   {
10216                      FreeExpContents(exp);
10217                      exp.type = identifierExp;
10218                      exp.identifier = MkIdentifier("class");
10219                      FreeType(exp.expType);
10220                      exp.expType = MkClassType("ecere::com::Class");
10221                      return;
10222                   }
10223                   yylloc = exp.member.member.loc;
10224                   Compiler_Error($"couldn't find member %s in class %s\n", id.string, _class.fullName);
10225                   if(inCompiler)
10226                      eClass_AddDataMember(_class, id.string, "int", 0, 0, publicAccess);
10227                }
10228
10229                if(_class && /*(_class.templateClass || _class.templateArgs) && */exp.expType)
10230                {
10231                   Class tClass;
10232
10233                   tClass = _class;
10234                   while(tClass && !tClass.templateClass) tClass = tClass.base;
10235
10236                   if(tClass && exp.expType.kind == templateType && exp.expType.templateParameter.type == TemplateParameterType::type)
10237                   {
10238                      int id = 0;
10239                      ClassTemplateParameter curParam = null;
10240                      Class sClass;
10241
10242                      for(sClass = tClass; sClass; sClass = sClass.base)
10243                      {
10244                         id = 0;
10245                         if(sClass.templateClass) sClass = sClass.templateClass;
10246                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
10247                         {
10248                            if(curParam.type == TemplateParameterType::type && !strcmp(exp.expType.templateParameter.identifier.string, curParam.name))
10249                            {
10250                               for(sClass = sClass.base; sClass; sClass = sClass.base)
10251                                  id += sClass.templateParams.count;
10252                               break;
10253                            }
10254                            id++;
10255                         }
10256                         if(curParam) break;
10257                      }
10258
10259                      if(curParam && tClass.templateArgs[id].dataTypeString)
10260                      {
10261                         ClassTemplateArgument arg = tClass.templateArgs[id];
10262                         Context context = SetupTemplatesContext(tClass);
10263                         bool constant = exp.expType.constant;
10264                         /*if(!arg.dataType)
10265                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
10266                         FreeType(exp.expType);
10267
10268                         exp.expType = ProcessTypeString(arg.dataTypeString, false);
10269                         if(exp.expType.kind == classType && constant) exp.expType.constant = true;
10270                         else if(exp.expType.kind == pointerType)
10271                         {
10272                            Type t = exp.expType.type;
10273                            while(t.kind == pointerType) t = t.type;
10274                            if(constant) t.constant = constant;
10275                         }
10276                         if(exp.expType)
10277                         {
10278                            if(exp.expType.kind == thisClassType)
10279                            {
10280                               FreeType(exp.expType);
10281                               exp.expType = ReplaceThisClassType(_class);
10282                            }
10283
10284                            if(tClass.templateClass)
10285                               exp.expType.passAsTemplate = true;
10286                            //exp.expType.refCount++;
10287                            if(!exp.destType)
10288                            {
10289                               exp.destType = ProcessTypeString(arg.dataTypeString, false);
10290                               if(exp.destType.kind == classType && constant) exp.destType.constant = true;
10291                               else if(exp.destType.kind == pointerType)
10292                               {
10293                                  Type t = exp.destType.type;
10294                                  while(t.kind == pointerType) t = t.type;
10295                                  if(constant) t.constant = constant;
10296                               }
10297
10298                               //exp.destType.refCount++;
10299
10300                               if(exp.destType.kind == thisClassType)
10301                               {
10302                                  FreeType(exp.destType);
10303                                  exp.destType = ReplaceThisClassType(_class);
10304                               }
10305                            }
10306                         }
10307                         FinishTemplatesContext(context);
10308                      }
10309                   }
10310                   // TODO: MORE GENERIC SUPPORT FOR DEEPER TYPES
10311                   else if(tClass && exp.expType.kind == pointerType && exp.expType.type && exp.expType.type.kind == templateType && exp.expType.type.templateParameter.type == TemplateParameterType::type)
10312                   {
10313                      int id = 0;
10314                      ClassTemplateParameter curParam = null;
10315                      Class sClass;
10316
10317                      for(sClass = tClass; sClass; sClass = sClass.base)
10318                      {
10319                         id = 0;
10320                         if(sClass.templateClass) sClass = sClass.templateClass;
10321                         for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
10322                         {
10323                            if(curParam.type == TemplateParameterType::type &&
10324                               !strcmp(exp.expType.type.templateParameter.identifier.string, curParam.name))
10325                            {
10326                               for(sClass = sClass.base; sClass; sClass = sClass.base)
10327                                  id += sClass.templateParams.count;
10328                               break;
10329                            }
10330                            id++;
10331                         }
10332                         if(curParam) break;
10333                      }
10334
10335                      if(curParam)
10336                      {
10337                         ClassTemplateArgument arg = tClass.templateArgs[id];
10338                         Context context = SetupTemplatesContext(tClass);
10339                         Type basicType;
10340                         /*if(!arg.dataType)
10341                            arg.dataType = ProcessTypeString(arg.dataTypeString, false);*/
10342
10343                         basicType = ProcessTypeString(arg.dataTypeString, false);
10344                         if(basicType)
10345                         {
10346                            if(basicType.kind == thisClassType)
10347                            {
10348                               FreeType(basicType);
10349                               basicType = ReplaceThisClassType(_class);
10350                            }
10351
10352                            /*    DO WE REALLY WANT THIS HERE? IT SEEMS TO BE ONLY USED WITH Array::array which was causing bug 135
10353                            if(tClass.templateClass)
10354                               basicType.passAsTemplate = true;
10355                            */
10356
10357                            FreeType(exp.expType);
10358
10359                            exp.expType = Type { refCount = 1, kind = pointerType, type = basicType };
10360                            //exp.expType.refCount++;
10361                            if(!exp.destType)
10362                            {
10363                               exp.destType = exp.expType;
10364                               exp.destType.refCount++;
10365                            }
10366
10367                            {
10368                               Expression newExp { };
10369                               OldList * specs = MkList();
10370                               Declarator decl;
10371                               decl = SpecDeclFromString(arg.dataTypeString, specs, null);
10372                               *newExp = *exp;
10373                               if(exp.destType) exp.destType.refCount++;
10374                               if(exp.expType)  exp.expType.refCount++;
10375                               exp.type = castExp;
10376                               exp.cast.typeName = MkTypeName(specs, MkDeclaratorPointer(MkPointer(null, null), decl));
10377                               exp.cast.exp = newExp;
10378                               //FreeType(exp.expType);
10379                               //exp.expType = null;
10380                               //ProcessExpressionType(sourceExp);
10381                            }
10382                         }
10383                         FinishTemplatesContext(context);
10384                      }
10385                   }
10386                   else if(tClass && exp.expType.kind == classType && exp.expType._class && strchr(exp.expType._class.string, '<'))
10387                   {
10388                      Class expClass = exp.expType._class.registered;
10389                      if(expClass)
10390                      {
10391                         Class cClass = null;
10392                         int c;
10393                         int p = 0;
10394                         int paramCount = 0;
10395                         int lastParam = -1;
10396                         char templateString[1024];
10397                         ClassTemplateParameter param;
10398                         sprintf(templateString, "%s<", expClass.templateClass.fullName);
10399                         while(cClass != expClass)
10400                         {
10401                            Class sClass;
10402                            for(sClass = expClass; sClass && sClass.base != cClass; sClass = sClass.base);
10403                            cClass = sClass;
10404
10405                            for(param = cClass.templateParams.first; param; param = param.next)
10406                            {
10407                               Class cClassCur = null;
10408                               int c;
10409                               int cp = 0;
10410                               ClassTemplateParameter paramCur = null;
10411                               ClassTemplateArgument arg;
10412                               while(cClassCur != tClass && !paramCur)
10413                               {
10414                                  Class sClassCur;
10415                                  for(sClassCur = tClass; sClassCur && sClassCur.base != cClassCur; sClassCur = sClassCur.base);
10416                                  cClassCur = sClassCur;
10417
10418                                  for(paramCur = cClassCur.templateParams.first; paramCur; paramCur = paramCur.next)
10419                                  {
10420                                     if(!strcmp(paramCur.name, param.name))
10421                                     {
10422
10423                                        break;
10424                                     }
10425                                     cp++;
10426                                  }
10427                               }
10428                               if(paramCur && paramCur.type == TemplateParameterType::type)
10429                                  arg = tClass.templateArgs[cp];
10430                               else
10431                                  arg = expClass.templateArgs[p];
10432
10433                               {
10434                                  char argument[256];
10435                                  argument[0] = '\0';
10436                                  /*if(arg.name)
10437                                  {
10438                                     strcat(argument, arg.name.string);
10439                                     strcat(argument, " = ");
10440                                  }*/
10441                                  switch(param.type)
10442                                  {
10443                                     case expression:
10444                                     {
10445                                        // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
10446                                        char expString[1024];
10447                                        OldList * specs = MkList();
10448                                        Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
10449                                        Expression exp;
10450                                        char * string = PrintHexUInt64(arg.expression.ui64);
10451                                        exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
10452                                        delete string;
10453
10454                                        ProcessExpressionType(exp);
10455                                        ComputeExpression(exp);
10456                                        expString[0] = '\0';
10457                                        PrintExpression(exp, expString);
10458                                        strcat(argument, expString);
10459                                        // delete exp;
10460                                        FreeExpression(exp);
10461                                        break;
10462                                     }
10463                                     case identifier:
10464                                     {
10465                                        strcat(argument, arg.member.name);
10466                                        break;
10467                                     }
10468                                     case TemplateParameterType::type:
10469                                     {
10470                                        if(arg.dataTypeString && (!param.defaultArg.dataTypeString || strcmp(arg.dataTypeString, param.defaultArg.dataTypeString)))
10471                                           strcat(argument, arg.dataTypeString);
10472                                        break;
10473                                     }
10474                                  }
10475                                  if(argument[0])
10476                                  {
10477                                     if(paramCount) strcat(templateString, ", ");
10478                                     if(lastParam != p - 1)
10479                                     {
10480                                        strcat(templateString, param.name);
10481                                        strcat(templateString, " = ");
10482                                     }
10483                                     strcat(templateString, argument);
10484                                     paramCount++;
10485                                     lastParam = p;
10486                                  }
10487                               }
10488                               p++;
10489                            }
10490                         }
10491                         {
10492                            int len = strlen(templateString);
10493                            if(templateString[len-1] == '>') templateString[len++] = ' ';
10494                            templateString[len++] = '>';
10495                            templateString[len++] = '\0';
10496                         }
10497
10498                         FreeType(exp.expType);
10499                         {
10500                            Context context = SetupTemplatesContext(tClass);
10501                            exp.expType = ProcessTypeString(templateString, false);
10502                            FinishTemplatesContext(context);
10503                         }
10504                      }
10505                   }
10506                }
10507             }
10508             else
10509                Compiler_Error($"undefined class %s\n", (id && (!id._class || id._class.name))? (id.classSym ? id.classSym.string : (type._class ? type._class.string : null)) : "(null)");
10510          }
10511          else if(type && (type.kind == structType || type.kind == unionType))
10512          {
10513             Type memberType = exp.member.member ? FindMember(type, exp.member.member.string) : null;
10514             if(memberType)
10515             {
10516                exp.expType = memberType;
10517                if(memberType)
10518                   memberType.refCount++;
10519             }
10520          }
10521          else
10522          {
10523             char expString[10240];
10524             expString[0] = '\0';
10525             if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
10526             Compiler_Error($"member operator on non-structure type expression %s\n", expString);
10527          }
10528
10529          if(exp.expType && exp.expType.kind == thisClassType && (!exp.destType || exp.destType.kind != thisClassType))
10530          {
10531             if(type && (type.kind == classType || type.kind == subClassType || type.kind == intType || type.kind == enumType))
10532             {
10533                Identifier id = exp.member.member;
10534                Class _class = (id && (!id._class || id._class.name))? ( id.classSym ? id.classSym.registered : (type._class ? type._class.registered : null)) : null;
10535                if(_class)
10536                {
10537                   FreeType(exp.expType);
10538                   exp.expType = ReplaceThisClassType(_class);
10539                }
10540             }
10541          }
10542          yylloc = oldyylloc;
10543          break;
10544       }
10545       // Convert x->y into (*x).y
10546       case pointerExp:
10547       {
10548          Type destType = exp.destType;
10549
10550          // DOING THIS LATER NOW...
10551          if(exp.member.member && exp.member.member._class && exp.member.member._class.name)
10552          {
10553             exp.member.member.classSym = exp.member.member._class.symbol; // FindClass(exp.member.member._class.name);
10554             /* TODO: Name Space Fix ups
10555             if(!exp.member.member.classSym)
10556                exp.member.member.nameSpace = eSystem_FindNameSpace(privateModule, exp.member.member._class.name);
10557             */
10558          }
10559
10560          exp.member.exp = MkExpBrackets(MkListOne(MkExpOp(null, '*', exp.member.exp)));
10561          exp.type = memberExp;
10562          if(destType)
10563             destType.count++;
10564          ProcessExpressionType(exp);
10565          if(destType)
10566             destType.count--;
10567          break;
10568       }
10569       case classSizeExp:
10570       {
10571          //ComputeExpression(exp);
10572
10573          Symbol classSym = exp._class.symbol; // FindClass(exp._class.name);
10574          if(classSym && classSym.registered)
10575          {
10576             if(classSym.registered.type == noHeadClass)
10577             {
10578                char name[1024];
10579                name[0] = '\0';
10580                DeclareStruct(classSym.string, false);
10581                FreeSpecifier(exp._class);
10582                exp.type = typeSizeExp;
10583                FullClassNameCat(name, classSym.string, false);
10584                exp.typeName = MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(name), null)), null);
10585             }
10586             else
10587             {
10588                if(classSym.registered.fixed)
10589                {
10590                   FreeSpecifier(exp._class);
10591                   exp.constant = PrintUInt(classSym.registered.templateClass ? classSym.registered.templateClass.structSize : classSym.registered.structSize);
10592                   exp.type = constantExp;
10593                }
10594                else
10595                {
10596                   char className[1024];
10597                   strcpy(className, "__ecereClass_");
10598                   FullClassNameCat(className, classSym.string, true);
10599                   MangleClassName(className);
10600
10601                   DeclareClass(classSym, className);
10602
10603                   FreeExpContents(exp);
10604                   exp.type = pointerExp;
10605                   exp.member.exp = MkExpIdentifier(MkIdentifier(className));
10606                   exp.member.member = MkIdentifier("structSize");
10607                }
10608             }
10609          }
10610
10611          exp.expType = Type
10612          {
10613             refCount = 1;
10614             kind = intSizeType;
10615          };
10616          // exp.isConstant = true;
10617          break;
10618       }
10619       case typeSizeExp:
10620       {
10621          Type type = ProcessType(exp.typeName.qualifiers, exp.typeName.declarator);
10622
10623          exp.expType = Type
10624          {
10625             refCount = 1;
10626             kind = intSizeType;
10627          };
10628          exp.isConstant = true;
10629
10630          DeclareType(type, false, false);
10631          FreeType(type);
10632          break;
10633       }
10634       case castExp:
10635       {
10636          Type type = ProcessType(exp.cast.typeName.qualifiers, exp.cast.typeName.declarator);
10637          type.count = 1;
10638          FreeType(exp.cast.exp.destType);
10639          exp.cast.exp.destType = type;
10640          type.refCount++;
10641          type.casted = true;
10642          ProcessExpressionType(exp.cast.exp);
10643          type.casted = false;
10644          type.count = 0;
10645          exp.expType = type;
10646          //type.refCount++;
10647
10648          // if(!NeedCast(exp.cast.exp.expType, exp.cast.exp.destType))
10649          if(!exp.cast.exp.needCast && !NeedCast(exp.cast.exp.expType, type))
10650          {
10651             void * prev = exp.prev, * next = exp.next;
10652             Type expType = exp.cast.exp.destType;
10653             Expression castExp = exp.cast.exp;
10654             Type destType = exp.destType;
10655
10656             if(expType) expType.refCount++;
10657
10658             //FreeType(exp.destType);
10659             FreeType(exp.expType);
10660             FreeTypeName(exp.cast.typeName);
10661
10662             *exp = *castExp;
10663             FreeType(exp.expType);
10664             FreeType(exp.destType);
10665
10666             exp.expType = expType;
10667             exp.destType = destType;
10668
10669             delete castExp;
10670
10671             exp.prev = prev;
10672             exp.next = next;
10673
10674          }
10675          else
10676          {
10677             exp.isConstant = exp.cast.exp.isConstant;
10678          }
10679          //FreeType(type);
10680          break;
10681       }
10682       case extensionInitializerExp:
10683       {
10684          Type type = ProcessType(exp.initializer.typeName.qualifiers, exp.initializer.typeName.declarator);
10685          // We have yet to support this... ( { } initializers are currently processed inside ProcessDeclaration()'s initDeclaration case statement
10686          // ProcessInitializer(exp.initializer.initializer, type);
10687          exp.expType = type;
10688          break;
10689       }
10690       case vaArgExp:
10691       {
10692          Type type = ProcessType(exp.vaArg.typeName.qualifiers, exp.vaArg.typeName.declarator);
10693          ProcessExpressionType(exp.vaArg.exp);
10694          exp.expType = type;
10695          break;
10696       }
10697       case conditionExp:
10698       {
10699          Expression e;
10700          exp.isConstant = true;
10701
10702          FreeType(exp.cond.cond.destType);
10703          exp.cond.cond.destType = MkClassType("bool");
10704          exp.cond.cond.destType.truth = true;
10705          ProcessExpressionType(exp.cond.cond);
10706          if(!exp.cond.cond.isConstant)
10707             exp.isConstant = false;
10708          for(e = exp.cond.exp->first; e; e = e.next)
10709          {
10710             if(!e.next)
10711             {
10712                FreeType(e.destType);
10713                e.destType = exp.destType;
10714                if(e.destType) e.destType.refCount++;
10715             }
10716             ProcessExpressionType(e);
10717             if(!e.next)
10718             {
10719                exp.expType = e.expType;
10720                if(e.expType) e.expType.refCount++;
10721             }
10722             if(!e.isConstant)
10723                exp.isConstant = false;
10724          }
10725
10726          FreeType(exp.cond.elseExp.destType);
10727          // Added this check if we failed to find an expType
10728          // exp.cond.elseExp.destType = exp.expType ? exp.expType : exp.destType;
10729
10730          // Reversed it...
10731          exp.cond.elseExp.destType = exp.destType ? exp.destType : exp.expType;
10732
10733          if(exp.cond.elseExp.destType)
10734             exp.cond.elseExp.destType.refCount++;
10735          ProcessExpressionType(exp.cond.elseExp);
10736
10737          // FIXED THIS: Was done before calling process on elseExp
10738          if(!exp.cond.elseExp.isConstant)
10739             exp.isConstant = false;
10740          break;
10741       }
10742       case extensionCompoundExp:
10743       {
10744          if(exp.compound && exp.compound.compound.statements && exp.compound.compound.statements->last)
10745          {
10746             Statement last = exp.compound.compound.statements->last;
10747             if(last.type == expressionStmt && last.expressions && last.expressions->last)
10748             {
10749                ((Expression)last.expressions->last).destType = exp.destType;
10750                if(exp.destType)
10751                   exp.destType.refCount++;
10752             }
10753             ProcessStatement(exp.compound);
10754             exp.expType = (last.expressions && last.expressions->last) ? ((Expression)last.expressions->last).expType : null;
10755             if(exp.expType)
10756                exp.expType.refCount++;
10757          }
10758          break;
10759       }
10760       case classExp:
10761       {
10762          Specifier spec = exp._classExp.specifiers->first;
10763          if(spec && spec.type == nameSpecifier)
10764          {
10765             exp.expType = MkClassType(spec.name);
10766             exp.expType.kind = subClassType;
10767             exp.byReference = true;
10768          }
10769          else
10770          {
10771             exp.expType = MkClassType("ecere::com::Class");
10772             exp.byReference = true;
10773          }
10774          break;
10775       }
10776       case classDataExp:
10777       {
10778          Class _class = thisClass ? thisClass : currentClass;
10779          if(_class)
10780          {
10781             Identifier id = exp.classData.id;
10782             char structName[1024];
10783             Expression classExp;
10784             strcpy(structName, "__ecereClassData_");
10785             FullClassNameCat(structName, _class.fullName, false);
10786             exp.type = pointerExp;
10787             exp.member.member = id;
10788             if(curCompound && FindSymbol("this", curContext, curCompound.compound.context, false, false))
10789                classExp = MkExpMember(MkExpIdentifier(MkIdentifier("this")), MkIdentifier("_class"));
10790             else
10791                classExp = MkExpIdentifier(MkIdentifier("class"));
10792
10793             exp.member.exp = MkExpBrackets(MkListOne(MkExpCast(
10794                MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)),
10795                   MkExpBrackets(MkListOne(MkExpOp(
10796                      MkExpCast(MkTypeName(MkListOne(MkSpecifier(CHAR)), MkDeclaratorPointer(MkPointer(null,null), null)),
10797                         MkExpMember(classExp, MkIdentifier("data"))), '+',
10798                            MkExpMember(MkExpClass(MkListOne(MkSpecifierName(_class.fullName)), null), MkIdentifier("offsetClass")))))
10799                      )));
10800
10801             ProcessExpressionType(exp);
10802             return;
10803          }
10804          break;
10805       }
10806       case arrayExp:
10807       {
10808          Type type = null;
10809          const char * typeString = null;
10810          char typeStringBuf[1024];
10811          if(exp.destType && exp.destType.kind == classType && exp.destType._class && exp.destType._class.registered &&
10812             exp.destType._class.registered != containerClass && eClass_IsDerived(exp.destType._class.registered, containerClass))
10813          {
10814             Class templateClass = exp.destType._class.registered;
10815             typeString = templateClass.templateArgs[2].dataTypeString;
10816          }
10817          else if(exp.list)
10818          {
10819             // Guess type from expressions in the array
10820             Expression e;
10821             for(e = exp.list->first; e; e = e.next)
10822             {
10823                ProcessExpressionType(e);
10824                if(e.expType)
10825                {
10826                   if(!type) { type = e.expType; type.refCount++; }
10827                   else
10828                   {
10829                      // if(!MatchType(e.expType, type, null, null, null, false, false, false))
10830                      if(!MatchTypeExpression(e, type, null, false, true))
10831                      {
10832                         FreeType(type);
10833                         type = e.expType;
10834                         e.expType = null;
10835
10836                         e = exp.list->first;
10837                         ProcessExpressionType(e);
10838                         if(e.expType)
10839                         {
10840                            //if(!MatchTypes(e.expType, type, null, null, null, false, false, false))
10841                            if(!MatchTypeExpression(e, type, null, false, true))
10842                            {
10843                               FreeType(e.expType);
10844                               e.expType = null;
10845                               FreeType(type);
10846                               type = null;
10847                               break;
10848                            }
10849                         }
10850                      }
10851                   }
10852                   if(e.expType)
10853                   {
10854                      FreeType(e.expType);
10855                      e.expType = null;
10856                   }
10857                }
10858             }
10859             if(type)
10860             {
10861                typeStringBuf[0] = '\0';
10862                PrintTypeNoConst(type, typeStringBuf, false, true);
10863                typeString = typeStringBuf;
10864                FreeType(type);
10865                type = null;
10866             }
10867          }
10868          if(typeString)
10869          {
10870             /*
10871             (Container)& (struct BuiltInContainer)
10872             {
10873                ._vTbl = class(BuiltInContainer)._vTbl,
10874                ._class = class(BuiltInContainer),
10875                .refCount = 0,
10876                .data = (int[]){ 1, 7, 3, 4, 5 },
10877                .count = 5,
10878                .type = class(int),
10879             }
10880             */
10881             char templateString[1024];
10882             OldList * initializers = MkList();
10883             OldList * structInitializers = MkList();
10884             OldList * specs = MkList();
10885             Expression expExt;
10886             Declarator decl = SpecDeclFromString(typeString, specs, null);
10887             sprintf(templateString, "Container<%s>", typeString);
10888
10889             if(exp.list)
10890             {
10891                Expression e;
10892                type = ProcessTypeString(typeString, false);
10893                while(e = exp.list->first)
10894                {
10895                   exp.list->Remove(e);
10896                   e.destType = type;
10897                   type.refCount++;
10898                   ProcessExpressionType(e);
10899                   ListAdd(initializers, MkInitializerAssignment(e));
10900                }
10901                FreeType(type);
10902                delete exp.list;
10903             }
10904
10905             DeclareStruct("ecere::com::BuiltInContainer", false);
10906
10907             ListAdd(structInitializers, /*MkIdentifier("_vTbl")*/    MkInitializerAssignment(MkExpMember(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null), MkIdentifier("_vTbl"))));
10908                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10909             ListAdd(structInitializers, /*MkIdentifier("_class")*/   MkInitializerAssignment(MkExpClass(MkListOne(MkSpecifierName("BuiltInContainer")), null)));
10910                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10911             ListAdd(structInitializers, /*MkIdentifier("_refCount")*/MkInitializerAssignment(MkExpConstant("0")));
10912                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10913             ListAdd(structInitializers, /*MkIdentifier("data")*/     MkInitializerAssignment(MkExpExtensionInitializer(
10914                MkTypeName(specs, MkDeclaratorArray(decl, null)),
10915                MkInitializerList(initializers))));
10916                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10917             ListAdd(structInitializers, /*MkIdentifier("count")*/    MkInitializerAssignment({ type = constantExp, constant = PrintString(initializers->count) }));
10918                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10919             ListAdd(structInitializers, /*MkIdentifier("type")*/     MkInitializerAssignment(MkExpClass(CopyList(specs, CopySpecifier), CopyDeclarator(decl))));
10920                ProcessExpressionType(((Initializer)structInitializers->last).exp);
10921             exp.expType = ProcessTypeString(templateString, false);
10922             exp.type = bracketsExp;
10923             exp.list = MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName(templateString)), null),
10924                MkExpOp(null, '&',
10925                expExt = MkExpExtensionInitializer(MkTypeName(MkListOne(MkSpecifierName("BuiltInContainer")), null),
10926                   MkInitializerList(structInitializers)))));
10927             ProcessExpressionType(expExt);
10928          }
10929          else
10930          {
10931             exp.expType = ProcessTypeString("Container", false);
10932             Compiler_Error($"Couldn't determine type of array elements\n");
10933          }
10934          break;
10935       }
10936    }
10937
10938    if(exp.expType && exp.expType.kind == thisClassType && thisClass && (!exp.destType || exp.destType.kind != thisClassType))
10939    {
10940       FreeType(exp.expType);
10941       exp.expType = ReplaceThisClassType(thisClass);
10942    }
10943
10944    // Resolve structures here
10945    if(exp.expType && (exp.expType.kind == structType || exp.expType.kind == unionType || exp.expType.kind == enumType) && !exp.expType.members.first && exp.expType.enumName)
10946    {
10947       Symbol symbol = FindSymbol(exp.expType.enumName, curContext, globalContext, true, false);
10948       // TODO: Fix members reference...
10949       if(symbol)
10950       {
10951          if(exp.expType.kind != enumType)
10952          {
10953             Type member;
10954             String enumName = CopyString(exp.expType.enumName);
10955
10956             // Fixed a memory leak on self-referencing C structs typedefs
10957             // by instantiating a new type rather than simply copying members
10958             // into exp.expType
10959             FreeType(exp.expType);
10960             exp.expType = Type { };
10961             exp.expType.kind = symbol.type.kind;
10962             exp.expType.refCount++;
10963             exp.expType.enumName = enumName;
10964
10965             exp.expType.members = symbol.type.members;
10966             for(member = symbol.type.members.first; member; member = member.next)
10967                member.refCount++;
10968          }
10969          else
10970          {
10971             NamedLink member;
10972             for(member = symbol.type.members.first; member; member = member.next)
10973             {
10974                NamedLink value { name = CopyString(member.name) };
10975                exp.expType.members.Add(value);
10976             }
10977          }
10978       }
10979    }
10980
10981    yylloc = exp.loc;
10982    if(exp.destType && (exp.destType.kind == voidType || exp.destType.kind == dummyType) );
10983    else if(exp.destType && !exp.destType.keepCast)
10984    {
10985       if(!CheckExpressionType(exp, exp.destType, false, !exp.destType.casted))
10986       {
10987          if(!exp.destType.count || unresolved)
10988          {
10989             if(!exp.expType)
10990             {
10991                yylloc = exp.loc;
10992                if(exp.destType.kind != ellipsisType)
10993                {
10994                   char type2[1024];
10995                   type2[0] = '\0';
10996                   if(inCompiler)
10997                   {
10998                      char expString[10240];
10999                      expString[0] = '\0';
11000
11001                      PrintType(exp.destType, type2, false, true);
11002
11003                      if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11004                      if(unresolved)
11005                         Compiler_Error($"unresolved identifier %s; expected %s\n", expString, type2);
11006                      else if(exp.type != dummyExp)
11007                         Compiler_Error($"couldn't determine type of %s; expected %s\n", expString, type2);
11008                   }
11009                }
11010                else
11011                {
11012                   char expString[10240] ;
11013                   expString[0] = '\0';
11014                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11015
11016                   if(unresolved)
11017                      Compiler_Error($"unresolved identifier %s\n", expString);
11018                   else if(exp.type != dummyExp)
11019                      Compiler_Error($"couldn't determine type of %s\n", expString);
11020                }
11021             }
11022             else
11023             {
11024                char type1[1024];
11025                char type2[1024];
11026                type1[0] = '\0';
11027                type2[0] = '\0';
11028                if(inCompiler)
11029                {
11030                   PrintType(exp.expType, type1, false, true);
11031                   PrintType(exp.destType, type2, false, true);
11032                }
11033
11034                //CheckExpressionType(exp, exp.destType, false);
11035
11036                if(exp.destType.truth && exp.destType._class && exp.destType._class.registered && !strcmp(exp.destType._class.registered.name, "bool") &&
11037                   exp.expType.kind != voidType && exp.expType.kind != structType && exp.expType.kind != unionType &&
11038                   (exp.expType.kind != classType || exp.expType.classObjectType || (exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type != structClass)));
11039                else
11040                {
11041                   char expString[10240];
11042                   expString[0] = '\0';
11043                   if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11044
11045 #ifdef _DEBUG
11046                   CheckExpressionType(exp, exp.destType, false, true);
11047 #endif
11048                   // Flex & Bison generate code that triggers this, so we ignore it for a quiet sdk build:
11049                   if(!sourceFile || (strcmp(sourceFile, "src\\lexer.ec") && strcmp(sourceFile, "src/lexer.ec") && strcmp(sourceFile, "src\\grammar.ec") && strcmp(sourceFile, "src/grammar.ec")))
11050                      Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
11051
11052                   // TO CHECK: FORCING HERE TO HELP DEBUGGER
11053                   FreeType(exp.expType);
11054                   exp.destType.refCount++;
11055                   exp.expType = exp.destType;
11056                }
11057             }
11058          }
11059       }
11060       else if(exp.destType && exp.destType.kind == ellipsisType && exp.expType && exp.expType.passAsTemplate)
11061       {
11062          Expression newExp { };
11063          char typeString[1024];
11064          OldList * specs = MkList();
11065          Declarator decl;
11066
11067          typeString[0] = '\0';
11068
11069          *newExp = *exp;
11070
11071          if(exp.expType)  exp.expType.refCount++;
11072          if(exp.expType)  exp.expType.refCount++;
11073          exp.type = castExp;
11074          newExp.destType = exp.expType;
11075
11076          PrintType(exp.expType, typeString, false, false);
11077          decl = SpecDeclFromString(typeString, specs, null);
11078
11079          exp.cast.typeName = MkTypeName(specs, decl);
11080          exp.cast.exp = newExp;
11081       }
11082    }
11083    else if(unresolved)
11084    {
11085       if(exp.identifier._class && exp.identifier._class.name)
11086          Compiler_Error($"unresolved identifier %s::%s\n", exp.identifier._class.name, exp.identifier.string);
11087       else if(exp.identifier.string && exp.identifier.string[0])
11088          Compiler_Error($"unresolved identifier %s\n", exp.identifier.string);
11089    }
11090    else if(!exp.expType && exp.type != dummyExp)
11091    {
11092       char expString[10240];
11093       expString[0] = '\0';
11094       if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
11095       Compiler_Error($"couldn't determine type of %s\n", expString);
11096    }
11097
11098    // Let's try to support any_object & typed_object here:
11099    if(inCompiler)
11100       ApplyAnyObjectLogic(exp);
11101
11102    // Mark nohead classes as by reference, unless we're casting them to an integral type
11103    if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
11104       exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
11105          (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
11106           exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
11107    {
11108       exp.byReference = true;
11109    }
11110    yylloc = oldyylloc;
11111 }
11112
11113 static void FindNextDataMember(Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
11114 {
11115    // THIS CODE WILL FIND NEXT MEMBER...
11116    if(*curMember)
11117    {
11118       *curMember = (*curMember).next;
11119
11120       if(subMemberStackPos && *subMemberStackPos > 0 && subMemberStack[*subMemberStackPos-1].type == unionMember)
11121       {
11122          *curMember = subMemberStack[--(*subMemberStackPos)];
11123          *curMember = (*curMember).next;
11124       }
11125
11126       // SKIP ALL PROPERTIES HERE...
11127       while((*curMember) && (*curMember).isProperty)
11128          *curMember = (*curMember).next;
11129
11130       if(subMemberStackPos)
11131       {
11132          while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
11133          {
11134             subMemberStack[(*subMemberStackPos)++] = *curMember;
11135
11136             *curMember = (*curMember).members.first;
11137             while(*curMember && (*curMember).isProperty)
11138                *curMember = (*curMember).next;
11139          }
11140       }
11141    }
11142    while(!*curMember)
11143    {
11144       if(!*curMember)
11145       {
11146          if(subMemberStackPos && *subMemberStackPos)
11147          {
11148             *curMember = subMemberStack[--(*subMemberStackPos)];
11149             *curMember = (*curMember).next;
11150          }
11151          else
11152          {
11153             Class lastCurClass = *curClass;
11154
11155             if(*curClass == _class) break;     // REACHED THE END
11156
11157             for(*curClass = _class; (*curClass).base != lastCurClass && (*curClass).base.type != systemClass; *curClass = (*curClass).base);
11158             *curMember = (*curClass).membersAndProperties.first;
11159          }
11160
11161          while((*curMember) && (*curMember).isProperty)
11162             *curMember = (*curMember).next;
11163          if(subMemberStackPos)
11164          {
11165             while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
11166             {
11167                subMemberStack[(*subMemberStackPos)++] = *curMember;
11168
11169                *curMember = (*curMember).members.first;
11170                while(*curMember && (*curMember).isProperty)
11171                   *curMember = (*curMember).next;
11172             }
11173          }
11174       }
11175    }
11176 }
11177
11178
11179 static void ProcessInitializer(Initializer init, Type type)
11180 {
11181    switch(init.type)
11182    {
11183       case expInitializer:
11184          if(!init.exp || init.exp.type != instanceExp || !init.exp.instance || init.exp.instance._class || !type || type.kind == classType)
11185          {
11186             // TESTING THIS FOR SHUTTING = 0 WARNING
11187             if(init.exp && !init.exp.destType)
11188             {
11189                FreeType(init.exp.destType);
11190                init.exp.destType = type;
11191                if(type) type.refCount++;
11192             }
11193             if(init.exp)
11194             {
11195                ProcessExpressionType(init.exp);
11196                init.isConstant = init.exp.isConstant;
11197             }
11198             break;
11199          }
11200          else
11201          {
11202             Expression exp = init.exp;
11203             Instantiation inst = exp.instance;
11204             MembersInit members;
11205
11206             init.type = listInitializer;
11207             init.list = MkList();
11208
11209             if(inst.members)
11210             {
11211                for(members = inst.members->first; members; members = members.next)
11212                {
11213                   if(members.type == dataMembersInit)
11214                   {
11215                      MemberInit member;
11216                      for(member = members.dataMembers->first; member; member = member.next)
11217                      {
11218                         ListAdd(init.list, member.initializer);
11219                         member.initializer = null;
11220                      }
11221                   }
11222                   // Discard all MembersInitMethod
11223                }
11224             }
11225             FreeExpression(exp);
11226          }
11227       case listInitializer:
11228       {
11229          Initializer i;
11230          Type initializerType = null;
11231          Class curClass = null;
11232          DataMember curMember = null;
11233          DataMember subMemberStack[256];
11234          int subMemberStackPos = 0;
11235
11236          if(type && type.kind == arrayType)
11237             initializerType = Dereference(type);
11238          else if(type && (type.kind == structType || type.kind == unionType))
11239             initializerType = type.members.first;
11240
11241          for(i = init.list->first; i; i = i.next)
11242          {
11243             if(type && type.kind == classType && type._class && type._class.registered)
11244             {
11245                // 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)
11246                FindNextDataMember(type._class.registered, &curClass, &curMember, subMemberStack, &subMemberStackPos);
11247                // TODO: Generate error on initializing a private data member this way from another module...
11248                if(curMember)
11249                {
11250                   if(!curMember.dataType)
11251                      curMember.dataType = ProcessTypeString(curMember.dataTypeString, false);
11252                   initializerType = curMember.dataType;
11253                }
11254             }
11255             ProcessInitializer(i, initializerType);
11256             if(initializerType && type && (type.kind == structType || type.kind == unionType))
11257                initializerType = initializerType.next;
11258             if(!i.isConstant)
11259                init.isConstant = false;
11260          }
11261
11262          if(type && type.kind == arrayType)
11263             FreeType(initializerType);
11264
11265          if(type && type.kind != arrayType && type.kind != structType && type.kind != unionType && (type.kind != classType || !type._class.registered || type._class.registered.type != structClass))
11266          {
11267             Compiler_Error($"Assigning list initializer to non list\n");
11268          }
11269          break;
11270       }
11271    }
11272 }
11273
11274 static void ProcessSpecifier(Specifier spec, bool declareStruct)
11275 {
11276    switch(spec.type)
11277    {
11278       case baseSpecifier:
11279       {
11280          if(spec.specifier == THISCLASS)
11281          {
11282             if(thisClass)
11283             {
11284                spec.type = nameSpecifier;
11285                spec.name = ReplaceThisClass(thisClass);
11286                spec.symbol = FindClass(spec.name);
11287                ProcessSpecifier(spec, declareStruct);
11288             }
11289          }
11290          break;
11291       }
11292       case nameSpecifier:
11293       {
11294          Symbol symbol = FindType(curContext, spec.name);
11295          if(symbol)
11296             DeclareType(symbol.type, true, true);
11297          else if((symbol = spec.symbol /*FindClass(spec.name)*/) && symbol.registered && symbol.registered.type == structClass && declareStruct)
11298             DeclareStruct(spec.name, false);
11299          break;
11300       }
11301       case enumSpecifier:
11302       {
11303          Enumerator e;
11304          if(spec.list)
11305          {
11306             for(e = spec.list->first; e; e = e.next)
11307             {
11308                if(e.exp)
11309                   ProcessExpressionType(e.exp);
11310             }
11311          }
11312          break;
11313       }
11314       case structSpecifier:
11315       case unionSpecifier:
11316       {
11317          if(spec.definitions)
11318          {
11319             ClassDef def;
11320             Symbol symbol = spec.id ? FindClass(spec.id.string) : null;
11321             //if(symbol)
11322                ProcessClass(spec.definitions, symbol);
11323             /*else
11324             {
11325                for(def = spec.definitions->first; def; def = def.next)
11326                {
11327                   //if(def.type == declarationClassDef && def.decl && def.decl.type == DeclarationStruct)
11328                      ProcessDeclaration(def.decl);
11329                }
11330             }*/
11331          }
11332          break;
11333       }
11334       /*
11335       case classSpecifier:
11336       {
11337          Symbol classSym = FindClass(spec.name);
11338          if(classSym && classSym.registered && classSym.registered.type == structClass)
11339             DeclareStruct(spec.name, false);
11340          break;
11341       }
11342       */
11343    }
11344 }
11345
11346
11347 static void ProcessDeclarator(Declarator decl)
11348 {
11349    switch(decl.type)
11350    {
11351       case identifierDeclarator:
11352          if(decl.identifier.classSym /* TODO: Name Space Fix ups  || decl.identifier.nameSpace*/)
11353          {
11354             FreeSpecifier(decl.identifier._class);
11355             decl.identifier._class = null;
11356          }
11357          break;
11358       case arrayDeclarator:
11359          if(decl.array.exp)
11360             ProcessExpressionType(decl.array.exp);
11361       case structDeclarator:
11362       case bracketsDeclarator:
11363       case functionDeclarator:
11364       case pointerDeclarator:
11365       case extendedDeclarator:
11366       case extendedDeclaratorEnd:
11367          if(decl.declarator)
11368             ProcessDeclarator(decl.declarator);
11369          if(decl.type == functionDeclarator)
11370          {
11371             Identifier id = GetDeclId(decl);
11372             if(id && id._class)
11373             {
11374                TypeName param
11375                {
11376                   qualifiers = MkListOne(id._class);
11377                   declarator = null;
11378                };
11379                if(!decl.function.parameters)
11380                   decl.function.parameters = MkList();
11381                decl.function.parameters->Insert(null, param);
11382                id._class = null;
11383             }
11384             if(decl.function.parameters)
11385             {
11386                TypeName param;
11387
11388                for(param = decl.function.parameters->first; param; param = param.next)
11389                {
11390                   if(param.qualifiers && param.qualifiers->first)
11391                   {
11392                      Specifier spec = param.qualifiers->first;
11393                      if(spec && spec.specifier == TYPED_OBJECT)
11394                      {
11395                         Declarator d = param.declarator;
11396                         TypeName newParam
11397                         {
11398                            qualifiers = MkListOne(MkSpecifier(VOID));
11399                            declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11400                         };
11401                         if(d.type != pointerDeclarator)
11402                            newParam.qualifiers->Insert(null, MkSpecifier(CONST));
11403
11404                         FreeList(param.qualifiers, FreeSpecifier);
11405
11406                         param.qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
11407                         param.declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
11408
11409                         decl.function.parameters->Insert(param, newParam);
11410                         param = newParam;
11411                      }
11412                      else if(spec && spec.specifier == ANY_OBJECT)
11413                      {
11414                         Declarator d = param.declarator;
11415
11416                         FreeList(param.qualifiers, FreeSpecifier);
11417
11418                         param.qualifiers = MkListOne(MkSpecifier(VOID));
11419                         if(d.type != pointerDeclarator)
11420                            param.qualifiers->Insert(null, MkSpecifier(CONST));
11421                         param.declarator = MkDeclaratorPointer(MkPointer(null,null), d);
11422                      }
11423                      else if(spec.specifier == THISCLASS)
11424                      {
11425                         if(thisClass)
11426                         {
11427                            spec.type = nameSpecifier;
11428                            spec.name = ReplaceThisClass(thisClass);
11429                            spec.symbol = FindClass(spec.name);
11430                            ProcessSpecifier(spec, false);
11431                         }
11432                      }
11433                   }
11434
11435                   if(param.declarator)
11436                      ProcessDeclarator(param.declarator);
11437                }
11438             }
11439          }
11440          break;
11441    }
11442 }
11443
11444 static void ProcessDeclaration(Declaration decl)
11445 {
11446    yylloc = decl.loc;
11447    switch(decl.type)
11448    {
11449       case initDeclaration:
11450       {
11451          bool declareStruct = false;
11452          /*
11453          lineNum = decl.pos.line;
11454          column = decl.pos.col;
11455          */
11456
11457          if(decl.declarators)
11458          {
11459             InitDeclarator d;
11460
11461             for(d = decl.declarators->first; d; d = d.next)
11462             {
11463                Type type, subType;
11464                ProcessDeclarator(d.declarator);
11465
11466                type = ProcessType(decl.specifiers, d.declarator);
11467
11468                if(d.initializer)
11469                {
11470                   ProcessInitializer(d.initializer, type);
11471
11472                   // Change "ColorRGB a = ColorRGB { 1,2,3 } => ColorRGB a { 1,2,3 }
11473
11474                   if(decl.declarators->count == 1 && d.initializer.type == expInitializer &&
11475                      d.initializer.exp.type == instanceExp)
11476                   {
11477                      if(type.kind == classType && type._class ==
11478                         d.initializer.exp.expType._class)
11479                      {
11480                         Instantiation inst = d.initializer.exp.instance;
11481                         inst.exp = MkExpIdentifier(CopyIdentifier(GetDeclId(d.declarator)));
11482
11483                         d.initializer.exp.instance = null;
11484                         if(decl.specifiers)
11485                            FreeList(decl.specifiers, FreeSpecifier);
11486                         FreeList(decl.declarators, FreeInitDeclarator);
11487
11488                         d = null;
11489
11490                         decl.type = instDeclaration;
11491                         decl.inst = inst;
11492                      }
11493                   }
11494                }
11495                for(subType = type; subType;)
11496                {
11497                   if(subType.kind == classType)
11498                   {
11499                      declareStruct = true;
11500                      break;
11501                   }
11502                   else if(subType.kind == pointerType)
11503                      break;
11504                   else if(subType.kind == arrayType)
11505                      subType = subType.arrayType;
11506                   else
11507                      break;
11508                }
11509
11510                FreeType(type);
11511                if(!d) break;
11512             }
11513          }
11514
11515          if(decl.specifiers)
11516          {
11517             Specifier s;
11518             for(s = decl.specifiers->first; s; s = s.next)
11519             {
11520                ProcessSpecifier(s, declareStruct);
11521             }
11522          }
11523          break;
11524       }
11525       case instDeclaration:
11526       {
11527          ProcessInstantiationType(decl.inst);
11528          break;
11529       }
11530       case structDeclaration:
11531       {
11532          Specifier spec;
11533          Declarator d;
11534          bool declareStruct = false;
11535
11536          if(decl.declarators)
11537          {
11538             for(d = decl.declarators->first; d; d = d.next)
11539             {
11540                Type type = ProcessType(decl.specifiers, d.declarator);
11541                Type subType;
11542                ProcessDeclarator(d);
11543                for(subType = type; subType;)
11544                {
11545                   if(subType.kind == classType)
11546                   {
11547                      declareStruct = true;
11548                      break;
11549                   }
11550                   else if(subType.kind == pointerType)
11551                      break;
11552                   else if(subType.kind == arrayType)
11553                      subType = subType.arrayType;
11554                   else
11555                      break;
11556                }
11557                FreeType(type);
11558             }
11559          }
11560          if(decl.specifiers)
11561          {
11562             for(spec = decl.specifiers->first; spec; spec = spec.next)
11563                ProcessSpecifier(spec, declareStruct);
11564          }
11565          break;
11566       }
11567    }
11568 }
11569
11570 static FunctionDefinition curFunction;
11571
11572 static void CreateFireWatcher(Property prop, Expression object, Statement stmt)
11573 {
11574    char propName[1024], propNameM[1024];
11575    char getName[1024], setName[1024];
11576    OldList * args;
11577
11578    DeclareProperty(prop, setName, getName);
11579
11580    // eInstance_FireWatchers(object, prop);
11581    strcpy(propName, "__ecereProp_");
11582    FullClassNameCat(propName, prop._class.fullName, false);
11583    strcat(propName, "_");
11584    // strcat(propName, prop.name);
11585    FullClassNameCat(propName, prop.name, true);
11586    MangleClassName(propName);
11587
11588    strcpy(propNameM, "__ecerePropM_");
11589    FullClassNameCat(propNameM, prop._class.fullName, false);
11590    strcat(propNameM, "_");
11591    // strcat(propNameM, prop.name);
11592    FullClassNameCat(propNameM, prop.name, true);
11593    MangleClassName(propNameM);
11594
11595    if(prop.isWatchable)
11596    {
11597       args = MkList();
11598       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11599       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11600       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11601
11602       args = MkList();
11603       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11604       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11605       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireWatchers")), args));
11606    }
11607
11608
11609    {
11610       args = MkList();
11611       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11612       ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
11613       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11614
11615       args = MkList();
11616       ListAdd(args, object ? CopyExpression(object) : MkExpIdentifier(MkIdentifier("this")));
11617       ListAdd(args, MkExpIdentifier(MkIdentifier(propNameM)));
11618       ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_FireSelfWatchers")), args));
11619    }
11620
11621    if(curFunction.propSet && !strcmp(curFunction.propSet.string, prop.name) &&
11622       (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
11623       curFunction.propSet.fireWatchersDone = true;
11624 }
11625
11626 static void ProcessStatement(Statement stmt)
11627 {
11628    yylloc = stmt.loc;
11629    /*
11630    lineNum = stmt.pos.line;
11631    column = stmt.pos.col;
11632    */
11633    switch(stmt.type)
11634    {
11635       case labeledStmt:
11636          ProcessStatement(stmt.labeled.stmt);
11637          break;
11638       case caseStmt:
11639          // This expression should be constant...
11640          if(stmt.caseStmt.exp)
11641          {
11642             FreeType(stmt.caseStmt.exp.destType);
11643             stmt.caseStmt.exp.destType = curSwitchType;
11644             if(curSwitchType) curSwitchType.refCount++;
11645             ProcessExpressionType(stmt.caseStmt.exp);
11646             ComputeExpression(stmt.caseStmt.exp);
11647          }
11648          if(stmt.caseStmt.stmt)
11649             ProcessStatement(stmt.caseStmt.stmt);
11650          break;
11651       case compoundStmt:
11652       {
11653          if(stmt.compound.context)
11654          {
11655             Declaration decl;
11656             Statement s;
11657
11658             Statement prevCompound = curCompound;
11659             Context prevContext = curContext;
11660
11661             if(!stmt.compound.isSwitch)
11662                curCompound = stmt;
11663             curContext = stmt.compound.context;
11664
11665             if(stmt.compound.declarations)
11666             {
11667                for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
11668                   ProcessDeclaration(decl);
11669             }
11670             if(stmt.compound.statements)
11671             {
11672                for(s = stmt.compound.statements->first; s; s = s.next)
11673                   ProcessStatement(s);
11674             }
11675
11676             curContext = prevContext;
11677             curCompound = prevCompound;
11678          }
11679          break;
11680       }
11681       case expressionStmt:
11682       {
11683          Expression exp;
11684          if(stmt.expressions)
11685          {
11686             for(exp = stmt.expressions->first; exp; exp = exp.next)
11687                ProcessExpressionType(exp);
11688          }
11689          break;
11690       }
11691       case ifStmt:
11692       {
11693          Expression exp;
11694
11695          FreeType(((Expression)stmt.ifStmt.exp->last).destType);
11696          ((Expression)stmt.ifStmt.exp->last).destType = MkClassType("bool");
11697          ((Expression)stmt.ifStmt.exp->last).destType.truth = true;
11698          for(exp = stmt.ifStmt.exp->first; exp; exp = exp.next)
11699          {
11700             ProcessExpressionType(exp);
11701          }
11702          if(stmt.ifStmt.stmt)
11703             ProcessStatement(stmt.ifStmt.stmt);
11704          if(stmt.ifStmt.elseStmt)
11705             ProcessStatement(stmt.ifStmt.elseStmt);
11706          break;
11707       }
11708       case switchStmt:
11709       {
11710          Type oldSwitchType = curSwitchType;
11711          if(stmt.switchStmt.exp)
11712          {
11713             Expression exp;
11714             for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
11715             {
11716                if(!exp.next)
11717                {
11718                   /*
11719                   Type destType
11720                   {
11721                      kind = intType;
11722                      refCount = 1;
11723                   };
11724                   e.exp.destType = destType;
11725                   */
11726
11727                   ProcessExpressionType(exp);
11728                }
11729                if(!exp.next)
11730                   curSwitchType = exp.expType;
11731             }
11732          }
11733          ProcessStatement(stmt.switchStmt.stmt);
11734          curSwitchType = oldSwitchType;
11735          break;
11736       }
11737       case whileStmt:
11738       {
11739          if(stmt.whileStmt.exp)
11740          {
11741             Expression exp;
11742
11743             FreeType(((Expression)stmt.whileStmt.exp->last).destType);
11744             ((Expression)stmt.whileStmt.exp->last).destType = MkClassType("bool");
11745             ((Expression)stmt.whileStmt.exp->last).destType.truth = true;
11746             for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
11747             {
11748                ProcessExpressionType(exp);
11749             }
11750          }
11751          if(stmt.whileStmt.stmt)
11752             ProcessStatement(stmt.whileStmt.stmt);
11753          break;
11754       }
11755       case doWhileStmt:
11756       {
11757          if(stmt.doWhile.exp)
11758          {
11759             Expression exp;
11760
11761             if(stmt.doWhile.exp->last)
11762             {
11763                FreeType(((Expression)stmt.doWhile.exp->last).destType);
11764                ((Expression)stmt.doWhile.exp->last).destType = MkClassType("bool");
11765                ((Expression)stmt.doWhile.exp->last).destType.truth = true;
11766             }
11767             for(exp = stmt.doWhile.exp->first; exp; exp = exp.next)
11768             {
11769                ProcessExpressionType(exp);
11770             }
11771          }
11772          if(stmt.doWhile.stmt)
11773             ProcessStatement(stmt.doWhile.stmt);
11774          break;
11775       }
11776       case forStmt:
11777       {
11778          Expression exp;
11779          if(stmt.forStmt.init)
11780             ProcessStatement(stmt.forStmt.init);
11781
11782          if(stmt.forStmt.check && stmt.forStmt.check.expressions)
11783          {
11784             FreeType(((Expression)stmt.forStmt.check.expressions->last).destType);
11785             ((Expression)stmt.forStmt.check.expressions->last).destType = MkClassType("bool");
11786             ((Expression)stmt.forStmt.check.expressions->last).destType.truth = true;
11787          }
11788
11789          if(stmt.forStmt.check)
11790             ProcessStatement(stmt.forStmt.check);
11791          if(stmt.forStmt.increment)
11792          {
11793             for(exp = stmt.forStmt.increment->first; exp; exp = exp.next)
11794                ProcessExpressionType(exp);
11795          }
11796
11797          if(stmt.forStmt.stmt)
11798             ProcessStatement(stmt.forStmt.stmt);
11799          break;
11800       }
11801       case forEachStmt:
11802       {
11803          Identifier id = stmt.forEachStmt.id;
11804          OldList * exp = stmt.forEachStmt.exp;
11805          OldList * filter = stmt.forEachStmt.filter;
11806          Statement block = stmt.forEachStmt.stmt;
11807          char iteratorType[1024];
11808          Type source;
11809          Expression e;
11810          bool isBuiltin = exp && exp->last &&
11811             (((Expression)exp->last).type == ExpressionType::arrayExp ||
11812               (((Expression)exp->last).type == castExp && ((Expression)exp->last).cast.exp.type == ExpressionType::arrayExp));
11813          Expression arrayExp;
11814          const char * typeString = null;
11815          int builtinCount = 0;
11816
11817          for(e = exp ? exp->first : null; e; e = e.next)
11818          {
11819             if(!e.next)
11820             {
11821                FreeType(e.destType);
11822                e.destType = ProcessTypeString("Container", false);
11823             }
11824             if(!isBuiltin || e.next)
11825                ProcessExpressionType(e);
11826          }
11827
11828          source = (exp && exp->last) ? ((Expression)exp->last).expType : null;
11829          if(isBuiltin || (source && source.kind == classType && source._class && source._class.registered && source._class.registered != containerClass &&
11830             eClass_IsDerived(source._class.registered, containerClass)))
11831          {
11832             Class _class = source ? source._class.registered : null;
11833             Symbol symbol;
11834             Expression expIt = null;
11835             bool isMap = false, isArray = false, isLinkList = false, isList = false, isCustomAVLTree = false; //, isAVLTree = false;
11836             Class arrayClass = eSystem_FindClass(privateModule, "Array");
11837             Class linkListClass = eSystem_FindClass(privateModule, "LinkList");
11838             Class customAVLTreeClass = eSystem_FindClass(privateModule, "CustomAVLTree");
11839             stmt.type = compoundStmt;
11840
11841             stmt.compound.context = Context { };
11842             stmt.compound.context.parent = curContext;
11843             curContext = stmt.compound.context;
11844
11845             if(source && eClass_IsDerived(source._class.registered, customAVLTreeClass))
11846             {
11847                Class mapClass = eSystem_FindClass(privateModule, "Map");
11848                //Class avlTreeClass = eSystem_FindClass(privateModule, "AVLTree");
11849                isCustomAVLTree = true;
11850                /*if(eClass_IsDerived(source._class.registered, avlTreeClass))
11851                   isAVLTree = true;
11852                else */if(eClass_IsDerived(source._class.registered, mapClass))
11853                   isMap = true;
11854             }
11855             else if(source && eClass_IsDerived(source._class.registered, arrayClass)) isArray = true;
11856             else if(source && eClass_IsDerived(source._class.registered, linkListClass))
11857             {
11858                Class listClass = eSystem_FindClass(privateModule, "List");
11859                isLinkList = true;
11860                isList = eClass_IsDerived(source._class.registered, listClass);
11861             }
11862
11863             if(isArray)
11864             {
11865                Declarator decl;
11866                OldList * specs = MkList();
11867                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
11868                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
11869                stmt.compound.declarations = MkListOne(
11870                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11871                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
11872                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalArray")),
11873                      MkInitializerAssignment(MkExpBrackets(exp))))));
11874             }
11875             else if(isBuiltin)
11876             {
11877                Type type = null;
11878                char typeStringBuf[1024];
11879
11880                // TODO: Merge this code?
11881                arrayExp = (((Expression)exp->last).type == ExpressionType::arrayExp) ? (Expression)exp->last : ((Expression)exp->last).cast.exp;
11882                if(((Expression)exp->last).type == castExp)
11883                {
11884                   TypeName typeName = ((Expression)exp->last).cast.typeName;
11885                   if(typeName)
11886                      arrayExp.destType = ProcessType(typeName.qualifiers, typeName.declarator);
11887                }
11888
11889                if(arrayExp.destType && arrayExp.destType.kind == classType && arrayExp.destType._class && arrayExp.destType._class.registered &&
11890                   arrayExp.destType._class.registered != containerClass && eClass_IsDerived(arrayExp.destType._class.registered, containerClass) &&
11891                   arrayExp.destType._class.registered.templateArgs)
11892                {
11893                   Class templateClass = arrayExp.destType._class.registered;
11894                   typeString = templateClass.templateArgs[2].dataTypeString;
11895                }
11896                else if(arrayExp.list)
11897                {
11898                   // Guess type from expressions in the array
11899                   Expression e;
11900                   for(e = arrayExp.list->first; e; e = e.next)
11901                   {
11902                      ProcessExpressionType(e);
11903                      if(e.expType)
11904                      {
11905                         if(!type) { type = e.expType; type.refCount++; }
11906                         else
11907                         {
11908                            // if(!MatchType(e.expType, type, null, null, null, false, false, false))
11909                            if(!MatchTypeExpression(e, type, null, false, true))
11910                            {
11911                               FreeType(type);
11912                               type = e.expType;
11913                               e.expType = null;
11914
11915                               e = arrayExp.list->first;
11916                               ProcessExpressionType(e);
11917                               if(e.expType)
11918                               {
11919                                  //if(!MatchTypes(e.expType, type, null, null, null, false, false, false, false))
11920                                  if(!MatchTypeExpression(e, type, null, false, true))
11921                                  {
11922                                     FreeType(e.expType);
11923                                     e.expType = null;
11924                                     FreeType(type);
11925                                     type = null;
11926                                     break;
11927                                  }
11928                               }
11929                            }
11930                         }
11931                         if(e.expType)
11932                         {
11933                            FreeType(e.expType);
11934                            e.expType = null;
11935                         }
11936                      }
11937                   }
11938                   if(type)
11939                   {
11940                      typeStringBuf[0] = '\0';
11941                      PrintType(type, typeStringBuf, false, true);
11942                      typeString = typeStringBuf;
11943                      FreeType(type);
11944                   }
11945                }
11946                if(typeString)
11947                {
11948                   OldList * initializers = MkList();
11949                   Declarator decl;
11950                   OldList * specs = MkList();
11951                   if(arrayExp.list)
11952                   {
11953                      Expression e;
11954
11955                      builtinCount = arrayExp.list->count;
11956                      type = ProcessTypeString(typeString, false);
11957                      while(e = arrayExp.list->first)
11958                      {
11959                         arrayExp.list->Remove(e);
11960                         e.destType = type;
11961                         type.refCount++;
11962                         ProcessExpressionType(e);
11963                         ListAdd(initializers, MkInitializerAssignment(e));
11964                      }
11965                      FreeType(type);
11966                      delete arrayExp.list;
11967                   }
11968                   decl = SpecDeclFromString(typeString, specs, MkDeclaratorIdentifier(id));
11969                   stmt.compound.declarations = MkListOne(MkDeclaration(CopyList(specs, CopySpecifier),
11970                      MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), /*CopyDeclarator(*/decl/*)*/), null))));
11971
11972                   ListAdd(stmt.compound.declarations, MkDeclaration(specs, MkListOne(MkInitDeclarator(
11973                      PlugDeclarator(
11974                         /*CopyDeclarator(*/decl/*)*/, MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("__internalArray")), null)
11975                         ), MkInitializerList(initializers)))));
11976                   FreeList(exp, FreeExpression);
11977                }
11978                else
11979                {
11980                   arrayExp.expType = ProcessTypeString("Container", false);
11981                   Compiler_Error($"Couldn't determine type of array elements\n");
11982                }
11983
11984                /*
11985                Declarator decl;
11986                OldList * specs = MkList();
11987
11988                decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs,
11989                   MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(id)));
11990                stmt.compound.declarations = MkListOne(
11991                   MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
11992                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName("BuiltInContainer")),
11993                   MkListOne(MkInitDeclarator(MkDeclaratorPointer(MkPointer(null, null), MkDeclaratorIdentifier(MkIdentifier("__internalArray"))),
11994                      MkInitializerAssignment(MkExpBrackets(exp))))));
11995                */
11996             }
11997             else if(isLinkList && !isList)
11998             {
11999                Declarator decl;
12000                OldList * specs = MkList();
12001                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
12002                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12003                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12004                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalLinkList")),
12005                      MkInitializerAssignment(MkExpBrackets(exp))))));
12006             }
12007             /*else if(isCustomAVLTree)
12008             {
12009                Declarator decl;
12010                OldList * specs = MkList();
12011                decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, MkDeclaratorIdentifier(id));
12012                stmt.compound.declarations = MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(decl, null))));
12013                ListAdd(stmt.compound.declarations, MkDeclaration(MkListOne(MkSpecifierName(source._class.registered.fullName)),
12014                   MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internalTree")),
12015                      MkInitializerAssignment(MkExpBrackets(exp))))));
12016             }*/
12017             else if(_class.templateArgs)
12018             {
12019                if(isMap)
12020                   sprintf(iteratorType, "MapIterator<%s, %s >", _class.templateArgs[5].dataTypeString, _class.templateArgs[6].dataTypeString);
12021                else
12022                   sprintf(iteratorType, "Iterator<%s, %s >", _class.templateArgs[2].dataTypeString, _class.templateArgs[1].dataTypeString);
12023
12024                stmt.compound.declarations = MkListOne(
12025                   MkDeclarationInst(MkInstantiationNamed(MkListOne(MkSpecifierName(iteratorType)),
12026                   MkExpIdentifier(id), MkListOne(MkMembersInitList(MkListOne(MkMemberInit(isMap ? MkListOne(MkIdentifier("map")) : null,
12027                   MkInitializerAssignment(MkExpBrackets(exp)))))))));
12028             }
12029             symbol = FindSymbol(id.string, curContext, curContext, false, false);
12030
12031             if(block)
12032             {
12033                // Reparent sub-contexts in this statement
12034                switch(block.type)
12035                {
12036                   case compoundStmt:
12037                      if(block.compound.context)
12038                         block.compound.context.parent = stmt.compound.context;
12039                      break;
12040                   case ifStmt:
12041                      if(block.ifStmt.stmt && block.ifStmt.stmt.type == compoundStmt && block.ifStmt.stmt.compound.context)
12042                         block.ifStmt.stmt.compound.context.parent = stmt.compound.context;
12043                      if(block.ifStmt.elseStmt && block.ifStmt.elseStmt.type == compoundStmt && block.ifStmt.elseStmt.compound.context)
12044                         block.ifStmt.elseStmt.compound.context.parent = stmt.compound.context;
12045                      break;
12046                   case switchStmt:
12047                      if(block.switchStmt.stmt && block.switchStmt.stmt.type == compoundStmt && block.switchStmt.stmt.compound.context)
12048                         block.switchStmt.stmt.compound.context.parent = stmt.compound.context;
12049                      break;
12050                   case whileStmt:
12051                      if(block.whileStmt.stmt && block.whileStmt.stmt.type == compoundStmt && block.whileStmt.stmt.compound.context)
12052                         block.whileStmt.stmt.compound.context.parent = stmt.compound.context;
12053                      break;
12054                   case doWhileStmt:
12055                      if(block.doWhile.stmt && block.doWhile.stmt.type == compoundStmt && block.doWhile.stmt.compound.context)
12056                         block.doWhile.stmt.compound.context.parent = stmt.compound.context;
12057                      break;
12058                   case forStmt:
12059                      if(block.forStmt.stmt && block.forStmt.stmt.type == compoundStmt && block.forStmt.stmt.compound.context)
12060                         block.forStmt.stmt.compound.context.parent = stmt.compound.context;
12061                      break;
12062                   case forEachStmt:
12063                      if(block.forEachStmt.stmt && block.forEachStmt.stmt.type == compoundStmt && block.forEachStmt.stmt.compound.context)
12064                         block.forEachStmt.stmt.compound.context.parent = stmt.compound.context;
12065                      break;
12066                   /* Only handle those with compound blocks for now... (Potential limitation on compound statements within expressions)
12067                   case labeledStmt:
12068                   case caseStmt
12069                   case expressionStmt:
12070                   case gotoStmt:
12071                   case continueStmt:
12072                   case breakStmt
12073                   case returnStmt:
12074                   case asmStmt:
12075                   case badDeclarationStmt:
12076                   case fireWatchersStmt:
12077                   case stopWatchingStmt:
12078                   case watchStmt:
12079                   */
12080                }
12081             }
12082             if(filter)
12083             {
12084                block = MkIfStmt(filter, block, null);
12085             }
12086             if(isArray)
12087             {
12088                stmt.compound.statements = MkListOne(MkForStmt(
12089                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array"))))),
12090                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12091                      MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("array")), '+', MkExpMember(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
12092                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12093                   block));
12094               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12095               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12096               ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12097             }
12098             else if(isBuiltin)
12099             {
12100                char count[128];
12101                //OldList * specs = MkList();
12102                // Declarator decl = SpecDeclFromString(typeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
12103
12104                sprintf(count, "%d", builtinCount);
12105
12106                stmt.compound.statements = MkListOne(MkForStmt(
12107                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpIdentifier(MkIdentifier("__internalArray"))))),
12108                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12109                      MkExpOp(MkExpIdentifier(MkIdentifier("__internalArray")), '+', MkExpConstant(count))))),
12110                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12111                   block));
12112
12113                /*
12114                Declarator decl = SpecDeclFromString(_class.templateArgs[2].dataTypeString, specs, MkDeclaratorPointer(MkPointer(null, null), null));
12115                stmt.compound.statements = MkListOne(MkForStmt(
12116                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))))),
12117                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '<',
12118                      MkExpOp(MkExpCast(MkTypeName(specs, decl), MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("data"))), '+', MkExpPointer(MkExpIdentifier(MkIdentifier("__internalArray")), MkIdentifier("count")))))),
12119                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), INC_OP, null)),
12120                   block));
12121               */
12122               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12123               ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12124               ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12125             }
12126             else if(isLinkList && !isList)
12127             {
12128                Class typeClass = eSystem_FindClass(_class.module, _class.templateArgs[3].dataTypeString);
12129                Class listItemClass = eSystem_FindClass(_class.module, "ListItem");
12130                if(typeClass && eClass_IsDerived(typeClass, listItemClass) && _class.templateArgs[5].dataTypeString &&
12131                   !strcmp(_class.templateArgs[5].dataTypeString, "LT::link"))
12132                {
12133                   stmt.compound.statements = MkListOne(MkForStmt(
12134                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
12135                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12136                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
12137                      block));
12138                }
12139                else
12140                {
12141                   OldList * specs = MkList();
12142                   Declarator decl = SpecDeclFromString(_class.templateArgs[3].dataTypeString, specs, null);
12143                   stmt.compound.statements = MkListOne(MkForStmt(
12144                      MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("first"))))),
12145                      MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12146                      MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpCast(MkTypeName(specs, decl), MkExpCall(
12147                         MkExpMember(MkExpIdentifier(MkIdentifier("__internalLinkList")), MkIdentifier("GetNext")),
12148                            MkListOne(MkExpCast(MkTypeName(MkListOne(MkSpecifierName("IteratorPointer")), null), MkExpIdentifier(CopyIdentifier(id)))))))),
12149                      block));
12150                }
12151                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12152                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12153                ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12154             }
12155             /*else if(isCustomAVLTree)
12156             {
12157                stmt.compound.statements = MkListOne(MkForStmt(
12158                   MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpMember(MkExpIdentifier(
12159                      MkIdentifier("__internalTree")), MkIdentifier("root")), MkIdentifier("minimum"))))),
12160                   MkExpressionStmt(MkListOne(MkExpIdentifier(CopyIdentifier(id)))),
12161                   MkListOne(MkExpOp(MkExpIdentifier(CopyIdentifier(id)), '=', MkExpMember(MkExpIdentifier(CopyIdentifier(id)), MkIdentifier("next")))),
12162                   block));
12163
12164                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.init);
12165                ProcessStatement(((Statement)stmt.compound.statements->first).forStmt.check);
12166                ProcessExpressionType(((Statement)stmt.compound.statements->first).forStmt.increment->first);
12167             }*/
12168             else
12169             {
12170                stmt.compound.statements = MkListOne(MkWhileStmt(MkListOne(MkExpCall(MkExpMember(expIt = MkExpIdentifier(CopyIdentifier(id)),
12171                   MkIdentifier("Next")), null)), block));
12172             }
12173             ProcessExpressionType(expIt);
12174             if(stmt.compound.declarations->first)
12175                ProcessDeclaration(stmt.compound.declarations->first);
12176
12177             if(symbol)
12178                symbol.isIterator = isMap ? 2 : ((isArray || isBuiltin) ? 3 : (isLinkList ? (isList ? 5 : 4) : (isCustomAVLTree ? 6 : 1)));
12179
12180             ProcessStatement(stmt);
12181             curContext = stmt.compound.context.parent;
12182             break;
12183          }
12184          else
12185          {
12186             Compiler_Error($"Expression is not a container\n");
12187          }
12188          break;
12189       }
12190       case gotoStmt:
12191          break;
12192       case continueStmt:
12193          break;
12194       case breakStmt:
12195          break;
12196       case returnStmt:
12197       {
12198          Expression exp;
12199          if(stmt.expressions)
12200          {
12201             for(exp = stmt.expressions->first; exp; exp = exp.next)
12202             {
12203                if(!exp.next)
12204                {
12205                   if(curFunction && !curFunction.type)
12206                      curFunction.type = ProcessType(
12207                         curFunction.specifiers, curFunction.declarator);
12208                   FreeType(exp.destType);
12209                   exp.destType = (curFunction && curFunction.type && curFunction.type.kind == functionType) ? curFunction.type.returnType : null;
12210                   if(exp.destType) exp.destType.refCount++;
12211                }
12212                ProcessExpressionType(exp);
12213             }
12214          }
12215          break;
12216       }
12217       case badDeclarationStmt:
12218       {
12219          ProcessDeclaration(stmt.decl);
12220          break;
12221       }
12222       case asmStmt:
12223       {
12224          AsmField field;
12225          if(stmt.asmStmt.inputFields)
12226          {
12227             for(field = stmt.asmStmt.inputFields->first; field; field = field.next)
12228                if(field.expression)
12229                   ProcessExpressionType(field.expression);
12230          }
12231          if(stmt.asmStmt.outputFields)
12232          {
12233             for(field = stmt.asmStmt.outputFields->first; field; field = field.next)
12234                if(field.expression)
12235                   ProcessExpressionType(field.expression);
12236          }
12237          if(stmt.asmStmt.clobberedFields)
12238          {
12239             for(field = stmt.asmStmt.clobberedFields->first; field; field = field.next)
12240             {
12241                if(field.expression)
12242                   ProcessExpressionType(field.expression);
12243             }
12244          }
12245          break;
12246       }
12247       case watchStmt:
12248       {
12249          PropertyWatch propWatch;
12250          OldList * watches = stmt._watch.watches;
12251          Expression object = stmt._watch.object;
12252          Expression watcher = stmt._watch.watcher;
12253          if(watcher)
12254             ProcessExpressionType(watcher);
12255          if(object)
12256             ProcessExpressionType(object);
12257
12258          if(inCompiler)
12259          {
12260             if(watcher || thisClass)
12261             {
12262                External external = curExternal;
12263                Context context = curContext;
12264
12265                stmt.type = expressionStmt;
12266                stmt.expressions = MkList();
12267
12268                curExternal = external.prev;
12269
12270                for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12271                {
12272                   ClassFunction func;
12273                   char watcherName[1024];
12274                   Class watcherClass = watcher ?
12275                      ((watcher.expType && watcher.expType.kind == classType && watcher.expType._class) ? watcher.expType._class.registered : null) : thisClass;
12276                   External createdExternal;
12277
12278                   // Create a declaration above
12279                   External externalDecl = MkExternalDeclaration(null);
12280                   ast->Insert(curExternal.prev, externalDecl);
12281
12282                   sprintf(watcherName,"__ecerePropertyWatcher_%d", propWatcherID++);
12283                   if(propWatch.deleteWatch)
12284                      strcat(watcherName, "_delete");
12285                   else
12286                   {
12287                      Identifier propID;
12288                      for(propID = propWatch.properties->first; propID; propID = propID.next)
12289                      {
12290                         strcat(watcherName, "_");
12291                         strcat(watcherName, propID.string);
12292                      }
12293                   }
12294
12295                   if(object && object.expType && object.expType.kind == classType && object.expType._class && object.expType._class.registered)
12296                   {
12297                      // TESTING THIS STUFF... BEWARE OF SYMBOL ID ISSUES
12298                      func = MkClassFunction(MkListOne(MkSpecifier(VOID)), null, MkDeclaratorFunction(MkDeclaratorIdentifier(MkIdentifier(watcherName)),
12299                         //MkListOne(MkTypeName(MkListOne(MkSpecifier(VOID)), null))), null);
12300                         MkListOne(MkTypeName(MkListOne(MkSpecifierName(object.expType._class.string)), MkDeclaratorIdentifier(MkIdentifier("value"))))), null);
12301                      ProcessClassFunctionBody(func, propWatch.compound);
12302                      propWatch.compound = null;
12303
12304                      //afterExternal = afterExternal ? afterExternal : curExternal;
12305
12306                      //createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal.prev);
12307                      createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal, true);
12308                      // TESTING THIS...
12309                      createdExternal.symbol.idCode = external.symbol.idCode;
12310
12311                      curExternal = createdExternal;
12312                      ProcessFunction(createdExternal.function);
12313
12314
12315                      // Create a declaration above
12316                      {
12317                         Declaration decl = MkDeclaration(CopyList(createdExternal.function.specifiers, CopySpecifier),
12318                            MkListOne(MkInitDeclarator(CopyDeclarator(createdExternal.function.declarator), null)));
12319                         externalDecl.declaration = decl;
12320                         if(decl.symbol && !decl.symbol.pointerExternal)
12321                            decl.symbol.pointerExternal = externalDecl;
12322                      }
12323
12324                      if(propWatch.deleteWatch)
12325                      {
12326                         OldList * args = MkList();
12327                         ListAdd(args, CopyExpression(object));
12328                         ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12329                         ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
12330                         ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_WatchDestruction")), args));
12331                      }
12332                      else
12333                      {
12334                         Class _class = object.expType._class.registered;
12335                         Identifier propID;
12336
12337                         for(propID = propWatch.properties->first; propID; propID = propID.next)
12338                         {
12339                            char propName[1024];
12340                            Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12341                            if(prop)
12342                            {
12343                               char getName[1024], setName[1024];
12344                               OldList * args = MkList();
12345
12346                               DeclareProperty(prop, setName, getName);
12347
12348                               // eInstance_Watch(stmt.watch.object, prop, stmt.watch.watcher, callback);
12349                               strcpy(propName, "__ecereProp_");
12350                               FullClassNameCat(propName, prop._class.fullName, false);
12351                               strcat(propName, "_");
12352                               // strcat(propName, prop.name);
12353                               FullClassNameCat(propName, prop.name, true);
12354
12355                               ListAdd(args, CopyExpression(object));
12356                               ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12357                               ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12358                               ListAdd(args, MkExpIdentifier(MkIdentifier(watcherName)));
12359
12360                               ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_Watch")), args));
12361                            }
12362                            else
12363                               Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12364                         }
12365                      }
12366                   }
12367                   else
12368                      Compiler_Error($"Invalid watched object\n");
12369                }
12370
12371                curExternal = external;
12372                curContext = context;
12373
12374                if(watcher)
12375                   FreeExpression(watcher);
12376                if(object)
12377                   FreeExpression(object);
12378                FreeList(watches, FreePropertyWatch);
12379             }
12380             else
12381                Compiler_Error($"No observer specified and not inside a _class\n");
12382          }
12383          else
12384          {
12385             for(propWatch = watches->first; propWatch; propWatch = propWatch.next)
12386             {
12387                ProcessStatement(propWatch.compound);
12388             }
12389
12390          }
12391          break;
12392       }
12393       case fireWatchersStmt:
12394       {
12395          OldList * watches = stmt._watch.watches;
12396          Expression object = stmt._watch.object;
12397          Class _class;
12398          // DEBUGGER BUG: Why doesn't watches evaluate to null??
12399          // printf("%X\n", watches);
12400          // printf("%X\n", stmt._watch.watches);
12401          if(object)
12402             ProcessExpressionType(object);
12403
12404          if(inCompiler)
12405          {
12406             _class = object ?
12407                   ((object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null) : thisClass;
12408
12409             if(_class)
12410             {
12411                Identifier propID;
12412
12413                stmt.type = expressionStmt;
12414                stmt.expressions = MkList();
12415
12416                // Check if we're inside a property set
12417                if(!watches && curFunction.propSet && (!object || (object.type == identifierExp && !strcmp(object.identifier.string, "this"))))
12418                {
12419                   watches = MkListOne(MkIdentifier(curFunction.propSet.string));
12420                }
12421                else if(!watches)
12422                {
12423                   //Compiler_Error($"No property specified and not inside a property set\n");
12424                }
12425                if(watches)
12426                {
12427                   for(propID = watches->first; propID; propID = propID.next)
12428                   {
12429                      Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12430                      if(prop)
12431                      {
12432                         CreateFireWatcher(prop, object, stmt);
12433                      }
12434                      else
12435                         Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12436                   }
12437                }
12438                else
12439                {
12440                   // Fire all properties!
12441                   Property prop;
12442                   Class base;
12443                   for(base = _class; base; base = base.base)
12444                   {
12445                      for(prop = base.membersAndProperties.first; prop; prop = prop.next)
12446                      {
12447                         if(prop.isProperty && prop.isWatchable)
12448                         {
12449                            CreateFireWatcher(prop, object, stmt);
12450                         }
12451                      }
12452                   }
12453                }
12454
12455                if(object)
12456                   FreeExpression(object);
12457                FreeList(watches, FreeIdentifier);
12458             }
12459             else
12460                Compiler_Error($"Invalid object specified and not inside a class\n");
12461          }
12462          break;
12463       }
12464       case stopWatchingStmt:
12465       {
12466          OldList * watches = stmt._watch.watches;
12467          Expression object = stmt._watch.object;
12468          Expression watcher = stmt._watch.watcher;
12469          Class _class;
12470          if(object)
12471             ProcessExpressionType(object);
12472          if(watcher)
12473             ProcessExpressionType(watcher);
12474          if(inCompiler)
12475          {
12476             _class = (object && object.expType && object.expType.kind == classType && object.expType._class) ? object.expType._class.registered : null;
12477
12478             if(watcher || thisClass)
12479             {
12480                if(_class)
12481                {
12482                   Identifier propID;
12483
12484                   stmt.type = expressionStmt;
12485                   stmt.expressions = MkList();
12486
12487                   if(!watches)
12488                   {
12489                      OldList * args;
12490                      // eInstance_StopWatching(object, null, watcher);
12491                      args = MkList();
12492                      ListAdd(args, CopyExpression(object));
12493                      ListAdd(args, MkExpConstant("0"));
12494                      ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12495                      ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12496                   }
12497                   else
12498                   {
12499                      for(propID = watches->first; propID; propID = propID.next)
12500                      {
12501                         char propName[1024];
12502                         Property prop = eClass_FindProperty(_class, propID.string, privateModule);
12503                         if(prop)
12504                         {
12505                            char getName[1024], setName[1024];
12506                            OldList * args = MkList();
12507
12508                            DeclareProperty(prop, setName, getName);
12509
12510                            // eInstance_StopWatching(object, prop, watcher);
12511                            strcpy(propName, "__ecereProp_");
12512                            FullClassNameCat(propName, prop._class.fullName, false);
12513                            strcat(propName, "_");
12514                            // strcat(propName, prop.name);
12515                            FullClassNameCat(propName, prop.name, true);
12516                            MangleClassName(propName);
12517
12518                            ListAdd(args, CopyExpression(object));
12519                            ListAdd(args, MkExpIdentifier(MkIdentifier(propName)));
12520                            ListAdd(args, watcher ? CopyExpression(watcher) : MkExpIdentifier(MkIdentifier("this")));
12521                            ListAdd(stmt.expressions, MkExpCall(MkExpIdentifier(MkIdentifier("ecere::com::eInstance_StopWatching")), args));
12522                         }
12523                         else
12524                            Compiler_Error($"Property %s not found in class %s\n", propID.string, _class.fullName);
12525                      }
12526                   }
12527
12528                   if(object)
12529                      FreeExpression(object);
12530                   if(watcher)
12531                      FreeExpression(watcher);
12532                   FreeList(watches, FreeIdentifier);
12533                }
12534                else
12535                   Compiler_Error($"Invalid object specified and not inside a class\n");
12536             }
12537             else
12538                Compiler_Error($"No observer specified and not inside a class\n");
12539          }
12540          break;
12541       }
12542    }
12543 }
12544
12545 static void ProcessFunction(FunctionDefinition function)
12546 {
12547    Identifier id = GetDeclId(function.declarator);
12548    Symbol symbol = function.declarator ? function.declarator.symbol : null;
12549    Type type = symbol ? symbol.type : null;
12550    Class oldThisClass = thisClass;
12551    Context oldTopContext = topContext;
12552
12553    yylloc = function.loc;
12554    // Process thisClass
12555
12556    if(type && type.thisClass)
12557    {
12558       Symbol classSym = type.thisClass;
12559       Class _class = type.thisClass.registered;
12560       char className[1024];
12561       char structName[1024];
12562       Declarator funcDecl;
12563       Symbol thisSymbol;
12564
12565       bool typedObject = false;
12566
12567       if(_class && !_class.base)
12568       {
12569          _class = currentClass;
12570          if(_class && !_class.symbol)
12571             _class.symbol = FindClass(_class.fullName);
12572          classSym = _class ? _class.symbol : null;
12573          typedObject = true;
12574       }
12575
12576       thisClass = _class;
12577
12578       if(inCompiler && _class)
12579       {
12580          if(type.kind == functionType)
12581          {
12582             if(symbol.type.params.count == 1 && ((Type)symbol.type.params.first).kind == voidType)
12583             {
12584                //TypeName param = symbol.type.params.first;
12585                Type param = symbol.type.params.first;
12586                symbol.type.params.Remove(param);
12587                //FreeTypeName(param);
12588                FreeType(param);
12589             }
12590             if(type.classObjectType != classPointer)
12591             {
12592                symbol.type.params.Insert(null, MkClassType(_class.fullName));
12593                symbol.type.staticMethod = true;
12594                symbol.type.thisClass = null;
12595
12596                // HIGH DANGER: VERIFYING THIS...
12597                symbol.type.extraParam = false;
12598             }
12599          }
12600
12601          strcpy(className, "__ecereClass_");
12602          FullClassNameCat(className, _class.fullName, true);
12603
12604          MangleClassName(className);
12605
12606          structName[0] = 0;
12607          FullClassNameCat(structName, _class.fullName, false);
12608
12609          // [class] this
12610
12611
12612          funcDecl = GetFuncDecl(function.declarator);
12613          if(funcDecl)
12614          {
12615             if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12616             {
12617                TypeName param = funcDecl.function.parameters->first;
12618                if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12619                {
12620                   funcDecl.function.parameters->Remove(param);
12621                   FreeTypeName(param);
12622                }
12623             }
12624
12625             // DANGER: Watch for this... Check if it's a Conversion?
12626             // if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
12627
12628             // WAS TRYING THIS FOR CONVERSION PROPERTIES ON NOHEAD CLASSES: if((_class.type == structClass) || function != (FunctionDefinition)symbol.externalSet)
12629             if(!function.propertyNoThis)
12630             {
12631                TypeName thisParam;
12632
12633                if(type.classObjectType != classPointer)
12634                {
12635                   thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12636                   if(!funcDecl.function.parameters)
12637                      funcDecl.function.parameters = MkList();
12638                   funcDecl.function.parameters->Insert(null, thisParam);
12639                }
12640
12641                if(typedObject)
12642                {
12643                   if(type.classObjectType != classPointer)
12644                   {
12645                      if(type.byReference || _class.type == unitClass || _class.type == systemClass || _class.type == enumClass || _class.type == bitClass)
12646                         thisParam.declarator = MkDeclaratorPointer(MkPointer(null,null), thisParam.declarator);
12647                   }
12648
12649                   thisParam = TypeName
12650                   {
12651                      declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
12652                      qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
12653                   };
12654                   funcDecl.function.parameters->Insert(null, thisParam);
12655                }
12656             }
12657          }
12658
12659          if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
12660          {
12661             InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
12662             funcDecl = GetFuncDecl(initDecl.declarator);
12663             if(funcDecl)
12664             {
12665                if(funcDecl.function.parameters && funcDecl.function.parameters->count == 1)
12666                {
12667                   TypeName param = funcDecl.function.parameters->first;
12668                   if(param.qualifiers && param.qualifiers->count == 1 && ((Specifier)param.qualifiers->first).specifier == VOID && !param.declarator)
12669                   {
12670                      funcDecl.function.parameters->Remove(param);
12671                      FreeTypeName(param);
12672                   }
12673                }
12674
12675                if(type.classObjectType != classPointer)
12676                {
12677                   // DANGER: Watch for this... Check if it's a Conversion?
12678                   if((_class.type != bitClass && _class.type != unitClass && _class.type != enumClass) || function != (FunctionDefinition)symbol.externalSet)
12679                   {
12680                      TypeName thisParam = QMkClass(_class.fullName, MkDeclaratorIdentifier(MkIdentifier("this")));
12681
12682                      if(!funcDecl.function.parameters)
12683                         funcDecl.function.parameters = MkList();
12684                      funcDecl.function.parameters->Insert(null, thisParam);
12685                   }
12686                }
12687             }
12688          }
12689       }
12690
12691       // Add this to the context
12692       if(function.body)
12693       {
12694          if(type.classObjectType != classPointer)
12695          {
12696             thisSymbol = Symbol
12697             {
12698                string = CopyString("this");
12699                type = classSym ? MkClassType(classSym.string) : null; //_class.fullName);
12700             };
12701             function.body.compound.context.symbols.Add((BTNode)thisSymbol);
12702
12703             if(typedObject && thisSymbol.type)
12704             {
12705                thisSymbol.type.classObjectType = ClassObjectType::typedObject;
12706                thisSymbol.type.byReference = type.byReference;
12707                thisSymbol.type.typedByReference = type.byReference;
12708                /*
12709                thisSymbol = Symbol { string = CopyString("class") };
12710                function.body.compound.context.symbols.Add(thisSymbol);
12711                */
12712             }
12713          }
12714       }
12715
12716       // Pointer to class data
12717
12718       if(inCompiler && _class && (_class.type == normalClass /*|| _class.type == noHeadClass*/) && type.classObjectType != classPointer)
12719       {
12720          DataMember member = null;
12721          {
12722             Class base;
12723             for(base = _class; base && base.type != systemClass; base = base.next)
12724             {
12725                for(member = base.membersAndProperties.first; member; member = member.next)
12726                   if(!member.isProperty)
12727                      break;
12728                if(member)
12729                   break;
12730             }
12731          }
12732          for(member = _class.membersAndProperties.first; member; member = member.next)
12733             if(!member.isProperty)
12734                break;
12735          if(member)
12736          {
12737             char pointerName[1024];
12738
12739             Declaration decl;
12740             Initializer initializer;
12741             Expression exp, bytePtr;
12742
12743             strcpy(pointerName, "__ecerePointer_");
12744             FullClassNameCat(pointerName, _class.fullName, false);
12745             {
12746                char className[1024];
12747                strcpy(className, "__ecereClass_");
12748                FullClassNameCat(className, classSym.string, true);
12749                MangleClassName(className);
12750
12751                // Testing This
12752                DeclareClass(classSym, className);
12753             }
12754
12755             // ((byte *) this)
12756             bytePtr = QBrackets(MkExpCast(QMkType("char", QMkPtrDecl(null)), QMkExpId("this")));
12757
12758             if(_class.fixed)
12759             {
12760                char string[256];
12761                sprintf(string, "%d", _class.offset);
12762                exp = QBrackets(MkExpOp(bytePtr, '+', MkExpConstant(string)));
12763             }
12764             else
12765             {
12766                // ([bytePtr] + [className]->offset)
12767                exp = QBrackets(MkExpOp(bytePtr, '+',
12768                   MkExpPointer(QMkExpId(className), MkIdentifier("offset"))));
12769             }
12770
12771             // (this ? [exp] : 0)
12772             exp = QBrackets(QMkExpCond(QMkExpId("this"), exp, MkExpConstant("0")));
12773             exp.expType = Type
12774             {
12775                refCount = 1;
12776                kind = pointerType;
12777                type = Type { refCount = 1, kind = voidType };
12778             };
12779
12780             if(function.body)
12781             {
12782                yylloc = function.body.loc;
12783                // ([structName] *) [exp]
12784                // initializer = MkInitializerAssignment(MkExpCast(QMkType(structName, QMkPtrDecl(null)), exp));
12785                initializer = MkInitializerAssignment(
12786                   MkExpCast(MkTypeName(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)), MkDeclaratorPointer(MkPointer(null, null), null)), exp));
12787
12788                // [structName] * [pointerName] = [initializer];
12789                // decl = QMkDeclaration(structName, MkInitDeclarator(QMkPtrDecl(pointerName), initializer));
12790
12791                {
12792                   Context prevContext = curContext;
12793                   curContext = function.body.compound.context;
12794
12795                   decl = MkDeclaration(MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier(structName), null)),
12796                      MkListOne(MkInitDeclarator(QMkPtrDecl(pointerName), initializer)));
12797
12798                   curContext = prevContext;
12799                }
12800
12801                // WHY?
12802                decl.symbol = null;
12803
12804                if(!function.body.compound.declarations)
12805                   function.body.compound.declarations = MkList();
12806                function.body.compound.declarations->Insert(null, decl);
12807             }
12808          }
12809       }
12810
12811
12812       // Loop through the function and replace undeclared identifiers
12813       // which are a member of the class (methods, properties or data)
12814       // by "this.[member]"
12815    }
12816    else
12817       thisClass = null;
12818
12819    if(id)
12820    {
12821       FreeSpecifier(id._class);
12822       id._class = null;
12823
12824       if(symbol && symbol.pointerExternal && symbol.pointerExternal.type == declarationExternal)
12825       {
12826          InitDeclarator initDecl = symbol.pointerExternal.declaration.declarators->first;
12827          id = GetDeclId(initDecl.declarator);
12828
12829          FreeSpecifier(id._class);
12830          id._class = null;
12831       }
12832    }
12833    if(function.body)
12834       topContext = function.body.compound.context;
12835    {
12836       FunctionDefinition oldFunction = curFunction;
12837       curFunction = function;
12838       if(function.body)
12839          ProcessStatement(function.body);
12840
12841       // If this is a property set and no firewatchers has been done yet, add one here
12842       if(inCompiler && function.propSet && !function.propSet.fireWatchersDone)
12843       {
12844          Statement prevCompound = curCompound;
12845          Context prevContext = curContext;
12846
12847          Statement fireWatchers = MkFireWatchersStmt(null, null);
12848          if(!function.body.compound.statements) function.body.compound.statements = MkList();
12849          ListAdd(function.body.compound.statements, fireWatchers);
12850
12851          curCompound = function.body;
12852          curContext = function.body.compound.context;
12853
12854          ProcessStatement(fireWatchers);
12855
12856          curContext = prevContext;
12857          curCompound = prevCompound;
12858
12859       }
12860
12861       curFunction = oldFunction;
12862    }
12863
12864    if(function.declarator)
12865    {
12866       ProcessDeclarator(function.declarator);
12867    }
12868
12869    topContext = oldTopContext;
12870    thisClass = oldThisClass;
12871 }
12872
12873 /////////// INSTANTIATIONS / DATA TYPES PASS /////////////////////////////////////////////
12874 static void ProcessClass(OldList definitions, Symbol symbol)
12875 {
12876    ClassDef def;
12877    External external = curExternal;
12878    Class regClass = symbol ? symbol.registered : null;
12879
12880    // Process all functions
12881    for(def = definitions.first; def; def = def.next)
12882    {
12883       if(def.type == functionClassDef)
12884       {
12885          if(def.function.declarator)
12886             curExternal = def.function.declarator.symbol.pointerExternal;
12887          else
12888             curExternal = external;
12889
12890          ProcessFunction((FunctionDefinition)def.function);
12891       }
12892       else if(def.type == declarationClassDef)
12893       {
12894          if(def.decl.type == instDeclaration)
12895          {
12896             thisClass = regClass;
12897             ProcessInstantiationType(def.decl.inst);
12898             thisClass = null;
12899          }
12900          // Testing this
12901          else
12902          {
12903             Class backThisClass = thisClass;
12904             if(regClass) thisClass = regClass;
12905             ProcessDeclaration(def.decl);
12906             thisClass = backThisClass;
12907          }
12908       }
12909       else if(def.type == defaultPropertiesClassDef && def.defProperties)
12910       {
12911          MemberInit defProperty;
12912
12913          // Add this to the context
12914          Symbol thisSymbol = Symbol
12915          {
12916             string = CopyString("this");
12917             type = regClass ? MkClassType(regClass.fullName) : null;
12918          };
12919          globalContext.symbols.Add((BTNode)thisSymbol);
12920
12921          for(defProperty = def.defProperties->first; defProperty; defProperty = defProperty.next)
12922          {
12923             thisClass = regClass;
12924             ProcessMemberInitData(defProperty, regClass, null, null, null, null);
12925             thisClass = null;
12926          }
12927
12928          globalContext.symbols.Remove((BTNode)thisSymbol);
12929          FreeSymbol(thisSymbol);
12930       }
12931       else if(def.type == propertyClassDef && def.propertyDef)
12932       {
12933          PropertyDef prop = def.propertyDef;
12934
12935          // Add this to the context
12936          /*
12937          Symbol thisSymbol = Symbol { string = CopyString("this"), type = MkClassType(regClass.fullName) };
12938          globalContext.symbols.Add(thisSymbol);
12939          */
12940
12941          thisClass = regClass;
12942          if(prop.setStmt)
12943          {
12944             if(regClass)
12945             {
12946                Symbol thisSymbol
12947                {
12948                   string = CopyString("this");
12949                   type = MkClassType(regClass.fullName);
12950                };
12951                prop.setStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12952             }
12953
12954             curExternal = prop.symbol ? prop.symbol.externalSet : null;
12955             ProcessStatement(prop.setStmt);
12956          }
12957          if(prop.getStmt)
12958          {
12959             if(regClass)
12960             {
12961                Symbol thisSymbol
12962                {
12963                   string = CopyString("this");
12964                   type = MkClassType(regClass.fullName);
12965                };
12966                prop.getStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12967             }
12968
12969             curExternal = prop.symbol ? prop.symbol.externalGet : null;
12970             ProcessStatement(prop.getStmt);
12971          }
12972          if(prop.issetStmt)
12973          {
12974             if(regClass)
12975             {
12976                Symbol thisSymbol
12977                {
12978                   string = CopyString("this");
12979                   type = MkClassType(regClass.fullName);
12980                };
12981                prop.issetStmt.compound.context.symbols.Add((BTNode)thisSymbol);
12982             }
12983
12984             curExternal = prop.symbol ? prop.symbol.externalIsSet : null;
12985             ProcessStatement(prop.issetStmt);
12986          }
12987
12988          thisClass = null;
12989
12990          /*
12991          globalContext.symbols.Remove(thisSymbol);
12992          FreeSymbol(thisSymbol);
12993          */
12994       }
12995       else if(def.type == propertyWatchClassDef && def.propertyWatch)
12996       {
12997          PropertyWatch propertyWatch = def.propertyWatch;
12998
12999          thisClass = regClass;
13000          if(propertyWatch.compound)
13001          {
13002             Symbol thisSymbol
13003             {
13004                string = CopyString("this");
13005                type = regClass ? MkClassType(regClass.fullName) : null;
13006             };
13007
13008             propertyWatch.compound.compound.context.symbols.Add((BTNode)thisSymbol);
13009
13010             curExternal = null;
13011             ProcessStatement(propertyWatch.compound);
13012          }
13013          thisClass = null;
13014       }
13015    }
13016 }
13017
13018 void DeclareFunctionUtil(const String s)
13019 {
13020    GlobalFunction function = eSystem_FindFunction(privateModule, s);
13021    if(function)
13022    {
13023       char name[1024];
13024       name[0] = 0;
13025       if(function.module.importType != staticImport && (!function.dataType || !function.dataType.dllExport))
13026          strcpy(name, "__ecereFunction_");
13027       FullClassNameCat(name, s, false); // Why is this using FullClassNameCat ?
13028       DeclareFunction(function, name);
13029    }
13030 }
13031
13032 void ComputeDataTypes()
13033 {
13034    External external;
13035    External temp { };
13036    External after = null;
13037
13038    currentClass = null;
13039
13040    containerClass = eSystem_FindClass(GetPrivateModule(), "Container");
13041
13042    for(external = ast->first; external; external = external.next)
13043    {
13044       if(external.type == declarationExternal)
13045       {
13046          Declaration decl = external.declaration;
13047          if(decl)
13048          {
13049             OldList * decls = decl.declarators;
13050             if(decls)
13051             {
13052                InitDeclarator initDecl = decls->first;
13053                if(initDecl)
13054                {
13055                   Declarator declarator = initDecl.declarator;
13056                   if(declarator && declarator.type == identifierDeclarator)
13057                   {
13058                      Identifier id = declarator.identifier;
13059                      if(id && id.string)
13060                      {
13061                         if(!strcmp(id.string, "uintptr_t") || !strcmp(id.string, "intptr_t") || !strcmp(id.string, "size_t") || !strcmp(id.string, "ssize_t"))
13062                         {
13063                            external.symbol.id = -1001, external.symbol.idCode = -1001;
13064                            after = external;
13065                         }
13066                      }
13067                   }
13068                }
13069             }
13070          }
13071        }
13072    }
13073
13074    temp.symbol = Symbol { id = -1000, idCode = -1000 };
13075    ast->Insert(after, temp);
13076    curExternal = temp;
13077
13078    DeclareFunctionUtil("eSystem_New");
13079    DeclareFunctionUtil("eSystem_New0");
13080    DeclareFunctionUtil("eSystem_Renew");
13081    DeclareFunctionUtil("eSystem_Renew0");
13082    DeclareFunctionUtil("eSystem_Delete");
13083    DeclareFunctionUtil("eClass_GetProperty");
13084    DeclareFunctionUtil("eClass_SetProperty");
13085    DeclareFunctionUtil("eInstance_FireSelfWatchers");
13086    DeclareFunctionUtil("eInstance_SetMethod");
13087    DeclareFunctionUtil("eInstance_IncRef");
13088    DeclareFunctionUtil("eInstance_StopWatching");
13089    DeclareFunctionUtil("eInstance_Watch");
13090    DeclareFunctionUtil("eInstance_FireWatchers");
13091
13092    DeclareStruct("ecere::com::Class", false);
13093    DeclareStruct("ecere::com::Instance", false);
13094    DeclareStruct("ecere::com::Property", false);
13095    DeclareStruct("ecere::com::DataMember", false);
13096    DeclareStruct("ecere::com::Method", false);
13097    DeclareStruct("ecere::com::SerialBuffer", false);
13098    DeclareStruct("ecere::com::ClassTemplateArgument", false);
13099
13100    ast->Remove(temp);
13101
13102    for(external = ast->first; external; external = external.next)
13103    {
13104       afterExternal = curExternal = external;
13105       if(external.type == functionExternal)
13106       {
13107          currentClass = external.function._class;
13108          ProcessFunction(external.function);
13109       }
13110       // There shouldn't be any _class member access here anyways...
13111       else if(external.type == declarationExternal)
13112       {
13113          currentClass = null;
13114          if(external.declaration)
13115             ProcessDeclaration(external.declaration);
13116       }
13117       else if(external.type == classExternal)
13118       {
13119          ClassDefinition _class = external._class;
13120          currentClass = external.symbol.registered;
13121          if(_class.definitions)
13122          {
13123             ProcessClass(_class.definitions, _class.symbol);
13124          }
13125          if(inCompiler)
13126          {
13127             // Free class data...
13128             ast->Remove(external);
13129             delete external;
13130          }
13131       }
13132       else if(external.type == nameSpaceExternal)
13133       {
13134          thisNameSpace = external.id.string;
13135       }
13136    }
13137    currentClass = null;
13138    thisNameSpace = null;
13139    curExternal = null;
13140
13141    delete temp.symbol;
13142    delete temp;
13143 }