compiler/bootstrap: Fully automated (make updatebootstrap)
[sdk] / compiler / libec / src / pass3.ec
index e834794..b411fae 100644 (file)
@@ -7,12 +7,12 @@ extern External curExternal;
 ///////////////// INSTANCE DECLARATION PASS ///////////////////////
 
 // Returns true if we should add a * to the declarator
-static bool ReplaceClassSpec(OldList specs, Specifier spec, bool param)
+static int ReplaceClassSpec(OldList specs, Specifier spec, bool param)
 {
    if(spec.type == templateTypeSpecifier)
    {
       TemplateParameter parameter = spec.templateParameter;
-      
+
       if(!param && parameter.dataTypeString)
       {
          OldList * newSpecs = MkList();
@@ -24,14 +24,14 @@ static bool ReplaceClassSpec(OldList specs, Specifier spec, bool param)
             delete newSpec;
          }
          FreeList(newSpecs, FreeSpecifier);
-         
+
          if(decl)
          {
             bool isPointer = decl.type == pointerDeclarator;
             if(decl)
                FreeDeclarator(decl);
             if(isPointer)
-               return true;
+               return 1;
          }
       }
       else if(!param && parameter.dataType)
@@ -44,12 +44,12 @@ static bool ReplaceClassSpec(OldList specs, Specifier spec, bool param)
             *spec = *newSpec;
             delete newSpec;
          }
-         
+
          if(decl)
          {
             bool isPointer = decl.type == pointerDeclarator;
             if(isPointer)
-               return true;
+               return 1;
          }
       }
       else
@@ -72,22 +72,17 @@ static bool ReplaceClassSpec(OldList specs, Specifier spec, bool param)
       if(classSym)
       {
          Class _class = classSym.registered;
-         spec.type = nameSpecifier;
 
-         if(spec.templateArgs)
-         {
-            FreeList(spec.templateArgs, FreeTemplateArgument);
-            spec.templateArgs = null;
-         }
+         FreeSpecifierContents(spec);
 
+         spec.type = nameSpecifier;
          if(_class && _class.type == structClass)
          {
             //Externalexternal;
             char name[1024];
             name[0] = 0;
             FullClassNameCat(name, _class.fullName, false);
-            //spec.name = CopyString(name);
-            delete spec.name;
+            FreeSpecifierContents(spec);
             spec.type = structSpecifier;
             spec.baseSpecs = null;
             spec.id = MkIdentifier(name);
@@ -100,7 +95,6 @@ static bool ReplaceClassSpec(OldList specs, Specifier spec, bool param)
          {
             char name[1024] = "";
             FullClassNameCat(name, _class.fullName, false);
-            delete spec.name;
             spec.type = structSpecifier;
             spec.baseSpecs = null;
             spec.id = MkIdentifier(name);
@@ -125,7 +119,6 @@ static bool ReplaceClassSpec(OldList specs, Specifier spec, bool param)
                !strcmp(_class.fullName, "uint") ||
                !strcmp(_class.fullName, "byte")))
             {
-               delete spec.name;
                if(_class.dataTypeString)
                {
                   if(!strcmp(_class.dataTypeString, "uint64") ||
@@ -140,17 +133,14 @@ static bool ReplaceClassSpec(OldList specs, Specifier spec, bool param)
                   {
                      if(!_class.dataType)
                         _class.dataType = ProcessTypeString(_class.dataTypeString, false);
-                     if(_class.dataType && _class.dataType.kind == classType) 
+                     if(_class.dataType && _class.dataType.kind == classType)
                         classSym = _class.dataType._class;
                      else
                         classSym = FindClass(_class.dataTypeString);
                      _class = classSym ? classSym.registered : null;
                   }
 
-                  if(!strcmp(_class.dataTypeString, "char *"))
-                     spec.name = CopyString("char");
-                  else
-                     spec.name = CopyString(_class.dataTypeString);
+                  spec.name = CopyString(!strcmp(_class.dataTypeString, "char *") ? "char" : _class.dataTypeString);
                   spec.symbol = null;
                }
                else
@@ -161,15 +151,13 @@ static bool ReplaceClassSpec(OldList specs, Specifier spec, bool param)
             }
             else if(!_class.base)
             {
-               delete spec.name;
                spec.type = baseSpecifier;
                spec.specifier = VOID;
-               return true;
+               return 1;
             }
          }
          else
          {
-            delete spec.name;
             spec.type = structSpecifier;
             spec.id = MkIdentifier("__ecereNameSpace__ecere__com__Instance");
             spec.list = null;
@@ -180,22 +168,23 @@ static bool ReplaceClassSpec(OldList specs, Specifier spec, bool param)
          }
 
          if(_class && _class.dataTypeString && !strcmp(_class.dataTypeString, "char *"))
-            return true; //false;
+            return 1; //false;
          if(!_class || _class.type == normalClass || _class.type == noHeadClass)
-            return true;
+            return 1;
          else if(param && _class.type == structClass)
             return 2;
       }
    }
    else if(spec.type == baseSpecifier)
    {
-      if(spec.specifier == ANY_OBJECT)
+      if(spec.specifier == ANY_OBJECT || spec.specifier == CLASS)
       {
-         spec.specifier = VOID;
-         return true;
+         spec.specifier = CONST;
+         specs.Add(MkSpecifier(VOID));
+         return 1;
       }
    }
