ecere/gui/Window: Prevent uninitialized values if base Window methods not overridden...
[sdk] / compiler / libec / src / loadSymbols.ec
1 import "ecdefs"
2 import "lexer"
3
4 extern int yychar;
5
6 NameSpace * globalData;
7 public void SetGlobalData(NameSpace * nameSpace) { globalData = nameSpace; }
8
9 OldList dataRedefinitions;
10
11 // #define MAX_INCLUDE_DEPTH 30
12
13 extern char sourceFileStack[MAX_INCLUDE_DEPTH][MAX_LOCATION];
14 extern int include_stack_ptr;
15
16 static int numIncludes;
17 static char ** includes;
18
19 bool inIDE = false;
20 public void SetInIDE(bool b) { inIDE = b; }
21 List<String> sourceDirs;
22
23 public void SetSourceDirs(List<String> list) { sourceDirs = list; }
24
25 OldList * includeDirs, * sysIncludeDirs;
26
27 public void SetIncludeDirs(OldList * list) { includeDirs = list; }
28 public void SetSysIncludeDirs(OldList * list) { sysIncludeDirs = list; }
29
30 // TOFIX: Declaration reordering error if right before above functions
31 // OldList * includeDirs, * sysIncludeDirs;
32
33 bool ecereImported;
34 public void SetEcereImported(bool b) { ecereImported = b; } public bool GetEcereImported() { return ecereImported; }
35 bool inPreCompiler = false;
36 public void SetInPreCompiler(bool b) {inPreCompiler = b; }
37 bool inSymbolGen = false;
38 public void SetInSymbolGen(bool b) {inSymbolGen = b; }
39 bool inDocumentor = false;
40 public void SetInDocumentor(bool b) { inDocumentor = b; }
41 OldList * precompDefines;
42 public void SetPrecompDefines(OldList * list) { precompDefines = list; }
43
44 public bool DummyMethod()
45 {
46    return true;
47 }
48
49 static void ReadDataMembers(Class regClass, DataMember member, File f)
50 {
51    char line[1024];
52    char name[1024];
53    int size = 0, bitPos = -1;
54    AccessMode memberAccess = publicAccess;
55
56    for(;;)
57    {
58       if(!f.GetLine(line, sizeof(line))) break;
59       TrimLSpaces(line, line);
60       if(!strcmp(line, ".")) break;
61       if(line[0] == '[')
62       {
63          if(!strcmp(line, "[Size]"))
64          {
65             f.GetLine(line, sizeof(line));
66             TrimLSpaces(line, line);
67             size = strtol(line, null, 0);
68          }
69          else if(!strcmp(line, "[Pos]"))
70          {
71             f.GetLine(line, sizeof(line));
72             TrimLSpaces(line, line);
73             bitPos = strtol(line, null, 0);
74          }
75          else if(!strcmp(line, "[Public]"))
76             memberAccess = publicAccess;
77          else if(!strcmp(line, "[Private]"))
78             memberAccess = privateAccess;
79          else if(!strcmp(line, "[Type]"))
80          {
81             f.GetLine(line, sizeof(line));
82             TrimLSpaces(line, line);
83
84             if(member)
85             {
86                if(!eMember_AddDataMember(member, name, line[0] ? line : 0, 0, 0 /*size *//*type->size*/, memberAccess))
87                   ;//Compiler_Error($"Member with same name (%s) already exists in member %s\n", name, member->name);
88             }
89             else if(regClass && regClass.type == bitClass)
90             {
91                //eClass_AddBitMember(regClass, name, line[0] ? line : 0, size, bitPos);
92                BitMember member = eClass_AddBitMember(regClass, name, line[0] ? line : 0, 0, 0, memberAccess);
93                if(member)
94                {
95                   member.size = size;
96                   member.pos = bitPos;
97                }
98             }
99             else if(regClass)
100             {
101                if(!eClass_AddDataMember(regClass, name, line[0] ? line : 0, 0, 0 /*size *//*type->size*/, memberAccess))
102                   ;//Compiler_Error($"Member with same name (%s) already exists in class %s\n", name, regClass.fullName);
103             }
104          }
105          else if(!strcmp(line, "[Struct]") || !strcmp(line, "[Union]"))
106          {
107             DataMember dataMember = (regClass || member) ? eMember_New((!strcmp(line, "[Union]")) ? unionMember : structMember, memberAccess) : null;
108             ReadDataMembers(null, dataMember, f);
109             if(member)
110             {
111                if(!eMember_AddMember(member, dataMember))
112                   ;//Compiler_Error($"Member with same name (%s) already exists in member %s\n", name, member->name);
113             }
114             else if(regClass)
115             {
116                if(!eClass_AddMember(regClass, dataMember))
117                   ;//Compiler_Error($"Member with same name (%s) already exists in class %s\n", name, regClass.name);
118             }
119          }
120       }
121       else
122       {
123          size = 0;
124          bitPos = -1;
125          strcpy(name, line);
126          memberAccess = publicAccess;
127       }
128    }
129 }
130
131 // This should register the stuff only...
132 // But also call ImportModule
133 public bool LoadSymbols(const char * fileName, ImportType importType, bool loadDllOnly)
134 {
135    File f = FileOpenBuffered(fileName, read);
136    bool globalInstance = false;
137    if(f)
138    {
139       bool ecereCOMModule = false;
140       char moduleName[MAX_LOCATION];
141       GetLastDirectory(fileName, moduleName);
142       // TEMP: UNTIL WE CAN HAVE PER SOURCE FILE PREPROCESSOR DEFINITIONS...
143       if(
144          !(strcmpi(moduleName, "instance.sym") && strcmpi(moduleName, "BinaryTree.sym") &&
145          strcmpi(moduleName, "dataTypes.sym") && strcmpi(moduleName, "OldList.sym") &&
146          strcmpi(moduleName, "String.sym") && strcmpi(moduleName, "BTNode.sym") &&
147          strcmpi(moduleName, "Array.sym") && strcmpi(moduleName, "AVLTree.sym") &&
148          strcmpi(moduleName, "BuiltInContainer.sym") && strcmpi(moduleName, "Container.sym") &&
149          strcmpi(moduleName, "CustomAVLTree.sym") && strcmpi(moduleName, "LinkList.sym") &&
150          strcmpi(moduleName, "List.sym") && strcmpi(moduleName, "Map.sym") &&
151          strcmpi(moduleName, "Mutex.sym")))
152          ecereCOMModule = true;
153
154       for(;;)
155       {
156          char line[1024];
157          if(!f.GetLine(line, sizeof(line))) break;
158          TrimLSpaces(line, line);
159
160          if(line[0] == '[')
161          {
162
163             if(!strcmp(line, "[Global Instance]"))
164                globalInstance = true;
165             else if(!strcmp(line, "[Defined Classes]"))
166             {
167                Class regClass = null;
168                char name[1024];
169                bool isRemote = false;
170                bool isStatic = false;
171                bool isWatchable = false;
172                ClassType classType = normalClass;
173                bool fixed = false;
174                bool noExpansion = false;
175                AccessMode inheritanceAccess = publicAccess;
176                for(;;)
177                {
178                   if(!f.GetLine(line, sizeof(line))) break;
179                   TrimLSpaces(line, line);
180                   if(!strcmp(line, ".")) break;
181
182                   if(line[0] == '[')
183                   {
184                      if(!strcmp(line, "[Remote]"))
185                         isRemote = true;
186                      else if(!strcmp(line, "[Static]"))
187                         isStatic = true;
188                      else if(!strcmp(line, "[Fixed]"))
189                         fixed = true;
190                      else if(!strcmp(line, "[No Expansion]"))
191                         noExpansion = true;
192                      else if(!strcmp(line, "[Watchable]"))
193                         isWatchable = true;
194                      else if(!strcmp(line, "[Enum]"))
195                         classType = enumClass;
196                      else if(!strcmp(line, "[Bit]"))
197                         classType = bitClass;
198                      else if(!strcmp(line, "[Struct]"))
199                         classType = structClass;
200                      else if(!strcmp(line, "[Unit]"))
201                         classType = unitClass;
202                      else if(!strcmp(line, "[NoHead]"))
203                         classType = noHeadClass;
204                      else if(!strcmp(line, "[Base]") || !strcmp(line, "[Private Base]"))
205                      {
206                         if(!strcmp(line, "[Private Base]"))
207                            inheritanceAccess = privateAccess;
208
209                         f.GetLine(line, sizeof(line));
210                         TrimLSpaces(line, line);
211
212                         if(importType == preDeclImport)
213                            DeclClass(null, name);
214                         if(isStatic || loadDllOnly || importType == preDeclImport || importType == comCheckImport)
215                           regClass = null;
216                         else if(regClass = eSystem_FindClass(privateModule, name), !regClass || regClass.internalDecl || regClass.isRemote)
217                         {
218                            Symbol existingClass = FindClass(name);
219                            const char * baseName = (classType == normalClass && importType == remoteImport && isRemote) ? "DCOMClientObject" : (!strcmp(line, "[None]") ? null : line);
220                            //Symbol baseSymbol = baseName ? FindClass(baseName) : null;
221                            //if(baseSymbol && !baseSymbol->registered)
222                            /*if(classType != unitClass && classType != bitClass && classType != enumClass && baseName && !eSystem_FindClass(privateModule, baseName))
223                            {
224                               Compiler_Error($"Base class %s undefined\n", baseName);
225                               DeclClass(name);
226                               regClass = null;
227                               continue;
228                            }
229                            */
230
231                            if(!isRemote || (importType != remoteImport) || (!sourceFile || !strstr(sourceFile, ".main.ec")))
232                            {
233                               if(!regClass || regClass.internalDecl)
234                                  regClass = eSystem_RegisterClass(classType, name, isRemote ? null : baseName, 0, 0, null, null, privateModule, ecereCOMModule ? baseSystemAccess : publicAccess, inheritanceAccess);
235                               if(/*importType == Remote && */regClass && isRemote)
236                                  regClass.isRemote = (importType == remoteImport) ? 1 : 2;
237
238                               if(isRemote)
239                               {
240                                  if(importType == remoteImport)
241                                  {
242                                     char className[1024] = "DCOMClient_";
243                                     strcat(className, name);
244                                     if(!existingClass)
245                                        existingClass = DeclClass(null, name);
246                                     regClass = eSystem_RegisterClass(classType, className, baseName, 0, 0, null, null, privateModule, ecereCOMModule ? baseSystemAccess : publicAccess, inheritanceAccess);
247                                  }
248                                  if(regClass)
249                                     regClass.isRemote = (importType == remoteImport) ? 1 : 3;
250                               }
251
252                               // Update templated classes
253                               if(existingClass)
254                               {
255                                  OldLink link;
256                                  for(link = existingClass.templatedClasses.first; link; link = link.next)
257                                  {
258                                     Symbol symbol = link.data;
259                                     symbol.registered = eSystem_FindClass(privateModule, symbol.string);
260                                  }
261                               }
262
263                               if(fixed)
264                                  regClass.fixed = true;
265                               if(noExpansion)
266                                  regClass.noExpansion = true;
267
268                               if(isWatchable)
269                               {
270                                  eClass_DestructionWatchable(regClass);
271                                  regClass.structSize = regClass.offset;    // THIS COULD PROBABLY BENEFIT FROM SOME EXPLANATIONS...
272                               }
273
274                               if(regClass && existingClass)
275                               {
276                                  existingClass.registered = regClass;
277                                  regClass.symbol = existingClass;
278                                  existingClass.notYetDeclared = true;
279                                  existingClass.imported = true;
280                                  if(regClass.module)
281                                     existingClass.module = FindModule(regClass.module);
282                                  else
283                                     existingClass.module = mainModule;
284                               }
285                            }
286                            else
287                               regClass = null;
288                         }
289                         else
290                            regClass = null;
291                         isRemote = false;
292                         isWatchable = false;
293                         fixed = false;
294                         isStatic = false;
295                      }
296                      else if(!strcmp(line, "[Enum Values]"))
297                      {
298                         for(;;)
299                         {
300                            char * equal;
301
302                            if(!f.GetLine(line, sizeof(line))) break;
303                            TrimLSpaces(line, line);
304                            if(!strcmp(line, ".")) break;
305
306                            if(regClass)
307                            {
308                               equal = strchr(line, '=');
309                               if(equal)
310                               {
311                                  char name[1024];
312                                  memcpy(name, line, (int)(equal - line));
313                                  name[equal - line] = '\0';
314                                  TrimLSpaces(name, name);
315                                  TrimRSpaces(name, name);
316                                  eEnum_AddFixedValue(regClass, name, strtoll(equal + 1, null, 0));
317                               }
318                               else
319                               {
320                                  eEnum_AddValue(regClass, line);
321                               }
322                            }
323                         }
324                      }
325                      else if(!strcmp(line, "[Defined Methods]"))
326                      {
327                         char name[1024];
328                         bool isVirtual = false;
329                         AccessMode memberAccess = publicAccess;
330                         for(;;)
331                         {
332                            if(!f.GetLine(line, sizeof(line))) break;
333                            TrimLSpaces(line, line);
334                            if(!strcmp(line, ".")) break;
335                            if(line[0] == '[')
336                            {
337                               if(!strcmp(line, "[Type]"))
338                               {
339                                  f.GetLine(line, sizeof(line));
340                                  if(regClass)
341                                  {
342                                     TrimLSpaces(line, line);
343                                     if(isVirtual)
344                                        eClass_AddVirtualMethod(regClass, name, line[0] ? line : 0, DummyMethod, memberAccess);
345                                     else
346                                        eClass_AddMethod(regClass, name, line[0] ? line : 0, DummyMethod, memberAccess);
347                                  }
348                               }
349                               else if(!strcmp(line, "[Virtual]"))
350                                  isVirtual = true;
351                               else if(!strcmp(line, "[Public]"))
352                                  memberAccess = publicAccess;
353                               else if(!strcmp(line, "[Private]"))
354                                  memberAccess = privateAccess;
355                            }
356                            else
357                            {
358                               strcpy(name, line);
359                               isVirtual = false;
360                               memberAccess = publicAccess;
361                            }
362                         }
363                      }
364                      else if(!strcmp(line, "[Defined Properties]"))
365                      {
366                         char name[1024];
367                         bool setStmt = false, getStmt = false, isVirtual = false, conversion = false;
368                         bool isWatchable = false;
369                         AccessMode memberAccess = publicAccess;
370                         for(;;)
371                         {
372                            if(!f.GetLine(line, sizeof(line))) break;
373                            TrimLSpaces(line, line);
374                            if(!strcmp(line, ".")) break;
375                            if(line[0] == '[')
376                            {
377                               if(!strcmp(line, "[Type]"))
378                               {
379                                  // Set type , set , get
380                                  f.GetLine(line, sizeof(line));
381                                  TrimLSpaces(line, line);
382                                  if(regClass)
383                                  {
384                                     Property prop = eClass_AddProperty(regClass, conversion ? null : name, line[0] ? line : 0, (void *)(uintptr)setStmt, (void *)(uintptr)getStmt, memberAccess);
385                                     if(prop)
386                                     {
387                                        prop.compiled = false;
388                                        if(isWatchable)
389                                        {
390                                           eProperty_Watchable(prop);
391                                           regClass.structSize = regClass.offset; // THIS COULD PROBABLY BENEFIT FROM SOME EXPLANATIONS
392                                        }
393                                     }
394                                  }
395                               }
396                               else if(!strcmp(line, "[Set]"))
397                                  setStmt = true;
398                               else if(!strcmp(line, "[Get]"))
399                                  getStmt = true;
400                               else if(!strcmp(line, "[Watchable]"))
401                                  isWatchable = true;
402                               else if(!strcmp(line, "[Public]"))
403                                  memberAccess = publicAccess;
404                               else if(!strcmp(line, "[Private]"))
405                                  memberAccess = privateAccess;
406                               else if(!strcmp(line, "[Conversion]"))
407                               {
408                                  conversion = true;
409                                  setStmt = getStmt = isVirtual = isWatchable = false;
410                               }
411                            }
412                            else
413                            {
414                               strcpy(name, line);
415                               setStmt = getStmt = isVirtual = conversion = isWatchable = false;
416                               memberAccess = publicAccess;
417                            }
418                         }
419                      }
420                      else if(!strcmp(line, "[Defined Class Properties]"))
421                      {
422                         char name[1024];
423                         bool setStmt = false, getStmt = false;
424                         for(;;)
425                         {
426                            if(!f.GetLine(line, sizeof(line))) break;
427                            TrimLSpaces(line, line);
428                            if(!strcmp(line, ".")) break;
429                            if(line[0] == '[')
430                            {
431                               if(!strcmp(line, "[Type]"))
432                               {
433                                  // Set type , set , get
434                                  f.GetLine(line, sizeof(line));
435                                  TrimLSpaces(line, line);
436                                  if(regClass)
437                                  {
438                                     eClass_AddClassProperty(regClass, name, line, (void *)(uintptr)setStmt, (void *)(uintptr)getStmt);
439                                  }
440                               }
441                               else if(!strcmp(line, "[Set]"))
442                                  setStmt = true;
443                               else if(!strcmp(line, "[Get]"))
444                                  getStmt = true;
445                            }
446                            else
447                            {
448                               strcpy(name, line);
449                               setStmt = getStmt = false;
450                            }
451                         }
452                      }
453                      else if(!strcmp(line, "[Defined Data Members]"))
454                      {
455                         ReadDataMembers(regClass, null, f);
456                      }
457                      else if(!strcmp(line, "[Template Parameters]"))
458                      {
459                         while(!f.Eof())
460                         {
461                            char name[1024];
462                            TemplateParameterType type = TemplateParameterType::type;
463                            ClassTemplateArgument defaultArg { };
464                            void * info = null;
465
466                            f.GetLine(line, sizeof(line)); TrimLSpaces(line, line);
467                            if(line[0] == '.') break;
468                            strcpy(name, line);
469
470                            f.GetLine(line, sizeof(line)); TrimLSpaces(line, line);
471                            if(!strcmp(line, "[Expression]")) type = expression;
472                            else if(!strcmp(line, "[Identifier]")) type = identifier;
473
474                            //printf("Inside template parameters\n");
475                            switch(type)
476                            {
477                               case TemplateParameterType::type:
478                                  f.GetLine(line, sizeof(line)); TrimLSpaces(line, line);
479                                  if(regClass && strcmp(line, "[None]"))
480                                  {
481                                     info = CopyString(line);      // FIXME: MEMORY LEAK
482                                  }
483
484                                  f.GetLine(line, sizeof(line)); TrimLSpaces(line, line);
485                                  // printf("%s\n", line);
486
487                                  if(regClass && strcmp(line, "[None]"))
488                                  {
489                                     defaultArg.dataTypeString = CopyString(line);   // FIXME: MEMORY LEAK
490                                  }
491                                  break;
492                               case expression:
493                                  f.GetLine(line, sizeof(line)); TrimLSpaces(line, line);
494                                  // Data type string (reusing base)
495                                  if(regClass && strcmp(line, "[None]"))
496                                  {
497                                     info = CopyString(line);   // FIXME: MEMORY LEAK
498                                  }
499
500                                  f.GetLine(line, sizeof(line)); TrimLSpaces(line, line);
501                                  if(regClass && strcmp(line, "[None]"))
502                                  {
503                                     LexerBackup backup = pushLexer();   // We currently don't have a separate Lexer instance for TU/Type/Expression
504                                     Operand op;
505                                     Expression exp;
506
507                                     skipErrors = true;
508                                     exp = ParseExpressionString(line);
509                                     if(exp)
510                                     {
511                                        if(info)
512                                           exp.destType = ProcessTypeString(info, false);
513                                        ProcessExpressionType(exp);
514                                        ComputeExpression(exp);
515                                        op = GetOperand(exp);
516                                        defaultArg.expression.ui64 = op.ui64;
517                                        FreeExpression(exp);
518                                     }
519                                     skipErrors = false;
520                                     popLexer(backup);
521                                  }
522                                  break;
523                               case identifier:
524                                  f.GetLine(line, sizeof(line)); TrimLSpaces(line, line);
525                                  if(!strcmp(line, "[Data member]")) info = (void *)TemplateMemberType::dataMember;
526                                  else if(!strcmp(line, "[Method]")) info = (void *)TemplateMemberType::method;
527                                  else if(!strcmp(line, "[Property]")) info = (void *)TemplateMemberType::prop;
528
529                                  f.GetLine(line, sizeof(line)); TrimLSpaces(line, line);
530                                  if(regClass && strcmp(line, "[None]"))
531                                  {
532                                     defaultArg.memberString = CopyString(line);
533                                  }
534                                  break;
535                            }
536                            if(regClass)
537                               eClass_AddTemplateParameter(regClass, name, type, info, defaultArg);
538                            if(type == TemplateParameterType::type || type == TemplateParameterType::expression)
539                               delete info;
540                            if(type == TemplateParameterType::type || type == TemplateParameterType::identifier)
541                               delete (void *)defaultArg.dataTypeString;
542                         }
543                         if(regClass)
544                            eClass_DoneAddingTemplateParameters(regClass);
545                      }
546                   }
547                   else
548                   {
549                      inheritanceAccess = publicAccess;
550                      classType = normalClass;
551                      isRemote = false;
552                      strcpy(name, line);
553                      regClass = null;
554                   }
555                }
556             }
557             else if(!strcmp(line, "[Defined Expressions]"))
558             {
559                char name[1024];
560                for(;;)
561                {
562                   if(!f.GetLine(line, sizeof(line))) break;
563                   TrimLSpaces(line, line);
564                   if(!strcmp(line, ".")) break;
565                   if(!strcmp(line, "[Value]"))
566                   {
567                      f.GetLine(line, sizeof(line));
568                      TrimLSpaces(line, line);
569                      if(!loadDllOnly && importType != preDeclImport && importType != comCheckImport)
570                         eSystem_RegisterDefine(name, line, privateModule, ecereCOMModule ? baseSystemAccess : publicAccess);
571                   }
572                   else if(line[0] != '[')
573                   {
574                      strcpy(name, line);
575                   }
576                }
577             }
578             else if(!strcmp(line, "[Defined Functions]"))
579             {
580                char name[1024];
581                for(;;)
582                {
583                   if(!f.GetLine(line, sizeof(line))) break;
584                   TrimLSpaces(line, line);
585                   if(!strcmp(line, ".")) break;
586                   if(!strcmp(line, "[Type]"))
587                   {
588                      f.GetLine(line, sizeof(line));
589                      TrimLSpaces(line, line);
590                      if(!loadDllOnly && importType != preDeclImport && importType != comCheckImport)
591                         eSystem_RegisterFunction(name, line, null, privateModule, ecereCOMModule ? baseSystemAccess : publicAccess);
592                   }
593                   else if(line[0] != '[')
594                   {
595                      strcpy(name, line);
596                   }
597                }
598             }
599             else if(!strcmp(line, "[Defined Data]"))
600             {
601                char name[1024];
602                for(;;)
603                {
604                   if(!f.GetLine(line, sizeof(line))) break;
605                   TrimLSpaces(line, line);
606                   if(!strcmp(line, ".")) break;
607                   if(!strcmp(line, "[Type]"))
608                   {
609                      f.GetLine(line, sizeof(line));
610                      TrimLSpaces(line, line);
611
612                      if(!loadDllOnly && importType != preDeclImport && importType != comCheckImport)
613                      {
614                         int start = 0, c;
615                         NameSpace * nameSpace = globalData;
616                         GlobalData data;
617
618                         // Register Global Data
619                         for(c = 0; name[c]; c++)
620                         {
621                            if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
622                            {
623                               NameSpace * newSpace;
624
625                               char * spaceName = new char[c - start + 1];
626                               strncpy(spaceName, name + start, c - start);
627                               spaceName[c-start] = '\0';
628
629                               newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
630                               if(!newSpace)
631                               {
632                                  newSpace = new0 NameSpace[1];
633                                  newSpace->classes.CompareKey = (void *)BinaryTree::CompareString;
634                                  newSpace->defines.CompareKey = (void *)BinaryTree::CompareString;
635                                  newSpace->functions.CompareKey = (void *)BinaryTree::CompareString;
636                                  newSpace->nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
637                                  newSpace->name = spaceName;
638                                  newSpace->parent = nameSpace;
639                                  nameSpace->nameSpaces.Add((BTNode)newSpace);
640                               }
641                               else
642                                  delete spaceName;
643                               nameSpace = newSpace;
644                               if(name[c] == ':') c++;
645                               start = c+1;
646                            }
647                         }
648                         if(c - start)
649                         {
650                            // TOFIX:
651                            //if(!(data = (GlobalData)nameSpace->functions.FindString(name)))
652                            data = (GlobalData)nameSpace->functions.FindString(name + start);
653                            if(!data)
654                            {
655                               data = GlobalData
656                               {
657                                  fullName = CopyString(name),
658                                  dataTypeString = CopyString(line),
659                                  module = privateModule
660                               };
661                               data.key = (uintptr)(data.fullName + start);
662                               // Reusing functions here...
663                               nameSpace->functions.Add((BTNode)data);
664                            }
665                            else if(strcmp(data.dataTypeString, line))
666                            {
667                               DataRedefinition redefinition { };
668                               strcpy(redefinition.name, name);
669                               strcpy(redefinition.type1, data.dataTypeString);
670                               strcpy(redefinition.type2, line);
671                               dataRedefinitions.Add(redefinition);
672                            }
673                         }
674                      }
675                   }
676                   else if(line[0] != '[')
677                   {
678                      strcpy(name, line);
679                   }
680                }
681             }
682             else if(!strcmp(line, "[Imported Modules]"))
683             {
684                ImportType moduleImportType = normalImport;
685                AccessMode importAccess = publicAccess;
686                for(;;)
687                {
688                   if(!f.GetLine(line, sizeof(line))) break;
689                   TrimLSpaces(line, line);
690                   if(!strcmp(line, ".")) break;
691                   if(!strcmp(line, "[Static]")) moduleImportType = staticImport;
692                   else if(!strcmp(line, "[Remote]")) moduleImportType = remoteImport;
693                   else if(!strcmp(line, "[Private]")) importAccess = privateAccess;
694                   else if(line[0] != '[')
695                   {
696                      if(importType != preDeclImport && importType != comCheckImport)
697                         ImportModule(line, moduleImportType, importAccess, loadDllOnly);
698                      else
699                         ImportModule(line, comCheckImport, importAccess, loadDllOnly);
700                      if(!strcmp(line, "ecere"))
701                         ecereImported = true;
702                      moduleImportType = normalImport;
703                      importAccess = publicAccess;
704                   }
705                }
706             }
707          }
708       }
709       delete f;
710    }
711    else if(importType != comCheckImport)
712    {
713       char sysFileName[MAX_LOCATION];
714       GetSystemPathBuffer(sysFileName, fileName);
715       Compiler_Error($"Couldn't open %s\n", sysFileName);
716    }
717    return globalInstance;
718 }
719
720 Map<String, List<Module> > loadedModules { };
721
722 // (Same function as in actual compiler)
723 public void ImportModule(const char * name, ImportType importType, AccessMode importAccess, bool loadDllOnly)
724 {
725    ImportedModule module = null;
726    char moduleName[MAX_LOCATION];
727    bool isSourceModule = false;
728    if(sourceFile)
729    {
730       char sourceFileModule[MAX_FILENAME];
731       GetLastDirectory(sourceFile, sourceFileModule);
732       StripExtension(sourceFileModule);
733       if(!strcmpi(sourceFileModule, name))
734          isSourceModule = true;
735    }
736
737    strncpy(moduleName, name, MAX_LOCATION-1);
738    moduleName[MAX_LOCATION-1] = 0;
739    StripExtension(moduleName);
740
741    for(module = defines->first; module; module = module.next)
742    {
743       if(module.type == moduleDefinition && !strcmpi(module.name, moduleName) &&
744          ((importType == remoteImport) == (module.importType == remoteImport) || isSourceModule))
745          break;
746    }
747    if((!module || (module.dllOnly && !loadDllOnly)) && strlen(name) < MAX_FILENAME)
748    {
749       char ext[MAX_EXTENSION];
750       Module loadedModule = null;
751       char symFile[MAX_LOCATION];
752       symFile[0] = '\0';
753
754       GetExtension(name, ext);
755
756       strcpy(symFile, symbolsDir ? symbolsDir : "");
757       PathCat(symFile, name);
758       ChangeExtension(symFile, "sym", symFile);
759
760       if(!strcmp(ext, "dll") || !strcmp(ext, "so") || !strcmp(ext, "dylib") || !ext[0])
761       {
762          if(importType != comCheckImport)
763          {
764             if(!module)
765             {
766                if(precompDefines)
767                {
768                   module = ImportedModule
769                   {
770                      name = CopyString(moduleName),
771                      type = moduleDefinition,
772                      importType = importType,
773                      importAccess = importAccess
774                   };
775                   precompDefines->Add(module);
776                }
777                module = ImportedModule
778                {
779                   name = CopyString(moduleName),
780                   type = moduleDefinition,
781                   importType = importType,
782                   importAccess = importAccess
783                };
784                defines->AddName(module);
785             }
786             module.dllOnly = loadDllOnly;
787
788             if(ext[0] || !FileExists(symFile))
789             {
790                bool skipLoad = false;
791                List<Module> list = null;
792                /*
793                char file[MAX_LOCATION];
794                strcpy(file, name);
795                StripExtension(file);
796                */
797
798                // Load an extra instance of any shared module to ensure freeing up a
799                // module loaded in another file will not invalidate our objects.
800
801                // Don't do this for Documentor, because files are loaded with full paths
802                // and won't be recognized as the same libecere that Documentor is actually using,
803                // and since this is loaded from the Documentor app module, it will invalidate classes in use.
804                // We only load one component app at a time for Documentor, so we do not need this trick.
805                if(!inCompiler && !inPreCompiler && !inSymbolGen && !inDocumentor)
806                {
807                   MapIterator<String, List<Module> > it { map = loadedModules };
808                   if(!it.Index(name /*file*/, false))
809                   {
810                      Module firstModule = eModule_LoadStrict(__thisModule.application, name /*file*/, importAccess);
811                      if(firstModule)
812                      {
813                         list = { };
814                         list.Add(firstModule);
815                         loadedModules[name /*file*/] = list;
816                      }
817                      else
818                         skipLoad = true;
819                   }
820                   else
821                      list = it.data;
822                }
823
824                if(!skipLoad)
825                {
826                   loadedModule = eModule_LoadStrict(privateModule, name /*file*/, importAccess);
827                   if(loadedModule)
828                   {
829                      loadedModule.importType = importType;
830                      module.dllOnly = false;    // If this is truly a dll, no need to reload it again...
831                      if(list) list.Add(loadedModule);
832                   }
833                }
834             }
835          }
836       }
837       if(!loadedModule && (!strcmp(ext, "ec") || !strcmp(ext, "sym") || !ext[0]))
838       {
839          //if(symbolsDir)
840          {
841             if(!module)
842             {
843                if(precompDefines)
844                {
845                   module = ImportedModule
846                   {
847                      name = CopyString(moduleName),
848                      type = moduleDefinition,
849                      importType = importType,
850                      importAccess = importAccess
851                   };
852                   precompDefines->Add(module);
853                }
854                module = ImportedModule
855                {
856                   name = CopyString(moduleName),
857                   type = moduleDefinition,
858                   importType = importType,
859                   importAccess = importAccess
860                };
861                defines->AddName(module);
862             }
863             module.dllOnly = loadDllOnly;
864
865             if(inPreCompiler)
866                return;
867
868             if(inIDE && !FileExists(symFile) && sourceDirs /*ide.workspace*/ /*ide.projectView*/)
869             {
870                for(dir : sourceDirs)
871                {
872                   char configDir[MAX_FILENAME];
873                   strcpy(symFile, dir);
874                   // PathCat(symFile, "Debug");
875                   PathCat(symFile, "obj");
876                   sprintf(configDir, "debug.%s", (__runtimePlatform == win32) ? "win32" : (__runtimePlatform == apple) ? "apple" : "linux");
877                   PathCat(symFile, configDir);
878
879                   PathCat(symFile, name);
880                   ChangeExtension(symFile, "sym", symFile);
881                   if(FileExists(symFile))
882                      break;
883                }
884             }
885
886             // ADDED THIS HERE TO HELP FINDING SYMBOLS IN DOCUMENTOR... HURTS ANYTHING?
887             if(!FileExists(symFile))
888             {
889                char fileName[MAX_FILENAME];
890                GetLastDirectory(symFile, fileName);
891                strcpy(symFile, symbolsDir ? symbolsDir : "");
892                PathCat(symFile, fileName);
893             }
894
895             module.globalInstance = LoadSymbols(symFile, importType, loadDllOnly);
896          }
897       }
898    }
899 }
900
901 int FindIncludeFileID(char * includeFile)
902 {
903    int c;
904    for(c = 0; c<numIncludes; c++)
905       if(!fstrcmp(includes[c], includeFile))
906          return c + 1;
907    return 0;
908 }
909
910 int GetIncludeFileID(char * includeFile)
911 {
912    int found = FindIncludeFileID(includeFile);
913    if(found)
914       return found;
915
916    includes = renew includes char *[numIncludes+1];
917    includes[numIncludes++] = CopyString(includeFile);
918    return numIncludes;
919 }
920
921 char * GetIncludeFileFromID(int id)
922 {
923    return includes[id-1];
924 }
925
926 // TODO: Add parameter to check system dirs before project dirs
927 File OpenIncludeFile(char * includeFile)
928 {
929    File file;
930    char location[MAX_FILENAME];
931    StripLastDirectory(sourceFileStack[(include_stack_ptr >= 0) ? include_stack_ptr : 0], location);
932    PathCat(location, includeFile);
933    file = FileOpen(location, read);
934    if(file)
935    {
936       strcpy(sourceFileStack[include_stack_ptr + 1], location);
937    }
938    else if(inIDE)
939    {
940       // TODO: Add support for project dirs as well as system dirs
941       NamedItem includeDir;
942       if(includeDirs)
943       {
944          for(includeDir = includeDirs->first; includeDir; includeDir = includeDir.next)
945          {
946             strcpy(location, includeDir.name);
947             PathCat(location, includeFile);
948             file = FileOpen(location, read);
949             if(file)
950                break;
951          }
952       }
953       if(!file && sysIncludeDirs)
954       {
955          for(includeDir = sysIncludeDirs->first; includeDir; includeDir = includeDir.next)
956          {
957             strcpy(location, includeDir.name);
958             PathCat(location, includeFile);
959             file = FileOpen(location, read);
960             if(file)
961                break;
962          }
963       }
964    }
965    return file;
966 }
967
968 public void FreeIncludeFiles()
969 {
970    int c;
971    for(c = 0; c<numIncludes; c++)
972       delete includes[c];
973    delete includes;
974    numIncludes = 0;
975 }
976
977 public void FreeGlobalData(NameSpace globalDataList)
978 {
979    NameSpace * ns;
980    GlobalData data;
981    // Unload functions
982    for(;(ns = (NameSpace *)globalDataList.nameSpaces.root);)
983    {
984       FreeGlobalData(ns);
985       globalDataList.nameSpaces.Remove((BTNode)ns);
986       delete (void *)ns->name;
987       delete ns;
988    }
989    for(;(data = (GlobalData)globalDataList.functions.root);)
990    {
991       globalDataList.functions.Remove(data);
992       if(data.symbol)
993          FreeSymbol(data.symbol);
994       FreeType(data.dataType);
995       delete data.fullName;
996       delete data.dataTypeString;
997       delete data;
998    }
999 }
1000
1001 public void CheckDataRedefinitions()
1002 {
1003    // Delaying this because conflict with main parser...
1004    DataRedefinition redefinition;
1005    for(redefinition = dataRedefinitions.first; redefinition; redefinition = redefinition.next)
1006    {
1007       // Added this check to resolve namespaces...
1008       Type type1 = ProcessTypeString(redefinition.type1, false);
1009       Type type2 = ProcessTypeString(redefinition.type2, false);
1010       char type1String[1024] = "";
1011       char type2String[1024] = "";
1012       PrintType(type1, type1String, false, true);
1013       PrintType(type2, type2String, false, true);
1014       if(strcmp(type1String, type2String))
1015          Compiler_Warning($"Redefinition of %s (defining as %s, already defined as %s)\n", redefinition.name, type1String, type2String);
1016       FreeType(type1);
1017       FreeType(type2);
1018    }
1019    dataRedefinitions.Free(null);
1020 }