-   return false;
+   return 0;
 }
 
 static void ReplaceByInstancePtr(Specifier spec, Declarator * declPtr, int type)
@@ -220,12 +209,12 @@ static void ReplaceByInstancePtr(Specifier spec, Declarator * declPtr, int type)
       else
          decl = newDecl;
       decl.type = pointerDeclarator;
-      decl.pointer.pointer = MkPointer(null, null);      
+      decl.pointer.pointer = MkPointer(null, null);
       *declPtr = decl;
    }
 }
 
-static void InstDeclPassSpecifier(Specifier spec)
+static void InstDeclPassSpecifier(Specifier spec, bool byRefTypedObject)
 {
    switch(spec.type)
    {
@@ -233,7 +222,10 @@ static void InstDeclPassSpecifier(Specifier spec)
          if(spec.specifier == TYPED_OBJECT)
          {
             spec.type = extendedSpecifier;
-            spec.extDecl = MkExtDeclString(CopyString("struct __ecereNameSpace__ecere__com__Class * class, void *"));
+            spec.extDecl = MkExtDeclString(CopyString(byRefTypedObject ?
+               "struct __ecereNameSpace__ecere__com__Class * class, void *" :
+               "struct __ecereNameSpace__ecere__com__Class * class, const void *"));
+            DeclareStruct(curExternal, "ecere::com::Class", false, true);
          }
          break;
       case nameSpecifier:
@@ -245,7 +237,7 @@ static void InstDeclPassSpecifier(Specifier spec)
          {
             for(e = spec.list->first; e; e = e.next)
             {
-            
+
             }
          }
          break;
@@ -289,14 +281,11 @@ static void InstDeclPassSpecifier(Specifier spec)
                      spec.extDecl.s = CopyString("extern __attribute__ ((visibility(\"default\")))");
                }
             }
-            else if(!strcmp(spec.extDecl.s, "stdcall") || !strcmp(spec.extDecl.s, "_stdcall") || 
+            else if(!strcmp(spec.extDecl.s, "stdcall") || !strcmp(spec.extDecl.s, "_stdcall") ||
                !strcmp(spec.extDecl.s, "__stdcall") || !strcmp(spec.extDecl.s, "__stdcall__"))
             {
                delete spec.extDecl.s;
-               if(targetPlatform == win32)
-                  spec.extDecl.s = CopyString("__attribute__((__stdcall__))");
-               else
-                  spec.extDecl.s = CopyString("");
+               spec.extDecl.s = CopyString("stdcall");
             }
          }
          break;
@@ -353,6 +342,7 @@ static void InstDeclPassDeclarator(Declarator decl)
                      qualifiers = MkListOne(MkStructOrUnion(structSpecifier, MkIdentifier("__ecereNameSpace__ecere__com__Class"), null));
                      declarator = MkDeclaratorPointer(MkPointer(null,null), MkDeclaratorIdentifier(MkIdentifier("class")));
                   };
+                  DeclareStruct(curExternal, "ecere::com::Class", false, true);
                   decl.function.parameters->Insert(spec.prev, _class);
                }
             }
@@ -373,14 +363,11 @@ static void InstDeclPassDeclarator(Declarator decl)
                   decl.extended.extended.s = CopyString("extern __attribute__ ((visibility(\"default\")))");
             }
             else if(decl.extended.extended.type == extDeclString && decl.extended.extended.s &&
-               (!strcmp(decl.extended.extended.s, "stdcall") || !strcmp(decl.extended.extended.s, "_stdcall") || 
+               (!strcmp(decl.extended.extended.s, "stdcall") || !strcmp(decl.extended.extended.s, "_stdcall") ||
                !strcmp(decl.extended.extended.s, "__stdcall") || !strcmp(decl.extended.extended.s, "__stdcall__")))
             {
                delete decl.extended.extended.s;
-               if(targetPlatform == win32)
-                  decl.extended.extended.s = CopyString("__attribute__((__stdcall__))");
-               else
-                  decl.extended.extended.s = CopyString("");
+               decl.extended.extended.s = CopyString("stdcall");
             }
          }
          if(decl.declarator)
@@ -402,11 +389,11 @@ static void InstDeclPassDeclarator(Declarator decl)
          else
          {
             Symbol classSym = (spec.type == nameSpecifier) ? spec.symbol /*FindClass(spec.name)*/ : null;
-            if(type.classObjectType && (!classSym || (classSym && classSym.registered && 
+            if(type.classObjectType && (!classSym || (classSym && classSym.registered &&
                (classSym.registered.type == enumClass || classSym.registered.type == bitClass || classSym.registered.type == unitClass))))
                ReplaceByInstancePtr(spec, &type.declarator, 2);
          }
-         InstDeclPassSpecifier(spec);
+         InstDeclPassSpecifier(spec, type.declarator && type.declarator.type == pointerDeclarator);
       }
    }
    if(type.declarator)
@@ -436,6 +423,106 @@ static void InstDeclPassIdentifier(Identifier id)
    }
 }
 
+/*static */bool IsVoidPtrCast(TypeName typeName)
+{
+   bool result = false;
+   Declarator d = typeName.declarator;
+   if(d && d.type == pointerDeclarator && d.pointer.pointer && !d.pointer.pointer.pointer)
+   {
+      if(typeName.qualifiers)
+      {
+         Specifier s;
+         for(s = typeName.qualifiers->first; s; s = s.next)
+         {
+            if(s.type == baseSpecifier && s.specifier == VOID)
+               result = true;
+         }
+      }
+   }
+   return result;
+}
+
+static void AddPointerCast(Expression e)
+{
+   Type src = e.expType;
+
+   if(src && (src.kind == templateType || src.kind == classType))
+   {
+      if(e.type != castExp || !IsVoidPtrCast(e.cast.typeName))
+      {
+         if(src) src.refCount++;
+         if(src.kind == templateType && src.templateParameter && src.templateParameter.type == type)
+         {
+            Type newType = null;
+            if(src.templateParameter.dataTypeString)
+               newType = ProcessTypeString(src.templateParameter.dataTypeString, false);
+            else if(src.templateParameter.dataType)
+               newType = ProcessType(src.templateParameter.dataType.specifiers, src.templateParameter.dataType.decl);
+            if(newType)
+            {
+               FreeType(src);
+               src = newType;
+            }
+         }
+         if(src && src.kind == classType && src._class)
+         {
+            Class sc = src._class.registered;
+            if(src.thisClassFrom && src.thisClassFrom.base)
+               sc = src.thisClassFrom;
+
+            if(sc && (sc.type == structClass || sc.type == noHeadClass))
+            {
+               Type dest = e.destType;
+
+               if(dest && (dest.kind == templateType || dest.kind == classType))
+               {
+                  if(dest) dest.refCount++;
+
+                  if(dest.kind == templateType && dest.templateParameter && dest.templateParameter.type == type)
+                  {
+                     Type newType = null;
+                     if(dest.templateParameter.dataTypeString)
+                        newType = ProcessTypeString(dest.templateParameter.dataTypeString, false);
+                     else if(dest.templateParameter.dataType)
+                        newType = ProcessType(dest.templateParameter.dataType.specifiers, dest.templateParameter.dataType.decl);
+                     if(newType)
+                     {
+                        FreeType(dest);
+                        dest = newType;
+                     }
+                  }
+                  if(!dest.passAsTemplate && dest.kind == classType && dest._class && dest._class.registered)
+                  {
+                     Class dc = dest._class.registered;
+
+                     if(sc.templateClass) sc = sc.templateClass;
+                     if(dc.templateClass) dc = dc.templateClass;
+                     if(dc.base && sc != dc)
+                     {
+                        e.cast.exp = MkExpBrackets(MkListOne(MoveExpContents(e)));
+                        e.type = castExp;
+                        e.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), QMkPtrDecl(null));
+                     }
+                  }
+                  FreeType(dest);
+               }
+            }
+         }
+         FreeType(src);
+      }
+   }
+   else if(src && src.kind == intPtrType && e.destType && e.destType.classObjectType)
+   {
+      Expression nbExp = GetNonBracketsExp(e);
+      if(nbExp.type != castExp || !IsVoidPtrCast(nbExp.cast.typeName))
+      {
+         e.cast.exp = MkExpBrackets(MkListOne(MoveExpContents(e)));
+         e.type = castExp;
+         e.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), QMkPtrDecl(null));
+      }
+   }
+}
+
 static void InstDeclPassExpression(Expression exp)
 {
    switch(exp.type)
@@ -454,7 +541,24 @@ static void InstDeclPassExpression(Expression exp)
          if(exp.op.exp1)
             InstDeclPassExpression(exp.op.exp1);
          if(exp.op.exp2)
+         {
             InstDeclPassExpression(exp.op.exp2);
+            if(exp.op.op != '=' && exp.op.exp1 && exp.op.exp1.expType && exp.op.exp1.expType.kind == pointerType && exp.op.exp1.expType.type && exp.op.exp1.expType.type.kind == templateType &&
+               exp.op.exp2.expType && exp.op.exp2.expType.kind == pointerType && exp.op.exp2.expType.type && exp.op.exp2.expType.type.kind == templateType)
+            {
+               Expression e = exp.op.exp2;
+               e.cast.exp = MkExpBrackets(MkListOne(MoveExpContents(e)));
+               e.type = castExp;
+               e.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), QMkPtrDecl(null));
+
+               e = exp.op.exp1;
+               e.cast.exp = MkExpBrackets(MkListOne(MoveExpContents(e)));
+               e.type = castExp;
+               e.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), QMkPtrDecl(null));
+            }
+            else if(exp.op.exp1 && (exp.op.op == '=' || exp.op.op == EQ_OP || exp.op.op == NE_OP))
+               AddPointerCast(exp.op.exp2);
+         }
          break;
       case extensionExpressionExp:
       case bracketsExp:
@@ -479,18 +583,39 @@ static void InstDeclPassExpression(Expression exp)
          if(exp.call.arguments)
          {
             for(e = exp.call.arguments->first; e; e = e.next)
+            {
+               bool addCast = false;
                InstDeclPassExpression(e);
+               AddPointerCast(e);
+
+               if(e.expType && e.expType.kind == pointerType && e.expType.type && (e.expType.type.kind == classType || (e.expType.type.kind == pointerType && e.expType.type.type && e.expType.type.type.kind != voidType)) &&
+                  e.destType && e.destType.kind == pointerType && e.destType.type && e.destType.type.kind == pointerType && e.destType.type.type && e.destType.type.type.kind == voidType)
+                  addCast = true;
+               // Fix for adding a cast to Unserialize with a struct passed as a parameter:
+               else if(e.expType && e.expType.kind == classType && e.expType._class && e.expType._class.registered && e.expType._class.registered.type == structClass && e.byReference &&
+                  e.destType && e.destType.kind == classType && e.destType.classObjectType && e.destType.byReference)
+                  addCast = true;
+
+               if(addCast && (e.type != castExp || !IsVoidPtrCast(e.cast.typeName)))
+               {
+                  e.cast.exp = MkExpBrackets(MkListOne(MoveExpContents(e)));
+                  e.type = castExp;
+                  e.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), QMkPtrDecl(null));
+               }
+            }
          }
          break;
       }
       case memberExp:
       {
-         InstDeclPassExpression(exp.member.exp);
+         if(exp.member.exp)
+            InstDeclPassExpression(exp.member.exp);
          break;
       }
       case pointerExp:
       {
-         InstDeclPassExpression(exp.member.exp);
+         if(exp.member.exp)
+            InstDeclPassExpression(exp.member.exp);
          break;
       }
       case typeSizeExp:
@@ -500,25 +625,46 @@ static void InstDeclPassExpression(Expression exp)
       {
          Type type = exp.expType;
          // Remove casts to simple structs... (Watch out for pointers later...)
-         if(type && type.kind == classType && type._class.registered && type._class.registered.type == structClass)
-         {
-            Expression castExp = exp.cast.exp;
-            Expression prev = exp.prev, next = exp.next;
-            exp.cast.exp = null;
-            FreeExpContents(exp);
-            FreeType(exp.expType);
-            FreeType(exp.destType);
-            *exp = *castExp;
-            delete castExp;
-            exp.prev = prev;
-            exp.next = next;
-            InstDeclPassExpression(exp);
+         if(type && type.kind == classType && type._class.registered && type._class.registered.type == structClass && !exp.needCast)
+         {
+            if(exp.destType && exp.destType.classObjectType == typedObject && exp.destType.byReference)
+            {
+               // For Unserialize with a StaticString
+               FreeTypeName(exp.cast.typeName);
+               exp.cast.typeName = MkTypeName(MkListOne(MkSpecifier(VOID)), MkDeclaratorPointer(MkPointer(null, MkPointer(null, null)), null));
+            }
+            else
+            {
+               Expression castExp = exp.cast.exp;
+               Expression prev = exp.prev, next = exp.next;
+               exp.cast.exp = null;
+               FreeExpContents(exp);
+               FreeType(exp.expType);
+               FreeType(exp.destType);
+               *exp = *castExp;
+               delete castExp;
+               exp.prev = prev;
+               exp.next = next;
+               InstDeclPassExpression(exp);
+            }
          }
          else
          {
-            InstDeclPassTypeName(exp.cast.typeName, false);
+            if(exp.expType && exp.expType.kind == pointerType)
+            {
+               if(exp.cast.exp && exp.cast.exp.expType && exp.cast.exp.expType.kind == templateType && !exp.cast.exp.expType.isPointerType)
+                  exp.cast.exp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), exp.cast.exp);
+            }
+
+            InstDeclPassTypeName(exp.cast.typeName, exp.usage.usageArg /*false*/);
             if(exp.cast.exp)
+            {
+               if(exp.expType && exp.expType.kind == templateType && exp.destType &&
+                  (exp.destType.passAsTemplate || (!exp.destType.templateParameter || (!exp.destType.templateParameter.dataType && !exp.destType.templateParameter.dataTypeString))) &&
+                  exp.cast.exp.expType && !exp.cast.exp.expType.passAsTemplate && exp.cast.exp.expType.isPointerType)
+                  exp.cast.exp = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uintptr")), null), exp.cast.exp);
                InstDeclPassExpression(exp.cast.exp);
+            }
          }
          break;
       }
@@ -555,7 +701,11 @@ static void InstDeclPassInitializer(Initializer init)
    switch(init.type)
    {
       case expInitializer:
-         InstDeclPassExpression(init.exp);
+         if(init.exp)
+         {
+            InstDeclPassExpression(init.exp);
+            AddPointerCast(init.exp);
+         }
          break;
       case listInitializer:
       {
@@ -588,7 +738,7 @@ static void InstDeclPassDeclaration(Declaration decl)
                         ReplaceByInstancePtr(spec, &d.declarator, type);
                   }
                }
-               InstDeclPassSpecifier(spec);
+               InstDeclPassSpecifier(spec, false);
             }
          }
          if(decl.declarators)
@@ -620,7 +770,7 @@ static void InstDeclPassDeclaration(Declaration decl)
                         ReplaceByInstancePtr(spec, &d, type);
                   }
                }
-               InstDeclPassSpecifier(spec);
+               InstDeclPassSpecifier(spec, false);
             }
          }
 
@@ -665,7 +815,7 @@ static void InstDeclPassStatement(Statement stmt)
 
          if(!stmt.compound.isSwitch)
             curContext = stmt.compound.context;
-         
+
          if(stmt.compound.declarations)
          {
             for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
@@ -706,16 +856,22 @@ static void InstDeclPassStatement(Statement stmt)
       case switchStmt:
       {
          Expression exp;
-         for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
-            InstDeclPassExpression(exp);
+         if(stmt.switchStmt.exp)
+         {
+            for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
+               InstDeclPassExpression(exp);
+         }
          InstDeclPassStatement(stmt.switchStmt.stmt);
          break;
       }
       case whileStmt:
       {
          Expression exp;
-         for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
-            InstDeclPassExpression(exp);
+         if(stmt.whileStmt.exp)
+         {
+            for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
+               InstDeclPassExpression(exp);
+         }
          InstDeclPassStatement(stmt.whileStmt.stmt);
          break;
       }
@@ -760,6 +916,7 @@ static void InstDeclPassStatement(Statement stmt)
          {
             for(exp = stmt.expressions->first; exp; exp = exp.next)
                InstDeclPassExpression(exp);
+            AddPointerCast(stmt.expressions->last);
          }
          break;
       }
@@ -789,6 +946,504 @@ static void InstDeclPassStatement(Statement stmt)
    }
 }
 
+void TopoSort(OldList * input)
+{
+   OldList L { };
+   OldList S { };
+   OldList B { };
+   External n, next;
+   //External x;
+
+   for(n = input->first; n; n = next)
+   {
+      next = n.next;
+      if(n.type == declarationExternal && !n.declaration)
+      {
+         input->Remove(n);
+         if(n.symbol && n.symbol.structExternal == n)
+            n.symbol.structExternal = null;
+         FreeExternal(n);
+      }
+      else if(!n.incoming.count)
+      {
+         input->Remove(n);
+         S.Add(n);
+      }
+      else if(!n.nonBreakableIncoming)
+      {
+         input->Remove(n);
+         B.Add(n);
+      }
+   }
+/*
+         for(x = input->first; x; x = x.next)
+         {
+            int count = 0;
+            for(e : x.incoming; !e.breakable)
+               count++;
+            if(count != x.nonBreakableIncoming)
+               printf("Bug in input");
+
+            if(!x.incoming.count)
+               printf("This node should be in S!\n");
+            for(e : x.incoming)
+            {
+               External y, from = e.from;
+               for(y = input->first; y; y = y.next)
+                  if(y == from)
+                     break;
+               if(!y)
+               {
+                  for(y = B.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+
+               if(!y)
+               {
+                  for(y = S.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+               if(!y)
+               {
+                  printf("This node is nowhere!\n");
+               }
+            }
+         }*/
+
+   while(true)
+   {
+      TopoEdge e, ne;
+      if((n = S.first))
+      {
+         /*
+         for(x = input->first; x; x = x.next)
+         {
+            int count = 0;
+            for(e : x.incoming; !e.breakable)
+               count++;
+            if(count != x.nonBreakableIncoming)
+               printf("Bug in input");
+            if(!x.incoming.count)
+               printf("This node should be in S!\n");
+            for(e : x.incoming)
+            {
+               External y, from = e.from;
+               for(y = input->first; y; y = y.next)
+                  if(y == from)
+                     break;
+               if(!y)
+               {
+                  for(y = B.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+
+               if(!y)
+               {
+                  for(y = S.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+               if(!y)
+               {
+                  printf("This node is nowhere!\n");
+               }
+            }
+         }*/
+
+         //DebugPrint("*** Free Node: [", n.id, "]\n\t", n.output);
+         S.Remove((IteratorPointer)n);
+
+         /*
+         if(n && n.symbol && n.symbol.string && !strcmp(n.symbol.string, "ecere::com::Instance"))
+            printf("Adding Instance\n");
+         */
+
+         L.Add(n);
+         for(e = n.outgoing.first; e; e = ne)
+         {
+            External m = e.to;
+            OldList * list;
+
+            //DebugPrint(" This Free Node has an edge to [", m.id, "] ", m.output);
+            if(m.nonBreakableIncoming)
+            {
+               //DebugPrint("... which we think is in input");
+               list = input;
+            }
+            else
+            {
+               //DebugPrint("... which we think is in B");
+               list = &B;
+            }
+
+            if(!list->count)
+               PrintLn("!!! Something's wrong !!!");
+            ne = e.out.next;
+
+            if(!e.breakable)
+            {
+#ifdef _DEBUG
+               if(!m.nonBreakableIncoming)
+                  printf("Bug");
+#endif
+               m.nonBreakableIncoming--;
+               //DebugPrint("Reducing non breakable incoming, now ", m.nonBreakableIncoming);
+            }
+
+            n.outgoing.Remove((IteratorPointer)e);
+            m.incoming.Remove((IteratorPointer)e);
+            delete e;
+
+            if(!m.incoming.count)
+            {
+               //DebugPrint("Last edge to this node taken out, moving to S...");
+               list->Remove(m);
+               S.Add(m);
+            }
+            else if(!m.nonBreakableIncoming)
+            {
+               //DebugPrint("Last non-breakable edge to this node taken out, moving to B...");
+               list->Remove(m);
+               B.Add(m);
+            }
+         }
+      }
+      else if((n = B.first))
+      {
+         //DebugPrint("Breaking some of the ", n.incoming.count, " incoming edges to [", n.id, "] ", n.output);
+         B.Remove((IteratorPointer)n);
+
+         // Break the edges of this node
+         for(e = n.incoming.first; e; e = ne)
+         {
+            TopoEdge e2, n2;
+            External m = e.from;
+            External f;
+/*
+         for(x = input->first; x; x = x.next)
+         {
+            int count = 0;
+            for(e : x.incoming; !e.breakable)
+               count++;
+            if(count != x.nonBreakableIncoming)
+               printf("Bug in input");
+            if(!x.incoming.count)
+               printf("This node should be in S!\n");
+            for(e : x.incoming)
+            {
+               External y, from = e.from;
+               for(y = input->first; y; y = y.next)
+                  if(y == from)
+                     break;
+               if(!y)
+               {
+                  for(y = B.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+
+               if(!y)
+               {
+                  for(y = S.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+               if(!y && from != n)
+               {
+                  printf("This node is nowhere!\n");
+               }
+            }
+         }*/
+
+            f = m.ForwardDeclare();
+            ne = e.in.next;
+/*
+         for(x = input->first; x; x = x.next)
+         {
+            int count = 0;
+            for(e : x.incoming; !e.breakable)
+               count++;
+            if(count != x.nonBreakableIncoming)
+               printf("Bug in input");
+            if(!x.incoming.count)
+               printf("This node should be in S!\n");
+            for(e : x.incoming)
+            {
+               External y, from = e.from;
+               for(y = input->first; y; y = y.next)
+                  if(y == from)
+                     break;
+               if(!y)
+               {
+                  for(y = B.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+
+               if(!y)
+               {
+                  for(y = S.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+               if(!y && from != n && from != f)
+               {
+                  printf("This node is nowhere!\n");
+               }
+            }
+         }
+*/
+            // Recheck input for edges created by forward declaration
+            {
+               External c, next;
+               for(c = input->first; c; c = next)
+               {
+                  next = c.next;
+                  if(!c.incoming.count)
+                  {
+                     input->Remove(c);
+                     S.Add(c);
+                  }
+                  else if(!c.nonBreakableIncoming)
+                  {
+                     input->Remove(c);
+                     B.Add(c);
+                  }
+               }
+            }
+
+            //DebugPrint("Breaking edge from ", e.from.id, " to ", e.to.id);
+            //DebugPrint("Creating a forward decl node [", f.id, "] for [", m.id, "]");
+
+            for(e2 = m.outgoing.first; e2; e2 = n2)
+            {
+               n2 = e2.out.next;
+               if(e2.breakable)
+               {
+                  External to = e2.to;
+
+                  if(e2 == e)
+                     ;//DebugPrint("Breaking this particular connection");
+                  else
+                     ;//DebugPrint("Also redirecting connection from ", m.id, " to ", to.id, " to come from ", f.id, " instead.");
+                  e2.breakable = false;
+                  e2.from = f;
+                  m.outgoing.Remove((IteratorPointer)e2);
+                  f.outgoing.Add(e2);
+                  to.nonBreakableIncoming++;
+                  if(e2 != e && to.nonBreakableIncoming == 1)
+                  {
+                     // If this node was previously in B, move it to input
+                     B.Remove(to);
+                     input->Add(to);
+                  }
+
+                  //DebugPrint("Node ", e2.to.id, " now has ", e2.to.nonBreakableIncoming, " non-breakable incoming edges.");
+               }
+            }
+/*
+         for(x = input->first; x; x = x.next)
+         {
+            int count = 0;
+            for(e : x.incoming; !e.breakable)
+               count++;
+            if(count != x.nonBreakableIncoming)
+               printf("Bug in input");
+            if(!x.incoming.count)
+               printf("This node should be in S!\n");
+            for(e : x.incoming)
+            {
+               External y, from = e.from;
+               for(y = input->first; y; y = y.next)
+                  if(y == from)
+                     break;
+               if(!y)
+               {
+                  for(y = B.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+
+               if(!y)
+               {
+                  for(y = S.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+               if(!y && from != n && from != f)
+               {
+                  printf("This node is nowhere!\n");
+               }
+            }
+         }*/
+            if(!f.incoming.count)
+               S.Add(f);
+            else if(!f.nonBreakableIncoming)
+               B.Add(f);
+            else
+               input->Add(f);
+/*
+         for(x = input->first; x; x = x.next)
+         {
+            int count = 0;
+            for(e : x.incoming; !e.breakable)
+               count++;
+            if(count != x.nonBreakableIncoming)
+               printf("Bug in input");
+            if(!x.incoming.count)
+               printf("This node should be in S!\n");
+            for(e : x.incoming)
+            {
+               External y, from = e.from;
+               for(y = input->first; y; y = y.next)
+                  if(y == from)
+                     break;
+               if(!y)
+               {
+                  for(y = B.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+
+               if(!y)
+               {
+                  for(y = S.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+
+               if(!y)
+               {
+                  for(y = L.first; y; y = y.next)
+                     if(y == from)
+                     {
+                        PrintLn("This node is already in L!");
+                        break;
+                     }
+               }
+
+               if(!y && from != n)
+               {
+                  ConsoleFile file { };
+                  printf("This node is nowhere!\n");
+                  OutputExternal(from, file);
+                  delete file;
+               }
+            }
+         }
+*/
+            // Avoid needless edge breaking by processing a node as soon as one shows up in S
+            if(S.first)
+               break;
+         }
+
+         // Put n back in input because it now has unbreakable edges
+         input->Add(n);
+      }
+      else
+      {
+         if(input->count)
+         {
+#ifdef _DEBUG
+            ConsoleFile f { };
+            External e = input->first;
+#endif
+            Compiler_Error("declarations cycles found\n");
+#ifdef _DEBUG
+            //OutputTree(input, f);
+/*
+         for(x = input->first; x; x = x.next)
+         {
+            int count = 0;
+            for(e : x.incoming; !e.breakable)
+               count++;
+            if(count != x.nonBreakableIncoming)
+               printf("Bug in input");
+            if(!x.incoming.count)
+               printf("This node should be in S!\n");
+
+            for(e : x.incoming)
+            {
+               External y, from = e.from;
+               for(y = input->first; y; y = y.next)
+                  if(y == from)
+                     break;
+               if(!y)
+               {
+                  for(y = B.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+
+               if(!y)
+               {
+                  for(y = S.first; y; y = y.next)
+                     if(y == from)
+                        break;
+               }
+               if(!y)
+               {
+                  printf("This node is nowhere!\n");
+               }
+            }
+         }
+*/
+            SetOutputLineNumbers(false);
+            OutputExternal(e, f);
+
+            PrintLn("\nDepends on:\n");
+            { TopoEdge i; for(i = e.incoming.last; i && !i.breakable && i.from.incoming.count; i = i.in.next) { e = i.from; break; } }
+
+            OutputExternal(e, f);
+
+            PrintLn("\nWhile that depends on:\n");
+            { TopoEdge i; for(i = e.incoming.first; i && !i.breakable && i.from.incoming.count; i = i.in.next) { e = i.from; break; } }
+
+            OutputExternal(e, f);
+
+            PrintLn("\nWhile that depends on:\n");
+            { TopoEdge i; for(i = e.incoming.first; i && !i.breakable && i.from.incoming.count; i = i.in.next) { e = i.from; break; } }
+
+            OutputExternal(e, f);
+
+            PrintLn("\nWhile that depends on:\n");
+            { TopoEdge i; for(i = e.incoming.first; i && !i.breakable && i.from.incoming.count; i = i.in.next) { e = i.from; break; } }
+
+            OutputExternal(e, f);
+            delete f;
+
+            system("pause");
+
+            while((e = input->first))
+            {
+               input->Remove(e);
+               L.Add(e);
+            }
+            *input = L;
+#endif
+         }
+         else
+            *input = L;
+         break;
+      }
+   }
+
+   for(n = input->first; n; n = next)
+   {
+      next = n.next;
+      if(n.type == declarationExternal && (!n.declaration || ((!n.declaration.specifiers || !n.declaration.specifiers->count) && (!n.declaration.declarators || !n.declaration.declarators->count))))
+      {
+         input->Remove(n);
+         if(n.symbol && n.symbol.structExternal == n)
+            n.symbol.structExternal = null;
+         FreeExternal(n);
+      }
+   }
+}
+
 public void ProcessInstanceDeclarations()
 {
    External external;
@@ -807,7 +1462,7 @@ public void ProcessInstanceDeclarations()
                int type;
                if((type = ReplaceClassSpec(func.specifiers, spec, false)))
                   ReplaceByInstancePtr(spec, &func.declarator, type);
-               InstDeclPassSpecifier(spec);
+               InstDeclPassSpecifier(spec, false);
             }
          }
          InstDeclPassDeclarator(func.declarator);
@@ -817,7 +1472,10 @@ public void ProcessInstanceDeclarations()
       else if(external.type == declarationExternal)
       {
          if(external.declaration)
-            InstDeclPassDeclaration(external.declaration);         
+            InstDeclPassDeclaration(external.declaration);
       }
    }
+
+   // Perform topological sort
+   TopoSort(ast);
 }